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