mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 19:28:49 -04:00
Remove locking from the mesh loading code.
This makes it easier to work with.
This commit is contained in:
parent
49179d0891
commit
021f762c01
230
src/chunk.zig
230
src/chunk.zig
@ -639,12 +639,10 @@ pub const meshing = struct {
|
||||
};
|
||||
pos: ChunkPosition,
|
||||
size: i32,
|
||||
chunk: std.atomic.Atomic(?*Chunk),
|
||||
chunk: *Chunk,
|
||||
opaqueMesh: PrimitiveMesh,
|
||||
voxelMesh: PrimitiveMesh,
|
||||
transparentMesh: PrimitiveMesh,
|
||||
generated: bool = false,
|
||||
mutex: std.Thread.Mutex = std.Thread.Mutex{},
|
||||
visibilityMask: u8 = 0xff,
|
||||
currentSorting: []SortingData = &.{},
|
||||
sortingOutputBuffer: []FaceData = &.{},
|
||||
@ -653,7 +651,7 @@ pub const meshing = struct {
|
||||
|
||||
chunkBorders: [6]BoundingRectToNeighborChunk = [1]BoundingRectToNeighborChunk{.{}} ** 6,
|
||||
|
||||
pub fn init(allocator: Allocator, pos: ChunkPosition) ChunkMesh {
|
||||
pub fn init(allocator: Allocator, pos: ChunkPosition, chunk: *Chunk) ChunkMesh {
|
||||
return ChunkMesh{
|
||||
.pos = pos,
|
||||
.size = chunkSize*pos.voxelSize,
|
||||
@ -666,7 +664,7 @@ pub const meshing = struct {
|
||||
.transparentMesh = .{
|
||||
.faces = std.ArrayList(FaceData).init(allocator)
|
||||
},
|
||||
.chunk = std.atomic.Atomic(?*Chunk).init(null),
|
||||
.chunk = chunk,
|
||||
};
|
||||
}
|
||||
|
||||
@ -676,9 +674,7 @@ pub const meshing = struct {
|
||||
self.transparentMesh.deinit();
|
||||
main.globalAllocator.free(self.currentSorting);
|
||||
main.globalAllocator.free(self.sortingOutputBuffer);
|
||||
if(self.chunk.load(.Monotonic)) |ch| {
|
||||
main.globalAllocator.destroy(ch);
|
||||
}
|
||||
main.globalAllocator.destroy(self.chunk);
|
||||
}
|
||||
|
||||
pub fn isEmpty(self: *const ChunkMesh) bool {
|
||||
@ -705,8 +701,7 @@ pub const meshing = struct {
|
||||
);
|
||||
}
|
||||
|
||||
pub fn regenerateMainMesh(self: *ChunkMesh, chunk: *Chunk) !void {
|
||||
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
|
||||
pub fn regenerateMainMesh(self: *ChunkMesh) !void {
|
||||
self.opaqueMesh.reset();
|
||||
self.voxelMesh.reset();
|
||||
self.transparentMesh.reset();
|
||||
@ -717,7 +712,7 @@ pub const meshing = struct {
|
||||
while(y < chunkSize): (y += 1) {
|
||||
var z: u8 = 0;
|
||||
while(z < chunkSize): (z += 1) {
|
||||
const block = (&chunk.blocks)[getIndex(x, y, z)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
const block = (&self.chunk.blocks)[getIndex(x, y, z)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
if(block.typ == 0) continue;
|
||||
// Check all neighbors:
|
||||
for(Neighbors.iterable) |i| {
|
||||
@ -726,7 +721,7 @@ pub const meshing = struct {
|
||||
const y2 = y + Neighbors.relY[i];
|
||||
const z2 = z + Neighbors.relZ[i];
|
||||
if(x2&chunkMask != x2 or y2&chunkMask != y2 or z2&chunkMask != z2) continue; // Neighbor is outside the chunk.
|
||||
const neighborBlock = (&chunk.blocks)[getIndex(x2, y2, z2)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
const neighborBlock = (&self.chunk.blocks)[getIndex(x2, y2, z2)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
if(canBeSeenThroughOtherBlock(block, neighborBlock, i)) {
|
||||
if(block.transparent()) {
|
||||
if(block.hasBackFace()) {
|
||||
@ -750,25 +745,21 @@ pub const meshing = struct {
|
||||
while(x < chunkSize): (x += 1) {
|
||||
var y: u8 = 0;
|
||||
while(y < chunkSize): (y += 1) {
|
||||
self.chunkBorders[Neighbors.dirNegX].adjustToBlock((&chunk.blocks)[getIndex(0, x, y)], .{0, x, y}, Neighbors.dirNegX); // TODO: Wait for the compiler bug to get fixed.
|
||||
self.chunkBorders[Neighbors.dirPosX].adjustToBlock((&chunk.blocks)[getIndex(chunkSize-1, x, y)], .{chunkSize, x, y}, Neighbors.dirPosX); // TODO: Wait for the compiler bug to get fixed.
|
||||
self.chunkBorders[Neighbors.dirDown].adjustToBlock((&chunk.blocks)[getIndex(x, 0, y)], .{x, 0, y}, Neighbors.dirDown); // TODO: Wait for the compiler bug to get fixed.
|
||||
self.chunkBorders[Neighbors.dirUp].adjustToBlock((&chunk.blocks)[getIndex(x, chunkSize-1, y)], .{x, chunkSize, y}, Neighbors.dirUp); // TODO: Wait for the compiler bug to get fixed.
|
||||
self.chunkBorders[Neighbors.dirNegZ].adjustToBlock((&chunk.blocks)[getIndex(x, y, 0)], .{x, y, 0}, Neighbors.dirNegZ); // TODO: Wait for the compiler bug to get fixed.
|
||||
self.chunkBorders[Neighbors.dirPosZ].adjustToBlock((&chunk.blocks)[getIndex(x, y, chunkSize-1)], .{x, y, chunkSize}, Neighbors.dirPosZ); // TODO: Wait for the compiler bug to get fixed.
|
||||
self.chunkBorders[Neighbors.dirNegX].adjustToBlock((&self.chunk.blocks)[getIndex(0, x, y)], .{0, x, y}, Neighbors.dirNegX); // TODO: Wait for the compiler bug to get fixed.
|
||||
self.chunkBorders[Neighbors.dirPosX].adjustToBlock((&self.chunk.blocks)[getIndex(chunkSize-1, x, y)], .{chunkSize, x, y}, Neighbors.dirPosX); // TODO: Wait for the compiler bug to get fixed.
|
||||
self.chunkBorders[Neighbors.dirDown].adjustToBlock((&self.chunk.blocks)[getIndex(x, 0, y)], .{x, 0, y}, Neighbors.dirDown); // TODO: Wait for the compiler bug to get fixed.
|
||||
self.chunkBorders[Neighbors.dirUp].adjustToBlock((&self.chunk.blocks)[getIndex(x, chunkSize-1, y)], .{x, chunkSize, y}, Neighbors.dirUp); // TODO: Wait for the compiler bug to get fixed.
|
||||
self.chunkBorders[Neighbors.dirNegZ].adjustToBlock((&self.chunk.blocks)[getIndex(x, y, 0)], .{x, y, 0}, Neighbors.dirNegZ); // TODO: Wait for the compiler bug to get fixed.
|
||||
self.chunkBorders[Neighbors.dirPosZ].adjustToBlock((&self.chunk.blocks)[getIndex(x, y, chunkSize-1)], .{x, y, chunkSize}, Neighbors.dirPosZ); // TODO: Wait for the compiler bug to get fixed.
|
||||
}
|
||||
}
|
||||
|
||||
if(self.chunk.swap(chunk, .Monotonic)) |oldChunk| {
|
||||
main.globalAllocator.destroy(oldChunk);
|
||||
}
|
||||
self.transparentMesh.updateCore();
|
||||
self.opaqueMesh.updateCore();
|
||||
self.voxelMesh.updateCore();
|
||||
}
|
||||
|
||||
fn addFace(self: *ChunkMesh, faceData: FaceData, fromNeighborChunk: ?u3, transparent: bool) !void {
|
||||
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
|
||||
if(transparent) {
|
||||
try self.transparentMesh.addFace(faceData, fromNeighborChunk);
|
||||
} else {
|
||||
@ -781,7 +772,6 @@ pub const meshing = struct {
|
||||
}
|
||||
|
||||
fn removeFace(self: *ChunkMesh, faceData: FaceData, fromNeighborChunk: ?u3, transparent: bool) void {
|
||||
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
|
||||
if(transparent) {
|
||||
self.transparentMesh.removeFace(faceData, fromNeighborChunk);
|
||||
} else {
|
||||
@ -797,10 +787,7 @@ pub const meshing = struct {
|
||||
const x = _x & chunkMask;
|
||||
const y = _y & chunkMask;
|
||||
const z = _z & chunkMask;
|
||||
self.mutex.lock();
|
||||
defer self.mutex.unlock();
|
||||
if(!self.generated) return;
|
||||
const oldBlock = self.chunk.load(.Monotonic).?.blocks[getIndex(x, y, z)];
|
||||
const oldBlock = self.chunk.blocks[getIndex(x, y, z)];
|
||||
for(Neighbors.iterable) |neighbor| {
|
||||
var neighborMesh = self;
|
||||
var nx = x + Neighbors.relX[neighbor];
|
||||
@ -808,14 +795,11 @@ pub const meshing = struct {
|
||||
var nz = z + Neighbors.relZ[neighbor];
|
||||
if(nx & chunkMask != nx or ny & chunkMask != ny or nz & chunkMask != nz) { // Outside this chunk.
|
||||
neighborMesh = renderer.RenderStructure.getNeighbor(self.pos, self.pos.voxelSize, neighbor) orelse continue;
|
||||
if(!neighborMesh.generated) continue;
|
||||
neighborMesh.mutex.lock();
|
||||
}
|
||||
defer if(neighborMesh != self) neighborMesh.mutex.unlock();
|
||||
nx &= chunkMask;
|
||||
ny &= chunkMask;
|
||||
nz &= chunkMask;
|
||||
const neighborBlock = neighborMesh.chunk.load(.Monotonic).?.blocks[getIndex(nx, ny, nz)];
|
||||
const neighborBlock = neighborMesh.chunk.blocks[getIndex(nx, ny, nz)];
|
||||
{ // TODO: Batch all the changes and apply them in one go for more efficiency.
|
||||
{ // The face of the changed block
|
||||
const newVisibility = canBeSeenThroughOtherBlock(newBlock, neighborBlock, neighbor);
|
||||
@ -896,7 +880,7 @@ pub const meshing = struct {
|
||||
try neighborMesh.transparentMesh.uploadData();
|
||||
}
|
||||
}
|
||||
self.chunk.load(.Monotonic).?.blocks[getIndex(x, y, z)] = newBlock;
|
||||
self.chunk.blocks[getIndex(x, y, z)] = newBlock;
|
||||
try self.opaqueMesh.uploadData();
|
||||
try self.voxelMesh.uploadData();
|
||||
try self.transparentMesh.uploadData();
|
||||
@ -911,8 +895,6 @@ pub const meshing = struct {
|
||||
}
|
||||
|
||||
pub fn uploadDataAndFinishNeighbors(self: *ChunkMesh) !void {
|
||||
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
|
||||
const chunk = self.chunk.load(.Monotonic) orelse return; // In the mean-time the mesh was discarded and recreated and all the data was lost.
|
||||
self.opaqueMesh.resetToCore();
|
||||
self.voxelMesh.resetToCore();
|
||||
self.transparentMesh.resetToCore();
|
||||
@ -923,87 +905,13 @@ pub const meshing = struct {
|
||||
const nullNeighborMesh = renderer.RenderStructure.getNeighbor(self.pos, self.pos.voxelSize, neighbor);
|
||||
if(nullNeighborMesh) |neighborMesh| {
|
||||
std.debug.assert(neighborMesh != self);
|
||||
neighborMesh.mutex.lock();
|
||||
defer neighborMesh.mutex.unlock();
|
||||
if(neighborMesh.generated) {
|
||||
var additionalNeighborFacesOpaque = std.ArrayList(FaceData).init(main.threadAllocator);
|
||||
defer additionalNeighborFacesOpaque.deinit();
|
||||
var additionalNeighborFacesVoxel = std.ArrayList(FaceData).init(main.threadAllocator);
|
||||
defer additionalNeighborFacesVoxel.deinit();
|
||||
var additionalNeighborFacesTransparent = std.ArrayList(FaceData).init(main.threadAllocator);
|
||||
defer additionalNeighborFacesTransparent.deinit();
|
||||
const x3: u8 = if(neighbor & 1 == 0) @intCast(chunkMask) else 0;
|
||||
var x1: u8 = 0;
|
||||
while(x1 < chunkSize): (x1 += 1) {
|
||||
var x2: u8 = 0;
|
||||
while(x2 < chunkSize): (x2 += 1) {
|
||||
var x: u8 = undefined;
|
||||
var y: u8 = undefined;
|
||||
var z: u8 = undefined;
|
||||
if(Neighbors.relX[neighbor] != 0) {
|
||||
x = x3;
|
||||
y = x1;
|
||||
z = x2;
|
||||
} else if(Neighbors.relY[neighbor] != 0) {
|
||||
x = x1;
|
||||
y = x3;
|
||||
z = x2;
|
||||
} else {
|
||||
x = x2;
|
||||
y = x1;
|
||||
z = x3;
|
||||
}
|
||||
const otherX: u8 = @intCast(x+%Neighbors.relX[neighbor] & chunkMask);
|
||||
const otherY: u8 = @intCast(y+%Neighbors.relY[neighbor] & chunkMask);
|
||||
const otherZ: u8 = @intCast(z+%Neighbors.relZ[neighbor] & chunkMask);
|
||||
const block = (&chunk.blocks)[getIndex(x, y, z)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
const otherBlock = (&neighborMesh.chunk.load(.Monotonic).?.blocks)[getIndex(otherX, otherY, otherZ)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
if(canBeSeenThroughOtherBlock(block, otherBlock, neighbor)) {
|
||||
if(block.transparent()) {
|
||||
if(block.hasBackFace()) {
|
||||
try self.transparentMesh.append(constructFaceData(block, neighbor ^ 1, x, y, z, true));
|
||||
}
|
||||
try additionalNeighborFacesTransparent.append(constructFaceData(block, neighbor, otherX, otherY, otherZ, false));
|
||||
} else {
|
||||
if(blocks.meshes.model(block).modelIndex == 0) {
|
||||
try additionalNeighborFacesOpaque.append(constructFaceData(block, neighbor, otherX, otherY, otherZ, false));
|
||||
} else {
|
||||
try additionalNeighborFacesVoxel.append(constructFaceData(block, neighbor, otherX, otherY, otherZ, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(canBeSeenThroughOtherBlock(otherBlock, block, neighbor ^ 1)) {
|
||||
if(otherBlock.transparent()) {
|
||||
if(otherBlock.hasBackFace()) {
|
||||
try additionalNeighborFacesTransparent.append(constructFaceData(otherBlock, neighbor, otherX, otherY, otherZ, true));
|
||||
}
|
||||
try self.transparentMesh.append(constructFaceData(otherBlock, neighbor ^ 1, x, y, z, false));
|
||||
} else {
|
||||
if(blocks.meshes.model(otherBlock).modelIndex == 0) {
|
||||
try self.opaqueMesh.append(constructFaceData(otherBlock, neighbor ^ 1, x, y, z, false));
|
||||
} else {
|
||||
try self.voxelMesh.append(constructFaceData(otherBlock, neighbor ^ 1, x, y, z, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
try neighborMesh.opaqueMesh.replaceNeighbors(neighbor, additionalNeighborFacesOpaque.items);
|
||||
try neighborMesh.voxelMesh.replaceNeighbors(neighbor, additionalNeighborFacesVoxel.items);
|
||||
try neighborMesh.transparentMesh.replaceNeighbors(neighbor, additionalNeighborFacesTransparent.items);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// lod border:
|
||||
if(self.pos.voxelSize == 1 << settings.highestLOD) continue;
|
||||
const neighborMesh = renderer.RenderStructure.getNeighbor(self.pos, 2*self.pos.voxelSize, neighbor) orelse return error.LODMissing;
|
||||
neighborMesh.mutex.lock();
|
||||
defer neighborMesh.mutex.unlock();
|
||||
if(neighborMesh.generated) {
|
||||
var additionalNeighborFacesOpaque = std.ArrayList(FaceData).init(main.threadAllocator);
|
||||
defer additionalNeighborFacesOpaque.deinit();
|
||||
var additionalNeighborFacesVoxel = std.ArrayList(FaceData).init(main.threadAllocator);
|
||||
defer additionalNeighborFacesVoxel.deinit();
|
||||
var additionalNeighborFacesTransparent = std.ArrayList(FaceData).init(main.threadAllocator);
|
||||
defer additionalNeighborFacesTransparent.deinit();
|
||||
const x3: u8 = if(neighbor & 1 == 0) @intCast(chunkMask) else 0;
|
||||
const offsetX = @divExact(self.pos.wx, self.pos.voxelSize) & chunkSize;
|
||||
const offsetY = @divExact(self.pos.wy, self.pos.voxelSize) & chunkSize;
|
||||
const offsetZ = @divExact(self.pos.wz, self.pos.voxelSize) & chunkSize;
|
||||
var x1: u8 = 0;
|
||||
while(x1 < chunkSize): (x1 += 1) {
|
||||
var x2: u8 = 0;
|
||||
@ -1024,13 +932,30 @@ pub const meshing = struct {
|
||||
y = x1;
|
||||
z = x3;
|
||||
}
|
||||
const otherX: u8 = @intCast((x+%Neighbors.relX[neighbor]+%offsetX >> 1) & chunkMask);
|
||||
const otherY: u8 = @intCast((y+%Neighbors.relY[neighbor]+%offsetY >> 1) & chunkMask);
|
||||
const otherZ: u8 = @intCast((z+%Neighbors.relZ[neighbor]+%offsetZ >> 1) & chunkMask);
|
||||
const block = (&chunk.blocks)[getIndex(x, y, z)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
const otherBlock = (&neighborMesh.chunk.load(.Monotonic).?.blocks)[getIndex(otherX, otherY, otherZ)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
const otherX: u8 = @intCast(x+%Neighbors.relX[neighbor] & chunkMask);
|
||||
const otherY: u8 = @intCast(y+%Neighbors.relY[neighbor] & chunkMask);
|
||||
const otherZ: u8 = @intCast(z+%Neighbors.relZ[neighbor] & chunkMask);
|
||||
const block = (&self.chunk.blocks)[getIndex(x, y, z)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
const otherBlock = (&neighborMesh.chunk.blocks)[getIndex(otherX, otherY, otherZ)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
if(canBeSeenThroughOtherBlock(block, otherBlock, neighbor)) {
|
||||
if(block.transparent()) {
|
||||
if(block.hasBackFace()) {
|
||||
try self.transparentMesh.append(constructFaceData(block, neighbor ^ 1, x, y, z, true));
|
||||
}
|
||||
try additionalNeighborFacesTransparent.append(constructFaceData(block, neighbor, otherX, otherY, otherZ, false));
|
||||
} else {
|
||||
if(blocks.meshes.model(block).modelIndex == 0) {
|
||||
try additionalNeighborFacesOpaque.append(constructFaceData(block, neighbor, otherX, otherY, otherZ, false));
|
||||
} else {
|
||||
try additionalNeighborFacesVoxel.append(constructFaceData(block, neighbor, otherX, otherY, otherZ, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(canBeSeenThroughOtherBlock(otherBlock, block, neighbor ^ 1)) {
|
||||
if(otherBlock.transparent()) {
|
||||
if(otherBlock.hasBackFace()) {
|
||||
try additionalNeighborFacesTransparent.append(constructFaceData(otherBlock, neighbor, otherX, otherY, otherZ, true));
|
||||
}
|
||||
try self.transparentMesh.append(constructFaceData(otherBlock, neighbor ^ 1, x, y, z, false));
|
||||
} else {
|
||||
if(blocks.meshes.model(otherBlock).modelIndex == 0) {
|
||||
@ -1040,27 +965,70 @@ pub const meshing = struct {
|
||||
}
|
||||
}
|
||||
}
|
||||
if(block.hasBackFace()) {
|
||||
if(canBeSeenThroughOtherBlock(block, otherBlock, neighbor)) {
|
||||
try self.transparentMesh.append(constructFaceData(block, neighbor ^ 1, x, y, z, true));
|
||||
}
|
||||
}
|
||||
try neighborMesh.opaqueMesh.replaceNeighbors(neighbor, additionalNeighborFacesOpaque.items);
|
||||
try neighborMesh.voxelMesh.replaceNeighbors(neighbor, additionalNeighborFacesVoxel.items);
|
||||
try neighborMesh.transparentMesh.replaceNeighbors(neighbor, additionalNeighborFacesTransparent.items);
|
||||
continue;
|
||||
}
|
||||
// lod border:
|
||||
if(self.pos.voxelSize == 1 << settings.highestLOD) continue;
|
||||
const neighborMesh = renderer.RenderStructure.getNeighbor(self.pos, 2*self.pos.voxelSize, neighbor) orelse continue;
|
||||
const x3: u8 = if(neighbor & 1 == 0) @intCast(chunkMask) else 0;
|
||||
const offsetX = @divExact(self.pos.wx, self.pos.voxelSize) & chunkSize;
|
||||
const offsetY = @divExact(self.pos.wy, self.pos.voxelSize) & chunkSize;
|
||||
const offsetZ = @divExact(self.pos.wz, self.pos.voxelSize) & chunkSize;
|
||||
var x1: u8 = 0;
|
||||
while(x1 < chunkSize): (x1 += 1) {
|
||||
var x2: u8 = 0;
|
||||
while(x2 < chunkSize): (x2 += 1) {
|
||||
var x: u8 = undefined;
|
||||
var y: u8 = undefined;
|
||||
var z: u8 = undefined;
|
||||
if(Neighbors.relX[neighbor] != 0) {
|
||||
x = x3;
|
||||
y = x1;
|
||||
z = x2;
|
||||
} else if(Neighbors.relY[neighbor] != 0) {
|
||||
x = x1;
|
||||
y = x3;
|
||||
z = x2;
|
||||
} else {
|
||||
x = x2;
|
||||
y = x1;
|
||||
z = x3;
|
||||
}
|
||||
const otherX: u8 = @intCast((x+%Neighbors.relX[neighbor]+%offsetX >> 1) & chunkMask);
|
||||
const otherY: u8 = @intCast((y+%Neighbors.relY[neighbor]+%offsetY >> 1) & chunkMask);
|
||||
const otherZ: u8 = @intCast((z+%Neighbors.relZ[neighbor]+%offsetZ >> 1) & chunkMask);
|
||||
const block = (&self.chunk.blocks)[getIndex(x, y, z)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
const otherBlock = (&neighborMesh.chunk.blocks)[getIndex(otherX, otherY, otherZ)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
if(canBeSeenThroughOtherBlock(otherBlock, block, neighbor ^ 1)) {
|
||||
if(otherBlock.transparent()) {
|
||||
try self.transparentMesh.append(constructFaceData(otherBlock, neighbor ^ 1, x, y, z, false));
|
||||
} else {
|
||||
if(blocks.meshes.model(otherBlock).modelIndex == 0) {
|
||||
try self.opaqueMesh.append(constructFaceData(otherBlock, neighbor ^ 1, x, y, z, false));
|
||||
} else {
|
||||
try self.voxelMesh.append(constructFaceData(otherBlock, neighbor ^ 1, x, y, z, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(block.hasBackFace()) {
|
||||
if(canBeSeenThroughOtherBlock(block, otherBlock, neighbor)) {
|
||||
try self.transparentMesh.append(constructFaceData(block, neighbor ^ 1, x, y, z, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return error.LODMissing;
|
||||
}
|
||||
}
|
||||
try self.opaqueMesh.finish();
|
||||
try self.voxelMesh.finish();
|
||||
try self.transparentMesh.finish();
|
||||
self.generated = true;
|
||||
}
|
||||
|
||||
pub fn render(self: *ChunkMesh, playerPosition: Vec3d) void {
|
||||
if(!self.generated) {
|
||||
return;
|
||||
}
|
||||
if(self.opaqueMesh.vertexCount == 0) return;
|
||||
c.glUniform3f(
|
||||
uniforms.modelPosition,
|
||||
@ -1075,9 +1043,6 @@ pub const meshing = struct {
|
||||
}
|
||||
|
||||
pub fn renderVoxelModels(self: *ChunkMesh, playerPosition: Vec3d) void {
|
||||
if(!self.generated) {
|
||||
return;
|
||||
}
|
||||
if(self.voxelMesh.vertexCount == 0) return;
|
||||
c.glUniform3f(
|
||||
voxelUniforms.modelPosition,
|
||||
@ -1092,9 +1057,6 @@ pub const meshing = struct {
|
||||
}
|
||||
|
||||
pub fn renderTransparent(self: *ChunkMesh, playerPosition: Vec3d) !void {
|
||||
if(!self.generated) {
|
||||
return;
|
||||
}
|
||||
if(self.transparentMesh.vertexCount == 0) return;
|
||||
|
||||
var needsUpdate: bool = false;
|
||||
|
153
src/renderer.zig
153
src/renderer.zig
@ -873,7 +873,7 @@ pub const MeshSelection = struct {
|
||||
|
||||
pub const RenderStructure = struct {
|
||||
const ChunkMeshNode = struct {
|
||||
mesh: chunk.meshing.ChunkMesh,
|
||||
mesh: ?*chunk.meshing.ChunkMesh,
|
||||
shouldBeRemoved: bool, // Internal use.
|
||||
drawableChildren: u32, // How many children can be renderer. If this is 8 then there is no need to render this mesh.
|
||||
lod: u3,
|
||||
@ -884,9 +884,7 @@ pub const RenderStructure = struct {
|
||||
var storageLists: [settings.highestLOD + 1][]?*ChunkMeshNode = [1][]?*ChunkMeshNode{&.{}} ** (settings.highestLOD + 1);
|
||||
var storageListsSwap: [settings.highestLOD + 1][]?*ChunkMeshNode = [1][]?*ChunkMeshNode{&.{}} ** (settings.highestLOD + 1);
|
||||
var meshList = std.ArrayList(*chunk.meshing.ChunkMesh).init(main.globalAllocator);
|
||||
var updatableList: std.ArrayList(chunk.ChunkPosition) = undefined;
|
||||
var updatableListSwap: std.ArrayList(chunk.ChunkPosition) = undefined;
|
||||
var clearList: std.ArrayList(*ChunkMeshNode) = undefined;
|
||||
var updatableList: std.ArrayList(*chunk.meshing.ChunkMesh) = undefined;
|
||||
var lastRD: i32 = 0;
|
||||
var lastFactor: f32 = 0;
|
||||
var lastX: [settings.highestLOD + 1]i32 = [_]i32{0} ** (settings.highestLOD + 1);
|
||||
@ -907,9 +905,8 @@ pub const RenderStructure = struct {
|
||||
pub fn init() !void {
|
||||
lastRD = 0;
|
||||
lastFactor = 0;
|
||||
updatableList = std.ArrayList(chunk.ChunkPosition).init(main.globalAllocator);
|
||||
updatableList = std.ArrayList(*chunk.meshing.ChunkMesh).init(main.globalAllocator);
|
||||
blockUpdateList = std.ArrayList(BlockUpdate).init(main.globalAllocator);
|
||||
clearList = std.ArrayList(*ChunkMeshNode).init(main.globalAllocator);
|
||||
for(&storageLists) |*storageList| {
|
||||
storageList.* = try main.globalAllocator.alloc(?*ChunkMeshNode, 0);
|
||||
}
|
||||
@ -917,10 +914,13 @@ pub const RenderStructure = struct {
|
||||
|
||||
pub fn deinit() void {
|
||||
for(storageLists) |storageList| {
|
||||
for(storageList) |nullChunkMesh| {
|
||||
if(nullChunkMesh) |chunkMesh| {
|
||||
chunkMesh.mesh.deinit();
|
||||
main.globalAllocator.destroy(chunkMesh);
|
||||
for(storageList) |nullNode| {
|
||||
if(nullNode) |node| {
|
||||
if(node.mesh) |mesh| {
|
||||
mesh.deinit();
|
||||
main.globalAllocator.destroy(mesh);
|
||||
}
|
||||
main.globalAllocator.destroy(node);
|
||||
}
|
||||
}
|
||||
main.globalAllocator.free(storageList);
|
||||
@ -928,13 +928,12 @@ pub const RenderStructure = struct {
|
||||
for(storageListsSwap) |storageList| {
|
||||
main.globalAllocator.free(storageList);
|
||||
}
|
||||
updatableList.deinit();
|
||||
for(clearList.items) |chunkMesh| {
|
||||
chunkMesh.mesh.deinit();
|
||||
main.globalAllocator.destroy(chunkMesh);
|
||||
for(updatableList.items) |mesh| {
|
||||
mesh.deinit();
|
||||
main.globalAllocator.destroy(mesh);
|
||||
}
|
||||
updatableList.deinit();
|
||||
blockUpdateList.deinit();
|
||||
clearList.deinit();
|
||||
meshList.deinit();
|
||||
}
|
||||
|
||||
@ -966,12 +965,13 @@ pub const RenderStructure = struct {
|
||||
|
||||
pub fn getChunk(x: i32, y: i32, z: i32) ?*chunk.Chunk {
|
||||
const node = RenderStructure._getNode(.{.wx = x, .wy = y, .wz = z, .voxelSize=1}) orelse return null;
|
||||
return node.mesh.chunk.load(.Monotonic);
|
||||
return &node.mesh.chunk;
|
||||
}
|
||||
|
||||
pub fn getBlock(x: i32, y: i32, z: i32) ?blocks.Block {
|
||||
const node = RenderStructure._getNode(.{.wx = x, .wy = y, .wz = z, .voxelSize=1}) orelse return null;
|
||||
const block = (node.mesh.chunk.load(.Monotonic) orelse return null).getBlock(x & chunk.chunkMask, y & chunk.chunkMask, z & chunk.chunkMask);
|
||||
const mesh = node.mesh orelse return null;
|
||||
const block = mesh.chunk.getBlock(x & chunk.chunkMask, y & chunk.chunkMask, z & chunk.chunkMask);
|
||||
return block;
|
||||
}
|
||||
|
||||
@ -979,7 +979,8 @@ pub const RenderStructure = struct {
|
||||
var lod: u5 = 0;
|
||||
while(lod < settings.highestLOD) : (lod += 1) {
|
||||
const node = RenderStructure._getNode(.{.wx = x, .wy = y, .wz = z, .voxelSize=@as(u31, 1) << lod}) orelse continue;
|
||||
const block = (node.mesh.chunk.load(.Monotonic) orelse continue).getBlock(x & chunk.chunkMask<<lod, y & chunk.chunkMask<<lod, z & chunk.chunkMask<<lod);
|
||||
const mesh = node.mesh orelse continue;
|
||||
const block = mesh.chunk.getBlock(x & chunk.chunkMask<<lod, y & chunk.chunkMask<<lod, z & chunk.chunkMask<<lod);
|
||||
return block;
|
||||
}
|
||||
return blocks.Block{.typ = 0, .data = 0};
|
||||
@ -992,7 +993,7 @@ pub const RenderStructure = struct {
|
||||
pos.wz += pos.voxelSize*chunk.chunkSize*chunk.Neighbors.relZ[neighbor];
|
||||
pos.voxelSize = resolution;
|
||||
const node = _getNode(pos) orelse return null;
|
||||
return &node.mesh;
|
||||
return node.mesh;
|
||||
}
|
||||
|
||||
pub fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: Vec3d, renderDistance: i32, LODFactor: f32) ![]*chunk.meshing.ChunkMesh {
|
||||
@ -1056,13 +1057,13 @@ pub const RenderStructure = struct {
|
||||
const pos = chunk.ChunkPosition{.wx=x, .wy=y, .wz=z, .voxelSize=@as(u31, 1)<<lod};
|
||||
var node = getNodeFromRenderThread(pos);
|
||||
if(node) |_node| {
|
||||
if(_node.mesh.generated) {
|
||||
_node.mesh.visibilityMask = 0xff;
|
||||
if(_node.mesh) |mesh| {
|
||||
mesh.visibilityMask = 0xff;
|
||||
}
|
||||
_node.shouldBeRemoved = false;
|
||||
} else {
|
||||
node = try main.globalAllocator.create(ChunkMeshNode);
|
||||
node.?.mesh = chunk.meshing.ChunkMesh.init(main.globalAllocator, pos);
|
||||
node.?.mesh = null;
|
||||
node.?.shouldBeRemoved = true; // Might be removed in the next iteration.
|
||||
try meshRequests.append(pos);
|
||||
}
|
||||
@ -1084,27 +1085,23 @@ pub const RenderStructure = struct {
|
||||
storageListsSwap[lod] = oldList;
|
||||
}
|
||||
for(oldList) |nullMesh| {
|
||||
if(nullMesh) |mesh| {
|
||||
if(mesh.shouldBeRemoved) {
|
||||
if(nullMesh) |node| {
|
||||
if(node.shouldBeRemoved) {
|
||||
// Update the neighbors, so we don't get cracks when we look back:
|
||||
for(chunk.Neighbors.iterable) |neighbor| {
|
||||
if(getNeighbor(mesh.mesh.pos, mesh.mesh.pos.voxelSize, neighbor)) |neighborMesh| {
|
||||
if(neighborMesh.generated) {
|
||||
neighborMesh.mutex.lock();
|
||||
defer neighborMesh.mutex.unlock();
|
||||
if(node.mesh) |mesh| {
|
||||
if(getNeighbor(mesh.pos, mesh.pos.voxelSize, neighbor)) |neighborMesh| {
|
||||
try neighborMesh.uploadDataAndFinishNeighbors();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(mesh.mesh.mutex.tryLock()) { // Make sure there is no task currently running on the thing.
|
||||
mesh.mesh.mutex.unlock();
|
||||
mesh.mesh.deinit();
|
||||
if(node.mesh) |mesh| {
|
||||
mesh.deinit();
|
||||
main.globalAllocator.destroy(mesh);
|
||||
} else {
|
||||
try clearList.append(mesh);
|
||||
}
|
||||
main.globalAllocator.destroy(node);
|
||||
} else {
|
||||
mesh.shouldBeRemoved = true;
|
||||
node.shouldBeRemoved = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1138,7 +1135,7 @@ pub const RenderStructure = struct {
|
||||
firstPos.wz &= ~@as(i32, chunk.chunkMask);
|
||||
var lod: u3 = 0;
|
||||
while(lod <= settings.highestLOD) : (lod += 1) {
|
||||
if(getNodeFromRenderThread(firstPos)) |node| if(node.mesh.generated) {
|
||||
if(getNodeFromRenderThread(firstPos)) |node| if(node.mesh != null) {
|
||||
node.lod = lod;
|
||||
node.min = @splat(-1);
|
||||
node.max = @splat(1);
|
||||
@ -1158,12 +1155,14 @@ pub const RenderStructure = struct {
|
||||
const projRotMat = game.projectionMatrix.mul(game.camera.viewMatrix);
|
||||
while(searchList.removeOrNull()) |data| {
|
||||
data.node.active = false;
|
||||
const mesh = &data.node.mesh;
|
||||
const mesh = data.node.mesh.?;
|
||||
if(data.node.lod+1 != storageLists.len) {
|
||||
if(getNodeFromRenderThread(.{.wx=mesh.pos.wx, .wy=mesh.pos.wy, .wz=mesh.pos.wz, .voxelSize=mesh.pos.voxelSize << 1})) |parent| {
|
||||
const sizeShift = chunk.chunkShift + data.node.lod;
|
||||
const octantIndex: u3 = @intCast((mesh.pos.wx>>sizeShift & 1) | (mesh.pos.wy>>sizeShift & 1)<<1 | (mesh.pos.wz>>sizeShift & 1)<<2);
|
||||
parent.mesh.visibilityMask &= ~(@as(u8, 1) << octantIndex);
|
||||
if(parent.mesh) |parentMesh| {
|
||||
const sizeShift = chunk.chunkShift + data.node.lod;
|
||||
const octantIndex: u3 = @intCast((mesh.pos.wx>>sizeShift & 1) | (mesh.pos.wy>>sizeShift & 1)<<1 | (mesh.pos.wz>>sizeShift & 1)<<2);
|
||||
parentMesh.visibilityMask &= ~(@as(u8, 1) << octantIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
try meshList.append(mesh);
|
||||
@ -1319,7 +1318,7 @@ pub const RenderStructure = struct {
|
||||
};
|
||||
var lod: u3 = data.node.lod;
|
||||
while(lod <= settings.highestLOD) : (lod += 1) {
|
||||
if(getNodeFromRenderThread(neighborPos)) |node| if(node.mesh.generated) {
|
||||
if(getNodeFromRenderThread(neighborPos)) |node| if(node.mesh != null) {
|
||||
if(node.active) {
|
||||
node.min = @min(node.min, min);
|
||||
node.max = @max(node.max, max);
|
||||
@ -1330,7 +1329,7 @@ pub const RenderStructure = struct {
|
||||
node.active = true;
|
||||
try searchList.add(.{
|
||||
.node = node,
|
||||
.distance = node.mesh.pos.getMaxDistanceSquared(playerPos)
|
||||
.distance = node.mesh.?.pos.getMaxDistanceSquared(playerPos),
|
||||
});
|
||||
}
|
||||
break :continueNeighborLoop;
|
||||
@ -1343,19 +1342,6 @@ pub const RenderStructure = struct {
|
||||
}
|
||||
}
|
||||
|
||||
var i: usize = 0;
|
||||
while(i < clearList.items.len) {
|
||||
const mesh = clearList.items[i];
|
||||
if(mesh.mesh.mutex.tryLock()) { // Make sure there is no task currently running on the thing.
|
||||
mesh.mesh.mutex.unlock();
|
||||
mesh.mesh.deinit();
|
||||
main.globalAllocator.destroy(mesh);
|
||||
_ = clearList.swapRemove(i);
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
lastRD = renderDistance;
|
||||
lastFactor = LODFactor;
|
||||
// Make requests after updating the, to avoid concurrency issues and reduce the number of requests:
|
||||
@ -1370,7 +1356,9 @@ pub const RenderStructure = struct {
|
||||
for(blockUpdateList.items) |blockUpdate| {
|
||||
const pos = chunk.ChunkPosition{.wx=blockUpdate.x, .wy=blockUpdate.y, .wz=blockUpdate.z, .voxelSize=1};
|
||||
if(_getNode(pos)) |node| {
|
||||
try node.mesh.updateBlock(blockUpdate.x, blockUpdate.y, blockUpdate.z, blockUpdate.newBlock);
|
||||
if(node.mesh) |mesh| {
|
||||
try mesh.updateBlock(blockUpdate.x, blockUpdate.y, blockUpdate.z, blockUpdate.newBlock);
|
||||
} // TODO: It seems like we simply ignore the block update if we don't have the mesh yet.
|
||||
}
|
||||
}
|
||||
blockUpdateList.clearRetainingCapacity();
|
||||
@ -1382,29 +1370,27 @@ pub const RenderStructure = struct {
|
||||
var closestPriority: f32 = -std.math.floatMax(f32);
|
||||
var closestIndex: usize = 0;
|
||||
const playerPos = game.Player.getPosBlocking();
|
||||
for(updatableList.items, 0..) |pos, i| {
|
||||
const priority = pos.getPriority(playerPos);
|
||||
for(updatableList.items, 0..) |mesh, i| {
|
||||
const priority = mesh.pos.getPriority(playerPos);
|
||||
if(priority > closestPriority) {
|
||||
closestPriority = priority;
|
||||
closestIndex = i;
|
||||
}
|
||||
}
|
||||
const pos = updatableList.orderedRemove(closestIndex);
|
||||
const mesh = updatableList.orderedRemove(closestIndex);
|
||||
mutex.unlock();
|
||||
defer mutex.lock();
|
||||
const nullNode = _getNode(pos);
|
||||
const nullNode = _getNode(mesh.pos);
|
||||
if(nullNode) |node| {
|
||||
node.mesh.mutex.lock();
|
||||
defer node.mesh.mutex.unlock();
|
||||
node.mesh.uploadDataAndFinishNeighbors() catch |err| {
|
||||
if(err == error.LODMissing) {
|
||||
mutex.lock();
|
||||
defer mutex.unlock();
|
||||
try updatableList.append(pos);
|
||||
} else {
|
||||
return err;
|
||||
}
|
||||
};
|
||||
try mesh.uploadDataAndFinishNeighbors();
|
||||
if(node.mesh) |oldMesh| {
|
||||
oldMesh.deinit();
|
||||
main.globalAllocator.destroy(oldMesh);
|
||||
}
|
||||
node.mesh = mesh;
|
||||
} else {
|
||||
mesh.deinit();
|
||||
main.globalAllocator.destroy(mesh);
|
||||
}
|
||||
if(std.time.milliTimestamp() >= targetTime) break; // Update at least one mesh.
|
||||
}
|
||||
@ -1442,25 +1428,18 @@ pub const RenderStructure = struct {
|
||||
|
||||
pub fn run(self: *MeshGenerationTask) Allocator.Error!void {
|
||||
const pos = self.mesh.pos;
|
||||
const nullNode = _getNode(pos);
|
||||
if(nullNode) |node| {
|
||||
{
|
||||
node.mesh.mutex.lock();
|
||||
defer node.mesh.mutex.unlock();
|
||||
try node.mesh.regenerateMainMesh(self.mesh);
|
||||
const mesh = try main.globalAllocator.create(chunk.meshing.ChunkMesh);
|
||||
mesh.* = chunk.meshing.ChunkMesh.init(main.globalAllocator, pos, self.mesh);
|
||||
try mesh.regenerateMainMesh();
|
||||
mutex.lock();
|
||||
defer mutex.unlock();
|
||||
updatableList.append(mesh) catch |err| {
|
||||
std.log.err("Error while regenerating mesh: {s}", .{@errorName(err)});
|
||||
if(@errorReturnTrace()) |trace| {
|
||||
std.log.err("Trace: {}", .{trace});
|
||||
}
|
||||
mutex.lock();
|
||||
defer mutex.unlock();
|
||||
updatableList.append(pos) catch |err| {
|
||||
std.log.err("Error while regenerating mesh: {s}", .{@errorName(err)});
|
||||
if(@errorReturnTrace()) |trace| {
|
||||
std.log.err("Trace: {}", .{trace});
|
||||
}
|
||||
main.globalAllocator.destroy(self.mesh);
|
||||
};
|
||||
} else {
|
||||
main.globalAllocator.destroy(self.mesh);
|
||||
}
|
||||
};
|
||||
main.globalAllocator.destroy(self);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user