diff --git a/src/chunk.zig b/src/chunk.zig index c726ea0e..2890af01 100644 --- a/src/chunk.zig +++ b/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; diff --git a/src/renderer.zig b/src/renderer.zig index a91ea50d..e0b63bdf 100644 --- a/src/renderer.zig +++ b/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<>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); }