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 }