1 /*
2 Copyright (c) 2019-2023 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.particle;
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 ParticleShader: Shader
48 {
49     String vs, fs;
50 
51     this(Owner owner)
52     {
53         vs = Shader.load("data/__internal/shaders/Particle/Particle.vert.glsl");
54         fs = Shader.load("data/__internal/shaders/Particle/Particle.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         Material mat = state.material;
69 
70         setParameter("modelViewMatrix", state.modelViewMatrix);
71         setParameter("projectionMatrix", state.projectionMatrix);
72         setParameter("invProjectionMatrix", state.invProjectionMatrix);
73         setParameter("viewMatrix", state.viewMatrix);
74         setParameter("invViewMatrix", state.invViewMatrix);
75         setParameter("prevModelViewMatrix", state.prevModelViewMatrix);
76 
77         setParameter("viewSize", state.resolution);
78 
79         setParameter("particleColor", mat.baseColorFactor);
80         setParameter("particleAlpha", state.opacity * mat.opacity);
81         setParameter("particleEnergy", mat.emissionEnergy);
82         
83         setParameter("alphaCutoutThreshold", mat.alphaTestThreshold);
84         setParameter("particlePosition", state.modelViewMatrix.translation);
85 
86         // Sun
87         Vector3f sunDirection = Vector3f(0.0f, 0.0f, 1.0f);
88         Color4f sunColor = Color4f(1.0f, 1.0f, 1.0f, 1.0f);
89         float sunEnergy = 1.0f;
90         float sunScatteringG = 0.0f;
91         float sunScatteringDensity = 1.0f;
92         bool shaded = false;
93         bool scatteringEnabled = false;
94         if (mat.sun)
95         {
96             auto sun = mat.sun;
97             sunDirection = sun.directionAbsolute;
98             sunColor = sun.color;
99             sunEnergy = sun.energy;
100             sunScatteringG = 1.0f - sun.scattering;
101             sunScatteringDensity = sun.mediumDensity;
102             shaded = !mat.shadeless;
103             scatteringEnabled = sun.scatteringEnabled;
104         }
105         Vector4f sunDirHg = Vector4f(sunDirection);
106         sunDirHg.w = 0.0;
107         setParameter("sunDirection", (sunDirHg * state.viewMatrix).xyz);
108         setParameter("sunColor", sunColor);
109         setParameter("sunEnergy", sunEnergy);
110         setParameter("sunScatteringG", sunScatteringG);
111         setParameter("sunScatteringDensity", sunScatteringDensity);
112         setParameter("sunScattering", scatteringEnabled);
113         setParameter("shaded", shaded);
114         
115         // Texture 0 - Diffuse
116         glActiveTexture(GL_TEXTURE0);
117         setParameter("diffuseTexture", cast(int)0);
118         setParameter("diffuseVector", mat.baseColorFactor);
119         if (mat.baseColorTexture)
120         {
121             mat.baseColorTexture.bind();
122             setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorTexture");
123         }
124         else
125         {
126             glBindTexture(GL_TEXTURE_2D, 0);
127             setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorValue");
128         }
129 
130         // Texture 1 - depth texture (for soft particles)
131         glActiveTexture(GL_TEXTURE1);
132         glBindTexture(GL_TEXTURE_2D, state.depthTexture);
133         setParameter("depthTexture", cast(int)1);
134         
135         // Texture 2 - normal map
136         glActiveTexture(GL_TEXTURE2);
137         setParameter("normalTexture", cast(int)2);
138         setParameter("normalVector", mat.normalFactor);
139         if (mat.normalTexture)
140         {
141             mat.normalTexture.bind();
142             setParameterSubroutine("normal", ShaderType.Fragment, "normalMap");
143             setParameter("generateTBN", cast(int)1);
144         }
145         else
146         {
147             glBindTexture(GL_TEXTURE_2D, 0);
148             if (mat.sphericalNormal)
149                 setParameterSubroutine("normal", ShaderType.Fragment, "normalFunctionHemisphere");
150             else
151                 setParameterSubroutine("normal", ShaderType.Fragment, "normalValue");
152             setParameter("generateTBN", cast(int)0);
153         }
154         
155         if (state.material.invertNormalY)
156             setParameter("normalYSign", -1.0f);
157         else
158             setParameter("normalYSign", 1.0f);
159 
160         // Textures 4, 5 - environment (equirectangular map, cube map)
161         if (state.environment)
162         {
163             setParameter("fogColor", state.environment.fogColor);
164             setParameter("fogStart", state.environment.fogStart);
165             setParameter("fogEnd", state.environment.fogEnd);
166             setParameter("ambientEnergy", state.environment.ambientEnergy);
167 
168             if (state.environment.ambientMap)
169             {
170                 auto ambientMap = state.environment.ambientMap;
171                 
172                 if (ambientMap.isCubemap)
173                 {
174                     glActiveTexture(GL_TEXTURE4);
175                     glBindTexture(GL_TEXTURE_2D, 0);
176                     setParameter("ambientTexture", cast(int)4);
177                     
178                     glActiveTexture(GL_TEXTURE5);
179                     ambientMap.bind();
180                     setParameter("ambientTextureCube", cast(int)5);
181                     
182                     setParameterSubroutine("ambient", ShaderType.Fragment, "ambientCubemap");
183                 }
184                 else
185                 {
186                     glActiveTexture(GL_TEXTURE4);
187                     ambientMap.bind();
188                     setParameter("ambientTexture", cast(int)4);
189                     
190                     glActiveTexture(GL_TEXTURE5);
191                     glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
192                     setParameter("ambientTextureCube", cast(int)5);
193                     
194                     setParameterSubroutine("ambient", ShaderType.Fragment, "ambientEquirectangularMap");
195                 }
196             }
197             else
198             {
199                 glActiveTexture(GL_TEXTURE4);
200                 glBindTexture(GL_TEXTURE_2D, 0);
201                 setParameter("ambientTexture", cast(int)4);
202                 
203                 glActiveTexture(GL_TEXTURE5);
204                 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
205                 setParameter("ambientTextureCube", cast(int)5);
206                 
207                 setParameter("ambientVector", state.environment.ambientColor);
208                 
209                 setParameterSubroutine("ambient", ShaderType.Fragment, "ambientColor");
210             }
211         }
212         else
213         {
214             setParameter("fogColor", Color4f(0.5f, 0.5f, 0.5f, 1.0f));
215             setParameter("fogStart", 0.0f);
216             setParameter("fogEnd", 1000.0f);
217             setParameter("ambientEnergy", 1.0f);
218             
219             glActiveTexture(GL_TEXTURE4);
220             glBindTexture(GL_TEXTURE_2D, 0);
221             setParameter("ambientTexture", cast(int)4);
222             
223             glActiveTexture(GL_TEXTURE5);
224             glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
225             setParameter("ambientTextureCube", cast(int)5);
226             
227             setParameter("ambientVector", Color4f(0.5f, 0.5f, 0.5f, 1.0f));
228             setParameterSubroutine("ambient", ShaderType.Fragment, "ambientColor");
229         }
230 
231         super.bindParameters(state);
232     }
233 
234     override void unbindParameters(GraphicsState* state)
235     {
236         super.unbindParameters(state);
237 
238         glActiveTexture(GL_TEXTURE0);
239         glBindTexture(GL_TEXTURE_2D, 0);
240 
241         glActiveTexture(GL_TEXTURE1);
242         glBindTexture(GL_TEXTURE_2D, 0);
243 
244         glActiveTexture(GL_TEXTURE2);
245         glBindTexture(GL_TEXTURE_2D, 0);
246 
247         glActiveTexture(GL_TEXTURE4);
248         glBindTexture(GL_TEXTURE_2D, 0);
249 
250         glActiveTexture(GL_TEXTURE5);
251         glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
252 
253         glActiveTexture(GL_TEXTURE0);
254     }
255 }