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

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--assets/opensb/rendering/opengl20.config6
-rw-r--r--assets/opensb/rendering/opengl20.frag10
-rw-r--r--source/base/StarCellularLighting.cpp33
-rw-r--r--source/base/StarCellularLighting.hpp4
-rw-r--r--source/client/StarClientApplication.cpp31
-rw-r--r--source/frontend/StarClientCommandProcessor.cpp7
-rw-r--r--source/frontend/StarClientCommandProcessor.hpp1
-rw-r--r--source/game/StarEntityMap.cpp1
-rw-r--r--source/game/StarMonster.cpp10
-rw-r--r--source/game/StarMonster.hpp2
-rw-r--r--source/game/StarNpc.cpp5
-rw-r--r--source/game/StarNpc.hpp2
-rw-r--r--source/game/StarObject.cpp7
-rw-r--r--source/game/StarObject.hpp2
-rw-r--r--source/game/StarPlayer.cpp5
-rw-r--r--source/game/StarPlayer.hpp2
-rw-r--r--source/game/StarPlayerDeployment.cpp5
-rw-r--r--source/game/StarPlayerDeployment.hpp1
-rw-r--r--source/game/StarProjectile.cpp10
-rw-r--r--source/game/StarProjectile.hpp1
-rw-r--r--source/game/StarVehicle.cpp7
-rw-r--r--source/game/StarVehicle.hpp2
-rw-r--r--source/game/StarWorldClient.cpp184
-rw-r--r--source/game/StarWorldClient.hpp14
-rw-r--r--source/game/StarWorldRenderData.hpp2
-rw-r--r--source/game/interfaces/StarChattyEntity.hpp2
-rw-r--r--source/game/interfaces/StarEntity.cpp2
-rw-r--r--source/game/interfaces/StarEntity.hpp2
-rw-r--r--source/rendering/StarTilePainter.cpp5
-rw-r--r--source/rendering/StarWorldPainter.cpp18
-rw-r--r--source/rendering/StarWorldPainter.hpp3
31 files changed, 287 insertions, 99 deletions
diff --git a/assets/opensb/rendering/opengl20.config b/assets/opensb/rendering/opengl20.config
index 923578c..70ff6c7 100644
--- a/assets/opensb/rendering/opengl20.config
+++ b/assets/opensb/rendering/opengl20.config
@@ -28,6 +28,12 @@
"textureSizeUniform" : "lightMapSize",
"textureAddressing" : "clamp",
"textureFiltering" : "linear"
+ },
+ "tileLightMap" : {
+ "textureUniform" : "tileLightMap",
+ "textureSizeUniform" : "tileLightMapSize",
+ "textureAddressing" : "clamp",
+ "textureFiltering" : "linear"
}
},
diff --git a/assets/opensb/rendering/opengl20.frag b/assets/opensb/rendering/opengl20.frag
index 92a121f..a57c029 100644
--- a/assets/opensb/rendering/opengl20.frag
+++ b/assets/opensb/rendering/opengl20.frag
@@ -6,7 +6,9 @@ uniform sampler2D texture2;
uniform sampler2D texture3;
uniform bool lightMapEnabled;
uniform vec2 lightMapSize;
+uniform vec2 tileLightMapSize;
uniform sampler2D lightMap;
+uniform sampler2D tileLightMap;
uniform float lightMapMultiplier;
varying vec2 fragmentTextureCoordinate;
@@ -53,6 +55,12 @@ vec4 bicubicSample(sampler2D texture, vec2 texcoord, vec2 texscale) {
mix(sample1, sample0, sx), sy);
}
+vec4 sampleLightMap(vec2 texcoord, vec2 texscale) {
+ vec4 a = bicubicSample(lightMap, texcoord, texscale);
+ vec4 b = bicubicSample(tileLightMap, texcoord, texscale);
+ return mix(a, b, b.z);
+}
+
void main() {
vec4 texColor;
if (fragmentTextureIndex > 2.9) {
@@ -70,6 +78,6 @@ void main() {
vec4 finalColor = texColor * fragmentColor;
float finalLightMapMultiplier = fragmentLightMapMultiplier * lightMapMultiplier;
if (lightMapEnabled && finalLightMapMultiplier > 0.0)
- finalColor.rgb *= bicubicSample(lightMap, fragmentLightMapCoordinate, 1.0 / lightMapSize).rgb * finalLightMapMultiplier;
+ finalColor.rgb *= sampleLightMap(fragmentLightMapCoordinate, 1.0 / lightMapSize).rgb * finalLightMapMultiplier;
gl_FragColor = finalColor;
} \ No newline at end of file
diff --git a/source/base/StarCellularLighting.cpp b/source/base/StarCellularLighting.cpp
index c29e78e..0578961 100644
--- a/source/base/StarCellularLighting.cpp
+++ b/source/base/StarCellularLighting.cpp
@@ -94,6 +94,39 @@ void CellularLightingCalculator::calculate(Image& output) {
}
}
+void CellularLightingCalculator::setupImage(Image& image, PixelFormat format) const {
+ Vec2S arrayMin = Vec2S(m_queryRegion.min() - m_calculationRegion.min());
+ Vec2S arrayMax = Vec2S(m_queryRegion.max() - m_calculationRegion.min());
+
+ image.reset(arrayMax[0] - arrayMin[0], arrayMax[1] - arrayMin[1], format);
+}
+
+ThreadFunction<Image> CellularLightingCalculator::calculateAsync() {
+ return ThreadFunction<Image>([this]() {
+ Vec2S arrayMin = Vec2S(m_queryRegion.min() - m_calculationRegion.min());
+ Vec2S arrayMax = Vec2S(m_queryRegion.max() - m_calculationRegion.min());
+
+ if (m_monochrome)
+ m_lightArray.right().calculate(arrayMin[0], arrayMin[1], arrayMax[0], arrayMax[1]);
+ else
+ m_lightArray.left().calculate(arrayMin[0], arrayMin[1], arrayMax[0], arrayMax[1]);
+
+ Image output;
+ setupImage(output, PixelFormat::RGB24);
+
+ for (size_t x = arrayMin[0]; x < arrayMax[0]; ++x) {
+ for (size_t y = arrayMin[1]; y < arrayMax[1]; ++y) {
+ if (m_monochrome)
+ output.set24(x - arrayMin[0], y - arrayMin[1], Color::grayf(m_lightArray.right().getLight(x, y)).toRgb());
+ else
+ output.set24(x - arrayMin[0], y - arrayMin[1], Color::v3fToByte(m_lightArray.left().getLight(x, y)));
+ }
+ }
+
+ return output;
+ }, "CellularLightingCalculator Thread");
+}
+
void CellularLightIntensityCalculator::setParameters(Json const& config) {
m_lightArray.setParameters(
config.getInt("spreadPasses"),
diff --git a/source/base/StarCellularLighting.hpp b/source/base/StarCellularLighting.hpp
index 7579a63..54be414 100644
--- a/source/base/StarCellularLighting.hpp
+++ b/source/base/StarCellularLighting.hpp
@@ -8,6 +8,7 @@
#include "StarColor.hpp"
#include "StarInterpolation.hpp"
#include "StarCellularLightArray.hpp"
+#include "StarThread.hpp"
namespace Star {
@@ -44,6 +45,9 @@ public:
// the call to 'begin', and formatted as RGB24.
void calculate(Image& output);
+ void setupImage(Image& image, PixelFormat format = PixelFormat::RGB24) const;
+
+ ThreadFunction<Image> calculateAsync();
private:
Json m_config;
bool m_monochrome;
diff --git a/source/client/StarClientApplication.cpp b/source/client/StarClientApplication.cpp
index a76a527..be32e58 100644
--- a/source/client/StarClientApplication.cpp
+++ b/source/client/StarClientApplication.cpp
@@ -361,18 +361,41 @@ void ClientApplication::render() {
m_cinematicOverlay->render();
} else if (m_state > MainAppState::Title) {
- if (auto worldClient = m_universeClient->worldClient()) {
- if (auto renderer = Application::renderer())
+ WorldClientPtr worldClient = m_universeClient->worldClient();
+ RendererPtr renderer = Application::renderer();
+ if (worldClient) {
+ if (renderer)
renderer->setEffectParameter("lightMapEnabled", true);
worldClient->render(m_renderData, TilePainter::BorderTileSize);
- m_worldPainter->render(m_renderData);
+ // Might have to move lightmap adjustment code back into worldPainter->render
+ // eventually, can't be bothered to remove the passed lambda yet
+ m_worldPainter->render(m_renderData, [&]() { worldClient->waitForLighting(); });
m_mainInterface->renderInWorldElements();
- if (auto renderer = Application::renderer())
+ if (renderer)
renderer->setEffectParameter("lightMapEnabled", false);
}
m_mainInterface->render();
m_cinematicOverlay->render();
+ if (worldClient && renderer) {
+ worldClient->waitForLighting();
+
+ if (m_renderData.isFullbright) {
+ renderer->setEffectTexture("lightMap", Image::filled(Vec2U(1, 1), { 255, 255, 255, 255 }, PixelFormat::RGB24));
+ renderer->setEffectTexture("tileLightMap", Image::filled(Vec2U(1, 1), { 0, 0, 0, 0 }, PixelFormat::RGBA32));
+ renderer->setEffectParameter("lightMapMultiplier", 1.0f);
+ }
+ else {
+ m_worldPainter->adjustLighting(m_renderData);
+
+ WorldCamera const& camera = m_worldPainter->camera();
+ renderer->setEffectParameter("lightMapMultiplier", assets->json("/rendering.config:lightMapMultiplier").toFloat());
+ renderer->setEffectParameter("lightMapScale", Vec2F::filled(TilePixels * camera.pixelRatio()));
+ renderer->setEffectParameter("lightMapOffset", camera.worldToScreen(Vec2F(m_renderData.lightMinPosition)));
+ renderer->setEffectTexture("lightMap", m_renderData.lightMap);
+ renderer->setEffectTexture("tileLightMap", m_renderData.tileLightMap);
+ }
+ }
}
if (!m_errorScreen->accepted())
diff --git a/source/frontend/StarClientCommandProcessor.cpp b/source/frontend/StarClientCommandProcessor.cpp
index f006d8e..b6ab53c 100644
--- a/source/frontend/StarClientCommandProcessor.cpp
+++ b/source/frontend/StarClientCommandProcessor.cpp
@@ -24,6 +24,7 @@ ClientCommandProcessor::ClientCommandProcessor(UniverseClientPtr universeClient,
{"debug", bind(&ClientCommandProcessor::debug, this)},
{"boxes", bind(&ClientCommandProcessor::boxes, this)},
{"fullbright", bind(&ClientCommandProcessor::fullbright, this)},
+ {"asyncLighting", bind(&ClientCommandProcessor::asyncLighting, this)},
{"setGravity", bind(&ClientCommandProcessor::setGravity, this, _1)},
{"resetGravity", bind(&ClientCommandProcessor::resetGravity, this)},
{"fixedCamera", bind(&ClientCommandProcessor::fixedCamera, this)},
@@ -151,6 +152,12 @@ String ClientCommandProcessor::fullbright() {
? "enabled" : "disabled");
}
+String ClientCommandProcessor::asyncLighting() {
+ return strf("Asynchronous render lighting {}",
+ m_universeClient->worldClient()->toggleAsyncLighting()
+ ? "enabled" : "disabled");
+}
+
String ClientCommandProcessor::setGravity(StringList const& arguments) {
if (!adminCommandAllowed())
return "You must be an admin to use this command.";
diff --git a/source/frontend/StarClientCommandProcessor.hpp b/source/frontend/StarClientCommandProcessor.hpp
index 9b0219b..3093450 100644
--- a/source/frontend/StarClientCommandProcessor.hpp
+++ b/source/frontend/StarClientCommandProcessor.hpp
@@ -31,6 +31,7 @@ private:
String debug();
String boxes();
String fullbright();
+ String asyncLighting();
String setGravity(StringList const& arguments);
String resetGravity();
String fixedCamera();
diff --git a/source/game/StarEntityMap.cpp b/source/game/StarEntityMap.cpp
index a3844dc..66d09a5 100644
--- a/source/game/StarEntityMap.cpp
+++ b/source/game/StarEntityMap.cpp
@@ -189,6 +189,7 @@ void EntityMap::forAllEntities(EntityCallback const& callback, function<bool(Ent
// Even if there is no sort order, we still copy pointers to a temporary
// list, so that it is safe to call addEntity from the callback.
List<EntityPtr const*> allEntities;
+ allEntities.reserve(m_spatialMap.size());
for (auto const& entry : m_spatialMap.entries())
allEntities.append(&entry.second.value);
diff --git a/source/game/StarMonster.cpp b/source/game/StarMonster.cpp
index e9d78f8..b91607a 100644
--- a/source/game/StarMonster.cpp
+++ b/source/game/StarMonster.cpp
@@ -494,10 +494,7 @@ void Monster::render(RenderCallback* renderCallback) {
renderCallback->addAudios(m_networkedAnimatorDynamicTarget.pullNewAudios());
renderCallback->addParticles(m_networkedAnimatorDynamicTarget.pullNewParticles());
- renderCallback->addLightSources(m_networkedAnimator.lightSources(position()));
-
renderCallback->addDrawables(m_statusController->drawables(), m_monsterVariant.renderLayer);
- renderCallback->addLightSources(m_statusController->lightSources());
renderCallback->addParticles(m_statusController->pullNewParticles());
renderCallback->addAudios(m_statusController->pullNewAudios());
@@ -505,11 +502,16 @@ void Monster::render(RenderCallback* renderCallback) {
for (auto drawablePair : m_scriptedAnimator.drawables())
renderCallback->addDrawable(drawablePair.first, drawablePair.second.value(m_monsterVariant.renderLayer));
- renderCallback->addLightSources(m_scriptedAnimator.lightSources());
renderCallback->addAudios(m_scriptedAnimator.pullNewAudios());
renderCallback->addParticles(m_scriptedAnimator.pullNewParticles());
}
+void Monster::renderLightSources(RenderCallback* renderCallback) {
+ renderCallback->addLightSources(m_networkedAnimator.lightSources(position()));
+ renderCallback->addLightSources(m_statusController->lightSources());
+ renderCallback->addLightSources(m_scriptedAnimator.lightSources());
+}
+
void Monster::setPosition(Vec2F const& pos) {
m_movementController->setPosition(pos);
}
diff --git a/source/game/StarMonster.hpp b/source/game/StarMonster.hpp
index ea95521..06ca26e 100644
--- a/source/game/StarMonster.hpp
+++ b/source/game/StarMonster.hpp
@@ -92,6 +92,8 @@ public:
void render(RenderCallback* renderCallback) override;
+ void renderLightSources(RenderCallback* renderCallback) override;
+
void setPosition(Vec2F const& pos);
Maybe<Json> receiveMessage(ConnectionId sendingConnection, String const& message, JsonArray const& args) override;
diff --git a/source/game/StarNpc.cpp b/source/game/StarNpc.cpp
index 75311a6..1d8a80b 100644
--- a/source/game/StarNpc.cpp
+++ b/source/game/StarNpc.cpp
@@ -464,7 +464,6 @@ void Npc::render(RenderCallback* renderCallback) {
renderCallback->addAudios(m_statusController->pullNewAudios());
renderCallback->addParticles(m_npcVariant.splashConfig.doSplash(position(), m_movementController->velocity(), world()));
- renderCallback->addLightSources(lightSources());
m_tools->render(renderCallback, inToolRange(), m_shifting.get(), renderLayer);
@@ -473,6 +472,10 @@ void Npc::render(RenderCallback* renderCallback) {
m_effectEmitter->render(renderCallback);
}
+void Npc::renderLightSources(RenderCallback* renderCallback) {
+ renderCallback->addLightSources(lightSources());
+}
+
void Npc::setPosition(Vec2F const& pos) {
m_movementController->setPosition(pos);
}
diff --git a/source/game/StarNpc.hpp b/source/game/StarNpc.hpp
index 193ffce..7c6c5a9 100644
--- a/source/game/StarNpc.hpp
+++ b/source/game/StarNpc.hpp
@@ -94,6 +94,8 @@ public:
void render(RenderCallback* renderCallback) override;
+ void renderLightSources(RenderCallback* renderCallback) override;
+
void setPosition(Vec2F const& pos);
float maxHealth() const override;
diff --git a/source/game/StarObject.cpp b/source/game/StarObject.cpp
index 1dfc89d..1b55ac0 100644
--- a/source/game/StarObject.cpp
+++ b/source/game/StarObject.cpp
@@ -394,7 +394,6 @@ void Object::update(uint64_t) {
void Object::render(RenderCallback* renderCallback) {
renderParticles(renderCallback);
- renderLights(renderCallback);
renderSounds(renderCallback);
for (auto const& imageKeyPair : m_imageKeys)
@@ -412,11 +411,15 @@ void Object::render(RenderCallback* renderCallback) {
for (auto drawablePair : m_scriptedAnimator.drawables())
renderCallback->addDrawable(drawablePair.first, drawablePair.second.value(renderLayer()));
- renderCallback->addLightSources(m_scriptedAnimator.lightSources());
renderCallback->addParticles(m_scriptedAnimator.pullNewParticles());
renderCallback->addAudios(m_scriptedAnimator.pullNewAudios());
}
+void Object::renderLightSources(RenderCallback* renderCallback) {
+ renderLights(renderCallback);
+ renderCallback->addLightSources(m_scriptedAnimator.lightSources());
+}
+
bool Object::damageTiles(List<Vec2I> const&, Vec2F const&, TileDamage const& tileDamage) {
if (m_unbreakable)
return false;
diff --git a/source/game/StarObject.hpp b/source/game/StarObject.hpp
index de3f370..e45a612 100644
--- a/source/game/StarObject.hpp
+++ b/source/game/StarObject.hpp
@@ -66,6 +66,8 @@ public:
virtual void render(RenderCallback* renderCallback) override;
+ virtual void renderLightSources(RenderCallback* renderCallback) override;
+
virtual bool checkBroken() override;
virtual Vec2I tilePosition() const override;
diff --git a/source/game/StarPlayer.cpp b/source/game/StarPlayer.cpp
index 93c05ae..188afef 100644
--- a/source/game/StarPlayer.cpp
+++ b/source/game/StarPlayer.cpp
@@ -1085,7 +1085,6 @@ void Player::render(RenderCallback* renderCallback) {
if (!isTeleporting())
renderCallback->addOverheadBars(bars(), position());
renderCallback->addParticles(particles());
- renderCallback->addLightSources(lightSources());
m_tools->render(renderCallback, inToolRange(), m_shifting, renderLayer);
@@ -1096,6 +1095,10 @@ void Player::render(RenderCallback* renderCallback) {
m_deployment->render(renderCallback, position());
}
+void Player::renderLightSources(RenderCallback* renderCallback) {
+ renderCallback->addLightSources(lightSources());
+}
+
Json Player::getGenericProperty(String const& name, Json const& defaultValue) const {
return m_genericProperties.value(name, defaultValue);
}
diff --git a/source/game/StarPlayer.hpp b/source/game/StarPlayer.hpp
index 88582a2..aa6853f 100644
--- a/source/game/StarPlayer.hpp
+++ b/source/game/StarPlayer.hpp
@@ -184,6 +184,8 @@ public:
void render(RenderCallback* renderCallback) override;
+ void renderLightSources(RenderCallback* renderCallback) override;
+
Json getGenericProperty(String const& name, Json const& defaultValue = Json()) const;
void setGenericProperty(String const& name, Json const& value);
diff --git a/source/game/StarPlayerDeployment.cpp b/source/game/StarPlayerDeployment.cpp
index b84e177..4565074 100644
--- a/source/game/StarPlayerDeployment.cpp
+++ b/source/game/StarPlayerDeployment.cpp
@@ -89,7 +89,6 @@ void PlayerDeployment::render(RenderCallback* renderCallback, Vec2F const& posit
drawablePair.first.translate(position);
renderCallback->addDrawable(drawablePair.first, drawablePair.second.value(RenderLayerPlayer));
}
- renderCallback->addLightSources(m_scriptComponent.lightSources());
renderCallback->addParticles(m_scriptComponent.pullNewParticles());
for (auto audio : m_scriptComponent.pullNewAudios()) {
audio->setPosition(position);
@@ -97,4 +96,8 @@ void PlayerDeployment::render(RenderCallback* renderCallback, Vec2F const& posit
}
}
+void PlayerDeployment::renderLightSources(RenderCallback* renderCallback) {
+ renderCallback->addLightSources(m_scriptComponent.lightSources());
+}
+
}
diff --git a/source/game/StarPlayerDeployment.hpp b/source/game/StarPlayerDeployment.hpp
index a5c8e3b..e9c9462 100644
--- a/source/game/StarPlayerDeployment.hpp
+++ b/source/game/StarPlayerDeployment.hpp
@@ -32,6 +32,7 @@ public:
void render(RenderCallback* renderCallback, Vec2F const& position);
+ void renderLightSources(RenderCallback* renderCallback);
private:
World* m_world;
Json m_config;
diff --git a/source/game/StarProjectile.cpp b/source/game/StarProjectile.cpp
index 060c4e3..89f3766 100644
--- a/source/game/StarProjectile.cpp
+++ b/source/game/StarProjectile.cpp
@@ -368,8 +368,14 @@ void Projectile::render(RenderCallback* renderCallback) {
drawable.fullbright = m_config->fullbright;
drawable.translate(position());
renderCallback->addDrawable(move(drawable), m_config->renderLayer);
+}
- renderCallback->addLightSource({position(), m_config->lightColor, m_config->pointLight, 0.0f, 0.0f, 0.0f});
+void Projectile::renderLightSources(RenderCallback* renderCallback) {
+ for (auto renderable : m_pendingRenderables) {
+ if (renderable.is<LightSource>())
+ renderCallback->addLightSource(renderable.get<LightSource>());
+ }
+ renderCallback->addLightSource({ position(), m_config->lightColor, m_config->pointLight, 0.0f, 0.0f, 0.0f });
}
Maybe<Json> Projectile::receiveMessage(ConnectionId sendingConnection, String const& message, JsonArray const& args) {
@@ -981,8 +987,6 @@ void Projectile::renderPendingRenderables(RenderCallback* renderCallback) {
renderCallback->addAudio(renderable.get<AudioInstancePtr>());
else if (renderable.is<Particle>())
renderCallback->addParticle(renderable.get<Particle>());
- else if (renderable.is<LightSource>())
- renderCallback->addLightSource(renderable.get<LightSource>());
}
m_pendingRenderables.clear();
}
diff --git a/source/game/StarProjectile.hpp b/source/game/StarProjectile.hpp
index 4c0bb18..7a36dfe 100644
--- a/source/game/StarProjectile.hpp
+++ b/source/game/StarProjectile.hpp
@@ -58,6 +58,7 @@ public:
void update(uint64_t currentStep) override;
void render(RenderCallback* renderCallback) override;
+ void renderLightSources(RenderCallback* renderCallback) override;
Maybe<Json> receiveMessage(ConnectionId sendingConnection, String const& message, JsonArray const& args) override;
diff --git a/source/game/StarVehicle.cpp b/source/game/StarVehicle.cpp
index 83fc9e2..e60e6e6 100644
--- a/source/game/StarVehicle.cpp
+++ b/source/game/StarVehicle.cpp
@@ -329,15 +329,18 @@ void Vehicle::render(RenderCallback* renderer) {
renderer->addAudios(m_networkedAnimatorDynamicTarget.pullNewAudios());
renderer->addParticles(m_networkedAnimatorDynamicTarget.pullNewParticles());
- renderer->addLightSources(m_networkedAnimator.lightSources(position()));
for (auto drawablePair : m_scriptedAnimator.drawables())
renderer->addDrawable(drawablePair.first, drawablePair.second.value(renderLayer(VehicleLayer::Front)));
- renderer->addLightSources(m_scriptedAnimator.lightSources());
renderer->addAudios(m_scriptedAnimator.pullNewAudios());
renderer->addParticles(m_scriptedAnimator.pullNewParticles());
}
+void Vehicle::renderLightSources(RenderCallback* renderer) {
+ renderer->addLightSources(m_networkedAnimator.lightSources(position()));
+ renderer->addLightSources(m_scriptedAnimator.lightSources());
+}
+
List<LightSource> Vehicle::lightSources() const {
auto lightSources = m_networkedAnimator.lightSources(position());
return lightSources;
diff --git a/source/game/StarVehicle.hpp b/source/game/StarVehicle.hpp
index f1ac2f3..381e207 100644
--- a/source/game/StarVehicle.hpp
+++ b/source/game/StarVehicle.hpp
@@ -55,6 +55,8 @@ public:
void render(RenderCallback* renderer) override;
+ void renderLightSources(RenderCallback* renderer) override;
+
List<LightSource> lightSources() const override;
bool shouldDestroy() const override;
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>());
diff --git a/source/game/StarWorldClient.hpp b/source/game/StarWorldClient.hpp
index 1a86f80..c5fbfd0 100644
--- a/source/game/StarWorldClient.hpp
+++ b/source/game/StarWorldClient.hpp
@@ -120,6 +120,8 @@ public:
// Disable normal client-side lighting algorithm, everything full brightness.
bool toggleFullbright();
+ // Disable asynchronous client-side lighting algorithm, run on main thread.
+ bool toggleAsyncLighting();
// Spatial log generated collision geometry.
bool toggleCollisionDebug();
@@ -153,6 +155,8 @@ public:
void collectLiquid(List<Vec2I> const& tilePositions, LiquidId liquidId);
+ void waitForLighting();
+
private:
static const float DropDist;
@@ -186,6 +190,8 @@ private:
bool operator<(DamageNumberKey const& other) const;
};
+ void lightingMain();
+
void initWorld(WorldStartPacket const& packet);
void clearWorld();
void tryGiveMainPlayerItem(ItemPtr item);
@@ -237,8 +243,16 @@ private:
uint64_t m_currentStep;
double m_currentServerStep;
bool m_fullBright;
+ bool m_asyncLighting;
CellularLightingCalculator m_lightingCalculator;
mutable CellularLightIntensityCalculator m_lightIntensityCalculator;
+ ThreadFunction<void> m_lightingThread;
+
+ mutable Mutex m_lightingMutex;
+ mutable ConditionVariable m_lightingCond;
+ mutable WorldRenderData* m_renderData;
+ bool m_stopLightingThread;
+
SkyPtr m_sky;
CollisionGenerator m_collisionGenerator;
diff --git a/source/game/StarWorldRenderData.hpp b/source/game/StarWorldRenderData.hpp
index 1d1bc09..b13fef5 100644
--- a/source/game/StarWorldRenderData.hpp
+++ b/source/game/StarWorldRenderData.hpp
@@ -9,6 +9,7 @@
#include "StarParticle.hpp"
#include "StarWeatherTypes.hpp"
#include "StarEntity.hpp"
+#include "StarThread.hpp"
namespace Star {
@@ -26,6 +27,7 @@ struct WorldRenderData {
RenderTileArray tiles;
Vec2I lightMinPosition;
Image lightMap;
+ Image tileLightMap;
List<EntityDrawables> entityDrawables;
List<Particle> particles;
diff --git a/source/game/interfaces/StarChattyEntity.hpp b/source/game/interfaces/StarChattyEntity.hpp
index 03c1ac9..cd6ac8a 100644
--- a/source/game/interfaces/StarChattyEntity.hpp
+++ b/source/game/interfaces/StarChattyEntity.hpp
@@ -10,7 +10,7 @@ STAR_CLASS(ChattyEntity);
class ChattyEntity : public virtual Entity {
public:
- virtual Vec2F mouthPosition() const { return mouthPosition(true); };
+ virtual Vec2F mouthPosition() const = 0;
virtual Vec2F mouthPosition(bool) const = 0;
virtual List<ChatAction> pullPendingChatActions() = 0;
};
diff --git a/source/game/interfaces/StarEntity.cpp b/source/game/interfaces/StarEntity.cpp
index 405fdde..67887c9 100644
--- a/source/game/interfaces/StarEntity.cpp
+++ b/source/game/interfaces/StarEntity.cpp
@@ -115,6 +115,8 @@ void Entity::update(uint64_t) {}
void Entity::render(RenderCallback*) {}
+void Entity::renderLightSources(RenderCallback*) {}
+
EntityId Entity::entityId() const {
return m_entityId;
}
diff --git a/source/game/interfaces/StarEntity.hpp b/source/game/interfaces/StarEntity.hpp
index 3452654..ad297a9 100644
--- a/source/game/interfaces/StarEntity.hpp
+++ b/source/game/interfaces/StarEntity.hpp
@@ -153,6 +153,8 @@ public:
virtual void render(RenderCallback* renderer);
+ virtual void renderLightSources(RenderCallback* renderer);
+
EntityId entityId() const;
EntityDamageTeam getTeam() const;
diff --git a/source/rendering/StarTilePainter.cpp b/source/rendering/StarTilePainter.cpp
index 68e1110..fc115e5 100644
--- a/source/rendering/StarTilePainter.cpp
+++ b/source/rendering/StarTilePainter.cpp
@@ -38,7 +38,8 @@ void TilePainter::adjustLighting(WorldRenderData& renderData) const {
RectI lightRange = RectI::withSize(renderData.lightMinPosition, Vec2I(renderData.lightMap.size()));
forEachRenderTile(renderData, lightRange, [&](Vec2I const& pos, RenderTile const& tile) {
// Only adjust lighting for full tiles
- if (liquidDrawLevel(byteToFloat(tile.liquidLevel)) < 1.0f)
+ float drawLevel = liquidDrawLevel(byteToFloat(tile.liquidLevel));
+ if (drawLevel == 0.0f)
return;
auto lightIndex = Vec2U(pos - renderData.lightMinPosition);
@@ -46,7 +47,7 @@ void TilePainter::adjustLighting(WorldRenderData& renderData) const {
auto const& liquid = m_liquids[tile.liquidId];
Vec3F tileLight = Vec3F(lightValue);
- float darknessLevel = (1 - tileLight.sum() / (3.0f * 255.0f));
+ float darknessLevel = (1 - tileLight.sum() / (3.0f * 255.0f)) * drawLevel;
lightValue = Vec3B(tileLight.piecewiseMultiply(Vec3F::filled(1 - darknessLevel) + liquid.bottomLightMix * darknessLevel));
renderData.lightMap.set(lightIndex, lightValue);
diff --git a/source/rendering/StarWorldPainter.cpp b/source/rendering/StarWorldPainter.cpp
index 7cb7c72..a93a592 100644
--- a/source/rendering/StarWorldPainter.cpp
+++ b/source/rendering/StarWorldPainter.cpp
@@ -45,7 +45,7 @@ WorldCamera& WorldPainter::camera() {
return m_camera;
}
-void WorldPainter::render(WorldRenderData& renderData) {
+void WorldPainter::render(WorldRenderData& renderData, function<void()> lightWaiter) {
m_camera.setScreenSize(m_renderer->screenSize());
m_camera.setTargetPixelRatio(Root::singleton().configuration()->get("zoomLevel").toFloat());
@@ -55,18 +55,6 @@ void WorldPainter::render(WorldRenderData& renderData) {
m_tilePainter->setup(m_camera, renderData);
- if (renderData.isFullbright) {
- m_renderer->setEffectTexture("lightMap", Image::filled(Vec2U(1, 1), {255, 255, 255, 255}, PixelFormat::RGB24));
- m_renderer->setEffectParameter("lightMapMultiplier", 1.0f);
- } else {
- m_tilePainter->adjustLighting(renderData);
-
- m_renderer->setEffectParameter("lightMapMultiplier", m_assets->json("/rendering.config:lightMapMultiplier").toFloat());
- m_renderer->setEffectParameter("lightMapScale", Vec2F::filled(TilePixels * m_camera.pixelRatio()));
- m_renderer->setEffectParameter("lightMapOffset", m_camera.worldToScreen(Vec2F(renderData.lightMinPosition)));
- m_renderer->setEffectTexture("lightMap", renderData.lightMap);
- }
-
// Stars, Debris Fields, Sky, and Orbiters
m_environmentPainter->renderStars(m_camera.pixelRatio(), Vec2F(m_camera.screenSize()), renderData.skyRenderData);
@@ -146,6 +134,10 @@ void WorldPainter::render(WorldRenderData& renderData) {
m_tilePainter->cleanup();
}
+void WorldPainter::adjustLighting(WorldRenderData& renderData) {
+ m_tilePainter->adjustLighting(renderData);
+}
+
void WorldPainter::renderParticles(WorldRenderData& renderData, Particle::Layer layer) {
const int textParticleFontSize = m_assets->json("/rendering.config:textParticleFontSize").toInt();
const RectF particleRenderWindow = RectF::withSize(Vec2F(), Vec2F(m_camera.screenSize())).padded(m_assets->json("/rendering.config:particleRenderWindowPadding").toInt());
diff --git a/source/rendering/StarWorldPainter.hpp b/source/rendering/StarWorldPainter.hpp
index dac94fd..0ae6a7d 100644
--- a/source/rendering/StarWorldPainter.hpp
+++ b/source/rendering/StarWorldPainter.hpp
@@ -23,7 +23,8 @@ public:
WorldCamera& camera();
- void render(WorldRenderData& renderData);
+ void render(WorldRenderData& renderData, function<void()> lightWaiter);
+ void adjustLighting(WorldRenderData& renderData);
private:
void renderParticles(WorldRenderData& renderData, Particle::Layer layer);