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 <algorithm> 22 #include <array> 23 #include <cfenv> 24 #include <cstdlib> 25 26 #include "SWFlatMapRenderer.h" 27 #include "SWImage.h" 28 #include "SWImageRenderer.h" 29 #include "SWMapRenderer.h" 30 #include "SWModel.h" 31 #include "SWModelRenderer.h" 32 #include "SWPort.h" 33 #include "SWRenderer.h" 34 #include <Client/GameMap.h> 35 #include <Core/Bitmap.h> 36 #include <Core/Settings.h> 37 38 #include "SWUtils.h" 39 40 DEFINE_SPADES_SETTING(r_swStatistics, "0"); 41 DEFINE_SPADES_SETTING(r_swNumThreads, "4"); 42 43 namespace spades { 44 namespace draw { SWRenderer(SWPort * port,SWFeatureLevel level)45 SWRenderer::SWRenderer(SWPort *port, SWFeatureLevel level) 46 : featureLevel(level), 47 port(port), 48 map(nullptr), 49 fb(nullptr), 50 inited(false), 51 sceneUsedInThisFrame(false), 52 fogDistance(128.f), 53 fogColor(MakeVector3(0.f, 0.f, 0.f)), 54 drawColorAlphaPremultiplied(MakeVector4(1, 1, 1, 1)), 55 legacyColorPremultiply(false), 56 lastTime(0), 57 duringSceneRendering(false) { 58 59 SPADES_MARK_FUNCTION(); 60 61 if (port == nullptr) { 62 SPRaise("Port is null."); 63 } 64 65 SPLog("---- SWRenderer early initialization started ---"); 66 67 #ifdef FE_DFL_DISABLE_SSE_DENORMS_ENV 68 SPLog("initializing FPU"); 69 fesetenv(FE_DFL_DISABLE_SSE_DENORMS_ENV); 70 #endif 71 72 SPLog("creating image manager"); 73 imageManager = std::make_shared<SWImageManager>(); 74 75 SPLog("creating image renderer"); 76 imageRenderer = std::make_shared<SWImageRenderer>(featureLevel); 77 imageRenderer->ResetPixelStatistics(); 78 renderStopwatch.Reset(); 79 80 SPLog("setting framebuffer."); 81 SetFramebuffer(port->GetFramebuffer()); 82 83 // alloc depth buffer 84 SPLog("initializing depth buffer."); 85 depthBuffer.resize(fb->GetWidth() * fb->GetHeight()); 86 imageRenderer->SetDepthBuffer(depthBuffer.data()); 87 88 SPLog("---- SWRenderer early initialization done ---"); 89 } 90 ~SWRenderer()91 SWRenderer::~SWRenderer() { 92 SPADES_MARK_FUNCTION(); 93 94 Shutdown(); 95 } 96 SetFramebuffer(spades::Bitmap * bmp)97 void SWRenderer::SetFramebuffer(spades::Bitmap *bmp) { 98 if (bmp == nullptr) { 99 SPRaise("Framebuffer is null."); 100 } 101 if (fb) { 102 SPAssert(bmp->GetWidth() == fb->GetWidth()); 103 SPAssert(bmp->GetHeight() == fb->GetHeight()); 104 } 105 fb = bmp; 106 imageRenderer->SetFramebuffer(bmp); 107 if ((bmp->GetWidth() & 7) || (bmp->GetHeight() & 7)) { 108 SPRaise("Framebuffer size is not multiple of 8."); 109 } 110 } 111 Init()112 void SWRenderer::Init() { 113 SPADES_MARK_FUNCTION(); 114 115 SPLog("---- SWRenderer late initialization started ---"); 116 modelManager = std::make_shared<SWModelManager>(); 117 118 SPLog("creating model renderer"); 119 modelRenderer = std::make_shared<SWModelRenderer>(this, featureLevel); 120 renderStopwatch.Reset(); 121 122 SPLog("---- SWRenderer late initialization done ---"); 123 124 inited = true; 125 } 126 Shutdown()127 void SWRenderer::Shutdown() { 128 SPADES_MARK_FUNCTION(); 129 130 SetGameMap(nullptr); 131 132 imageRenderer.reset(); 133 flatMapRenderer.reset(); 134 135 imageManager.reset(); 136 modelManager.reset(); 137 map = nullptr; 138 port = nullptr; 139 140 inited = false; 141 } 142 RegisterImage(const char * filename)143 client::IImage *SWRenderer::RegisterImage(const char *filename) { 144 SPADES_MARK_FUNCTION(); 145 EnsureValid(); 146 return imageManager->RegisterImage(filename); 147 } 148 RegisterModel(const char * filename)149 client::IModel *SWRenderer::RegisterModel(const char *filename) { 150 SPADES_MARK_FUNCTION(); 151 EnsureInitialized(); 152 return modelManager->RegisterModel(filename); 153 } 154 CreateImage(spades::Bitmap * bmp)155 client::IImage *SWRenderer::CreateImage(spades::Bitmap *bmp) { 156 SPADES_MARK_FUNCTION(); 157 EnsureValid(); 158 return imageManager->CreateImage(bmp); 159 } 160 CreateModel(spades::VoxelModel * model)161 client::IModel *SWRenderer::CreateModel(spades::VoxelModel *model) { 162 SPADES_MARK_FUNCTION(); 163 EnsureInitialized(); 164 return modelManager->CreateModel(model); 165 } 166 SetGameMap(client::GameMap * map)167 void SWRenderer::SetGameMap(client::GameMap *map) { 168 SPADES_MARK_FUNCTION(); 169 if (map) 170 EnsureInitialized(); 171 if (map == this->map) 172 return; 173 174 flatMapRenderer.reset(); 175 mapRenderer.reset(); 176 177 if (this->map) 178 this->map->RemoveListener(this); 179 this->map = map; 180 if (this->map) { 181 this->map->AddListener(this); 182 flatMapRenderer = std::make_shared<SWFlatMapRenderer>(this, map); 183 mapRenderer = std::make_shared<SWMapRenderer>(this, map, featureLevel); 184 } 185 } 186 SetFogColor(spades::Vector3 v)187 void SWRenderer::SetFogColor(spades::Vector3 v) { fogColor = v; } 188 BuildProjectionMatrix()189 void SWRenderer::BuildProjectionMatrix() { 190 SPADES_MARK_FUNCTION(); 191 192 float near = sceneDef.zNear; 193 float far = sceneDef.zFar; 194 float t = near * tanf(sceneDef.fovY * .5f); 195 float r = near * tanf(sceneDef.fovX * .5f); 196 float a = r * 2.f, b = t * 2.f, c = far - near; 197 Matrix4 mat; 198 mat.m[0] = near * 2.f / a; 199 mat.m[1] = 0.f; 200 mat.m[2] = 0.f; 201 mat.m[3] = 0.f; 202 mat.m[4] = 0.f; 203 mat.m[5] = near * 2.f / b; 204 mat.m[6] = 0.f; 205 mat.m[7] = 0.f; 206 mat.m[8] = 0.f; 207 mat.m[9] = 0.f; 208 mat.m[10] = -(far + near) / c; 209 mat.m[11] = -1.f; 210 mat.m[12] = 0.f; 211 mat.m[13] = 0.f; 212 mat.m[14] = -(far * near * 2.f) / c; 213 mat.m[15] = 0.f; 214 projectionMatrix = mat; 215 } 216 BuildView()217 void SWRenderer::BuildView() { 218 SPADES_MARK_FUNCTION(); 219 220 Matrix4 mat = Matrix4::Identity(); 221 mat.m[0] = sceneDef.viewAxis[0].x; 222 mat.m[4] = sceneDef.viewAxis[0].y; 223 mat.m[8] = sceneDef.viewAxis[0].z; 224 mat.m[1] = sceneDef.viewAxis[1].x; 225 mat.m[5] = sceneDef.viewAxis[1].y; 226 mat.m[9] = sceneDef.viewAxis[1].z; 227 mat.m[2] = -sceneDef.viewAxis[2].x; 228 mat.m[6] = -sceneDef.viewAxis[2].y; 229 mat.m[10] = -sceneDef.viewAxis[2].z; 230 231 Vector4 v = mat * sceneDef.viewOrigin; 232 mat.m[12] = -v.x; 233 mat.m[13] = -v.y; 234 mat.m[14] = -v.z; 235 236 viewMatrix = mat; 237 } 238 BuildFrustrum()239 void SWRenderer::BuildFrustrum() { 240 // far/near 241 frustrum[0] = Plane3::PlaneWithPointOnPlane(sceneDef.viewOrigin, sceneDef.viewAxis[2]); 242 frustrum[1] = frustrum[0].Flipped(); 243 frustrum[0].w -= sceneDef.zNear; 244 frustrum[1].w += sceneDef.zFar; 245 246 float xCos = cosf(sceneDef.fovX * .5f); 247 float xSin = sinf(sceneDef.fovX * .5f); 248 float yCos = cosf(sceneDef.fovY * .5f); 249 float ySin = sinf(sceneDef.fovY * .5f); 250 251 frustrum[2] = Plane3::PlaneWithPointOnPlane( 252 sceneDef.viewOrigin, sceneDef.viewAxis[2] * xSin - sceneDef.viewAxis[0] * xCos); 253 frustrum[3] = Plane3::PlaneWithPointOnPlane( 254 sceneDef.viewOrigin, sceneDef.viewAxis[2] * xSin + sceneDef.viewAxis[0] * xCos); 255 frustrum[4] = Plane3::PlaneWithPointOnPlane( 256 sceneDef.viewOrigin, sceneDef.viewAxis[2] * ySin - sceneDef.viewAxis[1] * yCos); 257 frustrum[5] = Plane3::PlaneWithPointOnPlane( 258 sceneDef.viewOrigin, sceneDef.viewAxis[2] * ySin + sceneDef.viewAxis[1] * yCos); 259 } 260 ApplyDynamicLight(const DynamicLight & light)261 template <SWFeatureLevel> void SWRenderer::ApplyDynamicLight(const DynamicLight &light) { 262 int fw = this->fb->GetWidth(); 263 int fh = this->fb->GetHeight(); 264 265 float fovX = tanf(sceneDef.fovX * 0.5f); 266 float fovY = tanf(sceneDef.fovY * 0.5f); 267 268 float dvx = -fovX * 2.f / static_cast<float>(fw); 269 float dvy = -fovY * 2.f / static_cast<float>(fh); 270 271 int minX = light.minX; 272 int minY = light.minY; 273 int maxX = light.maxX; 274 int maxY = light.maxY; 275 int lightHeight = maxY - minY; 276 277 SPAssert(minX >= 0); 278 SPAssert(minY >= 0); 279 SPAssert(maxX <= fw); 280 SPAssert(maxY <= fh); 281 282 Vector3 lightCenter; 283 Vector3 diff = light.param.origin - sceneDef.viewOrigin; 284 lightCenter.x = Vector3::Dot(diff, sceneDef.viewAxis[0]); 285 lightCenter.y = Vector3::Dot(diff, sceneDef.viewAxis[1]); 286 lightCenter.z = Vector3::Dot(diff, sceneDef.viewAxis[2]); 287 288 int lightR = ToFixedFactor8(light.param.color.x); 289 int lightG = ToFixedFactor8(light.param.color.y); 290 int lightB = ToFixedFactor8(light.param.color.z); 291 292 float invRadius2 = 1.f / (light.param.radius * light.param.radius); 293 294 InvokeParallel2([=](unsigned int threadId, unsigned int numThreads) { 295 int startY = lightHeight * threadId / numThreads; 296 int endY = lightHeight * (threadId + 1) / numThreads; 297 startY += minY; 298 endY += minY; 299 300 auto *fb = this->fb->GetPixels(); 301 float *db = depthBuffer.data(); 302 fb += startY * fw + minX; 303 db += startY * fw + minX; 304 305 float vy = fovY + dvy * startY; 306 float vx = fovX + dvx * minX; 307 308 int lightWidth = maxX - minX; 309 310 for (int y = startY; y < endY; y++) { 311 float vx2 = vx; 312 auto *fb2 = fb; 313 auto *db2 = db; 314 315 for (int x = lightWidth; x > 0; x--) { 316 Vector3 pos; 317 318 pos.z = *db2; 319 pos.x = vx2 * pos.z; 320 pos.y = vy * pos.z; 321 322 pos -= lightCenter; 323 324 float dist = pos.GetPoweredLength(); 325 dist *= invRadius2; 326 327 if (dist < 1.f) { 328 float strength = 1.f - dist; 329 strength *= strength; 330 strength *= 256.f; 331 332 int factor = static_cast<int>(strength); 333 334 int actualLightR = lightR * factor; 335 int actualLightG = lightG * factor; 336 int actualLightB = lightB * factor; 337 338 auto srcColor = *fb2; 339 auto srcColorR = (srcColor >> 16) & 0xff; 340 auto srcColorG = (srcColor >> 8) & 0xff; 341 auto srcColorB = srcColor & 0xff; 342 343 actualLightR *= srcColorR; 344 actualLightG *= srcColorG; 345 actualLightB *= srcColorB; 346 347 auto destColorR = actualLightR >> 16; 348 auto destColorG = actualLightG >> 16; 349 auto destColorB = actualLightB >> 16; 350 351 destColorR = std::min<uint32_t>(destColorR + srcColorR, 255); 352 destColorG = std::min<uint32_t>(destColorG + srcColorG, 255); 353 destColorB = std::min<uint32_t>(destColorB + srcColorB, 255); 354 355 uint32_t destColor = 356 destColorB | (destColorG << 8) | (destColorR << 16); 357 358 *fb2 = destColor; 359 } 360 361 vx2 += dvx; 362 fb2++; 363 db2++; 364 } 365 366 vy += dvy; 367 fb += fw; 368 db += fw; 369 } 370 }); 371 } 372 ApplyFog()373 template <SWFeatureLevel level> void SWRenderer::ApplyFog() { 374 int fw = this->fb->GetWidth(); 375 int fh = this->fb->GetHeight(); 376 377 float fovX = tanf(sceneDef.fovX * 0.5f); 378 float fovY = tanf(sceneDef.fovY * 0.5f); 379 380 float dvx = -fovX * 2.f / static_cast<float>(fw / 4); 381 float dvy = -fovY * 2.f / static_cast<float>(fh / 4); 382 383 int fogR = ToFixed8(fogColor.x); 384 int fogG = ToFixed8(fogColor.y); 385 int fogB = ToFixed8(fogColor.z); 386 uint32_t fog1 = static_cast<uint32_t>(fogB + fogR * 0x10000); 387 uint32_t fog2 = static_cast<uint32_t>(fogG * 0x100); 388 389 float scale = 255.f / fogDistance; 390 391 InvokeParallel2([&](unsigned int threadId, unsigned int numThreads) { 392 int startY = fh * threadId / numThreads; 393 int endY = fh * (threadId + 1) / numThreads; 394 startY &= ~3; 395 endY &= ~3; 396 397 float vy = fovY; 398 auto *fb = this->fb->GetPixels(); 399 float *db = depthBuffer.data(); 400 401 vy += dvy * (startY >> 2); 402 fb += fw * startY; 403 db += fw * startY; 404 405 for (int y = startY; y < endY; y += 4) { 406 float vx = fovX; 407 408 for (int x = 0; x < fw; x += 4) { 409 float depthScale = (1.f + vx * vx + vy * vy); 410 depthScale *= fastRSqrt(depthScale) * scale; 411 auto *fb2 = fb + x; 412 auto *db2 = db + x; 413 for (int by = 0; by < 4; by++) { 414 auto *fb3 = fb2; 415 auto *db3 = db2; 416 417 for (int bx = 0; bx < 4; bx++) { 418 419 float dist = *db3 * depthScale; 420 int factor = std::min(static_cast<int>(dist), 256); 421 factor = std::max(0, factor); 422 int factor2 = 256 - factor; 423 424 uint32_t color = *fb3; 425 uint32_t v1 = (color & 0xff00ff) * factor2; 426 uint32_t v2 = (color & 0x00ff00) * factor2; 427 v1 += fog1 * factor; 428 v2 += fog2 * factor; 429 v1 &= 0xff00ff00; 430 v2 &= 0xff0000; 431 *fb3 = (v1 | v2) >> 8; 432 433 fb3++; 434 db3++; 435 } 436 437 fb2 += fw; 438 db2 += fw; 439 } 440 441 vx += dvx; 442 } 443 444 vy += dvy; 445 fb += fw * 4; 446 db += fw * 4; 447 } 448 }); 449 450 } // ApplyFog() 451 452 #if ENABLE_SSE2 453 ApplyFog()454 template <> void SWRenderer::ApplyFog<SWFeatureLevel::SSE2>() { 455 int fw = this->fb->GetWidth(); 456 int fh = this->fb->GetHeight(); 457 458 float fovX = tanf(sceneDef.fovX * 0.5f); 459 float fovY = tanf(sceneDef.fovY * 0.5f); 460 461 float dvx = -fovX * 2.f / static_cast<float>(fw / 4); 462 float dvy = -fovY * 2.f / static_cast<float>(fh / 4); 463 464 int fogR = ToFixed8(fogColor.x); 465 int fogG = ToFixed8(fogColor.y); 466 int fogB = ToFixed8(fogColor.z); 467 __m128i fog = _mm_setr_epi16(fogB, fogG, fogR, 0, fogB, fogG, fogR, 0); 468 469 float scale = 255.f / fogDistance; 470 471 InvokeParallel2([&](unsigned int threadId, unsigned int numThreads) { 472 int startY = fh * threadId / numThreads; 473 int endY = fh * (threadId + 1) / numThreads; 474 startY &= ~3; 475 endY &= ~3; 476 477 float vy = fovY; 478 auto *fb = this->fb->GetPixels(); 479 float *db = depthBuffer.data(); 480 481 vy += dvy * (startY >> 2); 482 fb += fw * startY; 483 db += fw * startY; 484 485 for (int y = startY; y < endY; y += 4) { 486 float vx = fovX; 487 488 for (int x = 0; x < fw; x += 4) { 489 float depthScale = (1.f + vx * vx + vy * vy); 490 depthScale *= fastRSqrt(depthScale) * scale; 491 auto depthScale4 = _mm_set1_ps(depthScale); 492 493 auto *fb2 = fb + x; 494 auto *db2 = db + x; 495 for (int by = 0; by < 4; by++) { 496 auto *fb3 = fb2; 497 auto *db3 = db2; 498 499 auto dist = _mm_load_ps(db3); 500 auto color = _mm_load_si128(reinterpret_cast<__m128i *>(fb3)); 501 502 dist = _mm_mul_ps(dist, depthScale4); 503 dist = _mm_max_ps(dist, _mm_set1_ps(0.f)); 504 dist = _mm_min_ps(dist, _mm_set1_ps(256.f)); 505 auto factorX = _mm_cvtps_epi32(dist); 506 507 auto factorY = _mm_sub_epi32(_mm_set1_epi32(0x100), factorX); 508 509 factorX = _mm_shufflelo_epi16(factorX, 0xa0); 510 factorX = _mm_shufflehi_epi16(factorX, 0xa0); 511 factorY = _mm_shufflelo_epi16(factorY, 0xa0); 512 factorY = _mm_shufflehi_epi16(factorY, 0xa0); 513 514 // first 2px 515 auto color1 = _mm_unpacklo_epi8(color, _mm_setzero_si128()); 516 auto factor1X = _mm_shuffle_epi32(factorY, 0x50); 517 auto factor1Y = _mm_shuffle_epi32(factorX, 0x50); 518 color1 = _mm_mullo_epi16(color1, factor1X); 519 auto fog1 = _mm_mullo_epi16(fog, factor1Y); 520 fog1 = _mm_adds_epu16(fog1, color1); 521 fog1 = _mm_srli_epi16(fog1, 8); 522 523 // next 2px 524 auto color2 = _mm_unpackhi_epi8(color, _mm_setzero_si128()); 525 auto factor2X = _mm_shuffle_epi32(factorY, 0xfa); 526 auto factor2Y = _mm_shuffle_epi32(factorX, 0xfa); 527 color2 = _mm_mullo_epi16(color2, factor2X); 528 auto fog2 = _mm_mullo_epi16(fog, factor2Y); 529 fog2 = _mm_adds_epu16(fog2, color2); 530 fog2 = _mm_srli_epi16(fog2, 8); 531 532 auto pack = _mm_packus_epi16(fog1, fog2); 533 _mm_store_si128(reinterpret_cast<__m128i *>(fb3), pack); 534 535 fb2 += fw; 536 db2 += fw; 537 } 538 539 vx += dvx; 540 } 541 542 vy += dvy; 543 fb += fw * 4; 544 db += fw * 4; 545 } 546 }); 547 548 } // ApplyFog() 549 550 #endif 551 EnsureSceneStarted()552 void SWRenderer::EnsureSceneStarted() { 553 SPADES_MARK_FUNCTION_DEBUG(); 554 if (!duringSceneRendering) { 555 SPRaise("Illegal call outside of StartScene ... EndScene"); 556 } 557 } 558 EnsureSceneNotStarted()559 void SWRenderer::EnsureSceneNotStarted() { 560 SPADES_MARK_FUNCTION_DEBUG(); 561 if (duringSceneRendering) { 562 SPRaise("Illegal call between StartScene ... EndScene"); 563 } 564 } 565 EnsureInitialized()566 void SWRenderer::EnsureInitialized() { 567 SPADES_MARK_FUNCTION_DEBUG(); 568 if (!inited) { 569 SPRaise("Renderer is not initialized"); 570 } 571 EnsureValid(); 572 } 573 EnsureValid()574 void SWRenderer::EnsureValid() { 575 SPADES_MARK_FUNCTION_DEBUG(); 576 if (!port) { 577 SPRaise("Renderer is not valid"); 578 } 579 } 580 StartScene(const client::SceneDefinition & def)581 void SWRenderer::StartScene(const client::SceneDefinition &def) { 582 SPADES_MARK_FUNCTION(); 583 584 EnsureInitialized(); 585 EnsureSceneNotStarted(); 586 587 sceneDef = def; 588 duringSceneRendering = true; 589 590 BuildProjectionMatrix(); 591 BuildView(); 592 BuildFrustrum(); 593 594 projectionViewMatrix = projectionMatrix * viewMatrix; 595 } 596 RenderModel(client::IModel * model,const client::ModelRenderParam & param)597 void SWRenderer::RenderModel(client::IModel *model, const client::ModelRenderParam ¶m) { 598 SPADES_MARK_FUNCTION(); 599 EnsureInitialized(); 600 EnsureSceneStarted(); 601 602 auto *mdl = dynamic_cast<SWModel *>(model); 603 if (mdl == nullptr) 604 SPInvalidArgument("model"); 605 606 Model m; 607 m.model = mdl; 608 m.param = param; 609 610 models.push_back(m); 611 } 612 AddLight(const client::DynamicLightParam & param)613 void SWRenderer::AddLight(const client::DynamicLightParam ¶m) { 614 SPADES_MARK_FUNCTION(); 615 EnsureInitialized(); 616 EnsureSceneStarted(); 617 618 if (param.type != client::DynamicLightTypePoint) { 619 // TODO: support non-point lights 620 return; 621 } 622 623 auto diff = param.origin - sceneDef.viewOrigin; 624 float rad2 = param.radius * param.radius; 625 float poweredLength = diff.GetPoweredLength(); 626 627 float fogCullRange = param.radius + fogDistance; 628 if (poweredLength > fogCullRange * fogCullRange) { 629 // fog cull 630 return; 631 } 632 633 DynamicLight light; 634 if (poweredLength < rad2) { 635 light.minX = 0; 636 light.minY = 0; 637 light.maxX = fb->GetWidth(); 638 light.maxY = fb->GetHeight(); 639 } else if (Vector3::Dot(diff, sceneDef.viewAxis[2]) < 0.f) { 640 // view plane cull 641 return; 642 } else { 643 auto viewRange = [](float cx, float cy, float fov, 644 float screenSize) -> std::array<int, 2> { 645 auto trans = [screenSize, fov](float v) { 646 v = (v / fov) * 0.5f + 0.5f; 647 v = std::max(v, 0.f); 648 v = std::min(v, 1.f); 649 v *= screenSize; 650 return static_cast<int>(v); 651 }; 652 auto dist = cx * cx + cy * cy - 1.f; 653 if (dist <= 0.f) { 654 return std::array<int, 2>{{0, static_cast<int>(screenSize)}}; 655 } 656 657 auto denom = cx * cx - 1.f; 658 if (fabsf(denom) < 1.e-10f) { 659 denom = 1.e-8f; 660 } 661 denom = 1.f / denom; 662 663 dist = sqrtf(dist); 664 665 if (cx <= 1.f) { 666 if (cy > 0.f) { 667 return std::array<int, 2>{ 668 {trans(cx * cy - dist), static_cast<int>(screenSize)}}; 669 } else { 670 return std::array<int, 2>{{0, trans(cx * cy + dist)}}; 671 } 672 } else { 673 return std::array<int, 2>{{trans(cx * cy - dist), trans(cx * cy + dist)}}; 674 } 675 }; 676 auto invRad = 1.f / param.radius; 677 auto rangeX = viewRange(Vector3::Dot(diff, sceneDef.viewAxis[2]) * invRad, 678 Vector3::Dot(diff, sceneDef.viewAxis[0]) * invRad, 679 tanf(sceneDef.fovX * 0.5f), ScreenWidth()); 680 auto rangeY = viewRange(Vector3::Dot(diff, sceneDef.viewAxis[1]) * invRad, 681 Vector3::Dot(diff, sceneDef.viewAxis[0]) * invRad, 682 tanf(sceneDef.fovY * 0.5f), ScreenHeight()); 683 light.minX = rangeX[0]; 684 light.maxX = rangeX[1]; 685 light.minY = rangeY[0]; 686 light.maxY = rangeY[1]; 687 } 688 689 light.param = param; 690 lights.push_back(light); 691 } 692 AddDebugLine(spades::Vector3 a,spades::Vector3 b,spades::Vector4 color)693 void SWRenderer::AddDebugLine(spades::Vector3 a, spades::Vector3 b, spades::Vector4 color) { 694 EnsureInitialized(); 695 EnsureSceneStarted(); 696 697 DebugLine l = {a, b, color}; 698 debugLines.push_back(l); 699 } 700 AddSprite(client::IImage * image,spades::Vector3 center,float radius,float rotation)701 void SWRenderer::AddSprite(client::IImage *image, spades::Vector3 center, float radius, 702 float rotation) { 703 SPADES_MARK_FUNCTION(); 704 EnsureInitialized(); 705 EnsureSceneStarted(); 706 707 if (!SphereFrustrumCull(center, radius * 1.5f)) 708 return; 709 710 SWImage *img = dynamic_cast<SWImage *>(image); 711 if (!img) { 712 SPInvalidArgument("image"); 713 } 714 715 sprites.push_back(Sprite()); 716 auto &spr = sprites.back(); 717 718 spr.img = img; 719 spr.center = center; 720 spr.radius = radius; 721 spr.rotation = rotation; 722 spr.color = drawColorAlphaPremultiplied; 723 } 724 AddLongSprite(client::IImage *,spades::Vector3 p1,spades::Vector3 p2,float radius)725 void SWRenderer::AddLongSprite(client::IImage *, spades::Vector3 p1, spades::Vector3 p2, 726 float radius) { 727 SPADES_MARK_FUNCTION(); 728 EnsureInitialized(); 729 EnsureSceneStarted(); 730 // TODO: long sprite 731 } 732 ConvertColor32(Vector4 col)733 static uint32_t ConvertColor32(Vector4 col) { 734 auto convertColor = [](float f) { 735 int i = static_cast<int>(f * 255.f + .5f); 736 return static_cast<uint32_t>(std::max(std::min(i, 255), 0)); 737 }; 738 uint32_t c; 739 c = convertColor(col.x); 740 c |= convertColor(col.y) << 8; 741 c |= convertColor(col.z) << 16; 742 c |= convertColor(col.w) << 24; 743 return c; 744 } 745 EndScene()746 void SWRenderer::EndScene() { 747 EnsureInitialized(); 748 EnsureSceneStarted(); 749 750 // clear scene 751 std::fill(fb->GetPixels(), fb->GetPixels() + fb->GetWidth() * fb->GetHeight(), 752 ConvertColor32(MakeVector4(fogColor.x, fogColor.y, fogColor.z, 1.f))); 753 std::fill(fb->GetPixels(), fb->GetPixels() + fb->GetWidth() * fb->GetHeight(), 754 0x7f7f7f); 755 756 // draw map 757 if (mapRenderer) { 758 // flat map renderer sends 'Update RLE' to map renderer. 759 // rendering map before this leads to the corrupted renderer image. 760 flatMapRenderer->Update(); 761 mapRenderer->Render(sceneDef, fb, depthBuffer.data()); 762 } 763 764 // draw models 765 for (auto &m : models) { 766 modelRenderer->Render(m.model, m.param); 767 } 768 models.clear(); 769 770 // deferred lighting 771 for (const auto &light : lights) { 772 ApplyDynamicLight<SWFeatureLevel::None>(light); 773 } 774 lights.clear(); 775 776 #if ENABLE_SSE2 777 if (static_cast<int>(featureLevel) >= static_cast<int>(SWFeatureLevel::SSE2)) 778 ApplyFog<SWFeatureLevel::SSE2>(); 779 else 780 #endif 781 ApplyFog<SWFeatureLevel::None>(); 782 783 // render sprites 784 { 785 imageRenderer->SetShaderType(SWImageRenderer::ShaderType::Sprite); 786 imageRenderer->SetMatrix(projectionViewMatrix); 787 imageRenderer->SetZRange(sceneDef.zNear, sceneDef.zFar); 788 789 auto right = sceneDef.viewAxis[0]; 790 auto up = sceneDef.viewAxis[1]; 791 for (std::size_t i = 0; i < sprites.size(); i++) { 792 auto &spr = sprites[i]; 793 float s = sinf(spr.rotation) * spr.radius; 794 float c = cosf(spr.rotation) * spr.radius; 795 auto trans = [s, c, &spr, right, up](float x, float y) { 796 auto v = spr.center; 797 v += right * (c * x - s * y); 798 v += up * (s * x + c * y); 799 return MakeVector4(v.x, v.y, v.z, 1.f); 800 }; 801 auto x1 = trans(-1.f, -1.f); 802 auto x2 = trans(1.f, -1.f); 803 auto x3 = trans(-1.f, 1.f); 804 auto x4 = trans(1.f, 1.f); 805 SWImageRenderer::Vertex v1, v2, v3; 806 v1.color = v2.color = v3.color = spr.color; 807 v1.uv = MakeVector2(0.f, 0.f); 808 v1.position = x1; 809 v2.uv = MakeVector2(1.f, 0.f); 810 v2.position = x2; 811 v3.uv = MakeVector2(0.f, 1.f); 812 v3.position = x3; 813 imageRenderer->DrawPolygon(spr.img, v1, v2, v3); 814 v1.uv = MakeVector2(1.f, 0.f); 815 v1.position = x2; 816 v2.uv = MakeVector2(1.f, 1.f); 817 v2.position = x4; 818 v3.uv = MakeVector2(0.f, 1.f); 819 v3.position = x3; 820 imageRenderer->DrawPolygon(spr.img, v1, v2, v3); 821 } 822 sprites.clear(); 823 } 824 825 // render debug lines 826 { 827 float cw = fb->GetWidth() * 0.5f; 828 float ch = fb->GetHeight() * 0.5f; 829 for (size_t i = 0; i < debugLines.size(); i++) { 830 auto &l = debugLines[i]; 831 auto v1 = projectionViewMatrix * l.v1; 832 auto v2 = projectionViewMatrix * l.v2; 833 if (v1.z < 0.001f || v2.z < 0.001f) 834 continue; 835 836 // SWRenderer's depth value is based on view Z coord 837 float d1 = Vector3::Dot(l.v1 - sceneDef.viewOrigin, sceneDef.viewAxis[2]); 838 float d2 = Vector3::Dot(l.v2 - sceneDef.viewOrigin, sceneDef.viewAxis[2]); 839 d1 = fastRcp(d1); 840 d2 = fastRcp(d2); 841 842 v1 *= fastRcp(v1.w); 843 v2 *= fastRcp(v2.w); 844 845 int x1 = static_cast<int>(v1.x * cw + cw); 846 int y1 = static_cast<int>(ch - v1.y * ch); 847 int x2 = static_cast<int>(v2.x * cw + cw); 848 int y2 = static_cast<int>(ch - v2.y * ch); 849 850 auto *fb = this->fb->GetPixels(); 851 auto *db = this->depthBuffer.data(); 852 int fw = this->fb->GetWidth(); 853 int fh = this->fb->GetHeight(); 854 855 uint32_t col; 856 col = ToFixed8(l.color.z) | (ToFixed8(l.color.y) << 8) | 857 (ToFixed8(l.color.x) << 16); 858 859 if (x1 == x2 && y1 == y2) { 860 if (x1 >= 0 && y1 >= 0 && x1 < fw && y1 < fh) { 861 d1 = fastRcp(d1); 862 if (d1 < db[x1 + y1 * fw]) { 863 fb[x1 + y1 * fw] = col; 864 } 865 } 866 continue; 867 } 868 869 if (abs(x2 - x1) > abs(y2 - y1)) { 870 if (x1 >= x2) { 871 std::swap(x1, x2); 872 std::swap(y1, y2); 873 std::swap(d1, d2); 874 } 875 int sgn = (y2 > y1) ? 1 : -1; 876 int cy = y1; 877 int dy = abs(y2 - y1); 878 int fract = 0; 879 int divisor = x2 - x1; 880 int minX = std::max(x1, 0); 881 int maxX = std::min(x2, fw - 1); 882 float depth = d1, ddepth = (d2 - d1) * fastRcp(x2 - x1 + 1); 883 if (x1 < 0) { 884 long long v = dy; 885 v *= -x1; 886 cy += sgn * (v / divisor); 887 fract = v % divisor; 888 depth -= x1 * ddepth; 889 } 890 fb += minX; 891 db += minX; 892 for (int x = minX; x <= maxX; x++) { 893 if (cy >= 0 && cy < fh) { 894 float d = fastRcp(depth); 895 if (d < db[fw * cy]) { 896 fb[fw * cy] = col; 897 } 898 } 899 fract += dy; 900 if (fract >= divisor) { 901 cy += sgn; 902 fract -= divisor; 903 } 904 depth += ddepth; 905 fb++; 906 db++; 907 } 908 } else { 909 if (y1 >= y2) { 910 std::swap(x1, x2); 911 std::swap(y1, y2); 912 std::swap(d1, d2); 913 } 914 int sgn = (x2 > x1) ? 1 : -1; 915 int cx = x1; 916 int dx = abs(x2 - x1); 917 int fract = 0; 918 int divisor = y2 - y1; 919 int minY = std::max(y1, 0); 920 int maxY = std::min(y2, fh - 1); 921 float depth = d1, ddepth = (d2 - d1) * fastRcp(y2 - y1 + 1); 922 if (y1 < 0) { 923 long long v = dx; 924 v *= -y1; 925 cx += sgn * (v / divisor); 926 fract = v % divisor; 927 depth -= x1 * ddepth; 928 } 929 fb += minY * fw; 930 db += minY * fw; 931 for (int y = minY; y <= maxY; y++) { 932 if (cx >= 0 && cx < fw) { 933 float d = fastRcp(depth); 934 if (d < db[cx]) { 935 fb[cx] = col; 936 } 937 } 938 fract += dx; 939 if (fract >= divisor) { 940 cx += sgn; 941 fract -= divisor; 942 } 943 depth += ddepth; 944 fb += fw; 945 db += fw; 946 } 947 } 948 } 949 debugLines.clear(); 950 } 951 952 // all objects were rendered 953 954 duringSceneRendering = false; 955 } 956 MultiplyScreenColor(spades::Vector3 v)957 void SWRenderer::MultiplyScreenColor(spades::Vector3 v) { EnsureSceneNotStarted(); } 958 SetColor(spades::Vector4 col)959 void SWRenderer::SetColor(spades::Vector4 col) { 960 EnsureValid(); 961 drawColorAlphaPremultiplied = col; 962 legacyColorPremultiply = true; 963 } 964 SetColorAlphaPremultiplied(spades::Vector4 col)965 void SWRenderer::SetColorAlphaPremultiplied(spades::Vector4 col) { 966 EnsureValid(); 967 legacyColorPremultiply = false; 968 drawColorAlphaPremultiplied = col; 969 } 970 DrawImage(client::IImage * image,const spades::Vector2 & outTopLeft)971 void SWRenderer::DrawImage(client::IImage *image, const spades::Vector2 &outTopLeft) { 972 SPADES_MARK_FUNCTION(); 973 974 if (image == nullptr) { 975 SPRaise("Size must be specified when null image is provided"); 976 } 977 978 DrawImage(image, 979 AABB2(outTopLeft.x, outTopLeft.y, image->GetWidth(), image->GetHeight()), 980 AABB2(0, 0, image->GetWidth(), image->GetHeight())); 981 } 982 DrawImage(client::IImage * image,const spades::AABB2 & outRect)983 void SWRenderer::DrawImage(client::IImage *image, const spades::AABB2 &outRect) { 984 SPADES_MARK_FUNCTION(); 985 986 DrawImage(image, outRect, 987 AABB2(0, 0, image ? image->GetWidth() : 0, image ? image->GetHeight() : 0)); 988 } 989 DrawImage(client::IImage * image,const spades::Vector2 & outTopLeft,const spades::AABB2 & inRect)990 void SWRenderer::DrawImage(client::IImage *image, const spades::Vector2 &outTopLeft, 991 const spades::AABB2 &inRect) { 992 SPADES_MARK_FUNCTION(); 993 994 DrawImage(image, 995 AABB2(outTopLeft.x, outTopLeft.y, inRect.GetWidth(), inRect.GetHeight()), 996 inRect); 997 } 998 DrawImage(client::IImage * image,const spades::AABB2 & outRect,const spades::AABB2 & inRect)999 void SWRenderer::DrawImage(client::IImage *image, const spades::AABB2 &outRect, 1000 const spades::AABB2 &inRect) { 1001 SPADES_MARK_FUNCTION(); 1002 1003 DrawImage(image, Vector2::Make(outRect.GetMinX(), outRect.GetMinY()), 1004 Vector2::Make(outRect.GetMaxX(), outRect.GetMinY()), 1005 Vector2::Make(outRect.GetMinX(), outRect.GetMaxY()), inRect); 1006 } 1007 DrawImage(client::IImage * image,const spades::Vector2 & outTopLeft,const spades::Vector2 & outTopRight,const spades::Vector2 & outBottomLeft,const spades::AABB2 & inRect)1008 void SWRenderer::DrawImage(client::IImage *image, const spades::Vector2 &outTopLeft, 1009 const spades::Vector2 &outTopRight, 1010 const spades::Vector2 &outBottomLeft, 1011 const spades::AABB2 &inRect) { 1012 SPADES_MARK_FUNCTION(); 1013 1014 EnsureValid(); 1015 EnsureSceneNotStarted(); 1016 1017 // d = a + (b - a) + (c - a) 1018 // = b + c - a 1019 Vector2 outBottomRight = outTopRight + outBottomLeft - outTopLeft; 1020 1021 SWImage *img = dynamic_cast<SWImage *>(image); 1022 if (img == nullptr && image != nullptr) { 1023 // not SWImage 1024 SPInvalidArgument("image"); 1025 } 1026 1027 imageRenderer->SetShaderType(SWImageRenderer::ShaderType::Image); 1028 1029 Vector4 col = drawColorAlphaPremultiplied; 1030 if (legacyColorPremultiply) { 1031 // in legacy mode, image color is 1032 // non alpha-premultiplied. 1033 col.x *= col.w; 1034 col.y *= col.w; 1035 col.z *= col.w; 1036 } 1037 1038 std::array<SWImageRenderer::Vertex, 4> vtx; 1039 vtx[0].color = col; 1040 vtx[1].color = col; 1041 vtx[2].color = col; 1042 vtx[3].color = col; 1043 1044 vtx[0].position = MakeVector4(outTopLeft.x, outTopLeft.y, 1.f, 1.f); 1045 vtx[1].position = MakeVector4(outTopRight.x, outTopRight.y, 1.f, 1.f); 1046 vtx[2].position = MakeVector4(outBottomLeft.x, outBottomLeft.y, 1.f, 1.f); 1047 vtx[3].position = MakeVector4(outBottomRight.x, outBottomRight.y, 1.f, 1.f); 1048 if (img) { 1049 Vector2 scl = {img->GetInvWidth(), img->GetInvHeight()}; 1050 vtx[0].uv = MakeVector2(inRect.min.x, inRect.min.y) * scl; 1051 vtx[1].uv = MakeVector2(inRect.max.x, inRect.min.y) * scl; 1052 vtx[2].uv = MakeVector2(inRect.min.x, inRect.max.y) * scl; 1053 vtx[3].uv = MakeVector2(inRect.max.x, inRect.max.y) * scl; 1054 } 1055 1056 imageRenderer->DrawPolygon(img, vtx[0], vtx[1], vtx[2]); 1057 imageRenderer->DrawPolygon(img, vtx[1], vtx[3], vtx[2]); 1058 } 1059 DrawFlatGameMap(const spades::AABB2 & outRect,const spades::AABB2 & inRect)1060 void SWRenderer::DrawFlatGameMap(const spades::AABB2 &outRect, 1061 const spades::AABB2 &inRect) { 1062 SPADES_MARK_FUNCTION(); 1063 EnsureValid(); 1064 EnsureSceneNotStarted(); 1065 1066 if (!flatMapRenderer) { 1067 SPRaise("DrawFlatGameMap was called without an active map."); 1068 } 1069 1070 DrawImage(flatMapRenderer->GetImage(), outRect, inRect); 1071 } 1072 FrameDone()1073 void SWRenderer::FrameDone() { 1074 SPADES_MARK_FUNCTION(); 1075 EnsureValid(); 1076 EnsureSceneNotStarted(); 1077 } 1078 Flip()1079 void SWRenderer::Flip() { 1080 SPADES_MARK_FUNCTION(); 1081 EnsureValid(); 1082 EnsureSceneNotStarted(); 1083 1084 if (r_swStatistics) { 1085 double dur = renderStopwatch.GetTime(); 1086 SPLog("==== SWRenderer Statistics ===="); 1087 SPLog("Elapsed Time: %.3fus", dur * 1000000.0); 1088 SPLog("Polygon pixels drawn: %llu", imageRenderer->GetPixelsDrawn()); 1089 } 1090 1091 imageRenderer->ResetPixelStatistics(); 1092 renderStopwatch.Reset(); 1093 /* 1094 { 1095 uint32_t rdb = mt_engine(); 1096 uint32_t *ptr = fb->GetPixels(); 1097 for(int pixels = fb->GetWidth() * fb->GetHeight() / 10; 1098 pixels > 0; pixels--) { 1099 *ptr = ((rdb >> 16) & 0xff) * 0x10101; 1100 rdb = (rdb * 34563511) ^ 1245525; 1101 rdb += (pixels >> 10) + 1; 1102 ptr++; 1103 } 1104 } 1105 */ 1106 port->Swap(); 1107 1108 // next frame's framebuffer 1109 SetFramebuffer(port->GetFramebuffer()); 1110 } 1111 ReadBitmap()1112 Bitmap *SWRenderer::ReadBitmap() { 1113 SPADES_MARK_FUNCTION(); 1114 EnsureValid(); 1115 EnsureSceneNotStarted(); 1116 1117 int w = fb->GetWidth(); 1118 int h = fb->GetHeight(); 1119 uint32_t *inPix = fb->GetPixels(); 1120 Bitmap *bm = new Bitmap(w, h); 1121 uint32_t *outPix = bm->GetPixels(); 1122 for (int y = 0; y < h; y++) { 1123 uint32_t *src = inPix + y * w; 1124 uint32_t *dest = outPix + (h - 1 - y) * w; 1125 for (int x = w; x != 0; x--) { 1126 auto c = *(src++); 1127 c = 0xff000000 | (c & 0xff00) | ((c & 0xff) << 16) | ((c & 0xff0000) >> 16); 1128 *(dest++) = c; 1129 } 1130 } 1131 return bm; 1132 } 1133 ScreenWidth()1134 float SWRenderer::ScreenWidth() { 1135 SPADES_MARK_FUNCTION(); 1136 EnsureValid(); 1137 return static_cast<float>(fb->GetWidth()); 1138 } 1139 ScreenHeight()1140 float SWRenderer::ScreenHeight() { 1141 SPADES_MARK_FUNCTION(); 1142 EnsureValid(); 1143 return static_cast<float>(fb->GetHeight()); 1144 } 1145 BoxFrustrumCull(const AABB3 & box)1146 bool SWRenderer::BoxFrustrumCull(const AABB3 &box) { 1147 /*if(IsRenderingMirror()) { 1148 // reflect 1149 AABB3 bx = box; 1150 std::swap(bx.min.z, bx.max.z); 1151 bx.min.z = 63.f * 2.f - bx.min.z; 1152 bx.max.z = 63.f * 2.f - bx.max.z; 1153 return PlaneCullTest(frustrum[0], bx) && 1154 PlaneCullTest(frustrum[1], bx) && 1155 PlaneCullTest(frustrum[2], bx) && 1156 PlaneCullTest(frustrum[3], bx) && 1157 PlaneCullTest(frustrum[4], bx) && 1158 PlaneCullTest(frustrum[5], bx); 1159 }*/ 1160 return PlaneCullTest(frustrum[0], box) && PlaneCullTest(frustrum[1], box) && 1161 PlaneCullTest(frustrum[2], box) && PlaneCullTest(frustrum[3], box) && 1162 PlaneCullTest(frustrum[4], box) && PlaneCullTest(frustrum[5], box); 1163 } SphereFrustrumCull(const Vector3 & center,float radius)1164 bool SWRenderer::SphereFrustrumCull(const Vector3 ¢er, float radius) { 1165 /*if(IsRenderingMirror()) { 1166 // reflect 1167 Vector3 vx = center; 1168 vx.z = 63.f * 2.f - vx.z; 1169 for(int i = 0; i < 6; i++){ 1170 if(frustrum[i].GetDistanceTo(vx) < -radius) 1171 return false; 1172 } 1173 return true; 1174 }*/ 1175 for (int i = 0; i < 6; i++) { 1176 if (frustrum[i].GetDistanceTo(center) < -radius) 1177 return false; 1178 } 1179 return true; 1180 } 1181 GameMapChanged(int x,int y,int z,client::GameMap * map)1182 void SWRenderer::GameMapChanged(int x, int y, int z, client::GameMap *map) { 1183 if (map != this->map) { 1184 return; 1185 } 1186 1187 flatMapRenderer->SetNeedsUpdate(x, y); 1188 } 1189 } 1190 } 1191