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         auto itextureScale = "textureScale" in rc.material.inputs;
71 
72         int parallaxMethod = iparallax.asInteger;
73         if (parallaxMethod > ParallaxOcclusionMapping)
74             parallaxMethod = ParallaxOcclusionMapping;
75         if (parallaxMethod < 0)
76             parallaxMethod = 0;
77 
78         setParameter("layer", rc.layer);
79         setParameter("blurMask", rc.blurMask);
80 
81         setParameter("modelViewMatrix", rc.modelViewMatrix);
82         setParameter("projectionMatrix", rc.projectionMatrix);
83         setParameter("normalMatrix", rc.normalMatrix);
84 
85         setParameter("prevModelViewProjMatrix", rc.prevModelViewProjMatrix);
86         setParameter("blurModelViewProjMatrix", rc.blurModelViewProjMatrix);
87         
88         setParameter("textureScale", itextureScale.asVector2f);
89 
90         // Diffuse
91         if (idiffuse.texture)
92         {
93             glActiveTexture(GL_TEXTURE0);
94             idiffuse.texture.bind();
95             setParameter("diffuseTexture", cast(int)0);
96             setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorTexture");
97         }
98         else
99         {
100             setParameter("diffuseVector", rc.material.diffuse.asVector4f);
101             setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorValue");
102         }
103 
104         // Normal/height
105         bool haveHeightMap = inormal.texture !is null;
106         if (haveHeightMap)
107             haveHeightMap = inormal.texture.image.channels == 4;
108 
109         if (!haveHeightMap)
110         {
111             if (inormal.texture is null)
112             {
113                 if (iheight.texture !is null) // we have height map, but no normal map
114                 {
115                     Color4f color = Color4f(0.5f, 0.5f, 1.0f, 0.0f); // default normal pointing upwards
116                     inormal.texture = rc.material.makeTexture(color, iheight.texture);
117                     haveHeightMap = true;
118                 }
119             }
120             else
121             {
122                 if (iheight.texture !is null) // we have both normal and height maps
123                 {
124                     inormal.texture = rc.material.makeTexture(inormal.texture, iheight.texture);
125                     haveHeightMap = true;
126                 }
127             }
128         }
129 
130         if (inormal.texture)
131         {
132             setParameter("normalTexture", 1);
133             setParameterSubroutine("normal", ShaderType.Fragment, "normalMap");
134 
135             glActiveTexture(GL_TEXTURE1);
136             inormal.texture.bind();
137         }
138         else
139         {
140             setParameter("normalVector", rc.material.normal.asVector3f);
141             setParameterSubroutine("normal", ShaderType.Fragment, "normalValue");
142         }
143 
144         // Height and parallax
145 
146         // TODO: make these material properties
147         float parallaxScale = 0.03f;
148         float parallaxBias = -0.01f;
149         setParameter("parallaxScale", parallaxScale);
150         setParameter("parallaxBias", parallaxBias);
151 
152         if (haveHeightMap)
153         {
154             setParameterSubroutine("height", ShaderType.Fragment, "heightMap");
155         }
156         else
157         {
158             float h = 0.0f; //-parallaxBias / parallaxScale;
159             setParameter("heightScalar", h);
160             setParameterSubroutine("height", ShaderType.Fragment, "heightValue");
161             parallaxMethod = ParallaxNone;
162         }
163 
164         if (parallaxMethod == ParallaxSimple)
165             setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxSimple");
166         else if (parallaxMethod == ParallaxOcclusionMapping)
167             setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxOcclusionMapping");
168         else
169             setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxNone");
170 
171         // PBR
172         // TODO: pass solid values as uniforms, make subroutine for each mode
173         if (ipbr is null)
174         {
175             rc.material.setInput("pbr", 0.0f);
176             ipbr = "pbr" in rc.material.inputs;
177         }
178 
179         if (ipbr.texture is null)
180             ipbr.texture = rc.material.makeTexture(*iroughness, *imetallic, materialInput(0.0f), materialInput(0.0f));
181         glActiveTexture(GL_TEXTURE2);
182         ipbr.texture.bind();
183         setParameter("pbrTexture", 2);
184 
185         // Emission
186         if (iemission.texture)
187         {
188             glActiveTexture(GL_TEXTURE3);
189             iemission.texture.bind();
190 
191             setParameter("emissionTexture", 3);
192             setParameterSubroutine("emission", ShaderType.Fragment, "emissionMap");
193         }
194         else
195         {
196             setParameter("emissionVector", rc.material.emission.asVector4f);
197             setParameterSubroutine("emission", ShaderType.Fragment, "emissionValue");
198         }
199 
200         setParameter("emissionEnergy", ienergy.asFloat);
201 
202         glActiveTexture(GL_TEXTURE0);
203 
204         super.bind(rc);
205     }
206 
207     override void unbind(RenderingContext* rc)
208     {
209         super.unbind(rc);
210 
211         glActiveTexture(GL_TEXTURE0);
212         glBindTexture(GL_TEXTURE_2D, 0);
213 
214         glActiveTexture(GL_TEXTURE1);
215         glBindTexture(GL_TEXTURE_2D, 0);
216 
217         glActiveTexture(GL_TEXTURE2);
218         glBindTexture(GL_TEXTURE_2D, 0);
219 
220         glActiveTexture(GL_TEXTURE3);
221         glBindTexture(GL_TEXTURE_2D, 0);
222 
223         glActiveTexture(GL_TEXTURE4);
224         glBindTexture(GL_TEXTURE_2D, 0);
225 
226         glActiveTexture(GL_TEXTURE5);
227         glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
228 
229         glActiveTexture(GL_TEXTURE6);
230         glBindTexture(GL_TEXTURE_2D, 0);
231 
232         glActiveTexture(GL_TEXTURE7);
233         glBindTexture(GL_TEXTURE_2D, 0);
234 
235         glActiveTexture(GL_TEXTURE8);
236         glBindTexture(GL_TEXTURE_2D, 0);
237 
238         glActiveTexture(GL_TEXTURE0);
239     }
240 }