mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 19:28:49 -04:00
parent
77716b4679
commit
58b2a2627b
@ -93,7 +93,7 @@ pub const Neighbors = struct { // TODO: Should this be an enum?
|
||||
};
|
||||
|
||||
/// Gets the index of a given position inside this chunk.
|
||||
fn getIndex(x: i32, y: i32, z: i32) u32 {
|
||||
pub fn getIndex(x: i32, y: i32, z: i32) u32 {
|
||||
std.debug.assert((x & chunkMask) == x and (y & chunkMask) == y and (z & chunkMask) == z);
|
||||
return (@as(u32, @intCast(x)) << chunkShift) | (@as(u32, @intCast(y)) << chunkShift2) | @as(u32, @intCast(z));
|
||||
}
|
||||
@ -609,12 +609,12 @@ pub const meshing = struct {
|
||||
const z = (wz >> mesh.chunk.voxelSizeShift) & chunkMask;
|
||||
const index = getIndex(x, y, z);
|
||||
return .{
|
||||
mesh.lightingData.*[0].data[index],
|
||||
mesh.lightingData.*[1].data[index],
|
||||
mesh.lightingData.*[2].data[index],
|
||||
mesh.lightingData.*[3].data[index],
|
||||
mesh.lightingData.*[4].data[index],
|
||||
mesh.lightingData.*[5].data[index],
|
||||
mesh.lightingData.*[0].data[index].load(.Unordered),
|
||||
mesh.lightingData.*[1].data[index].load(.Unordered),
|
||||
mesh.lightingData.*[2].data[index].load(.Unordered),
|
||||
mesh.lightingData.*[3].data[index].load(.Unordered),
|
||||
mesh.lightingData.*[4].data[index].load(.Unordered),
|
||||
mesh.lightingData.*[5].data[index].load(.Unordered),
|
||||
};
|
||||
}
|
||||
|
||||
@ -812,9 +812,12 @@ pub const meshing = struct {
|
||||
|
||||
pub fn init(self: *ChunkMesh, pos: ChunkPosition, chunk: *Chunk) !void {
|
||||
const lightingData = try main.globalAllocator.create([6]lighting.ChannelChunk);
|
||||
for(lightingData) |*lightChunk| {
|
||||
try lightChunk.init(chunk);
|
||||
}
|
||||
try lightingData[0].init(chunk, .sun_red);
|
||||
try lightingData[1].init(chunk, .sun_green);
|
||||
try lightingData[2].init(chunk, .sun_blue);
|
||||
try lightingData[3].init(chunk, .red);
|
||||
try lightingData[4].init(chunk, .green);
|
||||
try lightingData[5].init(chunk, .blue);
|
||||
self.* = ChunkMesh{
|
||||
.pos = pos,
|
||||
.size = chunkSize*pos.voxelSize,
|
||||
@ -853,7 +856,7 @@ pub const meshing = struct {
|
||||
const prevVal = self.refCount.fetchSub(1, .Monotonic);
|
||||
std.debug.assert(prevVal != 0);
|
||||
if(prevVal == 1) {
|
||||
renderer.RenderStructure.addMeshToClearList(self) catch @panic("Out of Memory");
|
||||
renderer.RenderStructure.addMeshToClearListAndDecreaseRefCount(self) catch @panic("Out of Memory");
|
||||
}
|
||||
}
|
||||
|
||||
@ -886,6 +889,8 @@ pub const meshing = struct {
|
||||
self.mutex.lock();
|
||||
self.opaqueMesh.reset();
|
||||
self.transparentMesh.reset();
|
||||
var lightEmittingBlocks = std.ArrayList([3]u8).init(main.globalAllocator);
|
||||
defer lightEmittingBlocks.deinit();
|
||||
var n: u32 = 0;
|
||||
var x: u8 = 0;
|
||||
while(x < chunkSize): (x += 1) {
|
||||
@ -894,6 +899,7 @@ pub const meshing = struct {
|
||||
var z: u8 = 0;
|
||||
while(z < chunkSize): (z += 1) {
|
||||
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.light() != 0) try lightEmittingBlocks.append(.{x, y, z});
|
||||
if(block.typ == 0) continue;
|
||||
// Check all neighbors:
|
||||
for(Neighbors.iterable) |i| {
|
||||
@ -931,6 +937,10 @@ pub const meshing = struct {
|
||||
}
|
||||
}
|
||||
self.mutex.unlock();
|
||||
for(self.lightingData[3..]) |*lightingData| {
|
||||
try lightingData.propagateLights(lightEmittingBlocks.items, true);
|
||||
}
|
||||
// TODO: Sunlight propagation
|
||||
try self.finishNeighbors(false);
|
||||
}
|
||||
|
||||
@ -1071,7 +1081,7 @@ pub const meshing = struct {
|
||||
self.transparentMesh.clearNeighbor(neighbor, isLod);
|
||||
}
|
||||
|
||||
fn finishData(self: *ChunkMesh) !void {
|
||||
pub fn finishData(self: *ChunkMesh) !void {
|
||||
std.debug.assert(!self.mutex.tryLock());
|
||||
try self.opaqueMesh.finish(self);
|
||||
try self.transparentMesh.finish(self);
|
||||
@ -1167,7 +1177,7 @@ pub const meshing = struct {
|
||||
try neighborMesh.uploadData();
|
||||
} else {
|
||||
neighborMesh.increaseRefCount();
|
||||
try renderer.RenderStructure.addToUpdateList(neighborMesh);
|
||||
try renderer.RenderStructure.addToUpdateListAndDecreaseRefCount(neighborMesh);
|
||||
}
|
||||
} else {
|
||||
self.mutex.lock();
|
||||
|
155
src/lighting.zig
155
src/lighting.zig
@ -1,31 +1,164 @@
|
||||
const std = @import("std");
|
||||
const Atomic = std.atomic.Value;
|
||||
|
||||
const main = @import("root");
|
||||
const blocks = main.blocks;
|
||||
const chunk = main.chunk;
|
||||
|
||||
const Channel = enum {
|
||||
red,
|
||||
green,
|
||||
blue,
|
||||
const Channel = enum(u8) {
|
||||
sun_red = 0,
|
||||
sun_green = 1,
|
||||
sun_blue = 2,
|
||||
red = 3,
|
||||
green = 4,
|
||||
blue = 5,
|
||||
|
||||
pub fn shift(self: Channel) u5 {
|
||||
switch(self) {
|
||||
.red => return 16,
|
||||
.green => return 8,
|
||||
.blue => return 0,
|
||||
.red, .sun_red => return 16,
|
||||
.green, .sun_green => return 8,
|
||||
.blue, .sun_blue => return 0,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const ChannelChunk = struct {
|
||||
data: [chunk.chunkVolume]u8,
|
||||
data: [chunk.chunkVolume]Atomic(u8),
|
||||
mutex: std.Thread.Mutex,
|
||||
ch: *chunk.Chunk,
|
||||
channel: Channel,
|
||||
|
||||
pub fn init(self: *ChannelChunk, ch: *chunk.Chunk) !void {
|
||||
pub fn init(self: *ChannelChunk, ch: *chunk.Chunk, channel: Channel) !void {
|
||||
self.mutex = .{};
|
||||
for(&self.data, 0..) |*val, i| {
|
||||
val.* = if(ch.blocks[i].transparent()) 255 else 0; // TODO: Proper light propagation. This is just ambient occlusion at the moment.
|
||||
self.ch = ch;
|
||||
self.channel = channel;
|
||||
@memset(&self.data, Atomic(u8).init(0));
|
||||
}
|
||||
|
||||
const Entry = struct {
|
||||
x: u5,
|
||||
y: u5,
|
||||
z: u5,
|
||||
value: u8,
|
||||
|
||||
fn compare(_: void, a: @This(), b: @This()) std.math.Order {
|
||||
if (a.value > b.value) return .gt;
|
||||
if (a.value < b.value) return .lt;
|
||||
return .eq;
|
||||
}
|
||||
};
|
||||
|
||||
fn propagateDirect(self: *ChannelChunk, lightQueue: *std.PriorityQueue(Entry, void, Entry.compare)) std.mem.Allocator.Error!void {
|
||||
var neighborLists: [6]std.ArrayListUnmanaged(Entry) = .{.{}} ** 6;
|
||||
defer {
|
||||
for(&neighborLists) |*list| {
|
||||
list.deinit(main.globalAllocator);
|
||||
}
|
||||
}
|
||||
|
||||
self.mutex.lock();
|
||||
errdefer self.mutex.unlock();
|
||||
while(lightQueue.removeOrNull()) |entry| {
|
||||
const index = chunk.getIndex(entry.x, entry.y, entry.z);
|
||||
if(entry.value <= self.data[index].load(.Unordered)) continue;
|
||||
self.data[index].store(entry.value, .Unordered);
|
||||
for(chunk.Neighbors.iterable) |neighbor| {
|
||||
const nx = entry.x + chunk.Neighbors.relX[neighbor];
|
||||
const ny = entry.y + chunk.Neighbors.relY[neighbor];
|
||||
const nz = entry.z + chunk.Neighbors.relZ[neighbor];
|
||||
var result: Entry = .{.x = @intCast(nx & chunk.chunkMask), .y = @intCast(ny & chunk.chunkMask), .z = @intCast(nz & chunk.chunkMask), .value = entry.value};
|
||||
result.value -|= 8*|@as(u8, @intCast(self.ch.pos.voxelSize));
|
||||
if(result.value == 0) continue;
|
||||
if(nx < 0 or nx >= chunk.chunkSize or ny < 0 or ny >= chunk.chunkSize or nz < 0 or nz >= chunk.chunkSize) {
|
||||
try neighborLists[neighbor].append(main.globalAllocator, result);
|
||||
continue;
|
||||
}
|
||||
const neighborIndex = chunk.getIndex(nx, ny, nz);
|
||||
var absorption: u8 = @intCast(self.ch.blocks[neighborIndex].absorption() >> self.channel.shift() & 255);
|
||||
absorption *|= @intCast(self.ch.pos.voxelSize);
|
||||
result.value -|= absorption;
|
||||
if(result.value != 0) try lightQueue.add(result);
|
||||
}
|
||||
}
|
||||
self.mutex.unlock();
|
||||
if(main.renderer.RenderStructure.getMeshAndIncreaseRefCount(self.ch.pos)) |mesh| {
|
||||
mesh.mutex.lock();
|
||||
defer mesh.mutex.unlock();
|
||||
try mesh.finishData();
|
||||
try main.renderer.RenderStructure.addToUpdateListAndDecreaseRefCount(mesh);
|
||||
}
|
||||
|
||||
for(0..6) |neighbor| {
|
||||
if(neighborLists[neighbor].items.len == 0) continue;
|
||||
const neighborMesh = main.renderer.RenderStructure.getNeighborAndIncreaseRefCount(self.ch.pos, self.ch.pos.voxelSize, @intCast(neighbor)) orelse continue;
|
||||
defer neighborMesh.decreaseRefCount();
|
||||
try neighborMesh.lightingData[@intFromEnum(self.channel)].propagateFromNeighbor(neighborLists[neighbor].items);
|
||||
}
|
||||
}
|
||||
|
||||
fn propagateFromNeighbor(self: *ChannelChunk, lights: []Entry) std.mem.Allocator.Error!void {
|
||||
var lightQueue = std.PriorityQueue(Entry, void, Entry.compare).init(main.globalAllocator, {});
|
||||
defer lightQueue.deinit();
|
||||
for(lights) |entry| {
|
||||
const index = chunk.getIndex(entry.x, entry.y, entry.z);
|
||||
var result = entry;
|
||||
var absorption: u8 = @intCast(self.ch.blocks[index].absorption() >> self.channel.shift() & 255);
|
||||
absorption *|= @intCast(self.ch.pos.voxelSize);
|
||||
result.value -|= absorption;
|
||||
if(result.value != 0) try lightQueue.add(result);
|
||||
}
|
||||
try self.propagateDirect(&lightQueue);
|
||||
}
|
||||
|
||||
pub fn propagateLights(self: *ChannelChunk, lights: [][3]u8, comptime checkNeighbors: bool) std.mem.Allocator.Error!void {
|
||||
var lightQueue = std.PriorityQueue(Entry, void, Entry.compare).init(main.globalAllocator, {});
|
||||
defer lightQueue.deinit();
|
||||
for(lights) |pos| {
|
||||
const index = chunk.getIndex(pos[0], pos[1], pos[2]);
|
||||
try lightQueue.add(.{.x = @intCast(pos[0]), .y = @intCast(pos[1]), .z = @intCast(pos[2]), .value = @intCast(self.ch.blocks[index].light() >> self.channel.shift() & 255)});
|
||||
}
|
||||
if(checkNeighbors) {
|
||||
for(0..6) |neighbor| {
|
||||
const x3: i32 = if(neighbor & 1 == 0) chunk.chunkMask else 0;
|
||||
var x1: i32 = 0;
|
||||
while(x1 < chunk.chunkSize): (x1 += 1) {
|
||||
var x2: i32 = 0;
|
||||
while(x2 < chunk.chunkSize): (x2 += 1) {
|
||||
var x: i32 = undefined;
|
||||
var y: i32 = undefined;
|
||||
var z: i32 = undefined;
|
||||
if(chunk.Neighbors.relX[neighbor] != 0) {
|
||||
x = x3;
|
||||
y = x1;
|
||||
z = x2;
|
||||
} else if(chunk.Neighbors.relY[neighbor] != 0) {
|
||||
x = x1;
|
||||
y = x3;
|
||||
z = x2;
|
||||
} else {
|
||||
x = x2;
|
||||
y = x1;
|
||||
z = x3;
|
||||
}
|
||||
const otherX = x+%chunk.Neighbors.relX[neighbor] & chunk.chunkMask;
|
||||
const otherY = y+%chunk.Neighbors.relY[neighbor] & chunk.chunkMask;
|
||||
const otherZ = z+%chunk.Neighbors.relZ[neighbor] & chunk.chunkMask;
|
||||
const neighborMesh = main.renderer.RenderStructure.getNeighborAndIncreaseRefCount(self.ch.pos, self.ch.pos.voxelSize, @intCast(neighbor)) orelse continue;
|
||||
defer neighborMesh.decreaseRefCount();
|
||||
const neighborLightChunk = &neighborMesh.lightingData[@intFromEnum(self.channel)];
|
||||
const index = chunk.getIndex(x, y, z);
|
||||
const neighborIndex = chunk.getIndex(otherX, otherY, otherZ);
|
||||
var value: u8 = neighborLightChunk.data[neighborIndex].load(.Unordered);
|
||||
value -|= 8*|@as(u8, @intCast(self.ch.pos.voxelSize));
|
||||
if(value == 0) continue;
|
||||
var absorption: u8 = @intCast(self.ch.blocks[index].absorption() >> self.channel.shift() & 255);
|
||||
absorption *|= @intCast(self.ch.pos.voxelSize);
|
||||
value -|= absorption;
|
||||
if(value != 0) try lightQueue.add(.{.x = @intCast(x), .y = @intCast(y), .z = @intCast(z), .value = value});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
try self.propagateDirect(&lightQueue);
|
||||
}
|
||||
};
|
@ -1601,14 +1601,14 @@ pub const RenderStructure = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn addMeshToClearList(mesh: *chunk.meshing.ChunkMesh) !void {
|
||||
pub fn addMeshToClearListAndDecreaseRefCount(mesh: *chunk.meshing.ChunkMesh) !void {
|
||||
std.debug.assert(mesh.refCount.load(.Monotonic) == 0);
|
||||
mutex.lock();
|
||||
defer mutex.unlock();
|
||||
try clearList.append(mesh);
|
||||
}
|
||||
|
||||
pub fn addToUpdateList(mesh: *chunk.meshing.ChunkMesh) !void {
|
||||
pub fn addToUpdateListAndDecreaseRefCount(mesh: *chunk.meshing.ChunkMesh) !void {
|
||||
std.debug.assert(mesh.refCount.load(.Monotonic) != 0);
|
||||
mutex.lock();
|
||||
defer mutex.unlock();
|
||||
|
Loading…
x
Reference in New Issue
Block a user