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 "GLSparseShadowMapRenderer.h" 22 #include <Core/Debug.h> 23 #include <Core/Exception.h> 24 #include <Core/Settings.h> 25 #include "GLModel.h" 26 #include "GLModelRenderer.h" 27 #include "GLProfiler.h" 28 #include "GLRenderer.h" 29 #include "GLRenderer.h" 30 #include "IGLDevice.h" 31 32 namespace spades { 33 namespace draw { 34 GLSparseShadowMapRenderer(GLRenderer * r)35 GLSparseShadowMapRenderer::GLSparseShadowMapRenderer(GLRenderer *r) 36 : IGLShadowMapRenderer(r), device(r->GetGLDevice()), settings(r->GetSettings()) { 37 SPADES_MARK_FUNCTION(); 38 39 textureSize = settings.r_shadowMapSize; 40 if ((int)textureSize > 4096) { 41 SPLog("r_shadowMapSize is too large; changed to 4096"); 42 settings.r_shadowMapSize = textureSize = 4096; 43 } 44 45 for (minLod = 0; (Tiles << minLod) < textureSize; minLod++) 46 ; 47 // minLod = std::max(0, minLod - 2); 48 minLod = 0; 49 maxLod = 15; 50 51 colorTexture = device->GenTexture(); 52 device->BindTexture(IGLDevice::Texture2D, colorTexture); 53 device->TexImage2D(IGLDevice::Texture2D, 0, IGLDevice::RGB, textureSize, textureSize, 0, 54 IGLDevice::RGB, IGLDevice::UnsignedByte, NULL); 55 device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMagFilter, 56 IGLDevice::Linear); 57 device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMinFilter, 58 IGLDevice::Linear); 59 device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureWrapS, 60 IGLDevice::ClampToEdge); 61 device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureWrapT, 62 IGLDevice::ClampToEdge); 63 64 texture = device->GenTexture(); 65 device->BindTexture(IGLDevice::Texture2D, texture); 66 device->TexImage2D(IGLDevice::Texture2D, 0, IGLDevice::DepthComponent24, textureSize, 67 textureSize, 0, IGLDevice::DepthComponent, IGLDevice::UnsignedInt, 68 NULL); 69 device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMagFilter, 70 IGLDevice::Linear); 71 device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMinFilter, 72 IGLDevice::Linear); 73 device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureWrapS, 74 IGLDevice::ClampToEdge); 75 device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureWrapT, 76 IGLDevice::ClampToEdge); 77 78 pagetableTexture = device->GenTexture(); 79 device->BindTexture(IGLDevice::Texture2D, pagetableTexture); 80 device->TexImage2D(IGLDevice::Texture2D, 0, IGLDevice::RGBA8, Tiles, Tiles, 0, 81 IGLDevice::BGRA, IGLDevice::UnsignedByte, NULL); 82 device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMagFilter, 83 IGLDevice::Nearest); 84 device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMinFilter, 85 IGLDevice::Nearest); 86 device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureWrapS, 87 IGLDevice::ClampToEdge); 88 device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureWrapT, 89 IGLDevice::ClampToEdge); 90 91 framebuffer = device->GenFramebuffer(); 92 device->BindFramebuffer(IGLDevice::Framebuffer, framebuffer); 93 device->FramebufferTexture2D(IGLDevice::Framebuffer, IGLDevice::ColorAttachment0, 94 IGLDevice::Texture2D, colorTexture, 0); 95 device->FramebufferTexture2D(IGLDevice::Framebuffer, IGLDevice::DepthAttachment, 96 IGLDevice::Texture2D, texture, 0); 97 98 device->BindFramebuffer(IGLDevice::Framebuffer, 0); 99 } 100 ~GLSparseShadowMapRenderer()101 GLSparseShadowMapRenderer::~GLSparseShadowMapRenderer() { 102 SPADES_MARK_FUNCTION(); 103 104 device->DeleteTexture(texture); 105 device->DeleteTexture(pagetableTexture); 106 device->DeleteFramebuffer(framebuffer); 107 device->DeleteTexture(colorTexture); 108 } 109 110 #define Segment GLSSMRSegment 111 112 struct Segment { 113 float low, high; 114 bool empty; Segmentspades::draw::Segment115 Segment() : empty(true) {} Segmentspades::draw::Segment116 Segment(float l, float h) : low(std::min(l, h)), high(std::max(l, h)), empty(false) {} operator +=spades::draw::Segment117 void operator+=(const Segment &seg) { 118 if (seg.empty) 119 return; 120 if (empty) { 121 low = seg.low; 122 high = seg.high; 123 empty = false; 124 } else { 125 low = std::min(low, seg.low); 126 high = std::max(high, seg.high); 127 } 128 } operator +=spades::draw::Segment129 void operator+=(float v) { 130 if (empty) { 131 low = high = v; 132 } else { 133 if (v < low) 134 low = v; 135 if (v > high) 136 high = v; 137 } 138 } 139 }; 140 FrustrumCoord(const client::SceneDefinition & def,float x,float y,float z)141 static Vector3 FrustrumCoord(const client::SceneDefinition &def, float x, float y, 142 float z) { 143 x *= z; 144 y *= z; 145 return def.viewOrigin + def.viewAxis[0] * x + def.viewAxis[1] * y + def.viewAxis[2] * z; 146 } 147 ZRange(Vector3 base,Vector3 dir,Plane3 plane1,Plane3 plane2)148 static Segment ZRange(Vector3 base, Vector3 dir, Plane3 plane1, Plane3 plane2) { 149 return Segment(plane1.GetDistanceTo(base) / Vector3::Dot(dir, plane1.n), 150 plane2.GetDistanceTo(base) / Vector3::Dot(dir, plane2.n)); 151 } 152 BuildMatrix(float near,float far)153 void GLSparseShadowMapRenderer::BuildMatrix(float near, float far) { 154 // TODO: variable light direction? 155 Vector3 lightDir = MakeVector3(0, -1, -1).Normalize(); 156 // set better up dir? 157 Vector3 up = MakeVector3(0, 0, 1); 158 Vector3 side = Vector3::Cross(up, lightDir).Normalize(); 159 up = Vector3::Cross(lightDir, side).Normalize(); 160 161 // build frustrum 162 client::SceneDefinition def = GetRenderer()->GetSceneDef(); 163 Vector3 frustrum[8]; 164 float tanX = tanf(def.fovX * .5f); 165 float tanY = tanf(def.fovY * .5f); 166 167 frustrum[0] = FrustrumCoord(def, tanX, tanY, near); 168 frustrum[1] = FrustrumCoord(def, tanX, -tanY, near); 169 frustrum[2] = FrustrumCoord(def, -tanX, tanY, near); 170 frustrum[3] = FrustrumCoord(def, -tanX, -tanY, near); 171 frustrum[4] = FrustrumCoord(def, tanX, tanY, far); 172 frustrum[5] = FrustrumCoord(def, tanX, -tanY, far); 173 frustrum[6] = FrustrumCoord(def, -tanX, tanY, far); 174 frustrum[7] = FrustrumCoord(def, -tanX, -tanY, far); 175 176 // compute frustrum's x,y boundary 177 float minX, maxX, minY, maxY; 178 minX = maxX = Vector3::Dot(frustrum[0], side); 179 minY = maxY = Vector3::Dot(frustrum[0], up); 180 for (int i = 1; i < 8; i++) { 181 float x = Vector3::Dot(frustrum[i], side); 182 float y = Vector3::Dot(frustrum[i], up); 183 if (x < minX) 184 minX = x; 185 if (x > maxX) 186 maxX = x; 187 if (y < minY) 188 minY = y; 189 if (y > maxY) 190 maxY = y; 191 } 192 193 // compute frustrum's z boundary 194 Segment seg; 195 Plane3 plane1(0, 0, 1, -4.f); 196 Plane3 plane2(0, 0, 1, 64.f); 197 seg += ZRange(side * minX + up * minY, lightDir, plane1, plane2); 198 seg += ZRange(side * minX + up * maxY, lightDir, plane1, plane2); 199 seg += ZRange(side * maxX + up * minY, lightDir, plane1, plane2); 200 seg += ZRange(side * maxX + up * maxY, lightDir, plane1, plane2); 201 202 for (int i = 1; i < 8; i++) { 203 seg += Vector3::Dot(frustrum[i], lightDir); 204 } 205 206 // build frustrum obb 207 Vector3 origin = side * minX + up * minY + lightDir * seg.low; 208 Vector3 axis1 = side * (maxX - minX); 209 Vector3 axis2 = up * (maxY - minY); 210 Vector3 axis3 = lightDir * (seg.high - seg.low); 211 212 obb = OBB3(Matrix4::FromAxis(axis1, axis2, axis3, origin)); 213 vpWidth = 2.f / axis1.GetLength(); 214 vpHeight = 2.f / axis2.GetLength(); 215 216 // convert to projectionview matrix 217 matrix = obb.m.InversedFast(); 218 219 matrix = Matrix4::Scale(2.f) * matrix; 220 matrix = Matrix4::Translate(-1, -1, -1) * matrix; 221 222 // scale a little big for padding 223 matrix = Matrix4::Scale(.98f) * matrix; 224 // 225 matrix = Matrix4::Scale(1, 1, -1) * matrix; 226 227 // make sure frustrums in range 228 #ifndef NDEBUG 229 for (int i = 0; i < 8; i++) { 230 Vector4 v = matrix * frustrum[i]; 231 SPAssert(v.x >= -1.f); 232 SPAssert(v.y >= -1.f); 233 // SPAssert(v.z >= -1.f); 234 SPAssert(v.x < 1.f); 235 SPAssert(v.y < 1.f); 236 // SPAssert(v.z < 1.f); 237 } 238 #endif 239 } 240 Render()241 void GLSparseShadowMapRenderer::Render() { 242 SPADES_MARK_FUNCTION(); 243 244 IGLDevice::Integer lastFb = device->GetInteger(IGLDevice::FramebufferBinding); 245 246 // client::SceneDefinition def = GetRenderer()->GetSceneDef(); 247 248 float nearDist = 0.f; 249 float farDist = 150.f; 250 251 BuildMatrix(nearDist, farDist); 252 253 device->BindFramebuffer(IGLDevice::Framebuffer, framebuffer); 254 device->Viewport(0, 0, textureSize, textureSize); 255 device->ClearDepth(1.f); 256 device->Clear(IGLDevice::DepthBufferBit); 257 258 RenderShadowMapPass(); 259 260 device->BindFramebuffer(IGLDevice::Framebuffer, lastFb); 261 262 device->Viewport(0, 0, device->ScreenWidth(), device->ScreenHeight()); 263 } 264 265 #pragma mark - Sparse Processor 266 267 static const size_t NoGroup = (size_t)-1; 268 static const size_t NoInstance = (size_t)-1; 269 static const size_t NoNode = (size_t)-1; 270 static const size_t GroupNodeFlag = NoNode ^ (NoNode >> 1); 271 272 struct GLSparseShadowMapRenderer::Internal { 273 GLSparseShadowMapRenderer *renderer; 274 Vector3 cameraShadowCoord; 275 276 typedef int LodUnit; 277 278 struct Instance { 279 GLModel *model; 280 const client::ModelRenderParam *param; 281 IntVector3 tile1, tile2; // int aabb2 282 size_t prev, next; // instance in the same group 283 }; 284 285 /** All Instances. Sorted by model somehow. */ 286 std::vector<Instance> allInstances; 287 288 struct Group { 289 IntVector3 tile1, tile2; // int aabb2 290 size_t firstInstance, lastInstance; 291 LodUnit lod; 292 bool valid; 293 294 // shadow map texture coordinate 295 int rawX, rawY, rawW, rawH; 296 }; 297 298 std::vector<Group> groups; 299 300 // packing node 301 struct Node { 302 size_t child1, child2; 303 int pos; 304 bool horizontal; // true: x=pos, false: y=pos 305 }; 306 307 std::vector<Node> nodes; 308 int lodBias; 309 310 int mapSize; 311 312 size_t groupMap[Tiles][Tiles]; 313 ShadowMapToTileCoordspades::draw::GLSparseShadowMapRenderer::Internal314 static IntVector3 ShadowMapToTileCoord(Vector3 vec) { 315 vec.x = (vec.x * (float)(Tiles / 2)) + (float)(Tiles / 2); 316 vec.y = (vec.y * (float)(Tiles / 2)) + (float)(Tiles / 2); 317 318 IntVector3 v; 319 v.x = (int)floorf(vec.x); 320 v.y = (int)floorf(vec.y); 321 ; 322 return v; 323 } 324 TileToShadowMapCoordspades::draw::GLSparseShadowMapRenderer::Internal325 static Vector3 TileToShadowMapCoord(IntVector3 tile) { 326 Vector3 v; 327 v.x = (float)tile.x * (2.f / (float)Tiles) - 1.f; 328 v.y = (float)tile.y * (2.f / (float)Tiles) - 1.f; 329 return v; 330 } ComputeLodspades::draw::GLSparseShadowMapRenderer::Internal331 LodUnit ComputeLod(Vector3 shadowCoord) { 332 float dx = shadowCoord.x - cameraShadowCoord.x; 333 float dy = shadowCoord.y - cameraShadowCoord.y; 334 float sq = dx * dx + dy * dy; 335 float lod = 1.f / (sqrtf(sq) + .01f); 336 int iv = (int)(lod * 200.f); 337 if (iv < 1) 338 iv = 1; 339 if (iv > 65536) 340 iv = 65535; 341 342 int ld = 0; 343 while (iv > 0) { 344 ld++; 345 iv >>= 1; 346 } 347 return ld; 348 } 349 FillGroupMapspades::draw::GLSparseShadowMapRenderer::Internal350 void FillGroupMap(IntVector3 tile1, IntVector3 tile2, size_t val) { 351 for (int x = tile1.x; x < tile2.x; x++) 352 for (int y = tile1.y; y < tile2.y; y++) 353 groupMap[x][y] = val; 354 } 355 356 /** Combines `dest` and `src`. Group `src` will be 357 * no longer valid. */ CombineGroupspades::draw::GLSparseShadowMapRenderer::Internal358 void CombineGroup(size_t dest, size_t src) { 359 Group &g1 = groups[dest]; 360 Group &g2 = groups[src]; 361 FillGroupMap(g2.tile1, g2.tile2, dest); 362 363 // extend the area 364 g1.tile1.x = std::min(g1.tile1.x, g2.tile1.x); 365 g1.tile1.y = std::min(g1.tile1.y, g2.tile1.y); 366 g1.tile2.x = std::max(g1.tile2.x, g2.tile2.x); 367 g1.tile2.y = std::max(g1.tile2.y, g2.tile2.y); 368 369 g1.lod = std::max(g1.lod, g2.lod); 370 371 // combine the instance list 372 // [g1] + [g2] -> [g1, g2] 373 Instance &destLast = allInstances[g1.lastInstance]; 374 Instance &srcFirst = allInstances[g2.firstInstance]; 375 SPAssert(destLast.next == NoInstance); 376 SPAssert(srcFirst.prev == NoInstance); 377 destLast.next = g2.firstInstance; 378 srcFirst.prev = g1.lastInstance; 379 g1.lastInstance = g2.lastInstance; 380 381 // make sure the area is filled with the group `dest` 382 IntVector3 tile1 = g1.tile1, tile2 = g1.tile2; 383 for (int x = tile1.x; x < tile2.x; x++) 384 for (int y = tile1.y; y < tile2.y; y++) { 385 size_t g = groupMap[x][y]; 386 SPAssert(g != src); 387 if (g != NoGroup && g != dest) { 388 CombineGroup(dest, g); 389 SPAssert(groupMap[x][y] == dest); 390 } else { 391 groupMap[x][y] = dest; 392 } 393 } 394 395 g2.valid = false; 396 } 397 398 /** Finds an group in the specified range (tile1, tile2). 399 * If one was not found, creates a new group. 400 * If more than one was found, combines all groups. */ RegisterGroupspades::draw::GLSparseShadowMapRenderer::Internal401 size_t RegisterGroup(IntVector3 tile1, IntVector3 tile2) { 402 size_t foundGroup = NoGroup; 403 for (int x = tile1.x; x < tile2.x; x++) 404 for (int y = tile1.y; y < tile2.y; y++) { 405 size_t g = groupMap[x][y]; 406 if (g == NoGroup) 407 continue; 408 if (g == foundGroup) 409 continue; 410 if (foundGroup == NoGroup) { 411 foundGroup = g; 412 break; 413 } 414 // another group found. 415 // this should be combined with `foundGroup`. 416 CombineGroup(foundGroup, g); 417 SPAssert(groupMap[x][y] == foundGroup); 418 } 419 420 if (foundGroup == NoGroup) { 421 // new group here. 422 Group g; 423 g.tile1 = tile1; 424 g.tile2 = tile2; 425 g.firstInstance = NoInstance; 426 g.lastInstance = NoInstance; 427 g.lod = -100; // lod is an int 428 g.valid = true; 429 groups.push_back(g); 430 431 size_t id = groups.size() - 1; 432 FillGroupMap(tile1, tile2, id); 433 return id; 434 } else { 435 // instance is added to an existing group. 436 bool extended = false; 437 Group &g = groups[foundGroup]; 438 if (tile1.x < g.tile1.x) { 439 extended = true; 440 g.tile1.x = tile1.x; 441 } 442 if (tile1.y < g.tile1.y) { 443 extended = true; 444 g.tile1.y = tile1.y; 445 } 446 if (tile2.x > g.tile2.x) { 447 extended = true; 448 g.tile2.x = tile2.x; 449 } 450 if (tile2.y > g.tile2.y) { 451 extended = true; 452 g.tile2.y = tile2.y; 453 } 454 455 if (extended) { 456 SPAssert(foundGroup != NoGroup); 457 for (int x = g.tile1.x; x < g.tile2.x; x++) 458 for (int y = g.tile1.y; y < g.tile2.y; y++) { 459 size_t g = groupMap[x][y]; 460 if (g == NoGroup) { 461 groupMap[x][y] = foundGroup; 462 continue; 463 } 464 if (g == foundGroup) 465 continue; 466 // another group found. 467 // this should be combined with `foundGroup`. 468 CombineGroup(foundGroup, g); 469 SPAssert(groupMap[x][y] == foundGroup); 470 } 471 } 472 473 // don't add instance here 474 475 return foundGroup; 476 } 477 } 478 Internalspades::draw::GLSparseShadowMapRenderer::Internal479 Internal(GLSparseShadowMapRenderer *r) : renderer(r) { 480 481 GLProfiler::Context profiler(r->GetRenderer()->GetGLProfiler(), "Sparse Page Table Generation"); 482 483 cameraShadowCoord = r->GetRenderer()->GetSceneDef().viewOrigin; 484 cameraShadowCoord = (r->matrix * cameraShadowCoord).GetXYZ(); 485 486 // clear group maps 487 for (size_t x = 0; x < Tiles; x++) 488 for (size_t y = 0; y < Tiles; y++) 489 groupMap[x][y] = NoGroup; 490 491 const std::vector<GLModelRenderer::RenderModel> &rmodels = 492 renderer->GetRenderer()->GetModelRenderer()->models; 493 allInstances.reserve(256); 494 groups.reserve(64); 495 nodes.reserve(256); 496 497 for (std::vector<GLModelRenderer::RenderModel>::const_iterator it = rmodels.begin(); 498 it != rmodels.end(); it++) { 499 const GLModelRenderer::RenderModel &rmodel = *it; 500 Instance inst; 501 502 inst.model = rmodel.model; 503 OBB3 modelBounds = inst.model->GetBoundingBox(); 504 for (size_t i = 0; i < rmodel.params.size(); i++) { 505 inst.param = &(rmodel.params[i]); 506 507 if (inst.param->depthHack) 508 continue; 509 510 OBB3 instWorldBoundsOBB = inst.param->matrix * modelBounds; 511 // w should be 1, so this should wor 512 OBB3 instBoundsOBB = r->matrix * instWorldBoundsOBB; 513 AABB3 instBounds = instBoundsOBB.GetBoundingAABB(); 514 515 // frustrum(?) cull 516 if (instBounds.max.x < -1.f || instBounds.max.y < -1.f || 517 instBounds.min.x > 1.f || instBounds.min.y > 1.f) 518 continue; 519 520 inst.tile1 = ShadowMapToTileCoord(instBounds.min); 521 inst.tile2 = ShadowMapToTileCoord(instBounds.max); 522 inst.tile2.x++; 523 inst.tile2.y++; 524 525 if (inst.tile1.x < 0) 526 inst.tile1.x = 0; 527 if (inst.tile1.y < 0) 528 inst.tile1.y = 0; 529 if (inst.tile2.x > Tiles) 530 inst.tile2.x = Tiles; 531 if (inst.tile2.y > Tiles) 532 inst.tile2.y = Tiles; 533 534 if (inst.tile1.x >= inst.tile2.x) 535 continue; 536 if (inst.tile1.y >= inst.tile2.y) 537 continue; 538 539 size_t instId = allInstances.size(); 540 size_t grp = RegisterGroup(inst.tile1, inst.tile2); 541 Group &g = groups[grp]; 542 SPAssert(g.valid); 543 if (g.lastInstance == NoInstance) { 544 // this is new group. 545 g.firstInstance = instId; 546 g.lastInstance = instId; 547 inst.prev = NoInstance; 548 inst.next = NoInstance; 549 } else { 550 // adding this instance to the group 551 Instance &oldLast = allInstances[g.lastInstance]; 552 SPAssert(oldLast.next == NoInstance); 553 oldLast.next = instId; 554 inst.prev = g.lastInstance; 555 inst.next = NoInstance; 556 g.lastInstance = instId; 557 } 558 559 g.lod = std::max(g.lod, ComputeLod(instBoundsOBB.m.GetOrigin())); 560 561 allInstances.push_back(inst); 562 } 563 } 564 565 mapSize = r->settings.r_shadowMapSize; 566 } 567 AddGroupToNodespades::draw::GLSparseShadowMapRenderer::Internal568 bool AddGroupToNode(size_t &nodeRef, int nx, int ny, int nw, int nh, size_t gId) { 569 Group &g = groups[gId]; 570 if (nodeRef == NoNode) { 571 // empty node, try putting here 572 int w = g.tile2.x - g.tile1.x; 573 int h = g.tile2.y - g.tile1.y; 574 int lod = g.lod; 575 int minLod = renderer->minLod; 576 int maxLod = renderer->maxLod; 577 lod += lodBias; 578 if (lod < minLod) 579 lod = minLod; 580 if (lod > maxLod) 581 lod = maxLod; 582 w <<= lod; 583 h <<= lod; 584 w += 2; 585 h += 2; // safety margin 586 if (w > nw || h > nh) { 587 return false; 588 } 589 590 g.rawX = nx + 1; 591 g.rawY = ny + 1; 592 g.rawW = w - 1; 593 g.rawH = h - 1; 594 595 // how fits 596 if (w == nw && h == nh) { 597 // completely fits 598 nodeRef = gId | GroupNodeFlag; 599 } else if (w == nw) { 600 Node node; 601 node.child1 = gId | GroupNodeFlag; 602 node.child2 = NoNode; 603 node.horizontal = false; 604 node.pos = ny + h; 605 nodeRef = nodes.size(); 606 nodes.push_back(node); 607 } else if (h == nh) { 608 Node node; 609 node.child1 = gId | GroupNodeFlag; 610 node.child2 = NoNode; 611 node.horizontal = true; 612 node.pos = nx + w; 613 nodeRef = nodes.size(); 614 nodes.push_back(node); 615 } else { 616 Node node; 617 node.child1 = gId | GroupNodeFlag; 618 node.child2 = NoNode; 619 node.horizontal = true; 620 node.pos = nx + w; 621 size_t subnode = nodes.size(); 622 nodes.push_back(node); 623 624 node.child1 = subnode; 625 node.child2 = NoNode; 626 node.horizontal = false; 627 node.pos = ny + h; 628 nodeRef = nodes.size(); 629 nodes.push_back(node); 630 } 631 632 return true; 633 } else { 634 if (nodeRef & GroupNodeFlag) 635 return false; 636 Node &node = nodes[nodeRef]; 637 if (node.horizontal) { 638 if (AddGroupToNode(node.child1, nx, ny, node.pos - nx, nh, gId)) 639 return true; 640 if (AddGroupToNode(node.child2, node.pos, ny, nx + nw - node.pos, nh, gId)) 641 return true; 642 } else { 643 if (AddGroupToNode(node.child1, nx, ny, nw, node.pos - ny, gId)) 644 return true; 645 if (AddGroupToNode(node.child2, nx, node.pos, nw, ny + nh - node.pos, gId)) 646 return true; 647 } 648 return false; 649 } 650 } 651 TryPackspades::draw::GLSparseShadowMapRenderer::Internal652 bool TryPack() { 653 size_t rootNode = NoNode; 654 nodes.clear(); 655 for (size_t i = 0; i < groups.size(); i++) { 656 if (!AddGroupToNode(rootNode, 0, 0, mapSize, mapSize, i)) 657 return false; 658 } 659 return true; 660 } 661 Packspades::draw::GLSparseShadowMapRenderer::Internal662 void Pack() { 663 if (groups.empty()) 664 return; 665 666 GLProfiler::Context profiler(renderer->GetRenderer()->GetGLProfiler(), "Pack [%d group(s)]", (int)groups.size()); 667 668 lodBias = 100; 669 if (TryPack()) { 670 // try to make it more detail 671 do { 672 lodBias++; 673 } while (TryPack() && lodBias < 140); 674 lodBias--; 675 TryPack(); 676 } else { 677 // try to succeed packing by making it more rough 678 do { 679 lodBias--; 680 } while (!TryPack()); 681 } 682 } 683 }; 684 685 struct GLSparseShadowMapRenderer::ModelRenderer { 686 std::vector<client::ModelRenderParam> params; 687 GLModel *lastModel; 688 ModelRendererspades::draw::GLSparseShadowMapRenderer::ModelRenderer689 ModelRenderer() { 690 params.resize(64); 691 lastModel = NULL; 692 } 693 Flushspades::draw::GLSparseShadowMapRenderer::ModelRenderer694 void Flush() { 695 if (lastModel) { 696 lastModel->RenderShadowMapPass(params); 697 params.clear(); 698 lastModel = NULL; 699 } 700 } 701 RenderModelspades::draw::GLSparseShadowMapRenderer::ModelRenderer702 void RenderModel(GLModel *m, const client::ModelRenderParam ¶m) { 703 if (m != lastModel) 704 Flush(); 705 lastModel = m; 706 params.push_back(param); 707 } 708 }; 709 RenderShadowMapPass()710 void GLSparseShadowMapRenderer::RenderShadowMapPass() { 711 Internal itnl(this); 712 itnl.Pack(); 713 714 { 715 GLProfiler::Context profiler(GetRenderer()->GetGLProfiler(), "Page Table Generation"); 716 for (int x = 0; x < Tiles; x++) { 717 for (int y = 0; y < Tiles; y++) { 718 size_t val = itnl.groupMap[x][y]; 719 uint32_t out; 720 721 if (val == NoGroup) { 722 out = 0xffffffff; 723 } else { 724 Internal::Group &g = itnl.groups[val]; 725 int lod = g.lod; 726 lod += itnl.lodBias; 727 if (lod < minLod) 728 lod = minLod; 729 if (lod > maxLod) 730 lod = maxLod; 731 int ix = x - g.tile1.x; 732 int iy = y - g.tile1.y; 733 ix <<= lod; 734 iy <<= lod; 735 ix += g.rawX; 736 iy += g.rawY; 737 738 unsigned int rr, gg, bb, aa; 739 rr = (ix & 255); 740 gg = (iy & 255); 741 bb = (ix >> 8) | ((iy >> 8) << 4); 742 aa = lod; // 1 << (lod - minLod); 743 out = bb | (gg << 8) | (rr << 16) | (aa << 24); 744 } 745 746 pagetable[y][x] = out; 747 } 748 } 749 } 750 751 { 752 GLProfiler::Context profiler(GetRenderer()->GetGLProfiler(), "Page Table Upload"); 753 device->BindTexture(IGLDevice::Texture2D, pagetableTexture); 754 device->TexSubImage2D(IGLDevice::Texture2D, 0, 0, 0, Tiles, Tiles, IGLDevice::BGRA, 755 IGLDevice::UnsignedByte, pagetable); 756 } 757 758 Matrix4 baseMatrix = matrix; 759 { 760 GLProfiler::Context profiler(GetRenderer()->GetGLProfiler(), "Shadow Maps [%d group(s)]", (int)itnl.groups.size()); 761 ModelRenderer mrend; 762 for (size_t i = 0; i < itnl.groups.size(); i++) { 763 Internal::Group &g = itnl.groups[i]; 764 device->Viewport(g.rawX, g.rawY, g.rawW, g.rawH); 765 766 Vector3 dest1 = Internal::TileToShadowMapCoord(g.tile1); 767 Vector3 dest2 = Internal::TileToShadowMapCoord(g.tile2); 768 769 Matrix4 mat; 770 mat = Matrix4::Translate((dest1.x + dest2.x) * -.5f, (dest1.y + dest2.y) * -.5f, 771 0.f); 772 mat = 773 Matrix4::Scale(2.f / (dest2.x - dest1.x), 2.f / (dest2.y - dest1.y), 1.f) * 774 mat; 775 mat = mat * baseMatrix; 776 777 matrix = mat; 778 779 for (size_t mId = g.firstInstance; mId != NoInstance; 780 mId = itnl.allInstances[mId].next) { 781 Internal::Instance &inst = itnl.allInstances[mId]; 782 mrend.RenderModel(inst.model, *inst.param); 783 784 Vector3 v = 785 inst.model->GetBoundingBox().min + inst.model->GetBoundingBox().max; 786 v *= .5f; 787 v = (inst.param->matrix * v).GetXYZ(); 788 { 789 v = (baseMatrix * v).GetXYZ(); 790 SPAssert(v.x >= -1.2f); 791 SPAssert(v.y >= -1.2f); 792 SPAssert(v.x <= 1.2f); 793 SPAssert(v.y <= 1.2f); 794 } 795 } 796 mrend.Flush(); 797 } 798 } 799 800 matrix = baseMatrix; 801 } 802 Cull(const spades::AABB3 &)803 bool GLSparseShadowMapRenderer::Cull(const spades::AABB3 &) { 804 805 // TODO: who uses this? 806 SPNotImplemented(); 807 return true; 808 } 809 SphereCull(const spades::Vector3 & center,float rad)810 bool GLSparseShadowMapRenderer::SphereCull(const spades::Vector3 ¢er, float rad) { 811 return true; // for models, this is already done 812 /* 813 Vector4 vw = matrix * center; 814 float xx = fabsf(vw.x); 815 float yy = fabsf(vw.y); 816 float rx = rad * vpWidth; 817 float ry = rad * vpHeight; 818 819 return xx < (1.f + rx) && yy < (1.f + ry);*/ 820 } 821 } 822 } 823