diff --git a/assets/cubyz/shaders/chunks/transparent_fragment.fs b/assets/cubyz/shaders/chunks/transparent_fragment.fs index 529c837b..f44ae3e2 100644 --- a/assets/cubyz/shaders/chunks/transparent_fragment.fs +++ b/assets/cubyz/shaders/chunks/transparent_fragment.fs @@ -238,8 +238,6 @@ void main() { fragColor.rgb -= fogColor; blendColor.rgb = vec3(1); } - //blendColor.rgb = vec3(0); - //fragColor = vec4(1, 1, 1, 1); } else { if(emptyBackFace) { fragColor = vec4(0, 0, 0, 1); @@ -250,9 +248,5 @@ void main() { fragColor.rgb += fogFactor*fogColor; } blendColor.rgb = vec3(1); - - - //blendColor.rgb = vec3(0); - //fragColor = vec4(1, 0, 0, 1); } } diff --git a/assets/cubyz/shaders/item_texture_post.fs b/assets/cubyz/shaders/item_texture_post.fs new file mode 100644 index 00000000..8c06fb8f --- /dev/null +++ b/assets/cubyz/shaders/item_texture_post.fs @@ -0,0 +1,18 @@ +#version 430 +out vec4 fragColor; + +in vec2 texCoords; + +uniform sampler2D color; +uniform bool transparent; + +void main() { + fragColor = texture(color, texCoords); + if(transparent) { + fragColor.rgb /= fragColor.a; + fragColor.a = 1; + // TODO: Remove the background color. Somehow? + } + float maxColor = max(1.0, max(fragColor.r, max(fragColor.g, fragColor.b))); + fragColor.rgb = fragColor.rgb/maxColor; +} \ No newline at end of file diff --git a/assets/cubyz/shaders/item_texture_post.vs b/assets/cubyz/shaders/item_texture_post.vs new file mode 100644 index 00000000..ef5ed408 --- /dev/null +++ b/assets/cubyz/shaders/item_texture_post.vs @@ -0,0 +1,10 @@ +#version 430 + +layout (location=0) in vec2 inTexCoords; + +out vec2 texCoords; + +void main() { + texCoords = inTexCoords; + gl_Position = vec4(inTexCoords*2 - vec2(1, 1), 0, 1); +} \ No newline at end of file diff --git a/src/graphics.zig b/src/graphics.zig index 559fadf7..443cc777 100644 --- a/src/graphics.zig +++ b/src/graphics.zig @@ -6,6 +6,7 @@ const std = @import("std"); const freetype = @import("freetype"); const harfbuzz = @import("harfbuzz"); +const Mat4f = @import("vec.zig").Mat4f; const Vec4i = @import("vec.zig").Vec4i; const Vec4f = @import("vec.zig").Vec4f; const Vec2f = @import("vec.zig").Vec2f; @@ -1031,6 +1032,7 @@ pub fn init() !void { draw.initLine(); draw.initRect(); try TextRendering.init(); + try block_texture.init(); } pub fn deinit() void { @@ -1040,6 +1042,7 @@ pub fn deinit() void { draw.deinitLine(); draw.deinitRect(); TextRendering.deinit(); + block_texture.deinit(); } pub const Shader = struct { @@ -1603,4 +1606,120 @@ pub const Fog = struct { active: bool, color: Vec3f, density: f32, -}; \ No newline at end of file +}; + +const block_texture = struct { + var uniforms: struct { + color: c_int, + transparent: c_int, + } = undefined; + var shader: Shader = undefined; + var depthTexture: Texture = undefined; + const textureSize = 128; + + fn init() !void { + shader = try Shader.initAndGetUniforms("assets/cubyz/shaders/item_texture_post.vs", "assets/cubyz/shaders/item_texture_post.fs", &uniforms); + depthTexture = Texture.init(); + depthTexture.bind(); + var data: [128*128]f32 = undefined; + @memset(&data, main.renderer.zNear/132.0); + c.glTexImage2D(c.GL_TEXTURE_2D, 0, c.GL_R32F, textureSize, textureSize, 0, c.GL_RED, c.GL_FLOAT, &data); + c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MIN_FILTER, c.GL_NEAREST); + c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAG_FILTER, c.GL_NEAREST); + c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_WRAP_S, c.GL_REPEAT); + c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_WRAP_T, c.GL_REPEAT); + } + fn deinit() void { + shader.deinit(); + depthTexture.deinit(); + } +}; + +pub fn generateBlockTexture(blockType: u16) !Texture { + const block = main.blocks.Block{.typ = blockType, .data = 0}; // TODO: Use natural standard data. + const textureSize = block_texture.textureSize; + c.glViewport(0, 0, textureSize, textureSize); + + var frameBuffer: FrameBuffer = undefined; + const scissor = c.glIsEnabled(c.GL_SCISSOR_TEST); + c.glDisable(c.GL_SCISSOR_TEST); + defer if(scissor != 0) c.glEnable(c.GL_SCISSOR_TEST); + const depthTest = c.glIsEnabled(c.GL_DEPTH_TEST); + 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); + defer if(cullFace != 0) c.glEnable(c.GL_CULL_FACE); + + frameBuffer.init(false, c.GL_NEAREST, c.GL_REPEAT); + defer frameBuffer.deinit(); + frameBuffer.updateSize(textureSize, textureSize, c.GL_RGBA16F); + frameBuffer.bind(); + if(block.transparent()) { + frameBuffer.clear(.{0.683421, 0.6854237, 0.685426, 1}); // TODO: Alpha must be 1 for fog! + } else { + frameBuffer.clear(.{0, 0, 0, 0}); + } + + const projMatrix = Mat4f.perspective(0.013, 1, 64); + const oldViewMatrix = main.game.camera.viewMatrix; + main.game.camera.viewMatrix = Mat4f.rotationX(std.math.pi/4.0).mul(Mat4f.rotationY(-std.math.pi/4.0)); + defer main.game.camera.viewMatrix = oldViewMatrix; + if(block.transparent()) { + c.glBlendEquationSeparate(c.GL_FUNC_ADD, c.GL_FUNC_ADD); + c.glBlendFuncSeparate(c.GL_DST_ALPHA, c.GL_SRC1_COLOR, c.GL_DST_ALPHA, c.GL_ZERO); + main.chunk.meshing.bindTransparentShaderAndUniforms(projMatrix, .{1, 1, 1}, 0); + } else { + main.chunk.meshing.bindShaderAndUniforms(projMatrix, .{1, 1, 1}, 0); + } + const uniforms = if(block.transparent()) &main.chunk.meshing.transparentUniforms else &main.chunk.meshing.uniforms; + + var faceData: [6]main.chunk.meshing.FaceData = undefined; + var faces: u8 = 0; + if(block.hasBackFace()) { + faceData[2] = main.chunk.meshing.ChunkMesh.constructFaceData(block, main.chunk.Neighbors.dirPosX, 1, 1, 1, true); + faceData[1] = main.chunk.meshing.ChunkMesh.constructFaceData(block, main.chunk.Neighbors.dirUp, 1, 1, 1, true); + faceData[0] = main.chunk.meshing.ChunkMesh.constructFaceData(block, main.chunk.Neighbors.dirPosZ, 1, 1, 1, true); + faces += 3; + } + faceData[faces + 0] = main.chunk.meshing.ChunkMesh.constructFaceData(block, main.chunk.Neighbors.dirPosX, 1+1, 1, 1, false); + faceData[faces + 1] = main.chunk.meshing.ChunkMesh.constructFaceData(block, main.chunk.Neighbors.dirUp, 1, 1+1, 1, false); + faceData[faces + 2] = main.chunk.meshing.ChunkMesh.constructFaceData(block, main.chunk.Neighbors.dirPosZ, 1, 1, 1+1, false); + faces += 3; + var allocation: LargeBuffer.Allocation = .{.start = 0, .len = 0}; + try main.chunk.meshing.faceBuffer.realloc(&allocation, faces*@sizeOf(main.chunk.meshing.FaceData)); + main.chunk.meshing.faceBuffer.bufferSubData(allocation.start, main.chunk.meshing.FaceData, faceData[0..faces]); + + c.glUniform3f(uniforms.modelPosition, -65.5 - 1.5, -92.631 - 1.5, -65.5 - 1.5); + c.glUniform1i(uniforms.visibilityMask, 0xff); + c.glUniform1i(uniforms.voxelSize, 1); + c.glActiveTexture(c.GL_TEXTURE0); + main.blocks.meshes.blockTextureArray.bind(); + c.glActiveTexture(c.GL_TEXTURE1); + main.blocks.meshes.emissionTextureArray.bind(); + block_texture.depthTexture.bindTo(3); + c.glDrawElementsBaseVertex(c.GL_TRIANGLES, 6*faces, c.GL_UNSIGNED_INT, null, allocation.start/8*4); + + var finalFrameBuffer: FrameBuffer = undefined; + finalFrameBuffer.init(false, c.GL_NEAREST, c.GL_REPEAT); + finalFrameBuffer.updateSize(textureSize, textureSize, c.GL_RGBA8); + finalFrameBuffer.bind(); + var texture = Texture{.textureID = finalFrameBuffer.texture}; + defer c.glDeleteFramebuffers(1, &finalFrameBuffer.frameBuffer); + block_texture.shader.bind(); + c.glUniform1i(block_texture.uniforms.transparent, if(block.transparent()) c.GL_TRUE else c.GL_FALSE); + c.glUniform1i(block_texture.uniforms.color, 3); + frameBuffer.bindTexture(c.GL_TEXTURE3); + + c.glBindVertexArray(draw.rectVAO); + c.glDisable(c.GL_BLEND); + c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4); + c.glEnable(c.GL_BLEND); + + c.glBindFramebuffer(c.GL_FRAMEBUFFER, 0); + + try main.chunk.meshing.faceBuffer.free(allocation); + c.glViewport(0, 0, main.Window.width, main.Window.height); + c.glBlendFunc(c.GL_SRC_ALPHA, c.GL_ONE_MINUS_SRC_ALPHA); + return texture; +} \ No newline at end of file diff --git a/src/items.zig b/src/items.zig index 88eca8fb..f7c177b6 100644 --- a/src/items.zig +++ b/src/items.zig @@ -118,58 +118,10 @@ pub const BaseItem = struct { pub fn getTexture(self: *BaseItem) !graphics.Texture { if(self.texture == null) { if(self.block) |blockType| { - const block = main.blocks.Block{.typ = blockType, .data = 0}; // TODO: Use natural standard data. - const c = graphics.c; - c.glViewport(0, 0, 128, 128); - - var frameBuffer: graphics.FrameBuffer = undefined; - const scissor = c.glIsEnabled(c.GL_SCISSOR_TEST); - c.glDisable(c.GL_SCISSOR_TEST); - defer if(scissor != 0) c.glEnable(c.GL_SCISSOR_TEST); - const cullFace = c.glIsEnabled(c.GL_CULL_FACE); - c.glEnable(c.GL_CULL_FACE); - defer if(cullFace == 0) c.glDisable(c.GL_CULL_FACE); - - frameBuffer.init(false, c.GL_NEAREST, c.GL_REPEAT); - frameBuffer.updateSize(128, 128, c.GL_RGBA8); - frameBuffer.bind(); - frameBuffer.clear(.{1, 1, 1, 0}); - self.texture = graphics.Texture{.textureID = frameBuffer.texture}; - defer c.glDeleteFramebuffers(1, &frameBuffer.frameBuffer); - - const projMatrix = Mat4f.perspective(0.013, 1, 64); - const oldViewMatrix = main.game.camera.viewMatrix; - main.game.camera.viewMatrix = Mat4f.rotationX(std.math.pi/4.0).mul(Mat4f.rotationY(-std.math.pi/4.0)); - defer main.game.camera.viewMatrix = oldViewMatrix; - if(block.transparent()) { - c.glBlendFunc(c.GL_SRC_ALPHA, c.GL_SRC1_COLOR); - chunk.meshing.bindTransparentShaderAndUniforms(projMatrix, .{1, 1, 1}, 0); - } else { - chunk.meshing.bindShaderAndUniforms(projMatrix, .{1, 1, 1}, 0); - } - const uniforms = if(block.transparent()) &chunk.meshing.transparentUniforms else &chunk.meshing.uniforms; - - var allocation: graphics.LargeBuffer.Allocation = .{.start = 0, .len = 0}; - try chunk.meshing.faceBuffer.realloc(&allocation, 3*@sizeOf(chunk.meshing.FaceData)); - var faceData: [3]chunk.meshing.FaceData = undefined; - faceData[0] = chunk.meshing.ChunkMesh.constructFaceData(block, chunk.Neighbors.dirPosX, 1+1, 1, 1, false); - faceData[1] = chunk.meshing.ChunkMesh.constructFaceData(block, chunk.Neighbors.dirUp, 1, 1+1, 1, false); - faceData[2] = chunk.meshing.ChunkMesh.constructFaceData(block, chunk.Neighbors.dirPosZ, 1, 1, 1+1, false); - // TODO: Add back faces for foggy blocks. - chunk.meshing.faceBuffer.bufferSubData(allocation.start, chunk.meshing.FaceData, &faceData); - - c.glUniform3f(uniforms.modelPosition, -65.5 - 1.5, -92.631 - 1.5, -65.5 - 1.5); - c.glUniform1i(uniforms.visibilityMask, 0xff); - c.glUniform1i(uniforms.voxelSize, 1); - c.glActiveTexture(c.GL_TEXTURE0); - main.blocks.meshes.blockTextureArray.bind(); - c.glActiveTexture(c.GL_TEXTURE1); - main.blocks.meshes.emissionTextureArray.bind(); - c.glDrawElementsBaseVertex(c.GL_TRIANGLES, 18, c.GL_UNSIGNED_INT, null, allocation.start/8*4); - - try chunk.meshing.faceBuffer.free(allocation); - c.glViewport(0, 0, main.Window.width, main.Window.height); - c.glBlendFunc(c.GL_SRC_ALPHA, c.GL_ONE_MINUS_SRC_ALPHA); + self.texture = try graphics.generateBlockTexture(blockType); + var ret = self.texture.?; + self.texture = null; + return ret; } else { self.texture = graphics.Texture.init(); try self.texture.?.generate(self.image);