""" Floor lettering with the Season 1 bundle's own decal materials (its words, the orange chevron, the hazard band). Same rules as on Anchorage (models/anchorage/build/dressing.py), so station and ship read alike: * one type size: a word is a 3.2 x 0.8 m decal, centred on the axis of the opening it belongs to; * a word lies on the floor before the doorway it names and is read walking towards it; * white lettering on the dark deck; three orange chevrons after a word point where it leads; * orange hazard band = "something moves here". Only variants the pack ships are used, so nothing new is needed in Unreal: each mark is one decal (material, size, matrix) in the layout export. """ import math import numpy as np from mathutils import Matrix, Vector from units import Item GAME = "/Game/StarterBundle/" MATS = GAME + "ModularSciFiMats/Materials/Decals/" COMM = GAME + "ModularSci_Comm/Materials/Decals/" WORDS = { "CARGO": MATS + "Words/MI_Cargo", "DOCK": MATS + "Words/MI_Dock", "STAND CLEAR": MATS + "Words/MI_StandClear", "CONTROL": COMM + "Words/MI_Control", "MAINTENANCE": COMM + "Words/MI_Maintenance", "RESTRICTED": MATS + "Words/MI_RestrictedArea", "STATION": MATS + "Words/MI_Station", "OBSERVATION": COMM + "Words/MI_Observation", } CHEVRON = MATS + "Arrows/MI_Arrow_A" # orange chevron, points along +U HAZARD = MATS + "Stripes/MI_Stripe_H" HAZARD_FALLBACK = MATS + "Stripes/MI_Stripe_D" MAIN = (3.2, 0.8) _extent = {} def dir_vec(heading_deg): """Unit vector for a heading in the ship's frame: 0 = +X (bow), 90 = +Y (port).""" a = math.radians(heading_deg) return Vector((math.cos(a), math.sin(a), 0.0)) def text_extent(mat): """Where the lettering sits inside its texture: (u0, u1, v0, v1), v measured from the bottom.""" if mat.name in _extent: return _extent[mat.name] ext = (0.0, 1.0, 0.0, 1.0) for node in mat.node_tree.nodes: if node.type == "TEX_IMAGE" and node.image is not None and node.image.size[0] > 0: img = node.image w, h = img.size px = np.empty(w * h * 4, dtype=np.float32) img.pixels.foreach_get(px) a = px.reshape(h, w, 4)[:, :, 0] cols = np.where(a.max(axis=0) > 0.35)[0] rows = np.where(a.max(axis=1) > 0.35)[0] if len(cols) and len(rows): ext = (cols[0] / w, (cols[-1] + 1) / w, rows[0] / h, (rows[-1] + 1) / h) break _extent[mat.name] = ext return ext def mark(kit, mat_path, x, y, z, heading, size, name, centre_text=True): """One floor decal as a unit item (world frame): read by someone walking along `heading`, its visible mark centred on (x, y), lying on a floor at height z.""" d = dir_vec(heading) # text "up" on the floor = direction of travel r = Vector((d.y, -d.x, 0.0)) # text right = the reader's right w, h = size cx, cy = x, y if centre_text: u0, u1, v0, v1 = text_extent(kit.material(mat_path)) off = r * ((0.5 - (u0 + u1) / 2.0) * w) + d * ((0.5 - (v0 + v1) / 2.0) * h) cx, cy = x + off.x, y + off.y # decal frame: X = projection (down), Y = text up, Z = text right; the unit decal quad is 2 x 2 cm m = Matrix(((0.0, d.x * h * 50.0, r.x * w * 50.0, cx), (0.0, d.y * h * 50.0, r.y * w * 50.0, cy), (-12.0, 0.0, 0.0, z), (0.0, 0.0, 0.0, 1.0))) return Item("decal", mat_path, m, name, "", {"material": mat_path, "size": [1.0, 1.0, 1.0]}, Vector((cx, cy, z))) def word(kit, key, x, y, z, heading, size=MAIN, chevrons=True, gap=0.55): out = [mark(kit, WORDS[key], x, y, z, heading, size, "WORD " + key)] if chevrons: d = dir_vec(heading) s = size[1] * 0.62 start = size[1] * 0.5 + gap for i in range(3): p = Vector((x, y, 0)) + d * (start + i * s * 0.62) # the chevron texture points along +U (the reader's right): turn it to point ahead out.append(mark(kit, CHEVRON, p.x, p.y, z, heading + 90.0, (s, s), "CHEVRON", centre_text=False)) return out def hazard_band(kit, x, y, z, heading, width=8.0, piece=2.0): """A hazard band across the floor, `width` long, centred on (x, y), crossed by someone walking along `heading`.""" mat = HAZARD if HAZARD in kit.materials else HAZARD_FALLBACK r = Vector((dir_vec(heading).y, -dir_vec(heading).x, 0.0)) n = int(round(width / piece)) out = [] for i in range(n): p = Vector((x, y, 0)) + r * ((i - (n - 1) / 2.0) * piece) out.append(mark(kit, mat, p.x, p.y, z, heading, (piece, piece / 2.0), "HAZARD BAND")) return out