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.decal;
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.render.gbuffer;
47 
48 class DecalShader: Shader
49 {
50     String vs, fs;
51 
52     GBuffer gbuffer;
53 
54     this(GBuffer gbuffer, Owner owner)
55     {
56         vs = Shader.load("data/__internal/shaders/Decal/Decal.vert.glsl");
57         fs = Shader.load("data/__internal/shaders/Decal/Decal.frag.glsl");
58 
59         auto prog = New!ShaderProgram(vs, fs, this);
60         super(prog, owner);
61 
62         this.gbuffer = gbuffer;
63     }
64 
65     ~this()
66     {
67         vs.free();
68         fs.free();
69     }
70 
71     override void bindParameters(GraphicsState* state)
72     {
73         auto idiffuse = "diffuse" in state.material.inputs;
74         auto inormal = "normal" in state.material.inputs;
75         auto iheight = "height" in state.material.inputs;
76         auto iparallax = "parallax" in state.material.inputs;
77         auto iroughnessMetallic = "roughnessMetallic" in state.material.inputs;
78         auto iroughness = "roughness" in state.material.inputs;
79         auto imetallic = "metallic" in state.material.inputs;
80         auto ispecularity = "specularity" in state.material.inputs;
81         auto itextureScale = "textureScale" in state.material.inputs;
82         auto iemission = "emission" in state.material.inputs;
83         auto ienergy = "energy" in state.material.inputs;
84         auto ioutputColor = "outputColor" in state.material.inputs;
85         auto ioutputNormal = "outputNormal" in state.material.inputs;
86         auto ioutputPBR = "outputPBR" in state.material.inputs;
87         auto ioutputEmission = "outputEmission" in state.material.inputs;
88 
89         int parallaxMethod = iparallax.asInteger;
90         if (parallaxMethod > ParallaxOcclusionMapping)
91             parallaxMethod = ParallaxOcclusionMapping;
92         if (parallaxMethod < 0)
93             parallaxMethod = 0;
94 
95         setParameter("modelViewMatrix", state.modelViewMatrix);
96         setParameter("projectionMatrix", state.projectionMatrix);
97         setParameter("invProjectionMatrix", state.invProjectionMatrix);
98         setParameter("normalMatrix", state.normalMatrix);
99         setParameter("viewMatrix", state.viewMatrix);
100         setParameter("invViewMatrix", state.invViewMatrix);
101         setParameter("invModelMatrix", state.invModelMatrix);
102         setParameter("resolution", state.resolution);
103 
104         setParameter("opacity", state.opacity);
105         setParameter("textureScale", itextureScale.asVector2f);
106 
107         glActiveTexture(GL_TEXTURE0);
108         glBindTexture(GL_TEXTURE_2D, gbuffer.depthTexture);
109         setParameter("depthTexture", cast(int)0);
110 
111         // Diffuse
112         if (idiffuse.texture)
113         {
114             glActiveTexture(GL_TEXTURE1);
115             idiffuse.texture.bind();
116             setParameter("diffuseTexture", cast(int)1);
117             setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorTexture");
118         }
119         else
120         {
121             setParameter("diffuseVector", idiffuse.asVector4f);
122             setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorValue");
123         }
124 
125         if (!ioutputColor.asBool)
126         {
127             glColorMaski(0, 0, 0, 0, 0);
128         }
129 
130         // Normal/height
131         bool haveHeightMap = inormal.texture !is null;
132         if (haveHeightMap)
133             haveHeightMap = inormal.texture.image.channels == 4;
134 
135         if (!haveHeightMap)
136         {
137             if (inormal.texture is null)
138             {
139                 if (iheight.texture !is null) // we have height map, but no normal map
140                 {
141                     Color4f color = Color4f(0.5f, 0.5f, 1.0f, 0.0f); // default normal pointing upwards
142                     inormal.texture = state.material.makeTexture(color, iheight.texture);
143                     haveHeightMap = true;
144                 }
145             }
146             else
147             {
148                 if (iheight.texture !is null) // we have both normal and height maps
149                 {
150                     inormal.texture = state.material.makeTexture(inormal.texture, iheight.texture);
151                     haveHeightMap = true;
152                 }
153             }
154         }
155 
156         if (inormal.texture)
157         {
158             setParameter("normalTexture", 2);
159             setParameterSubroutine("normal", ShaderType.Fragment, "normalMap");
160 
161             glActiveTexture(GL_TEXTURE2);
162             inormal.texture.bind();
163         }
164         else
165         {
166             setParameter("normalVector", state.material.normal.asVector3f);
167             setParameterSubroutine("normal", ShaderType.Fragment, "normalValue");
168         }
169 
170         if (!ioutputNormal.asBool)
171         {
172             glColorMaski(1, 0, 0, 0, 0);
173         }
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, materialInput(0.0f));
210         }
211         glActiveTexture(GL_TEXTURE3);
212         iroughnessMetallic.texture.bind();
213         setParameter("pbrTexture", 3);
214         
215         setParameterSubroutine("specularity", ShaderType.Fragment, "specularityMap");
216         setParameterSubroutine("metallic", ShaderType.Fragment, "metallicMap");
217         setParameterSubroutine("roughness", ShaderType.Fragment, "roughnessMap");
218 
219         if (!ioutputPBR.asBool)
220         {
221             glColorMaski(2, 0, 0, 0, 0);
222         }
223 
224         // Emission
225         if (iemission.texture)
226         {
227             glActiveTexture(GL_TEXTURE4);
228             iemission.texture.bind();
229             setParameter("emissionTexture", cast(int)4);
230             setParameterSubroutine("emission", ShaderType.Fragment, "emissionMap");
231         }
232         else
233         {
234             setParameter("emissionVector", iemission.asVector4f);
235             setParameterSubroutine("emission", ShaderType.Fragment, "emissionValue");
236         }
237         setParameter("energy", ienergy.asFloat);
238 
239         if (!ioutputEmission.asBool)
240         {
241             glColorMaski(3, 0, 0, 0, 0);
242         }
243 
244         glActiveTexture(GL_TEXTURE0);
245 
246         super.bindParameters(state);
247     }
248 
249     override void unbindParameters(GraphicsState* state)
250     {
251         super.unbindParameters(state);
252 
253         glColorMaski(0, 1, 1, 1, 1);
254         glColorMaski(1, 1, 1, 1, 1);
255         glColorMaski(2, 1, 1, 1, 1);
256         glColorMaski(3, 1, 1, 1, 1);
257 
258         glActiveTexture(GL_TEXTURE0);
259         glBindTexture(GL_TEXTURE_2D, 0);
260 
261         glActiveTexture(GL_TEXTURE1);
262         glBindTexture(GL_TEXTURE_2D, 0);
263 
264         glActiveTexture(GL_TEXTURE2);
265         glBindTexture(GL_TEXTURE_2D, 0);
266 
267         glActiveTexture(GL_TEXTURE3);
268         glBindTexture(GL_TEXTURE_2D, 0);
269 
270         glActiveTexture(GL_TEXTURE4);
271         glBindTexture(GL_TEXTURE_2D, 0);
272 
273         glActiveTexture(GL_TEXTURE0);
274     }
275 }