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