Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/game/StarWorldClient.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/game/StarWorldClient.cpp')
-rw-r--r--source/game/StarWorldClient.cpp184
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>());