voxel-engine/src/Chunk.cpp
2025-11-24 13:08:22 -06:00

146 lines
4.9 KiB
C++

#include "Chunk.h"
#include <vector>
#include <iostream>
const int VERTEX_SIZE = 7; // x, y, z, nx, ny, nz, voxelKind
const float topFace[24] = {
// x, y, z, nx, ny, nz
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f
};
const float bottomFace[24] = {
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f
};
const float rightFace[24] = {
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f
};
const float leftFace[24] = {
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f
};
const float frontFace[24] = {
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f
};
const float backFace[24] = {
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f
};
void addFace(glm::ivec3 pos, const float *faceVertices, float voxelKind, std::vector<float> &vbo, std::vector<unsigned int> &ebo) {
unsigned int vIndex = vbo.size() / VERTEX_SIZE;
for (int i = 0; i < 4; i++) {
const float* v = &faceVertices[i * 6]; // Face data is still 6 floats per vertex
float world_x = v[0] + pos.x;
float world_y = v[1] + pos.y;
float world_z = v[2] + pos.z;
// Debug: Print first vertex of first face
// if (vbo.empty() && i == 0) {
// std::cout << "[MESH] First vertex - Local pos: (" << pos.x << ", " << pos.y << ", " << pos.z << ")" << std::endl;
// std::cout << "[MESH] First vertex - World: (" << world_x << ", " << world_y << ", " << world_z << ")" << std::endl;
// }
vbo.push_back(world_x);
vbo.push_back(world_y);
vbo.push_back(world_z);
vbo.push_back(v[3]);
vbo.push_back(v[4]);
vbo.push_back(v[5]);
vbo.push_back(voxelKind); // Add voxel kind as 7th component
}
ebo.push_back(vIndex + 0);
ebo.push_back(vIndex + 1);
ebo.push_back(vIndex + 2);
ebo.push_back(vIndex + 0);
ebo.push_back(vIndex + 2);
ebo.push_back(vIndex + 3);
}
Chunk::Chunk() {
this->data.fill(VoxelKind::Air);
}
Mesh* Chunk::getMesh() {
// Generate mesh on first access if not already generated, or if dirty
if ((!mesh || mesh_dirty) && !this->isEmpty()) {
generateMesh();
mesh_dirty = false;
}
return mesh.get();
}
void Chunk::generateMesh() {
std::vector<float> vboData;
std::vector<unsigned int> eboData;
// std::cout << "Generating Chunk mesh..." << std::endl;
const std::pair<glm::ivec3, const float*> neighbors[6] = {
std::pair(glm::ivec3(0, 1, 0), topFace), // top
std::pair(glm::ivec3(0, -1, 0), bottomFace), // bottom
std::pair(glm::ivec3(1, 0, 0), rightFace), // right
std::pair(glm::ivec3(-1, 0, 0), leftFace), // left
std::pair(glm::ivec3(0, 0, 1), frontFace), // front
std::pair(glm::ivec3(0, 0, -1), backFace) // back
};
for (int i = 0; i < TOTAL; ++i) {
VoxelKind kind = this->data[i];
if (kind == VoxelKind::Air) continue;
int x = i % SIZE;
int y = (i / SIZE) % SIZE;
int z = i / (SIZE * SIZE);
glm::ivec3 pos(x, y, z);
for (const auto& neighborPair : neighbors) {
glm::ivec3 dir = neighborPair.first;
const float* face = neighborPair.second;
int nx = x + dir.x;
int ny = y + dir.y;
int nz = z + dir.z;
bool neighbour_is_solid = false;
// in-bounds neighbor -> check data
if (nx >= 0 && nx < SIZE && ny >= 0 && ny < SIZE && nz >= 0 && nz < SIZE) {
// std::cout << "Accessing " << nx << ", " << ny << ", " << nz << std::endl;
neighbour_is_solid = (data[index(nx, ny, nz)] != VoxelKind::Air);
} else {
// neighbour out of this chunk: treat as air (exposed face)
// or call into World to query adjacent chunk here
neighbour_is_solid = false;
}
if (!neighbour_is_solid) {
addFace(pos, face, static_cast<float>(kind), vboData, eboData);
}
}
}
// Create and initialize mesh if it doesn't exist
if (!mesh) {
mesh = std::make_unique<Mesh>();
mesh->init();
}
// Now, upload this data to our mesh object
mesh->uploadData(vboData, eboData);
}