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