add chunks

This commit is contained in:
Yggdrasil75
2026-01-19 07:12:20 -05:00
parent 1ae8514e01
commit a914e7a1f7

View File

@@ -54,6 +54,8 @@ struct Voxel {
bool active;
float alpha;
Vec3ui8 color;
Voxel() = default;
Voxel(float weight, bool active, float alpha, Vec3ui8 color) : weight(weight), active(active), alpha(alpha), color(color) {}
// TODO: add curving and similar for water and glass and so on.
auto members() const -> std::tuple<const float&, const bool&, const float&, const Vec3ui8&> {
return std::tie(weight, active, alpha, color);
@@ -113,6 +115,264 @@ struct Vertex {
Vertex(Vec3f pos, Vec3f norm, Vec3ui8 colr, Vec2f tex = Vec2f(0,0)) : position(pos), normal(norm), color(colr), texCoord(tex) {}
};
struct Chunk {
float weight;
bool active;
float alpha;
Vec3ui8 color;
std::vector<Voxel> voxels;
std::vector<Chunk> children;
Vec3i chunkSize;
Vec3i minCorner;
Vec3i maxCorner;
int depth;
Chunk() : depth(0) {}
Chunk(Vec3i minCorner, Vec3i maxCorner, int depth = 0) : minCorner(minCorner), maxCorner(maxCorner), depth(depth) {
chunkSize = maxCorner - minCorner;
voxels.resize(chunkSize.x * chunkSize.y * chunkSize.z);
}
bool inChunk(Vec3i pos) const {
if (pos.AllGT(minCorner) && pos.AllLT(maxCorner)) return true;
return false;
}
bool setRecurse(Vec3i pos, Voxel newVox) {
if (!inChunk(pos)) return false;
if (children.empty()) {
int index = getVoxelIndex(pos);
if (index >= 0 && index < static_cast<int>(voxels.size())) {
voxels[index] = newVox;
return true;
updateAverages();
}
return false;
}
for (Chunk& child : children) {
if (child.set(pos, newVox)) {
return true;
}
}
return false;
}
Voxel get(Vec3i pos, int maxDepth = 0) const {
if (!inChunk(pos)) {
return Voxel();
}
if (children.empty() || (maxDepth > 0 && depth >= maxDepth)) {
int index = getVoxelIndex(pos);
if (index >= 0 && index < static_cast<int>(voxels.size())) {
return voxels[index];
}
return Voxel();
} else if (maxDepth > 0 && depth >= maxDepth) {
return Voxel(weight, active, alpha, color);
}
for (const Chunk& child : children) {
if (child.inChunk(pos)) {
return child.get(pos, maxDepth);
}
}
return Voxel();
}
bool set(Vec3i pos, Voxel newVox) {
if (inChunk(pos)) {
int index = getVoxelIndex(pos);
voxels[index] = newVox;
if (newVox.active) {
updateAveragesRecursive();
return true;
}
}
return false;
}
int getVoxelIndex(Vec3i pos) const {
Vec3i localPos = pos - minCorner;
return localPos.z * chunkSize.x * chunkSize.y +
localPos.y * chunkSize.x +
localPos.x;
}
void updateAverages() {
if (voxels.empty()) {
weight = 0.0f;
alpha = 0.0f;
color = Vec3ui8(0, 0, 0);
active = false;
return;
}
float totalWeight = 0.0f;
float totalAlpha = 0.0f;
float totalR = 0.0f;
float totalG = 0.0f;
float totalB = 0.0f;
int activeCount = 0;
for (const Voxel& voxel : voxels) {
totalWeight += voxel.weight;
totalAlpha += voxel.alpha;
if (voxel.active) {
totalR += voxel.color.x;
totalG += voxel.color.y;
totalB += voxel.color.z;
activeCount++;
}
}
int voxelCount = voxels.size();
weight = totalWeight / voxelCount;
alpha = totalAlpha / voxelCount;
if (activeCount > 0) {
color = Vec3ui8(
static_cast<uint8_t>(totalR / activeCount),
static_cast<uint8_t>(totalG / activeCount),
static_cast<uint8_t>(totalB / activeCount)
);
active = true;
} else {
color = Vec3ui8(0, 0, 0);
active = false;
}
}
void updateAveragesRecursive() {
if (children.empty()) {
updateAverages();
} else {
// Update all children first
for (Chunk& child : children) {
child.updateAveragesRecursive();
}
// Then update this chunk based on children
if (children.empty()) return;
float totalWeight = 0.0f;
float totalAlpha = 0.0f;
float totalR = 0.0f;
float totalG = 0.0f;
float totalB = 0.0f;
int activeChildren = 0;
for (const Chunk& child : children) {
totalWeight += child.weight;
totalAlpha += child.alpha;
if (child.active) {
totalR += child.color.x;
totalG += child.color.y;
totalB += child.color.z;
activeChildren++;
}
}
int childCount = children.size();
weight = totalWeight / childCount;
alpha = totalAlpha / childCount;
if (activeChildren > 0) {
color = Vec3ui8(
static_cast<uint8_t>(totalR / activeChildren),
static_cast<uint8_t>(totalG / activeChildren),
static_cast<uint8_t>(totalB / activeChildren)
);
active = true;
} else {
color = Vec3ui8(0, 0, 0);
active = false;
}
}
}
void subdivide(int numChildrenPerAxis = 2) {
if (!children.empty()) return; // Already subdivided
Vec3i childSize = (maxCorner - minCorner) / numChildrenPerAxis;
for (int z = 0; z < numChildrenPerAxis; z++) {
for (int y = 0; y < numChildrenPerAxis; y++) {
for (int x = 0; x < numChildrenPerAxis; x++) {
Vec3i childMin = minCorner + Vec3i(x, y, z) * childSize;
Vec3i childMax = childMin + childSize;
Chunk child(childMin, childMax, depth + 1);
// Copy voxel data from parent to child
for (int cz = childMin.z; cz < childMax.z; cz++) {
for (int cy = childMin.y; cy < childMax.y; cy++) {
for (int cx = childMin.x; cx < childMax.x; cx++) {
Vec3i pos(cx, cy, cz);
int parentIndex = getVoxelIndex(pos);
if (parentIndex >= 0 && parentIndex < static_cast<int>(voxels.size())) {
int childLocalIndex = (cz - childMin.z) * childSize.x * childSize.y +
(cy - childMin.y) * childSize.x +
(cx - childMin.x);
if (childLocalIndex >= 0 && childLocalIndex < static_cast<int>(child.voxels.size())) {
child.voxels[childLocalIndex] = voxels[parentIndex];
}
}
}
}
}
children.push_back(child);
}
}
}
// Clear parent voxels after subdivision to save memory
voxels.clear();
voxels.shrink_to_fit();
}
void merge() {
if (children.empty()) return;
// Calculate total size from children
Vec3i totalSize(0, 0, 0);
for (const Chunk& child : children) {
totalSize = totalSize.max(child.maxCorner);
}
chunkSize = totalSize - minCorner;
// Resize voxels vector
voxels.resize(chunkSize.x * chunkSize.y * chunkSize.z);
// Copy data from children
for (const Chunk& child : children) {
for (int z = child.minCorner.z; z < child.maxCorner.z; z++) {
for (int y = child.minCorner.y; y < child.maxCorner.y; y++) {
for (int x = child.minCorner.x; x < child.maxCorner.x; x++) {
Vec3i pos(x, y, z);
Voxel voxel = child.get(pos);
int parentIndex = getVoxelIndex(pos);
if (parentIndex >= 0 && parentIndex < static_cast<int>(voxels.size())) {
voxels[parentIndex] = voxel;
}
}
}
}
}
// Clear children
children.clear();
children.shrink_to_fit();
}
};
class VoxelGrid {
private:
Vec3i gridSize;
@@ -182,7 +442,7 @@ public:
}
void set(Vec3i pos, bool active, Vec3ui8 color) {
if (pos.x >= 0 || pos.y >= 0 || pos.z >= 0) {
if (pos.x >= 0 && pos.y >= 0 && pos.z >= 0) {
if (!(pos.x < gridSize.x)) {
resize(pos.x, gridSize.y, gridSize.z);
}