1 /* 2 Copyright (c) 2022 Timur Gafarov 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 Permission is hereby granted, free of charge, to any person or organization 6 obtaining a copy of the software and accompanying documentation covered by 7 this license (the "Software") to use, reproduce, display, distribute, 8 execute, and transmit the Software, and to prepare derivative works of the 9 Software, and to permit third-parties to whom the Software is furnished to 10 do so, all subject to the following: 11 12 The copyright notices in the Software and this entire statement, including 13 the above license grant, this restriction and the following disclaimer, 14 must be included in all copies of the Software, in whole or in part, and 15 all derivative works of the Software, unless such copies or derivative 16 works are solely in the form of machine-executable object code generated by 17 a source language processor. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 */ 27 28 module dagon.render.passes.terrain; 29 30 import std.stdio; 31 32 import dlib.core.memory; 33 import dlib.core.ownership; 34 import dlib.image.color; 35 36 import dagon.core.bindings; 37 import dagon.graphics.entity; 38 import dagon.graphics.terrain; 39 import dagon.graphics.screensurface; 40 import dagon.render.pipeline; 41 import dagon.render.pass; 42 import dagon.render.gbuffer; 43 import dagon.render.framebuffer; 44 import dagon.render.shaders.terrain; 45 46 class PassTerrain: RenderPass 47 { 48 GBuffer gbuffer; 49 ScreenSurface screenSurface; 50 TerrainGeometryShader terrainShader; 51 TerrainTextureLayerShader terrainTextureLayerShader; 52 Framebuffer normalBuffer; 53 Framebuffer texcoordBuffer; 54 GLuint framebuffer = 0; 55 56 this(RenderPipeline pipeline, GBuffer gbuffer, Framebuffer normalBuffer, Framebuffer texcoordBuffer, EntityGroup group = null) 57 { 58 super(pipeline, group); 59 this.gbuffer = gbuffer; 60 this.screenSurface = New!ScreenSurface(this); 61 this.terrainShader = New!TerrainGeometryShader(this); 62 this.terrainTextureLayerShader = New!TerrainTextureLayerShader(this); 63 this.normalBuffer = normalBuffer; 64 this.texcoordBuffer = texcoordBuffer; 65 } 66 67 void prepareFramebuffer() 68 { 69 if (framebuffer) 70 return; 71 72 glGenFramebuffers(1, &framebuffer); 73 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); 74 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, normalBuffer.colorTexture, 0); 75 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texcoordBuffer.colorTexture, 0); 76 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, gbuffer.velocityTexture, 0); 77 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, gbuffer.radiance.colorTexture, 0); 78 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, gbuffer.depthTexture, 0); 79 80 GLenum[4] drawBuffers = 81 [ 82 GL_COLOR_ATTACHMENT0, 83 GL_COLOR_ATTACHMENT1, 84 GL_COLOR_ATTACHMENT2, 85 GL_COLOR_ATTACHMENT3 86 ]; 87 glDrawBuffers(drawBuffers.length, drawBuffers.ptr); 88 89 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 90 if (status != GL_FRAMEBUFFER_COMPLETE) 91 writeln(status); 92 93 glBindFramebuffer(GL_FRAMEBUFFER, 0); 94 } 95 96 void resize(uint w, uint h) 97 { 98 if (glIsFramebuffer(framebuffer)) 99 { 100 glDeleteFramebuffers(1, &framebuffer); 101 framebuffer = 0; 102 } 103 } 104 105 override void render() 106 { 107 if (gbuffer is null || group is null) 108 return; 109 110 uint terrains = 0; 111 112 prepareFramebuffer(); 113 114 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer); 115 116 glScissor(0, 0, gbuffer.width, gbuffer.height); 117 glViewport(0, 0, gbuffer.width, gbuffer.height); 118 119 Color4f zero = Color4f(0, 0, 0, 0); 120 glClearBufferfv(GL_COLOR, 0, zero.arrayof.ptr); 121 glClearBufferfv(GL_COLOR, 1, zero.arrayof.ptr); 122 123 state.depthMask = true; 124 state.environment = pipeline.environment; 125 126 terrainShader.bind(); 127 foreach(entity; group) 128 { 129 if (entity.visible && entity.drawable) 130 { 131 if (entityIsTerrain(entity)) 132 { 133 renderEntity(entity, terrainShader); 134 terrains++; 135 } 136 } 137 } 138 terrainShader.unbind(); 139 140 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 141 142 // Texturing passes 143 // TODO: do it for each terrain entity (need to manage state properly) 144 TerrainMaterial terrainMaterial = pipeline.environment.terrainMaterial; 145 if (terrainMaterial && terrains > 0) 146 { 147 updateState(); 148 149 gbuffer.bind(); 150 151 state.normalTexture = normalBuffer.colorTexture; 152 state.texcoordTexture = texcoordBuffer.colorTexture; 153 state.depthMask = false; 154 155 glScissor(0, 0, gbuffer.width, gbuffer.height); 156 glViewport(0, 0, gbuffer.width, gbuffer.height); 157 158 glEnablei(GL_BLEND, 0); 159 glEnablei(GL_BLEND, 1); 160 glEnablei(GL_BLEND, 2); 161 glEnablei(GL_BLEND, 3); 162 glBlendFuncSeparatei(0, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 163 glBlendFuncSeparatei(1, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 164 glBlendFuncSeparatei(2, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 165 glBlendFuncSeparatei(3, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 166 167 glDisable(GL_DEPTH_TEST); 168 terrainTextureLayerShader.bind(); 169 170 if (terrainMaterial) 171 { 172 foreach(layer; terrainMaterial.layers) 173 { 174 state.material = layer; 175 terrainTextureLayerShader.bindParameters(&state); 176 screenSurface.render(&state); 177 terrainTextureLayerShader.unbindParameters(&state); 178 } 179 } 180 181 terrainTextureLayerShader.unbind(); 182 glEnable(GL_DEPTH_TEST); 183 184 glDisablei(GL_BLEND, 0); 185 glDisablei(GL_BLEND, 1); 186 glDisablei(GL_BLEND, 2); 187 glDisablei(GL_BLEND, 3); 188 189 gbuffer.unbind(); 190 } 191 } 192 }