mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-09-08 11:44:21 -04:00
Rework meshing to support arbitrary quad models. Add some X-shaped grass to demonstrate that this system works.
This commit is contained in:
parent
21f2ab084a
commit
1f78bde24f
@ -34,6 +34,13 @@
|
||||
"variation" : 4,
|
||||
"depth" : 2,
|
||||
"smoothness" : 0.2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id" : "cubyz:simple_vegetation",
|
||||
"block" : "cubyz:grass_vegetation",
|
||||
"chance" : 1,
|
||||
"height" : 1,
|
||||
"height_variation" : 0
|
||||
},
|
||||
]
|
||||
}
|
||||
|
12
assets/cubyz/blocks/grass_vegetation.json
Normal file
12
assets/cubyz/blocks/grass_vegetation.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"class" : "leaf",
|
||||
"hardness" : 0.1,
|
||||
"drops" : [
|
||||
"auto"
|
||||
],
|
||||
"degradable" : true,
|
||||
"viewThrough" : true,
|
||||
"absorbedLight" : 0x121012,
|
||||
"model" : "cross",
|
||||
"texture" : "cubyz:grass_vegetation"
|
||||
}
|
BIN
assets/cubyz/blocks/textures/grass_vegetation.png
Normal file
BIN
assets/cubyz/blocks/textures/grass_vegetation.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
@ -154,7 +154,7 @@ void main() {
|
||||
position *= voxelSize;
|
||||
ivec3 totalOffset = ivec3(16*voxelSize*quads[quadIndex].corners[vertexID]);
|
||||
totalOffset = ivec3(permutationMatrix*(vec3(equal(mirrorVector, vec3(1)))*totalOffset + vec3(equal(mirrorVector, vec3(-1)))*(1 - totalOffset)));
|
||||
position += totalOffset - 16*voxelSize*ivec3(normal);
|
||||
position += totalOffset;
|
||||
|
||||
direction = position.xyz/16.0 + permutationMatrix*(mirrorVector*modelPosition);
|
||||
|
||||
|
@ -1847,7 +1847,7 @@ pub fn generateBlockTexture(blockType: u16) Texture {
|
||||
c.glDisable(c.GL_DEPTH_TEST);
|
||||
defer if(depthTest != 0) c.glEnable(c.GL_DEPTH_TEST);
|
||||
const cullFace = c.glIsEnabled(c.GL_CULL_FACE);
|
||||
c.glDisable(c.GL_CULL_FACE);
|
||||
c.glEnable(c.GL_CULL_FACE);
|
||||
defer if(cullFace != 0) c.glEnable(c.GL_CULL_FACE);
|
||||
|
||||
frameBuffer.init(false, c.GL_NEAREST, c.GL_REPEAT);
|
||||
@ -1874,31 +1874,29 @@ pub fn generateBlockTexture(blockType: u16) Texture {
|
||||
c.glBlendFunc(c.GL_ONE, c.GL_SRC1_COLOR);
|
||||
main.renderer.chunk_meshing.bindTransparentShaderAndUniforms(projMatrix, .{1, 1, 1});
|
||||
} else {
|
||||
if(block.mode().model(block).modelIndex == 0) {
|
||||
main.renderer.chunk_meshing.bindShaderAndUniforms(projMatrix, .{1, 1, 1});
|
||||
} else {
|
||||
std.log.err("TODO: Item textures for non-cube models.", .{});
|
||||
}
|
||||
main.renderer.chunk_meshing.bindShaderAndUniforms(projMatrix, .{1, 1, 1});
|
||||
}
|
||||
const uniforms = if(block.transparent()) &main.renderer.chunk_meshing.transparentUniforms else &main.renderer.chunk_meshing.uniforms;
|
||||
|
||||
var faceData: [6]main.renderer.chunk_meshing.FaceData = undefined;
|
||||
var faces: u8 = 0;
|
||||
faceData[faces + 0] = main.renderer.chunk_meshing.ChunkMesh.constructFaceData(block, main.chunk.Neighbors.dirPosX, 1+1, 1, 1, false);
|
||||
faceData[faces + 1] = main.renderer.chunk_meshing.ChunkMesh.constructFaceData(block, main.chunk.Neighbors.dirPosY, 1, 1+1, 1, false);
|
||||
faceData[faces + 2] = main.renderer.chunk_meshing.ChunkMesh.constructFaceData(block, main.chunk.Neighbors.dirUp, 1, 1, 1+1, false);
|
||||
faces += 3;
|
||||
if(block.hasBackFace()) {
|
||||
faceData[faces+2] = main.renderer.chunk_meshing.ChunkMesh.constructFaceData(block, main.chunk.Neighbors.dirPosX, 1, 1, 1, true);
|
||||
faceData[faces+1] = main.renderer.chunk_meshing.ChunkMesh.constructFaceData(block, main.chunk.Neighbors.dirPosY, 1, 1, 1, true);
|
||||
faceData[faces+0] = main.renderer.chunk_meshing.ChunkMesh.constructFaceData(block, main.chunk.Neighbors.dirUp, 1, 1, 1, true);
|
||||
faces += 3;
|
||||
var faceData: main.ListUnmanaged(main.renderer.chunk_meshing.FaceData) = .{};
|
||||
defer faceData.deinit(main.stackAllocator);
|
||||
const model = &main.models.models.items[main.blocks.meshes.model(block).modelIndex];
|
||||
model.appendInternalQuadsToList(&faceData, main.stackAllocator, block, 1, 1, 1, false);
|
||||
for(main.chunk.Neighbors.iterable) |neighbor| {
|
||||
model.appendNeighborFacingQuadsToList(&faceData, main.stackAllocator, block, neighbor, 1 + main.chunk.Neighbors.relX[neighbor], 1 + main.chunk.Neighbors.relY[neighbor], 1 + main.chunk.Neighbors.relZ[neighbor], false);
|
||||
}
|
||||
for(faceData[0..faces]) |*face| {
|
||||
if(block.hasBackFace()) {
|
||||
model.appendInternalQuadsToList(&faceData, main.stackAllocator, block, 1, 1, 1, true);
|
||||
for(main.chunk.Neighbors.iterable) |neighbor| {
|
||||
model.appendNeighborFacingQuadsToList(&faceData, main.stackAllocator, block, neighbor, 1, 1, 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
for(faceData.items) |*face| {
|
||||
@memset(&face.light, ~@as(u32, 0));
|
||||
}
|
||||
var allocation: SubAllocation = .{.start = 0, .len = 0};
|
||||
main.renderer.chunk_meshing.faceBuffer.uploadData(faceData[0..faces], &allocation);
|
||||
main.renderer.chunk_meshing.faceBuffer.uploadData(faceData.items, &allocation);
|
||||
|
||||
c.glUniform3f(uniforms.modelPosition, -65.5 - 1.5, -65.5 - 1.5, -92.631 - 1.5);
|
||||
c.glUniform1i(uniforms.visibilityMask, 0xff);
|
||||
@ -1910,8 +1908,9 @@ pub fn generateBlockTexture(blockType: u16) Texture {
|
||||
c.glActiveTexture(c.GL_TEXTURE2);
|
||||
main.blocks.meshes.reflectivityAndAbsorptionTextureArray.bind();
|
||||
block_texture.depthTexture.bindTo(5);
|
||||
c.glDrawElementsBaseVertex(c.GL_TRIANGLES, 6*faces, c.GL_UNSIGNED_INT, null, allocation.start*4);
|
||||
c.glDrawElementsBaseVertex(c.GL_TRIANGLES, @intCast(6*faceData.items.len), c.GL_UNSIGNED_INT, null, allocation.start*4);
|
||||
|
||||
c.glDisable(c.GL_CULL_FACE);
|
||||
var finalFrameBuffer: FrameBuffer = undefined;
|
||||
finalFrameBuffer.init(false, c.GL_NEAREST, c.GL_REPEAT);
|
||||
finalFrameBuffer.updateSize(textureSize, textureSize, c.GL_RGBA8);
|
||||
|
187
src/models.zig
187
src/models.zig
@ -8,6 +8,8 @@ const vec = @import("vec.zig");
|
||||
const Vec3i = vec.Vec3i;
|
||||
const Vec3f = vec.Vec3f;
|
||||
const Vec2f = vec.Vec2f;
|
||||
const FaceData = main.renderer.chunk_meshing.FaceData;
|
||||
const NeverFailingAllocator = main.utils.NeverFailingAllocator;
|
||||
|
||||
var quadSSBO: graphics.SSBO = undefined;
|
||||
|
||||
@ -21,7 +23,81 @@ const QuadInfo = extern struct {
|
||||
const Model = struct {
|
||||
min: Vec3i,
|
||||
max: Vec3i,
|
||||
quads: []u16,
|
||||
internalQuads: []u16,
|
||||
neighborFacingQuads: [6][]u16,
|
||||
|
||||
fn getFaceNeighbor(quad: *const QuadInfo) ?u3 {
|
||||
var allZero: @Vector(3, bool) = .{true, true, true};
|
||||
var allOne: @Vector(3, bool) = .{true, true, true};
|
||||
for(quad.corners) |corner| {
|
||||
allZero = @select(bool, allZero, corner == Vec3f{0, 0, 0}, allZero); // vector and TODO: #14306
|
||||
allOne = @select(bool, allOne, corner == Vec3f{1, 1, 1}, allOne); // vector and TODO: #14306
|
||||
}
|
||||
if(allZero[0]) return Neighbors.dirNegX;
|
||||
if(allZero[1]) return Neighbors.dirNegY;
|
||||
if(allZero[2]) return Neighbors.dirDown;
|
||||
if(allOne[0]) return Neighbors.dirPosX;
|
||||
if(allOne[1]) return Neighbors.dirPosY;
|
||||
if(allOne[2]) return Neighbors.dirUp;
|
||||
return null;
|
||||
}
|
||||
|
||||
fn init(self: *Model, allocator: NeverFailingAllocator, quadInfos: []const QuadInfo) void {
|
||||
var amounts: [6]usize = .{0, 0, 0, 0, 0, 0};
|
||||
var internalAmount: usize = 0;
|
||||
for(quadInfos) |*quad| {
|
||||
if(getFaceNeighbor(quad)) |neighbor| {
|
||||
amounts[neighbor] += 1;
|
||||
} else {
|
||||
internalAmount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
for(0..6) |i| {
|
||||
self.neighborFacingQuads[i] = allocator.alloc(u16, amounts[i]);
|
||||
}
|
||||
self.internalQuads = allocator.alloc(u16, internalAmount);
|
||||
|
||||
var indices: [6]usize = .{0, 0, 0, 0, 0, 0};
|
||||
var internalIndex: usize = 0;
|
||||
for(quadInfos) |_quad| {
|
||||
var quad = _quad;
|
||||
if(getFaceNeighbor(&quad)) |neighbor| {
|
||||
for(&quad.corners) |*corner| {
|
||||
corner.* -= quad.normal;
|
||||
}
|
||||
const quadIndex = addQuad(quad);
|
||||
self.neighborFacingQuads[neighbor][indices[neighbor]] = quadIndex;
|
||||
indices[neighbor] += 1;
|
||||
} else {
|
||||
const quadIndex = addQuad(quad);
|
||||
self.internalQuads[internalIndex] = quadIndex;
|
||||
internalIndex += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deinit(self: *const Model, allocator: NeverFailingAllocator) void {
|
||||
for(0..6) |i| {
|
||||
allocator.free(self.neighborFacingQuads[i]);
|
||||
}
|
||||
allocator.free(self.internalQuads);
|
||||
}
|
||||
|
||||
fn appendQuadsToList(quadList: []const u16, list: *main.ListUnmanaged(FaceData), allocator: NeverFailingAllocator, block: main.blocks.Block, x: i32, y: i32, z: i32, comptime backFace: bool) void {
|
||||
for(quadList) |quadIndex| {
|
||||
const texture = main.blocks.meshes.textureIndex(block, quads.items[quadIndex].textureSlot);
|
||||
list.append(allocator, FaceData.init(texture, quadIndex, x, y, z, backFace));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn appendInternalQuadsToList(self: *const Model, list: *main.ListUnmanaged(FaceData), allocator: NeverFailingAllocator, block: main.blocks.Block, x: i32, y: i32, z: i32, comptime backFace: bool) void {
|
||||
appendQuadsToList(self.internalQuads, list, allocator, block, x, y, z, backFace);
|
||||
}
|
||||
|
||||
pub fn appendNeighborFacingQuadsToList(self: *const Model, list: *main.ListUnmanaged(FaceData), allocator: NeverFailingAllocator, block: main.blocks.Block, neighbor: u3, x: i32, y: i32, z: i32, comptime backFace: bool) void {
|
||||
appendQuadsToList(self.neighborFacingQuads[neighbor], list, allocator, block, x, y, z, backFace);
|
||||
}
|
||||
};
|
||||
|
||||
var nameToIndex: std.StringHashMap(u16) = undefined;
|
||||
@ -37,7 +113,7 @@ pub var quads: main.List(QuadInfo) = undefined;
|
||||
pub var models: main.List(Model) = undefined;
|
||||
pub var fullCube: u16 = undefined;
|
||||
|
||||
fn addQuad(info: QuadInfo) u16 {
|
||||
fn addQuad(info: QuadInfo) u16 { // TODO: Merge duplicates
|
||||
const index: u16 = @intCast(quads.items.len);
|
||||
quads.append(info);
|
||||
return index;
|
||||
@ -56,45 +132,78 @@ pub fn init() void {
|
||||
const cube = models.addOne();
|
||||
cube.min = .{0, 0, 0};
|
||||
cube.max = .{16, 16, 16};
|
||||
cube.quads = main.globalAllocator.alloc(u16, 6);
|
||||
cube.quads[chunk.Neighbors.dirNegX] = addQuad(.{
|
||||
.normal = .{-1, 0, 0},
|
||||
.corners = .{.{0, 1, 0}, .{0, 1, 1}, .{0, 0, 0}, .{0, 0, 1}},
|
||||
.cornerUV = .{.{0, 0}, .{0, 1}, .{1, 0}, .{1, 1}},
|
||||
.textureSlot = chunk.Neighbors.dirNegX,
|
||||
});
|
||||
cube.quads[chunk.Neighbors.dirPosX] = addQuad(.{
|
||||
.normal = .{1, 0, 0},
|
||||
.corners = .{.{1, 0, 0}, .{1, 0, 1}, .{1, 1, 0}, .{1, 1, 1}},
|
||||
.cornerUV = .{.{0, 0}, .{0, 1}, .{1, 0}, .{1, 1}},
|
||||
.textureSlot = chunk.Neighbors.dirPosX,
|
||||
});
|
||||
cube.quads[chunk.Neighbors.dirNegY] = addQuad(.{
|
||||
.normal = .{0, -1, 0},
|
||||
.corners = .{.{0, 0, 0}, .{0, 0, 1}, .{1, 0, 0}, .{1, 0, 1}},
|
||||
.cornerUV = .{.{0, 0}, .{0, 1}, .{1, 0}, .{1, 1}},
|
||||
.textureSlot = chunk.Neighbors.dirNegY,
|
||||
});
|
||||
cube.quads[chunk.Neighbors.dirPosY] = addQuad(.{
|
||||
.normal = .{0, 1, 0},
|
||||
.corners = .{.{1, 1, 0}, .{1, 1, 1}, .{0, 1, 0}, .{0, 1, 1}},
|
||||
.cornerUV = .{.{0, 0}, .{0, 1}, .{1, 0}, .{1, 1}},
|
||||
.textureSlot = chunk.Neighbors.dirPosY,
|
||||
});
|
||||
cube.quads[chunk.Neighbors.dirDown] = addQuad(.{
|
||||
.normal = .{0, 0, -1},
|
||||
.corners = .{.{0, 1, 0}, .{0, 0, 0}, .{1, 1, 0}, .{1, 0, 0}},
|
||||
.cornerUV = .{.{0, 0}, .{0, 1}, .{1, 0}, .{1, 1}},
|
||||
.textureSlot = chunk.Neighbors.dirDown,
|
||||
});
|
||||
cube.quads[chunk.Neighbors.dirUp] = addQuad(.{
|
||||
.normal = .{0, 0, 1},
|
||||
.corners = .{.{1, 1, 1}, .{1, 0, 1}, .{0, 1, 1}, .{0, 0, 1}},
|
||||
.cornerUV = .{.{0, 0}, .{0, 1}, .{1, 0}, .{1, 1}},
|
||||
.textureSlot = chunk.Neighbors.dirUp,
|
||||
cube.init(main.globalAllocator, &.{
|
||||
.{
|
||||
.normal = .{-1, 0, 0},
|
||||
.corners = .{.{0, 1, 0}, .{0, 1, 1}, .{0, 0, 0}, .{0, 0, 1}},
|
||||
.cornerUV = .{.{0, 0}, .{0, 1}, .{1, 0}, .{1, 1}},
|
||||
.textureSlot = chunk.Neighbors.dirNegX,
|
||||
},
|
||||
.{
|
||||
.normal = .{1, 0, 0},
|
||||
.corners = .{.{1, 0, 0}, .{1, 0, 1}, .{1, 1, 0}, .{1, 1, 1}},
|
||||
.cornerUV = .{.{0, 0}, .{0, 1}, .{1, 0}, .{1, 1}},
|
||||
.textureSlot = chunk.Neighbors.dirPosX,
|
||||
},
|
||||
.{
|
||||
.normal = .{0, -1, 0},
|
||||
.corners = .{.{0, 0, 0}, .{0, 0, 1}, .{1, 0, 0}, .{1, 0, 1}},
|
||||
.cornerUV = .{.{0, 0}, .{0, 1}, .{1, 0}, .{1, 1}},
|
||||
.textureSlot = chunk.Neighbors.dirNegY,
|
||||
},
|
||||
.{
|
||||
.normal = .{0, 1, 0},
|
||||
.corners = .{.{1, 1, 0}, .{1, 1, 1}, .{0, 1, 0}, .{0, 1, 1}},
|
||||
.cornerUV = .{.{0, 0}, .{0, 1}, .{1, 0}, .{1, 1}},
|
||||
.textureSlot = chunk.Neighbors.dirPosY,
|
||||
},
|
||||
.{
|
||||
.normal = .{0, 0, -1},
|
||||
.corners = .{.{0, 1, 0}, .{0, 0, 0}, .{1, 1, 0}, .{1, 0, 0}},
|
||||
.cornerUV = .{.{0, 0}, .{0, 1}, .{1, 0}, .{1, 1}},
|
||||
.textureSlot = chunk.Neighbors.dirDown,
|
||||
},
|
||||
.{
|
||||
.normal = .{0, 0, 1},
|
||||
.corners = .{.{1, 1, 1}, .{1, 0, 1}, .{0, 1, 1}, .{0, 0, 1}},
|
||||
.cornerUV = .{.{0, 0}, .{0, 1}, .{1, 0}, .{1, 1}},
|
||||
.textureSlot = chunk.Neighbors.dirUp,
|
||||
},
|
||||
});
|
||||
fullCube = cubeIndex;
|
||||
|
||||
const crossModelIndex: u16 = @intCast(models.items.len);
|
||||
nameToIndex.put("cross", crossModelIndex) catch unreachable;
|
||||
const cross = models.addOne();
|
||||
cross.min = .{0, 0, 0};
|
||||
cross.max = .{16, 16, 16};
|
||||
cross.init(main.globalAllocator, &.{
|
||||
.{
|
||||
.normal = .{-std.math.sqrt1_2, std.math.sqrt1_2, 0},
|
||||
.corners = .{.{1, 1, 0}, .{1, 1, 1}, .{0, 0, 0}, .{0, 0, 1}},
|
||||
.cornerUV = .{.{0, 0}, .{0, 1}, .{1, 0}, .{1, 1}},
|
||||
.textureSlot = 0,
|
||||
},
|
||||
.{
|
||||
.normal = .{std.math.sqrt1_2, -std.math.sqrt1_2, 0},
|
||||
.corners = .{.{0, 0, 0}, .{0, 0, 1}, .{1, 1, 0}, .{1, 1, 1}},
|
||||
.cornerUV = .{.{0, 0}, .{0, 1}, .{1, 0}, .{1, 1}},
|
||||
.textureSlot = 0,
|
||||
},
|
||||
.{
|
||||
.normal = .{-std.math.sqrt1_2, -std.math.sqrt1_2, 0},
|
||||
.corners = .{.{0, 1, 0}, .{0, 1, 1}, .{1, 0, 0}, .{1, 0, 1}},
|
||||
.cornerUV = .{.{0, 0}, .{0, 1}, .{1, 0}, .{1, 1}},
|
||||
.textureSlot = 0,
|
||||
},
|
||||
.{
|
||||
.normal = .{std.math.sqrt1_2, std.math.sqrt1_2, 0},
|
||||
.corners = .{.{1, 0, 0}, .{1, 0, 1}, .{0, 1, 0}, .{0, 1, 1}},
|
||||
.cornerUV = .{.{0, 0}, .{0, 1}, .{1, 0}, .{1, 1}},
|
||||
.textureSlot = 0,
|
||||
},
|
||||
});
|
||||
|
||||
quadSSBO = graphics.SSBO.initStatic(QuadInfo, quads.items);
|
||||
quadSSBO.bind(4);
|
||||
}
|
||||
@ -103,7 +212,7 @@ pub fn deinit() void {
|
||||
quadSSBO.deinit();
|
||||
nameToIndex.deinit();
|
||||
for(models.items) |model| {
|
||||
main.globalAllocator.free(model.quads);
|
||||
model.deinit(main.globalAllocator);
|
||||
}
|
||||
models.deinit();
|
||||
quads.deinit();
|
||||
|
@ -144,6 +144,13 @@ pub const FaceData = extern struct {
|
||||
quadIndex: u16,
|
||||
},
|
||||
light: [4]u32 = .{0, 0, 0, 0},
|
||||
|
||||
pub inline fn init(texture: u16, quadIndex: u16, x: i32, y: i32, z: i32, comptime backFace: bool) FaceData {
|
||||
return FaceData {
|
||||
.position = .{.x = @intCast(x), .y = @intCast(y), .z = @intCast(z), .permutation = @bitCast(@as(u6, 0)), .isBackFace = backFace}, // TODO: Handle permutation during meshing
|
||||
.blockAndQuad = .{.texture = texture, .quadIndex = quadIndex},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const PrimitiveMesh = struct {
|
||||
@ -181,15 +188,22 @@ const PrimitiveMesh = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn appendCore(self: *PrimitiveMesh, face: FaceData) void {
|
||||
self.coreFaces.append(main.globalAllocator, face);
|
||||
fn appendInternalQuadsToCore(self: *PrimitiveMesh, block: Block, x: i32, y: i32, z: i32, comptime backFace: bool) void {
|
||||
const model = blocks.meshes.model(block);
|
||||
models.models.items[model.modelIndex].appendInternalQuadsToList(&self.coreFaces, main.globalAllocator, block, x, y, z, backFace);
|
||||
}
|
||||
|
||||
fn appendNeighbor(self: *PrimitiveMesh, face: FaceData, neighbor: u3, comptime isLod: bool) void {
|
||||
fn appendNeighborFacingQuadsToCore(self: *PrimitiveMesh, block: Block, neighbor: u3, x: i32, y: i32, z: i32, comptime backFace: bool) void {
|
||||
const model = blocks.meshes.model(block);
|
||||
models.models.items[model.modelIndex].appendNeighborFacingQuadsToList(&self.coreFaces, main.globalAllocator, block, neighbor, x, y, z, backFace);
|
||||
}
|
||||
|
||||
fn appendNeighborFacingQuadsToNeighbor(self: *PrimitiveMesh, block: Block, neighbor: u3, x: i32, y: i32, z: i32, comptime backFace: bool, comptime isLod: bool) void {
|
||||
const model = blocks.meshes.model(block);
|
||||
if(isLod) {
|
||||
self.neighborFacesHigherLod[neighbor].append(main.globalAllocator, face);
|
||||
models.models.items[model.modelIndex].appendNeighborFacingQuadsToList(&self.neighborFacesHigherLod[neighbor ^ 1], main.globalAllocator, block, neighbor, x, y, z, backFace);
|
||||
} else {
|
||||
self.neighborFacesSameLod[neighbor].append(main.globalAllocator, face);
|
||||
models.models.items[model.modelIndex].appendNeighborFacingQuadsToList(&self.neighborFacesSameLod[neighbor ^ 1], main.globalAllocator, block, neighbor, x, y, z, backFace);
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,7 +283,7 @@ const PrimitiveMesh = struct {
|
||||
const normal = models.quads.items[quadIndex].normal;
|
||||
for(0..4) |i| {
|
||||
const vertexPos = models.quads.items[quadIndex].corners[i];
|
||||
const lightPos = vertexPos + @as(Vec3f, @floatFromInt(blockPos)) - normal*@as(Vec3f, @splat(0.5)) - @as(Vec3f, @splat(0.5));
|
||||
const lightPos = vertexPos + @as(Vec3f, @floatFromInt(blockPos)) + normal*@as(Vec3f, @splat(0.5)) - @as(Vec3f, @splat(0.5));
|
||||
const startPos: Vec3i = @intFromFloat(@floor(lightPos));
|
||||
const interp = lightPos - @floor(lightPos);
|
||||
var val: [6]f32 = .{0, 0, 0, 0, 0, 0};
|
||||
@ -344,36 +358,6 @@ const PrimitiveMesh = struct {
|
||||
self.vertexCount = @intCast(6*fullBuffer.len);
|
||||
self.wasChanged = true;
|
||||
}
|
||||
|
||||
fn addFace(self: *PrimitiveMesh, faceData: FaceData, fromNeighborChunk: ?u3) void {
|
||||
if(fromNeighborChunk) |neighbor| {
|
||||
self.neighborFacesSameLod[neighbor].append(main.globalAllocator, faceData);
|
||||
} else {
|
||||
self.coreFaces.append(main.globalAllocator, faceData);
|
||||
}
|
||||
}
|
||||
|
||||
fn removeFace(self: *PrimitiveMesh, faceData: FaceData, fromNeighborChunk: ?u3) void {
|
||||
if(fromNeighborChunk) |neighbor| {
|
||||
var pos: usize = std.math.maxInt(usize);
|
||||
for(self.neighborFacesSameLod[neighbor].items, 0..) |item, i| {
|
||||
if(std.meta.eql(faceData, item)) {
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ = self.neighborFacesSameLod[neighbor].swapRemove(pos);
|
||||
} else {
|
||||
var pos: usize = std.math.maxInt(usize);
|
||||
for(self.coreFaces.items, 0..) |item, i| {
|
||||
if(std.meta.eql(faceData, item)) {
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ = self.coreFaces.swapRemove(pos);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const ChunkMesh = struct {
|
||||
@ -669,14 +653,19 @@ pub const ChunkMesh = struct {
|
||||
if(canBeSeenThroughOtherBlock(block, neighborBlock, i)) {
|
||||
if(block.transparent()) {
|
||||
if(block.hasBackFace()) {
|
||||
self.transparentMesh.appendCore(constructFaceData(block, i ^ 1, x, y, z, true));
|
||||
self.transparentMesh.appendNeighborFacingQuadsToCore(block, i ^ 1, x, y, z, true);
|
||||
}
|
||||
self.transparentMesh.appendCore(constructFaceData(block, i, x2, y2, z2, false));
|
||||
self.transparentMesh.appendNeighborFacingQuadsToCore(block, i, x2, y2, z2, false);
|
||||
} else {
|
||||
self.opaqueMesh.appendCore(constructFaceData(block, i, x2, y2, z2, false)); // TODO: Create multiple faces for non-cube meshes.
|
||||
self.opaqueMesh.appendNeighborFacingQuadsToCore(block, i, x2, y2, z2, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(block.transparent()) {
|
||||
self.transparentMesh.appendInternalQuadsToCore(block, x, y, z, false);
|
||||
} else {
|
||||
self.opaqueMesh.appendInternalQuadsToCore(block, x, y, z, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -698,28 +687,11 @@ pub const ChunkMesh = struct {
|
||||
self.finishNeighbors();
|
||||
}
|
||||
|
||||
fn addFace(self: *ChunkMesh, faceData: FaceData, fromNeighborChunk: ?u3, transparent: bool) void {
|
||||
if(transparent) {
|
||||
self.transparentMesh.addFace(faceData, fromNeighborChunk);
|
||||
} else {
|
||||
self.opaqueMesh.addFace(faceData, fromNeighborChunk);
|
||||
}
|
||||
}
|
||||
|
||||
fn removeFace(self: *ChunkMesh, faceData: FaceData, fromNeighborChunk: ?u3, transparent: bool) void {
|
||||
if(transparent) {
|
||||
self.transparentMesh.removeFace(faceData, fromNeighborChunk);
|
||||
} else {
|
||||
self.opaqueMesh.removeFace(faceData, fromNeighborChunk);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn updateBlock(self: *ChunkMesh, _x: i32, _y: i32, _z: i32, newBlock: Block) void {
|
||||
self.mutex.lock();
|
||||
const x = _x & chunk.chunkMask;
|
||||
const y = _y & chunk.chunkMask;
|
||||
const z = _z & chunk.chunkMask;
|
||||
const oldBlock = self.chunk.blocks[chunk.getIndex(x, y, z)];
|
||||
self.chunk.blocks[chunk.getIndex(x, y, z)] = newBlock;
|
||||
self.mutex.unlock();
|
||||
for(self.lightingData[0..]) |lightingData| {
|
||||
@ -732,118 +704,36 @@ pub const ChunkMesh = struct {
|
||||
}
|
||||
self.mutex.lock();
|
||||
defer self.mutex.unlock();
|
||||
for(chunk.Neighbors.iterable) |neighbor| {
|
||||
var neighborMesh = self;
|
||||
var nx = x + chunk.Neighbors.relX[neighbor];
|
||||
var ny = y + chunk.Neighbors.relY[neighbor];
|
||||
var nz = z + chunk.Neighbors.relZ[neighbor];
|
||||
if(nx & chunk.chunkMask != nx or ny & chunk.chunkMask != ny or nz & chunk.chunkMask != nz) { // Outside this chunk.
|
||||
neighborMesh = mesh_storage.getNeighborFromRenderThread(self.pos, self.pos.voxelSize, neighbor) orelse continue;
|
||||
}
|
||||
if(neighborMesh != self) {
|
||||
self.mutex.unlock();
|
||||
deadlockFreeDoubleLock(&self.mutex, &neighborMesh.mutex);
|
||||
}
|
||||
defer if(neighborMesh != self) neighborMesh.mutex.unlock();
|
||||
nx &= chunk.chunkMask;
|
||||
ny &= chunk.chunkMask;
|
||||
nz &= chunk.chunkMask;
|
||||
const neighborBlock = neighborMesh.chunk.blocks[chunk.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);
|
||||
const oldVisibility = canBeSeenThroughOtherBlock(oldBlock, neighborBlock, neighbor);
|
||||
if(oldVisibility) { // Removing the face
|
||||
const faceData = constructFaceData(oldBlock, neighbor, nx, ny, nz, false);
|
||||
if(neighborMesh == self) {
|
||||
self.removeFace(faceData, null, oldBlock.transparent());
|
||||
} else {
|
||||
neighborMesh.removeFace(faceData, neighbor ^ 1, oldBlock.transparent());
|
||||
}
|
||||
if(oldBlock.hasBackFace()) {
|
||||
const backFaceData = constructFaceData(oldBlock, neighbor ^ 1, x, y, z, true);
|
||||
if(neighborMesh == self) {
|
||||
self.removeFace(backFaceData, null, true);
|
||||
} else {
|
||||
self.removeFace(backFaceData, neighbor, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(newVisibility) { // Adding the face
|
||||
const faceData = constructFaceData(newBlock, neighbor, nx, ny, nz, false);
|
||||
if(neighborMesh == self) {
|
||||
self.addFace(faceData, null, newBlock.transparent());
|
||||
} else {
|
||||
neighborMesh.addFace(faceData, neighbor ^ 1, newBlock.transparent());
|
||||
}
|
||||
if(newBlock.hasBackFace()) {
|
||||
const backFaceData = constructFaceData(newBlock, neighbor ^ 1, x, y, z, true);
|
||||
if(neighborMesh == self) {
|
||||
self.addFace(backFaceData, null, true);
|
||||
} else {
|
||||
self.addFace(backFaceData, neighbor, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{ // The face of the neighbor block
|
||||
const newVisibility = canBeSeenThroughOtherBlock(neighborBlock, newBlock, neighbor ^ 1);
|
||||
if(canBeSeenThroughOtherBlock(neighborBlock, oldBlock, neighbor ^ 1) != newVisibility) {
|
||||
if(newVisibility) { // Adding the face
|
||||
const faceData = constructFaceData(neighborBlock, neighbor ^ 1, x, y, z, false);
|
||||
if(neighborMesh == self) {
|
||||
self.addFace(faceData, null, neighborBlock.transparent());
|
||||
} else {
|
||||
self.addFace(faceData, neighbor, neighborBlock.transparent());
|
||||
}
|
||||
if(neighborBlock.hasBackFace()) {
|
||||
const backFaceData = constructFaceData(neighborBlock, neighbor, nx, ny, nz, true);
|
||||
if(neighborMesh == self) {
|
||||
self.addFace(backFaceData, null, true);
|
||||
} else {
|
||||
neighborMesh.addFace(backFaceData, neighbor ^ 1, true);
|
||||
}
|
||||
}
|
||||
} else { // Removing the face
|
||||
const faceData = constructFaceData(neighborBlock, neighbor ^ 1, x, y, z, false);
|
||||
if(neighborMesh == self) {
|
||||
self.removeFace(faceData, null, neighborBlock.transparent());
|
||||
} else {
|
||||
self.removeFace(faceData, neighbor, neighborBlock.transparent());
|
||||
}
|
||||
if(neighborBlock.hasBackFace()) {
|
||||
const backFaceData = constructFaceData(neighborBlock, neighbor, nx, ny, nz, true);
|
||||
if(neighborMesh == self) {
|
||||
self.removeFace(backFaceData, null, true);
|
||||
} else {
|
||||
neighborMesh.removeFace(backFaceData, neighbor ^ 1, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(neighborMesh != self) {
|
||||
_ = neighborMesh.needsLightRefresh.swap(false, .AcqRel);
|
||||
neighborMesh.finishData();
|
||||
neighborMesh.uploadData();
|
||||
}
|
||||
// Update neighbor chunks:
|
||||
if(x == 0) {
|
||||
self.lastNeighborsHigherLod[chunk.Neighbors.dirNegX] = null;
|
||||
self.lastNeighborsSameLod[chunk.Neighbors.dirNegX] = null;
|
||||
} else if(x == 31) {
|
||||
self.lastNeighborsHigherLod[chunk.Neighbors.dirPosX] = null;
|
||||
self.lastNeighborsSameLod[chunk.Neighbors.dirPosX] = null;
|
||||
}
|
||||
_ = self.needsLightRefresh.swap(false, .AcqRel);
|
||||
self.finishData();
|
||||
if(y == 0) {
|
||||
self.lastNeighborsHigherLod[chunk.Neighbors.dirNegY] = null;
|
||||
self.lastNeighborsSameLod[chunk.Neighbors.dirNegY] = null;
|
||||
} else if(y == 31) {
|
||||
self.lastNeighborsHigherLod[chunk.Neighbors.dirPosY] = null;
|
||||
self.lastNeighborsSameLod[chunk.Neighbors.dirPosY] = null;
|
||||
}
|
||||
if(z == 0) {
|
||||
self.lastNeighborsHigherLod[chunk.Neighbors.dirDown] = null;
|
||||
self.lastNeighborsSameLod[chunk.Neighbors.dirDown] = null;
|
||||
} else if(z == 31) {
|
||||
self.lastNeighborsHigherLod[chunk.Neighbors.dirUp] = null;
|
||||
self.lastNeighborsSameLod[chunk.Neighbors.dirUp] = null;
|
||||
}
|
||||
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.mutex.lock();
|
||||
self.uploadData();
|
||||
}
|
||||
|
||||
pub inline fn constructFaceData(block: Block, normal: u3, x: i32, y: i32, z: i32, comptime backFace: bool) FaceData {
|
||||
const model = blocks.meshes.model(block);
|
||||
const quadIndex = models.models.items[model.modelIndex].quads[normal];
|
||||
const texture = blocks.meshes.textureIndex(block, models.quads.items[quadIndex].textureSlot);
|
||||
return FaceData {
|
||||
.position = .{.x = @intCast(x), .y = @intCast(y), .z = @intCast(z), .permutation = model.permutation.toInt(), .isBackFace = backFace},
|
||||
.blockAndQuad = .{.texture = texture, .quadIndex = quadIndex}, // TODO: Expand the meshing algorithm to allow non-cuboid models.
|
||||
};
|
||||
}
|
||||
|
||||
fn clearNeighbor(self: *ChunkMesh, neighbor: u3, comptime isLod: bool) void {
|
||||
self.opaqueMesh.clearNeighbor(neighbor, isLod);
|
||||
self.transparentMesh.clearNeighbor(neighbor, isLod);
|
||||
@ -920,21 +810,21 @@ pub const ChunkMesh = struct {
|
||||
if(canBeSeenThroughOtherBlock(block, otherBlock, neighbor)) {
|
||||
if(block.transparent()) {
|
||||
if(block.hasBackFace()) {
|
||||
self.transparentMesh.appendNeighbor(constructFaceData(block, neighbor ^ 1, x, y, z, true), neighbor, false);
|
||||
self.transparentMesh.appendNeighborFacingQuadsToNeighbor(block, neighbor ^ 1, x, y, z, true, false);
|
||||
}
|
||||
neighborMesh.transparentMesh.appendNeighbor(constructFaceData(block, neighbor, otherX, otherY, otherZ, false), neighbor ^ 1, false);
|
||||
neighborMesh.transparentMesh.appendNeighborFacingQuadsToNeighbor(block, neighbor, otherX, otherY, otherZ, false, false);
|
||||
} else {
|
||||
neighborMesh.opaqueMesh.appendNeighbor(constructFaceData(block, neighbor, otherX, otherY, otherZ, false), neighbor ^ 1, false);
|
||||
neighborMesh.opaqueMesh.appendNeighborFacingQuadsToNeighbor(block, neighbor, otherX, otherY, otherZ, false, false);
|
||||
}
|
||||
}
|
||||
if(canBeSeenThroughOtherBlock(otherBlock, block, neighbor ^ 1)) {
|
||||
if(otherBlock.transparent()) {
|
||||
if(otherBlock.hasBackFace()) {
|
||||
neighborMesh.transparentMesh.appendNeighbor(constructFaceData(otherBlock, neighbor, otherX, otherY, otherZ, true), neighbor ^ 1, false);
|
||||
neighborMesh.transparentMesh.appendNeighborFacingQuadsToNeighbor(otherBlock, neighbor, otherX, otherY, otherZ, true, false);
|
||||
}
|
||||
self.transparentMesh.appendNeighbor(constructFaceData(otherBlock, neighbor ^ 1, x, y, z, false), neighbor, false);
|
||||
self.transparentMesh.appendNeighborFacingQuadsToNeighbor(otherBlock, neighbor ^ 1, x, y, z, false, false);
|
||||
} else {
|
||||
self.opaqueMesh.appendNeighbor(constructFaceData(otherBlock, neighbor ^ 1, x, y, z, false), neighbor, false);
|
||||
self.opaqueMesh.appendNeighborFacingQuadsToNeighbor(otherBlock, neighbor ^ 1, x, y, z, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1000,14 +890,14 @@ pub const ChunkMesh = struct {
|
||||
const otherBlock = (&neighborMesh.chunk.blocks)[chunk.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()) {
|
||||
self.transparentMesh.appendNeighbor(constructFaceData(otherBlock, neighbor ^ 1, x, y, z, false), neighbor, true);
|
||||
self.transparentMesh.appendNeighborFacingQuadsToNeighbor(otherBlock, neighbor ^ 1, x, y, z, false, true);
|
||||
} else {
|
||||
self.opaqueMesh.appendNeighbor(constructFaceData(otherBlock, neighbor ^ 1, x, y, z, false), neighbor, true);
|
||||
self.opaqueMesh.appendNeighborFacingQuadsToNeighbor(otherBlock, neighbor ^ 1, x, y, z, false, true);
|
||||
}
|
||||
}
|
||||
if(block.hasBackFace()) {
|
||||
if(canBeSeenThroughOtherBlock(block, otherBlock, neighbor)) {
|
||||
self.transparentMesh.appendNeighbor(constructFaceData(block, neighbor ^ 1, x, y, z, true), neighbor, true);
|
||||
self.transparentMesh.appendNeighborFacingQuadsToNeighbor(block, neighbor ^ 1, x, y, z, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user