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 }; } }