Trile_Side :: enum_flags u8 { TOP :: 0x0; // Larger Y LEFT :: 0x1; // 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) { if 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 { qlist := *quads[idx]; array_add(qlist, .{}); table_add(qlist[i], .{.{16,16}, .{0,0}}, true); } } } // 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 side == { case Trile_Side.TOP; return y, x, z; case Trile_Side.BOTTOM; return y, z, x; case Trile_Side.FRONT; return x, z, y; case Trile_Side.BACK; return x, y, z; case Trile_Side.LEFT; return z, y, x; case Trile_Side.RIGHT; return z, x, y; } } quad2d_add_to_quads_3d :: (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; for quad : it { array_add(*quads2d, quad.bottomLeft); array_add(*quads2d, .{quad.bottomLeft.x, quad.topRight.y}); array_add(*quads2d, quad.topRight); array_add(*quads2d, .{quad.topRight.x, quad.bottomLeft.y}); } quad2_add_to_quads3d(*quads2d, *quads3d, side, it, normals); } } } /* void quadsToVecs(Quads& quads, std::vector& vecs, std::vector& normals){ std::vector quads3d; for(TrileSide side : TrileSideValues){ for(int i=0; i quads2d; for(Quad quad : quads[side][i]){ quads2d.push_back(quad.bottomLeft); quads2d.push_back({quad.bottomLeft.x,quad.topRight.y}); quads2d.push_back(quad.topRight); quads2d.push_back({quad.topRight.x,quad.bottomLeft.y}); } quad2dAddToQuads3d(quads2d,quads3d,side,i,normals); } } for(Vector3 quad : quads3d) { vecs.push_back(quad.x); vecs.push_back(quad.y); vecs.push_back(quad.z); } } bool isInsideOther(Quad a, Quad other){ if( (other.topRight.x >= a.topRight.x) && (other.topRight.y >= a.topRight.y)){ if( (other.bottomLeft.x <= a.bottomLeft.x) && (other.bottomLeft.y <= a.bottomLeft.y) ){ return true; } } return false; } void removeQuad(Quad quad, std::set& quadSet){ auto parentIt = quadSet.lower_bound(quad); while(!isInsideOther(quad,*parentIt)){ parentIt++; //The "parent"quad should always be found before reaching set end } Quad parent = *parentIt; quadSet.erase(parentIt); Vector2 topLeft = {quad.bottomLeft.x,quad.topRight.y}; Vector2 bottomRight = {quad.topRight.x,quad.bottomLeft.y}; if(quad.topRight.x != parent.topRight.x){ quadSet.insert({parent.topRight,bottomRight}); } if(quad.topRight.y != parent.topRight.y){ quadSet.insert({quad.topRight.x,parent.topRight.y,parent.bottomLeft.x,quad.topRight.y}); } if(quad.bottomLeft.y != parent.bottomLeft.y){ quadSet.insert({parent.topRight.x,quad.bottomLeft.y,quad.bottomLeft.x,parent.bottomLeft.y}); } if(quad.bottomLeft.x != parent.bottomLeft.x){ quadSet.insert({topLeft,parent.bottomLeft}); } } void removeNotSeen(Trile *trilept, Quads& quads){ for(int x = 0; x < 16; x++) { for(int y = 0; y < 16; y++){ for(int z = 0; z < 16; z++) { // Check for "air" contact on each side of the trixel. char exposure = SidesWithAirExposure(trilept, x, y, z); for(TrileSide side : TrileSideValues){ if( !(side & exposure)){ int *ux,*uy,*uz; changePerspective(&x,&y,&z,ux,uy,uz,side); removeQuad(Quad{(float)*ux+1,(float)*uy+1,(float)*ux,(float)*uy},quads[side][*uz]); } } } } } } void generateOptimizedQuadMesh(Trile *trilept, std::vector& vecs, std::vector& normals){ Quads quads; initQuads(quads); removeNotSeen(trilept,quads); quadsToVecs(quads,vecs,normals); } Mesh GenerateMeshMatias(Trile *trileptr){ std::vector quadVecs; std::vector triangleVecs; std::vector quadNorms; std::vector triangleNorms; Mesh temp = {}; generateOptimizedQuadMesh(trileptr,quadVecs,quadNorms); //generateBasicQuadMesh(trileptr,quadVecs,quadNorms); quadsToTriangles(quadVecs, triangleVecs,quadNorms, triangleNorms); temp.vertexCount = triangleVecs.size() / 3; temp.triangleCount = temp.vertexCount / 3; float* vecs = new float[triangleVecs.size()]; float* norms = new float[triangleNorms.size()]; for(int i=0; i