mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-09-11 21:37:46 -04:00
parent
b1dc5cacf0
commit
faaae6ff4a
@ -49,12 +49,11 @@ struct ChunkData {
|
|||||||
vec4 minPos;
|
vec4 minPos;
|
||||||
vec4 maxPos;
|
vec4 maxPos;
|
||||||
int voxelSize;
|
int voxelSize;
|
||||||
|
uint lightStart;
|
||||||
uint vertexStartOpaque;
|
uint vertexStartOpaque;
|
||||||
uint faceCountsByNormalOpaque[14];
|
uint faceCountsByNormalOpaque[14];
|
||||||
uint lightStartOpaque;
|
|
||||||
uint vertexStartTransparent;
|
uint vertexStartTransparent;
|
||||||
uint vertexCountTransparent;
|
uint vertexCountTransparent;
|
||||||
uint lightStartTransparent;
|
|
||||||
uint visibilityState;
|
uint visibilityState;
|
||||||
uint oldVisibilityState;
|
uint oldVisibilityState;
|
||||||
};
|
};
|
||||||
@ -72,11 +71,7 @@ void main() {
|
|||||||
vec3 modelPosition = vec3(chunks[chunkID].position.xyz - playerPositionInteger) - playerPositionFraction;
|
vec3 modelPosition = vec3(chunks[chunkID].position.xyz - playerPositionInteger) - playerPositionFraction;
|
||||||
int encodedPositionAndLightIndex = faceData[faceID].encodedPositionAndLightIndex;
|
int encodedPositionAndLightIndex = faceData[faceID].encodedPositionAndLightIndex;
|
||||||
int textureAndQuad = faceData[faceID].textureAndQuad;
|
int textureAndQuad = faceData[faceID].textureAndQuad;
|
||||||
#ifdef transparent
|
uint lightIndex = chunks[chunkID].lightStart + 4*(encodedPositionAndLightIndex >> 16);
|
||||||
uint lightIndex = chunks[chunkID].lightStartTransparent + 4*(encodedPositionAndLightIndex >> 16);
|
|
||||||
#else
|
|
||||||
uint lightIndex = chunks[chunkID].lightStartOpaque + 4*(encodedPositionAndLightIndex >> 16);
|
|
||||||
#endif
|
|
||||||
uint fullLight = lightData[lightIndex + vertexID];
|
uint fullLight = lightData[lightIndex + vertexID];
|
||||||
vec3 sunLight = vec3(
|
vec3 sunLight = vec3(
|
||||||
fullLight >> 25 & 31u,
|
fullLight >> 25 & 31u,
|
||||||
|
@ -12,12 +12,11 @@ struct ChunkData {
|
|||||||
vec4 minPos;
|
vec4 minPos;
|
||||||
vec4 maxPos;
|
vec4 maxPos;
|
||||||
int voxelSize;
|
int voxelSize;
|
||||||
|
uint lightStart;
|
||||||
uint vertexStartOpaque;
|
uint vertexStartOpaque;
|
||||||
uint faceCountsByNormalOpaque[14];
|
uint faceCountsByNormalOpaque[14];
|
||||||
uint lightStartOpaque;
|
|
||||||
uint vertexStartTransparent;
|
uint vertexStartTransparent;
|
||||||
uint vertexCountTransparent;
|
uint vertexCountTransparent;
|
||||||
uint lightStartTransparent;
|
|
||||||
uint visibilityState;
|
uint visibilityState;
|
||||||
uint oldVisibilityState;
|
uint oldVisibilityState;
|
||||||
};
|
};
|
||||||
|
@ -9,12 +9,11 @@ struct ChunkData {
|
|||||||
vec4 minPos;
|
vec4 minPos;
|
||||||
vec4 maxPos;
|
vec4 maxPos;
|
||||||
int voxelSize;
|
int voxelSize;
|
||||||
|
uint lightStart;
|
||||||
uint vertexStartOpaque;
|
uint vertexStartOpaque;
|
||||||
uint faceCountsByNormalOpaque[14];
|
uint faceCountsByNormalOpaque[14];
|
||||||
uint lightStartOpaque;
|
|
||||||
uint vertexStartTransparent;
|
uint vertexStartTransparent;
|
||||||
uint vertexCountTransparent;
|
uint vertexCountTransparent;
|
||||||
uint lightStartTransparent;
|
|
||||||
uint visibilityState;
|
uint visibilityState;
|
||||||
uint oldVisibilityState;
|
uint oldVisibilityState;
|
||||||
};
|
};
|
||||||
|
@ -7,12 +7,11 @@ struct ChunkData {
|
|||||||
vec4 minPos;
|
vec4 minPos;
|
||||||
vec4 maxPos;
|
vec4 maxPos;
|
||||||
int voxelSize;
|
int voxelSize;
|
||||||
|
uint lightStart;
|
||||||
uint vertexStartOpaque;
|
uint vertexStartOpaque;
|
||||||
uint faceCountsByNormalOpaque[14];
|
uint faceCountsByNormalOpaque[14];
|
||||||
uint lightStartOpaque;
|
|
||||||
uint vertexStartTransparent;
|
uint vertexStartTransparent;
|
||||||
uint vertexCountTransparent;
|
uint vertexCountTransparent;
|
||||||
uint lightStartTransparent;
|
|
||||||
uint visibilityState;
|
uint visibilityState;
|
||||||
uint oldVisibilityState;
|
uint oldVisibilityState;
|
||||||
};
|
};
|
||||||
|
@ -604,9 +604,9 @@ pub const meshes = struct { // MARK: meshes
|
|||||||
pub fn registerBlockBreakingAnimation(assetFolder: []const u8) void {
|
pub fn registerBlockBreakingAnimation(assetFolder: []const u8) void {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while(true) : (i += 1) {
|
while(true) : (i += 1) {
|
||||||
const path1 = std.fmt.allocPrint(main.stackAllocator.allocator, "assets/cubyz/blocks/textures/{}.png", .{i}) catch unreachable;
|
const path1 = std.fmt.allocPrint(main.stackAllocator.allocator, "assets/cubyz/blocks/textures/breaking/{}.png", .{i}) catch unreachable;
|
||||||
defer main.stackAllocator.free(path1);
|
defer main.stackAllocator.free(path1);
|
||||||
const path2 = std.fmt.allocPrint(main.stackAllocator.allocator, "{s}/cubyz/blocks/textures/{}.png", .{assetFolder, i}) catch unreachable;
|
const path2 = std.fmt.allocPrint(main.stackAllocator.allocator, "{s}/cubyz/blocks/textures/breaking/{}.png", .{assetFolder, i}) catch unreachable;
|
||||||
defer main.stackAllocator.free(path2);
|
defer main.stackAllocator.free(path2);
|
||||||
if(!main.files.hasFile(path1) and !main.files.hasFile(path2)) break;
|
if(!main.files.hasFile(path1) and !main.files.hasFile(path2)) break;
|
||||||
|
|
||||||
|
@ -43,6 +43,10 @@ pub const Neighbor = enum(u3) { // MARK: Neighbor
|
|||||||
const arr = [_]i32 {1, -1, 0, 0, 0, 0};
|
const arr = [_]i32 {1, -1, 0, 0, 0, 0};
|
||||||
return arr[@intFromEnum(self)];
|
return arr[@intFromEnum(self)];
|
||||||
}
|
}
|
||||||
|
/// Index to relative position
|
||||||
|
pub fn relPos(self: Neighbor) Vec3i {
|
||||||
|
return .{self.relX(), self.relY(), self.relZ()};
|
||||||
|
}
|
||||||
/// Index to bitMask for bitmap direction data
|
/// Index to bitMask for bitmap direction data
|
||||||
pub inline fn bitMask(self: Neighbor) u6 {
|
pub inline fn bitMask(self: Neighbor) u6 {
|
||||||
return @as(u6, 1) << @intFromEnum(self);
|
return @as(u6, 1) << @intFromEnum(self);
|
||||||
|
@ -2071,12 +2071,11 @@ pub fn generateBlockTexture(blockType: u16) Texture {
|
|||||||
.min = undefined,
|
.min = undefined,
|
||||||
.max = undefined,
|
.max = undefined,
|
||||||
.voxelSize = 1,
|
.voxelSize = 1,
|
||||||
|
.lightStart = lightAllocation.start,
|
||||||
.vertexStartOpaque = undefined,
|
.vertexStartOpaque = undefined,
|
||||||
.faceCountsByNormalOpaque = undefined,
|
.faceCountsByNormalOpaque = undefined,
|
||||||
.lightStartOpaque = lightAllocation.start,
|
|
||||||
.vertexStartTransparent = undefined,
|
.vertexStartTransparent = undefined,
|
||||||
.vertexCountTransparent = undefined,
|
.vertexCountTransparent = undefined,
|
||||||
.lightStartTransparent = lightAllocation.start,
|
|
||||||
.visibilityState = 0,
|
.visibilityState = 0,
|
||||||
.oldVisibilityState = 0,
|
.oldVisibilityState = 0,
|
||||||
}}, &chunkAllocation);
|
}}, &chunkAllocation);
|
||||||
|
@ -809,6 +809,7 @@ pub const MeshSelection = struct { // MARK: MeshSelection
|
|||||||
pub fn breakBlock(inventory: main.items.Inventory, slot: u32, deltaTime: f64) void {
|
pub fn breakBlock(inventory: main.items.Inventory, slot: u32, deltaTime: f64) void {
|
||||||
if(selectedBlockPos) |selectedPos| {
|
if(selectedBlockPos) |selectedPos| {
|
||||||
if(@reduce(.Or, lastSelectedBlockPos != selectedPos)) {
|
if(@reduce(.Or, lastSelectedBlockPos != selectedPos)) {
|
||||||
|
mesh_storage.removeBreakingAnimation(lastSelectedBlockPos);
|
||||||
lastSelectedBlockPos = selectedPos;
|
lastSelectedBlockPos = selectedPos;
|
||||||
currentBlockProgress = 0;
|
currentBlockProgress = 0;
|
||||||
}
|
}
|
||||||
@ -830,9 +831,13 @@ pub const MeshSelection = struct { // MARK: MeshSelection
|
|||||||
}
|
}
|
||||||
currentBlockProgress += @as(f32, @floatCast(deltaTime))/breakTime;
|
currentBlockProgress += @as(f32, @floatCast(deltaTime))/breakTime;
|
||||||
if(currentBlockProgress < 1) {
|
if(currentBlockProgress < 1) {
|
||||||
|
mesh_storage.removeBreakingAnimation(lastSelectedBlockPos);
|
||||||
|
mesh_storage.addBreakingAnimation(lastSelectedBlockPos, currentBlockProgress);
|
||||||
main.items.Inventory.Sync.ClientSide.mutex.unlock();
|
main.items.Inventory.Sync.ClientSide.mutex.unlock();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
mesh_storage.removeBreakingAnimation(lastSelectedBlockPos);
|
||||||
currentBlockProgress = 0;
|
currentBlockProgress = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -264,12 +264,11 @@ pub const ChunkData = extern struct {
|
|||||||
min: Vec3f align(16),
|
min: Vec3f align(16),
|
||||||
max: Vec3f align(16),
|
max: Vec3f align(16),
|
||||||
voxelSize: i32,
|
voxelSize: i32,
|
||||||
|
lightStart: u32,
|
||||||
vertexStartOpaque: u32,
|
vertexStartOpaque: u32,
|
||||||
faceCountsByNormalOpaque: [14]u32,
|
faceCountsByNormalOpaque: [14]u32,
|
||||||
lightStartOpaque: u32,
|
|
||||||
vertexStartTransparent: u32,
|
vertexStartTransparent: u32,
|
||||||
vertexCountTransparent: u32,
|
vertexCountTransparent: u32,
|
||||||
lightStartTransparent: u32,
|
|
||||||
visibilityState: u32,
|
visibilityState: u32,
|
||||||
oldVisibilityState: u32,
|
oldVisibilityState: u32,
|
||||||
};
|
};
|
||||||
@ -288,15 +287,12 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
|||||||
neighborFacesHigherLod: [6]main.ListUnmanaged(FaceData) = [_]main.ListUnmanaged(FaceData){.{}} ** 6,
|
neighborFacesHigherLod: [6]main.ListUnmanaged(FaceData) = [_]main.ListUnmanaged(FaceData){.{}} ** 6,
|
||||||
optionalFaces: main.ListUnmanaged(FaceData) = .{},
|
optionalFaces: main.ListUnmanaged(FaceData) = .{},
|
||||||
completeList: []FaceData = &.{},
|
completeList: []FaceData = &.{},
|
||||||
lightList: []u32 = &.{},
|
|
||||||
lightListNeedsUpload: bool = false,
|
|
||||||
coreLen: u32 = 0,
|
coreLen: u32 = 0,
|
||||||
sameLodLens: [6]u32 = .{0} ** 6,
|
sameLodLens: [6]u32 = .{0} ** 6,
|
||||||
higherLodLens: [6]u32 = .{0} ** 6,
|
higherLodLens: [6]u32 = .{0} ** 6,
|
||||||
optionalLen: u32 = 0,
|
optionalLen: u32 = 0,
|
||||||
mutex: std.Thread.Mutex = .{},
|
mutex: std.Thread.Mutex = .{},
|
||||||
bufferAllocation: graphics.SubAllocation = .{.start = 0, .len = 0},
|
bufferAllocation: graphics.SubAllocation = .{.start = 0, .len = 0},
|
||||||
lightAllocation: graphics.SubAllocation = .{.start = 0, .len = 0},
|
|
||||||
vertexCount: u31 = 0,
|
vertexCount: u31 = 0,
|
||||||
byNormalCount: [14]u32 = .{0} ** 14,
|
byNormalCount: [14]u32 = .{0} ** 14,
|
||||||
wasChanged: bool = false,
|
wasChanged: bool = false,
|
||||||
@ -305,7 +301,6 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
|||||||
|
|
||||||
fn deinit(self: *PrimitiveMesh) void {
|
fn deinit(self: *PrimitiveMesh) void {
|
||||||
faceBuffer.free(self.bufferAllocation);
|
faceBuffer.free(self.bufferAllocation);
|
||||||
lightBuffer.free(self.lightAllocation);
|
|
||||||
self.coreFaces.deinit(main.globalAllocator);
|
self.coreFaces.deinit(main.globalAllocator);
|
||||||
self.optionalFaces.deinit(main.globalAllocator);
|
self.optionalFaces.deinit(main.globalAllocator);
|
||||||
for(&self.neighborFacesSameLod) |*neighborFaces| {
|
for(&self.neighborFacesSameLod) |*neighborFaces| {
|
||||||
@ -315,7 +310,6 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
|||||||
neighborFaces.deinit(main.globalAllocator);
|
neighborFaces.deinit(main.globalAllocator);
|
||||||
}
|
}
|
||||||
main.globalAllocator.free(self.completeList);
|
main.globalAllocator.free(self.completeList);
|
||||||
main.globalAllocator.free(self.lightList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset(self: *PrimitiveMesh) void {
|
fn reset(self: *PrimitiveMesh) void {
|
||||||
@ -356,7 +350,7 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(self: *PrimitiveMesh, parent: *ChunkMesh) void {
|
fn finish(self: *PrimitiveMesh, parent: *ChunkMesh, lightList: *main.List(u32), lightMap: *std.AutoHashMap([4]u32, u16)) void {
|
||||||
var len: usize = self.coreFaces.items.len;
|
var len: usize = self.coreFaces.items.len;
|
||||||
for(self.neighborFacesSameLod) |neighborFaces| {
|
for(self.neighborFacesSameLod) |neighborFaces| {
|
||||||
len += neighborFaces.items.len;
|
len += neighborFaces.items.len;
|
||||||
@ -379,10 +373,6 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
|||||||
}
|
}
|
||||||
@memcpy(completeList[i..][0..self.optionalFaces.items.len], self.optionalFaces.items);
|
@memcpy(completeList[i..][0..self.optionalFaces.items.len], self.optionalFaces.items);
|
||||||
i += self.optionalFaces.items.len;
|
i += self.optionalFaces.items.len;
|
||||||
var lightList = main.List(u32).init(main.stackAllocator);
|
|
||||||
defer lightList.deinit();
|
|
||||||
var lightMap = std.AutoHashMap([4]u32, u16).init(main.stackAllocator.allocator);
|
|
||||||
defer lightMap.deinit();
|
|
||||||
|
|
||||||
self.min = @splat(std.math.floatMax(f32));
|
self.min = @splat(std.math.floatMax(f32));
|
||||||
self.max = @splat(-std.math.floatMax(f32));
|
self.max = @splat(-std.math.floatMax(f32));
|
||||||
@ -411,13 +401,7 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
|||||||
parent.lightingData[0].lock.unlockRead();
|
parent.lightingData[0].lock.unlockRead();
|
||||||
parent.lightingData[1].lock.unlockRead();
|
parent.lightingData[1].lock.unlockRead();
|
||||||
|
|
||||||
const completeLightList = main.globalAllocator.alloc(u32, lightList.items.len);
|
|
||||||
@memcpy(completeLightList, lightList.items);
|
|
||||||
|
|
||||||
self.mutex.lock();
|
self.mutex.lock();
|
||||||
const oldLightList = self.lightList;
|
|
||||||
self.lightList = completeLightList;
|
|
||||||
self.lightListNeedsUpload = true;
|
|
||||||
const oldList = self.completeList;
|
const oldList = self.completeList;
|
||||||
self.completeList = completeList;
|
self.completeList = completeList;
|
||||||
self.coreLen = @intCast(self.coreFaces.items.len);
|
self.coreLen = @intCast(self.coreFaces.items.len);
|
||||||
@ -430,7 +414,6 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
|||||||
self.optionalLen = @intCast(self.optionalFaces.items.len);
|
self.optionalLen = @intCast(self.optionalFaces.items.len);
|
||||||
self.mutex.unlock();
|
self.mutex.unlock();
|
||||||
main.globalAllocator.free(oldList);
|
main.globalAllocator.free(oldList);
|
||||||
main.globalAllocator.free(oldLightList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getValues(mesh: *ChunkMesh, wx: i32, wy: i32, wz: i32) [6]u8 {
|
fn getValues(mesh: *ChunkMesh, wx: i32, wy: i32, wz: i32) [6]u8 {
|
||||||
@ -657,10 +640,6 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
|||||||
std.debug.assert(i == fullBuffer.len);
|
std.debug.assert(i == fullBuffer.len);
|
||||||
self.vertexCount = @intCast(6*fullBuffer.len);
|
self.vertexCount = @intCast(6*fullBuffer.len);
|
||||||
self.wasChanged = true;
|
self.wasChanged = true;
|
||||||
if(self.lightListNeedsUpload) {
|
|
||||||
self.lightListNeedsUpload = false;
|
|
||||||
lightBuffer.uploadData(self.lightList, &self.lightAllocation);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -694,6 +673,10 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
lightingData: [2]*lighting.ChannelChunk,
|
lightingData: [2]*lighting.ChannelChunk,
|
||||||
opaqueMesh: PrimitiveMesh,
|
opaqueMesh: PrimitiveMesh,
|
||||||
transparentMesh: PrimitiveMesh,
|
transparentMesh: PrimitiveMesh,
|
||||||
|
lightList: []u32 = &.{},
|
||||||
|
lightListNeedsUpload: bool = false,
|
||||||
|
lightAllocation: graphics.SubAllocation = .{.start = 0, .len = 0},
|
||||||
|
|
||||||
lastNeighborsSameLod: [6]?*const ChunkMesh = [_]?*const ChunkMesh{null} ** 6,
|
lastNeighborsSameLod: [6]?*const ChunkMesh = [_]?*const ChunkMesh{null} ** 6,
|
||||||
lastNeighborsHigherLod: [6]?*const ChunkMesh = [_]?*const ChunkMesh{null} ** 6,
|
lastNeighborsHigherLod: [6]?*const ChunkMesh = [_]?*const ChunkMesh{null} ** 6,
|
||||||
isNeighborLod: [6]bool = .{false} ** 6,
|
isNeighborLod: [6]bool = .{false} ** 6,
|
||||||
@ -712,6 +695,10 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
min: Vec3f = undefined,
|
min: Vec3f = undefined,
|
||||||
max: Vec3f = undefined,
|
max: Vec3f = undefined,
|
||||||
|
|
||||||
|
blockBreakingFaces: main.List(FaceData),
|
||||||
|
blockBreakingFacesSortingData: []SortingData = &.{},
|
||||||
|
blockBreakingFacesChanged: bool = false,
|
||||||
|
|
||||||
pub fn init(self: *ChunkMesh, pos: chunk.ChunkPosition, ch: *chunk.Chunk) void {
|
pub fn init(self: *ChunkMesh, pos: chunk.ChunkPosition, ch: *chunk.Chunk) void {
|
||||||
self.* = ChunkMesh{
|
self.* = ChunkMesh{
|
||||||
.pos = pos,
|
.pos = pos,
|
||||||
@ -723,6 +710,7 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
lighting.ChannelChunk.init(ch, false),
|
lighting.ChannelChunk.init(ch, false),
|
||||||
lighting.ChannelChunk.init(ch, true),
|
lighting.ChannelChunk.init(ch, true),
|
||||||
},
|
},
|
||||||
|
.blockBreakingFaces = .init(main.globalAllocator),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -737,6 +725,10 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
for(self.lightingData) |lightingChunk| {
|
for(self.lightingData) |lightingChunk| {
|
||||||
lightingChunk.deinit();
|
lightingChunk.deinit();
|
||||||
}
|
}
|
||||||
|
self.blockBreakingFaces.deinit();
|
||||||
|
main.globalAllocator.free(self.blockBreakingFacesSortingData);
|
||||||
|
main.globalAllocator.free(self.lightList);
|
||||||
|
lightBuffer.free(self.lightAllocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn increaseRefCount(self: *ChunkMesh) void {
|
pub fn increaseRefCount(self: *ChunkMesh) void {
|
||||||
@ -1332,8 +1324,19 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
|
|
||||||
pub fn finishData(self: *ChunkMesh) void {
|
pub fn finishData(self: *ChunkMesh) void {
|
||||||
main.utils.assertLocked(&self.mutex);
|
main.utils.assertLocked(&self.mutex);
|
||||||
self.opaqueMesh.finish(self);
|
|
||||||
self.transparentMesh.finish(self);
|
var lightList = main.List(u32).init(main.stackAllocator);
|
||||||
|
defer lightList.deinit();
|
||||||
|
var lightMap = std.AutoHashMap([4]u32, u16).init(main.stackAllocator.allocator);
|
||||||
|
defer lightMap.deinit();
|
||||||
|
|
||||||
|
self.opaqueMesh.finish(self, &lightList, &lightMap);
|
||||||
|
self.transparentMesh.finish(self, &lightList, &lightMap);
|
||||||
|
|
||||||
|
self.lightList = main.globalAllocator.realloc(self.lightList, lightList.items.len);
|
||||||
|
@memcpy(self.lightList, lightList.items);
|
||||||
|
self.lightListNeedsUpload = true;
|
||||||
|
|
||||||
self.min = @min(self.opaqueMesh.min, self.transparentMesh.min);
|
self.min = @min(self.opaqueMesh.min, self.transparentMesh.min);
|
||||||
self.max = @max(self.opaqueMesh.max, self.transparentMesh.max);
|
self.max = @max(self.opaqueMesh.max, self.transparentMesh.max);
|
||||||
}
|
}
|
||||||
@ -1341,6 +1344,12 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
pub fn uploadData(self: *ChunkMesh) void {
|
pub fn uploadData(self: *ChunkMesh) void {
|
||||||
self.opaqueMesh.uploadData(self.isNeighborLod);
|
self.opaqueMesh.uploadData(self.isNeighborLod);
|
||||||
self.transparentMesh.uploadData(self.isNeighborLod);
|
self.transparentMesh.uploadData(self.isNeighborLod);
|
||||||
|
|
||||||
|
if(self.lightListNeedsUpload) {
|
||||||
|
self.lightListNeedsUpload = false;
|
||||||
|
lightBuffer.uploadData(self.lightList, &self.lightAllocation);
|
||||||
|
}
|
||||||
|
|
||||||
self.uploadChunkPosition();
|
self.uploadChunkPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1504,12 +1513,11 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
chunkBuffer.uploadData(&.{ChunkData{
|
chunkBuffer.uploadData(&.{ChunkData{
|
||||||
.position = .{self.pos.wx, self.pos.wy, self.pos.wz},
|
.position = .{self.pos.wx, self.pos.wy, self.pos.wz},
|
||||||
.voxelSize = self.pos.voxelSize,
|
.voxelSize = self.pos.voxelSize,
|
||||||
|
.lightStart = self.lightAllocation.start,
|
||||||
.vertexStartOpaque = self.opaqueMesh.bufferAllocation.start*4,
|
.vertexStartOpaque = self.opaqueMesh.bufferAllocation.start*4,
|
||||||
.faceCountsByNormalOpaque = self.opaqueMesh.byNormalCount,
|
.faceCountsByNormalOpaque = self.opaqueMesh.byNormalCount,
|
||||||
.lightStartOpaque = self.opaqueMesh.lightAllocation.start,
|
|
||||||
.vertexStartTransparent = self.transparentMesh.bufferAllocation.start*4,
|
.vertexStartTransparent = self.transparentMesh.bufferAllocation.start*4,
|
||||||
.vertexCountTransparent = self.transparentMesh.bufferAllocation.len*6,
|
.vertexCountTransparent = self.transparentMesh.bufferAllocation.len*6,
|
||||||
.lightStartTransparent = self.transparentMesh.lightAllocation.start,
|
|
||||||
.min = self.min,
|
.min = self.min,
|
||||||
.max = self.max,
|
.max = self.max,
|
||||||
.visibilityState = 0,
|
.visibilityState = 0,
|
||||||
@ -1526,7 +1534,7 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepareTransparentRendering(self: *ChunkMesh, playerPosition: Vec3d, chunkList: *main.List(u32)) void {
|
pub fn prepareTransparentRendering(self: *ChunkMesh, playerPosition: Vec3d, chunkList: *main.List(u32)) void {
|
||||||
if(self.transparentMesh.vertexCount == 0) return;
|
if(self.transparentMesh.vertexCount == 0 and self.blockBreakingFaces.items.len == 0) return;
|
||||||
|
|
||||||
var needsUpdate: bool = false;
|
var needsUpdate: bool = false;
|
||||||
if(self.transparentMesh.wasChanged) {
|
if(self.transparentMesh.wasChanged) {
|
||||||
@ -1552,8 +1560,8 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
}
|
}
|
||||||
offset += neighborLen;
|
offset += neighborLen;
|
||||||
}
|
}
|
||||||
self.sortingOutputBuffer = main.globalAllocator.realloc(self.sortingOutputBuffer, len);
|
|
||||||
self.currentSorting = main.globalAllocator.realloc(self.currentSorting, len);
|
self.currentSorting = main.globalAllocator.realloc(self.currentSorting, len);
|
||||||
|
self.sortingOutputBuffer = main.globalAllocator.realloc(self.sortingOutputBuffer, len + self.blockBreakingFaces.items.len);
|
||||||
for(0..self.transparentMesh.coreLen) |i| {
|
for(0..self.transparentMesh.coreLen) |i| {
|
||||||
self.currentSorting[i].face = self.transparentMesh.completeList[i];
|
self.currentSorting[i].face = self.transparentMesh.completeList[i];
|
||||||
}
|
}
|
||||||
@ -1580,6 +1588,15 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
self.lastTransparentUpdatePos = updatePos;
|
self.lastTransparentUpdatePos = updatePos;
|
||||||
needsUpdate = true;
|
needsUpdate = true;
|
||||||
}
|
}
|
||||||
|
if(self.blockBreakingFacesChanged) {
|
||||||
|
self.blockBreakingFacesChanged = false;
|
||||||
|
self.sortingOutputBuffer = main.globalAllocator.realloc(self.sortingOutputBuffer, self.currentSorting.len + self.blockBreakingFaces.items.len);
|
||||||
|
self.blockBreakingFacesSortingData = main.globalAllocator.realloc(self.blockBreakingFacesSortingData, self.blockBreakingFaces.items.len);
|
||||||
|
for(0..self.blockBreakingFaces.items.len) |i| {
|
||||||
|
self.blockBreakingFacesSortingData[i].face = self.blockBreakingFaces.items[i];
|
||||||
|
}
|
||||||
|
needsUpdate = true;
|
||||||
|
}
|
||||||
if(needsUpdate) {
|
if(needsUpdate) {
|
||||||
for(self.currentSorting) |*val| {
|
for(self.currentSorting) |*val| {
|
||||||
val.update(
|
val.update(
|
||||||
@ -1588,10 +1605,13 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
updatePos[2],
|
updatePos[2],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
for(0..self.blockBreakingFaces.items.len) |i| {
|
||||||
|
self.blockBreakingFacesSortingData[i].update(updatePos[0], updatePos[1], updatePos[2]);
|
||||||
|
}
|
||||||
|
|
||||||
// Sort by back vs front face:
|
// Sort by back vs front face:
|
||||||
{
|
|
||||||
var backFaceStart: usize = 0;
|
var backFaceStart: usize = 0;
|
||||||
|
{
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
var culledStart: usize = self.currentSorting.len;
|
var culledStart: usize = self.currentSorting.len;
|
||||||
while(culledStart > 0) {
|
while(culledStart > 0) {
|
||||||
@ -1622,6 +1642,9 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
// Sort it using bucket sort:
|
// Sort it using bucket sort:
|
||||||
var buckets: [34*3]u32 = undefined;
|
var buckets: [34*3]u32 = undefined;
|
||||||
@memset(&buckets, 0);
|
@memset(&buckets, 0);
|
||||||
|
for(self.blockBreakingFacesSortingData) |val| {
|
||||||
|
buckets[34*3 - 1 - val.distance] += 1;
|
||||||
|
}
|
||||||
for(self.currentSorting[0..self.culledSortingCount]) |val| {
|
for(self.currentSorting[0..self.culledSortingCount]) |val| {
|
||||||
buckets[34*3 - 1 - val.distance] += 1;
|
buckets[34*3 - 1 - val.distance] += 1;
|
||||||
}
|
}
|
||||||
@ -1632,12 +1655,23 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
prefixSum += copy;
|
prefixSum += copy;
|
||||||
}
|
}
|
||||||
// Move it over into a new buffer:
|
// Move it over into a new buffer:
|
||||||
for(0..self.culledSortingCount) |i| {
|
for(0..backFaceStart) |i| {
|
||||||
const bucket = 34*3 - 1 - self.currentSorting[i].distance;
|
const bucket = 34*3 - 1 - self.currentSorting[i].distance;
|
||||||
self.sortingOutputBuffer[buckets[bucket]] = self.currentSorting[i].face;
|
self.sortingOutputBuffer[buckets[bucket]] = self.currentSorting[i].face;
|
||||||
buckets[bucket] += 1;
|
buckets[bucket] += 1;
|
||||||
}
|
}
|
||||||
|
// Block breaking faces should be drawn after front faces, but before the corresponding backfaces.
|
||||||
|
for(self.blockBreakingFacesSortingData) |val| {
|
||||||
|
const bucket = 34*3 - 1 - val.distance;
|
||||||
|
self.sortingOutputBuffer[buckets[bucket]] = val.face;
|
||||||
|
buckets[bucket] += 1;
|
||||||
|
}
|
||||||
|
for(backFaceStart..self.culledSortingCount) |i| {
|
||||||
|
const bucket = 34*3 - 1 - self.currentSorting[i].distance;
|
||||||
|
self.sortingOutputBuffer[buckets[bucket]] = self.currentSorting[i].face;
|
||||||
|
buckets[bucket] += 1;
|
||||||
|
}
|
||||||
|
self.culledSortingCount += @intCast(self.blockBreakingFaces.items.len);
|
||||||
// Upload:
|
// Upload:
|
||||||
faceBuffer.uploadData(self.sortingOutputBuffer[0..self.culledSortingCount], &self.transparentMesh.bufferAllocation);
|
faceBuffer.uploadData(self.sortingOutputBuffer[0..self.culledSortingCount], &self.transparentMesh.bufferAllocation);
|
||||||
self.uploadChunkPosition();
|
self.uploadChunkPosition();
|
||||||
|
@ -942,3 +942,85 @@ pub fn updateChunkMesh(mesh: *chunk.Chunk) void {
|
|||||||
pub fn updateLightMap(map: *LightMap.LightMapFragment) void {
|
pub fn updateLightMap(map: *LightMap.LightMapFragment) void {
|
||||||
mapUpdatableList.enqueue(map);
|
mapUpdatableList.enqueue(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: Block breaking animation
|
||||||
|
|
||||||
|
pub fn addBreakingAnimation(pos: Vec3i, breakingProgress: f32) void {
|
||||||
|
const animationFrame: usize = @intFromFloat(breakingProgress*@as(f32, @floatFromInt(main.blocks.meshes.blockBreakingTextures.items.len)));
|
||||||
|
const texture = main.blocks.meshes.blockBreakingTextures.items[animationFrame];
|
||||||
|
|
||||||
|
const block = getBlock(pos[0], pos[1], pos[2]) orelse return;
|
||||||
|
const modelIndex = main.blocks.meshes.model(block);
|
||||||
|
const model = &main.models.models.items[modelIndex];
|
||||||
|
|
||||||
|
for(model.internalQuads) |quadIndex| {
|
||||||
|
addBreakingAnimationFace(pos, quadIndex, texture, null, block.transparent());
|
||||||
|
}
|
||||||
|
for(&model.neighborFacingQuads, 0..) |quads, n| {
|
||||||
|
for(quads) |quadIndex| {
|
||||||
|
addBreakingAnimationFace(pos, quadIndex, texture, @enumFromInt(n), block.transparent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn addBreakingAnimationFace(pos: Vec3i, quadIndex: u16, texture: u16, neighbor: ?chunk.Neighbor, isTransparent: bool) void {
|
||||||
|
const worldPos = pos +% if(neighbor) |n| n.relPos() else Vec3i{0, 0, 0};
|
||||||
|
const relPos = worldPos & @as(Vec3i, @splat(main.chunk.chunkMask));
|
||||||
|
const mesh = getMeshAndIncreaseRefCount(.{.wx = worldPos[0], .wy = worldPos[1], .wz = worldPos[2], .voxelSize = 1}) orelse return;
|
||||||
|
defer mesh.decreaseRefCount();
|
||||||
|
mesh.mutex.lock();
|
||||||
|
defer mesh.mutex.unlock();
|
||||||
|
const lightIndex = blk: {
|
||||||
|
const meshData = if(isTransparent) &mesh.transparentMesh else &mesh.opaqueMesh;
|
||||||
|
for(meshData.completeList) |face| {
|
||||||
|
if(face.position.x == relPos[0] and face.position.y == relPos[1] and face.position.z == relPos[2] and face.blockAndQuad.quadIndex == quadIndex) {
|
||||||
|
break :blk face.position.lightIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The face doesn't exist.
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
mesh.blockBreakingFacesChanged = true;
|
||||||
|
mesh.blockBreakingFaces.append(.{
|
||||||
|
.position = .{
|
||||||
|
.x = @intCast(relPos[0]),
|
||||||
|
.y = @intCast(relPos[1]),
|
||||||
|
.z = @intCast(relPos[2]),
|
||||||
|
.isBackFace = false,
|
||||||
|
.lightIndex = lightIndex,
|
||||||
|
},
|
||||||
|
.blockAndQuad = .{
|
||||||
|
.texture = texture,
|
||||||
|
.quadIndex = quadIndex,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn removeBreakingAnimationFace(pos: Vec3i, quadIndex: u16, neighbor: ?chunk.Neighbor) void {
|
||||||
|
const worldPos = pos +% if(neighbor) |n| n.relPos() else Vec3i{0, 0, 0};
|
||||||
|
const relPos = worldPos & @as(Vec3i, @splat(main.chunk.chunkMask));
|
||||||
|
const mesh = getMeshAndIncreaseRefCount(.{.wx = worldPos[0], .wy = worldPos[1], .wz = worldPos[2], .voxelSize = 1}) orelse return;
|
||||||
|
defer mesh.decreaseRefCount();
|
||||||
|
for(mesh.blockBreakingFaces.items, 0..) |face, i| {
|
||||||
|
if(face.position.x == relPos[0] and face.position.y == relPos[1] and face.position.z == relPos[2] and face.blockAndQuad.quadIndex == quadIndex) {
|
||||||
|
_ = mesh.blockBreakingFaces.swapRemove(i);
|
||||||
|
mesh.blockBreakingFacesChanged = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn removeBreakingAnimation(pos: Vec3i) void {
|
||||||
|
const block = getBlock(pos[0], pos[1], pos[2]) orelse return;
|
||||||
|
const modelIndex = main.blocks.meshes.model(block);
|
||||||
|
const model = &main.models.models.items[modelIndex];
|
||||||
|
|
||||||
|
for(model.internalQuads) |quadIndex| {
|
||||||
|
removeBreakingAnimationFace(pos, quadIndex, null);
|
||||||
|
}
|
||||||
|
for(&model.neighborFacingQuads, 0..) |quads, n| {
|
||||||
|
for(quads) |quadIndex| {
|
||||||
|
removeBreakingAnimationFace(pos, quadIndex, @enumFromInt(n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user