use comparray; fn section_build_geometry(pos: SectionPos) []Vertex = { const section = getsection(pos) as *Section; if (section.bstates.palette_size == 1 && section.bstates.data_constant == 0) { return []; }; const neighbors = [ getsection(SectionPos { x = pos.x - 1, y = pos.y, z = pos.z }), getsection(SectionPos { x = pos.x + 1, y = pos.y, z = pos.z }), getsection(SectionPos { x = pos.x, y = pos.y - 1, z = pos.z }), getsection(SectionPos { x = pos.x, y = pos.y + 1, z = pos.z }), getsection(SectionPos { x = pos.x, y = pos.y, z = pos.z - 1 }), getsection(SectionPos { x = pos.x, y = pos.y, z = pos.z + 1 }), ]; let vertices: []Vertex = alloc([], 1024); for (let y = 0u8; y < 16; y += 1) for (let z = 0u8; z < 16; z += 1) for (let x = 0u8; x < 16; x += 1) { const i = x | z << 4 | y: size << 8; const bstate = comparray::lookup(§ion.bstates, comparray::get(§ion.bstates, i)); if (bstate == 0) continue; const render_bstate = &BSTATES_RENDER[bstate]; for (let i = 0z; i < len(render_bstate.parts); i += 1) { const part = &render_bstate.parts[i]; const geom = part.model.geom as *ModelGeom; for (let j = 0z; j < len(geom.faces); j += 1) { const face = &geom.faces[j]; if (face.cull_face != CullFace::NONE) { let axis = 0u8; for (true; axis += 1) { if (part.swizzle >> axis >> axis & 3 == face.cull_face >> 1) break; }; const flip = part.flags: u8 >> axis; const sign = (face.cull_face: u8 ^ flip) & 1; const cull_face = axis << 1 | sign; let neighbor = [x, y, z]; const coord = &neighbor[axis]; *coord += (sign << 1) - 1; const section_ = if (*coord & 0xf0 != 0) neighbors[cull_face] else section; *coord &= 0x0f; match (section_) { case let section_: *Section => const k = neighbor[0] | neighbor[2] << 4 | neighbor[1]: size << 8; const bstate_ = comparray::lookup(§ion_.bstates, comparray::get(§ion_.bstates, k)); if ((bstate >= 77 && bstate <= 92 || !(bstate_ >= 77 && bstate_ <= 92)) && len((BSTATES_RENDER[bstate_].parts[0].model.geom as *ModelGeom).faces) != 0) continue; case null => if (axis != 1) continue; }; }; let face_vertices: [4][3]u16 = [[0...]...]; for (let k = 0z; k < 4; k += 1) { const vert = &face.vertices[k]; let vx = vert[part.swizzle & 3]; if (part.flags & BstateRenderPartFlags::FLIP_X != 0) vx = 6144 - vx; vx += x: u16 * 2048; let vy = vert[part.swizzle >> 2 & 3]; if (part.flags & BstateRenderPartFlags::FLIP_Y != 0) vy = 6144 - vy; vy += y: u16 * 2048; let vz = vert[part.swizzle >> 4]; if (part.flags & BstateRenderPartFlags::FLIP_Z != 0) vz = 6144 - vz; vz += z: u16 * 2048; face_vertices[k] = [vx, vy, vz]; }; let normal = [ face.normal[part.swizzle & 3], face.normal[part.swizzle >> 2 & 3], face.normal[part.swizzle >> 4], ]; if (part.flags & BstateRenderPartFlags::FLIP_X != 0) normal[0] = -normal[0]; if (part.flags & BstateRenderPartFlags::FLIP_Y != 0) normal[1] = -normal[1]; if (part.flags & BstateRenderPartFlags::FLIP_Z != 0) normal[2] = -normal[2]; const sprite = part.model.textures[face.texture]; const tex_left = face.texcoord[0]; const tex_top = face.texcoord[1]; const tex_right = face.texcoord[2]; const tex_bottom = face.texcoord[3]; const flags_left: VertexFlags = if (tex_left < tex_right) 0 else VertexFlags::U_EXCL; const flags_top: VertexFlags = if (tex_top < tex_bottom) 0 else VertexFlags::V_EXCL; const flags_right = flags_left ^ VertexFlags::U_EXCL; const flags_bottom = flags_top ^ VertexFlags::V_EXCL; let texcoord: [4][2]u16 = [ [tex_left, tex_top], [tex_left, tex_bottom], [tex_right, tex_bottom], [tex_right, tex_top], ]; let flags = [ flags_left | flags_top, flags_left | flags_bottom, flags_right | flags_bottom, flags_right | flags_top, ]; const mask = 1 << face.dir; const flip_u = part.flip_u & mask != 0; const flip_v = part.flip_v & mask != 0; const swap_uv = part.swap_uv & mask != 0; const tex_flipped = tex_left < tex_right != tex_top < tex_bottom; // flipping the texture reverses the apparent // rotation wrt. the rotation applied to the // texcoords, so we need to compensate. const (flip_u, flip_v) = if (tex_flipped) (flip_v, flip_u) else (flip_u, flip_v); for (let k = 0u8; k < 4; k += 1) { const uv = &texcoord[k]; const f = &flags[k]; if (swap_uv) { *uv = [uv[1], uv[0]]; const u_excl = *f & VertexFlags::U_EXCL; const v_excl = *f & VertexFlags::V_EXCL; *f = u_excl << 1 | v_excl >> 1; }; if (flip_u) { uv[0] = 128 - uv[0]; *f ^= VertexFlags::U_EXCL; }; if (flip_v) { uv[1] = 128 - uv[1]; *f ^= VertexFlags::V_EXCL; }; uv[0] = sprite.x: u16 + (sprite.width * uv[0] >> 7): u16; uv[1] = sprite.y: u16 + (sprite.height * uv[1] >> 7): u16; }; append(vertices, [ Vertex { position = face_vertices[0], normal = normal, texcoord = texcoord[face.rotation & 3], flags = flags[face.rotation & 3] }, Vertex { position = face_vertices[1], normal = normal, texcoord = texcoord[1 + face.rotation & 3], flags = flags[1 + face.rotation & 3] }, Vertex { position = face_vertices[2], normal = normal, texcoord = texcoord[2 + face.rotation & 3], flags = flags[2 + face.rotation & 3] }, Vertex { position = face_vertices[2], normal = normal, texcoord = texcoord[2 + face.rotation & 3], flags = flags[2 + face.rotation & 3] }, Vertex { position = face_vertices[3], normal = normal, texcoord = texcoord[3 + face.rotation & 3], flags = flags[3 + face.rotation & 3] }, Vertex { position = face_vertices[0], normal = normal, texcoord = texcoord[face.rotation & 3], flags = flags[face.rotation & 3] }, ]...); }; }; }; return vertices; };