1 /*
2 Copyright (c) 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.forward;
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 import dagon.graphics.cubemap;
47 import dagon.graphics.csm;
48 
49 class ForwardShader: Shader
50 {
51     String vs, fs;
52 
53     Matrix4x4f defaultShadowMatrix;
54     GLuint defaultShadowTexture;
55 
56     this(Owner owner)
57     {
58         vs = Shader.load("data/__internal/shaders/Forward/Forward.vert.glsl");
59         fs = Shader.load("data/__internal/shaders/Forward/Forward.frag.glsl");
60 
61         auto prog = New!ShaderProgram(vs, fs, this);
62         super(prog, owner);
63 
64         defaultShadowMatrix = Matrix4x4f.identity;
65 
66         glGenTextures(1, &defaultShadowTexture);
67         glActiveTexture(GL_TEXTURE0);
68         glBindTexture(GL_TEXTURE_2D_ARRAY, defaultShadowTexture);
69         glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT24, 1, 1, 3, 0, GL_DEPTH_COMPONENT, GL_FLOAT, null);
70         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
71 	    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
72         glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
73     }
74 
75     ~this()
76     {
77         if (glIsFramebuffer(defaultShadowTexture))
78             glDeleteFramebuffers(1, &defaultShadowTexture);
79 
80         vs.free();
81         fs.free();
82     }
83 
84     override void bindParameters(GraphicsState* state)
85     {
86         auto idiffuse = "diffuse" in state.material.inputs;
87         auto inormal = "normal" in state.material.inputs;
88         auto iheight = "height" in state.material.inputs;
89         auto ipbr = "pbr" in state.material.inputs;
90         auto iroughness = "roughness" in state.material.inputs;
91         auto imetallic = "metallic" in state.material.inputs;
92         auto ispecularity = "specularity" in state.material.inputs;
93         auto itranslucency = "translucency" in state.material.inputs;
94         auto itextureScale = "textureScale" in state.material.inputs;
95         auto iparallax = "parallax" in state.material.inputs;
96         auto iemission = "emission" in state.material.inputs;
97         auto ienergy = "energy" in state.material.inputs;
98         auto isphericalNormal = "sphericalNormal" in state.material.inputs;
99         auto ishadeless = "shadeless" in state.material.inputs;
100 
101         setParameter("modelViewMatrix", state.modelViewMatrix);
102         setParameter("projectionMatrix", state.projectionMatrix);
103         setParameter("normalMatrix", state.normalMatrix);
104         setParameter("viewMatrix", state.viewMatrix);
105         setParameter("invViewMatrix", state.invViewMatrix);
106         setParameter("prevModelViewMatrix", state.prevModelViewMatrix);
107 
108         setParameter("layer", cast(float)(state.layer));
109         setParameter("opacity", state.opacity);
110         setParameter("textureScale", itextureScale.asVector2f);
111 
112         setParameter("viewSize", state.resolution);
113 
114         // Sun
115         Vector3f sunDirection = Vector3f(0.0f, 0.0f, 1.0f);
116         Color4f sunColor = Color4f(1.0f, 1.0f, 1.0f, 1.0f);
117         float sunEnergy = 1.0f;
118         bool sunScatteringEnabled = false;
119         float sunScatteringG = 0.0f;
120         float sunScatteringDensity = 1.0f;
121         int sunScatteringSamples = 1;
122         float sunScatteringMaxRandomStepOffset = 0.0f;
123         bool sunScatteringShadow = false;
124         bool shaded = !ishadeless.asBool;
125         if (state.material.sun)
126         {
127             auto sun = state.material.sun;
128             sunDirection = sun.directionAbsolute;
129             sunColor = sun.color;
130             sunEnergy = sun.energy;
131             sunScatteringG = 1.0f - sun.scattering;
132             sunScatteringDensity = sun.mediumDensity;
133             sunScatteringEnabled = sun.scatteringEnabled;
134             sunScatteringSamples = sun.scatteringSamples;
135             sunScatteringMaxRandomStepOffset = sun.scatteringMaxRandomStepOffset;
136             sunScatteringShadow = sun.scatteringUseShadow;
137         }
138         Vector4f sunDirHg = Vector4f(sunDirection);
139         sunDirHg.w = 0.0;
140         setParameter("sunDirection", (sunDirHg * state.viewMatrix).xyz);
141         setParameter("sunColor", sunColor);
142         setParameter("sunEnergy", sunEnergy);
143         setParameter("sunScatteringG", sunScatteringG);
144         setParameter("sunScatteringDensity", sunScatteringDensity);
145         setParameter("sunScattering", sunScatteringEnabled);
146         setParameter("sunScatteringSamples", sunScatteringSamples);
147         setParameter("sunScatteringMaxRandomStepOffset", sunScatteringMaxRandomStepOffset);
148         setParameter("sunScatteringShadow", sunScatteringShadow);
149         setParameter("shaded", shaded);
150 
151         setParameter("time", state.localTime);
152 
153         // Parallax mode
154         int parallaxMethod = iparallax.asInteger;
155         if (parallaxMethod > ParallaxOcclusionMapping)
156             parallaxMethod = ParallaxOcclusionMapping;
157         if (parallaxMethod < 0)
158             parallaxMethod = 0;
159 
160         setParameter("sphericalNormal", cast(int)isphericalNormal.asBool);
161 
162         // Diffuse
163         if (idiffuse.texture)
164         {
165             glActiveTexture(GL_TEXTURE0);
166             idiffuse.texture.bind();
167             setParameter("diffuseTexture", cast(int)0);
168             setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorTexture");
169         }
170         else
171         {
172             setParameter("diffuseVector", idiffuse.asVector4f);
173             setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorValue");
174         }
175 
176         // Normal/height
177         bool haveHeightMap = inormal.texture !is null;
178         if (haveHeightMap)
179             haveHeightMap = inormal.texture.image.channels == 4;
180 
181         if (!haveHeightMap)
182         {
183             if (inormal.texture is null)
184             {
185                 if (iheight.texture !is null) // we have height map, but no normal map
186                 {
187                     Color4f color = Color4f(0.5f, 0.5f, 1.0f, 0.0f); // default normal pointing upwards
188                     inormal.texture = state.material.makeTexture(color, iheight.texture);
189                     haveHeightMap = true;
190                 }
191                 else
192                 {
193                     Color4f color = Color4f(0.5f, 0.5f, 1.0f, 0.0f); // default normal pointing upwards
194                     inormal.texture = state.material.makeTexture(color);
195                 }
196             }
197             else
198             {
199                 if (iheight.texture !is null) // we have both normal and height maps
200                 {
201                     inormal.texture = state.material.makeTexture(inormal.texture, iheight.texture);
202                     haveHeightMap = true;
203                 }
204             }
205         }
206 
207         if (inormal.texture)
208         {
209             setParameter("normalTexture", 1);
210             setParameterSubroutine("normal", ShaderType.Fragment, "normalMap");
211 
212             glActiveTexture(GL_TEXTURE1);
213             inormal.texture.bind();
214         }
215         else
216         {
217             setParameter("normalVector", state.material.normal.asVector3f);
218             setParameterSubroutine("normal", ShaderType.Fragment, "normalValue");
219         }
220 
221         // Height and parallax
222         // TODO: make these material properties
223         float parallaxScale = 0.03f;
224         float parallaxBias = -0.01f;
225         setParameter("parallaxScale", parallaxScale);
226         setParameter("parallaxBias", parallaxBias);
227 
228         if (haveHeightMap)
229         {
230             setParameterSubroutine("height", ShaderType.Fragment, "heightMap");
231         }
232         else
233         {
234             float h = 0.0f; //-parallaxBias / parallaxScale;
235             setParameter("heightScalar", h);
236             setParameterSubroutine("height", ShaderType.Fragment, "heightValue");
237             parallaxMethod = ParallaxNone;
238         }
239 
240         if (parallaxMethod == ParallaxSimple)
241             setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxSimple");
242         else if (parallaxMethod == ParallaxOcclusionMapping)
243             setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxOcclusionMapping");
244         else
245             setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxNone");
246 
247         // PBR
248         if (ipbr is null)
249         {
250             state.material.setInput("pbr", 0.0f);
251             ipbr = "pbr" in state.material.inputs;
252         }
253         if (ipbr.texture is null)
254         {
255             ipbr.texture = state.material.makeTexture(*iroughness, *imetallic, *ispecularity, *itranslucency);
256         }
257         glActiveTexture(GL_TEXTURE2);
258         ipbr.texture.bind();
259         setParameter("pbrTexture", 2);
260 
261         if (iroughness.texture is null)
262         {
263             setParameterSubroutine("roughness", ShaderType.Fragment, "roughnessValue");
264 
265             if (iroughness.type == MaterialInputType.Float)
266                 setParameter("roughnessScalar", iroughness.asFloat);
267             else if (iroughness.type == MaterialInputType.Bool)
268                 setParameter("roughnessScalar", cast(float)iroughness.asBool);
269             else if (iroughness.type == MaterialInputType.Integer)
270                 setParameter("roughnessScalar", cast(float)iroughness.asInteger);
271             else if (iroughness.type == MaterialInputType.Vec2)
272                 setParameter("roughnessScalar", iroughness.asVector2f.r);
273             else if (iroughness.type == MaterialInputType.Vec3)
274                 setParameter("roughnessScalar", iroughness.asVector3f.r);
275             else if (iroughness.type == MaterialInputType.Vec4)
276                 setParameter("roughnessScalar", iroughness.asVector4f.r);
277         }
278         else
279         {
280             setParameterSubroutine("roughness", ShaderType.Fragment, "roughnessMap");
281         }
282 
283         if (imetallic.texture is null)
284         {
285             setParameterSubroutine("metallic", ShaderType.Fragment, "metallicValue");
286 
287             if (imetallic.type == MaterialInputType.Float)
288                 setParameter("metallicScalar", imetallic.asFloat);
289             else if (imetallic.type == MaterialInputType.Bool)
290                 setParameter("metallicScalar", cast(float)imetallic.asBool);
291             else if (imetallic.type == MaterialInputType.Integer)
292                 setParameter("metallicScalar", cast(float)imetallic.asInteger);
293             else if (imetallic.type == MaterialInputType.Vec2)
294                 setParameter("metallicScalar", imetallic.asVector2f.r);
295             else if (imetallic.type == MaterialInputType.Vec3)
296                 setParameter("metallicScalar", imetallic.asVector3f.r);
297             else if (imetallic.type == MaterialInputType.Vec4)
298                 setParameter("metallicScalar", imetallic.asVector4f.r);
299         }
300         else
301         {
302             setParameterSubroutine("metallic", ShaderType.Fragment, "metallicMap");
303         }
304 
305         if (ispecularity.texture is null)
306         {
307             setParameterSubroutine("specularity", ShaderType.Fragment, "specularityValue");
308 
309             if (ispecularity.type == MaterialInputType.Float)
310                 setParameter("specularityScalar", ispecularity.asFloat);
311             else if (ispecularity.type == MaterialInputType.Bool)
312                 setParameter("specularityScalar", cast(float)ispecularity.asBool);
313             else if (ispecularity.type == MaterialInputType.Integer)
314                 setParameter("specularityScalar", cast(float)ispecularity.asInteger);
315             else if (ispecularity.type == MaterialInputType.Vec2)
316                 setParameter("specularityScalar", ispecularity.asVector2f.r);
317             else if (ispecularity.type == MaterialInputType.Vec3)
318                 setParameter("specularityScalar", ispecularity.asVector3f.r);
319             else if (ispecularity.type == MaterialInputType.Vec4)
320                 setParameter("specularityScalar", ispecularity.asVector4f.r);
321         }
322         else
323         {
324             setParameterSubroutine("specularity", ShaderType.Fragment, "specularityMap");
325         }
326 
327         if (itranslucency.texture is null)
328         {
329             setParameterSubroutine("translucency", ShaderType.Fragment, "translucencyValue");
330 
331             if (itranslucency.type == MaterialInputType.Float)
332                 setParameter("translucencyScalar", itranslucency.asFloat);
333             else if (itranslucency.type == MaterialInputType.Bool)
334                 setParameter("translucencyScalar", cast(float)itranslucency.asBool);
335             else if (itranslucency.type == MaterialInputType.Integer)
336                 setParameter("translucencyScalar", cast(float)itranslucency.asInteger);
337             else if (itranslucency.type == MaterialInputType.Vec2)
338                 setParameter("translucencyScalar", itranslucency.asVector2f.r);
339             else if (itranslucency.type == MaterialInputType.Vec3)
340                 setParameter("translucencyScalar", itranslucency.asVector3f.r);
341             else if (itranslucency.type == MaterialInputType.Vec4)
342                 setParameter("translucencyScalar", itranslucency.asVector4f.r);
343         }
344         else
345         {
346             setParameterSubroutine("translucency", ShaderType.Fragment, "translucencyMap");
347         }
348 
349         // Emission
350         if (iemission.texture)
351         {
352             glActiveTexture(GL_TEXTURE3);
353             iemission.texture.bind();
354             setParameter("emissionTexture", cast(int)3);
355             setParameterSubroutine("emission", ShaderType.Fragment, "emissionColorTexture");
356         }
357         else
358         {
359             setParameter("emissionVector", iemission.asVector4f);
360             setParameterSubroutine("emission", ShaderType.Fragment, "emissionColorValue");
361         }
362         setParameter("energy", ienergy.asFloat);
363 
364         // Environment
365         if (state.environment)
366         {
367             setParameter("fogColor", state.environment.fogColor);
368             setParameter("fogStart", state.environment.fogStart);
369             setParameter("fogEnd", state.environment.fogEnd);
370             setParameter("ambientEnergy", state.environment.ambientEnergy);
371 
372             if (state.environment.ambientMap)
373             {
374                 glActiveTexture(GL_TEXTURE4);
375                 state.environment.ambientMap.bind();
376                 if (cast(Cubemap)state.environment.ambientMap)
377                 {
378                     setParameter("ambientTextureCube", 4);
379                     setParameterSubroutine("ambient", ShaderType.Fragment, "ambientCubemap");
380                 }
381                 else
382                 {
383                     setParameter("ambientTexture", 4);
384                     setParameterSubroutine("ambient", ShaderType.Fragment, "ambientEquirectangularMap");
385                 }
386             }
387             else
388             {
389                 setParameter("ambientVector", state.environment.ambientColor);
390                 setParameterSubroutine("ambient", ShaderType.Fragment, "ambientColor");
391             }
392         }
393         else
394         {
395             setParameter("fogColor", Color4f(0.5f, 0.5f, 0.5f, 1.0f));
396             setParameter("fogStart", 0.0f);
397             setParameter("fogEnd", 1000.0f);
398             setParameter("ambientEnergy", 1.0f);
399             setParameter("ambientVector", Color4f(0.5f, 0.5f, 0.5f, 1.0f));
400             setParameterSubroutine("ambient", ShaderType.Fragment, "ambientColor");
401         }
402 
403         // Shadow map
404         if (state.material.sun)
405         {
406             if (state.material.sun.shadowEnabled)
407             {
408                 CascadedShadowMap csm = cast(CascadedShadowMap)state.material.sun.shadowMap;
409 
410                 glActiveTexture(GL_TEXTURE5);
411                 glBindTexture(GL_TEXTURE_2D_ARRAY, csm.depthTexture);
412                 setParameter("shadowTextureArray", 5);
413                 setParameter("shadowResolution", cast(float)csm.resolution);
414                 setParameter("shadowMatrix1", csm.area[0].shadowMatrix);
415                 setParameter("shadowMatrix2", csm.area[1].shadowMatrix);
416                 setParameter("shadowMatrix3", csm.area[2].shadowMatrix);
417                 setParameterSubroutine("shadowMap", ShaderType.Fragment, "shadowMapCascaded");
418             }
419             else
420             {
421                 glActiveTexture(GL_TEXTURE5);
422                 glBindTexture(GL_TEXTURE_2D_ARRAY, defaultShadowTexture);
423                 setParameter("shadowTextureArray", 5);
424                 setParameter("shadowMatrix1", defaultShadowMatrix);
425                 setParameter("shadowMatrix2", defaultShadowMatrix);
426                 setParameter("shadowMatrix3", defaultShadowMatrix);
427                 setParameterSubroutine("shadowMap", ShaderType.Fragment, "shadowMapNone");
428             }
429         }
430         else
431         {
432             glActiveTexture(GL_TEXTURE5);
433             glBindTexture(GL_TEXTURE_2D_ARRAY, defaultShadowTexture);
434             setParameter("shadowTextureArray", 5);
435             setParameter("shadowMatrix1", defaultShadowMatrix);
436             setParameter("shadowMatrix2", defaultShadowMatrix);
437             setParameter("shadowMatrix3", defaultShadowMatrix);
438             setParameterSubroutine("shadowMap", ShaderType.Fragment, "shadowMapNone");
439         }
440 
441         super.bindParameters(state);
442     }
443 
444     override void unbindParameters(GraphicsState* state)
445     {
446         super.unbindParameters(state);
447 
448         glActiveTexture(GL_TEXTURE0);
449         glBindTexture(GL_TEXTURE_2D, 0);
450 
451         glActiveTexture(GL_TEXTURE1);
452         glBindTexture(GL_TEXTURE_2D, 0);
453 
454         glActiveTexture(GL_TEXTURE2);
455         glBindTexture(GL_TEXTURE_2D, 0);
456 
457         glActiveTexture(GL_TEXTURE3);
458         glBindTexture(GL_TEXTURE_2D, 0);
459 
460         glActiveTexture(GL_TEXTURE4);
461         glBindTexture(GL_TEXTURE_2D, 0);
462         glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
463 
464         glActiveTexture(GL_TEXTURE5);
465         glBindTexture(GL_TEXTURE_2D, 0);
466 
467         glActiveTexture(GL_TEXTURE0);
468     }
469 }