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