summaryrefslogtreecommitdiff
path: root/section_geometry.ha
diff options
context:
space:
mode:
Diffstat (limited to 'section_geometry.ha')
-rw-r--r--section_geometry.ha164
1 files changed, 164 insertions, 0 deletions
diff --git a/section_geometry.ha b/section_geometry.ha
new file mode 100644
index 0000000..c39780e
--- /dev/null
+++ b/section_geometry.ha
@@ -0,0 +1,164 @@
+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(&section.bstates, comparray::get(&section.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(&section_.bstates, comparray::get(&section_.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;
+};