1 /*
2 Copyright (c) 2019-2020 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.shaders.terrain;
29 
30 import std.stdio;
31 import std.math;
32 
33 import dlib.core.memory;
34 import dlib.core.ownership;
35 import dlib.math.vector;
36 import dlib.math.matrix;
37 import dlib.math.transformation;
38 import dlib.math.interpolation;
39 import dlib.image.color;
40 import dlib.text.str;
41 
42 import dagon.core.bindings;
43 import dagon.graphics.material;
44 import dagon.graphics.shader;
45 import dagon.graphics.state;
46 
47 class TerrainShader: Shader
48 {
49     String vs, fs;
50 
51     this(Owner owner)
52     {
53         vs = Shader.load("data/__internal/shaders/Terrain/Terrain.vert.glsl");
54         fs = Shader.load("data/__internal/shaders/Terrain/Terrain.frag.glsl");
55 
56         auto prog = New!ShaderProgram(vs, fs, this);
57         super(prog, owner);
58     }
59 
60     ~this()
61     {
62         vs.free();
63         fs.free();
64     }
65 
66     override void bindParameters(GraphicsState* state)
67     {
68         auto idiffuse1 = "diffuse" in state.material.inputs;
69         auto idiffuse2 = "diffuse2" in state.material.inputs;
70         auto idiffuse3 = "diffuse3" in state.material.inputs;
71         auto idiffuse4 = "diffuse4" in state.material.inputs;
72 
73         auto inormal1 = "normal" in state.material.inputs;
74         auto inormal2 = "normal2" in state.material.inputs;
75         auto inormal3 = "normal3" in state.material.inputs;
76         auto inormal4 = "normal4" in state.material.inputs;
77 
78         auto iheight1 = "height" in state.material.inputs;
79         auto iheight2 = "height2" in state.material.inputs;
80         auto iheight3 = "height3" in state.material.inputs;
81         auto iheight4 = "height4" in state.material.inputs;
82 
83         auto itextureScale1 = "textureScale" in state.material.inputs;
84         auto itextureScale2 = "textureScale2" in state.material.inputs;
85         auto itextureScale3 = "textureScale3" in state.material.inputs;
86         auto itextureScale4 = "textureScale4" in state.material.inputs;
87 
88         auto isplat = "splat" in state.material.inputs;
89 
90         auto isplatmap1 = "splatmap1" in state.material.inputs;
91         auto isplatmap2 = "splatmap2" in state.material.inputs;
92         auto isplatmap3 = "splatmap3" in state.material.inputs;
93         auto isplatmap4 = "splatmap4" in state.material.inputs;
94 
95         setParameter("modelViewMatrix", state.modelViewMatrix);
96         setParameter("projectionMatrix", state.projectionMatrix);
97         setParameter("normalMatrix", state.normalMatrix);
98         setParameter("viewMatrix", state.viewMatrix);
99         setParameter("invViewMatrix", state.invViewMatrix);
100         setParameter("prevModelViewMatrix", state.prevModelViewMatrix);
101 
102         setParameter("layer", cast(float)(state.layer));
103         setParameter("opacity", state.opacity);
104 
105         setParameter("textureScale1", itextureScale1.asVector2f);
106         setParameter("textureScale2", itextureScale2.asVector2f);
107         setParameter("textureScale3", itextureScale3.asVector2f);
108         setParameter("textureScale4", itextureScale4.asVector2f);
109         /*
110         int parallaxMethod = iparallax.asInteger;
111         if (parallaxMethod > ParallaxOcclusionMapping)
112             parallaxMethod = ParallaxOcclusionMapping;
113         if (parallaxMethod < 0)
114             parallaxMethod = 0;
115         */
116         //setParameter("sphericalNormal", cast(int)isphericalNormal.asBool);
117 
118         // Diffuse 1
119         if (idiffuse1.texture)
120         {
121             glActiveTexture(GL_TEXTURE0);
122             idiffuse1.texture.bind();
123             setParameter("diffuse1Texture", cast(int)0);
124             setParameterSubroutine("diffuse1", ShaderType.Fragment, "diffuse1ColorTexture");
125         }
126         else
127         {
128             setParameter("diffuse1Vector", idiffuse1.asVector4f);
129             setParameterSubroutine("diffuse1", ShaderType.Fragment, "diffuse1ColorValue");
130         }
131 
132         // Normal/height 1
133         bool haveHeightMap1 = inormal1.texture !is null;
134         if (haveHeightMap1)
135             haveHeightMap1 = inormal1.texture.image.channels == 4;
136         if (!haveHeightMap1)
137         {
138             if (inormal1.texture is null)
139             {
140                 if (iheight1.texture !is null) // we have height map, but no normal map
141                 {
142                     Color4f color = Color4f(0.5f, 0.5f, 1.0f, 0.0f); // default normal pointing upwards
143                     inormal1.texture = state.material.makeTexture(color, iheight1.texture);
144                     haveHeightMap1 = true;
145                 }
146             }
147             else
148             {
149                 if (iheight1.texture !is null) // we have both normal and height maps
150                 {
151                     inormal1.texture = state.material.makeTexture(inormal1.texture, iheight1.texture);
152                     haveHeightMap1 = true;
153                 }
154             }
155         }
156         if (inormal1.texture)
157         {
158             setParameter("normal1Texture", 1);
159             setParameterSubroutine("normal1", ShaderType.Fragment, "normal1Map");
160 
161             glActiveTexture(GL_TEXTURE1);
162             inormal1.texture.bind();
163         }
164         else
165         {
166             setParameter("normal1Vector", inormal1.asVector3f);
167             setParameterSubroutine("normal1", ShaderType.Fragment, "normal1Value");
168         }
169 
170         // Diffuse 2
171         if (idiffuse2.texture)
172         {
173             glActiveTexture(GL_TEXTURE2);
174             idiffuse2.texture.bind();
175             setParameter("diffuse2Texture", cast(int)2);
176             setParameterSubroutine("diffuse2", ShaderType.Fragment, "diffuse2ColorTexture");
177         }
178         else
179         {
180             setParameter("diffuse2Vector", idiffuse2.asVector4f);
181             setParameterSubroutine("diffuse2", ShaderType.Fragment, "diffuse2ColorValue");
182         }
183 
184         // Normal/height 2
185         bool haveHeightMap2 = inormal2.texture !is null;
186         if (haveHeightMap2)
187             haveHeightMap2 = inormal2.texture.image.channels == 4;
188         if (!haveHeightMap2)
189         {
190             if (inormal2.texture is null)
191             {
192                 if (iheight2.texture !is null) // we have height map, but no normal map
193                 {
194                     Color4f color = Color4f(0.5f, 0.5f, 1.0f, 0.0f); // default normal pointing upwards
195                     inormal2.texture = state.material.makeTexture(color, iheight2.texture);
196                     haveHeightMap2 = true;
197                 }
198             }
199             else
200             {
201                 if (iheight2.texture !is null) // we have both normal and height maps
202                 {
203                     inormal2.texture = state.material.makeTexture(inormal2.texture, iheight2.texture);
204                     haveHeightMap2 = true;
205                 }
206             }
207         }
208         if (inormal2.texture)
209         {
210             setParameter("normal2Texture", 3);
211             setParameterSubroutine("normal2", ShaderType.Fragment, "normal2Map");
212 
213             glActiveTexture(GL_TEXTURE3);
214             inormal2.texture.bind();
215         }
216         else
217         {
218             setParameter("normal2Vector", inormal2.asVector3f);
219             setParameterSubroutine("normal2", ShaderType.Fragment, "normal2Value");
220         }
221 
222         // Diffuse 3
223         if (idiffuse3.texture)
224         {
225             glActiveTexture(GL_TEXTURE4);
226             idiffuse3.texture.bind();
227             setParameter("diffuse3Texture", cast(int)4);
228             setParameterSubroutine("diffuse3", ShaderType.Fragment, "diffuse3ColorTexture");
229         }
230         else
231         {
232             setParameter("diffuse3Vector", idiffuse3.asVector4f);
233             setParameterSubroutine("diffuse3", ShaderType.Fragment, "diffuse3ColorValue");
234         }
235 
236         // Normal/height 3
237         bool haveHeightMap3 = inormal3.texture !is null;
238         if (haveHeightMap3)
239             haveHeightMap3 = inormal3.texture.image.channels == 4;
240         if (!haveHeightMap3)
241         {
242             if (inormal3.texture is null)
243             {
244                 if (iheight3.texture !is null) // we have height map, but no normal map
245                 {
246                     Color4f color = Color4f(0.5f, 0.5f, 1.0f, 0.0f); // default normal pointing upwards
247                     inormal3.texture = state.material.makeTexture(color, iheight3.texture);
248                     haveHeightMap3 = true;
249                 }
250             }
251             else
252             {
253                 if (iheight3.texture !is null) // we have both normal and height maps
254                 {
255                     inormal3.texture = state.material.makeTexture(inormal3.texture, iheight3.texture);
256                     haveHeightMap3 = true;
257                 }
258             }
259         }
260         if (inormal3.texture)
261         {
262             setParameter("normal3Texture", 5);
263             setParameterSubroutine("normal3", ShaderType.Fragment, "normal3Map");
264 
265             glActiveTexture(GL_TEXTURE5);
266             inormal3.texture.bind();
267         }
268         else
269         {
270             setParameter("normal3Vector", inormal3.asVector3f);
271             setParameterSubroutine("normal3", ShaderType.Fragment, "normal3Value");
272         }
273 
274         // Diffuse 4
275         if (idiffuse4.texture)
276         {
277             glActiveTexture(GL_TEXTURE6);
278             idiffuse4.texture.bind();
279             setParameter("diffuse4Texture", cast(int)6);
280             setParameterSubroutine("diffuse4", ShaderType.Fragment, "diffuse4ColorTexture");
281         }
282         else
283         {
284             setParameter("diffuse4Vector", idiffuse4.asVector4f);
285             setParameterSubroutine("diffuse4", ShaderType.Fragment, "diffuse4ColorValue");
286         }
287 
288         // Normal/height 4
289         bool haveHeightMap4 = inormal4.texture !is null;
290         if (haveHeightMap4)
291             haveHeightMap4 = inormal4.texture.image.channels == 4;
292         if (!haveHeightMap4)
293         {
294             if (inormal4.texture is null)
295             {
296                 if (iheight4.texture !is null) // we have height map, but no normal map
297                 {
298                     Color4f color = Color4f(0.5f, 0.5f, 1.0f, 0.0f); // default normal pointing upwards
299                     inormal4.texture = state.material.makeTexture(color, iheight4.texture);
300                     haveHeightMap4 = true;
301                 }
302             }
303             else
304             {
305                 if (iheight4.texture !is null) // we have both normal and height maps
306                 {
307                     inormal4.texture = state.material.makeTexture(inormal4.texture, iheight4.texture);
308                     haveHeightMap4 = true;
309                 }
310             }
311         }
312         if (inormal4.texture)
313         {
314             setParameter("normal4Texture", 7);
315             setParameterSubroutine("normal4", ShaderType.Fragment, "normal4Map");
316 
317             glActiveTexture(GL_TEXTURE7);
318             inormal4.texture.bind();
319         }
320         else
321         {
322             setParameter("normal4Vector", inormal4.asVector3f);
323             setParameterSubroutine("normal4", ShaderType.Fragment, "normal4Value");
324         }
325 
326         // Splatmap
327         if (isplat is null)
328         {
329             state.material.setInput("splat", 0.0f);
330             isplat = "splat" in state.material.inputs;
331         }
332 
333         // PBR
334         Vector4f rms1 = Vector4f(state.material.roughness.asFloat, state.material.metallic.asFloat, 0.0f, 1.0f);
335         Vector4f rms2 = Vector4f(state.material.roughness2.asFloat, state.material.metallic2.asFloat, 0.0f, 1.0f);
336         Vector4f rms3 = Vector4f(state.material.roughness3.asFloat, state.material.metallic3.asFloat, 0.0f, 1.0f);
337         Vector4f rms4 = Vector4f(state.material.roughness4.asFloat, state.material.metallic4.asFloat, 0.0f, 1.0f);
338 
339         setParameter("rms1", rms1);
340         setParameter("rms2", rms2);
341         setParameter("rms3", rms3);
342         setParameter("rms4", rms4);
343 
344         if (isplat.texture is null)
345             isplat.texture = state.material.makeTexture(*isplatmap1, *isplatmap2, *isplatmap3, *isplatmap4);
346         glActiveTexture(GL_TEXTURE8);
347         isplat.texture.bind();
348         setParameter("splatmap", cast(int)8);
349 
350         glActiveTexture(GL_TEXTURE0);
351 
352         super.bindParameters(state);
353     }
354 
355     override void unbindParameters(GraphicsState* state)
356     {
357         super.unbindParameters(state);
358 
359         glActiveTexture(GL_TEXTURE0);
360         glBindTexture(GL_TEXTURE_2D, 0);
361 
362         glActiveTexture(GL_TEXTURE1);
363         glBindTexture(GL_TEXTURE_2D, 0);
364 
365         glActiveTexture(GL_TEXTURE2);
366         glBindTexture(GL_TEXTURE_2D, 0);
367 
368         glActiveTexture(GL_TEXTURE3);
369         glBindTexture(GL_TEXTURE_2D, 0);
370 
371         glActiveTexture(GL_TEXTURE4);
372         glBindTexture(GL_TEXTURE_2D, 0);
373 
374         glActiveTexture(GL_TEXTURE5);
375         glBindTexture(GL_TEXTURE_2D, 0);
376 
377         glActiveTexture(GL_TEXTURE6);
378         glBindTexture(GL_TEXTURE_2D, 0);
379 
380         glActiveTexture(GL_TEXTURE7);
381         glBindTexture(GL_TEXTURE_2D, 0);
382 
383         glActiveTexture(GL_TEXTURE8);
384         glBindTexture(GL_TEXTURE_2D, 0);
385 
386         glActiveTexture(GL_TEXTURE0);
387     }
388 }