1 /*
2 Copyright (c) 2018-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.special.water;
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.texture;
45 import dagon.graphics.shader;
46 import dagon.graphics.state;
47 import dagon.graphics.cubemap;
48 import dagon.graphics.csm;
49 import dagon.render.gbuffer;
50 import dagon.resource.asset;
51 import dagon.resource.texture;
52 
53 // TODO: move to dlib.math.utils
54 real frac(real v)
55 {
56     real intpart;
57     return modf(v, intpart);
58 }
59 
60 class WaterShader: Shader
61 {
62     String vs, fs;
63 
64     GBuffer gbuffer;
65     Texture rippleTexture;
66     Texture normalTexture1;
67     Texture normalTexture2;
68 
69     Matrix4x4f defaultShadowMatrix;
70     GLuint defaultShadowTexture;
71 
72     Color4f waterColor = Color4f(0.02f, 0.02f, 0.08f, 0.9f);
73     float rainIntensity = 0.1f;
74     float flowSpeed = 0.08f;
75     float waveAmplitude = 0.3f;
76 
77     this(GBuffer gbuffer, AssetManager assetManager, Owner owner)
78     {
79         vs = Shader.load("data/__internal/shaders/Water/Water.vert.glsl");
80         fs = Shader.load("data/__internal/shaders/Water/Water.frag.glsl");
81 
82         auto prog = New!ShaderProgram(vs, fs, this);
83         super(prog, owner);
84 
85         this.gbuffer = gbuffer;
86 
87         TextureAsset rippleTextureAsset = textureAsset(assetManager, "data/__internal/textures/ripples.png");
88         rippleTexture = rippleTextureAsset.texture;
89 
90         TextureAsset normalTexture1Asset = textureAsset(assetManager, "data/__internal/textures/water_normal1.png");
91         normalTexture1 = normalTexture1Asset.texture;
92 
93         TextureAsset normalTexture2Asset = textureAsset(assetManager, "data/__internal/textures/water_normal2.png");
94         normalTexture2 = normalTexture2Asset.texture;
95 
96         defaultShadowMatrix = Matrix4x4f.identity;
97 
98         glGenTextures(1, &defaultShadowTexture);
99         glActiveTexture(GL_TEXTURE0);
100         glBindTexture(GL_TEXTURE_2D_ARRAY, defaultShadowTexture);
101         glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT24, 1, 1, 3, 0, GL_DEPTH_COMPONENT, GL_FLOAT, null);
102         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
103         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
104         glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
105     }
106 
107     ~this()
108     {
109         if (glIsFramebuffer(defaultShadowTexture))
110             glDeleteFramebuffers(1, &defaultShadowTexture);
111 
112         vs.free();
113         fs.free();
114     }
115 
116     override void bindParameters(GraphicsState* state)
117     {
118         auto itextureScale = "textureScale" in state.material.inputs;
119         auto ishadeless = "shadeless" in state.material.inputs;
120 
121         setParameter("modelViewMatrix", state.modelViewMatrix);
122         setParameter("projectionMatrix", state.projectionMatrix);
123         setParameter("invProjectionMatrix", state.invProjectionMatrix);
124         setParameter("normalMatrix", state.normalMatrix);
125         setParameter("viewMatrix", state.viewMatrix);
126         setParameter("invViewMatrix", state.invViewMatrix);
127         setParameter("prevModelViewMatrix", state.prevModelViewMatrix);
128 
129         setParameter("textureScale", itextureScale.asVector2f);
130 
131         setParameter("viewSize", state.resolution);
132 
133         // Water props
134         setParameter("waterColor", waterColor);
135         setParameter("rainIntensity", rainIntensity);
136         setParameter("flowSpeed", flowSpeed);
137         setParameter("waveAmplitude", waveAmplitude);
138 
139         // Sun
140         Vector3f sunDirection = Vector3f(0.0f, 0.0f, 1.0f);
141         Color4f sunColor = Color4f(1.0f, 1.0f, 1.0f, 1.0f);
142         float sunEnergy = 1.0f;
143         bool sunScatteringEnabled = false;
144         float sunScatteringG = 0.0f;
145         float sunScatteringDensity = 1.0f;
146         int sunScatteringSamples = 1;
147         float sunScatteringMaxRandomStepOffset = 0.0f;
148         bool shaded = !ishadeless.asBool;
149         if (state.material.sun)
150         {
151             auto sun = state.material.sun;
152             sunDirection = sun.directionAbsolute;
153             sunColor = sun.color;
154             sunEnergy = sun.energy;
155             sunScatteringG = 1.0f - sun.scattering;
156             sunScatteringDensity = sun.mediumDensity;
157             sunScatteringEnabled = sun.scatteringEnabled;
158         }
159         Vector4f sunDirHg = Vector4f(sunDirection);
160         sunDirHg.w = 0.0;
161         setParameter("sunDirection", (sunDirHg * state.viewMatrix).xyz);
162         setParameter("sunColor", sunColor);
163         setParameter("sunEnergy", sunEnergy);
164         setParameter("sunScatteringG", sunScatteringG);
165         setParameter("sunScatteringDensity", sunScatteringDensity);
166         setParameter("sunScattering", sunScatteringEnabled);
167         setParameter("sunScatteringSamples", sunScatteringSamples);
168         setParameter("sunScatteringMaxRandomStepOffset", sunScatteringMaxRandomStepOffset);
169         setParameter("shaded", shaded);
170 
171         // Texture 0 - depth texture (for smooth coast transparency)
172         glActiveTexture(GL_TEXTURE0);
173         glBindTexture(GL_TEXTURE_2D, gbuffer.depthTexture);
174         setParameter("depthBuffer", 0);
175 
176         // Ripple parameters
177         glActiveTexture(GL_TEXTURE1);
178         rippleTexture.bind();
179         setParameter("rippleTexture", 1);
180 
181         float rippleTimesX = frac((state.time.elapsed) * 1.6);
182         float rippleTimesY = frac((state.time.elapsed * 0.85 + 0.2) * 1.6);
183         float rippleTimesZ = frac((state.time.elapsed * 0.93 + 0.45) * 1.6);
184         float rippleTimesW = frac((state.time.elapsed * 1.13 + 0.7) * 1.6);
185         setParameter("rippleTimes", Vector4f(rippleTimesX, rippleTimesY, rippleTimesZ, rippleTimesW));
186 
187         // Environment
188         if (state.environment)
189         {
190             setParameter("fogColor", state.environment.fogColor);
191             setParameter("fogStart", state.environment.fogStart);
192             setParameter("fogEnd", state.environment.fogEnd);
193             setParameter("ambientEnergy", state.environment.ambientEnergy);
194 
195             if (state.environment.ambientMap)
196             {
197                 glActiveTexture(GL_TEXTURE2);
198                 state.environment.ambientMap.bind();
199                 if (cast(Cubemap)state.environment.ambientMap)
200                 {
201                     setParameter("ambientTextureCube", 2);
202                     setParameterSubroutine("ambient", ShaderType.Fragment, "ambientCubemap");
203                 }
204                 else
205                 {
206                     setParameter("ambientTexture", 2);
207                     setParameterSubroutine("ambient", ShaderType.Fragment, "ambientEquirectangularMap");
208                 }
209             }
210             else
211             {
212                 setParameter("ambientVector", state.environment.ambientColor);
213                 setParameterSubroutine("ambient", ShaderType.Fragment, "ambientColor");
214             }
215         }
216         else
217         {
218             setParameter("fogColor", Color4f(0.5f, 0.5f, 0.5f, 1.0f));
219             setParameter("fogStart", 0.0f);
220             setParameter("fogEnd", 1000.0f);
221             setParameter("ambientEnergy", 1.0f);
222             setParameter("ambientVector", Color4f(0.5f, 0.5f, 0.5f, 1.0f));
223             setParameterSubroutine("ambient", ShaderType.Fragment, "ambientColor");
224         }
225 
226         // Shadow map
227         if (state.material.sun)
228         {
229             if (state.material.sun.shadowEnabled)
230             {
231                 CascadedShadowMap csm = cast(CascadedShadowMap)state.material.sun.shadowMap;
232 
233                 glActiveTexture(GL_TEXTURE3);
234                 glBindTexture(GL_TEXTURE_2D_ARRAY, csm.depthTexture);
235                 setParameter("shadowTextureArray", 3);
236                 setParameter("shadowResolution", cast(float)csm.resolution);
237                 setParameter("shadowMatrix1", csm.area[0].shadowMatrix);
238                 setParameter("shadowMatrix2", csm.area[1].shadowMatrix);
239                 setParameter("shadowMatrix3", csm.area[2].shadowMatrix);
240                 setParameterSubroutine("shadowMap", ShaderType.Fragment, "shadowMapCascaded");
241             }
242             else
243             {
244                 glActiveTexture(GL_TEXTURE3);
245                 glBindTexture(GL_TEXTURE_2D_ARRAY, defaultShadowTexture);
246                 setParameter("shadowTextureArray", 3);
247                 setParameter("shadowMatrix1", defaultShadowMatrix);
248                 setParameter("shadowMatrix2", defaultShadowMatrix);
249                 setParameter("shadowMatrix3", defaultShadowMatrix);
250                 setParameterSubroutine("shadowMap", ShaderType.Fragment, "shadowMapNone");
251             }
252         }
253         else
254         {
255             glActiveTexture(GL_TEXTURE3);
256             glBindTexture(GL_TEXTURE_2D_ARRAY, defaultShadowTexture);
257             setParameter("shadowTextureArray", 3);
258             setParameter("shadowMatrix1", defaultShadowMatrix);
259             setParameter("shadowMatrix2", defaultShadowMatrix);
260             setParameter("shadowMatrix3", defaultShadowMatrix);
261             setParameterSubroutine("shadowMap", ShaderType.Fragment, "shadowMapNone");
262         }
263 
264         // Normal maps
265         glActiveTexture(GL_TEXTURE4);
266         normalTexture1.bind();
267         setParameter("normalTexture1", 4);
268 
269         glActiveTexture(GL_TEXTURE5);
270         normalTexture2.bind();
271         setParameter("normalTexture2", 5);
272 
273         setParameter("time", cast(float)state.time.elapsed);
274 
275         super.bindParameters(state);
276     }
277 
278     override void unbindParameters(GraphicsState* state)
279     {
280         super.unbindParameters(state);
281 
282         glActiveTexture(GL_TEXTURE0);
283         glBindTexture(GL_TEXTURE_2D, 0);
284 
285         glActiveTexture(GL_TEXTURE1);
286         glBindTexture(GL_TEXTURE_2D, 0);
287 
288         glActiveTexture(GL_TEXTURE2);
289         glBindTexture(GL_TEXTURE_2D, 0);
290         glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
291 
292         glActiveTexture(GL_TEXTURE3);
293         glBindTexture(GL_TEXTURE_2D, 0);
294 
295         glActiveTexture(GL_TEXTURE4);
296         glBindTexture(GL_TEXTURE_2D, 0);
297 
298         glActiveTexture(GL_TEXTURE5);
299         glBindTexture(GL_TEXTURE_2D, 0);
300 
301         glActiveTexture(GL_TEXTURE0);
302     }
303 }