1 /*
2  Copyright (c) 2013 yvt
3 
4  This file is part of OpenSpades.
5 
6  OpenSpades is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  OpenSpades is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with OpenSpades.  If not, see <http://www.gnu.org/licenses/>.
18 
19  */
20 
21 #include <cstdlib>
22 #include <vector>
23 
24 #include <kiss_fft130/kiss_fft.h>
25 
26 #include <Client/GameMap.h>
27 #include <Core/ConcurrentDispatch.h>
28 #include <Core/Debug.h>
29 #include <Core/Settings.h>
30 #include "GLFramebufferManager.h"
31 #include "GLImage.h"
32 #include "GLProfiler.h"
33 #include "GLProgram.h"
34 #include "GLProgramAttribute.h"
35 #include "GLProgramUniform.h"
36 #include "GLRenderer.h"
37 #include "GLShadowShader.h"
38 #include "GLWaterRenderer.h"
39 #include "IGLDevice.h"
40 
41 namespace spades {
42 	namespace draw {
43 
44 #pragma mark - Wave Tank Simulation
45 
46 		class GLWaterRenderer::IWaveTank : public ConcurrentDispatch {
47 		protected:
48 			float dt;
49 			int size, samples;
50 
51 		private:
52 			uint32_t *bitmap;
53 
Encode8bit(float v)54 			int Encode8bit(float v) {
55 				v = (v + 1.f) * .5f * 255.f;
56 				v = floorf(v + .5f);
57 
58 				int i = (int)v;
59 				if (i < 0)
60 					i = 0;
61 				if (i > 255)
62 					i = 255;
63 				return i;
64 			}
65 
MakeBitmapPixel(float dx,float dy,float h)66 			uint32_t MakeBitmapPixel(float dx, float dy, float h) {
67 				float x = dx, y = dy, z = 0.04f;
68 				float scale = 200.f;
69 				x *= scale;
70 				y *= scale;
71 				z *= scale;
72 
73 				uint32_t out;
74 				out = Encode8bit(z);
75 				out |= Encode8bit(y) << 8;
76 				out |= Encode8bit(x) << 16;
77 				out |= Encode8bit(h * -10.f) << 24;
78 				return out;
79 			}
80 
MakeBitmapRow(float * h1,float * h2,float * h3,uint32_t * out)81 			void MakeBitmapRow(float *h1, float *h2, float *h3, uint32_t *out) {
82 				out[0] = MakeBitmapPixel(h2[1] - h2[size - 1], h3[0] - h1[0], h2[0]);
83 				out[size - 1] =
84 				  MakeBitmapPixel(h2[0] - h2[size - 2], h3[size - 1] - h1[size - 1], h2[size - 1]);
85 				for (int x = 1; x < size - 1; x++) {
86 					out[x] = MakeBitmapPixel(h2[x + 1] - h2[x - 1], h3[x] - h1[x], h2[x]);
87 				}
88 			}
89 
90 		public:
IWaveTank(int size)91 			IWaveTank(int size) : size(size) {
92 
93 				bitmap = new uint32_t[size * size];
94 
95 				samples = size * size;
96 			}
~IWaveTank()97 			virtual ~IWaveTank() { delete[] bitmap; }
SetTimeStep(float dt)98 			void SetTimeStep(float dt) { this->dt = dt; }
99 
GetSize() const100 			int GetSize() const { return size; }
101 
GetBitmap() const102 			uint32_t *GetBitmap() const { return bitmap; }
103 
MakeBitmap(float * height)104 			void MakeBitmap(float *height) {
105 				MakeBitmapRow(height + (size - 1) * size, height, height + size, bitmap);
106 				MakeBitmapRow(height + (size - 2) * size, height + (size - 1) * size, height,
107 				              bitmap + (size - 1) * size);
108 				for (int y = 1; y < size - 1; y++) {
109 					MakeBitmapRow(height + (y - 1) * size, height + y * size,
110 					              height + (y + 1) * size, bitmap + y * size);
111 				}
112 			}
113 		};
114 
115 #pragma mark - FFT Wave Solver
116 
117 		struct SinCosTable {
118 			float sinCoarse[256];
119 			float cosCoarse[256];
120 			float sinFine[256];
121 			float cosFine[256];
122 
123 		public:
SinCosTablespades::draw::SinCosTable124 			SinCosTable() {
125 				for (int i = 0; i < 256; i++) {
126 					float ang = (float)i / 256.f * (float)M_PI * 2.f;
127 					sinCoarse[i] = sinf(ang);
128 					cosCoarse[i] = cosf(ang);
129 
130 					ang = (float)i / 65536.f * (float)M_PI * 2.f;
131 					sinFine[i] = sinf(ang);
132 					cosFine[i] = cosf(ang);
133 				}
134 			}
135 
Computespades::draw::SinCosTable136 			void Compute(unsigned int step, float &outSin, float &outCos) {
137 				step &= 0xffff;
138 				if (step == 0) {
139 					outSin = 0;
140 					outCos = 1.f;
141 					return;
142 				}
143 
144 				int fine = step & 0xff;
145 				int coarse = step >> 8;
146 
147 				outSin = sinCoarse[coarse];
148 				outCos = cosCoarse[coarse];
149 
150 				if (fine != 0) {
151 					float c = cosFine[fine];
152 					float s = sinFine[fine];
153 					float c2 = outCos * c - outSin * s;
154 					float s2 = outCos * s + outSin * c;
155 					outCos = c2;
156 					outSin = s2;
157 				}
158 			}
159 		};
160 
161 		static SinCosTable sinCosTable;
162 
163 		template <int SizeBits> class GLWaterRenderer::FFTWaveTank : public IWaveTank {
164 			enum { Size = 1 << SizeBits, SizeHalf = Size / 2 };
165 			kiss_fft_cfg fft;
166 
167 			typedef kiss_fft_cpx Complex;
168 
169 			struct Cell {
170 				float magnitude;
171 				uint32_t phase;
172 				float phasePerSecond;
173 
174 				float m00, m01;
175 				float m10, m11;
176 			};
177 
178 			Cell cells[SizeHalf + 1][Size];
179 
180 			Complex spectrum[SizeHalf + 1][Size];
181 
182 			Complex temp1[Size];
183 			Complex temp2[Size];
184 			Complex temp3[Size][Size];
185 
186 			float height[Size][Size];
187 
188 		public:
FFTWaveTank()189 			FFTWaveTank() : IWaveTank(Size) {
190 				auto *getRandom = SampleRandomFloat;
191 
192 				fft = kiss_fft_alloc(Size, 1, NULL, NULL);
193 
194 				for (int x = 0; x < Size; x++) {
195 					for (int y = 0; y <= SizeHalf; y++) {
196 						Cell &cell = cells[y][x];
197 						if (x == 0 && y == 0) {
198 							cell.magnitude = 0;
199 							cell.phasePerSecond = 0.f;
200 							cell.phase = 0;
201 						} else {
202 							int cx = std::min(x, Size - x);
203 							float dist = (float)sqrtf(cx * cx + y * y);
204 							float mag = 0.8f / dist / (float)Size;
205 							mag /= dist;
206 
207 							float scal = dist / (float)SizeHalf;
208 							scal *= scal;
209 							mag *= expf(-scal * 3.f);
210 
211 							cell.magnitude = mag;
212 							cell.phase = static_cast<uint32_t>(SampleRandom());
213 							cell.phasePerSecond = dist * 1.e+9f * 128 / Size;
214 						}
215 
216 						cell.m00 = getRandom() - getRandom();
217 						cell.m01 = getRandom() - getRandom();
218 						cell.m10 = getRandom() - getRandom();
219 						cell.m11 = getRandom() - getRandom();
220 					}
221 				}
222 			}
~FFTWaveTank()223 			~FFTWaveTank() { kiss_fft_free(fft); }
224 
Run()225 			void Run() override {
226 				// advance cells
227 				for (int x = 0; x < Size; x++) {
228 					for (int y = 0; y <= SizeHalf; y++) {
229 						Cell &cell = cells[y][x];
230 						uint32_t dphase;
231 						dphase = (uint32_t)(cell.phasePerSecond * dt);
232 						cell.phase += dphase;
233 
234 						unsigned int phase = cell.phase >> 16;
235 						float c, s;
236 						sinCosTable.Compute(phase, s, c);
237 
238 						float u, v;
239 						u = c * cell.m00 + s * cell.m01;
240 						v = c * cell.m10 + s * cell.m11;
241 
242 						spectrum[y][x].r = u * cell.magnitude;
243 						spectrum[y][x].i = v * cell.magnitude;
244 					}
245 				}
246 
247 				// rfft
248 				for (int y = 0; y <= SizeHalf; y++) {
249 					for (int x = 0; x < Size; x++)
250 						temp1[x] = spectrum[y][x];
251 
252 					kiss_fft(fft, temp1, temp2);
253 
254 					if (y == 0) {
255 						for (int x = 0; x < Size; x++) {
256 							temp3[x][0] = temp2[x];
257 						}
258 					} else if (y == SizeHalf) {
259 						for (int x = 0; x < Size; x++) {
260 							temp3[x][SizeHalf].r = temp2[x].r;
261 							temp3[x][SizeHalf].i = 0.f;
262 						}
263 					} else {
264 						for (int x = 0; x < Size; x++) {
265 							temp3[x][y] = temp2[x];
266 							temp3[x][Size - y].r = temp2[x].r;
267 							temp3[x][Size - y].i = -temp2[x].i;
268 						}
269 					}
270 				}
271 				for (int x = 0; x < Size; x++) {
272 					kiss_fft(fft, temp3[x], temp2);
273 					for (int y = 0; y < Size; y++) {
274 						height[x][y] = temp2[y].r;
275 					}
276 				}
277 
278 				MakeBitmap((float *)height);
279 			}
280 		};
281 
282 #pragma mark - FTCS PDE Solver
283 
284 		class GLWaterRenderer::StandardWaveTank : public IWaveTank {
285 			float *height;
286 			float *heightFiltered;
287 			float *velocity;
288 
DoPDELine(float * vy,float * y1,float * y2,float * yy)289 			template <bool xy> void DoPDELine(float *vy, float *y1, float *y2, float *yy) {
290 				int pitch = xy ? size : 1;
291 				for (int i = 0; i < size; i++) {
292 					float v1 = *y1, v2 = *y2, v = *yy;
293 					float force = v1 + v2 - (v + v);
294 					force *= dt * 80.f;
295 					*vy += force;
296 
297 					y1 += pitch;
298 					y2 += pitch;
299 					yy += pitch;
300 					vy += pitch;
301 				}
302 			}
303 
Denoise(float * arr)304 			template <bool xy> void Denoise(float *arr) {
305 				int pitch = xy ? size : 1;
306 #if 1
307 				if ((arr[0] > 0.f && arr[(size - 1) * pitch] < 0.f && arr[pitch] < 0.f) ||
308 				    (arr[0] < 0.f && arr[(size - 1) * pitch] > 0.f && arr[pitch] > 0.f)) {
309 					float ttl = (arr[1] + arr[(size - 1) * pitch]) * .5f;
310 					arr[0] = ttl;
311 				}
312 				if ((arr[(size - 1) * pitch] > 0.f && arr[(size - 2) * pitch] < 0.f &&
313 				     arr[0] < 0.f) ||
314 				    (arr[(size - 1) * pitch] < 0.f && arr[(size - 2) * pitch] > 0.f &&
315 				     arr[0] > 0.f)) {
316 					float ttl = (arr[0] + arr[(size - 2) * pitch]) * .5f;
317 					arr[(size - 1) * pitch] = ttl;
318 				}
319 				for (int i = 1; i < size - 1; i++) {
320 					if ((arr[i * pitch] > 0.f && arr[(i - 1) * pitch] < 0.f &&
321 					     arr[(i + 1) * pitch] < 0.f) ||
322 					    (arr[i * pitch] < 0.f && arr[(i - 1) * pitch] > 0.f &&
323 					     arr[(i + 1) * pitch] > 0.f)) {
324 						float ttl = (arr[(i + 1) * pitch] + arr[(i - 1) * pitch]) * .5f;
325 						arr[i * pitch] = ttl;
326 					}
327 				}
328 #else
329 				// Lax-Friedrich
330 				float buf[256]; // TODO: variable size
331 				SPAssert(size <= 256);
332 				for (int i = 0; i < size; i++)
333 					buf[i] = arr[i * pitch] * .5f;
334 
335 				arr[0] = buf[1] + buf[size - 1];
336 				arr[(size - 1) * pitch] = buf[size - 2] + buf[0];
337 
338 				for (int i = 1; i < size - 1; i++)
339 					arr[i * pitch] = buf[i - 1] + buf[i + 1];
340 
341 #endif
342 			}
343 
344 		public:
StandardWaveTank(int size)345 			StandardWaveTank(int size) : IWaveTank(size) {
346 				height = new float[size * size];
347 				heightFiltered = new float[size * size];
348 				velocity = new float[size * size];
349 				std::fill(height, height + size * size, 0.f);
350 				std::fill(velocity, velocity + size * size, 0.f);
351 			}
352 
~StandardWaveTank()353 			~StandardWaveTank() {
354 
355 				delete[] height;
356 				delete[] heightFiltered;
357 				delete[] velocity;
358 			}
359 
Run()360 			void Run() override {
361 				// advance time
362 				for (int i = 0; i < samples; i++)
363 					height[i] += velocity[i] * dt;
364 #ifndef NDEBUG
365 				for (int i = 0; i < samples; i++)
366 					SPAssert(!std::isnan(height[i]));
367 				for (int i = 0; i < samples; i++)
368 					SPAssert(!std::isnan(velocity[i]));
369 #endif
370 
371 				// solve ddz/dtt = c^2 (ddz/dxx + ddz/dyy)
372 
373 				// do ddz/dyy
374 				DoPDELine<false>(velocity, height + (size - 1) * size, height + size, height);
375 				DoPDELine<false>(velocity + (size - 1) * size, height + (size - 2) * size, height,
376 				                 height + (size - 1) * size);
377 				for (int y = 1; y < size - 1; y++) {
378 					DoPDELine<false>(velocity + y * size, height + (y - 1) * size,
379 					                 height + (y + 1) * size, height + y * size);
380 				}
381 
382 				// do ddz/dxx
383 				DoPDELine<true>(velocity, height + (size - 1), height + 1, height);
384 				DoPDELine<true>(velocity + (size - 1), height + (size - 2), height,
385 				                height + (size - 1));
386 				for (int x = 1; x < size - 1; x++) {
387 					DoPDELine<true>(velocity + x, height + (x - 1), height + (x + 1), height + x);
388 				}
389 
390 				// make average 0
391 				float sum = 0.f;
392 				for (int i = 0; i < samples; i++)
393 					sum += height[i];
394 				sum /= (float)samples;
395 				for (int i = 0; i < samples; i++)
396 					height[i] -= sum;
397 
398 				// limit energy
399 				sum = 0.f;
400 				for (int i = 0; i < samples; i++) {
401 					sum += height[i] * height[i];
402 					sum += velocity[i] * velocity[i];
403 				}
404 				sum = sqrtf(sum / (float)samples / 2.f) * 80.f;
405 				if (sum > 1.f) {
406 					sum = 1.f / sum;
407 					for (int i = 0; i < samples; i++) {
408 						height[i] *= sum;
409 						velocity[i] *= sum;
410 					}
411 				}
412 
413 				// denoise
414 				for (int i = 0; i < size; i++) {
415 					Denoise<true>(height + i);
416 				}
417 				for (int i = 0; i < size; i++) {
418 					Denoise<false>(height + i * size);
419 				}
420 
421 				// add randomness
422 				int count = (int)floorf(dt * 600.f);
423 				if (count > 400)
424 					count = 400;
425 
426 				for (int i = 0; i < count; i++) {
427 					int ox = SampleRandomInt(0, size - 3);
428 					int oy = SampleRandomInt(0, size - 3);
429 					static const float gauss[] = {0.225610111284052f, 0.548779777431897f,
430 					                              0.225610111284052f};
431 					float strength = (SampleRandomFloat() - SampleRandomFloat()) * 0.15f * 100.f;
432 					for (int x = 0; x < 3; x++)
433 						for (int y = 0; y < 3; y++) {
434 							velocity[(x + ox) + (y + oy) * size] += strength * gauss[x] * gauss[y];
435 						}
436 				}
437 
438 				for (int i = 0; i < samples; i++)
439 					heightFiltered[i] = height[i]; // * height[i] * 100.f;
440 
441 				// build bitmap
442 				MakeBitmap(heightFiltered);
443 			}
444 		};
445 
446 #pragma mark - Water Renderer
447 
PreloadShaders(spades::draw::GLRenderer * renderer)448 		void GLWaterRenderer::PreloadShaders(spades::draw::GLRenderer *renderer) {
449 			auto &settings = renderer->GetSettings();
450 			if ((int)settings.r_water >= 3)
451 				renderer->RegisterProgram("Shaders/Water3.program");
452 			else if ((int)settings.r_water >= 2)
453 				renderer->RegisterProgram("Shaders/Water2.program");
454 			else
455 				renderer->RegisterProgram("Shaders/Water.program");
456 		}
457 
GLWaterRenderer(GLRenderer * renderer,client::GameMap * map)458 		GLWaterRenderer::GLWaterRenderer(GLRenderer *renderer, client::GameMap *map)
459 		    : renderer(renderer),
460 		      device(renderer->GetGLDevice()),
461 		      settings(renderer->GetSettings()),
462 		      map(map) {
463 			SPADES_MARK_FUNCTION();
464 			if ((int)settings.r_water >= 3)
465 				program = renderer->RegisterProgram("Shaders/Water3.program");
466 			else if ((int)settings.r_water >= 2)
467 				program = renderer->RegisterProgram("Shaders/Water2.program");
468 			else
469 				program = renderer->RegisterProgram("Shaders/Water.program");
470 			BuildVertices();
471 
472 			tempDepthTexture = device->GenTexture();
473 			device->BindTexture(IGLDevice::Texture2D, tempDepthTexture);
474 			device->TexImage2D(IGLDevice::Texture2D, 0, IGLDevice::DepthComponent24,
475 			                   device->ScreenWidth(), device->ScreenHeight(), 0,
476 			                   IGLDevice::DepthComponent, IGLDevice::UnsignedInt, NULL);
477 			device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMagFilter,
478 			                     IGLDevice::Nearest);
479 			device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMinFilter,
480 			                     IGLDevice::Nearest);
481 			device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureWrapS,
482 			                     IGLDevice::ClampToEdge);
483 			device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureWrapT,
484 			                     IGLDevice::ClampToEdge);
485 
486 			tempFramebuffer = device->GenFramebuffer();
487 			device->BindFramebuffer(IGLDevice::Framebuffer, tempFramebuffer);
488 			device->FramebufferTexture2D(IGLDevice::Framebuffer, IGLDevice::DepthAttachment,
489 			                             IGLDevice::Texture2D, tempDepthTexture, 0);
490 
491 			// create water color texture
492 			texture = device->GenTexture();
493 			device->BindTexture(IGLDevice::Texture2D, texture);
494 			device->TexImage2D(IGLDevice::Texture2D, 0, IGLDevice::RGBA8, map->Width(),
495 			                   map->Height(), 0, IGLDevice::RGBA, IGLDevice::UnsignedByte, NULL);
496 			device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMagFilter,
497 			                     IGLDevice::Linear);
498 			device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMinFilter,
499 			                     IGLDevice::Linear);
500 			device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureWrapS, IGLDevice::Repeat);
501 			device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureWrapT, IGLDevice::Repeat);
502 
503 			w = map->Width();
504 			h = map->Height();
505 
506 			updateBitmapPitch = (w + 31) / 32;
507 			updateBitmap.resize(updateBitmapPitch * h);
508 
509 			bitmap.resize(w * h);
510 			std::fill(updateBitmap.begin(), updateBitmap.end(), 0xffffffffUL);
511 			std::fill(bitmap.begin(), bitmap.end(), 0xffffffffUL);
512 
513 			device->TexSubImage2D(IGLDevice::Texture2D, 0, 0, 0, w, h, IGLDevice::BGRA,
514 			                      IGLDevice::UnsignedByte, bitmap.data());
515 
516 
517 			size_t numLayers = ((int)settings.r_water >= 2) ? 3 : 1;
518 
519 
520 			// create wave tank simlation
521 			for (size_t i = 0; i < numLayers; i++) {
522 				if ((int)settings.r_water >= 3) {
523 					waveTanks.push_back(new FFTWaveTank<8>());
524 				} else {
525 					waveTanks.push_back(new FFTWaveTank<7>());
526 				}
527 			}
528 
529 			// create heightmap texture
530 			waveTexture = device->GenTexture();
531 			if (numLayers == 1) {
532 				device->BindTexture(IGLDevice::Texture2D, waveTexture);
533 				device->TexImage2D(IGLDevice::Texture2D, 0, IGLDevice::RGBA8,
534 				                   waveTanks[0]->GetSize(), waveTanks[0]->GetSize(), 0,
535 				                   IGLDevice::BGRA, IGLDevice::UnsignedByte, NULL);
536 				device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMagFilter,
537 				                     IGLDevice::Linear);
538 				device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMinFilter,
539 				                     IGLDevice::LinearMipmapLinear);
540 				device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureWrapS,
541 				                     IGLDevice::Repeat);
542 				device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureWrapT,
543 				                     IGLDevice::Repeat);
544 				if (settings.r_maxAnisotropy > 1.0f) {
545 					device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMaxAnisotropy,
546 					                     (float)settings.r_maxAnisotropy);
547 				}
548 			} else {
549 				device->BindTexture(IGLDevice::Texture2DArray, waveTexture);
550 				device->TexImage3D(IGLDevice::Texture2DArray, 0, IGLDevice::RGBA8,
551 				                   waveTanks[0]->GetSize(), waveTanks[0]->GetSize(), static_cast<IGLDevice::Sizei>(numLayers), 0,
552 				                   IGLDevice::BGRA, IGLDevice::UnsignedByte, NULL);
553 				device->TexParamater(IGLDevice::Texture2DArray, IGLDevice::TextureMagFilter,
554 				                     IGLDevice::Linear);
555 				device->TexParamater(IGLDevice::Texture2DArray, IGLDevice::TextureMinFilter,
556 				                     IGLDevice::LinearMipmapLinear);
557 				device->TexParamater(IGLDevice::Texture2DArray, IGLDevice::TextureWrapS,
558 				                     IGLDevice::Repeat);
559 				device->TexParamater(IGLDevice::Texture2DArray, IGLDevice::TextureWrapT,
560 				                     IGLDevice::Repeat);
561 				if (settings.r_maxAnisotropy > 1.0f) {
562 					device->TexParamater(IGLDevice::Texture2DArray, IGLDevice::TextureMaxAnisotropy,
563 					                     (float)settings.r_maxAnisotropy);
564 				}
565 			}
566 
567 			occlusionQuery = 0;
568 		}
569 
570 		struct GLWaterRenderer::Vertex {
571 			float x, y;
572 		};
573 
BuildVertices()574 		void GLWaterRenderer::BuildVertices() {
575 			SPADES_MARK_FUNCTION();
576 			std::vector<Vertex> vertices;
577 			std::vector<uint32_t> indices;
578 
579 			int meshSize = 16;
580 			if ((int)settings.r_water >= 2)
581 				meshSize = 128;
582 			float meshSizeInv = 1.f / (float)meshSize;
583 			for (int y = -meshSize; y <= meshSize; y++) {
584 				for (int x = -meshSize; x <= meshSize; x++) {
585 					Vertex v;
586 					v.x = (float)(x)*meshSizeInv;
587 					v.y = (float)(y)*meshSizeInv;
588 
589 					// higher density near the camera
590 					v.x *= v.x * v.x;
591 					v.y *= v.y * v.y;
592 
593 					vertices.push_back(v);
594 				}
595 			}
596 #define VID(x, y) (((x) + meshSize) + ((y) + meshSize) * (meshSize * 2 + 1))
597 			for (int x = -meshSize; x < meshSize; x++) {
598 				for (int y = -meshSize; y < meshSize; y++) {
599 					indices.push_back(VID(x, y));
600 					indices.push_back(VID(x + 1, y));
601 					indices.push_back(VID(x, y + 1));
602 
603 					indices.push_back(VID(x + 1, y));
604 					indices.push_back(VID(x + 1, y + 1));
605 					indices.push_back(VID(x, y + 1));
606 				}
607 			}
608 
609 			buffer = device->GenBuffer();
610 			device->BindBuffer(IGLDevice::ArrayBuffer, buffer);
611 			device->BufferData(IGLDevice::ArrayBuffer,
612 			                   static_cast<IGLDevice::Sizei>(sizeof(Vertex) * vertices.size()),
613 			                   vertices.data(), IGLDevice::StaticDraw);
614 			idxBuffer = device->GenBuffer();
615 			device->BindBuffer(IGLDevice::ArrayBuffer, idxBuffer);
616 			device->BufferData(IGLDevice::ArrayBuffer,
617 			                   static_cast<IGLDevice::Sizei>(sizeof(uint32_t) * indices.size()),
618 			                   indices.data(), IGLDevice::StaticDraw);
619 			device->BindBuffer(IGLDevice::ArrayBuffer, 0);
620 
621 			numIndices = indices.size();
622 		}
623 
~GLWaterRenderer()624 		GLWaterRenderer::~GLWaterRenderer() {
625 			SPADES_MARK_FUNCTION();
626 			device->DeleteBuffer(buffer);
627 			device->DeleteBuffer(idxBuffer);
628 			device->DeleteFramebuffer(tempFramebuffer);
629 			device->DeleteTexture(tempDepthTexture);
630 			device->DeleteTexture(texture);
631 
632 			if (occlusionQuery)
633 				device->DeleteQuery(occlusionQuery);
634 
635 			for (size_t i = 0; i < waveTanks.size(); i++) {
636 				waveTanks[i]->Join();
637 				delete waveTanks[i];
638 			}
639 			device->DeleteTexture(waveTexture);
640 		}
641 
Render()642 		void GLWaterRenderer::Render() {
643 			SPADES_MARK_FUNCTION();
644 
645 			GLProfiler::Context profiler(renderer->GetGLProfiler(), "Render");
646 
647 			if (occlusionQuery == 0 && settings.r_occlusionQuery)
648 				occlusionQuery = device->GenQuery();
649 
650 			GLColorBuffer colorBuffer;
651 
652 			{
653 				GLProfiler::Context profiler(renderer->GetGLProfiler(), "Preparation");
654 				colorBuffer = renderer->GetFramebufferManager()->PrepareForWaterRendering(
655 				  tempFramebuffer, tempDepthTexture);
656 			}
657 
658 			float fogDist = renderer->GetFogDistance();
659 			Vector3 fogCol = renderer->GetFogColorForSolidPass();
660 			fogCol *= fogCol; // linearize
661 
662 			Vector3 skyCol = renderer->GetFogColor();
663 			skyCol *= skyCol; // linearize
664 
665 			const client::SceneDefinition &def = renderer->GetSceneDef();
666 			float waterLevel = 63.f;
667 			float waterRange = 128.f;
668 
669 			Matrix4 mat = Matrix4::Translate(def.viewOrigin.x, def.viewOrigin.y, waterLevel);
670 			mat = mat * Matrix4::Scale(waterRange, waterRange, 1.f);
671 
672 			GLProfiler::Context profiler2(renderer->GetGLProfiler(), "Draw Plane");
673 
674 			// do color
675 			device->DepthFunc(IGLDevice::Less);
676 			device->ColorMask(true, true, true, true);
677 			{
678 				GLProgram *prg = program;
679 				prg->Use();
680 
681 				static GLProgramUniform projectionViewModelMatrix("projectionViewModelMatrix");
682 				static GLProgramUniform projectionViewMatrix("projectionViewMatrix");
683 				static GLProgramUniform modelMatrix("modelMatrix");
684 				static GLProgramUniform viewModelMatrix("viewModelMatrix");
685 				static GLProgramUniform viewMatrix("viewMatrix");
686 				static GLProgramUniform fogDistance("fogDistance");
687 				static GLProgramUniform fogColor("fogColor");
688 				static GLProgramUniform skyColor("skyColor");
689 				static GLProgramUniform zNearFar("zNearFar");
690 				static GLProgramUniform viewOrigin("viewOrigin");
691 				static GLProgramUniform displaceScale("displaceScale");
692 				static GLProgramUniform fovTan("fovTan");
693 				static GLProgramUniform waterPlane("waterPlane");
694 
695 				projectionViewModelMatrix(prg);
696 				projectionViewMatrix(prg);
697 				modelMatrix(prg);
698 				viewModelMatrix(prg);
699 				viewMatrix(prg);
700 				fogDistance(prg);
701 				fogColor(prg);
702 				skyColor(prg);
703 				zNearFar(prg);
704 				viewOrigin(prg);
705 				displaceScale(prg);
706 				fovTan(prg);
707 				waterPlane(prg);
708 
709 				projectionViewModelMatrix.SetValue(renderer->GetProjectionViewMatrix() * mat);
710 				projectionViewMatrix.SetValue(renderer->GetProjectionViewMatrix());
711 				modelMatrix.SetValue(mat);
712 				viewModelMatrix.SetValue(renderer->GetViewMatrix() * mat);
713 				viewMatrix.SetValue(renderer->GetViewMatrix());
714 				fogDistance.SetValue(fogDist);
715 				fogColor.SetValue(fogCol.x, fogCol.y, fogCol.z);
716 				skyColor.SetValue(skyCol.x, skyCol.y, skyCol.z);
717 				zNearFar.SetValue(def.zNear, def.zFar);
718 				viewOrigin.SetValue(def.viewOrigin.x, def.viewOrigin.y, def.viewOrigin.z);
719 				/*displaceScale.SetValue(1.f / renderer->ScreenWidth() / tanf(def.fovX * .5f),
720 				                       1.f / renderer->ScreenHeight() / tanf(def.fovY) * .5f);*/
721 				displaceScale.SetValue(1.f / tanf(def.fovX * .5f), 1.f / tanf(def.fovY * .5f));
722 				fovTan.SetValue(tanf(def.fovX * .5f), -tanf(def.fovY * .5f), -tanf(def.fovX * .5f),
723 				                tanf(def.fovY * .5f));
724 
725 				// make water plane in view coord
726 				Matrix4 wmat = renderer->GetViewMatrix() * mat;
727 				Vector3 dir = wmat.GetAxis(2);
728 				waterPlane.SetValue(dir.x, dir.y, dir.z, -Vector3::Dot(dir, wmat.GetOrigin()));
729 
730 				static GLProgramUniform screenTexture("screenTexture");
731 				static GLProgramUniform depthTexture("depthTexture");
732 				static GLProgramUniform textureUnif("mainTexture");
733 				static GLProgramUniform waveTextureUnif("waveTexture");
734 				static GLProgramUniform waveTextureArrayUnif("waveTextureArray");
735 				static GLProgramUniform mirrorTexture("mirrorTexture");
736 				static GLProgramUniform mirrorDepthTexture("mirrorDepthTexture");
737 
738 				screenTexture(prg);
739 				depthTexture(prg);
740 				textureUnif(prg);
741 				waveTextureUnif(prg);
742 				waveTextureArrayUnif(prg);
743 				mirrorTexture(prg);
744 				mirrorDepthTexture(prg);
745 
746 				device->ActiveTexture(0);
747 				device->BindTexture(IGLDevice::Texture2D, colorBuffer.GetTexture());
748 				screenTexture.SetValue(0);
749 				// depth is not interpolated, so color shouldn't be
750 				device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMagFilter,
751 				                     IGLDevice::Nearest);
752 				device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMinFilter,
753 				                     IGLDevice::Nearest);
754 
755 				device->ActiveTexture(1);
756 				device->BindTexture(IGLDevice::Texture2D, tempDepthTexture);
757 				depthTexture.SetValue(1);
758 
759 				device->ActiveTexture(2);
760 				device->BindTexture(IGLDevice::Texture2D, texture);
761 				textureUnif.SetValue(2);
762 
763 				static GLShadowShader shadowShader;
764 
765 				if (waveTanks.size() == 1) {
766 					device->ActiveTexture(3);
767 					device->BindTexture(IGLDevice::Texture2D, waveTexture);
768 					waveTextureUnif.SetValue(3);
769 
770 					shadowShader(renderer, prg, 4);
771 				} else if (waveTanks.size() == 3) {
772 					device->ActiveTexture(3);
773 					device->BindTexture(IGLDevice::Texture2DArray, waveTexture);
774 					waveTextureArrayUnif.SetValue(3);
775 
776 					// mirror
777 					device->ActiveTexture(4);
778 					device->BindTexture(IGLDevice::Texture2D,
779 					                    renderer->GetFramebufferManager()->GetMirrorTexture());
780 					if ((float)settings.r_maxAnisotropy > 1.1f) {
781 						device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMaxAnisotropy,
782 						                     (float)settings.r_maxAnisotropy);
783 					}
784 					mirrorTexture.SetValue(4);
785 
786 					if ((int)settings.r_water >= 3) {
787 						device->ActiveTexture(5);
788 						device->BindTexture(
789 						  IGLDevice::Texture2D,
790 						  renderer->GetFramebufferManager()->GetMirrorDepthTexture());
791 						mirrorDepthTexture.SetValue(5);
792 
793 						shadowShader(renderer, prg, 6);
794 					} else {
795 						shadowShader(renderer, prg, 5);
796 					}
797 				} else {
798 					SPAssert(false);
799 				}
800 
801 				static GLProgramAttribute positionAttribute("positionAttribute");
802 
803 				positionAttribute(prg);
804 
805 				device->EnableVertexAttribArray(positionAttribute(), true);
806 
807 				device->BindBuffer(IGLDevice::ArrayBuffer, buffer);
808 				device->VertexAttribPointer(positionAttribute(), 2, IGLDevice::FloatType, false,
809 				                            sizeof(Vertex), NULL);
810 				device->BindBuffer(IGLDevice::ArrayBuffer, 0);
811 
812 				device->BindBuffer(IGLDevice::ElementArrayBuffer, idxBuffer);
813 
814 				if (occlusionQuery)
815 					device->BeginQuery(IGLDevice::SamplesPassed, occlusionQuery);
816 
817 				device->DrawElements(IGLDevice::Triangles,
818 				                     static_cast<IGLDevice::Sizei>(numIndices),
819 				                     IGLDevice::UnsignedInt, NULL);
820 
821 				if (occlusionQuery)
822 					device->EndQuery(IGLDevice::SamplesPassed);
823 
824 				device->BindBuffer(IGLDevice::ElementArrayBuffer, 0);
825 
826 				device->EnableVertexAttribArray(positionAttribute(), false);
827 
828 				device->ActiveTexture(0);
829 				// restore filter mode for color buffer
830 				device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMagFilter,
831 				                     IGLDevice::Linear);
832 				device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMinFilter,
833 				                     IGLDevice::Linear);
834 			}
835 		}
836 
LinearlizeColor(uint32_t v)837 		static uint32_t LinearlizeColor(uint32_t v) {
838 			int r = (uint8_t)(v);
839 			int g = (uint8_t)(v >> 8);
840 			int b = (uint8_t)(v >> 16);
841 			r = (r * r + 128) >> 8;
842 			g = (g * g + 128) >> 8;
843 			b = (b * b + 128) >> 8;
844 			return b | (g << 8) | (r << 16);
845 		}
846 
Update(float dt)847 		void GLWaterRenderer::Update(float dt) {
848 			SPADES_MARK_FUNCTION();
849 			GLProfiler::Context profiler(renderer->GetGLProfiler(), "Update");
850 
851 			// update wavetank simulation
852 			{
853 				GLProfiler::Context profiler(renderer->GetGLProfiler(), "Waiting for Simulation To Done");
854 				for (size_t i = 0; i < waveTanks.size(); i++) {
855 					waveTanks[i]->Join();
856 				}
857 			}
858 			{
859 				{
860 					GLProfiler::Context profiler(renderer->GetGLProfiler(), "Upload");
861 					if (waveTanks.size() == 1) {
862 						device->BindTexture(IGLDevice::Texture2D, waveTexture);
863 						device->TexSubImage2D(IGLDevice::Texture2D, 0, 0, 0,
864 						                      waveTanks[0]->GetSize(), waveTanks[0]->GetSize(),
865 						                      IGLDevice::BGRA, IGLDevice::UnsignedByte,
866 						                      waveTanks[0]->GetBitmap());
867 					} else {
868 						device->BindTexture(IGLDevice::Texture2DArray, waveTexture);
869 						for (size_t i = 0; i < waveTanks.size(); i++) {
870 							device->TexSubImage3D(IGLDevice::Texture2DArray, 0, 0, 0, static_cast<IGLDevice::Sizei>(i),
871 												  waveTanks[i]->GetSize(), waveTanks[i]->GetSize(), 1,
872 												  IGLDevice::BGRA, IGLDevice::UnsignedByte,
873 												  waveTanks[i]->GetBitmap());
874 						}
875 					}
876 				}
877 				{
878 					GLProfiler::Context profiler(renderer->GetGLProfiler(), "Generate Mipmap");
879 					if (waveTanks.size() == 1) {
880 						device->BindTexture(IGLDevice::Texture2D, waveTexture);
881 						device->GenerateMipmap(IGLDevice::Texture2D);
882 					} else {
883 						device->BindTexture(IGLDevice::Texture2DArray, waveTexture);
884 						device->GenerateMipmap(IGLDevice::Texture2DArray);
885 					}
886 				}
887 			}
888 			for (size_t i = 0; i < waveTanks.size(); i++) {
889 				switch (i) {
890 					case 0: waveTanks[i]->SetTimeStep(dt); break;
891 					case 1: waveTanks[i]->SetTimeStep(dt * 0.15704f / .08f); break;
892 					case 2: waveTanks[i]->SetTimeStep(dt * 0.02344f / .08f); break;
893 				}
894 				waveTanks[i]->Start();
895 			}
896 
897 			{
898 				GLProfiler::Context profiler(renderer->GetGLProfiler(), "Upload Water Color Texture");
899 				device->BindTexture(IGLDevice::Texture2D, texture);
900 				bool fullUpdate = true;
901 				for (size_t i = 0; i < updateBitmap.size(); i++) {
902 					if (updateBitmap[i] == 0) {
903 						fullUpdate = false;
904 						break;
905 					}
906 				}
907 
908 				if (fullUpdate) {
909 					uint32_t *pixels = bitmap.data();
910 					bool modified = false;
911 					int x = 0, y = 0;
912 					for (int i = w * h; i > 0; i--) {
913 						uint32_t col = map->GetColor(x, y, 63);
914 
915 						x++;
916 						if (x == w) {
917 							x = 0;
918 							y++;
919 						}
920 
921 						col = LinearlizeColor(col);
922 
923 						if (*pixels != col)
924 							modified = true;
925 						else {
926 							pixels++;
927 							continue;
928 						}
929 						*(pixels++) = col;
930 					}
931 
932 					if (modified) {
933 						device->TexSubImage2D(IGLDevice::Texture2D, 0, 0, 0, w, h, IGLDevice::BGRA,
934 						                      IGLDevice::UnsignedByte, bitmap.data());
935 					}
936 
937 					for (size_t i = 0; i < updateBitmap.size(); i++) {
938 						updateBitmap[i] = 0;
939 					}
940 				} else {
941 					// partial update
942 					for (size_t i = 0; i < updateBitmap.size(); i++) {
943 						int y = static_cast<int>(i / updateBitmapPitch);
944 						int x = static_cast<int>((i - y * updateBitmapPitch) * 32);
945 						if (updateBitmap[i] == 0)
946 							continue;
947 
948 						uint32_t *pixels = bitmap.data() + x + y * w;
949 						bool modified = false;
950 						for (int j = 0; j < 32; j++) {
951 							uint32_t col = map->GetColor(x + j, y, 63);
952 
953 							col = LinearlizeColor(col);
954 
955 							if (pixels[j] != col)
956 								modified = true;
957 							else
958 								continue;
959 							pixels[j] = col;
960 							// pixels[j] = GeneratePixel(x + j, y);
961 						}
962 
963 						if (modified) {
964 							device->TexSubImage2D(IGLDevice::Texture2D, 0, x, y, 32, 1,
965 							                      IGLDevice::BGRA, IGLDevice::UnsignedByte, pixels);
966 						}
967 
968 						updateBitmap[i] = 0;
969 					}
970 					// partial update - done
971 				}
972 			}
973 		}
974 
MarkUpdate(int x,int y)975 		void GLWaterRenderer::MarkUpdate(int x, int y) {
976 			x &= w - 1;
977 			y &= h - 1;
978 			updateBitmap[(x >> 5) + y * updateBitmapPitch] |= 1UL << (x & 31);
979 		}
980 
GameMapChanged(int x,int y,int z,client::GameMap * map)981 		void GLWaterRenderer::GameMapChanged(int x, int y, int z, client::GameMap *map) {
982 			if (map != this->map)
983 				return;
984 			if (z < 63)
985 				return;
986 			MarkUpdate(x, y);
987 		}
988 	}
989 }
990