diff --git a/src/graphics.zig b/src/graphics.zig index 896deb343f..103a4d55b1 100644 --- a/src/graphics.zig +++ b/src/graphics.zig @@ -2649,73 +2649,16 @@ pub fn generateBlockTexture(blockType: u16) Texture { const oldViewMatrix = main.game.camera.viewMatrix; main.game.camera.viewMatrix = Mat4f.identity().mul(Mat4f.rotationX(std.math.pi/4.0)).mul(Mat4f.rotationZ(1.0*std.math.pi/4.0)); defer main.game.camera.viewMatrix = oldViewMatrix; - const uniforms = if (block.transparent()) &main.renderer.chunk_meshing.transparentUniforms else &main.renderer.chunk_meshing.uniforms; - - var faceData: main.ListUnmanaged(main.renderer.chunk_meshing.FaceData) = .{}; - defer faceData.deinit(main.stackAllocator); - const model = main.blocks.meshes.model(block).model(); - const pos: main.chunk.BlockPos = .fromCoords(1, 1, 1); - if (block.hasBackFace()) { - model.appendInternalQuadsToList(&faceData, main.stackAllocator, block, pos, true); - for (main.chunk.Neighbor.iterable) |neighbor| { - model.appendNeighborFacingQuadsToList(&faceData, main.stackAllocator, block, neighbor, pos, true); - } - } - model.appendInternalQuadsToList(&faceData, main.stackAllocator, block, pos, false); - for (main.chunk.Neighbor.iterable) |neighbor| { - model.appendNeighborFacingQuadsToList(&faceData, main.stackAllocator, block, neighbor, pos.neighbor(neighbor)[0], false); - } - - for (faceData.items) |*face| { - face.position.lightIndex = 0; - } - var allocation: SubAllocation = .{.start = 0, .len = 0}; - main.renderer.chunk_meshing.faceBuffers[0].uploadData(faceData.items, &allocation); - defer main.renderer.chunk_meshing.faceBuffers[0].free(allocation); - var lightAllocation: SubAllocation = .{.start = 0, .len = 0}; - main.renderer.chunk_meshing.lightBuffers[0].uploadData(&.{0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}, &lightAllocation); - defer main.renderer.chunk_meshing.lightBuffers[0].free(lightAllocation); - - { - const i = 4; // Easily switch between the 8 diagonal coordinates. - var x: f64 = -65.5 + 1.5; - var y: f64 = -65.5 + 1.5; - var z: f64 = -92.631 + 1.5; - if (i & 1 != 0) x = -x + 3; - if (i & 2 != 0) y = -y + 3; - if (i & 4 != 0) z = -z + 3; - var chunkAllocation: SubAllocation = .{.start = 0, .len = 0}; - main.renderer.chunk_meshing.chunkBuffer.uploadData(&.{.{ - .position = .{0, 0, 0}, - .min = undefined, - .max = undefined, - .voxelSize = 1, - .lightStart = lightAllocation.start, - .vertexStartOpaque = undefined, - .faceCountsByNormalOpaque = undefined, - .vertexStartTransparent = undefined, - .vertexCountTransparent = undefined, - .visibilityState = 0, - .oldVisibilityState = 0, - }}, &chunkAllocation); - defer main.renderer.chunk_meshing.chunkBuffer.free(chunkAllocation); - if (block.transparent()) { - c.glBlendEquation(c.GL_FUNC_ADD); - c.glBlendFunc(c.GL_ONE, c.GL_SRC1_COLOR); - main.renderer.chunk_meshing.bindTransparentShaderAndUniforms(projMatrix, .{1, 1, 1}, .{x, y, z}); - } else { - main.renderer.chunk_meshing.bindShaderAndUniforms(projMatrix, .{1, 1, 1}, .{x, y, z}); - } - c.glUniform1f(uniforms.contrast, 0.25); - c.glActiveTexture(c.GL_TEXTURE0); - main.blocks.meshes.blockTextureArray.bind(); - c.glActiveTexture(c.GL_TEXTURE1); - main.blocks.meshes.emissionTextureArray.bind(); - c.glActiveTexture(c.GL_TEXTURE2); - main.blocks.meshes.reflectivityAndAbsorptionTextureArray.bind(); - block_texture.depthTexture.bindTo(5); - c.glDrawElementsInstancedBaseVertexBaseInstance(c.GL_TRIANGLES, @intCast(6*faceData.items.len), c.GL_UNSIGNED_INT, null, 1, allocation.start*4, chunkAllocation.start); - } + + const i = 4; // Easily switch between the 8 diagonal coordinates. + var x: f64 = -65.5 + 0.5; + var y: f64 = -65.5 + 0.5; + var z: f64 = -92.631 + 0.5; + if (i & 1 != 0) x = -x + 1; + if (i & 2 != 0) y = -y + 1; + if (i & 4 != 0) z = -z + 1; + + main.renderer.renderBlock(projMatrix, Mat4f.identity(), block, .{.uniform = 0xffffffff}, .{1, 1, 1}, .{x, y, z}, .transparent, 0.25); c.glDisable(c.GL_CULL_FACE); var finalFrameBuffer: FrameBuffer = undefined; diff --git a/src/renderer.zig b/src/renderer.zig index 0c19621d60..f6b0506ae1 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -54,6 +54,30 @@ var fakeReflectionUniforms: struct { frequency: c_int, reflectionMapSize: c_int, } = undefined; +const BlockUniforms = struct { + projectionMatrix: c_int, + viewMatrix: c_int, + modelMatrix: c_int, + playerPositionInteger: c_int, + playerPositionFraction: c_int, + screenSize: c_int, + ambientLight: c_int, + contrast: c_int, + @"fog.color": c_int, + @"fog.density": c_int, + @"fog.fogLower": c_int, + @"fog.fogHigher": c_int, + reflectionMapSize: c_int, + lodDistance: c_int, + zNear: c_int, + zFar: c_int, +}; + +var blockUniforms: BlockUniforms = undefined; +var blockTransparentUniforms: BlockUniforms = undefined; + +var blockPipeline: graphics.Pipeline = undefined; +var blockTransparentPipeline: graphics.Pipeline = undefined; pub var activeFrameBuffer: c_uint = 0; @@ -79,6 +103,31 @@ pub fn init() void { .{.depthTest = false, .depthWrite = false}, .{.attachments = &.{.noBlending}}, ); + blockPipeline = graphics.Pipeline.init( + "assets/cubyz/shaders/chunks/chunk_vertex.vert", + "assets/cubyz/shaders/chunks/chunk_fragment.frag", + "#define ENTITY", + &blockUniforms, + .{}, + .{.depthTest = true, .depthWrite = true}, + .{.attachments = &.{.noBlending}}, + ); + blockTransparentPipeline = graphics.Pipeline.init( + "assets/cubyz/shaders/chunks/chunk_vertex.vert", + "assets/cubyz/shaders/chunks/transparent_fragment.frag", + "#define ENTITY\n#define transparent\n", + &blockTransparentUniforms, + .{}, + .{.depthTest = true, .depthWrite = false, .depthCompare = .lessOrEqual}, + .{.attachments = &.{.{ + .srcColorBlendFactor = .one, + .dstColorBlendFactor = .src1Color, + .colorBlendOp = .add, + .srcAlphaBlendFactor = .one, + .dstAlphaBlendFactor = .src1Alpha, + .alphaBlendOp = .add, + }}}, + ); worldFrameBuffer.init(true, c.GL_NEAREST, c.GL_CLAMP_TO_EDGE); worldFrameBuffer.updateSize(Window.width, Window.height, c.GL_RGB16F); Bloom.init(); @@ -95,6 +144,8 @@ pub fn init() void { pub fn deinit() void { deferredRenderPassPipeline.deinit(); fakeReflectionPipeline.deinit(); + blockPipeline.deinit(); + blockTransparentPipeline.deinit(); worldFrameBuffer.deinit(); Bloom.deinit(); MeshSelection.deinit(); @@ -327,6 +378,121 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo gpu_performance_measuring.stopQuery(); } +pub fn renderBlock(projMatrix: Mat4f, modelMatrix: Mat4f, block: blocks.Block, lighting: union(enum) { + world: Vec3i, + uniform: u32, +}, ambientLight: Vec3f, playerPosition: Vec3d, transparencyMode: enum { + @"opaque", + transparent, +}, contrast: f32) void { + var faceData: main.ListUnmanaged(chunk_meshing.FaceData) = .{}; + defer faceData.deinit(main.stackAllocator); + const model = main.blocks.meshes.model(block).model(); + if (block.hasBackFace()) { + model.appendInternalQuadsToList(&faceData, main.stackAllocator, block, .fromCoords(1, 1, 1), true); + for (main.chunk.Neighbor.iterable) |neighbor| { + model.appendNeighborFacingQuadsToList(&faceData, main.stackAllocator, block, neighbor, .fromCoords(1, 1, 1), true); + } + } + model.appendInternalQuadsToList(&faceData, main.stackAllocator, block, .fromCoords(1, 1, 1), false); + for (main.chunk.Neighbor.iterable) |neighbor| { + model.appendNeighborFacingQuadsToList(&faceData, main.stackAllocator, block, neighbor, main.chunk.BlockPos.fromCoords(1, 1, 1).neighbor(neighbor)[0], false); + } + for (faceData.items, 0..) |*face, i| { + face.position.lightIndex = @intCast(i); + } + + const lightData = main.stackAllocator.alloc(u32, faceData.items.len*4); + defer main.stackAllocator.free(lightData); + + switch (lighting) { + .world => |lightPos| { + const mesh = mesh_storage.getMesh(main.chunk.ChunkPosition.initFromWorldPos(lightPos, 1)) orelse return; + for (faceData.items) |face| { + const quad = face.blockAndQuad.quadIndex.quadInfo(); + const light: [4]u32 = chunk_meshing.PrimitiveMesh.getLightWithTransform(mesh, modelMatrix, -Vec3i{mesh.pos.wx, mesh.pos.wy, mesh.pos.wz}, blocks.meshes.textureIndex(block, quad.textureSlot), face.blockAndQuad.quadIndex); + lightData[face.position.lightIndex*4 ..][0..4].* = light; + } + }, + .uniform => |light| { + @memset(lightData, light); + }, + } + + const transparent = block.transparent() and transparencyMode == .transparent; + + renderFaces(projMatrix, modelMatrix, faceData.items, lightData, ambientLight, playerPosition, transparent, contrast); +} + +fn renderFaces(projMatrix: Mat4f, modelMatrix: Mat4f, faceData: []chunk_meshing.FaceData, lightData: []u32, ambientLight: Vec3f, playerPosition: Vec3d, transparent: bool, contrast: f32) void { + var allocation: graphics.SubAllocation = .{.start = 0, .len = 0}; + main.renderer.chunk_meshing.faceBuffers[0].uploadData(faceData, &allocation); + defer main.renderer.chunk_meshing.faceBuffers[0].free(allocation); + var lightAllocation: graphics.SubAllocation = .{.start = 0, .len = 0}; + main.renderer.chunk_meshing.lightBuffers[0].uploadData(lightData, &lightAllocation); + defer main.renderer.chunk_meshing.lightBuffers[0].free(lightAllocation); + + var chunkAllocation: graphics.SubAllocation = .{.start = 0, .len = 0}; + main.renderer.chunk_meshing.chunkBuffer.uploadData(&.{.{ + .position = .{0, 0, 0}, + .min = undefined, + .max = undefined, + .voxelSize = 1, + .lightStart = lightAllocation.start, + .vertexStartOpaque = undefined, + .faceCountsByNormalOpaque = undefined, + .vertexStartTransparent = undefined, + .vertexCountTransparent = undefined, + .visibilityState = 0, + .oldVisibilityState = 0, + }}, &chunkAllocation); + defer main.renderer.chunk_meshing.chunkBuffer.free(chunkAllocation); + + const uniforms = if (transparent) blockTransparentUniforms else blockUniforms; + if (transparent) { + blockTransparentPipeline.bind(null); + + c.glUniform3fv(uniforms.@"fog.color", 1, @ptrCast(&game.fog.skyColor)); + c.glUniform1f(uniforms.@"fog.density", game.fog.density); + c.glUniform1f(uniforms.@"fog.fogLower", game.fog.fogLower); + c.glUniform1f(uniforms.@"fog.fogHigher", game.fog.fogHigher); + } else { + blockPipeline.bind(null); + } + + c.glUniformMatrix4fv(uniforms.projectionMatrix, 1, c.GL_TRUE, @ptrCast(&projMatrix)); + + c.glUniform1f(uniforms.reflectionMapSize, main.renderer.reflectionCubeMapSize); + + c.glUniform1f(uniforms.contrast, contrast); + + c.glUniform1f(uniforms.lodDistance, main.settings.@"lod0.5Distance"); + + c.glUniformMatrix4fv(uniforms.viewMatrix, 1, c.GL_TRUE, @ptrCast(&main.game.camera.viewMatrix)); + + c.glUniform3f(uniforms.ambientLight, ambientLight[0], ambientLight[1], ambientLight[2]); + + c.glUniform1f(uniforms.zNear, main.renderer.zNear); + c.glUniform1f(uniforms.zFar, main.renderer.zFar); + + const playerPos = playerPosition + Vec3d{1, 1, 1}; + c.glUniform3i(uniforms.playerPositionInteger, @intFromFloat(@floor(playerPos[0])), @intFromFloat(@floor(playerPos[1])), @intFromFloat(@floor(playerPos[2]))); + c.glUniform3f(uniforms.playerPositionFraction, @floatCast(@mod(playerPos[0], 1)), @floatCast(@mod(playerPos[1], 1)), @floatCast(@mod(playerPos[2], 1))); + c.glUniformMatrix4fv(uniforms.modelMatrix, 1, c.GL_TRUE, @ptrCast(&modelMatrix)); + + main.renderer.chunk_meshing.vao.bind(); + + main.renderer.chunk_meshing.faceBuffers[0].ssbo.bind(main.renderer.chunk_meshing.faceBuffers[0].binding); + main.renderer.chunk_meshing.lightBuffers[0].ssbo.bind(main.renderer.chunk_meshing.lightBuffers[0].binding); + c.glActiveTexture(c.GL_TEXTURE0); + main.blocks.meshes.blockTextureArray.bind(); + c.glActiveTexture(c.GL_TEXTURE1); + main.blocks.meshes.emissionTextureArray.bind(); + c.glActiveTexture(c.GL_TEXTURE2); + main.blocks.meshes.reflectivityAndAbsorptionTextureArray.bind(); + c.glDrawElementsInstancedBaseVertexBaseInstance(c.GL_TRIANGLES, @intCast(6*faceData.len), c.GL_UNSIGNED_INT, null, 1, allocation.start*4, chunkAllocation.start); +} + const Bloom = struct { // MARK: Bloom var buffer1: graphics.FrameBuffer = undefined; var buffer2: graphics.FrameBuffer = undefined;