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.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 import dagon.graphics.cubemap;
47 
48 class ParticleShader: Shader
49 {
50     String vs, fs;
51 
52     this(Owner owner)
53     {
54         vs = Shader.load("data/__internal/shaders/Particle/Particle.vert.glsl");
55         fs = Shader.load("data/__internal/shaders/Particle/Particle.frag.glsl");
56 
57         auto prog = New!ShaderProgram(vs, fs, this);
58         super(prog, owner);
59     }
60 
61     ~this()
62     {
63         vs.free();
64         fs.free();
65     }
66 
67     override void bindParameters(GraphicsState* state)
68     {
69         auto idiffuse = "diffuse" in state.material.inputs;
70         auto inormal = "normal" in state.material.inputs;
71         auto itransparency = "transparency" in state.material.inputs;
72         auto iparticleColor = "particleColor" in state.material.inputs;
73         auto iparticleSphericalNormal = "particleSphericalNormal" in state.material.inputs;
74         auto ishadeless = "shadeless" in state.material.inputs;
75         auto ialphaCutout = "alphaCutout" in state.material.inputs;
76         auto ialphaCutoutThreshold = "alphaCutoutThreshold" in state.material.inputs;
77 
78         setParameter("modelViewMatrix", state.modelViewMatrix);
79         setParameter("projectionMatrix", state.projectionMatrix);
80         setParameter("invProjectionMatrix", state.invProjectionMatrix);
81         setParameter("viewMatrix", state.viewMatrix);
82         setParameter("invViewMatrix", state.invViewMatrix);
83         setParameter("prevModelViewMatrix", state.prevModelViewMatrix);
84 
85         setParameter("viewSize", state.resolution);
86 
87         Color4f particleColor = Color4f(1.0f, 1.0f, 1.0f, 1.0f);
88         if (iparticleColor)
89             particleColor = Color4f(iparticleColor.asVector4f);
90 
91         float particleAlpha = 1.0f;
92         if (itransparency)
93             particleAlpha = itransparency.asFloat;
94 
95         setParameter("particleColor", particleColor);
96         setParameter("particleAlpha", particleAlpha);
97         if (ialphaCutout)
98             setParameter("alphaCutout", ialphaCutout.asBool);
99         else
100             setParameter("alphaCutout", false);
101         if (ialphaCutoutThreshold)
102             setParameter("alphaCutoutThreshold", ialphaCutoutThreshold.asFloat);
103         else
104             setParameter("alphaCutoutThreshold", 0.5f);
105         setParameter("particlePosition", state.modelViewMatrix.translation);
106 
107         // Sun
108         Vector3f sunDirection = Vector3f(0.0f, 0.0f, 1.0f);
109         Color4f sunColor = Color4f(1.0f, 1.0f, 1.0f, 1.0f);
110         float sunEnergy = 1.0f;
111         float sunScatteringG = 0.0f;
112         float sunScatteringDensity = 1.0f;
113         bool shaded = false;
114         bool scatteringEnabled = false;
115         if (state.material.sun)
116         {
117             auto sun = state.material.sun;
118             sunDirection = sun.directionAbsolute;
119             sunColor = sun.color;
120             sunEnergy = sun.energy;
121             sunScatteringG = 1.0f - sun.scattering;
122             sunScatteringDensity = sun.mediumDensity;
123             shaded = !ishadeless.asBool;
124             scatteringEnabled = sun.scatteringEnabled;
125         }
126         Vector4f sunDirHg = Vector4f(sunDirection);
127         sunDirHg.w = 0.0;
128         setParameter("sunDirection", (sunDirHg * state.viewMatrix).xyz);
129         setParameter("sunColor", sunColor);
130         setParameter("sunEnergy", sunEnergy);
131         setParameter("sunScatteringG", sunScatteringG);
132         setParameter("sunScatteringDensity", sunScatteringDensity);
133         setParameter("sunScattering", scatteringEnabled);
134         setParameter("shaded", shaded);
135 
136         // Texture 0 - diffuse texture
137         if (idiffuse.texture is null)
138         {
139             setParameter("diffuseVector", idiffuse.asVector4f);
140             setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorValue");
141         }
142         else
143         {
144             glActiveTexture(GL_TEXTURE0);
145             idiffuse.texture.bind();
146             setParameter("diffuseTexture", 0);
147             setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorTexture");
148         }
149 
150         // Texture 1 - depth texture (for soft particles)
151         glActiveTexture(GL_TEXTURE1);
152         glBindTexture(GL_TEXTURE_2D, state.depthTexture);
153         setParameter("depthTexture", 1);
154 
155         // Texture 2 - normal map
156         if (inormal.texture is null)
157         {
158             bool sphericalNormal = false;
159             if (iparticleSphericalNormal)
160                 sphericalNormal = iparticleSphericalNormal.asBool;
161             if (sphericalNormal)
162             {
163                 setParameterSubroutine("normal", ShaderType.Fragment, "normalFunctionHemisphere");
164             }
165             else
166             {
167                 Vector3f nVec = inormal.asVector3f;
168                 setParameter("normalVector", nVec);
169                 setParameterSubroutine("normal", ShaderType.Fragment, "normalValue");
170             }
171         }
172         else
173         {
174             glActiveTexture(GL_TEXTURE2);
175             inormal.texture.bind();
176             setParameter("normalTexture", 2);
177             setParameterSubroutine("normal", ShaderType.Fragment, "normalMap");
178         }
179 
180         // Texture 4 - environment
181         if (state.environment)
182         {
183             setParameter("fogColor", state.environment.fogColor);
184             setParameter("fogStart", state.environment.fogStart);
185             setParameter("fogEnd", state.environment.fogEnd);
186             setParameter("ambientEnergy", state.environment.ambientEnergy);
187 
188             if (state.environment.ambientMap)
189             {
190                 glActiveTexture(GL_TEXTURE4);
191                 state.environment.ambientMap.bind();
192                 if (cast(Cubemap)state.environment.ambientMap)
193                 {
194                     setParameter("ambientTextureCube", 4);
195                     setParameterSubroutine("ambient", ShaderType.Fragment, "ambientCubemap");
196                 }
197                 else
198                 {
199                     setParameter("ambientTexture", 4);
200                     setParameterSubroutine("ambient", ShaderType.Fragment, "ambientEquirectangularMap");
201                 }
202             }
203             else
204             {
205                 setParameter("ambientVector", state.environment.ambientColor);
206                 setParameterSubroutine("ambient", ShaderType.Fragment, "ambientColor");
207             }
208         }
209         else
210         {
211             setParameter("fogColor", Color4f(0.5f, 0.5f, 0.5f, 1.0f));
212             setParameter("fogStart", 0.0f);
213             setParameter("fogEnd", 1000.0f);
214             setParameter("ambientEnergy", 1.0f);
215             setParameter("ambientVector", Color4f(0.5f, 0.5f, 0.5f, 1.0f));
216             setParameterSubroutine("ambient", ShaderType.Fragment, "ambientColor");
217         }
218 
219         super.bindParameters(state);
220     }
221 
222     override void unbindParameters(GraphicsState* state)
223     {
224         super.unbindParameters(state);
225 
226         glActiveTexture(GL_TEXTURE0);
227         glBindTexture(GL_TEXTURE_2D, 0);
228 
229         glActiveTexture(GL_TEXTURE1);
230         glBindTexture(GL_TEXTURE_2D, 0);
231 
232         glActiveTexture(GL_TEXTURE2);
233         glBindTexture(GL_TEXTURE_2D, 0);
234 
235         glActiveTexture(GL_TEXTURE4);
236         glBindTexture(GL_TEXTURE_2D, 0);
237         glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
238 
239         glActiveTexture(GL_TEXTURE0);
240     }
241 }