mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 19:28:49 -04:00
parent
b1dc5cacf0
commit
faaae6ff4a
@ -49,12 +49,11 @@ struct ChunkData {
|
||||
vec4 minPos;
|
||||
vec4 maxPos;
|
||||
int voxelSize;
|
||||
uint lightStart;
|
||||
uint vertexStartOpaque;
|
||||
uint faceCountsByNormalOpaque[14];
|
||||
uint lightStartOpaque;
|
||||
uint vertexStartTransparent;
|
||||
uint vertexCountTransparent;
|
||||
uint lightStartTransparent;
|
||||
uint visibilityState;
|
||||
uint oldVisibilityState;
|
||||
};
|
||||
@ -72,11 +71,7 @@ void main() {
|
||||
vec3 modelPosition = vec3(chunks[chunkID].position.xyz - playerPositionInteger) - playerPositionFraction;
|
||||
int encodedPositionAndLightIndex = faceData[faceID].encodedPositionAndLightIndex;
|
||||
int textureAndQuad = faceData[faceID].textureAndQuad;
|
||||
#ifdef transparent
|
||||
uint lightIndex = chunks[chunkID].lightStartTransparent + 4*(encodedPositionAndLightIndex >> 16);
|
||||
#else
|
||||
uint lightIndex = chunks[chunkID].lightStartOpaque + 4*(encodedPositionAndLightIndex >> 16);
|
||||
#endif
|
||||
uint lightIndex = chunks[chunkID].lightStart + 4*(encodedPositionAndLightIndex >> 16);
|
||||
uint fullLight = lightData[lightIndex + vertexID];
|
||||
vec3 sunLight = vec3(
|
||||
fullLight >> 25 & 31u,
|
||||
|
@ -12,12 +12,11 @@ struct ChunkData {
|
||||
vec4 minPos;
|
||||
vec4 maxPos;
|
||||
int voxelSize;
|
||||
uint lightStart;
|
||||
uint vertexStartOpaque;
|
||||
uint faceCountsByNormalOpaque[14];
|
||||
uint lightStartOpaque;
|
||||
uint vertexStartTransparent;
|
||||
uint vertexCountTransparent;
|
||||
uint lightStartTransparent;
|
||||
uint visibilityState;
|
||||
uint oldVisibilityState;
|
||||
};
|
||||
|
@ -9,12 +9,11 @@ struct ChunkData {
|
||||
vec4 minPos;
|
||||
vec4 maxPos;
|
||||
int voxelSize;
|
||||
uint lightStart;
|
||||
uint vertexStartOpaque;
|
||||
uint faceCountsByNormalOpaque[14];
|
||||
uint lightStartOpaque;
|
||||
uint vertexStartTransparent;
|
||||
uint vertexCountTransparent;
|
||||
uint lightStartTransparent;
|
||||
uint visibilityState;
|
||||
uint oldVisibilityState;
|
||||
};
|
||||
|
@ -7,12 +7,11 @@ struct ChunkData {
|
||||
vec4 minPos;
|
||||
vec4 maxPos;
|
||||
int voxelSize;
|
||||
uint lightStart;
|
||||
uint vertexStartOpaque;
|
||||
uint faceCountsByNormalOpaque[14];
|
||||
uint lightStartOpaque;
|
||||
uint vertexStartTransparent;
|
||||
uint vertexCountTransparent;
|
||||
uint lightStartTransparent;
|
||||
uint visibilityState;
|
||||
uint oldVisibilityState;
|
||||
};
|
||||
|
@ -604,9 +604,9 @@ pub const meshes = struct { // MARK: meshes
|
||||
pub fn registerBlockBreakingAnimation(assetFolder: []const u8) void {
|
||||
var i: usize = 0;
|
||||
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);
|
||||
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);
|
||||
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};
|
||||
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
|
||||
pub inline fn bitMask(self: Neighbor) u6 {
|
||||
return @as(u6, 1) << @intFromEnum(self);
|
||||
|
@ -2071,12 +2071,11 @@ pub fn generateBlockTexture(blockType: u16) Texture {
|
||||
.min = undefined,
|
||||
.max = undefined,
|
||||
.voxelSize = 1,
|
||||
.lightStart = lightAllocation.start,
|
||||
.vertexStartOpaque = undefined,
|
||||
.faceCountsByNormalOpaque = undefined,
|
||||
.lightStartOpaque = lightAllocation.start,
|
||||
.vertexStartTransparent = undefined,
|
||||
.vertexCountTransparent = undefined,
|
||||
.lightStartTransparent = lightAllocation.start,
|
||||
.visibilityState = 0,
|
||||
.oldVisibilityState = 0,
|
||||
}}, &chunkAllocation);
|
||||
|
@ -809,6 +809,7 @@ pub const MeshSelection = struct { // MARK: MeshSelection
|
||||
pub fn breakBlock(inventory: main.items.Inventory, slot: u32, deltaTime: f64) void {
|
||||
if(selectedBlockPos) |selectedPos| {
|
||||
if(@reduce(.Or, lastSelectedBlockPos != selectedPos)) {
|
||||
mesh_storage.removeBreakingAnimation(lastSelectedBlockPos);
|
||||
lastSelectedBlockPos = selectedPos;
|
||||
currentBlockProgress = 0;
|
||||
}
|
||||
@ -830,9 +831,13 @@ pub const MeshSelection = struct { // MARK: MeshSelection
|
||||
}
|
||||
currentBlockProgress += @as(f32, @floatCast(deltaTime))/breakTime;
|
||||
if(currentBlockProgress < 1) {
|
||||
mesh_storage.removeBreakingAnimation(lastSelectedBlockPos);
|
||||
mesh_storage.addBreakingAnimation(lastSelectedBlockPos, currentBlockProgress);
|
||||
main.items.Inventory.Sync.ClientSide.mutex.unlock();
|
||||
|
||||
return;
|
||||
} else {
|
||||
mesh_storage.removeBreakingAnimation(lastSelectedBlockPos);
|
||||
currentBlockProgress = 0;
|
||||
}
|
||||
} else {
|
||||
|
@ -264,12 +264,11 @@ pub const ChunkData = extern struct {
|
||||
min: Vec3f align(16),
|
||||
max: Vec3f align(16),
|
||||
voxelSize: i32,
|
||||
lightStart: u32,
|
||||
vertexStartOpaque: u32,
|
||||
faceCountsByNormalOpaque: [14]u32,
|
||||
lightStartOpaque: u32,
|
||||
vertexStartTransparent: u32,
|
||||
vertexCountTransparent: u32,
|
||||
lightStartTransparent: u32,
|
||||
visibilityState: u32,
|
||||
oldVisibilityState: u32,
|
||||
};
|
||||
@ -288,15 +287,12 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
||||
neighborFacesHigherLod: [6]main.ListUnmanaged(FaceData) = [_]main.ListUnmanaged(FaceData){.{}} ** 6,
|
||||
optionalFaces: main.ListUnmanaged(FaceData) = .{},
|
||||
completeList: []FaceData = &.{},
|
||||
lightList: []u32 = &.{},
|
||||
lightListNeedsUpload: bool = false,
|
||||
coreLen: u32 = 0,
|
||||
sameLodLens: [6]u32 = .{0} ** 6,
|
||||
higherLodLens: [6]u32 = .{0} ** 6,
|
||||
optionalLen: u32 = 0,
|
||||
mutex: std.Thread.Mutex = .{},
|
||||
bufferAllocation: graphics.SubAllocation = .{.start = 0, .len = 0},
|
||||
lightAllocation: graphics.SubAllocation = .{.start = 0, .len = 0},
|
||||
vertexCount: u31 = 0,
|
||||
byNormalCount: [14]u32 = .{0} ** 14,
|
||||
wasChanged: bool = false,
|
||||
@ -305,7 +301,6 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
||||
|
||||
fn deinit(self: *PrimitiveMesh) void {
|
||||
faceBuffer.free(self.bufferAllocation);
|
||||
lightBuffer.free(self.lightAllocation);
|
||||
self.coreFaces.deinit(main.globalAllocator);
|
||||
self.optionalFaces.deinit(main.globalAllocator);
|
||||
for(&self.neighborFacesSameLod) |*neighborFaces| {
|
||||
@ -315,7 +310,6 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
||||
neighborFaces.deinit(main.globalAllocator);
|
||||
}
|
||||
main.globalAllocator.free(self.completeList);
|
||||
main.globalAllocator.free(self.lightList);
|
||||
}
|
||||
|
||||
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;
|
||||
for(self.neighborFacesSameLod) |neighborFaces| {
|
||||
len += neighborFaces.items.len;
|
||||
@ -379,10 +373,6 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
||||
}
|
||||
@memcpy(completeList[i..][0..self.optionalFaces.items.len], self.optionalFaces.items);
|
||||
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.max = @splat(-std.math.floatMax(f32));
|
||||
@ -411,13 +401,7 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
||||
parent.lightingData[0].lock.unlockRead();
|
||||
parent.lightingData[1].lock.unlockRead();
|
||||
|
||||
const completeLightList = main.globalAllocator.alloc(u32, lightList.items.len);
|
||||
@memcpy(completeLightList, lightList.items);
|
||||
|
||||
self.mutex.lock();
|
||||
const oldLightList = self.lightList;
|
||||
self.lightList = completeLightList;
|
||||
self.lightListNeedsUpload = true;
|
||||
const oldList = self.completeList;
|
||||
self.completeList = completeList;
|
||||
self.coreLen = @intCast(self.coreFaces.items.len);
|
||||
@ -430,7 +414,6 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
||||
self.optionalLen = @intCast(self.optionalFaces.items.len);
|
||||
self.mutex.unlock();
|
||||
main.globalAllocator.free(oldList);
|
||||
main.globalAllocator.free(oldLightList);
|
||||
}
|
||||
|
||||
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);
|
||||
self.vertexCount = @intCast(6*fullBuffer.len);
|
||||
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,
|
||||
opaqueMesh: PrimitiveMesh,
|
||||
transparentMesh: PrimitiveMesh,
|
||||
lightList: []u32 = &.{},
|
||||
lightListNeedsUpload: bool = false,
|
||||
lightAllocation: graphics.SubAllocation = .{.start = 0, .len = 0},
|
||||
|
||||
lastNeighborsSameLod: [6]?*const ChunkMesh = [_]?*const ChunkMesh{null} ** 6,
|
||||
lastNeighborsHigherLod: [6]?*const ChunkMesh = [_]?*const ChunkMesh{null} ** 6,
|
||||
isNeighborLod: [6]bool = .{false} ** 6,
|
||||
@ -712,6 +695,10 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
||||
min: 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 {
|
||||
self.* = ChunkMesh{
|
||||
.pos = pos,
|
||||
@ -723,6 +710,7 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
||||
lighting.ChannelChunk.init(ch, false),
|
||||
lighting.ChannelChunk.init(ch, true),
|
||||
},
|
||||
.blockBreakingFaces = .init(main.globalAllocator),
|
||||
};
|
||||
}
|
||||
|
||||
@ -737,6 +725,10 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
||||
for(self.lightingData) |lightingChunk| {
|
||||
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 {
|
||||
@ -1332,8 +1324,19 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
||||
|
||||
pub fn finishData(self: *ChunkMesh) void {
|
||||
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.max = @max(self.opaqueMesh.max, self.transparentMesh.max);
|
||||
}
|
||||
@ -1341,6 +1344,12 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
||||
pub fn uploadData(self: *ChunkMesh) void {
|
||||
self.opaqueMesh.uploadData(self.isNeighborLod);
|
||||
self.transparentMesh.uploadData(self.isNeighborLod);
|
||||
|
||||
if(self.lightListNeedsUpload) {
|
||||
self.lightListNeedsUpload = false;
|
||||
lightBuffer.uploadData(self.lightList, &self.lightAllocation);
|
||||
}
|
||||
|
||||
self.uploadChunkPosition();
|
||||
}
|
||||
|
||||
@ -1504,12 +1513,11 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
||||
chunkBuffer.uploadData(&.{ChunkData{
|
||||
.position = .{self.pos.wx, self.pos.wy, self.pos.wz},
|
||||
.voxelSize = self.pos.voxelSize,
|
||||
.lightStart = self.lightAllocation.start,
|
||||
.vertexStartOpaque = self.opaqueMesh.bufferAllocation.start*4,
|
||||
.faceCountsByNormalOpaque = self.opaqueMesh.byNormalCount,
|
||||
.lightStartOpaque = self.opaqueMesh.lightAllocation.start,
|
||||
.vertexStartTransparent = self.transparentMesh.bufferAllocation.start*4,
|
||||
.vertexCountTransparent = self.transparentMesh.bufferAllocation.len*6,
|
||||
.lightStartTransparent = self.transparentMesh.lightAllocation.start,
|
||||
.min = self.min,
|
||||
.max = self.max,
|
||||
.visibilityState = 0,
|
||||
@ -1526,7 +1534,7 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
||||
}
|
||||
|
||||
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;
|
||||
if(self.transparentMesh.wasChanged) {
|
||||
@ -1552,8 +1560,8 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
||||
}
|
||||
offset += neighborLen;
|
||||
}
|
||||
self.sortingOutputBuffer = main.globalAllocator.realloc(self.sortingOutputBuffer, 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| {
|
||||
self.currentSorting[i].face = self.transparentMesh.completeList[i];
|
||||
}
|
||||
@ -1580,6 +1588,15 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
||||
self.lastTransparentUpdatePos = updatePos;
|
||||
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) {
|
||||
for(self.currentSorting) |*val| {
|
||||
val.update(
|
||||
@ -1588,10 +1605,13 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
||||
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:
|
||||
{
|
||||
var backFaceStart: usize = 0;
|
||||
{
|
||||
var i: usize = 0;
|
||||
var culledStart: usize = self.currentSorting.len;
|
||||
while(culledStart > 0) {
|
||||
@ -1622,6 +1642,9 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
||||
// Sort it using bucket sort:
|
||||
var buckets: [34*3]u32 = undefined;
|
||||
@memset(&buckets, 0);
|
||||
for(self.blockBreakingFacesSortingData) |val| {
|
||||
buckets[34*3 - 1 - val.distance] += 1;
|
||||
}
|
||||
for(self.currentSorting[0..self.culledSortingCount]) |val| {
|
||||
buckets[34*3 - 1 - val.distance] += 1;
|
||||
}
|
||||
@ -1632,12 +1655,23 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
||||
prefixSum += copy;
|
||||
}
|
||||
// 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;
|
||||
self.sortingOutputBuffer[buckets[bucket]] = self.currentSorting[i].face;
|
||||
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:
|
||||
faceBuffer.uploadData(self.sortingOutputBuffer[0..self.culledSortingCount], &self.transparentMesh.bufferAllocation);
|
||||
self.uploadChunkPosition();
|
||||
|
@ -942,3 +942,85 @@ pub fn updateChunkMesh(mesh: *chunk.Chunk) void {
|
||||
pub fn updateLightMap(map: *LightMap.LightMapFragment) void {
|
||||
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