1 /*
2 Copyright (c) 2017-2018 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.graphics.shaders.geometrypass;
29 
30 import std.stdio;
31 import std.math;
32 
33 import dlib.core.memory;
34 import dlib.math.vector;
35 import dlib.math.matrix;
36 import dlib.math.transformation;
37 import dlib.math.interpolation;
38 import dlib.image.color;
39 
40 import dagon.core.libs;
41 import dagon.core.ownership;
42 import dagon.graphics.rc;
43 import dagon.graphics.shadow;
44 import dagon.graphics.texture;
45 import dagon.graphics.material;
46 import dagon.graphics.shader;
47 
48 class GeometryPassShader: Shader
49 {
50     string vs = import("GeometryPass.vs");
51     string fs = import("GeometryPass.fs");
52 
53     this(Owner o)
54     {
55         auto myProgram = New!ShaderProgram(vs, fs, this);
56         super(myProgram, o);
57     }
58 
59     override void bind(RenderingContext* rc)
60     {
61         auto idiffuse = "diffuse" in rc.material.inputs;
62         auto inormal = "normal" in rc.material.inputs;
63         auto iheight = "height" in rc.material.inputs;
64         auto ipbr = "pbr" in rc.material.inputs;
65         auto iroughness = "roughness" in rc.material.inputs;
66         auto imetallic = "metallic" in rc.material.inputs;
67         auto iemission = "emission" in rc.material.inputs;
68         auto ienergy = "energy" in rc.material.inputs;
69         auto iparallax = "parallax" in rc.material.inputs;
70 
71         int parallaxMethod = iparallax.asInteger;
72         if (parallaxMethod > ParallaxOcclusionMapping)
73             parallaxMethod = ParallaxOcclusionMapping;
74         if (parallaxMethod < 0)
75             parallaxMethod = 0;
76 
77         setParameter("layer", rc.layer);
78         setParameter("blurMask", rc.blurMask);
79 
80         setParameter("modelViewMatrix", rc.modelViewMatrix);
81         setParameter("projectionMatrix", rc.projectionMatrix);
82         setParameter("normalMatrix", rc.normalMatrix);
83 
84         setParameter("prevModelViewProjMatrix", rc.prevModelViewProjMatrix);
85         setParameter("blurModelViewProjMatrix", rc.blurModelViewProjMatrix);
86 
87         // Diffuse
88         if (idiffuse.texture)
89         {
90             glActiveTexture(GL_TEXTURE0);
91             idiffuse.texture.bind();
92             setParameter("diffuseTexture", cast(int)0);
93             setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorTexture");
94         }
95         else
96         {
97             setParameter("diffuseVector", rc.material.diffuse.asVector4f);
98             setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorValue");
99         }
100 
101         // Normal/height
102         bool haveHeightMap = inormal.texture !is null;
103         if (haveHeightMap)
104             haveHeightMap = inormal.texture.image.channels == 4;
105 
106         if (!haveHeightMap)
107         {
108             if (inormal.texture is null)
109             {
110                 if (iheight.texture !is null) // we have height map, but no normal map
111                 {
112                     Color4f color = Color4f(0.5f, 0.5f, 1.0f, 0.0f); // default normal pointing upwards
113                     inormal.texture = rc.material.makeTexture(color, iheight.texture);
114                     haveHeightMap = true;
115                 }
116             }
117             else
118             {
119                 if (iheight.texture !is null) // we have both normal and height maps
120                 {
121                     inormal.texture = rc.material.makeTexture(inormal.texture, iheight.texture);
122                     haveHeightMap = true;
123                 }
124             }
125         }
126 
127         if (inormal.texture)
128         {
129             setParameter("normalTexture", 1);
130             setParameterSubroutine("normal", ShaderType.Fragment, "normalMap");
131 
132             glActiveTexture(GL_TEXTURE1);
133             inormal.texture.bind();
134         }
135         else
136         {
137             setParameter("normalVector", rc.material.normal.asVector3f);
138             setParameterSubroutine("normal", ShaderType.Fragment, "normalValue");
139         }
140 
141         // Height and parallax
142 
143         // TODO: make these material properties
144         float parallaxScale = 0.03f;
145         float parallaxBias = -0.01f;
146         setParameter("parallaxScale", parallaxScale);
147         setParameter("parallaxBias", parallaxBias);
148 
149         if (haveHeightMap)
150         {
151             setParameterSubroutine("height", ShaderType.Fragment, "heightMap");
152         }
153         else
154         {
155             float h = 0.0f; //-parallaxBias / parallaxScale;
156             setParameter("heightScalar", h);
157             setParameterSubroutine("height", ShaderType.Fragment, "heightValue");
158             parallaxMethod = ParallaxNone;
159         }
160 
161         if (parallaxMethod == ParallaxSimple)
162             setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxSimple");
163         else if (parallaxMethod == ParallaxOcclusionMapping)
164             setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxOcclusionMapping");
165         else
166             setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxNone");
167 
168         // PBR
169         // TODO: pass solid values as uniforms, make subroutine for each mode
170         if (ipbr is null)
171         {
172             rc.material.setInput("pbr", 0.0f);
173             ipbr = "pbr" in rc.material.inputs;
174         }
175 
176         if (ipbr.texture is null)
177             ipbr.texture = rc.material.makeTexture(*iroughness, *imetallic, materialInput(0.0f), materialInput(0.0f));
178         glActiveTexture(GL_TEXTURE2);
179         ipbr.texture.bind();
180         setParameter("pbrTexture", 2);
181 
182         // Emission
183         if (iemission.texture)
184         {
185             glActiveTexture(GL_TEXTURE3);
186             iemission.texture.bind();
187 
188             setParameter("emissionTexture", 3);
189             setParameterSubroutine("emission", ShaderType.Fragment, "emissionMap");
190         }
191         else
192         {
193             setParameter("emissionVector", rc.material.emission.asVector4f);
194             setParameterSubroutine("emission", ShaderType.Fragment, "emissionValue");
195         }
196 
197         setParameter("emissionEnergy", ienergy.asFloat);
198 
199         glActiveTexture(GL_TEXTURE0);
200 
201         super.bind(rc);
202     }
203 
204     override void unbind(RenderingContext* rc)
205     {
206         super.unbind(rc);
207 
208         glActiveTexture(GL_TEXTURE0);
209         glBindTexture(GL_TEXTURE_2D, 0);
210 
211         glActiveTexture(GL_TEXTURE1);
212         glBindTexture(GL_TEXTURE_2D, 0);
213 
214         glActiveTexture(GL_TEXTURE2);
215         glBindTexture(GL_TEXTURE_2D, 0);
216 
217         glActiveTexture(GL_TEXTURE3);
218         glBindTexture(GL_TEXTURE_2D, 0);
219 
220         glActiveTexture(GL_TEXTURE4);
221         glBindTexture(GL_TEXTURE_2D, 0);
222 
223         glActiveTexture(GL_TEXTURE5);
224         glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
225 
226         glActiveTexture(GL_TEXTURE6);
227         glBindTexture(GL_TEXTURE_2D, 0);
228 
229         glActiveTexture(GL_TEXTURE7);
230         glBindTexture(GL_TEXTURE_2D, 0);
231 
232         glActiveTexture(GL_TEXTURE8);
233         glBindTexture(GL_TEXTURE_2D, 0);
234 
235         glActiveTexture(GL_TEXTURE0);
236     }
237 }