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

summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/CMakeLists.txt7
-rw-r--r--source/application/StarRenderer.hpp3
-rw-r--r--source/application/StarRenderer_opengl20.cpp57
-rw-r--r--source/application/StarRenderer_opengl20.hpp5
-rw-r--r--source/base/CMakeLists.txt1
-rw-r--r--source/base/StarAssets.cpp107
-rw-r--r--source/base/StarAssets.hpp8
-rw-r--r--source/base/StarCellularLightArray.cpp130
-rw-r--r--source/base/StarCellularLightArray.hpp72
-rw-r--r--source/base/StarCellularLighting.cpp65
-rw-r--r--source/base/StarCellularLighting.hpp101
-rw-r--r--source/client/StarClientApplication.cpp70
-rw-r--r--source/client/StarClientApplication.hpp4
-rw-r--r--source/core/StarImage.cpp6
-rw-r--r--source/core/StarImage.hpp28
-rw-r--r--source/core/StarJsonExtra.cpp4
-rw-r--r--source/game/StarItemDrop.cpp2
-rw-r--r--source/game/StarLightSource.hpp2
-rw-r--r--source/game/StarNetworkedAnimator.cpp2
-rw-r--r--source/game/StarNpc.cpp4
-rw-r--r--source/game/StarNpc.hpp2
-rw-r--r--source/game/StarObject.cpp2
-rw-r--r--source/game/StarParticleManager.cpp6
-rw-r--r--source/game/StarParticleManager.hpp2
-rw-r--r--source/game/StarPlayer.cpp8
-rw-r--r--source/game/StarPlayer.hpp4
-rw-r--r--source/game/StarProjectile.cpp4
-rw-r--r--source/game/StarProjectileDatabase.cpp2
-rw-r--r--source/game/StarProjectileDatabase.hpp2
-rw-r--r--source/game/StarToolUser.cpp19
-rw-r--r--source/game/StarToolUser.hpp2
-rw-r--r--source/game/StarWorldClient.cpp31
-rw-r--r--source/game/StarWorldClient.hpp8
-rw-r--r--source/game/StarWorldImpl.hpp4
-rw-r--r--source/game/StarWorldRenderData.hpp4
-rw-r--r--source/game/interfaces/StarBeamItem.cpp21
-rw-r--r--source/game/interfaces/StarBeamItem.hpp4
-rw-r--r--source/game/interfaces/StarToolUserEntity.hpp2
-rw-r--r--source/game/items/StarInspectionTool.cpp2
-rw-r--r--source/game/items/StarMaterialItem.cpp4
-rw-r--r--source/game/items/StarTools.cpp12
-rw-r--r--source/game/scripting/StarLuaAnimationComponent.hpp2
-rw-r--r--source/rendering/StarTilePainter.cpp11
-rw-r--r--source/rendering/StarWorldPainter.cpp1
44 files changed, 586 insertions, 251 deletions
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index 2994a43..d0fb879 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -32,6 +32,13 @@ set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../cmake)
set(CMAKE_CONFIGURATION_TYPES Debug RelWithAsserts RelWithDebInfo Release)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "")
set(CMAKE_EXE_LINKER_FLAGS_RELWITHASSERTS "" CACHE STRING "" FORCE)
+
+#include(CheckIPOSupported)
+#check_ipo_supported(RESULT lto_supported OUTPUT lto_output)
+#if(lto_supported)
+# set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
+#endif()
+
# Update the docstring on CMAKE_BUILD_TYPE to show what options we actually
# allow
# SET (CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING "Choose the type of build, options are: Debug RelWithAsserts RelWithDebInfo Release" FORCE)
diff --git a/source/application/StarRenderer.hpp b/source/application/StarRenderer.hpp
index 7b75077..77b53bd 100644
--- a/source/application/StarRenderer.hpp
+++ b/source/application/StarRenderer.hpp
@@ -141,8 +141,7 @@ public:
// The effect config will specify named parameters and textures which can be
// set here.
virtual void setEffectParameter(String const& parameterName, RenderEffectParameter const& parameter) = 0;
- virtual void setEffectTexture(String const& textureName, Image const& image) = 0;
-
+ virtual void setEffectTexture(String const& textureName, ImageView const& image) = 0;
virtual bool switchEffectConfig(String const& name) = 0;
// Any further rendering will be scissored based on this rect, specified in
diff --git a/source/application/StarRenderer_opengl20.cpp b/source/application/StarRenderer_opengl20.cpp
index ac141a4..ca29a70 100644
--- a/source/application/StarRenderer_opengl20.cpp
+++ b/source/application/StarRenderer_opengl20.cpp
@@ -118,7 +118,7 @@ Vec2U OpenGl20Renderer::screenSize() const {
}
OpenGl20Renderer::GlFrameBuffer::GlFrameBuffer(Json const& fbConfig) : config(fbConfig) {
- texture = createGlTexture(Image(), TextureAddressing::Clamp, TextureFiltering::Nearest);
+ texture = createGlTexture(ImageView(), TextureAddressing::Clamp, TextureFiltering::Nearest);
glBindTexture(GL_TEXTURE_2D, texture->glTextureId());
Vec2U size = jsonToVec2U(config.getArray("size", { 256, 256 }));
@@ -147,13 +147,15 @@ void OpenGl20Renderer::loadConfig(Json const& config) {
for (auto& pair : config.getObject("frameBuffers", {}))
m_frameBuffers[pair.first] = make_ref<GlFrameBuffer>(pair.second);
+
+ setScreenSize(m_screenSize);
}
void OpenGl20Renderer::loadEffectConfig(String const& name, Json const& effectConfig, StringMap<String> const& shaders) {
- if (m_effects.contains(name)) {
- Logger::warn("OpenGL effect {} already exists", name);
- switchEffectConfig(name);
- return;
+ if (auto effect = m_effects.ptr(name)) {
+ Logger::info("Reloading OpenGL effect {}", name);
+ glDeleteProgram(effect->program);
+ m_effects.erase(name);
}
GLint status = 0;
@@ -177,8 +179,18 @@ void OpenGl20Renderer::loadEffectConfig(String const& name, Json const& effectCo
return shader;
};
- GLuint vertexShader = compileShader(GL_VERTEX_SHADER, "vertex");
- GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, "fragment");
+ GLuint vertexShader = 0, fragmentShader = 0;
+ try {
+ vertexShader = compileShader(GL_VERTEX_SHADER, "vertex");
+ fragmentShader = compileShader(GL_FRAGMENT_SHADER, "fragment");
+ }
+ catch (RendererException const& e) {
+ Logger::error("Shader compile error, using default: {}", e.what());
+ if (vertexShader) glDeleteShader(vertexShader);
+ if (fragmentShader) glDeleteShader(fragmentShader);
+ vertexShader = compileShader(GL_VERTEX_SHADER, DefaultVertexShader);
+ fragmentShader = compileShader(GL_FRAGMENT_SHADER, DefaultFragmentShader);
+ }
GLuint program = glCreateProgram();
@@ -308,7 +320,7 @@ void OpenGl20Renderer::setEffectParameter(String const& parameterName, RenderEff
ptr->parameterValue = value;
}
-void OpenGl20Renderer::setEffectTexture(String const& textureName, Image const& image) {
+void OpenGl20Renderer::setEffectTexture(String const& textureName, ImageView const& image) {
auto ptr = m_currentEffect->textures.ptr(textureName);
if (!ptr)
return;
@@ -319,8 +331,8 @@ void OpenGl20Renderer::setEffectTexture(String const& textureName, Image const&
ptr->textureValue = createGlTexture(image, ptr->textureAddressing, ptr->textureFiltering);
} else {
glBindTexture(GL_TEXTURE_2D, ptr->textureValue->textureId);
- ptr->textureValue->textureSize = image.size();
- uploadTextureImage(image.pixelFormat(), image.size(), image.data());
+ ptr->textureValue->textureSize = image.size;
+ uploadTextureImage(image.format, image.size, image.data);
}
if (ptr->textureSizeUniform != -1) {
@@ -789,7 +801,9 @@ bool OpenGl20Renderer::logGlErrorSummary(String prefix) {
void OpenGl20Renderer::uploadTextureImage(PixelFormat pixelFormat, Vec2U size, uint8_t const* data) {
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ Maybe<GLenum> internalFormat;
GLenum format;
+ GLenum type = GL_UNSIGNED_BYTE;
if (pixelFormat == PixelFormat::RGB24)
format = GL_RGB;
else if (pixelFormat == PixelFormat::RGBA32)
@@ -798,10 +812,19 @@ void OpenGl20Renderer::uploadTextureImage(PixelFormat pixelFormat, Vec2U size, u
format = GL_BGR;
else if (pixelFormat == PixelFormat::BGRA32)
format = GL_BGRA;
- else
- throw RendererException("Unsupported texture format in OpenGL20Renderer::uploadTextureImage");
+ else {
+ type = GL_FLOAT;
+ if (pixelFormat == PixelFormat::RGB_F) {
+ internalFormat = GL_RGB32F;
+ format = GL_RGB;
+ } else if (pixelFormat == PixelFormat::RGBA_F) {
+ internalFormat = GL_RGBA32F;
+ format = GL_RGBA;
+ } else
+ throw RendererException("Unsupported texture format in OpenGL20Renderer::uploadTextureImage");
+ }
- glTexImage2D(GL_TEXTURE_2D, 0, format, size[0], size[1], 0, format, GL_UNSIGNED_BYTE, data);
+ glTexImage2D(GL_TEXTURE_2D, 0, internalFormat.value(format), size[0], size[1], 0, format, type, data);
}
void OpenGl20Renderer::flushImmediatePrimitives() {
@@ -813,12 +836,12 @@ void OpenGl20Renderer::flushImmediatePrimitives() {
renderGlBuffer(*m_immediateRenderBuffer, Mat3F::identity());
}
-auto OpenGl20Renderer::createGlTexture(Image const& image, TextureAddressing addressing, TextureFiltering filtering)
- -> RefPtr<GlLoneTexture> {
+auto OpenGl20Renderer::createGlTexture(ImageView const& image, TextureAddressing addressing, TextureFiltering filtering)
+ ->RefPtr<GlLoneTexture> {
auto glLoneTexture = make_ref<GlLoneTexture>();
glLoneTexture->textureFiltering = filtering;
glLoneTexture->textureAddressing = addressing;
- glLoneTexture->textureSize = image.size();
+ glLoneTexture->textureSize = image.size;
glGenTextures(1, &glLoneTexture->textureId);
if (glLoneTexture->textureId == 0)
@@ -844,7 +867,7 @@ auto OpenGl20Renderer::createGlTexture(Image const& image, TextureAddressing add
if (!image.empty())
- uploadTextureImage(image.pixelFormat(), image.size(), image.data());
+ uploadTextureImage(image.format, image.size, image.data);
return glLoneTexture;
}
diff --git a/source/application/StarRenderer_opengl20.hpp b/source/application/StarRenderer_opengl20.hpp
index 8c96775..fa406b6 100644
--- a/source/application/StarRenderer_opengl20.hpp
+++ b/source/application/StarRenderer_opengl20.hpp
@@ -25,7 +25,7 @@ public:
void loadEffectConfig(String const& name, Json const& effectConfig, StringMap<String> const& shaders) override;
void setEffectParameter(String const& parameterName, RenderEffectParameter const& parameter) override;
- void setEffectTexture(String const& textureName, Image const& image) override;
+ void setEffectTexture(String const& textureName, ImageView const& image) override;
void setScissorRect(Maybe<RectI> const& scissorRect) override;
@@ -188,7 +188,8 @@ private:
static bool logGlErrorSummary(String prefix);
static void uploadTextureImage(PixelFormat pixelFormat, Vec2U size, uint8_t const* data);
- static RefPtr<GlLoneTexture> createGlTexture(Image const& texture, TextureAddressing addressing, TextureFiltering filtering);
+
+ static RefPtr<GlLoneTexture> createGlTexture(ImageView const& image, TextureAddressing addressing, TextureFiltering filtering);
shared_ptr<GlRenderBuffer> createGlRenderBuffer();
diff --git a/source/base/CMakeLists.txt b/source/base/CMakeLists.txt
index f16257a..8f4d18b 100644
--- a/source/base/CMakeLists.txt
+++ b/source/base/CMakeLists.txt
@@ -25,6 +25,7 @@ SET (star_base_HEADERS
SET (star_base_SOURCES
StarAnimatedPartSet.cpp
StarAssets.cpp
+ StarCellularLightArray.cpp
StarCellularLighting.cpp
StarConfiguration.cpp
StarDirectoryAssetSource.cpp
diff --git a/source/base/StarAssets.cpp b/source/base/StarAssets.cpp
index 6593d3d..2bbe509 100644
--- a/source/base/StarAssets.cpp
+++ b/source/base/StarAssets.cpp
@@ -110,8 +110,15 @@ Assets::Assets(Settings settings, StringList assetSources) {
m_assetSources = std::move(assetSources);
auto luaEngine = LuaEngine::create();
+ m_luaEngine = luaEngine;
+ auto pushGlobalContext = [&luaEngine](String const& name, LuaCallbacks & callbacks) {
+ auto table = luaEngine->createTable();
+ for (auto const& p : callbacks.callbacks())
+ table.set(p.first, luaEngine->createWrappedFunction(p.second));
+ luaEngine->setGlobal(name, table);
+ };
+ pushGlobalContext("sb", LuaBindings::makeUtilityCallbacks());
auto decorateLuaContext = [this](LuaContext& context, MemoryAssetSourcePtr newFiles) {
- context.setCallbacks("sb", LuaBindings::makeUtilityCallbacks());
LuaCallbacks callbacks;
callbacks.registerCallbackWithSignature<StringSet, String>("byExtension", bind(&Assets::scanExtension, this, _1));
callbacks.registerCallbackWithSignature<Json, String>("json", bind(&Assets::json, this, _1));
@@ -133,38 +140,40 @@ Assets::Assets(Settings settings, StringList assetSources) {
return b ? scan(a.value(), *b) : scan(a.value());
});
- callbacks.registerCallback("add", [this, &newFiles](LuaEngine& engine, String const& path, LuaValue const& data) {
- ByteArray bytes;
- if (auto str = engine.luaMaybeTo<String>(data))
- bytes = ByteArray(str->utf8Ptr(), str->utf8Size());
- else {
- auto json = engine.luaTo<Json>(data).repr();
- bytes = ByteArray(json.utf8Ptr(), json.utf8Size());
- }
- newFiles->set(path, bytes);
- });
+ if (newFiles) {
+ callbacks.registerCallback("add", [this, &newFiles](LuaEngine& engine, String const& path, LuaValue const& data) {
+ ByteArray bytes;
+ if (auto str = engine.luaMaybeTo<String>(data))
+ bytes = ByteArray(str->utf8Ptr(), str->utf8Size());
+ else {
+ auto json = engine.luaTo<Json>(data).repr();
+ bytes = ByteArray(json.utf8Ptr(), json.utf8Size());
+ }
+ newFiles->set(path, bytes);
+ });
- callbacks.registerCallback("patch", [this, &newFiles](String const& path, String const& patchPath) -> bool {
- if (auto file = m_files.ptr(path)) {
- if (newFiles->contains(patchPath)) {
- file->patchSources.append(make_pair(patchPath, newFiles));
- return true;
- } else {
- if (auto asset = m_files.ptr(patchPath)) {
- file->patchSources.append(make_pair(patchPath, asset->source));
+ callbacks.registerCallback("patch", [this, &newFiles](String const& path, String const& patchPath) -> bool {
+ if (auto file = m_files.ptr(path)) {
+ if (newFiles->contains(patchPath)) {
+ file->patchSources.append(make_pair(patchPath, newFiles));
return true;
+ } else {
+ if (auto asset = m_files.ptr(patchPath)) {
+ file->patchSources.append(make_pair(patchPath, asset->source));
+ return true;
+ }
}
}
- }
- return false;
- });
+ return false;
+ });
- callbacks.registerCallback("erase", [this](String const& path) -> bool {
- bool erased = m_files.erase(path);
- if (erased)
- m_filesByExtension[AssetPath::extension(path).toLower()].erase(path);
- return erased;
- });
+ callbacks.registerCallback("erase", [this](String const& path) -> bool {
+ bool erased = m_files.erase(path);
+ if (erased)
+ m_filesByExtension[AssetPath::extension(path).toLower()].erase(path);
+ return erased;
+ });
+ }
context.setCallbacks("assets", callbacks);
};
@@ -883,21 +892,35 @@ Json Assets::readJson(String const& path) const {
try {
Json result = inputUtf8Json(streamData.begin(), streamData.end(), false);
for (auto const& pair : m_files.get(path).patchSources) {
- auto patchStream = pair.second->read(pair.first);
- auto patchJson = inputUtf8Json(patchStream.begin(), patchStream.end(), false);
- if (patchJson.isType(Json::Type::Array)) {
- auto patchData = patchJson.toArray();
- try {
- result = checkPatchArray(pair.first, pair.second, result, patchData, {});
- } catch (JsonPatchTestFail const& e) {
- Logger::debug("Patch test failure from file {} in source: '{}' at '{}'. Caused by: {}", pair.first, pair.second->metadata().value("name", ""), m_assetSourcePaths.getLeft(pair.second), e.what());
- } catch (JsonPatchException const& e) {
- Logger::error("Could not apply patch from file {} in source: '{}' at '{}'. Caused by: {}", pair.first, pair.second->metadata().value("name", ""), m_assetSourcePaths.getLeft(pair.second), e.what());
+ auto& patchPath = pair.first;
+ auto& patchSource = pair.second;
+ auto patchStream = patchSource->read(patchPath);
+ if (pair.first.endsWith(".lua")) {
+ MutexLocker luaLocker(m_luaMutex);
+ // Kae: i don't like that lock. perhaps have a LuaEngine and patch context cache per worker thread later on?
+ LuaContextPtr& context = m_patchContexts[patchPath];
+ if (!context) {
+ context = make_shared<LuaContext>(as<LuaEngine>(m_luaEngine.get())->createContext());
+ context->load(patchStream, patchPath);
+ }
+ auto newResult = context->invokePath<Json>("patch", result, path);
+ if (newResult)
+ result = std::move(newResult);
+ } else {
+ auto patchJson = inputUtf8Json(patchStream.begin(), patchStream.end(), false);
+ if (patchJson.isType(Json::Type::Array)) {
+ auto patchData = patchJson.toArray();
+ try {
+ result = checkPatchArray(patchPath, patchSource, result, patchData, {});
+ } catch (JsonPatchTestFail const& e) {
+ Logger::debug("Patch test failure from file {} in source: '{}' at '{}'. Caused by: {}", patchPath, patchSource->metadata().value("name", ""), m_assetSourcePaths.getLeft(patchSource), e.what());
+ } catch (JsonPatchException const& e) {
+ Logger::error("Could not apply patch from file {} in source: '{}' at '{}'. Caused by: {}", patchPath, patchSource->metadata().value("name", ""), m_assetSourcePaths.getLeft(patchSource), e.what());
+ }
+ } else if (patchJson.isType(Json::Type::Object)) {//Kae: Do a good ol' json merge instead if the .patch file is a Json object
+ result = jsonMergeNulling(result, patchJson.toObject());
+ }
}
- } else if (patchJson.isType(Json::Type::Object)) { //Kae: Do a good ol' json merge instead if the .patch file is a Json object
- auto patchData = patchJson.toObject();
- result = jsonMergeNulling(result, patchData);
- }
}
return result;
} catch (std::exception const& e) {
diff --git a/source/base/StarAssets.hpp b/source/base/StarAssets.hpp
index f945cf8..8cfbc52 100644
--- a/source/base/StarAssets.hpp
+++ b/source/base/StarAssets.hpp
@@ -7,6 +7,7 @@
#include "StarThread.hpp"
#include "StarAssetSource.hpp"
#include "StarAssetPath.hpp"
+#include "StarRefPtr.hpp"
namespace Star {
@@ -16,6 +17,8 @@ STAR_CLASS(Image);
STAR_STRUCT(FramesSpecification);
STAR_CLASS(Assets);
+STAR_CLASS(LuaContext);
+
STAR_EXCEPTION(AssetException, StarException);
// The contents of an assets .frames file, which can be associated with one or
@@ -313,6 +316,11 @@ private:
mutable StringMap<String> m_bestFramesFiles;
mutable StringMap<FramesSpecificationConstPtr> m_framesSpecifications;
+ // Lua
+ RefPtr<RefCounter> m_luaEngine; // dumb but to avoid including Lua.hpp in here...
+ mutable StringMap<LuaContextPtr> m_patchContexts;
+ mutable Mutex m_luaMutex;
+
// Paths of all used asset sources, in load order.
StringList m_assetSources;
diff --git a/source/base/StarCellularLightArray.cpp b/source/base/StarCellularLightArray.cpp
new file mode 100644
index 0000000..60a6d95
--- /dev/null
+++ b/source/base/StarCellularLightArray.cpp
@@ -0,0 +1,130 @@
+#include "StarCellularLightArray.hpp"
+// just specializing these in a cpp file so I can iterate on them without recompiling like 40 files!!
+
+namespace Star {
+
+template <>
+void CellularLightArray<ScalarLightTraits>::calculatePointLighting(size_t xmin, size_t ymin, size_t xmax, size_t ymax) {
+ float perBlockObstacleAttenuation = 1.0f / m_pointMaxObstacle;
+ float perBlockAirAttenuation = 1.0f / m_pointMaxAir;
+
+ for (PointLight light : m_pointLights) {
+ if (light.position[0] < 0 || light.position[0] > m_width - 1 || light.position[1] < 0 || light.position[1] > m_height - 1)
+ continue;
+
+ float maxIntensity = ScalarLightTraits::maxIntensity(light.value);
+ Vec2F beamDirection = Vec2F(1, 0).rotate(light.beamAngle);
+
+ float maxRange = maxIntensity * m_pointMaxAir;
+ // The min / max considering the radius of the light
+ size_t lxmin = std::floor(std::max<float>(xmin, light.position[0] - maxRange));
+ size_t lymin = std::floor(std::max<float>(ymin, light.position[1] - maxRange));
+ size_t lxmax = std::ceil(std::min<float>(xmax, light.position[0] + maxRange));
+ size_t lymax = std::ceil(std::min<float>(ymax, light.position[1] + maxRange));
+
+ for (size_t x = lxmin; x < lxmax; ++x) {
+ for (size_t y = lymin; y < lymax; ++y) {
+ LightValue lvalue = getLight(x, y);
+ // + 0.5f to correct block position to center
+ Vec2F blockPos = Vec2F(x + 0.5f, y + 0.5f);
+
+ Vec2F relativeLightPosition = blockPos - light.position;
+ float distance = relativeLightPosition.magnitude();
+ if (distance == 0.0f) {
+ setLight(x, y, light.value + lvalue);
+ continue;
+ }
+
+ float attenuation = distance * perBlockAirAttenuation;
+ if (attenuation >= 1.0f)
+ continue;
+
+ Vec2F direction = relativeLightPosition / distance;
+ if (light.beam > 0.0f) {
+ attenuation += (1.0f - light.beamAmbience) * clamp(light.beam * (1.0f - direction * beamDirection), 0.0f, 1.0f);
+ if (attenuation >= 1.0f)
+ continue;
+ }
+
+ float remainingAttenuation = maxIntensity - attenuation;
+ if (remainingAttenuation <= 0.0f)
+ continue;
+
+ // Need to circularize manhattan attenuation here
+ float circularizedPerBlockObstacleAttenuation = perBlockObstacleAttenuation / max(fabs(direction[0]), fabs(direction[1]));
+ float blockAttenuation = lineAttenuation(blockPos, light.position, circularizedPerBlockObstacleAttenuation, remainingAttenuation);
+
+ // Apply single obstacle boost (determine single obstacle by one
+ // block unit of attenuation).
+ attenuation += blockAttenuation + min(blockAttenuation, circularizedPerBlockObstacleAttenuation) * m_pointObstacleBoost;
+
+ if (attenuation < 1.0f)
+ setLight(x, y, lvalue + ScalarLightTraits::subtract(light.value, attenuation));
+ }
+ }
+ }
+}
+
+template <>
+void CellularLightArray<ColoredLightTraits>::calculatePointLighting(size_t xmin, size_t ymin, size_t xmax, size_t ymax) {
+ float perBlockObstacleAttenuation = 1.0f / m_pointMaxObstacle;
+ float perBlockAirAttenuation = 1.0f / m_pointMaxAir;
+
+ for (PointLight light : m_pointLights) {
+ if (light.position[0] < 0 || light.position[0] > m_width - 1 || light.position[1] < 0 || light.position[1] > m_height - 1)
+ continue;
+
+ float maxIntensity = ColoredLightTraits::maxIntensity(light.value);
+ Vec2F beamDirection = Vec2F(1, 0).rotate(light.beamAngle);
+
+ float maxRange = maxIntensity * m_pointMaxAir;
+ // The min / max considering the radius of the light
+ size_t lxmin = std::floor(std::max<float>(xmin, light.position[0] - maxRange));
+ size_t lymin = std::floor(std::max<float>(ymin, light.position[1] - maxRange));
+ size_t lxmax = std::ceil(std::min<float>(xmax, light.position[0] + maxRange));
+ size_t lymax = std::ceil(std::min<float>(ymax, light.position[1] + maxRange));
+
+ for (size_t x = lxmin; x < lxmax; ++x) {
+ for (size_t y = lymin; y < lymax; ++y) {
+ LightValue lvalue = getLight(x, y);
+ // + 0.5f to correct block position to center
+ Vec2F blockPos = Vec2F(x + 0.5f, y + 0.5f);
+
+ Vec2F relativeLightPosition = blockPos - light.position;
+ float distance = relativeLightPosition.magnitude();
+ if (distance == 0.0f) {
+ setLight(x, y, light.value + lvalue);
+ continue;
+ }
+
+ float attenuation = distance * perBlockAirAttenuation;
+ if (attenuation >= 1.0f)
+ continue;
+
+ Vec2F direction = relativeLightPosition / distance;
+ if (light.beam > 0.0f) {
+ attenuation += (1.0f - light.beamAmbience) * clamp(light.beam * (1.0f - direction * beamDirection), 0.0f, 1.0f);
+ if (attenuation >= 1.0f)
+ continue;
+ }
+
+ float remainingAttenuation = maxIntensity - attenuation;
+ if (remainingAttenuation <= 0.0f)
+ continue;
+
+ // Need to circularize manhattan attenuation here
+ float circularizedPerBlockObstacleAttenuation = perBlockObstacleAttenuation / max(fabs(direction[0]), fabs(direction[1]));
+ float blockAttenuation = lineAttenuation(blockPos, light.position, circularizedPerBlockObstacleAttenuation, remainingAttenuation);
+
+ // Apply single obstacle boost (determine single obstacle by one
+ // block unit of attenuation).
+ attenuation += blockAttenuation + min(blockAttenuation, circularizedPerBlockObstacleAttenuation) * m_pointObstacleBoost;
+
+ if (attenuation < 1.0f)
+ setLight(x, y, lvalue + ColoredLightTraits::subtract(light.value, attenuation));
+ }
+ }
+ }
+}
+
+} \ No newline at end of file
diff --git a/source/base/StarCellularLightArray.hpp b/source/base/StarCellularLightArray.hpp
index d73cacf..225d42b 100644
--- a/source/base/StarCellularLightArray.hpp
+++ b/source/base/StarCellularLightArray.hpp
@@ -11,6 +11,7 @@ struct ScalarLightTraits {
static float spread(float source, float dest, float drop);
static float subtract(float value, float drop);
+ static float multiply(float v1, float v2);
static float maxIntensity(float value);
static float minIntensity(float value);
@@ -26,6 +27,7 @@ struct ColoredLightTraits {
static Vec3F spread(Vec3F const& source, Vec3F const& dest, float drop);
static Vec3F subtract(Vec3F value, float drop);
+ static Vec3F multiply(Vec3F value, float drop);
static float maxIntensity(Vec3F const& value);
static float minIntensity(Vec3F const& value);
@@ -139,6 +141,10 @@ inline float ScalarLightTraits::subtract(float c, float drop) {
return std::max(c - drop, 0.0f);
}
+inline float ScalarLightTraits::multiply(float v1, float v2) {
+ return v1 * v2;
+}
+
inline float ScalarLightTraits::maxIntensity(float value) {
return value;
}
@@ -179,6 +185,10 @@ inline Vec3F ColoredLightTraits::subtract(Vec3F c, float drop) {
return c;
}
+inline Vec3F ColoredLightTraits::multiply(Vec3F c, float drop) {
+ return c * drop;
+}
+
inline float ColoredLightTraits::maxIntensity(Vec3F const& value) {
return value.max();
}
@@ -388,68 +398,6 @@ void CellularLightArray<LightTraits>::calculateLightSpread(size_t xMin, size_t y
}
template <typename LightTraits>
-void CellularLightArray<LightTraits>::calculatePointLighting(size_t xmin, size_t ymin, size_t xmax, size_t ymax) {
- float perBlockObstacleAttenuation = 1.0f / m_pointMaxObstacle;
- float perBlockAirAttenuation = 1.0f / m_pointMaxAir;
-
- for (PointLight light : m_pointLights) {
- if (light.position[0] < 0 || light.position[0] > m_width - 1 || light.position[1] < 0 || light.position[1] > m_height - 1)
- continue;
-
- float maxIntensity = LightTraits::maxIntensity(light.value);
- Vec2F beamDirection = Vec2F(1, 0).rotate(light.beamAngle);
-
- float maxRange = maxIntensity * m_pointMaxAir;
- // The min / max considering the radius of the light
- size_t lxmin = std::floor(std::max<float>(xmin, light.position[0] - maxRange));
- size_t lymin = std::floor(std::max<float>(ymin, light.position[1] - maxRange));
- size_t lxmax = std::ceil(std::min<float>(xmax, light.position[0] + maxRange));
- size_t lymax = std::ceil(std::min<float>(ymax, light.position[1] + maxRange));
-
- for (size_t x = lxmin; x < lxmax; ++x) {
- for (size_t y = lymin; y < lymax; ++y) {
- LightValue lvalue = getLight(x, y);
- // + 0.5f to correct block position to center
- Vec2F blockPos = Vec2F(x + 0.5f, y + 0.5f);
-
- Vec2F relativeLightPosition = blockPos - light.position;
- float distance = relativeLightPosition.magnitude();
- if (distance == 0.0f) {
- setLight(x, y, LightTraits::max(light.value, lvalue));
- continue;
- }
-
- float attenuation = distance * perBlockAirAttenuation;
- if (attenuation >= 1.0f)
- continue;
-
- Vec2F direction = relativeLightPosition / distance;
- if (light.beam > 0.0f) {
- attenuation += (1.0f - light.beamAmbience) * clamp(light.beam * (1.0f - direction * beamDirection), 0.0f, 1.0f);
- if (attenuation >= 1.0f)
- continue;
- }
-
- float remainingAttenuation = maxIntensity - LightTraits::minIntensity(lvalue) - attenuation;
- if (remainingAttenuation <= 0.0f)
- continue;
-
- // Need to circularize manhattan attenuation here
- float circularizedPerBlockObstacleAttenuation = perBlockObstacleAttenuation / max(fabs(direction[0]), fabs(direction[1]));
- float blockAttenuation = lineAttenuation(blockPos, light.position, circularizedPerBlockObstacleAttenuation, remainingAttenuation);
-
- // Apply single obstacle boost (determine single obstacle by one
- // block unit of attenuation).
- attenuation += blockAttenuation + min(blockAttenuation, circularizedPerBlockObstacleAttenuation) * m_pointObstacleBoost;
-
- if (attenuation < 1.0f)
- setLight(x, y, LightTraits::max(LightTraits::subtract(light.value, attenuation), lvalue));
- }
- }
- }
-}
-
-template <typename LightTraits>
float CellularLightArray<LightTraits>::lineAttenuation(Vec2F const& start, Vec2F const& end,
float perObstacleAttenuation, float maxAttenuation) {
// Run Xiaolin Wu's line algorithm from start to end, summing over colliding
diff --git a/source/base/StarCellularLighting.cpp b/source/base/StarCellularLighting.cpp
index c0a92ea..579f48a 100644
--- a/source/base/StarCellularLighting.cpp
+++ b/source/base/StarCellularLighting.cpp
@@ -2,6 +2,45 @@
namespace Star {
+Lightmap::Lightmap() : m_width(0), m_height(0) {}
+
+Lightmap::Lightmap(unsigned width, unsigned height) : m_width(width), m_height(height) {
+ m_data = std::make_unique<float[]>(len());
+}
+
+Lightmap::Lightmap(Lightmap const& lightMap) {
+ operator=(lightMap);
+}
+
+Lightmap::Lightmap(Lightmap&& lightMap) noexcept {
+ operator=(std::move(lightMap));
+}
+
+Lightmap& Lightmap::operator=(Lightmap const& lightMap) {
+ m_width = lightMap.m_width;
+ m_height = lightMap.m_height;
+ if (lightMap.m_data) {
+ m_data = std::make_unique<float[]>(len());
+ memcpy(m_data.get(), lightMap.m_data.get(), len());
+ }
+ return *this;
+}
+
+Lightmap& Lightmap::operator=(Lightmap&& lightMap) noexcept {
+ m_width = take(lightMap.m_width);
+ m_height = take(lightMap.m_height);
+ m_data = take(lightMap.m_data);
+ return *this;
+}
+
+Lightmap::operator ImageView() {
+ ImageView view;
+ view.data = (uint8_t*)m_data.get();
+ view.size = size();
+ view.format = PixelFormat::RGB_F;
+ return view;
+}
+
CellularLightingCalculator::CellularLightingCalculator(bool monochrome)
: m_monochrome(monochrome)
{
@@ -104,6 +143,32 @@ void CellularLightingCalculator::calculate(Image& output) {
}
}
+void CellularLightingCalculator::calculate(Lightmap& output) {
+ 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]);
+
+ output = Lightmap(arrayMax[0] - arrayMin[0], arrayMax[1] - arrayMin[1]);
+
+ if (m_monochrome) {
+ for (size_t x = arrayMin[0]; x < arrayMax[0]; ++x) {
+ for (size_t y = arrayMin[1]; y < arrayMax[1]; ++y) {
+ output.set(x - arrayMin[0], y - arrayMin[1], m_lightArray.right().getLight(x, y));
+ }
+ }
+ } else {
+ for (size_t x = arrayMin[0]; x < arrayMax[0]; ++x) {
+ for (size_t y = arrayMin[1]; y < arrayMax[1]; ++y) {
+ output.set(x - arrayMin[0], y - arrayMin[1], m_lightArray.left().getLight(x, y));
+ }
+ }
+ }
+}
+
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());
diff --git a/source/base/StarCellularLighting.hpp b/source/base/StarCellularLighting.hpp
index caa52ae..7cb230f 100644
--- a/source/base/StarCellularLighting.hpp
+++ b/source/base/StarCellularLighting.hpp
@@ -11,6 +11,105 @@
namespace Star {
+STAR_EXCEPTION(LightmapException, StarException);
+
+class Lightmap {
+public:
+ Lightmap();
+ Lightmap(unsigned width, unsigned height);
+ Lightmap(Lightmap const& lightMap);
+ Lightmap(Lightmap&& lightMap) noexcept;
+
+ Lightmap& operator=(Lightmap const& lightMap);
+ Lightmap& operator=(Lightmap&& lightMap) noexcept;
+
+ operator ImageView();
+
+ void set(unsigned x, unsigned y, float v);
+ void set(unsigned x, unsigned y, Vec3F const& v);
+ void add(unsigned x, unsigned y, Vec3F const& v);
+ Vec3F get(unsigned x, unsigned y) const;
+
+ bool empty() const;
+
+ Vec2U size() const;
+ unsigned width() const;
+ unsigned height() const;
+ float* data();
+
+private:
+ size_t len() const;
+
+ std::unique_ptr<float[]> m_data;
+ unsigned m_width;
+ unsigned m_height;
+};
+
+inline void Lightmap::set(unsigned x, unsigned y, float v) {
+ if (x >= m_width || y >= m_height) {
+ throw LightmapException(strf("[{}, {}] out of range in Lightmap::set", x, y));
+ return;
+ }
+ float* ptr = m_data.get() + (y * m_width * 3 + x * 3);
+ ptr[0] = ptr[1] = ptr[2] = v;
+}
+
+inline void Lightmap::set(unsigned x, unsigned y, Vec3F const& v) {
+ if (x >= m_width || y >= m_height) {
+ throw LightmapException(strf("[{}, {}] out of range in Lightmap::set", x, y));
+ return;
+ }
+ float* ptr = m_data.get() + (y * m_width * 3 + x * 3);
+ ptr[0] = v.x();
+ ptr[1] = v.y();
+ ptr[2] = v.z();
+}
+
+inline void Lightmap::add(unsigned x, unsigned y, Vec3F const& v) {
+ if (x >= m_width || y >= m_height) {
+ throw LightmapException(strf("[{}, {}] out of range in Lightmap::add", x, y));
+ return;
+ }
+ float* ptr = m_data.get() + (y * m_width * 3 + x * 3);
+ ptr[0] += v.x();
+ ptr[1] += v.y();
+ ptr[2] += v.z();
+}
+
+inline Vec3F Lightmap::get(unsigned x, unsigned y) const {
+ if (x >= m_width || y >= m_height) {
+ throw LightmapException(strf("[{}, {}] out of range in Lightmap::get", x, y));
+ return Vec3F();
+ }
+ float* ptr = m_data.get() + (y * m_width * 3 + x * 3);
+ return Vec3F(ptr[0], ptr[1], ptr[2]);
+}
+
+
+inline bool Lightmap::empty() const {
+ return m_width == 0 || m_height == 0;
+}
+
+inline Vec2U Lightmap::size() const {
+ return { m_width, m_height };
+}
+
+inline unsigned Lightmap::width() const {
+ return m_width;
+}
+
+inline unsigned Lightmap::height() const {
+ return m_height;
+}
+
+inline float* Lightmap::data() {
+ return m_data.get();
+}
+
+inline size_t Lightmap::len() const {
+ return m_width * m_height * 3;
+}
+
// Produce lighting values from an integral cellular grid. Allows for floating
// positional point and cellular light sources, as well as pre-lighting cells
// individually.
@@ -43,6 +142,8 @@ public:
// output image. The image will be reset to the size of the region given in
// the call to 'begin', and formatted as RGB24.
void calculate(Image& output);
+ // Same as above, but the color data in a float buffer instead.
+ void calculate(Lightmap& output);
void setupImage(Image& image, PixelFormat format = PixelFormat::RGB24) const;
private:
diff --git a/source/client/StarClientApplication.cpp b/source/client/StarClientApplication.cpp
index 54c78b3..e97a8b7 100644
--- a/source/client/StarClientApplication.cpp
+++ b/source/client/StarClientApplication.cpp
@@ -228,35 +228,8 @@ void ClientApplication::applicationInit(ApplicationControllerPtr appController)
void ClientApplication::renderInit(RendererPtr renderer) {
Application::renderInit(renderer);
- auto assets = m_root->assets();
-
- auto loadEffectConfig = [&](String const& name) {
- String path = strf("/rendering/effects/{}.config", name);
- if (assets->assetExists(path)) {
- StringMap<String> shaders;
- auto config = assets->json(path);
- auto shaderConfig = config.getObject("effectShaders");
- for (auto& entry : shaderConfig) {
- if (entry.second.isType(Json::Type::String)) {
- String shader = entry.second.toString();
- if (!shader.hasChar('\n')) {
- auto shaderBytes = assets->bytes(AssetPath::relativeTo(path, shader));
- shader = std::string(shaderBytes->ptr(), shaderBytes->size());
- }
- shaders[entry.first] = shader;
- }
- }
-
- renderer->loadEffectConfig(name, config, shaders);
- }
- else
- Logger::warn("No rendering config found for renderer with id '{}'", renderer->rendererId());
- };
-
- renderer->loadConfig(assets->json("/rendering/opengl20.config"));
-
- loadEffectConfig("world");
- loadEffectConfig("interface");
+ renderReload();
+ m_root->registerReloadListener(m_reloadListener = make_shared<CallbackListener>([this]() { renderReload(); }));
if (m_root->configuration()->get("limitTextureAtlasSize").optBool().value(false))
renderer->setSizeLimitEnabled(true);
@@ -427,12 +400,7 @@ void ClientApplication::render() {
auto paintStart = Time::monotonicMicroseconds();
m_worldPainter->render(m_renderData, [&]() -> bool {
- if (auto newMinPosition = worldClient->waitForLighting(&m_renderData.lightMap)) {
- m_renderData.lightMinPosition = *newMinPosition;
- return true;
- } else {
- return false;
- }
+ return worldClient->waitForLighting(&m_renderData);
});
LogMap::set("client_render_world_painter", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - paintStart));
LogMap::set("client_render_world_total", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - totalStart));
@@ -458,6 +426,38 @@ void ClientApplication::getAudioData(int16_t* sampleData, size_t frameCount) {
}
}
+void ClientApplication::renderReload() {
+ auto assets = m_root->assets();
+ auto renderer = Application::renderer();
+
+ auto loadEffectConfig = [&](String const& name) {
+ String path = strf("/rendering/effects/{}.config", name);
+ if (assets->assetExists(path)) {
+ StringMap<String> shaders;
+ auto config = assets->json(path);
+ auto shaderConfig = config.getObject("effectShaders");
+ for (auto& entry : shaderConfig) {
+ if (entry.second.isType(Json::Type::String)) {
+ String shader = entry.second.toString();
+ if (!shader.hasChar('\n')) {
+ auto shaderBytes = assets->bytes(AssetPath::relativeTo(path, shader));
+ shader = std::string(shaderBytes->ptr(), shaderBytes->size());
+ }
+ shaders[entry.first] = shader;
+ }
+ }
+
+ renderer->loadEffectConfig(name, config, shaders);
+ } else
+ Logger::warn("No rendering config found for renderer with id '{}'", renderer->rendererId());
+ };
+
+ renderer->loadConfig(assets->json("/rendering/opengl20.config"));
+
+ loadEffectConfig("world");
+ loadEffectConfig("interface");
+}
+
void ClientApplication::changeState(MainAppState newState) {
MainAppState oldState = m_state;
m_state = newState;
diff --git a/source/client/StarClientApplication.hpp b/source/client/StarClientApplication.hpp
index 6f80349..5670595 100644
--- a/source/client/StarClientApplication.hpp
+++ b/source/client/StarClientApplication.hpp
@@ -53,6 +53,8 @@ private:
String password;
};
+ void renderReload();
+
void changeState(MainAppState newState);
void setError(String const& error);
void setError(String const& error, std::exception const& e);
@@ -71,6 +73,8 @@ private:
RootUPtr m_root;
ThreadFunction<void> m_rootLoader;
+ CallbackListenerPtr m_reloadListener;
+
MainAppState m_state = MainAppState::Startup;
// Valid after applicationInit is called
diff --git a/source/core/StarImage.cpp b/source/core/StarImage.cpp
index 0147369..82e3b05 100644
--- a/source/core/StarImage.cpp
+++ b/source/core/StarImage.cpp
@@ -518,4 +518,10 @@ void Image::writePng(IODevicePtr device) const {
png_destroy_write_struct(&png_ptr, &info_ptr);
}
+ImageView::ImageView(Image const& image) {
+ size = image.size();
+ data = image.data();
+ format = image.pixelFormat();
+}
+
}
diff --git a/source/core/StarImage.hpp b/source/core/StarImage.hpp
index 6f186df..478d074 100644
--- a/source/core/StarImage.hpp
+++ b/source/core/StarImage.hpp
@@ -6,11 +6,13 @@
namespace Star {
-enum class PixelFormat {
+enum class PixelFormat : uint8_t {
RGB24,
RGBA32,
BGR24,
- BGRA32
+ BGRA32,
+ RGB_F,
+ RGBA_F
};
uint8_t bitsPerPixel(PixelFormat pf);
@@ -148,8 +150,12 @@ inline uint8_t bitsPerPixel(PixelFormat pf) {
return 32;
case PixelFormat::BGR24:
return 24;
- default:
+ case PixelFormat::BGRA32:
return 32;
+ case PixelFormat::RGB_F:
+ return 96;
+ default:
+ return 128;
}
}
@@ -161,8 +167,12 @@ inline uint8_t bytesPerPixel(PixelFormat pf) {
return 4;
case PixelFormat::BGR24:
return 3;
- default:
+ case PixelFormat::BGRA32:
return 4;
+ case PixelFormat::RGB_F:
+ return 12;
+ default:
+ return 16;
}
}
@@ -307,4 +317,14 @@ void Image::forEachPixel(CallbackType&& callback) {
}
}
+struct ImageView {
+ inline bool empty() const { return size.x() == 0 || size.y() == 0; }
+ ImageView() = default;
+ ImageView(Image const& image);
+
+ Vec2U size{0, 0};
+ uint8_t const* data = nullptr;
+ PixelFormat format = PixelFormat::RGB24;
+};
+
}
diff --git a/source/core/StarJsonExtra.cpp b/source/core/StarJsonExtra.cpp
index dcf2bf6..2517b7b 100644
--- a/source/core/StarJsonExtra.cpp
+++ b/source/core/StarJsonExtra.cpp
@@ -214,7 +214,6 @@ Color jsonToColor(Json const& v) {
if (v.type() != Json::Type::Array || (v.size() != 3 && v.size() != 4))
throw JsonException("Json not an array of size 3 or 4 in jsonToColor");
Color c = Color::rgba(0, 0, 0, 255);
-
c.setRed(v.getInt(0));
c.setGreen(v.getInt(1));
c.setBlue(v.getInt(2));
@@ -235,9 +234,8 @@ Json jsonFromColor(Color const& color) {
result.push_back(color.red());
result.push_back(color.green());
result.push_back(color.blue());
- if (color.alpha() != 255) {
+ if (color.alpha() < 255)
result.push_back(color.alpha());
- }
return result;
}
diff --git a/source/game/StarItemDrop.cpp b/source/game/StarItemDrop.cpp
index 1df91f9..f3a74c7 100644
--- a/source/game/StarItemDrop.cpp
+++ b/source/game/StarItemDrop.cpp
@@ -321,7 +321,7 @@ void ItemDrop::render(RenderCallback* renderCallback) {
void ItemDrop::renderLightSources(RenderCallback* renderCallback) {
LightSource light;
light.pointLight = false;
- light.color = Vec3B::filled(20);
+ light.color = Vec3F::filled(20.f / 255.f);
light.position = position();
renderCallback->addLightSource(std::move(light));
}
diff --git a/source/game/StarLightSource.hpp b/source/game/StarLightSource.hpp
index 8810220..a6948cb 100644
--- a/source/game/StarLightSource.hpp
+++ b/source/game/StarLightSource.hpp
@@ -7,7 +7,7 @@ namespace Star {
struct LightSource {
Vec2F position;
- Vec3B color;
+ Vec3F color;
bool pointLight;
// pointBeam of 0.0 means light has no beam component, as pointBeam goes up,
diff --git a/source/game/StarNetworkedAnimator.cpp b/source/game/StarNetworkedAnimator.cpp
index f64d293..d013c48 100644
--- a/source/game/StarNetworkedAnimator.cpp
+++ b/source/game/StarNetworkedAnimator.cpp
@@ -716,7 +716,7 @@ List<LightSource> NetworkedAnimator::lightSources(Vec2F const& translate) const
lightSources.append(LightSource{
position + translate,
- color.toRgb(),
+ color.toRgbF(),
pair.second.pointLight,
pair.second.pointBeam,
pointAngle,
diff --git a/source/game/StarNpc.cpp b/source/game/StarNpc.cpp
index 476dfb4..5450e6f 100644
--- a/source/game/StarNpc.cpp
+++ b/source/game/StarNpc.cpp
@@ -1014,8 +1014,8 @@ bool Npc::isAdmin() const {
return false;
}
-Vec4B Npc::favoriteColor() const {
- return Color::White.toRgba();
+Color Npc::favoriteColor() const {
+ return Color::White;
}
float Npc::beamGunRadius() const {
diff --git a/source/game/StarNpc.hpp b/source/game/StarNpc.hpp
index 083abc6..ab8bc0f 100644
--- a/source/game/StarNpc.hpp
+++ b/source/game/StarNpc.hpp
@@ -143,7 +143,7 @@ public:
Direction facingDirection() const override;
Direction walkingDirection() const override;
bool isAdmin() const override;
- Vec4B favoriteColor() const override;
+ Color favoriteColor() const override;
float beamGunRadius() const override;
void addParticles(List<Particle> const& particles) override;
void addSound(String const& sound, float volume = 1.0f, float pitch = 1.0f) override;
diff --git a/source/game/StarObject.cpp b/source/game/StarObject.cpp
index c56229e..7bac350 100644
--- a/source/game/StarObject.cpp
+++ b/source/game/StarObject.cpp
@@ -261,7 +261,7 @@ List<LightSource> Object::lightSources() const {
LightSource lightSource;
lightSource.position = position() + centerOfTile(orientation->lightPosition);
- lightSource.color = color.toRgb();
+ lightSource.color = color.toRgbF();
lightSource.pointLight = m_config->pointLight;
lightSource.pointBeam = m_config->pointBeam;
lightSource.beamAngle = orientation->beamAngle;
diff --git a/source/game/StarParticleManager.cpp b/source/game/StarParticleManager.cpp
index e4e028c..6ba0dbf 100644
--- a/source/game/StarParticleManager.cpp
+++ b/source/game/StarParticleManager.cpp
@@ -103,11 +103,11 @@ List<Particle> const& ParticleManager::particles() const {
return m_particles;
}
-List<pair<Vec2F, Vec3B>> ParticleManager::lightSources() const {
- List<pair<Vec2F, Vec3B>> lsources;
+List<pair<Vec2F, Vec3F>> ParticleManager::lightSources() const {
+ List<pair<Vec2F, Vec3F>> lsources;
for (auto const& particle : m_particles) {
if (particle.light != Color::Clear)
- lsources.append({particle.position, particle.light.toRgb()});
+ lsources.append({particle.position, particle.light.toRgbF()});
}
return lsources;
}
diff --git a/source/game/StarParticleManager.hpp b/source/game/StarParticleManager.hpp
index 3a94d9f..3371d89 100644
--- a/source/game/StarParticleManager.hpp
+++ b/source/game/StarParticleManager.hpp
@@ -24,7 +24,7 @@ public:
void update(float dt, RectF const& cullRegion, float wind);
List<Particle> const& particles() const;
- List<pair<Vec2F, Vec3B>> lightSources() const;
+ List<pair<Vec2F, Vec3F>> lightSources() const;
private:
enum class TileType { Colliding, Water, Empty };
diff --git a/source/game/StarPlayer.cpp b/source/game/StarPlayer.cpp
index e9f0daf..7d751af 100644
--- a/source/game/StarPlayer.cpp
+++ b/source/game/StarPlayer.cpp
@@ -1912,13 +1912,13 @@ bool Player::isAdmin() const {
return m_isAdmin;
}
-void Player::setFavoriteColor(Vec4B color) {
- m_identity.color = color;
+void Player::setFavoriteColor(Color color) {
+ m_identity.color = color.toRgba();
updateIdentity();
}
-Vec4B Player::favoriteColor() const {
- return m_identity.color;
+Color Player::favoriteColor() const {
+ return Color::rgba(m_identity.color);
}
bool Player::isTeleporting() const {
diff --git a/source/game/StarPlayer.hpp b/source/game/StarPlayer.hpp
index 933f623..fb32005 100644
--- a/source/game/StarPlayer.hpp
+++ b/source/game/StarPlayer.hpp
@@ -354,8 +354,8 @@ public:
bool isDead() const;
void kill();
- void setFavoriteColor(Vec4B color);
- Vec4B favoriteColor() const override;
+ void setFavoriteColor(Color color);
+ Color favoriteColor() const override;
// Starts the teleport animation sequence, locking player movement and
// preventing some update code
diff --git a/source/game/StarProjectile.cpp b/source/game/StarProjectile.cpp
index cfb93ba..5a73e8b 100644
--- a/source/game/StarProjectile.cpp
+++ b/source/game/StarProjectile.cpp
@@ -379,7 +379,7 @@ void Projectile::renderLightSources(RenderCallback* renderCallback) {
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.toRgbF(), m_config->pointLight, 0.0f, 0.0f, 0.0f});
}
Maybe<Json> Projectile::receiveMessage(ConnectionId sendingConnection, String const& message, JsonArray const& args) {
@@ -824,7 +824,7 @@ void Projectile::processAction(Json const& action) {
m_pendingRenderables.append(LightSource{
position(),
- jsonToColor(parameters.get("color")).toRgb(),
+ jsonToColor(parameters.get("color")).toRgbF(),
parameters.getBool("pointLight", true),
0.0f,
0.0f,
diff --git a/source/game/StarProjectileDatabase.cpp b/source/game/StarProjectileDatabase.cpp
index fd52df6..dd7327b 100644
--- a/source/game/StarProjectileDatabase.cpp
+++ b/source/game/StarProjectileDatabase.cpp
@@ -116,7 +116,7 @@ ProjectileConfigPtr ProjectileDatabase::readConfig(String const& path) {
projectileConfig->fullbright = config.getBool("fullbright", false);
projectileConfig->renderLayer = parseRenderLayer(config.getString("renderLayer", "Projectile"));
- projectileConfig->lightColor = jsonToVec3B(config.get("lightColor", JsonArray{0, 0, 0}));
+ projectileConfig->lightColor = jsonToColor(config.get("lightColor", JsonArray{0, 0, 0}));
projectileConfig->lightPosition = jsonToVec2F(config.get("lightPosition", JsonArray{0, 0}));
projectileConfig->pointLight = config.getBool("pointLight", false);
diff --git a/source/game/StarProjectileDatabase.hpp b/source/game/StarProjectileDatabase.hpp
index f78f150..833d0eb 100644
--- a/source/game/StarProjectileDatabase.hpp
+++ b/source/game/StarProjectileDatabase.hpp
@@ -66,7 +66,7 @@ struct ProjectileConfig {
bool fullbright = false;
EntityRenderLayer renderLayer;
- Vec3B lightColor;
+ Color lightColor;
Vec2F lightPosition;
bool pointLight = false;
diff --git a/source/game/StarToolUser.cpp b/source/game/StarToolUser.cpp
index 4951128..4135dd0 100644
--- a/source/game/StarToolUser.cpp
+++ b/source/game/StarToolUser.cpp
@@ -165,7 +165,7 @@ Maybe<float> ToolUser::toolRadius() const {
return {};
}
-List<Drawable> ToolUser::renderObjectPreviews(Vec2F aimPosition, Direction walkingDirection, bool inToolRange, Vec4B favoriteColor) const {
+List<Drawable> ToolUser::renderObjectPreviews(Vec2F aimPosition, Direction walkingDirection, bool inToolRange, Color favoriteColor) const {
if (m_suppress.get() || !m_user)
return {};
@@ -178,21 +178,16 @@ List<Drawable> ToolUser::renderObjectPreviews(Vec2F aimPosition, Direction walki
Color opacityMask = Color::White;
opacityMask.setAlphaF(item->getAppropriateOpacity());
- Vec4B favoriteColorTrans;
- if (inToolRange && objectDatabase->canPlaceObject(m_user->world(), aimPos, item->objectName())) {
- favoriteColorTrans = favoriteColor;
- } else {
- Color color = Color::rgba(favoriteColor);
- color.setHue(color.hue() + 120);
- favoriteColorTrans = color.toRgba();
- }
+ Color favoriteColorTrans = favoriteColor;
+ if (!inToolRange || !objectDatabase->canPlaceObject(m_user->world(), aimPos, item->objectName()))
+ favoriteColorTrans.setHue(favoriteColor.hue() + 120);
- favoriteColorTrans[3] = m_objectPreviewOuterAlpha * 255;
- Color nearWhite = Color::rgba(favoriteColorTrans);
+ favoriteColorTrans.setAlphaF(m_objectPreviewOuterAlpha);
+ Color nearWhite = favoriteColorTrans;
nearWhite.setValue(1 - (1 - nearWhite.value()) / 5);
nearWhite.setSaturation(nearWhite.saturation() / 5);
nearWhite.setAlphaF(m_objectPreviewInnerAlpha);
- ImageOperation op = BorderImageOperation{m_beamGunGlowBorder, nearWhite.toRgba(), favoriteColorTrans, false, false};
+ ImageOperation op = BorderImageOperation{m_beamGunGlowBorder, nearWhite.toRgba(), favoriteColorTrans.toRgba(), false, false};
for (Drawable& drawable : drawables) {
if (drawable.isImage())
diff --git a/source/game/StarToolUser.hpp b/source/game/StarToolUser.hpp
index de1960c..41fe98f 100644
--- a/source/game/StarToolUser.hpp
+++ b/source/game/StarToolUser.hpp
@@ -43,7 +43,7 @@ public:
// with the rest of everything else, there are TILE previews and OBJECT
// previews, but of course one has to go through the render method and the
// other has to be rendered separately.
- List<Drawable> renderObjectPreviews(Vec2F aimPosition, Direction walkingDirection, bool inToolRange, Vec4B favoriteColor) const;
+ List<Drawable> renderObjectPreviews(Vec2F aimPosition, Direction walkingDirection, bool inToolRange, Color favoriteColor) const;
// Returns the facing override direciton if there is one
Maybe<Direction> setupHumanoidHandItems(Humanoid& humanoid, Vec2F position, Vec2F aimPosition) const;
void setupHumanoidHandItemDrawables(Humanoid& humanoid) const;
diff --git a/source/game/StarWorldClient.cpp b/source/game/StarWorldClient.cpp
index 5e6dc0e..df69b94 100644
--- a/source/game/StarWorldClient.cpp
+++ b/source/game/StarWorldClient.cpp
@@ -1375,21 +1375,23 @@ void WorldClient::collectLiquid(List<Vec2I> const& tilePositions, LiquidId liqui
m_outgoingPackets.append(make_shared<CollectLiquidPacket>(tilePositions, liquidId));
}
-Maybe<Vec2I> WorldClient::waitForLighting(Image* out) {
+bool WorldClient::waitForLighting(WorldRenderData* renderData) {
MutexLocker prepLocker(m_lightMapPrepMutex);
MutexLocker lightMapLocker(m_lightMapMutex);
- if (out && !m_lightMap.empty()) {
+ if (renderData && !m_lightMap.empty()) {
for (auto& previewTile : m_previewTiles) {
if (previewTile.updateLight) {
Vec2I lightArrayPos = m_geometry.diff(previewTile.position, m_lightMinPosition);
- if (lightArrayPos[0] >= 0 && lightArrayPos[0] < (int)m_lightMap.width() && lightArrayPos[1] >= 0 && lightArrayPos[1] < (int)m_lightMap.height())
- m_lightMap.set(Vec2U(lightArrayPos), previewTile.light);
+ if (lightArrayPos[0] >= 0 && lightArrayPos[0] < (int)m_lightMap.width()
+ && lightArrayPos[1] >= 0 && lightArrayPos[1] < (int)m_lightMap.height())
+ m_lightMap.set(lightArrayPos[0], lightArrayPos[1], Color::v3bToFloat(previewTile.light));
}
}
- *out = std::move(m_lightMap);
- return m_lightMinPosition;
+ renderData->lightMap = std::move(m_lightMap);
+ renderData->lightMinPosition = m_lightMinPosition;
+ return true;
}
- return {};
+ return false;
}
WorldClient::BroadcastCallback& WorldClient::broadcastCallback() {
@@ -1636,25 +1638,30 @@ void WorldClient::lightingTileGather() {
void WorldClient::lightingCalc() {
MutexLocker prepLocker(m_lightMapPrepMutex);
+
RectI lightRange = m_pendingLightRange;
List<LightSource> lights = std::move(m_pendingLights);
- List<std::pair<Vec2F, Vec3B>> particleLights = std::move(m_pendingParticleLights);
+ List<std::pair<Vec2F, Vec3F>> particleLights = std::move(m_pendingParticleLights);
m_lightingCalculator.setMonochrome(Root::singleton().configuration()->get("monochromeLighting").toBool());
m_lightingCalculator.begin(lightRange);
lightingTileGather();
+
prepLocker.unlock();
+
+
for (auto const& light : lights) {
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));
+ m_lightingCalculator.addPointLight(position, light.color, light.pointBeam, light.beamAngle, light.beamAmbience);
+ else {
+ m_lightingCalculator.addSpreadLight(position, light.color);
+ }
}
for (auto const& lightPair : particleLights) {
Vec2F position = m_geometry.nearestTo(Vec2F(m_lightingCalculator.calculationRegion().min()), lightPair.first);
- m_lightingCalculator.addSpreadLight(position, Color::v3bToFloat(lightPair.second));
+ m_lightingCalculator.addSpreadLight(position, lightPair.second);
}
m_lightingCalculator.calculate(m_pendingLightMap);
diff --git a/source/game/StarWorldClient.hpp b/source/game/StarWorldClient.hpp
index 6ccd52e..6f40b63 100644
--- a/source/game/StarWorldClient.hpp
+++ b/source/game/StarWorldClient.hpp
@@ -170,7 +170,7 @@ public:
void collectLiquid(List<Vec2I> const& tilePositions, LiquidId liquidId);
- Maybe<Vec2I> waitForLighting(Image* out = nullptr);
+ bool waitForLighting(WorldRenderData* renderData = nullptr);
typedef std::function<bool(PlayerPtr, StringView)> BroadcastCallback;
BroadcastCallback& broadcastCallback();
@@ -278,10 +278,10 @@ private:
Mutex m_lightMapPrepMutex;
Mutex m_lightMapMutex;
- Image m_pendingLightMap;
- Image m_lightMap;
+ Lightmap m_pendingLightMap;
+ Lightmap m_lightMap;
List<LightSource> m_pendingLights;
- List<std::pair<Vec2F, Vec3B>> m_pendingParticleLights;
+ List<std::pair<Vec2F, Vec3F>> m_pendingParticleLights;
RectI m_pendingLightRange;
Vec2I m_lightMinPosition;
List<PreviewTile> m_previewTiles;
diff --git a/source/game/StarWorldImpl.hpp b/source/game/StarWorldImpl.hpp
index 828ed1e..dec827f 100644
--- a/source/game/StarWorldImpl.hpp
+++ b/source/game/StarWorldImpl.hpp
@@ -446,9 +446,9 @@ namespace WorldImpl {
for (auto const& light : entity->lightSources()) {
Vec2F position = worldGeometry.nearestTo(Vec2F(lighting.calculationRegion().min()), light.position);
if (light.pointLight)
- lighting.addPointLight(position, Color::v3bToFloat(light.color).sum() / 3.0f, light.pointBeam, light.beamAngle, light.beamAmbience);
+ lighting.addPointLight(position, light.color.sum() / 3.0f, light.pointBeam, light.beamAngle, light.beamAmbience);
else
- lighting.addSpreadLight(position, Color::v3bToFloat(light.color).sum() / 3.0f);
+ lighting.addSpreadLight(position, light.color.sum() / 3.0f);
}
}
diff --git a/source/game/StarWorldRenderData.hpp b/source/game/StarWorldRenderData.hpp
index b392615..0030a10 100644
--- a/source/game/StarWorldRenderData.hpp
+++ b/source/game/StarWorldRenderData.hpp
@@ -9,6 +9,7 @@
#include "StarWeatherTypes.hpp"
#include "StarEntity.hpp"
#include "StarThread.hpp"
+#include "StarCellularLighting.hpp"
namespace Star {
@@ -17,6 +18,7 @@ struct EntityDrawables {
Map<EntityRenderLayer, List<Drawable>> layers;
};
+
struct WorldRenderData {
void clear();
@@ -25,7 +27,7 @@ struct WorldRenderData {
Vec2I tileMinPosition;
RenderTileArray tiles;
Vec2I lightMinPosition;
- Image lightMap;
+ Lightmap lightMap;
List<EntityDrawables> entityDrawables;
List<Particle> const* particles;
diff --git a/source/game/interfaces/StarBeamItem.cpp b/source/game/interfaces/StarBeamItem.cpp
index 2bf8e02..030a29c 100644
--- a/source/game/interfaces/StarBeamItem.cpp
+++ b/source/game/interfaces/StarBeamItem.cpp
@@ -38,7 +38,7 @@ BeamItem::BeamItem(Json config) {
m_innerBrightnessScale = config.get("innerBrightnessScale").toFloat();
m_firstStripeThickness = config.get("firstStripeThickness").toFloat();
m_secondStripeThickness = config.get("secondStripeThickness").toFloat();
- m_color = {255, 255, 255, 255};
+ m_color = Color::White;
m_particleGenerateCooldown = .25;
m_inRangeLastUpdate = false;
}
@@ -160,12 +160,9 @@ List<Drawable> BeamItem::beamDrawables(bool canPlace) const {
if ((endPoint - owner()->position()).magnitude() <= m_range && curveLen <= m_range) {
m_inRangeLastUpdate = true;
int numLines = projectOntoRange(m_minBeamLines, m_maxBeamLines);
- Vec4B mainColor = m_color;
- if (!canPlace) {
- Color temp = Color::rgba(m_color);
- temp.setHue(temp.hue() + 120);
- mainColor = temp.toRgba();
- }
+ Color mainColor = m_color;
+ if (!canPlace)
+ mainColor.setHue(mainColor.hue() + 120);
m_lastUpdateColor = mainColor;
String endImage = "";
@@ -189,9 +186,9 @@ List<Drawable> BeamItem::beamDrawables(bool canPlace) const {
for (auto line = 0; line < numLines; line++) {
float lineThickness = rangeRand(m_beamWidthDev, m_minBeamWidth, m_maxBeamWidth);
float beamTransparency = rangeRand(m_beamTransDev, m_minBeamTrans, m_maxBeamTrans);
- mainColor[3] = mainColor[3] * beamTransparency;
+ mainColor.setAlphaF(mainColor.alphaF() * beamTransparency);
Vec2F previousLoc = m_beamCurve.origin(); // lines meet at origin and dest.
- Color innerStripe = Color::rgba(mainColor);
+ Color innerStripe = mainColor;
innerStripe.setValue(1 - (1 - innerStripe.value()) / m_innerBrightnessScale);
innerStripe.setSaturation(innerStripe.saturation() / m_innerBrightnessScale);
Vec4B firstStripe = innerStripe.toRgba();
@@ -206,7 +203,7 @@ List<Drawable> BeamItem::beamDrawables(bool canPlace) const {
m_beamCurve.pointAt(pos) + Vec2F(rangeRand(m_beamJitterDev, -m_maxBeamJitter, m_maxBeamJitter),
rangeRand(m_beamJitterDev, -m_maxBeamJitter, m_maxBeamJitter));
res.push_back(
- Drawable::makeLine(Line2F(previousLoc, currentLoc), lineThickness, Color::rgba(mainColor), Vec2F()));
+ Drawable::makeLine(Line2F(previousLoc, currentLoc), lineThickness, mainColor, Vec2F()));
res.push_back(Drawable::makeLine(Line2F(previousLoc, currentLoc),
lineThickness * m_firstStripeThickness,
Color::rgba(firstStripe),
@@ -218,7 +215,7 @@ List<Drawable> BeamItem::beamDrawables(bool canPlace) const {
previousLoc = std::move(currentLoc);
}
res.push_back(Drawable::makeLine(
- Line2F(previousLoc, m_beamCurve.dest()), lineThickness, Color::rgba(mainColor), Vec2F()));
+ Line2F(previousLoc, m_beamCurve.dest()), lineThickness, mainColor, Vec2F()));
res.push_back(Drawable::makeLine(Line2F(previousLoc, m_beamCurve.dest()),
lineThickness * m_firstStripeThickness,
Color::rgba(firstStripe),
@@ -243,7 +240,7 @@ List<Drawable> BeamItem::beamDrawables(bool canPlace) const {
beamParticle.position = m_beamCurve.pointAt(curveLoc);
beamParticle.size = 1.0f;
- Color randomColor = Color::rgba(m_lastUpdateColor);
+ Color randomColor = m_lastUpdateColor;
randomColor.setValue(1 - (1 - randomColor.value()) / Random::randf(1, 4));
randomColor.setSaturation(randomColor.saturation() / Random::randf(1, 4));
diff --git a/source/game/interfaces/StarBeamItem.hpp b/source/game/interfaces/StarBeamItem.hpp
index 8267a40..e8f471d 100644
--- a/source/game/interfaces/StarBeamItem.hpp
+++ b/source/game/interfaces/StarBeamItem.hpp
@@ -63,10 +63,10 @@ protected:
float m_innerBrightnessScale;
float m_firstStripeThickness;
float m_secondStripeThickness;
- Vec4B m_color;
+ Color m_color;
mutable bool m_inRangeLastUpdate;
- mutable Vec4B m_lastUpdateColor;
+ mutable Color m_lastUpdateColor;
mutable float m_particleGenerateCooldown;
CSplineF m_beamCurve;
diff --git a/source/game/interfaces/StarToolUserEntity.hpp b/source/game/interfaces/StarToolUserEntity.hpp
index dcda91d..2d7cc49 100644
--- a/source/game/interfaces/StarToolUserEntity.hpp
+++ b/source/game/interfaces/StarToolUserEntity.hpp
@@ -26,7 +26,7 @@ public:
virtual Vec2F aimPosition() const = 0;
virtual bool isAdmin() const = 0;
- virtual Vec4B favoriteColor() const = 0;
+ virtual Color favoriteColor() const = 0;
virtual String species() const = 0;
virtual void requestEmote(String const& emote) = 0;
diff --git a/source/game/items/StarInspectionTool.cpp b/source/game/items/StarInspectionTool.cpp
index 6ab6789..a9e3109 100644
--- a/source/game/items/StarInspectionTool.cpp
+++ b/source/game/items/StarInspectionTool.cpp
@@ -56,7 +56,7 @@ List<LightSource> InspectionTool::lightSources() const {
LightSource lightSource;
lightSource.pointLight = true;
lightSource.position = owner()->position() + owner()->handPosition(hand(), m_lightPosition - m_handPosition);
- lightSource.color = m_lightColor.toRgb();
+ lightSource.color = m_lightColor.toRgbF();
lightSource.pointBeam = m_beamWidth;
lightSource.beamAngle = angle;
lightSource.beamAmbience = m_ambientFactor;
diff --git a/source/game/items/StarMaterialItem.cpp b/source/game/items/StarMaterialItem.cpp
index 42f90fc..4d13a62 100644
--- a/source/game/items/StarMaterialItem.cpp
+++ b/source/game/items/StarMaterialItem.cpp
@@ -122,7 +122,7 @@ void MaterialItem::update(float dt, FireMode fireMode, bool shifting, HashSet<Mo
void MaterialItem::render(RenderCallback* renderCallback, EntityRenderLayer) {
if (m_collisionOverride != TileCollisionOverride::None) {
float pulseLevel = 1.f - 0.3f * 0.5f * ((float)sin(2 * Constants::pi * 4.0 * Time::monotonicTime()) + 1.f);
- Color color = Color::rgba(owner()->favoriteColor()).mix(Color::White);
+ Color color = owner()->favoriteColor().mix(Color::White);
color.setAlphaF(color.alphaF() * pulseLevel * 0.95f);
auto addIndicator = [&](String const& path) {
Vec2F basePosition = Vec2F(0.5f, 0.5f);
@@ -336,7 +336,7 @@ TileCollisionOverride& MaterialItem::collisionOverride() {
List<PreviewTile> MaterialItem::previewTiles(bool shifting) const {
List<PreviewTile> result;
if (initialized()) {
- Color lightColor = Color::rgba(owner()->favoriteColor());
+ Color lightColor = owner()->favoriteColor();
Vec3B light = lightColor.toRgb();
auto material = materialId();
diff --git a/source/game/items/StarTools.cpp b/source/game/items/StarTools.cpp
index e1bb576..0f2781a 100644
--- a/source/game/items/StarTools.cpp
+++ b/source/game/items/StarTools.cpp
@@ -241,7 +241,7 @@ List<LightSource> Flashlight::lightSources() const {
LightSource lightSource;
lightSource.pointLight = true;
lightSource.position = owner()->position() + owner()->handPosition(hand(), (m_lightPosition - m_handPosition) / TilePixels);
- lightSource.color = m_lightColor.toRgb();
+ lightSource.color = m_lightColor.toRgbF();
lightSource.pointBeam = m_beamWidth;
lightSource.beamAngle = angle;
lightSource.beamAmbience = m_ambientFactor;
@@ -367,7 +367,7 @@ List<PreviewTile> BeamMiningTool::previewTiles(bool shifting) const {
if (ownerp && worldp) {
if (ownerp->isAdmin() || ownerp->inToolRange()) {
- Color lightColor = Color::rgba(ownerp->favoriteColor());
+ Color lightColor = ownerp->favoriteColor();
if (!ready())
lightColor *= Color::rgbaf(0.75f, 0.75f, 0.75f, 1.0f);
Vec3B light = lightColor.toRgb();
@@ -604,13 +604,13 @@ PaintingBeamTool::PaintingBeamTool(Json const& config, String const& directory,
m_blockVolume = assets->json("/sfx.config:miningBlockVolume").toFloat();
m_endType = EndType::Object;
- for (auto color : instanceValue("colorNumbers").toArray())
+ for (auto& color : instanceValue("colorNumbers").toArray())
m_colors.append(jsonToColor(color));
m_colorKeys = jsonToStringList(instanceValue("colorKeys"));
m_colorIndex = instanceValue("colorIndex", 0).toInt();
- m_color = m_colors[m_colorIndex].toRgba();
+ m_color = m_colors[m_colorIndex];
}
ItemPtr PaintingBeamTool::clone() const {
@@ -666,7 +666,7 @@ List<PreviewTile> PaintingBeamTool::previewTiles(bool shifting) const {
void PaintingBeamTool::init(ToolUserEntity* owner, ToolHand hand) {
FireableItem::init(owner, hand);
BeamItem::init(owner, hand);
- m_color = m_colors[m_colorIndex].toRgba();
+ m_color = m_colors[m_colorIndex];
}
List<Drawable> PaintingBeamTool::nonRotatedDrawables() const {
@@ -681,7 +681,7 @@ void PaintingBeamTool::fire(FireMode mode, bool shifting, bool edgeTriggered) {
if (mode == FireMode::Alt && edgeTriggered) {
m_colorIndex = (m_colorIndex + 1) % m_colors.size();
- m_color = m_colors[m_colorIndex].toRgba();
+ m_color = m_colors[m_colorIndex];
setInstanceValue("colorIndex", m_colorIndex);
return;
}
diff --git a/source/game/scripting/StarLuaAnimationComponent.hpp b/source/game/scripting/StarLuaAnimationComponent.hpp
index 540f517..8866724 100644
--- a/source/game/scripting/StarLuaAnimationComponent.hpp
+++ b/source/game/scripting/StarLuaAnimationComponent.hpp
@@ -76,7 +76,7 @@ LuaAnimationComponent<Base>::LuaAnimationComponent() {
animationCallbacks.registerCallback("addLightSource", [this](LuaTable const& lightSourceTable) {
m_lightSources.append({
lightSourceTable.get<Vec2F>("position"),
- lightSourceTable.get<Color>("color").toRgb(),
+ lightSourceTable.get<Color>("color").toRgbF(),
lightSourceTable.get<Maybe<bool>>("pointLight").value(),
lightSourceTable.get<Maybe<float>>("pointBeam").value(),
lightSourceTable.get<Maybe<float>>("beamAngle").value(),
diff --git a/source/rendering/StarTilePainter.cpp b/source/rendering/StarTilePainter.cpp
index 31fe0a6..58d9d28 100644
--- a/source/rendering/StarTilePainter.cpp
+++ b/source/rendering/StarTilePainter.cpp
@@ -38,20 +38,19 @@ TilePainter::TilePainter(RendererPtr renderer) : TileDrawer() {
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
+ // Only adjust lighting for tiles with liquid above the draw threshold
float drawLevel = liquidDrawLevel(byteToFloat(tile.liquidLevel));
if (drawLevel == 0.0f)
return;
auto lightIndex = Vec2U(pos - renderData.lightMinPosition);
- auto lightValue = renderData.lightMap.get(lightIndex).vec3();
+ auto lightValue = renderData.lightMap.get(lightIndex.x(), lightIndex.y());
auto const& liquid = m_liquids[tile.liquidId];
- Vec3F tileLight = Vec3F(lightValue);
- float darknessLevel = (1 - tileLight.sum() / (3.0f * 255.0f)) * drawLevel;
- lightValue = Vec3B(tileLight.piecewiseMultiply(Vec3F::filled(1 - darknessLevel) + liquid.bottomLightMix * darknessLevel));
+ float darknessLevel = (1.f - (lightValue.sum() / 3.0f)) * drawLevel;
+ lightValue = lightValue.piecewiseMultiply(Vec3F::filled(1.f - darknessLevel) + liquid.bottomLightMix * darknessLevel);
- renderData.lightMap.set(lightIndex, lightValue);
+ renderData.lightMap.set(lightIndex.x(), lightIndex.y(), lightValue);
});
}
diff --git a/source/rendering/StarWorldPainter.cpp b/source/rendering/StarWorldPainter.cpp
index c55f372..5d33182 100644
--- a/source/rendering/StarWorldPainter.cpp
+++ b/source/rendering/StarWorldPainter.cpp
@@ -83,6 +83,7 @@ void WorldPainter::render(WorldRenderData& renderData, function<bool()> lightWai
LogMap::set("client_render_world_async_light_wait", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - start));
}
+ m_renderer->setEffectParameter("lightMapEnabled", !renderData.isFullbright);
if (renderData.isFullbright) {
m_renderer->setEffectTexture("lightMap", Image::filled(Vec2U(1, 1), { 255, 255, 255, 255 }, PixelFormat::RGB24));
m_renderer->setEffectParameter("lightMapMultiplier", 1.0f);