trueno/src/rendering/trile_mesher.jai
2026-10-03 00:01:24 +03:00

97 lines
3.8 KiB
Plaintext

mesh_trile :: (trile: *Trile) -> vertices: []Trile_Vertex, indices: []u16 {
vertices : [..]Trile_Vertex;
indices : [..]u16;
vertices.allocator = temp;
indices.allocator = temp;
for axis: 0..2 for sign: s32.[1, -1] {
u_axis := (axis + 1) % 3;
v_axis := (axis + 2) % 3;
for depth: 0..15 {
mask : [16][16]Face;
for u: 0..15 for v: 0..15 {
c : [3]s32;
c[axis] = xx depth; c[u_axis] = xx u; c[v_axis] = xx v;
swatch := trixel(trile, c);
c[axis] += sign;
if !swatch || trixel(trile, c) continue;
face := *mask[u][v];
face.swatch = swatch;
for corner: 0..3 {
side_u := c; side_u[u_axis] += xx ifx corner == 1 || corner == 2 then 1 else -1;
side_v := c; side_v[v_axis] += xx ifx corner >= 2 then 1 else -1;
diagonal := side_u; diagonal[v_axis] = side_v[v_axis];
a := trixel(trile, side_u) != 0;
b := trixel(trile, side_v) != 0;
d := trixel(trile, diagonal) != 0;
face.ao[corner] = xx ifx a && b then 0 else 3 - cast(int) a - cast(int) b - cast(int) d;
}
}
for u0: 0..15 for v0: 0..15 {
face := mask[u0][v0];
if !face.swatch continue;
// A face with an AO gradient keeps its own quad, so the gradient isn't stretched.
u1, v1 := u0 + 1, v0 + 1;
if flat(face) {
while v1 < 16 && mask[u0][v1] == face v1 += 1;
while u1 < 16 && row_matches(*mask, u1, v0, v1, face) u1 += 1;
}
for u: u0..u1-1 for v: v0..v1-1 mask[u][v] = .{};
plane := cast(float)(depth + ifx sign > 0 then 1 else 0);
corner :: (u: int, v: int, ao: u8) -> Trile_Vertex #expand {
p : Vector3;
p.component[`axis] = `plane * TRIXEL_SIZE;
p.component[`u_axis] = u * TRIXEL_SIZE;
p.component[`v_axis] = v * TRIXEL_SIZE;
return .{p, xx `face.swatch, ao / 3.0};
}
q := Trile_Vertex.[
corner(u0, v0, face.ao[0]),
corner(u1, v0, face.ao[1]),
corner(u1, v1, face.ao[2]),
corner(u0, v1, face.ao[3]),
];
if sign < 0 q[1], q[3] = q[3], q[1];
// Split along the brighter diagonal so AO interpolates evenly.
base := cast(u16) vertices.count;
array_add(*vertices, ..q);
if face.ao[0] + face.ao[2] < face.ao[1] + face.ao[3] {
for u16.[1, 2, 3, 1, 3, 0] array_add(*indices, base + it);
} else {
for u16.[0, 1, 2, 0, 2, 3] array_add(*indices, base + it);
}
}
}
}
return vertices, indices;
}
#scope_file
// ao is per corner in the order (u0, v0), (u1, v0), (u1, v1), (u0, v1); 3 = open.
Face :: struct {
swatch : u8;
ao : [4]u8;
}
operator == :: (a: Face, b: Face) -> bool {
return a.swatch == b.swatch && a.ao[0] == b.ao[0] && a.ao[1] == b.ao[1] && a.ao[2] == b.ao[2] && a.ao[3] == b.ao[3];
}
flat :: (face: Face) -> bool {
return face.ao[0] == face.ao[1] && face.ao[1] == face.ao[2] && face.ao[2] == face.ao[3];
}
row_matches :: (mask: *[16][16]Face, u: int, v0: int, v1: int, face: Face) -> bool {
for v: v0..v1-1 if mask.*[u][v] != face return false;
return true;
}
trixel :: (trile: *Trile, c: [3]s32) -> u8 {
for c if it < 0 || it > 15 return 0;
return trile.trixels[c[0]][c[1]][c[2]];
}