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.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 ipbr = "pbr" 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 itranslucency = "translucency" in state.material.inputs;
76         auto itextureScale = "textureScale" in state.material.inputs;
77         auto iparallax = "parallax" in state.material.inputs;
78         auto iemission = "emission" in state.material.inputs;
79         auto ienergy = "energy" in state.material.inputs;
80         auto isphericalNormal = "sphericalNormal" in state.material.inputs;
81 
82         setParameter("modelViewMatrix", state.modelViewMatrix);
83         setParameter("projectionMatrix", state.projectionMatrix);
84         setParameter("normalMatrix", state.normalMatrix);
85         setParameter("viewMatrix", state.viewMatrix);
86         setParameter("invViewMatrix", state.invViewMatrix);
87         setParameter("prevModelViewMatrix", state.prevModelViewMatrix);
88 
89         setParameter("layer", cast(float)(state.layer));
90         setParameter("opacity", state.opacity);
91         setParameter("textureScale", itextureScale.asVector2f);
92 
93         int parallaxMethod = iparallax.asInteger;
94         if (parallaxMethod > ParallaxOcclusionMapping)
95             parallaxMethod = ParallaxOcclusionMapping;
96         if (parallaxMethod < 0)
97             parallaxMethod = 0;
98 
99         setParameter("sphericalNormal", cast(int)isphericalNormal.asBool);
100 
101         // Diffuse
102         if (idiffuse.texture)
103         {
104             glActiveTexture(GL_TEXTURE0);
105             idiffuse.texture.bind();
106             setParameter("diffuseTexture", cast(int)0);
107             setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorTexture");
108         }
109         else
110         {
111             setParameter("diffuseVector", idiffuse.asVector4f);
112             setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorValue");
113         }
114 
115         // Normal/height
116         bool haveHeightMap = inormal.texture !is null;
117         if (haveHeightMap)
118             haveHeightMap = inormal.texture.image.channels == 4;
119 
120         if (!haveHeightMap)
121         {
122             if (inormal.texture is null)
123             {
124                 if (iheight.texture !is null) // we have height map, but no normal map
125                 {
126                     Color4f color = Color4f(0.5f, 0.5f, 1.0f, 0.0f); // default normal pointing upwards
127                     inormal.texture = state.material.makeTexture(color, iheight.texture);
128                     haveHeightMap = true;
129                 }
130                 else
131                 {
132                     Color4f color = Color4f(0.5f, 0.5f, 1.0f, 0.0f); // default normal pointing upwards
133                     inormal.texture = state.material.makeTexture(color);
134                 }
135             }
136             else
137             {
138                 if (iheight.texture !is null) // we have both normal and height maps
139                 {
140                     inormal.texture = state.material.makeTexture(inormal.texture, iheight.texture);
141                     haveHeightMap = true;
142                 }
143             }
144         }
145 
146         if (inormal.texture)
147         {
148             setParameter("normalTexture", 1);
149             setParameterSubroutine("normal", ShaderType.Fragment, "normalMap");
150 
151             glActiveTexture(GL_TEXTURE1);
152             inormal.texture.bind();
153         }
154         else
155         {
156             setParameter("normalVector", state.material.normal.asVector3f);
157             setParameterSubroutine("normal", ShaderType.Fragment, "normalValue");
158         }
159 
160         // Height and parallax
161         // TODO: make these material properties
162         float parallaxScale = 0.03f;
163         float parallaxBias = -0.01f;
164         setParameter("parallaxScale", parallaxScale);
165         setParameter("parallaxBias", parallaxBias);
166 
167         if (haveHeightMap)
168         {
169             setParameterSubroutine("height", ShaderType.Fragment, "heightMap");
170         }
171         else
172         {
173             float h = 0.0f; //-parallaxBias / parallaxScale;
174             setParameter("heightScalar", h);
175             setParameterSubroutine("height", ShaderType.Fragment, "heightValue");
176             parallaxMethod = ParallaxNone;
177         }
178 
179         if (parallaxMethod == ParallaxSimple)
180             setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxSimple");
181         else if (parallaxMethod == ParallaxOcclusionMapping)
182             setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxOcclusionMapping");
183         else
184             setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxNone");
185 
186         // PBR
187         if (ipbr is null)
188         {
189             state.material.setInput("pbr", 0.0f);
190             ipbr = "pbr" in state.material.inputs;
191         }
192         if (ipbr.texture is null)
193         {
194             ipbr.texture = state.material.makeTexture(*iroughness, *imetallic, *ispecularity, *itranslucency);
195         }
196         glActiveTexture(GL_TEXTURE2);
197         ipbr.texture.bind();
198         setParameter("pbrTexture", 2);
199 
200         if (iroughness.texture is null)
201         {
202             setParameterSubroutine("roughness", ShaderType.Fragment, "roughnessValue");
203 
204             if (iroughness.type == MaterialInputType.Float)
205                 setParameter("roughnessScalar", iroughness.asFloat);
206             else if (iroughness.type == MaterialInputType.Bool)
207                 setParameter("roughnessScalar", cast(float)iroughness.asBool);
208             else if (iroughness.type == MaterialInputType.Integer)
209                 setParameter("roughnessScalar", cast(float)iroughness.asInteger);
210             else if (iroughness.type == MaterialInputType.Vec2)
211                 setParameter("roughnessScalar", iroughness.asVector2f.r);
212             else if (iroughness.type == MaterialInputType.Vec3)
213                 setParameter("roughnessScalar", iroughness.asVector3f.r);
214             else if (iroughness.type == MaterialInputType.Vec4)
215                 setParameter("roughnessScalar", iroughness.asVector4f.r);
216         }
217         else
218         {
219             setParameterSubroutine("roughness", ShaderType.Fragment, "roughnessMap");
220         }
221 
222         if (imetallic.texture is null)
223         {
224             setParameterSubroutine("metallic", ShaderType.Fragment, "metallicValue");
225 
226             if (imetallic.type == MaterialInputType.Float)
227                 setParameter("metallicScalar", imetallic.asFloat);
228             else if (imetallic.type == MaterialInputType.Bool)
229                 setParameter("metallicScalar", cast(float)imetallic.asBool);
230             else if (imetallic.type == MaterialInputType.Integer)
231                 setParameter("metallicScalar", cast(float)imetallic.asInteger);
232             else if (imetallic.type == MaterialInputType.Vec2)
233                 setParameter("metallicScalar", imetallic.asVector2f.r);
234             else if (imetallic.type == MaterialInputType.Vec3)
235                 setParameter("metallicScalar", imetallic.asVector3f.r);
236             else if (imetallic.type == MaterialInputType.Vec4)
237                 setParameter("metallicScalar", imetallic.asVector4f.r);
238         }
239         else
240         {
241             setParameterSubroutine("metallic", ShaderType.Fragment, "metallicMap");
242         }
243 
244         if (ispecularity.texture is null)
245         {
246             setParameterSubroutine("specularity", ShaderType.Fragment, "specularityValue");
247 
248             if (ispecularity.type == MaterialInputType.Float)
249                 setParameter("specularityScalar", ispecularity.asFloat);
250             else if (ispecularity.type == MaterialInputType.Bool)
251                 setParameter("specularityScalar", cast(float)ispecularity.asBool);
252             else if (ispecularity.type == MaterialInputType.Integer)
253                 setParameter("specularityScalar", cast(float)ispecularity.asInteger);
254             else if (ispecularity.type == MaterialInputType.Vec2)
255                 setParameter("specularityScalar", ispecularity.asVector2f.r);
256             else if (ispecularity.type == MaterialInputType.Vec3)
257                 setParameter("specularityScalar", ispecularity.asVector3f.r);
258             else if (ispecularity.type == MaterialInputType.Vec4)
259                 setParameter("specularityScalar", ispecularity.asVector4f.r);
260         }
261         else
262         {
263             setParameterSubroutine("specularity", ShaderType.Fragment, "specularityMap");
264         }
265 
266         if (itranslucency.texture is null)
267         {
268             setParameterSubroutine("translucency", ShaderType.Fragment, "translucencyValue");
269 
270             if (itranslucency.type == MaterialInputType.Float)
271                 setParameter("translucencyScalar", itranslucency.asFloat);
272             else if (itranslucency.type == MaterialInputType.Bool)
273                 setParameter("translucencyScalar", cast(float)itranslucency.asBool);
274             else if (itranslucency.type == MaterialInputType.Integer)
275                 setParameter("translucencyScalar", cast(float)itranslucency.asInteger);
276             else if (itranslucency.type == MaterialInputType.Vec2)
277                 setParameter("translucencyScalar", itranslucency.asVector2f.r);
278             else if (itranslucency.type == MaterialInputType.Vec3)
279                 setParameter("translucencyScalar", itranslucency.asVector3f.r);
280             else if (itranslucency.type == MaterialInputType.Vec4)
281                 setParameter("translucencyScalar", itranslucency.asVector4f.r);
282         }
283         else
284         {
285             setParameterSubroutine("translucency", ShaderType.Fragment, "translucencyMap");
286         }
287 
288         // Emission
289         if (iemission.texture)
290         {
291             glActiveTexture(GL_TEXTURE3);
292             iemission.texture.bind();
293             setParameter("emissionTexture", cast(int)3);
294             setParameterSubroutine("emission", ShaderType.Fragment, "emissionColorTexture");
295         }
296         else
297         {
298             setParameter("emissionVector", iemission.asVector4f);
299             setParameterSubroutine("emission", ShaderType.Fragment, "emissionColorValue");
300         }
301         setParameter("energy", ienergy.asFloat);
302 
303         glActiveTexture(GL_TEXTURE0);
304 
305         super.bindParameters(state);
306     }
307 
308     override void unbindParameters(GraphicsState* state)
309     {
310         super.unbindParameters(state);
311 
312         glActiveTexture(GL_TEXTURE0);
313         glBindTexture(GL_TEXTURE_2D, 0);
314 
315         glActiveTexture(GL_TEXTURE1);
316         glBindTexture(GL_TEXTURE_2D, 0);
317 
318         glActiveTexture(GL_TEXTURE2);
319         glBindTexture(GL_TEXTURE_2D, 0);
320 
321         glActiveTexture(GL_TEXTURE3);
322         glBindTexture(GL_TEXTURE_2D, 0);
323 
324         glActiveTexture(GL_TEXTURE0);
325     }
326 }