work on porting mesh generation

This commit is contained in:
Tuomas Katajisto 2025-07-03 23:57:55 +03:00
parent b307bb2a93
commit 169985481c
3 changed files with 443 additions and 0 deletions

View File

@ -1,6 +1,8 @@
#import "Basic"; #import "Basic";
#import "Math"; #import "Math";
#import "Input"; #import "Input";
#import "Hash_Table";
#import "Hash";
stbi :: #import "stb_image"; stbi :: #import "stb_image";
#load "trile.jai"; #load "trile.jai";

439
src/meshgen.jai Normal file
View File

@ -0,0 +1,439 @@
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<float>& vecs, std::vector<float>& normals){
std::vector<Vector3> quads3d;
for(TrileSide side : TrileSideValues){
for(int i=0; i<quads[side].size(); i++){
std::vector<Vector2> 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<Quad>& 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<float>& vecs, std::vector<float>& normals){
Quads quads;
initQuads(quads);
removeNotSeen(trilept,quads);
quadsToVecs(quads,vecs,normals);
}
Mesh GenerateMeshMatias(Trile *trileptr){
std::vector<float> quadVecs;
std::vector<float> triangleVecs;
std::vector<float> quadNorms;
std::vector<float> 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<triangleVecs.size(); i++){
vecs[i] = triangleVecs[i];
norms[i] = triangleNorms[i];
}
temp.vertices = vecs;
temp.normals = norms;
return temp;
}
*/

View File

@ -1,3 +1,5 @@
#load "meshgen.jai";
Material :: struct { Material :: struct {
roughness : float = 0.5; roughness : float = 0.5;
metallic : float = 0; metallic : float = 0;