1 /*
2 Copyright (c) 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.materials.particle;
29 
30 import std.stdio;
31 import std.math;
32 import std.conv;
33 
34 import dlib.core.memory;
35 import dlib.math.vector;
36 import dlib.math.matrix;
37 import dlib.image.color;
38 import dlib.image.unmanaged;
39 
40 import derelict.opengl;
41 
42 import dagon.core.ownership;
43 import dagon.graphics.rc;
44 import dagon.graphics.material;
45 import dagon.graphics.materials.generic;
46 
47 /*
48  * Backend for particle systems
49  */
50 
51 class ParticleBackend: GLSLMaterialBackend
52 {    
53     private string vsText = q{
54         #version 330 core
55         
56         layout (location = 0) in vec3 va_Vertex;
57         layout (location = 2) in vec2 va_Texcoord;
58         
59         out vec3 eyePosition;
60         out vec2 texCoord;
61         
62         uniform mat4 modelViewMatrix;
63         uniform mat4 projectionMatrix;
64         
65         uniform mat4 invViewMatrix;
66     
67         void main()
68         {
69             vec4 pos = modelViewMatrix * vec4(va_Vertex, 1.0);
70             eyePosition = pos.xyz;
71         
72             texCoord = va_Texcoord;
73             gl_Position = projectionMatrix * pos;
74         }
75     };
76     
77     private string fsText = q{
78         #version 330 core
79         
80         uniform sampler2D diffuseTexture;
81         uniform vec4 particleColor;
82         uniform float alpha;
83         uniform float energy;
84         
85         in vec3 eyePosition;
86         in vec2 texCoord;
87         
88         layout(location = 0) out vec4 frag_color;
89         layout(location = 1) out vec4 frag_velocity;
90         layout(location = 2) out vec4 frag_luma;
91         layout(location = 3) out vec4 frag_position;
92         
93         float luminance(vec3 color)
94         {
95             return (
96                 color.x * 0.27 +
97                 color.y * 0.67 +
98                 color.z * 0.06
99             );
100         }
101         
102         vec3 toLinear(vec3 v)
103         {
104             return pow(v, vec3(2.2));
105         }
106 
107         void main()
108         {
109             vec4 textureColor = texture(diffuseTexture, texCoord);
110             vec3 outColor = toLinear(textureColor.rgb) * toLinear(particleColor.rgb) * energy;
111             float outAlpha = textureColor.a * particleColor.a * alpha;
112             
113             frag_color = vec4(outColor, outAlpha);
114             frag_luma = vec4(energy * outAlpha, 0.0, 0.0, 1.0);
115             frag_velocity = vec4(0.0, 0.0, 0.0, 1.0);
116             frag_position = vec4(eyePosition, 0.0);
117         }
118     };
119     
120     override string vertexShaderSrc() {return vsText;}
121     override string fragmentShaderSrc() {return fsText;}
122 
123     GLint modelViewMatrixLoc;
124     GLint projectionMatrixLoc;
125     
126     GLint diffuseTextureLoc;
127     GLint alphaLoc;
128     GLint energyLoc;
129     GLint particleColorLoc;
130     
131     this(Owner o)
132     {
133         super(o);
134         
135         modelViewMatrixLoc = glGetUniformLocation(shaderProgram, "modelViewMatrix");
136         projectionMatrixLoc = glGetUniformLocation(shaderProgram, "projectionMatrix");
137             
138         diffuseTextureLoc = glGetUniformLocation(shaderProgram, "diffuseTexture");
139         alphaLoc = glGetUniformLocation(shaderProgram, "alpha");
140         energyLoc = glGetUniformLocation(shaderProgram, "energy");
141         particleColorLoc = glGetUniformLocation(shaderProgram, "particleColor");
142     }
143     
144     override void bind(GenericMaterial mat, RenderingContext* rc)
145     {
146         auto idiffuse = "diffuse" in mat.inputs;
147         auto ienergy = "energy" in mat.inputs;
148         auto itransparency = "transparency" in mat.inputs;
149         auto iparticleColor = "particleColor" in mat.inputs;
150         
151         float energy = ienergy.asFloat;
152 
153         glUseProgram(shaderProgram);
154         
155         // Matrices
156         glUniformMatrix4fv(modelViewMatrixLoc, 1, GL_FALSE, rc.modelViewMatrix.arrayof.ptr);
157         glUniformMatrix4fv(projectionMatrixLoc, 1, GL_FALSE, rc.projectionMatrix.arrayof.ptr);
158 
159         // Texture 0 - diffuse texture
160         Color4f particleColor = Color4f(1.0f, 1.0f, 1.0f, 1.0f);
161         Color4f color = Color4f(idiffuse.asVector4f);
162         float alpha = 1.0f;
163         
164         if (idiffuse.texture is null)
165         {
166             idiffuse.texture = makeOnePixelTexture(mat, color);
167         }
168         
169         if (itransparency)
170         {
171             alpha = itransparency.asFloat;
172         }
173         
174         if (iparticleColor)
175         {
176             particleColor = Color4f(iparticleColor.asVector4f);
177         }
178         
179         glActiveTexture(GL_TEXTURE0);
180         idiffuse.texture.bind();
181         glUniform1i(diffuseTextureLoc, 0);
182         glUniform1f(alphaLoc, alpha);
183         glUniform1f(energyLoc, energy);
184         glUniform4fv(particleColorLoc, 1, particleColor.arrayof.ptr);
185     }
186     
187     override void unbind(GenericMaterial mat, RenderingContext* rc)
188     {
189         auto idiffuse = "diffuse" in mat.inputs;
190         
191         glActiveTexture(GL_TEXTURE0);
192         idiffuse.texture.unbind();
193     
194         glUseProgram(0);
195     }
196 }