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