503 lines
18 KiB
Plaintext
503 lines
18 KiB
Plaintext
Trile_Side :: enum_flags u8 {
|
|
TOP :: 0x1; // Larger Y
|
|
LEFT :: 0x2; // Larger Z
|
|
RIGHT :: 0x4; // Smaller Z
|
|
FRONT :: 0x8; // Larger X
|
|
BACK :: 0x10; // Smaller X
|
|
BOTTOM :: 0x20; // Smaller Ys
|
|
}
|
|
|
|
trileSideValues : [6]Trile_Side = .[.TOP, .LEFT, .RIGHT, .FRONT, .BACK, .BOTTOM];
|
|
|
|
sides_with_air_exposure :: (trileptr: *Trile, x: int, y: int, z: int) -> u8 {
|
|
res : u8 = 0;
|
|
if trileptr.trixels[x][y][z].empty then return res;
|
|
|
|
// Top
|
|
if y == 15 || trileptr.trixels[x][y+1][z].empty then res |= xx Trile_Side.TOP;
|
|
// Bottom
|
|
if y == 0 || trileptr.trixels[x][y-1][z].empty then res |= xx Trile_Side.BOTTOM;
|
|
// Left
|
|
if z == 15 || trileptr.trixels[x][y][z+1].empty then res |= xx Trile_Side.LEFT;
|
|
// Right
|
|
if z == 0 || trileptr.trixels[x][y][z-1].empty then res |= xx Trile_Side.RIGHT;
|
|
// Front
|
|
if x == 15 || trileptr.trixels[x+1][y][z].empty then res |= xx Trile_Side.FRONT;
|
|
// Back
|
|
if x == 0 || trileptr.trixels[x-1][y][z].empty then res |= xx Trile_Side.BACK;
|
|
|
|
return res;
|
|
}
|
|
|
|
draw_trile_side_triangles :: (vecs: *[]float, normals: *[]float, index: *int, side: Trile_Side, x: int, y: int, z: int) {
|
|
points : [4][3]float;
|
|
normal : [3]float;
|
|
|
|
if side == Trile_Side.TOP {
|
|
points[0][0] = 1; points[0][1] = 1; points[0][2] = 1;
|
|
points[1][0] = 1; points[1][1] = 1; points[1][2] = 0;
|
|
points[2][0] = 0; points[2][1] = 1; points[2][2] = 1;
|
|
points[3][0] = 0; points[3][1] = 1; points[3][2] = 0;
|
|
normal[0] = 0; normal[1] = 1; normal[2] = 0;
|
|
}
|
|
if side == Trile_Side.BOTTOM {
|
|
points[0][0] = 1; points[0][1] = 0; points[0][2] = 1;
|
|
points[2][0] = 1; points[2][1] = 0; points[2][2] = 0;
|
|
points[1][0] = 0; points[1][1] = 0; points[1][2] = 1;
|
|
points[3][0] = 0; points[3][1] = 0; points[3][2] = 0;
|
|
normal[0] = 0; normal[1] = -1; normal[2] = 0;
|
|
}
|
|
if side == Trile_Side.FRONT {
|
|
points[0][0] = 1; points[0][1] = 1; points[0][2] = 1;
|
|
points[2][0] = 1; points[2][1] = 1; points[2][2] = 0;
|
|
points[1][0] = 1; points[1][1] = 0; points[1][2] = 1;
|
|
points[3][0] = 1; points[3][1] = 0; points[3][2] = 0;
|
|
normal[0] = 1; normal[1] = 0; normal[2] = 0;
|
|
}
|
|
if side == Trile_Side.BACK {
|
|
points[0][0] = 0; points[0][1] = 1; points[0][2] = 1;
|
|
points[1][0] = 0; points[1][1] = 1; points[1][2] = 0;
|
|
points[2][0] = 0; points[2][1] = 0; points[2][2] = 1;
|
|
points[3][0] = 0; points[3][1] = 0; points[3][2] = 0;
|
|
normal[0] = -1; normal[1] = 0; normal[2] = 0;
|
|
}
|
|
if side == Trile_Side.LEFT {
|
|
points[0][0] = 1; points[0][1] = 1; points[0][2] = 1;
|
|
points[2][0] = 1; points[2][1] = 0; points[2][2] = 1;
|
|
points[1][0] = 0; points[1][1] = 1; points[1][2] = 1;
|
|
points[3][0] = 0; points[3][1] = 0; points[3][2] = 1;
|
|
normal[0] = 0; normal[1] = 0; normal[2] = 1;
|
|
}
|
|
if side == Trile_Side.RIGHT {
|
|
points[0][0] = 1; points[0][1] = 1; points[0][2] = 0;
|
|
points[1][0] = 1; points[1][1] = 0; points[1][2] = 0;
|
|
points[2][0] = 0; points[2][1] = 1; points[2][2] = 0;
|
|
points[3][0] = 0; points[3][1] = 0; points[3][2] = 0;
|
|
normal[0] = 0; normal[1] = 0; normal[2] = -1;
|
|
}
|
|
|
|
for 0..2 {
|
|
vecs.*[index.*] = (x + points[it][0]) * TRIXEL_SIZE;
|
|
vecs.*[index.*+1] = (y + points[it][1]) * TRIXEL_SIZE;
|
|
vecs.*[index.*+2] = (z + points[it][2]) * TRIXEL_SIZE;
|
|
normals.*[index.*] = normal[0];
|
|
normals.*[index.*+1] = normal[1];
|
|
normals.*[index.*+2] = normal[2];
|
|
index.* = index.* + 3;
|
|
}
|
|
|
|
for #v2 < 0..2 {
|
|
vecs.*[index.*] = (x + points[it][0]) * TRIXEL_SIZE;
|
|
vecs.*[index.*+1] = (y + points[it][1]) * TRIXEL_SIZE;
|
|
vecs.*[index.*+2] = (z + points[it][2]) * TRIXEL_SIZE;
|
|
normals.*[index.*] = normal[0];
|
|
normals.*[index.*+1] = normal[1];
|
|
normals.*[index.*+2] = normal[2];
|
|
index.* = index.* + 3;
|
|
}
|
|
}
|
|
|
|
draw_trile_side_quad :: (vecs: *[..]float, norms: *[..]float, side: Trile_Side, x: int, y: int, z: int) {
|
|
points : [4][3]float;
|
|
normal : [3]float;
|
|
|
|
if side == {
|
|
case Trile_Side.TOP;
|
|
points[0][0] = 1; points[0][1] = 1; points[0][2] = 1;
|
|
points[1][0] = 1; points[1][1] = 1; points[1][2] = 0;
|
|
points[2][0] = 0; points[2][1] = 1; points[2][2] = 1;
|
|
points[3][0] = 0; points[3][1] = 1; points[3][2] = 0;
|
|
normal[0] = 0; normal[1] = 1; normal[2] = 0;
|
|
case Trile_Side.BOTTOM;
|
|
points[0][0] = 1; points[0][1] = 0; points[0][2] = 1;
|
|
points[2][0] = 1; points[2][1] = 0; points[2][2] = 0;
|
|
points[1][0] = 0; points[1][1] = 0; points[1][2] = 1;
|
|
points[3][0] = 0; points[3][1] = 0; points[3][2] = 0;
|
|
normal[0] = 0; normal[1] = -1; normal[2] = 0;
|
|
case Trile_Side.FRONT;
|
|
points[0][0] = 1; points[0][1] = 1; points[0][2] = 1;
|
|
points[2][0] = 1; points[2][1] = 1; points[2][2] = 0;
|
|
points[1][0] = 1; points[1][1] = 0; points[1][2] = 1;
|
|
points[3][0] = 1; points[3][1] = 0; points[3][2] = 0;
|
|
normal[0] = 1; normal[1] = 0; normal[2] = 0;
|
|
case Trile_Side.BACK;
|
|
points[0][0] = 0; points[0][1] = 1; points[0][2] = 1;
|
|
points[1][0] = 0; points[1][1] = 1; points[1][2] = 0;
|
|
points[2][0] = 0; points[2][1] = 0; points[2][2] = 1;
|
|
points[3][0] = 0; points[3][1] = 0; points[3][2] = 0;
|
|
normal[0] = -1; normal[1] = 0; normal[2] = 0;
|
|
case Trile_Side.LEFT;
|
|
points[0][0] = 1; points[0][1] = 1; points[0][2] = 1;
|
|
points[2][0] = 1; points[2][1] = 0; points[2][2] = 1;
|
|
points[1][0] = 0; points[1][1] = 1; points[1][2] = 1;
|
|
points[3][0] = 0; points[3][1] = 0; points[3][2] = 1;
|
|
normal[0] = 0; normal[1] = 0; normal[2] = 1;
|
|
case Trile_Side.RIGHT;
|
|
points[0][0] = 1; points[0][1] = 1; points[0][2] = 0;
|
|
points[1][0] = 1; points[1][1] = 0; points[1][2] = 0;
|
|
points[2][0] = 0; points[2][1] = 1; points[2][2] = 0;
|
|
points[3][0] = 0; points[3][1] = 0; points[3][2] = 0;
|
|
normal[0] = 0; normal[1] = 0; normal[2] = -1;
|
|
}
|
|
|
|
order : [4]int = .[0,1,3,2];
|
|
coords : [3]int = .[x,y,z];
|
|
for i: 0..3 {
|
|
for j: 0..2 {
|
|
array_add(vecs, (coords[j]+points[order[i]][j])*TRIXEL_SIZE);
|
|
array_add(norms, normal[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
generate_basic_quad_mesh :: (trileptr: *Trile, vecs: *[..]float, norms: *[..]float) {
|
|
for x: 0..15 {
|
|
for y: 0..15 {
|
|
for z: 0..15 {
|
|
exposure: u8 = sides_with_air_exposure(trileptr, x, y, z);
|
|
for trileSideValues {
|
|
if (cast(u8)it) & exposure then draw_trile_side_quad(vecs, norms, it, x, y, z);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
quads_to_triangles :: (quadVecs: *[..]float, triangleVecs: *[..]float, quadNorms: *[..]float, triangleNorms: *[..]float) {
|
|
assert(quadVecs.count % (3*4) == 0);
|
|
assert(quadVecs.count == quadNorms.count);
|
|
i := 0;
|
|
while i < quadVecs.count {
|
|
quadStart : *float = *(quadVecs.*[i]);
|
|
normStart : *float = *(quadNorms.*[i]);
|
|
for j : 0..4 {
|
|
for k : 0..2 {
|
|
array_add(triangleVecs, quadStart[(j%4)*3+k]);
|
|
array_add(triangleNorms, normStart[(j%4)*3+k]);
|
|
}
|
|
if j == 2 {
|
|
for k : 0..2 {
|
|
//add the third point twice to get 2 triangles
|
|
array_add(triangleVecs, quadStart[(j%4)*3+k]);
|
|
array_add(triangleNorms, normStart[(j%4)*3+k]);
|
|
}
|
|
}
|
|
}
|
|
i += 3*4;
|
|
}
|
|
}
|
|
|
|
Quad :: struct {
|
|
topRight : Vector2;
|
|
bottomLeft : Vector2;
|
|
};
|
|
|
|
operator < :: (a: Quad, b: Quad) -> bool {
|
|
if a.topRight.x == b.topRight.x then return a.topRight.y < b.topRight.y;
|
|
return a.topRight.x < b.topRight.x;
|
|
}
|
|
|
|
quad_comp :: (a: Quad, b: Quad) -> bool {
|
|
if a.topRight != b.topRight then return false;
|
|
if a.bottomLeft != b.bottomLeft then return false;
|
|
return true;
|
|
}
|
|
|
|
quad_hash :: (q: Quad) -> u32 {
|
|
return sdbm_hash(*q, size_of(Quad));
|
|
}
|
|
|
|
Quad_Set :: Table(Quad, bool, quad_hash, quad_comp);
|
|
Quads :: [6][..]Quad_Set;
|
|
|
|
side_to_quad_list_index :: (side: Trile_Side) -> s32 {
|
|
if #complete side == {
|
|
case Trile_Side.TOP;
|
|
return 0;
|
|
case Trile_Side.BOTTOM;
|
|
return 1;
|
|
case Trile_Side.FRONT;
|
|
return 2;
|
|
case Trile_Side.BACK;
|
|
return 3;
|
|
case Trile_Side.LEFT;
|
|
return 4;
|
|
case Trile_Side.RIGHT;
|
|
return 5;
|
|
}
|
|
}
|
|
|
|
init_quads :: (quads: *Quads) { // NOTE: unsure about if this is correctly ported.
|
|
for side : trileSideValues {
|
|
idx := side_to_quad_list_index(side);
|
|
for i : 0..15 {
|
|
quadset : Quad_Set;
|
|
table_add(*quadset, .{.{16,16}, .{0,0}}, true);
|
|
array_add(*(quads.*[idx]), quadset);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Looking at the side, what axis should be used as x,y and z,
|
|
// so that x and z are parallel to the side.
|
|
// (And not all of it seems to work when the used x and y and normal of the side abide by the left hand rule)
|
|
change_perspective :: (x: *$T, y: *T, z: *T, side: Trile_Side) -> (*T,*T,*T) {
|
|
if #complete side == {
|
|
case Trile_Side.TOP;
|
|
return x, z, y;
|
|
case Trile_Side.BOTTOM;
|
|
return z, x, y;
|
|
case Trile_Side.FRONT;
|
|
return z, y, x;
|
|
case Trile_Side.BACK;
|
|
return y, z, x;
|
|
case Trile_Side.LEFT;
|
|
return y, x, z;
|
|
case Trile_Side.RIGHT;
|
|
return x, y, z;
|
|
}
|
|
}
|
|
|
|
quad2d_add_to_quads3d :: (quads2d: *[..]Vector2, quads3d: *[..]Vector3, side: Trile_Side, depth: int, normals: *[..]float) {
|
|
x, y, z : float;
|
|
normal : [3]float;
|
|
offset : float = 0.0;
|
|
|
|
ux, uy, uz := change_perspective(*x, *y, *z, side);
|
|
|
|
if side == {
|
|
case Trile_Side.TOP;
|
|
normal[0] = 0;
|
|
normal[1] = 1;
|
|
normal[2] = 0;
|
|
offset = 1;
|
|
case Trile_Side.BOTTOM;
|
|
normal[0] = 0;
|
|
normal[1] = -1;
|
|
normal[2] = 0;
|
|
case Trile_Side.FRONT;
|
|
normal[0] = 1;
|
|
normal[1] = 0;
|
|
normal[2] = 0;
|
|
offset = 1;
|
|
case Trile_Side.BACK;
|
|
normal[0] = -1;
|
|
normal[1] = 0;
|
|
normal[2] = 0;
|
|
case Trile_Side.LEFT;
|
|
normal[0] = 0;
|
|
normal[1] = 0;
|
|
normal[2] = 1;
|
|
offset = 1;
|
|
case Trile_Side.RIGHT;
|
|
normal[0] = 0;
|
|
normal[1] = 0;
|
|
normal[2] = -1;
|
|
}
|
|
|
|
for quad : quads2d.* {
|
|
uz.* = (depth + offset) * TRIXEL_SIZE;
|
|
ux.* = quad.x * TRIXEL_SIZE;
|
|
uy.* = quad.y * TRIXEL_SIZE;
|
|
|
|
array_add(quads3d, .{x,y,z});
|
|
array_add(normals, normal[0]);
|
|
array_add(normals, normal[1]);
|
|
array_add(normals, normal[2]);
|
|
}
|
|
}
|
|
|
|
quads_to_vecs :: (quads: *Quads, vecs: *[..]float, normals: *[..]float) {
|
|
quads3d : [..]Vector3;
|
|
|
|
for side : trileSideValues {
|
|
idx := side_to_quad_list_index(side);
|
|
for 0..quads.*[idx].count-1 {
|
|
quads2d : [..]Vector2;
|
|
table := *(quads.*[idx][it]);
|
|
for k, v : table {
|
|
array_add(*quads2d, v.bottomLeft);
|
|
array_add(*quads2d, .{v.bottomLeft.x, v.topRight.y});
|
|
array_add(*quads2d, v.topRight);
|
|
array_add(*quads2d, .{v.topRight.x, v.bottomLeft.y});
|
|
}
|
|
quad2d_add_to_quads3d(*quads2d, *quads3d, side, it, normals);
|
|
}
|
|
}
|
|
for quad : quads3d {
|
|
array_add(vecs, quad.x);
|
|
array_add(vecs, quad.y);
|
|
array_add(vecs, quad.z);
|
|
}
|
|
}
|
|
|
|
a_is_inside_b :: (a: Quad, b: Quad) -> bool {
|
|
if (b.topRight.x >= a.topRight.x) && (b.topRight.y >= a.topRight.y) {
|
|
if (b.bottomLeft.x <= a.bottomLeft.x) && (b.bottomLeft.y <= a.bottomLeft.y) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
remove_quad :: (quad: Quad, quadSet: *Quad_Set) {
|
|
parent : Quad;
|
|
|
|
for v, k : quadSet {
|
|
if k < quad then continue;
|
|
if a_is_inside_b(quad, k) {
|
|
parent = k;
|
|
table_remove(quadSet, k);
|
|
break;
|
|
}
|
|
}
|
|
|
|
topLeft : Vector2 = .{quad.bottomLeft.x,quad.topRight.y};
|
|
bottomRight : Vector2 = .{quad.topRight.x,quad.bottomLeft.y};
|
|
|
|
if quad.topRight.x != parent.topRight.x {
|
|
table_add(quadSet, .{parent.topRight,bottomRight}, true);
|
|
}
|
|
|
|
if quad.topRight.y != parent.topRight.y {
|
|
table_add(quadSet, .{.{quad.topRight.x,parent.topRight.y},.{parent.bottomLeft.x,quad.topRight.y}}, true);
|
|
}
|
|
if quad.bottomLeft.y != parent.bottomLeft.y {
|
|
table_add(quadSet, .{.{parent.topRight.x,quad.bottomLeft.y},.{quad.bottomLeft.x,parent.bottomLeft.y}}, true);
|
|
}
|
|
if quad.bottomLeft.x != parent.bottomLeft.x {
|
|
table_add(quadSet, .{topLeft,parent.bottomLeft}, true);
|
|
}
|
|
}
|
|
|
|
remove_not_seen :: (trilept: *Trile, quads: *Quads) {
|
|
for x: 0..15 {
|
|
for y: 0..15 {
|
|
for z: 0..15 {
|
|
exposure: u8 = sides_with_air_exposure(trilept, x, y, z);
|
|
for side: trileSideValues {
|
|
if !((cast(u8)side) & exposure) {
|
|
ux, uy, uz := change_perspective(*x, *y, *z, side);
|
|
remove_quad(.{.{cast(float)ux.*+1, cast(float)uy.*+1}, .{cast(float)ux.*, cast(float)uy.*}}, *quads.*[side_to_quad_list_index(side)][uz.*]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
generate_optimized_quad_mesh :: (trilept: *Trile, vecs: *[..]float, normals: *[..]float) {
|
|
quads : Quads;
|
|
init_quads(*quads);
|
|
remove_not_seen(trilept, *quads);
|
|
quads_to_vecs(*quads, vecs, normals);
|
|
}
|
|
|
|
Pool :: #import "Pool";
|
|
meshgenpool : Pool.Pool;
|
|
|
|
generate_trile_gfx_matias :: (trileptr : *Trile) -> Trile_GFX {
|
|
if !meshgenpool.block_allocator.proc then Pool.set_allocators(*meshgenpool); // @ToDo: Only do this if we haven't yet done it.
|
|
|
|
old_alloc := context.allocator;
|
|
new_context := context;
|
|
new_context.allocator = .{Pool.pool_allocator_proc, *meshgenpool};
|
|
push_context new_context {
|
|
triangleVecs : [..]float;
|
|
triangleNorms : [..]float;
|
|
quadVecs : [..]float;
|
|
quadNorms : [..]float;
|
|
|
|
generate_optimized_quad_mesh(trileptr,*quadVecs,*quadNorms);
|
|
|
|
quads_to_triangles(*quadVecs, *triangleVecs,*quadNorms, *triangleNorms);
|
|
|
|
trile_vert_buffer_info := sg_buffer_desc.{ data = .{ ptr = triangleVecs.data, size = xx (triangleVecs.count * 4) } };
|
|
trile_vert_buffer := sg_make_buffer(*trile_vert_buffer_info);
|
|
|
|
trile_normal_buffer_info := sg_buffer_desc.{ data = .{ ptr = triangleNorms.data, size = xx (triangleNorms.count * 4) } };
|
|
trile_normal_buffer := sg_make_buffer(*trile_normal_buffer_info);
|
|
|
|
print("Successfully generated mesh for trile with % triangles.\n", triangleVecs.count / 3 / 3);
|
|
|
|
centres : [..]float;
|
|
|
|
// Generate triangle centers.
|
|
for 0..(triangleVecs.count/3/3)-1 {
|
|
x1 := triangleVecs[it * 9 + 0];
|
|
x2 := triangleVecs[it * 9 + 3];
|
|
x3 := triangleVecs[it * 9 + 6];
|
|
xr := (x1+x2+x3) / 3.0;
|
|
|
|
y1 := triangleVecs[it * 9 + 1];
|
|
y2 := triangleVecs[it * 9 + 4];
|
|
y3 := triangleVecs[it * 9 + 7];
|
|
yr := (y1+y2+y3) / 3.0;
|
|
|
|
z1 := triangleVecs[it * 9 + 2];
|
|
z2 := triangleVecs[it * 9 + 5];
|
|
z3 := triangleVecs[it * 9 + 8];
|
|
zr := (z1+z2+z3) / 3.0;
|
|
|
|
for 0..2 {
|
|
array_add(*centres, xr);
|
|
array_add(*centres, yr);
|
|
array_add(*centres, zr);
|
|
}
|
|
}
|
|
|
|
trile_centre_buffer_info := sg_buffer_desc.{ data = .{ ptr = centres.data, size = xx (centres.count * 4) } };
|
|
trile_centre_buffer := sg_make_buffer(*trile_centre_buffer_info);
|
|
|
|
// Create the texture for the trile, from which it gets it's colors for trixels.
|
|
|
|
materialdata : [16*16*16*4]u8;
|
|
counter : int = 0;
|
|
|
|
for x: 0..15 {
|
|
for y: 0..15 {
|
|
for z: 0..15 {
|
|
if trileptr.trixels[x][y][z].empty {
|
|
// @ToDo: add some null pattern here to help in shader side.
|
|
materialdata[counter + 0] = 0;
|
|
materialdata[counter + 1] = 0;
|
|
materialdata[counter + 2] = 0;
|
|
materialdata[counter + 3] = 0;
|
|
counter += 4;
|
|
} else {
|
|
r,g,b,a := material_to_rgba(trileptr.trixels[x][y][z].material);
|
|
materialdata[counter + 0] = r;
|
|
materialdata[counter + 1] = g;
|
|
materialdata[counter + 2] = b;
|
|
materialdata[counter + 3] = a;
|
|
counter += 4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
imgdata : sg_image_data;
|
|
imgdata.subimage[0][0] = .{materialdata.data, materialdata.count};
|
|
|
|
texdesc : sg_image_desc = .{
|
|
render_target = false,
|
|
width = 16,
|
|
height = 16*16,
|
|
pixel_format = sg_pixel_format.RGBA8,
|
|
sample_count = 1,
|
|
data = imgdata
|
|
};
|
|
|
|
img := sg_make_image(*texdesc);
|
|
|
|
state := sg_query_image_state(img);
|
|
print("IMG: %\n", state);
|
|
|
|
context.allocator = old_alloc;
|
|
vecsCopy := array_copy(triangleVecs);
|
|
Pool.reset(*meshgenpool);
|
|
return .{ img, trile_vert_buffer, trile_normal_buffer, trile_centre_buffer, vecsCopy, triangleVecs.count / 3 };
|
|
}
|
|
}
|