mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 11:17:05 -04:00
parent
d40da846a0
commit
04f9bae91c
@ -717,12 +717,8 @@ pub const ChunkMesh = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scheduleLightRefreshAndDecreaseRefCount(self: *ChunkMesh) void {
|
||||
if(!self.needsLightRefresh.swap(true, .acq_rel)) {
|
||||
LightRefreshTask.scheduleAndDecreaseRefCount(self);
|
||||
} else {
|
||||
self.decreaseRefCount();
|
||||
}
|
||||
pub fn scheduleLightRefreshAndDecreaseRefCount1(self: *ChunkMesh) void {
|
||||
LightRefreshTask.scheduleAndDecreaseRefCount(self);
|
||||
}
|
||||
const LightRefreshTask = struct {
|
||||
mesh: *ChunkMesh,
|
||||
@ -783,7 +779,7 @@ pub const ChunkMesh = struct {
|
||||
);
|
||||
}
|
||||
|
||||
fn initLight(self: *ChunkMesh) void {
|
||||
fn initLight(self: *ChunkMesh, lightRefreshList: *main.List(*ChunkMesh)) void {
|
||||
self.mutex.lock();
|
||||
var lightEmittingBlocks = main.List([3]u8).init(main.stackAllocator);
|
||||
defer lightEmittingBlocks.deinit();
|
||||
@ -799,7 +795,7 @@ pub const ChunkMesh = struct {
|
||||
}
|
||||
}
|
||||
self.mutex.unlock();
|
||||
self.lightingData[0].propagateLights(lightEmittingBlocks.items, true);
|
||||
self.lightingData[0].propagateLights(lightEmittingBlocks.items, true, lightRefreshList);
|
||||
sunLight: {
|
||||
var allSun: bool = self.chunk.data.paletteLength == 1 and self.chunk.data.palette[0].typ == 0;
|
||||
var sunStarters: [chunk.chunkSize*chunk.chunkSize][3]u8 = undefined;
|
||||
@ -821,9 +817,9 @@ pub const ChunkMesh = struct {
|
||||
}
|
||||
}
|
||||
if(allSun) {
|
||||
self.lightingData[1].propagateUniformSun();
|
||||
self.lightingData[1].propagateUniformSun(lightRefreshList);
|
||||
} else {
|
||||
self.lightingData[1].propagateLights(sunStarters[0..index], true);
|
||||
self.lightingData[1].propagateLights(sunStarters[0..index], true, lightRefreshList);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -835,7 +831,9 @@ pub const ChunkMesh = struct {
|
||||
self.mutex.unlock();
|
||||
try mesh_storage.addMeshToStorage(self);
|
||||
|
||||
self.initLight();
|
||||
var lightRefreshList = main.List(*ChunkMesh).init(main.stackAllocator);
|
||||
defer lightRefreshList.deinit();
|
||||
self.initLight(&lightRefreshList);
|
||||
|
||||
self.mutex.lock();
|
||||
self.finishedLighting = true;
|
||||
@ -858,20 +856,28 @@ pub const ChunkMesh = struct {
|
||||
const shiftSelf: u5 = @intCast(((dx + 1)*3 + dy + 1)*3 + dz + 1);
|
||||
const shiftOther: u5 = @intCast(((-dx + 1)*3 + -dy + 1)*3 + -dz + 1);
|
||||
if(neighborMesh.litNeighbors.fetchOr(@as(u27, 1) << shiftOther, .monotonic) ^ @as(u27, 1) << shiftOther == ~@as(u27, 0)) { // Trigger mesh creation for neighbor
|
||||
neighborMesh.generateMesh();
|
||||
neighborMesh.generateMesh(&lightRefreshList);
|
||||
}
|
||||
neighborMesh.mutex.lock();
|
||||
const neighborFinishedLighting = neighborMesh.finishedLighting;
|
||||
neighborMesh.mutex.unlock();
|
||||
if(neighborFinishedLighting and self.litNeighbors.fetchOr(@as(u27, 1) << shiftSelf, .monotonic) ^ @as(u27, 1) << shiftSelf == ~@as(u27, 0)) {
|
||||
self.generateMesh();
|
||||
self.generateMesh(&lightRefreshList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(lightRefreshList.items) |other| {
|
||||
if(other.needsLightRefresh.load(.unordered)) {
|
||||
other.scheduleLightRefreshAndDecreaseRefCount1();
|
||||
} else {
|
||||
other.decreaseRefCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generateMesh(self: *ChunkMesh) void {
|
||||
pub fn generateMesh(self: *ChunkMesh, lightRefreshList: *main.List(*ChunkMesh)) void {
|
||||
var canSeeNeighbor: [6][chunk.chunkSize][chunk.chunkSize]u32 = undefined;
|
||||
@memset(std.mem.asBytes(&canSeeNeighbor), 0);
|
||||
var canSeeAllNeighbors: [chunk.chunkSize][chunk.chunkSize]u32 = undefined;
|
||||
@ -1108,23 +1114,32 @@ pub const ChunkMesh = struct {
|
||||
}
|
||||
self.mutex.unlock();
|
||||
|
||||
self.finishNeighbors();
|
||||
self.finishNeighbors(lightRefreshList);
|
||||
}
|
||||
|
||||
fn updateBlockLight(self: *ChunkMesh, x: u5, y: u5, z: u5, newBlock: Block) void {
|
||||
fn updateBlockLight(self: *ChunkMesh, x: u5, y: u5, z: u5, newBlock: Block, lightRefreshList: *main.List(*ChunkMesh)) void {
|
||||
for(self.lightingData[0..]) |lightingData| {
|
||||
lightingData.propagateLightsDestructive(&.{.{x, y, z}});
|
||||
lightingData.propagateLightsDestructive(&.{.{x, y, z}}, lightRefreshList);
|
||||
}
|
||||
if(newBlock.light() != 0) {
|
||||
self.lightingData[0].propagateLights(&.{.{x, y, z}}, false);
|
||||
self.lightingData[0].propagateLights(&.{.{x, y, z}}, false, lightRefreshList);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn updateBlock(self: *ChunkMesh, _x: i32, _y: i32, _z: i32, _newBlock: Block) void {
|
||||
std.log.err("Block: {} {} {}", .{_x, _y, _z});
|
||||
var lightRefreshList = main.List(*ChunkMesh).init(main.stackAllocator);
|
||||
defer lightRefreshList.deinit();
|
||||
const x: u5 = @intCast(_x & chunk.chunkMask);
|
||||
const y: u5 = @intCast(_y & chunk.chunkMask);
|
||||
const z: u5 = @intCast(_z & chunk.chunkMask);
|
||||
var newBlock = _newBlock;
|
||||
self.mutex.lock();
|
||||
if(std.meta.eql(self.chunk.data.getValue(chunk.getIndex(x, y, z)), newBlock)) {
|
||||
self.mutex.unlock();
|
||||
return;
|
||||
}
|
||||
self.mutex.unlock();
|
||||
var neighborBlocks: [6]Block = undefined;
|
||||
@memset(&neighborBlocks, .{.typ = 0, .data = 0});
|
||||
for(chunk.Neighbors.iterable) |neighbor| {
|
||||
@ -1143,8 +1158,8 @@ pub const ChunkMesh = struct {
|
||||
neighborChunkMesh.opaqueMesh.coreFaces.clearRetainingCapacity();
|
||||
neighborChunkMesh.transparentMesh.coreFaces.clearRetainingCapacity();
|
||||
neighborChunkMesh.mutex.unlock();
|
||||
neighborChunkMesh.updateBlockLight(@intCast(nx & chunk.chunkMask), @intCast(ny & chunk.chunkMask), @intCast(nz & chunk.chunkMask), neighborBlock);
|
||||
neighborChunkMesh.generateMesh();
|
||||
neighborChunkMesh.updateBlockLight(@intCast(nx & chunk.chunkMask), @intCast(ny & chunk.chunkMask), @intCast(nz & chunk.chunkMask), neighborBlock, &lightRefreshList);
|
||||
neighborChunkMesh.generateMesh(&lightRefreshList);
|
||||
neighborChunkMesh.mutex.lock();
|
||||
}
|
||||
}
|
||||
@ -1157,7 +1172,7 @@ pub const ChunkMesh = struct {
|
||||
if(neighborBlock.mode().dependsOnNeighbors) {
|
||||
if(neighborBlock.mode().updateData(&neighborBlock, neighbor ^ 1, newBlock)) {
|
||||
self.chunk.data.setValue(index, neighborBlock);
|
||||
self.updateBlockLight(@intCast(nx & chunk.chunkMask), @intCast(ny & chunk.chunkMask), @intCast(nz & chunk.chunkMask), neighborBlock);
|
||||
self.updateBlockLight(@intCast(nx & chunk.chunkMask), @intCast(ny & chunk.chunkMask), @intCast(nz & chunk.chunkMask), neighborBlock, &lightRefreshList);
|
||||
}
|
||||
}
|
||||
self.mutex.unlock();
|
||||
@ -1172,7 +1187,7 @@ pub const ChunkMesh = struct {
|
||||
self.mutex.lock();
|
||||
self.chunk.data.setValue(chunk.getIndex(x, y, z), newBlock);
|
||||
self.mutex.unlock();
|
||||
self.updateBlockLight(x, y, z, newBlock);
|
||||
self.updateBlockLight(x, y, z, newBlock, &lightRefreshList);
|
||||
self.mutex.lock();
|
||||
defer self.mutex.unlock();
|
||||
// Update neighbor chunks:
|
||||
@ -1200,8 +1215,15 @@ pub const ChunkMesh = struct {
|
||||
self.opaqueMesh.coreFaces.clearRetainingCapacity();
|
||||
self.transparentMesh.coreFaces.clearRetainingCapacity();
|
||||
self.mutex.unlock();
|
||||
self.generateMesh(); // TODO: Batch mesh updates instead of applying them for each block changes.
|
||||
self.generateMesh(&lightRefreshList); // TODO: Batch mesh updates instead of applying them for each block changes.
|
||||
self.mutex.lock();
|
||||
for(lightRefreshList.items) |other| {
|
||||
if(other.needsLightRefresh.load(.unordered)) {
|
||||
other.scheduleLightRefreshAndDecreaseRefCount1();
|
||||
} else {
|
||||
other.decreaseRefCount();
|
||||
}
|
||||
}
|
||||
self.uploadData();
|
||||
}
|
||||
|
||||
@ -1241,7 +1263,7 @@ pub const ChunkMesh = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn finishNeighbors(self: *ChunkMesh) void {
|
||||
fn finishNeighbors(self: *ChunkMesh, lightRefreshList: *main.List(*ChunkMesh)) void {
|
||||
for(chunk.Neighbors.iterable) |neighbor| {
|
||||
const nullNeighborMesh = mesh_storage.getNeighborAndIncreaseRefCount(self.pos, self.pos.voxelSize, neighbor);
|
||||
if(nullNeighborMesh) |neighborMesh| sameLodBlock: {
|
||||
@ -1303,10 +1325,9 @@ pub const ChunkMesh = struct {
|
||||
}
|
||||
}
|
||||
}
|
||||
_ = neighborMesh.needsLightRefresh.swap(false, .acq_rel);
|
||||
neighborMesh.finishData();
|
||||
_ = neighborMesh.needsLightRefresh.store(true, .release);
|
||||
neighborMesh.increaseRefCount();
|
||||
mesh_storage.addToUpdateListAndDecreaseRefCount(neighborMesh);
|
||||
lightRefreshList.append(neighborMesh);
|
||||
} else {
|
||||
self.mutex.lock();
|
||||
defer self.mutex.unlock();
|
||||
|
@ -103,7 +103,7 @@ pub const ChannelChunk = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn propagateDirect(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry)) void {
|
||||
fn propagateDirect(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry), lightRefreshList: *main.List(*chunk_meshing.ChunkMesh)) void {
|
||||
var neighborLists: [6]main.ListUnmanaged(Entry) = .{.{}} ** 6;
|
||||
defer {
|
||||
for(&neighborLists) |*list| {
|
||||
@ -146,19 +146,26 @@ pub const ChannelChunk = struct {
|
||||
}
|
||||
self.data.optimizeLayout();
|
||||
self.lock.unlockWrite();
|
||||
if(mesh_storage.getMeshAndIncreaseRefCount(self.ch.pos)) |mesh| {
|
||||
mesh.scheduleLightRefreshAndDecreaseRefCount();
|
||||
if(mesh_storage.getMeshAndIncreaseRefCount(self.ch.pos)) |mesh| outer: {
|
||||
for(lightRefreshList.items) |other| {
|
||||
if(mesh == other) {
|
||||
mesh.decreaseRefCount();
|
||||
break :outer;
|
||||
}
|
||||
}
|
||||
mesh.needsLightRefresh.store(true, .release);
|
||||
lightRefreshList.append(mesh);
|
||||
}
|
||||
|
||||
for(0..6) |neighbor| {
|
||||
if(neighborLists[neighbor].items.len == 0) continue;
|
||||
const neighborMesh = mesh_storage.getNeighborAndIncreaseRefCount(self.ch.pos, self.ch.pos.voxelSize, @intCast(neighbor)) orelse continue;
|
||||
defer neighborMesh.decreaseRefCount();
|
||||
neighborMesh.lightingData[@intFromBool(self.isSun)].propagateFromNeighbor(lightQueue, neighborLists[neighbor].items);
|
||||
neighborMesh.lightingData[@intFromBool(self.isSun)].propagateFromNeighbor(lightQueue, neighborLists[neighbor].items, lightRefreshList);
|
||||
}
|
||||
}
|
||||
|
||||
fn propagateDestructive(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry), constructiveEntries: *main.ListUnmanaged(ChunkEntries), isFirstBlock: bool) main.ListUnmanaged(PositionEntry) {
|
||||
fn propagateDestructive(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry), constructiveEntries: *main.ListUnmanaged(ChunkEntries), isFirstBlock: bool, lightRefreshList: *main.List(*chunk_meshing.ChunkMesh)) main.ListUnmanaged(PositionEntry) {
|
||||
var neighborLists: [6]main.ListUnmanaged(Entry) = .{.{}} ** 6;
|
||||
var constructiveList: main.ListUnmanaged(PositionEntry) = .{};
|
||||
defer {
|
||||
@ -224,8 +231,15 @@ pub const ChannelChunk = struct {
|
||||
}
|
||||
}
|
||||
self.lock.unlockWrite();
|
||||
if(mesh_storage.getMeshAndIncreaseRefCount(self.ch.pos)) |mesh| {
|
||||
mesh.scheduleLightRefreshAndDecreaseRefCount();
|
||||
if(mesh_storage.getMeshAndIncreaseRefCount(self.ch.pos)) |mesh| outer: {
|
||||
for(lightRefreshList.items) |other| {
|
||||
if(mesh == other) {
|
||||
mesh.decreaseRefCount();
|
||||
break :outer;
|
||||
}
|
||||
}
|
||||
mesh.needsLightRefresh.store(true, .release);
|
||||
lightRefreshList.append(mesh);
|
||||
}
|
||||
|
||||
for(0..6) |neighbor| {
|
||||
@ -233,14 +247,14 @@ pub const ChannelChunk = struct {
|
||||
const neighborMesh = mesh_storage.getNeighborAndIncreaseRefCount(self.ch.pos, self.ch.pos.voxelSize, @intCast(neighbor)) orelse continue;
|
||||
constructiveEntries.append(main.stackAllocator, .{
|
||||
.mesh = neighborMesh,
|
||||
.entries = neighborMesh.lightingData[@intFromBool(self.isSun)].propagateDestructiveFromNeighbor(lightQueue, neighborLists[neighbor].items, constructiveEntries),
|
||||
.entries = neighborMesh.lightingData[@intFromBool(self.isSun)].propagateDestructiveFromNeighbor(lightQueue, neighborLists[neighbor].items, constructiveEntries, lightRefreshList),
|
||||
});
|
||||
}
|
||||
|
||||
return constructiveList;
|
||||
}
|
||||
|
||||
fn propagateFromNeighbor(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry), lights: []const Entry) void {
|
||||
fn propagateFromNeighbor(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry), lights: []const Entry, lightRefreshList: *main.List(*chunk_meshing.ChunkMesh)) void {
|
||||
std.debug.assert(lightQueue.startIndex == lightQueue.endIndex);
|
||||
for(lights) |entry| {
|
||||
const index = chunk.getIndex(entry.x, entry.y, entry.z);
|
||||
@ -248,10 +262,10 @@ pub const ChannelChunk = struct {
|
||||
calculateIncomingOcclusion(&result.value, self.ch.data.getValue(index), self.ch.pos.voxelSize, entry.sourceDir);
|
||||
if(result.value[0] != 0 or result.value[1] != 0 or result.value[2] != 0) lightQueue.enqueue(result);
|
||||
}
|
||||
self.propagateDirect(lightQueue);
|
||||
self.propagateDirect(lightQueue, lightRefreshList);
|
||||
}
|
||||
|
||||
fn propagateDestructiveFromNeighbor(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry), lights: []const Entry, constructiveEntries: *main.ListUnmanaged(ChunkEntries)) main.ListUnmanaged(PositionEntry) {
|
||||
fn propagateDestructiveFromNeighbor(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry), lights: []const Entry, constructiveEntries: *main.ListUnmanaged(ChunkEntries), lightRefreshList: *main.List(*chunk_meshing.ChunkMesh)) main.ListUnmanaged(PositionEntry) {
|
||||
std.debug.assert(lightQueue.startIndex == lightQueue.endIndex);
|
||||
for(lights) |entry| {
|
||||
const index = chunk.getIndex(entry.x, entry.y, entry.z);
|
||||
@ -259,10 +273,10 @@ pub const ChannelChunk = struct {
|
||||
calculateIncomingOcclusion(&result.value, self.ch.data.getValue(index), self.ch.pos.voxelSize, entry.sourceDir);
|
||||
lightQueue.enqueue(result);
|
||||
}
|
||||
return self.propagateDestructive(lightQueue, constructiveEntries, false);
|
||||
return self.propagateDestructive(lightQueue, constructiveEntries, false, lightRefreshList);
|
||||
}
|
||||
|
||||
pub fn propagateLights(self: *ChannelChunk, lights: []const [3]u8, comptime checkNeighbors: bool) void {
|
||||
pub fn propagateLights(self: *ChannelChunk, lights: []const [3]u8, comptime checkNeighbors: bool, lightRefreshList: *main.List(*chunk_meshing.ChunkMesh)) void {
|
||||
var lightQueue = main.utils.CircularBufferQueue(Entry).init(main.stackAllocator, 1 << 12);
|
||||
defer lightQueue.deinit();
|
||||
for(lights) |pos| {
|
||||
@ -320,10 +334,10 @@ pub const ChannelChunk = struct {
|
||||
}
|
||||
}
|
||||
}
|
||||
self.propagateDirect(&lightQueue);
|
||||
self.propagateDirect(&lightQueue, lightRefreshList);
|
||||
}
|
||||
|
||||
pub fn propagateUniformSun(self: *ChannelChunk) void {
|
||||
pub fn propagateUniformSun(self: *ChannelChunk, lightRefreshList: *main.List(*chunk_meshing.ChunkMesh)) void {
|
||||
std.debug.assert(self.isSun);
|
||||
self.lock.lockWrite();
|
||||
if(self.data.paletteLength != 1) {
|
||||
@ -367,11 +381,11 @@ pub const ChannelChunk = struct {
|
||||
entry.sourceDir = neighbor ^ 1;
|
||||
}
|
||||
}
|
||||
neighborMesh.lightingData[1].propagateFromNeighbor(&lightQueue, &list);
|
||||
neighborMesh.lightingData[1].propagateFromNeighbor(&lightQueue, &list, lightRefreshList);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn propagateLightsDestructive(self: *ChannelChunk, lights: []const [3]u8) void {
|
||||
pub fn propagateLightsDestructive(self: *ChannelChunk, lights: []const [3]u8, lightRefreshList: *main.List(*chunk_meshing.ChunkMesh)) void {
|
||||
var lightQueue = main.utils.CircularBufferQueue(Entry).init(main.stackAllocator, 1 << 12);
|
||||
defer lightQueue.deinit();
|
||||
self.lock.lockRead();
|
||||
@ -384,7 +398,7 @@ pub const ChannelChunk = struct {
|
||||
defer constructiveEntries.deinit(main.stackAllocator);
|
||||
constructiveEntries.append(main.stackAllocator, .{
|
||||
.mesh = null,
|
||||
.entries = self.propagateDestructive(&lightQueue, &constructiveEntries, true),
|
||||
.entries = self.propagateDestructive(&lightQueue, &constructiveEntries, true, lightRefreshList),
|
||||
});
|
||||
for(constructiveEntries.items) |entries| {
|
||||
const mesh = entries.mesh;
|
||||
@ -401,7 +415,7 @@ pub const ChannelChunk = struct {
|
||||
lightQueue.enqueue(.{.x = entry.x, .y = entry.y, .z = entry.z, .value = value, .sourceDir = 6, .activeValue = 0b111});
|
||||
}
|
||||
channelChunk.lock.unlockWrite();
|
||||
channelChunk.propagateDirect(&lightQueue);
|
||||
channelChunk.propagateDirect(&lightQueue, lightRefreshList);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user