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.geometry;
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 GeometryShader: Shader
48 {
49     String vs, fs;
50 
51     this(Owner owner)
52     {
53         vs = Shader.load("data/__internal/shaders/Geometry/Geometry.vert.glsl");
54         fs = Shader.load("data/__internal/shaders/Geometry/Geometry.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 idiffuse = "diffuse" in state.material.inputs;
69         auto inormal = "normal" in state.material.inputs;
70         auto iheight = "height" in state.material.inputs;
71         auto iroughnessMetallic = "roughnessMetallic" in state.material.inputs;
72         auto iroughness = "roughness" in state.material.inputs;
73         auto imetallic = "metallic" in state.material.inputs;
74         auto ispecularity = "specularity" in state.material.inputs;
75         auto itransparency = "transparency" in state.material.inputs;
76         auto iclipThreshold = "clipThreshold" in state.material.inputs;
77         auto itranslucency = "translucency" in state.material.inputs;
78         auto itextureScale = "textureScale" in state.material.inputs;
79         auto iparallax = "parallax" in state.material.inputs;
80         auto iemission = "emission" in state.material.inputs;
81         auto ienergy = "energy" in state.material.inputs;
82         auto isphericalNormal = "sphericalNormal" in state.material.inputs;
83 
84         setParameter("modelViewMatrix", state.modelViewMatrix);
85         setParameter("projectionMatrix", state.projectionMatrix);
86         setParameter("normalMatrix", state.normalMatrix);
87         setParameter("viewMatrix", state.viewMatrix);
88         setParameter("invViewMatrix", state.invViewMatrix);
89         setParameter("prevModelViewMatrix", state.prevModelViewMatrix);
90 
91         setParameter("layer", cast(float)(state.layer));
92         setParameter("textureScale", itextureScale.asVector2f);
93         setParameter("blurMask", state.blurMask);
94 
95         int parallaxMethod = iparallax.asInteger;
96         if (parallaxMethod > ParallaxOcclusionMapping)
97             parallaxMethod = ParallaxOcclusionMapping;
98         if (parallaxMethod < 0)
99             parallaxMethod = 0;
100 
101         setParameter("sphericalNormal", cast(int)isphericalNormal.asBool);
102 
103         // Transparency
104         float materialOpacity = 1.0f;
105         if (itransparency)
106             materialOpacity = itransparency.asFloat;
107         setParameter("opacity", state.opacity * materialOpacity);
108         
109         float clipThreshold = 0.5f;
110         if (iclipThreshold)
111             clipThreshold = iclipThreshold.asFloat;
112         setParameter("clipThreshold", clipThreshold);
113 
114         // Diffuse
115         if (idiffuse.texture)
116         {
117             glActiveTexture(GL_TEXTURE0);
118             idiffuse.texture.bind();
119             setParameter("diffuseTexture", cast(int)0);
120             setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorTexture");
121         }
122         else
123         {
124             setParameter("diffuseVector", idiffuse.asVector4f);
125             setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorValue");
126         }
127 
128         // Normal/height
129         bool haveHeightMap = inormal.texture !is null;
130         if (haveHeightMap)
131             haveHeightMap = inormal.texture.image.channels == 4;
132 
133         if (!haveHeightMap)
134         {
135             if (inormal.texture is null)
136             {
137                 if (iheight.texture !is null) // we have height map, but no normal map
138                 {
139                     Color4f color = Color4f(0.5f, 0.5f, 1.0f, 0.0f); // default normal pointing upwards
140                     inormal.texture = state.material.makeTexture(color, iheight.texture);
141                     haveHeightMap = true;
142                 }
143             }
144             else
145             {
146                 if (iheight.texture !is null) // we have both normal and height maps
147                 {
148                     inormal.texture = state.material.makeTexture(inormal.texture, iheight.texture);
149                     haveHeightMap = true;
150                 }
151             }
152         }
153 
154         if (inormal.texture)
155         {
156             setParameter("generateTBN", 1);
157             setParameter("normalTexture", 1);
158             setParameterSubroutine("normal", ShaderType.Fragment, "normalMap");
159 
160             glActiveTexture(GL_TEXTURE1);
161             inormal.texture.bind();
162         }
163         else
164         {
165             setParameter("generateTBN", 0);
166             setParameter("normalVector", state.material.normal.asVector3f);
167             setParameterSubroutine("normal", ShaderType.Fragment, "normalValue");
168         }
169         
170         if (state.material.invertNormalY)
171             setParameter("normalYSign", -1.0f);
172         else
173             setParameter("normalYSign", 1.0f);
174 
175         // Height and parallax
176         // TODO: make these material properties
177         float parallaxScale = 0.03f;
178         float parallaxBias = -0.01f;
179         setParameter("parallaxScale", parallaxScale);
180         setParameter("parallaxBias", parallaxBias);
181 
182         if (haveHeightMap)
183         {
184             setParameterSubroutine("height", ShaderType.Fragment, "heightMap");
185         }
186         else
187         {
188             float h = 0.0f; //-parallaxBias / parallaxScale;
189             setParameter("heightScalar", h);
190             setParameterSubroutine("height", ShaderType.Fragment, "heightValue");
191             parallaxMethod = ParallaxNone;
192         }
193 
194         if (parallaxMethod == ParallaxSimple)
195             setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxSimple");
196         else if (parallaxMethod == ParallaxOcclusionMapping)
197             setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxOcclusionMapping");
198         else
199             setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxNone");
200 
201         // PBR
202         if (iroughnessMetallic is null)
203         {
204             state.material.setInput("roughnessMetallic", 0.0f);
205             iroughnessMetallic = "roughnessMetallic" in state.material.inputs;
206         }
207         if (iroughnessMetallic.texture is null)
208         {
209             iroughnessMetallic.texture = state.material.makeTexture(*ispecularity, *iroughness, *imetallic, *itranslucency);
210         }
211         glActiveTexture(GL_TEXTURE2);
212         iroughnessMetallic.texture.bind();
213         setParameter("pbrTexture", 2);
214         
215         setParameterSubroutine("specularity", ShaderType.Fragment, "specularityMap");
216         setParameterSubroutine("metallic", ShaderType.Fragment, "metallicMap");
217         setParameterSubroutine("roughness", ShaderType.Fragment, "roughnessMap");
218         setParameterSubroutine("translucency", ShaderType.Fragment, "translucencyMap");
219         
220         // TODO: specularity, translucensy
221 
222         // Emission
223         if (iemission.texture)
224         {
225             glActiveTexture(GL_TEXTURE3);
226             iemission.texture.bind();
227             setParameter("emissionTexture", cast(int)3);
228             setParameterSubroutine("emission", ShaderType.Fragment, "emissionColorTexture");
229         }
230         else
231         {
232             setParameter("emissionVector", iemission.asVector4f);
233             setParameterSubroutine("emission", ShaderType.Fragment, "emissionColorValue");
234         }
235         setParameter("energy", ienergy.asFloat);
236 
237         glActiveTexture(GL_TEXTURE0);
238 
239         super.bindParameters(state);
240     }
241 
242     override void unbindParameters(GraphicsState* state)
243     {
244         super.unbindParameters(state);
245 
246         glActiveTexture(GL_TEXTURE0);
247         glBindTexture(GL_TEXTURE_2D, 0);
248 
249         glActiveTexture(GL_TEXTURE1);
250         glBindTexture(GL_TEXTURE_2D, 0);
251 
252         glActiveTexture(GL_TEXTURE2);
253         glBindTexture(GL_TEXTURE_2D, 0);
254 
255         glActiveTexture(GL_TEXTURE3);
256         glBindTexture(GL_TEXTURE_2D, 0);
257 
258         glActiveTexture(GL_TEXTURE0);
259     }
260 }