Move lighting calculation to separate thread
This commit is contained in:
parent
9d67cda97f
commit
624c7aaaf1
@ -28,6 +28,12 @@
|
|||||||
"textureSizeUniform" : "lightMapSize",
|
"textureSizeUniform" : "lightMapSize",
|
||||||
"textureAddressing" : "clamp",
|
"textureAddressing" : "clamp",
|
||||||
"textureFiltering" : "linear"
|
"textureFiltering" : "linear"
|
||||||
|
},
|
||||||
|
"tileLightMap" : {
|
||||||
|
"textureUniform" : "tileLightMap",
|
||||||
|
"textureSizeUniform" : "tileLightMapSize",
|
||||||
|
"textureAddressing" : "clamp",
|
||||||
|
"textureFiltering" : "linear"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -6,7 +6,9 @@ uniform sampler2D texture2;
|
|||||||
uniform sampler2D texture3;
|
uniform sampler2D texture3;
|
||||||
uniform bool lightMapEnabled;
|
uniform bool lightMapEnabled;
|
||||||
uniform vec2 lightMapSize;
|
uniform vec2 lightMapSize;
|
||||||
|
uniform vec2 tileLightMapSize;
|
||||||
uniform sampler2D lightMap;
|
uniform sampler2D lightMap;
|
||||||
|
uniform sampler2D tileLightMap;
|
||||||
uniform float lightMapMultiplier;
|
uniform float lightMapMultiplier;
|
||||||
|
|
||||||
varying vec2 fragmentTextureCoordinate;
|
varying vec2 fragmentTextureCoordinate;
|
||||||
@ -53,6 +55,12 @@ vec4 bicubicSample(sampler2D texture, vec2 texcoord, vec2 texscale) {
|
|||||||
mix(sample1, sample0, sx), sy);
|
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() {
|
void main() {
|
||||||
vec4 texColor;
|
vec4 texColor;
|
||||||
if (fragmentTextureIndex > 2.9) {
|
if (fragmentTextureIndex > 2.9) {
|
||||||
@ -70,6 +78,6 @@ void main() {
|
|||||||
vec4 finalColor = texColor * fragmentColor;
|
vec4 finalColor = texColor * fragmentColor;
|
||||||
float finalLightMapMultiplier = fragmentLightMapMultiplier * lightMapMultiplier;
|
float finalLightMapMultiplier = fragmentLightMapMultiplier * lightMapMultiplier;
|
||||||
if (lightMapEnabled && finalLightMapMultiplier > 0.0)
|
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;
|
gl_FragColor = finalColor;
|
||||||
}
|
}
|
@ -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) {
|
void CellularLightIntensityCalculator::setParameters(Json const& config) {
|
||||||
m_lightArray.setParameters(
|
m_lightArray.setParameters(
|
||||||
config.getInt("spreadPasses"),
|
config.getInt("spreadPasses"),
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "StarColor.hpp"
|
#include "StarColor.hpp"
|
||||||
#include "StarInterpolation.hpp"
|
#include "StarInterpolation.hpp"
|
||||||
#include "StarCellularLightArray.hpp"
|
#include "StarCellularLightArray.hpp"
|
||||||
|
#include "StarThread.hpp"
|
||||||
|
|
||||||
namespace Star {
|
namespace Star {
|
||||||
|
|
||||||
@ -44,6 +45,9 @@ public:
|
|||||||
// the call to 'begin', and formatted as RGB24.
|
// the call to 'begin', and formatted as RGB24.
|
||||||
void calculate(Image& output);
|
void calculate(Image& output);
|
||||||
|
|
||||||
|
void setupImage(Image& image, PixelFormat format = PixelFormat::RGB24) const;
|
||||||
|
|
||||||
|
ThreadFunction<Image> calculateAsync();
|
||||||
private:
|
private:
|
||||||
Json m_config;
|
Json m_config;
|
||||||
bool m_monochrome;
|
bool m_monochrome;
|
||||||
|
@ -361,18 +361,41 @@ void ClientApplication::render() {
|
|||||||
m_cinematicOverlay->render();
|
m_cinematicOverlay->render();
|
||||||
|
|
||||||
} else if (m_state > MainAppState::Title) {
|
} else if (m_state > MainAppState::Title) {
|
||||||
if (auto worldClient = m_universeClient->worldClient()) {
|
WorldClientPtr worldClient = m_universeClient->worldClient();
|
||||||
if (auto renderer = Application::renderer())
|
RendererPtr renderer = Application::renderer();
|
||||||
|
if (worldClient) {
|
||||||
|
if (renderer)
|
||||||
renderer->setEffectParameter("lightMapEnabled", true);
|
renderer->setEffectParameter("lightMapEnabled", true);
|
||||||
worldClient->render(m_renderData, TilePainter::BorderTileSize);
|
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();
|
m_mainInterface->renderInWorldElements();
|
||||||
if (auto renderer = Application::renderer())
|
if (renderer)
|
||||||
renderer->setEffectParameter("lightMapEnabled", false);
|
renderer->setEffectParameter("lightMapEnabled", false);
|
||||||
}
|
}
|
||||||
m_mainInterface->render();
|
m_mainInterface->render();
|
||||||
m_cinematicOverlay->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())
|
if (!m_errorScreen->accepted())
|
||||||
|
@ -24,6 +24,7 @@ ClientCommandProcessor::ClientCommandProcessor(UniverseClientPtr universeClient,
|
|||||||
{"debug", bind(&ClientCommandProcessor::debug, this)},
|
{"debug", bind(&ClientCommandProcessor::debug, this)},
|
||||||
{"boxes", bind(&ClientCommandProcessor::boxes, this)},
|
{"boxes", bind(&ClientCommandProcessor::boxes, this)},
|
||||||
{"fullbright", bind(&ClientCommandProcessor::fullbright, this)},
|
{"fullbright", bind(&ClientCommandProcessor::fullbright, this)},
|
||||||
|
{"asyncLighting", bind(&ClientCommandProcessor::asyncLighting, this)},
|
||||||
{"setGravity", bind(&ClientCommandProcessor::setGravity, this, _1)},
|
{"setGravity", bind(&ClientCommandProcessor::setGravity, this, _1)},
|
||||||
{"resetGravity", bind(&ClientCommandProcessor::resetGravity, this)},
|
{"resetGravity", bind(&ClientCommandProcessor::resetGravity, this)},
|
||||||
{"fixedCamera", bind(&ClientCommandProcessor::fixedCamera, this)},
|
{"fixedCamera", bind(&ClientCommandProcessor::fixedCamera, this)},
|
||||||
@ -151,6 +152,12 @@ String ClientCommandProcessor::fullbright() {
|
|||||||
? "enabled" : "disabled");
|
? "enabled" : "disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String ClientCommandProcessor::asyncLighting() {
|
||||||
|
return strf("Asynchronous render lighting {}",
|
||||||
|
m_universeClient->worldClient()->toggleAsyncLighting()
|
||||||
|
? "enabled" : "disabled");
|
||||||
|
}
|
||||||
|
|
||||||
String ClientCommandProcessor::setGravity(StringList const& arguments) {
|
String ClientCommandProcessor::setGravity(StringList const& arguments) {
|
||||||
if (!adminCommandAllowed())
|
if (!adminCommandAllowed())
|
||||||
return "You must be an admin to use this command.";
|
return "You must be an admin to use this command.";
|
||||||
|
@ -31,6 +31,7 @@ private:
|
|||||||
String debug();
|
String debug();
|
||||||
String boxes();
|
String boxes();
|
||||||
String fullbright();
|
String fullbright();
|
||||||
|
String asyncLighting();
|
||||||
String setGravity(StringList const& arguments);
|
String setGravity(StringList const& arguments);
|
||||||
String resetGravity();
|
String resetGravity();
|
||||||
String fixedCamera();
|
String fixedCamera();
|
||||||
|
@ -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
|
// 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, so that it is safe to call addEntity from the callback.
|
||||||
List<EntityPtr const*> allEntities;
|
List<EntityPtr const*> allEntities;
|
||||||
|
allEntities.reserve(m_spatialMap.size());
|
||||||
for (auto const& entry : m_spatialMap.entries())
|
for (auto const& entry : m_spatialMap.entries())
|
||||||
allEntities.append(&entry.second.value);
|
allEntities.append(&entry.second.value);
|
||||||
|
|
||||||
|
@ -494,10 +494,7 @@ void Monster::render(RenderCallback* renderCallback) {
|
|||||||
renderCallback->addAudios(m_networkedAnimatorDynamicTarget.pullNewAudios());
|
renderCallback->addAudios(m_networkedAnimatorDynamicTarget.pullNewAudios());
|
||||||
renderCallback->addParticles(m_networkedAnimatorDynamicTarget.pullNewParticles());
|
renderCallback->addParticles(m_networkedAnimatorDynamicTarget.pullNewParticles());
|
||||||
|
|
||||||
renderCallback->addLightSources(m_networkedAnimator.lightSources(position()));
|
|
||||||
|
|
||||||
renderCallback->addDrawables(m_statusController->drawables(), m_monsterVariant.renderLayer);
|
renderCallback->addDrawables(m_statusController->drawables(), m_monsterVariant.renderLayer);
|
||||||
renderCallback->addLightSources(m_statusController->lightSources());
|
|
||||||
renderCallback->addParticles(m_statusController->pullNewParticles());
|
renderCallback->addParticles(m_statusController->pullNewParticles());
|
||||||
renderCallback->addAudios(m_statusController->pullNewAudios());
|
renderCallback->addAudios(m_statusController->pullNewAudios());
|
||||||
|
|
||||||
@ -505,11 +502,16 @@ void Monster::render(RenderCallback* renderCallback) {
|
|||||||
|
|
||||||
for (auto drawablePair : m_scriptedAnimator.drawables())
|
for (auto drawablePair : m_scriptedAnimator.drawables())
|
||||||
renderCallback->addDrawable(drawablePair.first, drawablePair.second.value(m_monsterVariant.renderLayer));
|
renderCallback->addDrawable(drawablePair.first, drawablePair.second.value(m_monsterVariant.renderLayer));
|
||||||
renderCallback->addLightSources(m_scriptedAnimator.lightSources());
|
|
||||||
renderCallback->addAudios(m_scriptedAnimator.pullNewAudios());
|
renderCallback->addAudios(m_scriptedAnimator.pullNewAudios());
|
||||||
renderCallback->addParticles(m_scriptedAnimator.pullNewParticles());
|
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) {
|
void Monster::setPosition(Vec2F const& pos) {
|
||||||
m_movementController->setPosition(pos);
|
m_movementController->setPosition(pos);
|
||||||
}
|
}
|
||||||
|
@ -92,6 +92,8 @@ public:
|
|||||||
|
|
||||||
void render(RenderCallback* renderCallback) override;
|
void render(RenderCallback* renderCallback) override;
|
||||||
|
|
||||||
|
void renderLightSources(RenderCallback* renderCallback) override;
|
||||||
|
|
||||||
void setPosition(Vec2F const& pos);
|
void setPosition(Vec2F const& pos);
|
||||||
|
|
||||||
Maybe<Json> receiveMessage(ConnectionId sendingConnection, String const& message, JsonArray const& args) override;
|
Maybe<Json> receiveMessage(ConnectionId sendingConnection, String const& message, JsonArray const& args) override;
|
||||||
|
@ -464,7 +464,6 @@ void Npc::render(RenderCallback* renderCallback) {
|
|||||||
renderCallback->addAudios(m_statusController->pullNewAudios());
|
renderCallback->addAudios(m_statusController->pullNewAudios());
|
||||||
|
|
||||||
renderCallback->addParticles(m_npcVariant.splashConfig.doSplash(position(), m_movementController->velocity(), world()));
|
renderCallback->addParticles(m_npcVariant.splashConfig.doSplash(position(), m_movementController->velocity(), world()));
|
||||||
renderCallback->addLightSources(lightSources());
|
|
||||||
|
|
||||||
m_tools->render(renderCallback, inToolRange(), m_shifting.get(), renderLayer);
|
m_tools->render(renderCallback, inToolRange(), m_shifting.get(), renderLayer);
|
||||||
|
|
||||||
@ -473,6 +472,10 @@ void Npc::render(RenderCallback* renderCallback) {
|
|||||||
m_effectEmitter->render(renderCallback);
|
m_effectEmitter->render(renderCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Npc::renderLightSources(RenderCallback* renderCallback) {
|
||||||
|
renderCallback->addLightSources(lightSources());
|
||||||
|
}
|
||||||
|
|
||||||
void Npc::setPosition(Vec2F const& pos) {
|
void Npc::setPosition(Vec2F const& pos) {
|
||||||
m_movementController->setPosition(pos);
|
m_movementController->setPosition(pos);
|
||||||
}
|
}
|
||||||
|
@ -94,6 +94,8 @@ public:
|
|||||||
|
|
||||||
void render(RenderCallback* renderCallback) override;
|
void render(RenderCallback* renderCallback) override;
|
||||||
|
|
||||||
|
void renderLightSources(RenderCallback* renderCallback) override;
|
||||||
|
|
||||||
void setPosition(Vec2F const& pos);
|
void setPosition(Vec2F const& pos);
|
||||||
|
|
||||||
float maxHealth() const override;
|
float maxHealth() const override;
|
||||||
|
@ -394,7 +394,6 @@ void Object::update(uint64_t) {
|
|||||||
|
|
||||||
void Object::render(RenderCallback* renderCallback) {
|
void Object::render(RenderCallback* renderCallback) {
|
||||||
renderParticles(renderCallback);
|
renderParticles(renderCallback);
|
||||||
renderLights(renderCallback);
|
|
||||||
renderSounds(renderCallback);
|
renderSounds(renderCallback);
|
||||||
|
|
||||||
for (auto const& imageKeyPair : m_imageKeys)
|
for (auto const& imageKeyPair : m_imageKeys)
|
||||||
@ -412,11 +411,15 @@ void Object::render(RenderCallback* renderCallback) {
|
|||||||
|
|
||||||
for (auto drawablePair : m_scriptedAnimator.drawables())
|
for (auto drawablePair : m_scriptedAnimator.drawables())
|
||||||
renderCallback->addDrawable(drawablePair.first, drawablePair.second.value(renderLayer()));
|
renderCallback->addDrawable(drawablePair.first, drawablePair.second.value(renderLayer()));
|
||||||
renderCallback->addLightSources(m_scriptedAnimator.lightSources());
|
|
||||||
renderCallback->addParticles(m_scriptedAnimator.pullNewParticles());
|
renderCallback->addParticles(m_scriptedAnimator.pullNewParticles());
|
||||||
renderCallback->addAudios(m_scriptedAnimator.pullNewAudios());
|
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) {
|
bool Object::damageTiles(List<Vec2I> const&, Vec2F const&, TileDamage const& tileDamage) {
|
||||||
if (m_unbreakable)
|
if (m_unbreakable)
|
||||||
return false;
|
return false;
|
||||||
|
@ -66,6 +66,8 @@ public:
|
|||||||
|
|
||||||
virtual void render(RenderCallback* renderCallback) override;
|
virtual void render(RenderCallback* renderCallback) override;
|
||||||
|
|
||||||
|
virtual void renderLightSources(RenderCallback* renderCallback) override;
|
||||||
|
|
||||||
virtual bool checkBroken() override;
|
virtual bool checkBroken() override;
|
||||||
|
|
||||||
virtual Vec2I tilePosition() const override;
|
virtual Vec2I tilePosition() const override;
|
||||||
|
@ -1085,7 +1085,6 @@ void Player::render(RenderCallback* renderCallback) {
|
|||||||
if (!isTeleporting())
|
if (!isTeleporting())
|
||||||
renderCallback->addOverheadBars(bars(), position());
|
renderCallback->addOverheadBars(bars(), position());
|
||||||
renderCallback->addParticles(particles());
|
renderCallback->addParticles(particles());
|
||||||
renderCallback->addLightSources(lightSources());
|
|
||||||
|
|
||||||
m_tools->render(renderCallback, inToolRange(), m_shifting, renderLayer);
|
m_tools->render(renderCallback, inToolRange(), m_shifting, renderLayer);
|
||||||
|
|
||||||
@ -1096,6 +1095,10 @@ void Player::render(RenderCallback* renderCallback) {
|
|||||||
m_deployment->render(renderCallback, position());
|
m_deployment->render(renderCallback, position());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Player::renderLightSources(RenderCallback* renderCallback) {
|
||||||
|
renderCallback->addLightSources(lightSources());
|
||||||
|
}
|
||||||
|
|
||||||
Json Player::getGenericProperty(String const& name, Json const& defaultValue) const {
|
Json Player::getGenericProperty(String const& name, Json const& defaultValue) const {
|
||||||
return m_genericProperties.value(name, defaultValue);
|
return m_genericProperties.value(name, defaultValue);
|
||||||
}
|
}
|
||||||
|
@ -184,6 +184,8 @@ public:
|
|||||||
|
|
||||||
void render(RenderCallback* renderCallback) override;
|
void render(RenderCallback* renderCallback) override;
|
||||||
|
|
||||||
|
void renderLightSources(RenderCallback* renderCallback) override;
|
||||||
|
|
||||||
Json getGenericProperty(String const& name, Json const& defaultValue = Json()) const;
|
Json getGenericProperty(String const& name, Json const& defaultValue = Json()) const;
|
||||||
void setGenericProperty(String const& name, Json const& value);
|
void setGenericProperty(String const& name, Json const& value);
|
||||||
|
|
||||||
|
@ -89,7 +89,6 @@ void PlayerDeployment::render(RenderCallback* renderCallback, Vec2F const& posit
|
|||||||
drawablePair.first.translate(position);
|
drawablePair.first.translate(position);
|
||||||
renderCallback->addDrawable(drawablePair.first, drawablePair.second.value(RenderLayerPlayer));
|
renderCallback->addDrawable(drawablePair.first, drawablePair.second.value(RenderLayerPlayer));
|
||||||
}
|
}
|
||||||
renderCallback->addLightSources(m_scriptComponent.lightSources());
|
|
||||||
renderCallback->addParticles(m_scriptComponent.pullNewParticles());
|
renderCallback->addParticles(m_scriptComponent.pullNewParticles());
|
||||||
for (auto audio : m_scriptComponent.pullNewAudios()) {
|
for (auto audio : m_scriptComponent.pullNewAudios()) {
|
||||||
audio->setPosition(position);
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ public:
|
|||||||
|
|
||||||
void render(RenderCallback* renderCallback, Vec2F const& position);
|
void render(RenderCallback* renderCallback, Vec2F const& position);
|
||||||
|
|
||||||
|
void renderLightSources(RenderCallback* renderCallback);
|
||||||
private:
|
private:
|
||||||
World* m_world;
|
World* m_world;
|
||||||
Json m_config;
|
Json m_config;
|
||||||
|
@ -368,7 +368,13 @@ void Projectile::render(RenderCallback* renderCallback) {
|
|||||||
drawable.fullbright = m_config->fullbright;
|
drawable.fullbright = m_config->fullbright;
|
||||||
drawable.translate(position());
|
drawable.translate(position());
|
||||||
renderCallback->addDrawable(move(drawable), m_config->renderLayer);
|
renderCallback->addDrawable(move(drawable), m_config->renderLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 });
|
renderCallback->addLightSource({ position(), m_config->lightColor, m_config->pointLight, 0.0f, 0.0f, 0.0f });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -981,8 +987,6 @@ void Projectile::renderPendingRenderables(RenderCallback* renderCallback) {
|
|||||||
renderCallback->addAudio(renderable.get<AudioInstancePtr>());
|
renderCallback->addAudio(renderable.get<AudioInstancePtr>());
|
||||||
else if (renderable.is<Particle>())
|
else if (renderable.is<Particle>())
|
||||||
renderCallback->addParticle(renderable.get<Particle>());
|
renderCallback->addParticle(renderable.get<Particle>());
|
||||||
else if (renderable.is<LightSource>())
|
|
||||||
renderCallback->addLightSource(renderable.get<LightSource>());
|
|
||||||
}
|
}
|
||||||
m_pendingRenderables.clear();
|
m_pendingRenderables.clear();
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@ public:
|
|||||||
|
|
||||||
void update(uint64_t currentStep) override;
|
void update(uint64_t currentStep) override;
|
||||||
void render(RenderCallback* renderCallback) override;
|
void render(RenderCallback* renderCallback) override;
|
||||||
|
void renderLightSources(RenderCallback* renderCallback) override;
|
||||||
|
|
||||||
Maybe<Json> receiveMessage(ConnectionId sendingConnection, String const& message, JsonArray const& args) override;
|
Maybe<Json> receiveMessage(ConnectionId sendingConnection, String const& message, JsonArray const& args) override;
|
||||||
|
|
||||||
|
@ -329,15 +329,18 @@ void Vehicle::render(RenderCallback* renderer) {
|
|||||||
|
|
||||||
renderer->addAudios(m_networkedAnimatorDynamicTarget.pullNewAudios());
|
renderer->addAudios(m_networkedAnimatorDynamicTarget.pullNewAudios());
|
||||||
renderer->addParticles(m_networkedAnimatorDynamicTarget.pullNewParticles());
|
renderer->addParticles(m_networkedAnimatorDynamicTarget.pullNewParticles());
|
||||||
renderer->addLightSources(m_networkedAnimator.lightSources(position()));
|
|
||||||
|
|
||||||
for (auto drawablePair : m_scriptedAnimator.drawables())
|
for (auto drawablePair : m_scriptedAnimator.drawables())
|
||||||
renderer->addDrawable(drawablePair.first, drawablePair.second.value(renderLayer(VehicleLayer::Front)));
|
renderer->addDrawable(drawablePair.first, drawablePair.second.value(renderLayer(VehicleLayer::Front)));
|
||||||
renderer->addLightSources(m_scriptedAnimator.lightSources());
|
|
||||||
renderer->addAudios(m_scriptedAnimator.pullNewAudios());
|
renderer->addAudios(m_scriptedAnimator.pullNewAudios());
|
||||||
renderer->addParticles(m_scriptedAnimator.pullNewParticles());
|
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 {
|
List<LightSource> Vehicle::lightSources() const {
|
||||||
auto lightSources = m_networkedAnimator.lightSources(position());
|
auto lightSources = m_networkedAnimator.lightSources(position());
|
||||||
return lightSources;
|
return lightSources;
|
||||||
|
@ -55,6 +55,8 @@ public:
|
|||||||
|
|
||||||
void render(RenderCallback* renderer) override;
|
void render(RenderCallback* renderer) override;
|
||||||
|
|
||||||
|
void renderLightSources(RenderCallback* renderer) override;
|
||||||
|
|
||||||
List<LightSource> lightSources() const override;
|
List<LightSource> lightSources() const override;
|
||||||
|
|
||||||
bool shouldDestroy() const override;
|
bool shouldDestroy() const override;
|
||||||
|
@ -34,6 +34,7 @@ WorldClient::WorldClient(PlayerPtr mainPlayer) {
|
|||||||
m_currentStep = 0;
|
m_currentStep = 0;
|
||||||
m_currentServerStep = 0.0;
|
m_currentServerStep = 0.0;
|
||||||
m_fullBright = false;
|
m_fullBright = false;
|
||||||
|
m_asyncLighting = true;
|
||||||
m_worldDimTimer = GameTimer(m_clientConfig.getFloat("worldDimTime"));
|
m_worldDimTimer = GameTimer(m_clientConfig.getFloat("worldDimTime"));
|
||||||
m_worldDimTimer.setDone();
|
m_worldDimTimer.setDone();
|
||||||
m_worldDimLevel = 0.0f;
|
m_worldDimLevel = 0.0f;
|
||||||
@ -77,10 +78,20 @@ WorldClient::WorldClient(PlayerPtr mainPlayer) {
|
|||||||
m_altMusicTrack.setVolume(0, 0, 0);
|
m_altMusicTrack.setVolume(0, 0, 0);
|
||||||
m_altMusicActive = false;
|
m_altMusicActive = false;
|
||||||
|
|
||||||
|
m_stopLightingThread = false;
|
||||||
|
m_lightingThread = Thread::invoke("WorldClient::lightingMain", mem_fn(&WorldClient::lightingMain), this);
|
||||||
|
m_renderData = nullptr;
|
||||||
|
|
||||||
clearWorld();
|
clearWorld();
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldClient::~WorldClient() {
|
WorldClient::~WorldClient() {
|
||||||
|
m_stopLightingThread = true;
|
||||||
|
{
|
||||||
|
MutexLocker locker(m_lightingMutex);
|
||||||
|
m_lightingCond.broadcast();
|
||||||
|
}
|
||||||
|
|
||||||
clearWorld();
|
clearWorld();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,76 +355,16 @@ void WorldClient::render(WorldRenderData& renderData, unsigned bufferTiles) {
|
|||||||
|
|
||||||
renderData.geometry = m_geometry;
|
renderData.geometry = m_geometry;
|
||||||
|
|
||||||
float pulseAmount = Root::singleton().assets()->json("/highlights.config:interactivePulseAmount").toFloat();
|
ClientRenderCallback lightingRenderCallback;
|
||||||
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);
|
|
||||||
|
|
||||||
bool inspecting = m_mainPlayer->inspecting();
|
|
||||||
float inspectionFlickerMultiplier = Random::randf(1 - Root::singleton().assets()->json("/highlights.config:inspectionFlickerAmount").toFloat(), 1);
|
|
||||||
|
|
||||||
EntityId playerAimInteractive = NullEntityId;
|
|
||||||
if (Root::singleton().configuration()->get("interactiveHighlight").toBool()) {
|
|
||||||
if (auto entity = m_mainPlayer->bestInteractionEntity(false))
|
|
||||||
playerAimInteractive = entity->entityId();
|
|
||||||
}
|
|
||||||
|
|
||||||
const List<Directives>* directives = nullptr;
|
|
||||||
if (auto& worldTemplate = m_worldTemplate) {
|
|
||||||
if (const auto& parameters = worldTemplate->worldParameters())
|
|
||||||
if (auto& globalDirectives = m_worldTemplate->worldParameters()->globalDirectives)
|
|
||||||
directives = &globalDirectives.get();
|
|
||||||
}
|
|
||||||
m_entityMap->forAllEntities([&](EntityPtr const& entity) {
|
m_entityMap->forAllEntities([&](EntityPtr const& entity) {
|
||||||
if (m_startupHiddenEntities.contains(entity->entityId()))
|
if (m_startupHiddenEntities.contains(entity->entityId()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ClientRenderCallback renderCallback;
|
entity->renderLightSources(&lightingRenderCallback);
|
||||||
entity->render(&renderCallback);
|
|
||||||
|
|
||||||
EntityDrawables ed;
|
|
||||||
for (auto& p : renderCallback.drawables) {
|
|
||||||
if (directives) {
|
|
||||||
int directiveIndex = unsigned(entity->entityId()) % directives->size();
|
|
||||||
for (auto& d : p.second) {
|
|
||||||
if (d.isImage())
|
|
||||||
d.imagePart().addDirectives(directives->at(directiveIndex), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ed.layers[p.first] = move(p.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_interactiveHighlightMode || (!inspecting && entity->entityId() == playerAimInteractive)) {
|
|
||||||
if (auto interactive = as<InteractiveEntity>(entity)) {
|
|
||||||
if (interactive->isInteractive()) {
|
|
||||||
ed.highlightEffect.type = EntityHighlightEffectType::Interactive;
|
|
||||||
ed.highlightEffect.level = pulseLevel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (inspecting) {
|
|
||||||
if (auto inspectable = as<InspectableEntity>(entity)) {
|
|
||||||
ed.highlightEffect = m_mainPlayer->inspectionHighlight(inspectable);
|
|
||||||
ed.highlightEffect.level *= inspectionFlickerMultiplier;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
renderData.entityDrawables.append(move(ed));
|
|
||||||
|
|
||||||
renderLightSources.appendAll(move(renderCallback.lightSources));
|
|
||||||
|
|
||||||
if (directives) {
|
|
||||||
int directiveIndex = unsigned(entity->entityId()) % directives->size();
|
|
||||||
for (auto& p : renderCallback.particles)
|
|
||||||
p.directives.append(directives->get(directiveIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_particles->addParticles(move(renderCallback.particles));
|
|
||||||
m_samples.appendAll(move(renderCallback.audios));
|
|
||||||
previewTiles.appendAll(move(renderCallback.previewTiles));
|
|
||||||
renderData.overheadBars.appendAll(move(renderCallback.overheadBars));
|
|
||||||
|
|
||||||
}, [](EntityPtr const& a, EntityPtr const& b) {
|
|
||||||
return a->entityId() < b->entityId();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
renderLightSources = move(lightingRenderCallback.lightSources);
|
||||||
|
|
||||||
RectI window = m_clientState.window();
|
RectI window = m_clientState.window();
|
||||||
RectI tileRange = window.padded(bufferTiles);
|
RectI tileRange = window.padded(bufferTiles);
|
||||||
RectI lightRange = window.padded(1);
|
RectI lightRange = window.padded(1);
|
||||||
@ -422,31 +373,11 @@ void WorldClient::render(WorldRenderData& renderData, unsigned bufferTiles) {
|
|||||||
renderData.tileMinPosition = tileRange.min();
|
renderData.tileMinPosition = tileRange.min();
|
||||||
renderData.lightMinPosition = lightRange.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;
|
|
||||||
|
|
||||||
renderTile.background = clientTile.background;
|
|
||||||
renderTile.backgroundMod = clientTile.backgroundMod;
|
|
||||||
|
|
||||||
renderTile.foregroundHueShift = clientTile.foregroundHueShift;
|
|
||||||
renderTile.foregroundModHueShift = clientTile.foregroundModHueShift;
|
|
||||||
renderTile.foregroundColorVariant = clientTile.foregroundColorVariant;
|
|
||||||
renderTile.foregroundDamageType = clientTile.foregroundDamage.damageType();
|
|
||||||
renderTile.foregroundDamageLevel = floatToByte(clientTile.foregroundDamage.damageEffectPercentage());
|
|
||||||
|
|
||||||
renderTile.backgroundHueShift = clientTile.backgroundHueShift;
|
|
||||||
renderTile.backgroundModHueShift = clientTile.backgroundModHueShift;
|
|
||||||
renderTile.backgroundColorVariant = clientTile.backgroundColorVariant;
|
|
||||||
renderTile.backgroundDamageType = clientTile.backgroundDamage.damageType();
|
|
||||||
renderTile.backgroundDamageLevel = floatToByte(clientTile.backgroundDamage.damageEffectPercentage());
|
|
||||||
|
|
||||||
renderTile.liquidId = clientTile.liquid.liquid;
|
|
||||||
renderTile.liquidLevel = floatToByte(clientTile.liquid.level);
|
|
||||||
});
|
|
||||||
|
|
||||||
Vec2U lightSize(lightRange.size());
|
Vec2U lightSize(lightRange.size());
|
||||||
|
|
||||||
|
renderData.tileLightMap.reset(lightSize, PixelFormat::RGBA32);
|
||||||
|
renderData.tileLightMap.fill(Vec4B::filled(0));
|
||||||
|
|
||||||
if (m_fullBright) {
|
if (m_fullBright) {
|
||||||
renderData.lightMap.reset(lightSize, PixelFormat::RGB24);
|
renderData.lightMap.reset(lightSize, PixelFormat::RGB24);
|
||||||
renderData.lightMap.fill(Vec3B(255, 255, 255));
|
renderData.lightMap.fill(Vec3B(255, 255, 255));
|
||||||
@ -493,8 +424,106 @@ void WorldClient::render(WorldRenderData& renderData, unsigned bufferTiles) {
|
|||||||
m_lightingCalculator.addSpreadLight(position, Color::v3bToFloat(lightPair.second));
|
m_lightingCalculator.addSpreadLight(position, Color::v3bToFloat(lightPair.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_asyncLighting) {
|
||||||
|
m_renderData = &renderData;
|
||||||
|
m_lightingCond.signal();
|
||||||
|
}
|
||||||
|
else {
|
||||||
m_lightingCalculator.calculate(renderData.lightMap);
|
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);
|
||||||
|
|
||||||
|
bool inspecting = m_mainPlayer->inspecting();
|
||||||
|
float inspectionFlickerMultiplier = Random::randf(1 - Root::singleton().assets()->json("/highlights.config:inspectionFlickerAmount").toFloat(), 1);
|
||||||
|
|
||||||
|
EntityId playerAimInteractive = NullEntityId;
|
||||||
|
if (Root::singleton().configuration()->get("interactiveHighlight").toBool()) {
|
||||||
|
if (auto entity = m_mainPlayer->bestInteractionEntity(false))
|
||||||
|
playerAimInteractive = entity->entityId();
|
||||||
|
}
|
||||||
|
|
||||||
|
const List<Directives>* directives = nullptr;
|
||||||
|
if (auto& worldTemplate = m_worldTemplate) {
|
||||||
|
if (const auto& parameters = worldTemplate->worldParameters())
|
||||||
|
if (auto& globalDirectives = m_worldTemplate->worldParameters()->globalDirectives)
|
||||||
|
directives = &globalDirectives.get();
|
||||||
|
}
|
||||||
|
m_entityMap->forAllEntities([&](EntityPtr const& entity) {
|
||||||
|
if (m_startupHiddenEntities.contains(entity->entityId()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ClientRenderCallback renderCallback;
|
||||||
|
|
||||||
|
entity->render(&renderCallback);
|
||||||
|
|
||||||
|
EntityDrawables ed;
|
||||||
|
for (auto& p : renderCallback.drawables) {
|
||||||
|
if (directives) {
|
||||||
|
int directiveIndex = unsigned(entity->entityId()) % directives->size();
|
||||||
|
for (auto& d : p.second) {
|
||||||
|
if (d.isImage())
|
||||||
|
d.imagePart().addDirectives(directives->at(directiveIndex), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ed.layers[p.first] = move(p.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_interactiveHighlightMode || (!inspecting && entity->entityId() == playerAimInteractive)) {
|
||||||
|
if (auto interactive = as<InteractiveEntity>(entity)) {
|
||||||
|
if (interactive->isInteractive()) {
|
||||||
|
ed.highlightEffect.type = EntityHighlightEffectType::Interactive;
|
||||||
|
ed.highlightEffect.level = pulseLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (inspecting) {
|
||||||
|
if (auto inspectable = as<InspectableEntity>(entity)) {
|
||||||
|
ed.highlightEffect = m_mainPlayer->inspectionHighlight(inspectable);
|
||||||
|
ed.highlightEffect.level *= inspectionFlickerMultiplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
renderData.entityDrawables.append(move(ed));
|
||||||
|
|
||||||
|
if (directives) {
|
||||||
|
int directiveIndex = unsigned(entity->entityId()) % directives->size();
|
||||||
|
for (auto& p : renderCallback.particles)
|
||||||
|
p.directives.append(directives->get(directiveIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_particles->addParticles(move(renderCallback.particles));
|
||||||
|
m_samples.appendAll(move(renderCallback.audios));
|
||||||
|
previewTiles.appendAll(move(renderCallback.previewTiles));
|
||||||
|
renderData.overheadBars.appendAll(move(renderCallback.overheadBars));
|
||||||
|
|
||||||
|
}, [](EntityPtr const& a, EntityPtr const& b) {
|
||||||
|
return a->entityId() < b->entityId();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_tileArray->tileEachTo(renderData.tiles, tileRange, [](RenderTile& renderTile, Vec2I const&, ClientTile const& clientTile) {
|
||||||
|
renderTile.foreground = clientTile.foreground;
|
||||||
|
renderTile.foregroundMod = clientTile.foregroundMod;
|
||||||
|
|
||||||
|
renderTile.background = clientTile.background;
|
||||||
|
renderTile.backgroundMod = clientTile.backgroundMod;
|
||||||
|
|
||||||
|
renderTile.foregroundHueShift = clientTile.foregroundHueShift;
|
||||||
|
renderTile.foregroundModHueShift = clientTile.foregroundModHueShift;
|
||||||
|
renderTile.foregroundColorVariant = clientTile.foregroundColorVariant;
|
||||||
|
renderTile.foregroundDamageType = clientTile.foregroundDamage.damageType();
|
||||||
|
renderTile.foregroundDamageLevel = floatToByte(clientTile.foregroundDamage.damageEffectPercentage());
|
||||||
|
|
||||||
|
renderTile.backgroundHueShift = clientTile.backgroundHueShift;
|
||||||
|
renderTile.backgroundModHueShift = clientTile.backgroundModHueShift;
|
||||||
|
renderTile.backgroundColorVariant = clientTile.backgroundColorVariant;
|
||||||
|
renderTile.backgroundDamageType = clientTile.backgroundDamage.damageType();
|
||||||
|
renderTile.backgroundDamageLevel = floatToByte(clientTile.backgroundDamage.damageEffectPercentage());
|
||||||
|
|
||||||
|
renderTile.liquidId = clientTile.liquid.liquid;
|
||||||
|
renderTile.liquidLevel = floatToByte(clientTile.liquid.level);
|
||||||
|
});
|
||||||
|
|
||||||
for (auto const& previewTile : previewTiles) {
|
for (auto const& previewTile : previewTiles) {
|
||||||
Vec2I tileArrayPos = m_geometry.diff(previewTile.position, renderData.tileMinPosition);
|
Vec2I tileArrayPos = m_geometry.diff(previewTile.position, renderData.tileMinPosition);
|
||||||
@ -524,8 +553,8 @@ void WorldClient::render(WorldRenderData& renderData, unsigned bufferTiles) {
|
|||||||
|
|
||||||
if (previewTile.updateLight) {
|
if (previewTile.updateLight) {
|
||||||
Vec2I lightArrayPos = m_geometry.diff(previewTile.position, renderData.lightMinPosition);
|
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())
|
if (lightArrayPos[0] >= 0 && lightArrayPos[0] < (int)renderData.tileLightMap.width() && lightArrayPos[1] >= 0 && lightArrayPos[1] < (int)renderData.tileLightMap.height())
|
||||||
renderData.lightMap.set(Vec2U(lightArrayPos), previewTile.light);
|
renderData.tileLightMap.set(Vec2U(lightArrayPos), previewTile.light);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -634,6 +663,11 @@ bool WorldClient::toggleFullbright() {
|
|||||||
return m_fullBright;
|
return m_fullBright;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WorldClient::toggleAsyncLighting() {
|
||||||
|
m_asyncLighting = !m_asyncLighting;
|
||||||
|
return m_asyncLighting;
|
||||||
|
}
|
||||||
|
|
||||||
bool WorldClient::toggleCollisionDebug() {
|
bool WorldClient::toggleCollisionDebug() {
|
||||||
m_collisionDebug = !m_collisionDebug;
|
m_collisionDebug = !m_collisionDebug;
|
||||||
return 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));
|
m_outgoingPackets.append(make_shared<CollectLiquidPacket>(tilePositions, liquidId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorldClient::waitForLighting() {
|
||||||
|
MutexLocker lock(m_lightingMutex);
|
||||||
|
}
|
||||||
|
|
||||||
bool WorldClient::isTileProtected(Vec2I const& pos) const {
|
bool WorldClient::isTileProtected(Vec2I const& pos) const {
|
||||||
if (!inWorld())
|
if (!inWorld())
|
||||||
return true;
|
return true;
|
||||||
@ -1401,6 +1439,26 @@ RpcPromise<InteractAction> WorldClient::interact(InteractRequest const& request)
|
|||||||
return pair.first;
|
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) {
|
void WorldClient::initWorld(WorldStartPacket const& startPacket) {
|
||||||
clearWorld();
|
clearWorld();
|
||||||
m_outgoingPackets.append(make_shared<WorldStartAcknowledgePacket>());
|
m_outgoingPackets.append(make_shared<WorldStartAcknowledgePacket>());
|
||||||
|
@ -120,6 +120,8 @@ public:
|
|||||||
|
|
||||||
// Disable normal client-side lighting algorithm, everything full brightness.
|
// Disable normal client-side lighting algorithm, everything full brightness.
|
||||||
bool toggleFullbright();
|
bool toggleFullbright();
|
||||||
|
// Disable asynchronous client-side lighting algorithm, run on main thread.
|
||||||
|
bool toggleAsyncLighting();
|
||||||
// Spatial log generated collision geometry.
|
// Spatial log generated collision geometry.
|
||||||
bool toggleCollisionDebug();
|
bool toggleCollisionDebug();
|
||||||
|
|
||||||
@ -153,6 +155,8 @@ public:
|
|||||||
|
|
||||||
void collectLiquid(List<Vec2I> const& tilePositions, LiquidId liquidId);
|
void collectLiquid(List<Vec2I> const& tilePositions, LiquidId liquidId);
|
||||||
|
|
||||||
|
void waitForLighting();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const float DropDist;
|
static const float DropDist;
|
||||||
|
|
||||||
@ -186,6 +190,8 @@ private:
|
|||||||
bool operator<(DamageNumberKey const& other) const;
|
bool operator<(DamageNumberKey const& other) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void lightingMain();
|
||||||
|
|
||||||
void initWorld(WorldStartPacket const& packet);
|
void initWorld(WorldStartPacket const& packet);
|
||||||
void clearWorld();
|
void clearWorld();
|
||||||
void tryGiveMainPlayerItem(ItemPtr item);
|
void tryGiveMainPlayerItem(ItemPtr item);
|
||||||
@ -237,8 +243,16 @@ private:
|
|||||||
uint64_t m_currentStep;
|
uint64_t m_currentStep;
|
||||||
double m_currentServerStep;
|
double m_currentServerStep;
|
||||||
bool m_fullBright;
|
bool m_fullBright;
|
||||||
|
bool m_asyncLighting;
|
||||||
CellularLightingCalculator m_lightingCalculator;
|
CellularLightingCalculator m_lightingCalculator;
|
||||||
mutable CellularLightIntensityCalculator m_lightIntensityCalculator;
|
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;
|
SkyPtr m_sky;
|
||||||
|
|
||||||
CollisionGenerator m_collisionGenerator;
|
CollisionGenerator m_collisionGenerator;
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "StarParticle.hpp"
|
#include "StarParticle.hpp"
|
||||||
#include "StarWeatherTypes.hpp"
|
#include "StarWeatherTypes.hpp"
|
||||||
#include "StarEntity.hpp"
|
#include "StarEntity.hpp"
|
||||||
|
#include "StarThread.hpp"
|
||||||
|
|
||||||
namespace Star {
|
namespace Star {
|
||||||
|
|
||||||
@ -26,6 +27,7 @@ struct WorldRenderData {
|
|||||||
RenderTileArray tiles;
|
RenderTileArray tiles;
|
||||||
Vec2I lightMinPosition;
|
Vec2I lightMinPosition;
|
||||||
Image lightMap;
|
Image lightMap;
|
||||||
|
Image tileLightMap;
|
||||||
|
|
||||||
List<EntityDrawables> entityDrawables;
|
List<EntityDrawables> entityDrawables;
|
||||||
List<Particle> particles;
|
List<Particle> particles;
|
||||||
|
@ -10,7 +10,7 @@ STAR_CLASS(ChattyEntity);
|
|||||||
|
|
||||||
class ChattyEntity : public virtual Entity {
|
class ChattyEntity : public virtual Entity {
|
||||||
public:
|
public:
|
||||||
virtual Vec2F mouthPosition() const { return mouthPosition(true); };
|
virtual Vec2F mouthPosition() const = 0;
|
||||||
virtual Vec2F mouthPosition(bool) const = 0;
|
virtual Vec2F mouthPosition(bool) const = 0;
|
||||||
virtual List<ChatAction> pullPendingChatActions() = 0;
|
virtual List<ChatAction> pullPendingChatActions() = 0;
|
||||||
};
|
};
|
||||||
|
@ -115,6 +115,8 @@ void Entity::update(uint64_t) {}
|
|||||||
|
|
||||||
void Entity::render(RenderCallback*) {}
|
void Entity::render(RenderCallback*) {}
|
||||||
|
|
||||||
|
void Entity::renderLightSources(RenderCallback*) {}
|
||||||
|
|
||||||
EntityId Entity::entityId() const {
|
EntityId Entity::entityId() const {
|
||||||
return m_entityId;
|
return m_entityId;
|
||||||
}
|
}
|
||||||
|
@ -153,6 +153,8 @@ public:
|
|||||||
|
|
||||||
virtual void render(RenderCallback* renderer);
|
virtual void render(RenderCallback* renderer);
|
||||||
|
|
||||||
|
virtual void renderLightSources(RenderCallback* renderer);
|
||||||
|
|
||||||
EntityId entityId() const;
|
EntityId entityId() const;
|
||||||
|
|
||||||
EntityDamageTeam getTeam() const;
|
EntityDamageTeam getTeam() const;
|
||||||
|
@ -38,7 +38,8 @@ void TilePainter::adjustLighting(WorldRenderData& renderData) const {
|
|||||||
RectI lightRange = RectI::withSize(renderData.lightMinPosition, Vec2I(renderData.lightMap.size()));
|
RectI lightRange = RectI::withSize(renderData.lightMinPosition, Vec2I(renderData.lightMap.size()));
|
||||||
forEachRenderTile(renderData, lightRange, [&](Vec2I const& pos, RenderTile const& tile) {
|
forEachRenderTile(renderData, lightRange, [&](Vec2I const& pos, RenderTile const& tile) {
|
||||||
// Only adjust lighting for full tiles
|
// Only adjust lighting for full tiles
|
||||||
if (liquidDrawLevel(byteToFloat(tile.liquidLevel)) < 1.0f)
|
float drawLevel = liquidDrawLevel(byteToFloat(tile.liquidLevel));
|
||||||
|
if (drawLevel == 0.0f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto lightIndex = Vec2U(pos - renderData.lightMinPosition);
|
auto lightIndex = Vec2U(pos - renderData.lightMinPosition);
|
||||||
@ -46,7 +47,7 @@ void TilePainter::adjustLighting(WorldRenderData& renderData) const {
|
|||||||
|
|
||||||
auto const& liquid = m_liquids[tile.liquidId];
|
auto const& liquid = m_liquids[tile.liquidId];
|
||||||
Vec3F tileLight = Vec3F(lightValue);
|
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));
|
lightValue = Vec3B(tileLight.piecewiseMultiply(Vec3F::filled(1 - darknessLevel) + liquid.bottomLightMix * darknessLevel));
|
||||||
|
|
||||||
renderData.lightMap.set(lightIndex, lightValue);
|
renderData.lightMap.set(lightIndex, lightValue);
|
||||||
|
@ -45,7 +45,7 @@ WorldCamera& WorldPainter::camera() {
|
|||||||
return m_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.setScreenSize(m_renderer->screenSize());
|
||||||
m_camera.setTargetPixelRatio(Root::singleton().configuration()->get("zoomLevel").toFloat());
|
m_camera.setTargetPixelRatio(Root::singleton().configuration()->get("zoomLevel").toFloat());
|
||||||
|
|
||||||
@ -55,18 +55,6 @@ void WorldPainter::render(WorldRenderData& renderData) {
|
|||||||
|
|
||||||
m_tilePainter->setup(m_camera, 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
|
// Stars, Debris Fields, Sky, and Orbiters
|
||||||
|
|
||||||
m_environmentPainter->renderStars(m_camera.pixelRatio(), Vec2F(m_camera.screenSize()), renderData.skyRenderData);
|
m_environmentPainter->renderStars(m_camera.pixelRatio(), Vec2F(m_camera.screenSize()), renderData.skyRenderData);
|
||||||
@ -146,6 +134,10 @@ void WorldPainter::render(WorldRenderData& renderData) {
|
|||||||
m_tilePainter->cleanup();
|
m_tilePainter->cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorldPainter::adjustLighting(WorldRenderData& renderData) {
|
||||||
|
m_tilePainter->adjustLighting(renderData);
|
||||||
|
}
|
||||||
|
|
||||||
void WorldPainter::renderParticles(WorldRenderData& renderData, Particle::Layer layer) {
|
void WorldPainter::renderParticles(WorldRenderData& renderData, Particle::Layer layer) {
|
||||||
const int textParticleFontSize = m_assets->json("/rendering.config:textParticleFontSize").toInt();
|
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());
|
const RectF particleRenderWindow = RectF::withSize(Vec2F(), Vec2F(m_camera.screenSize())).padded(m_assets->json("/rendering.config:particleRenderWindowPadding").toInt());
|
||||||
|
@ -23,7 +23,8 @@ public:
|
|||||||
|
|
||||||
WorldCamera& camera();
|
WorldCamera& camera();
|
||||||
|
|
||||||
void render(WorldRenderData& renderData);
|
void render(WorldRenderData& renderData, function<void()> lightWaiter);
|
||||||
|
void adjustLighting(WorldRenderData& renderData);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void renderParticles(WorldRenderData& renderData, Particle::Layer layer);
|
void renderParticles(WorldRenderData& renderData, Particle::Layer layer);
|
||||||
|
Loading…
Reference in New Issue
Block a user