diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-29 10:11:19 +1000 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-29 10:11:19 +1000 |
commit | 624c7aaaf192f2e87081a241123a8507a4718ba3 (patch) | |
tree | a54b09902da8d724f3ba740a215fd53d8a861fd9 /source/game/StarWorldClient.cpp | |
parent | 9d67cda97fc327ca3c53e044a897fbfb196104c4 (diff) |
Move lighting calculation to separate thread
Diffstat (limited to 'source/game/StarWorldClient.cpp')
-rw-r--r-- | source/game/StarWorldClient.cpp | 184 |
1 files changed, 121 insertions, 63 deletions
diff --git a/source/game/StarWorldClient.cpp b/source/game/StarWorldClient.cpp index 3a3fe39..b0b2c1e 100644 --- a/source/game/StarWorldClient.cpp +++ b/source/game/StarWorldClient.cpp @@ -34,6 +34,7 @@ WorldClient::WorldClient(PlayerPtr mainPlayer) { m_currentStep = 0; m_currentServerStep = 0.0; m_fullBright = false; + m_asyncLighting = true; m_worldDimTimer = GameTimer(m_clientConfig.getFloat("worldDimTime")); m_worldDimTimer.setDone(); m_worldDimLevel = 0.0f; @@ -77,10 +78,20 @@ WorldClient::WorldClient(PlayerPtr mainPlayer) { m_altMusicTrack.setVolume(0, 0, 0); m_altMusicActive = false; + m_stopLightingThread = false; + m_lightingThread = Thread::invoke("WorldClient::lightingMain", mem_fn(&WorldClient::lightingMain), this); + m_renderData = nullptr; + clearWorld(); } WorldClient::~WorldClient() { + m_stopLightingThread = true; + { + MutexLocker locker(m_lightingMutex); + m_lightingCond.broadcast(); + } + clearWorld(); } @@ -344,6 +355,84 @@ void WorldClient::render(WorldRenderData& renderData, unsigned bufferTiles) { renderData.geometry = m_geometry; + ClientRenderCallback lightingRenderCallback; + m_entityMap->forAllEntities([&](EntityPtr const& entity) { + if (m_startupHiddenEntities.contains(entity->entityId())) + return; + + entity->renderLightSources(&lightingRenderCallback); + }); + + renderLightSources = move(lightingRenderCallback.lightSources); + + RectI window = m_clientState.window(); + RectI tileRange = window.padded(bufferTiles); + RectI lightRange = window.padded(1); + //Kae: Padded by one to fix light spread issues at the edges of the frame. + + renderData.tileMinPosition = tileRange.min(); + renderData.lightMinPosition = lightRange.min(); + + Vec2U lightSize(lightRange.size()); + + renderData.tileLightMap.reset(lightSize, PixelFormat::RGBA32); + renderData.tileLightMap.fill(Vec4B::filled(0)); + + if (m_fullBright) { + renderData.lightMap.reset(lightSize, PixelFormat::RGB24); + renderData.lightMap.fill(Vec3B(255, 255, 255)); + } else { + m_lightingCalculator.begin(lightRange); + + Vec3F environmentLight = m_sky->environmentLight().toRgbF(); + float undergroundLevel = m_worldTemplate->undergroundLevel(); + auto liquidsDatabase = Root::singleton().liquidsDatabase(); + auto materialDatabase = Root::singleton().materialDatabase(); + + // Each column in tileEvalColumns is guaranteed to be no larger than the sector size. + m_tileArray->tileEvalColumns(m_lightingCalculator.calculationRegion(), [&](Vec2I const& pos, ClientTile const* column, size_t ySize) { + size_t baseIndex = m_lightingCalculator.baseIndexFor(pos); + for (size_t y = 0; y < ySize; ++y) { + auto& tile = column[y]; + + Vec3F light; + if (tile.foreground != EmptyMaterialId || tile.foregroundMod != NoModId) + light += materialDatabase->radiantLight(tile.foreground, tile.foregroundMod); + + if (tile.liquid.liquid != EmptyLiquidId && tile.liquid.level != 0.0f) + light += liquidsDatabase->radiantLight(tile.liquid); + if (tile.foregroundLightTransparent) { + if (tile.background != EmptyMaterialId || tile.backgroundMod != NoModId) + light += materialDatabase->radiantLight(tile.background, tile.backgroundMod); + if (tile.backgroundLightTransparent && pos[1] + y > undergroundLevel) + light += environmentLight; + } + m_lightingCalculator.setCellIndex(baseIndex + y, move(light), !tile.foregroundLightTransparent); + } + }); + + for (auto const& light : renderLightSources) { + Vec2F position = m_geometry.nearestTo(Vec2F(m_lightingCalculator.calculationRegion().min()), light.position); + if (light.pointLight) + m_lightingCalculator.addPointLight(position, Color::v3bToFloat(light.color), light.pointBeam, light.beamAngle, light.beamAmbience); + else + m_lightingCalculator.addSpreadLight(position, Color::v3bToFloat(light.color)); + } + + for (auto const& lightPair : m_particles->lightSources()) { + Vec2F position = m_geometry.nearestTo(Vec2F(m_lightingCalculator.calculationRegion().min()), lightPair.first); + m_lightingCalculator.addSpreadLight(position, Color::v3bToFloat(lightPair.second)); + } + + if (m_asyncLighting) { + m_renderData = &renderData; + m_lightingCond.signal(); + } + else { + m_lightingCalculator.calculate(renderData.lightMap); + } + } + float pulseAmount = Root::singleton().assets()->json("/highlights.config:interactivePulseAmount").toFloat(); float pulseRate = Root::singleton().assets()->json("/highlights.config:interactivePulseRate").toFloat(); float pulseLevel = 1 - pulseAmount * 0.5 * (sin(2 * Constants::pi * pulseRate * Time::monotonicMilliseconds() / 1000.0) + 1); @@ -368,6 +457,7 @@ void WorldClient::render(WorldRenderData& renderData, unsigned bufferTiles) { return; ClientRenderCallback renderCallback; + entity->render(&renderCallback); EntityDrawables ed; @@ -397,8 +487,6 @@ void WorldClient::render(WorldRenderData& renderData, unsigned bufferTiles) { } renderData.entityDrawables.append(move(ed)); - renderLightSources.appendAll(move(renderCallback.lightSources)); - if (directives) { int directiveIndex = unsigned(entity->entityId()) % directives->size(); for (auto& p : renderCallback.particles) @@ -414,14 +502,6 @@ void WorldClient::render(WorldRenderData& renderData, unsigned bufferTiles) { return a->entityId() < b->entityId(); }); - RectI window = m_clientState.window(); - RectI tileRange = window.padded(bufferTiles); - RectI lightRange = window.padded(1); - //Kae: Padded by one to fix light spread issues at the edges of the frame. - - renderData.tileMinPosition = tileRange.min(); - renderData.lightMinPosition = lightRange.min(); - m_tileArray->tileEachTo(renderData.tiles, tileRange, [](RenderTile& renderTile, Vec2I const&, ClientTile const& clientTile) { renderTile.foreground = clientTile.foreground; renderTile.foregroundMod = clientTile.foregroundMod; @@ -445,57 +525,6 @@ void WorldClient::render(WorldRenderData& renderData, unsigned bufferTiles) { renderTile.liquidLevel = floatToByte(clientTile.liquid.level); }); - Vec2U lightSize(lightRange.size()); - - if (m_fullBright) { - renderData.lightMap.reset(lightSize, PixelFormat::RGB24); - renderData.lightMap.fill(Vec3B(255, 255, 255)); - } else { - m_lightingCalculator.begin(lightRange); - - Vec3F environmentLight = m_sky->environmentLight().toRgbF(); - float undergroundLevel = m_worldTemplate->undergroundLevel(); - auto liquidsDatabase = Root::singleton().liquidsDatabase(); - auto materialDatabase = Root::singleton().materialDatabase(); - - // Each column in tileEvalColumns is guaranteed to be no larger than the sector size. - m_tileArray->tileEvalColumns(m_lightingCalculator.calculationRegion(), [&](Vec2I const& pos, ClientTile const* column, size_t ySize) { - size_t baseIndex = m_lightingCalculator.baseIndexFor(pos); - for (size_t y = 0; y < ySize; ++y) { - auto& tile = column[y]; - - Vec3F light; - if (tile.foreground != EmptyMaterialId || tile.foregroundMod != NoModId) - light += materialDatabase->radiantLight(tile.foreground, tile.foregroundMod); - - if (tile.liquid.liquid != EmptyLiquidId && tile.liquid.level != 0.0f) - light += liquidsDatabase->radiantLight(tile.liquid); - if (tile.foregroundLightTransparent) { - if (tile.background != EmptyMaterialId || tile.backgroundMod != NoModId) - light += materialDatabase->radiantLight(tile.background, tile.backgroundMod); - if (tile.backgroundLightTransparent && pos[1] + y > undergroundLevel) - light += environmentLight; - } - m_lightingCalculator.setCellIndex(baseIndex + y, move(light), !tile.foregroundLightTransparent); - } - }); - - for (auto const& light : renderLightSources) { - Vec2F position = m_geometry.nearestTo(Vec2F(m_lightingCalculator.calculationRegion().min()), light.position); - if (light.pointLight) - m_lightingCalculator.addPointLight(position, Color::v3bToFloat(light.color), light.pointBeam, light.beamAngle, light.beamAmbience); - else - m_lightingCalculator.addSpreadLight(position, Color::v3bToFloat(light.color)); - } - - for (auto const& lightPair : m_particles->lightSources()) { - Vec2F position = m_geometry.nearestTo(Vec2F(m_lightingCalculator.calculationRegion().min()), lightPair.first); - m_lightingCalculator.addSpreadLight(position, Color::v3bToFloat(lightPair.second)); - } - - m_lightingCalculator.calculate(renderData.lightMap); - } - for (auto const& previewTile : previewTiles) { Vec2I tileArrayPos = m_geometry.diff(previewTile.position, renderData.tileMinPosition); if (tileArrayPos[0] >= 0 && tileArrayPos[0] < (int)renderData.tiles.size(0) && tileArrayPos[1] >= 0 && tileArrayPos[1] < (int)renderData.tiles.size(1)) { @@ -524,8 +553,8 @@ void WorldClient::render(WorldRenderData& renderData, unsigned bufferTiles) { if (previewTile.updateLight) { Vec2I lightArrayPos = m_geometry.diff(previewTile.position, renderData.lightMinPosition); - if (lightArrayPos[0] >= 0 && lightArrayPos[0] < (int)renderData.lightMap.width() && lightArrayPos[1] >= 0 && lightArrayPos[1] < (int)renderData.lightMap.height()) - renderData.lightMap.set(Vec2U(lightArrayPos), previewTile.light); + if (lightArrayPos[0] >= 0 && lightArrayPos[0] < (int)renderData.tileLightMap.width() && lightArrayPos[1] >= 0 && lightArrayPos[1] < (int)renderData.tileLightMap.height()) + renderData.tileLightMap.set(Vec2U(lightArrayPos), previewTile.light); } } @@ -634,6 +663,11 @@ bool WorldClient::toggleFullbright() { return m_fullBright; } +bool WorldClient::toggleAsyncLighting() { + m_asyncLighting = !m_asyncLighting; + return m_asyncLighting; +} + bool WorldClient::toggleCollisionDebug() { m_collisionDebug = !m_collisionDebug; return m_collisionDebug; @@ -1154,6 +1188,10 @@ void WorldClient::collectLiquid(List<Vec2I> const& tilePositions, LiquidId liqui m_outgoingPackets.append(make_shared<CollectLiquidPacket>(tilePositions, liquidId)); } +void WorldClient::waitForLighting() { + MutexLocker lock(m_lightingMutex); +} + bool WorldClient::isTileProtected(Vec2I const& pos) const { if (!inWorld()) return true; @@ -1401,6 +1439,26 @@ RpcPromise<InteractAction> WorldClient::interact(InteractRequest const& request) return pair.first; } +void WorldClient::lightingMain() { + while (true) { + if (m_stopLightingThread) + return; + + MutexLocker locker(m_lightingMutex); + + if (m_renderData) { + m_lightingCalculator.calculate(m_renderData->lightMap); + m_renderData = nullptr; + } + + m_lightingCond.wait(m_lightingMutex); + continue; + + locker.unlock(); + Thread::yield(); + } +} + void WorldClient::initWorld(WorldStartPacket const& startPacket) { clearWorld(); m_outgoingPackets.append(make_shared<WorldStartAcknowledgePacket>()); |