diff --git a/assets/opensb/font/dotsies.woff2 b/assets/opensb/font/dotsies.woff2 new file mode 100644 index 0000000..853124b Binary files /dev/null and b/assets/opensb/font/dotsies.woff2 differ diff --git a/assets/opensb/objects/opensb/object.patch.lua b/assets/opensb/objects/opensb/object.patch.lua index 2d70052..df783ac 100644 --- a/assets/opensb/objects/opensb/object.patch.lua +++ b/assets/opensb/objects/opensb/object.patch.lua @@ -1,21 +1,6 @@ --- unused for now - -local function modLight(light) - for i = 1, #light do - light[i] = light[i] * 0.4 - end -end - function patch(object, path) - if object.lightColor then - modLight(object.lightColor) - object.pointLight = true - return object; - elseif object.lightColors then - for i, v in pairs(object.lightColors) do - modLight(v) - end - object.pointLight = true + if object.pointLight ~= true and (object.lightColor or object.lightColors) then + object.lightType = "PointAsSpread" return object; end end \ No newline at end of file diff --git a/assets/opensb/scripts/opensb/assets/postload.lua b/assets/opensb/scripts/opensb/assets/postload.lua index 0b57b7a..d84dd75 100644 --- a/assets/opensb/scripts/opensb/assets/postload.lua +++ b/assets/opensb/scripts/opensb/assets/postload.lua @@ -11,8 +11,8 @@ if assets.image("/cursors/cursors.png"):size()[1] == 64 then end -- Add object patches ---local objects = assets.byExtension("object") ---local path = "/objects/opensb/object.patch.lua" ---for i = 1, #objects do --- assets.patch(objects[i], path) ---end \ No newline at end of file +local objects = assets.byExtension("object") +local path = "/objects/opensb/object.patch.lua" +for i = 1, #objects do + assets.patch(objects[i], path) +end \ No newline at end of file diff --git a/source/base/StarCellularLightArray.cpp b/source/base/StarCellularLightArray.cpp index 60a6d95..99490ce 100644 --- a/source/base/StarCellularLightArray.cpp +++ b/source/base/StarCellularLightArray.cpp @@ -1,12 +1,13 @@ #include "StarCellularLightArray.hpp" +#include "StarInterpolation.hpp" // just specializing these in a cpp file so I can iterate on them without recompiling like 40 files!! namespace Star { template <> void CellularLightArray::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; + float pointPerBlockObstacleAttenuation = 1.0f / m_pointMaxObstacle; + float pointPerBlockAirAttenuation = 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) @@ -14,8 +15,10 @@ void CellularLightArray::calculatePointLighting(size_t xmin, float maxIntensity = ScalarLightTraits::maxIntensity(light.value); Vec2F beamDirection = Vec2F(1, 0).rotate(light.beamAngle); + float perBlockObstacleAttenuation = light.asSpread ? 1.0f / m_spreadMaxObstacle : pointPerBlockObstacleAttenuation; + float perBlockAirAttenuation = light.asSpread ? 1.0f / m_spreadMaxAir : pointPerBlockAirAttenuation; - float maxRange = maxIntensity * m_pointMaxAir; + float maxRange = maxIntensity * (light.asSpread ? m_spreadMaxAir : m_pointMaxAir); // The min / max considering the radius of the light size_t lxmin = std::floor(std::max(xmin, light.position[0] - maxRange)); size_t lymin = std::floor(std::max(ymin, light.position[1] - maxRange)); @@ -40,7 +43,7 @@ void CellularLightArray::calculatePointLighting(size_t xmin, continue; Vec2F direction = relativeLightPosition / distance; - if (light.beam > 0.0f) { + if (light.beam > 0.0001f) { attenuation += (1.0f - light.beamAmbience) * clamp(light.beam * (1.0f - direction * beamDirection), 0.0f, 1.0f); if (attenuation >= 1.0f) continue; @@ -54,12 +57,21 @@ void CellularLightArray::calculatePointLighting(size_t xmin, float circularizedPerBlockObstacleAttenuation = perBlockObstacleAttenuation / max(fabs(direction[0]), fabs(direction[1])); float blockAttenuation = lineAttenuation(blockPos, light.position, circularizedPerBlockObstacleAttenuation, remainingAttenuation); + attenuation += blockAttenuation; // Apply single obstacle boost (determine single obstacle by one // block unit of attenuation). - attenuation += blockAttenuation + min(blockAttenuation, circularizedPerBlockObstacleAttenuation) * m_pointObstacleBoost; + if (!light.asSpread) + attenuation += min(blockAttenuation, circularizedPerBlockObstacleAttenuation) * m_pointObstacleBoost; - if (attenuation < 1.0f) - setLight(x, y, lvalue + ScalarLightTraits::subtract(light.value, attenuation)); + if (attenuation < 1.0f) { + auto newLight = ScalarLightTraits::subtract(light.value, attenuation); + if (ScalarLightTraits::maxIntensity(newLight) > 0.0001f) { + if (light.asSpread) + setLight(x, y, lvalue + newLight * 0.25f); + else + setLight(x, y, lvalue + newLight); + } + } } } } @@ -67,8 +79,8 @@ void CellularLightArray::calculatePointLighting(size_t xmin, template <> void CellularLightArray::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; + float pointPerBlockObstacleAttenuation = 1.0f / m_pointMaxObstacle; + float pointPerBlockAirAttenuation = 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) @@ -76,8 +88,10 @@ void CellularLightArray::calculatePointLighting(size_t xmin, float maxIntensity = ColoredLightTraits::maxIntensity(light.value); Vec2F beamDirection = Vec2F(1, 0).rotate(light.beamAngle); + float perBlockObstacleAttenuation = light.asSpread ? 1.0f / m_spreadMaxObstacle : pointPerBlockObstacleAttenuation; + float perBlockAirAttenuation = light.asSpread ? 1.0f / m_spreadMaxAir : pointPerBlockAirAttenuation; - float maxRange = maxIntensity * m_pointMaxAir; + float maxRange = maxIntensity * (light.asSpread ? m_spreadMaxAir : m_pointMaxAir); // The min / max considering the radius of the light size_t lxmin = std::floor(std::max(xmin, light.position[0] - maxRange)); size_t lymin = std::floor(std::max(ymin, light.position[1] - maxRange)); @@ -116,12 +130,21 @@ void CellularLightArray::calculatePointLighting(size_t xmin, float circularizedPerBlockObstacleAttenuation = perBlockObstacleAttenuation / max(fabs(direction[0]), fabs(direction[1])); float blockAttenuation = lineAttenuation(blockPos, light.position, circularizedPerBlockObstacleAttenuation, remainingAttenuation); + attenuation += blockAttenuation; // Apply single obstacle boost (determine single obstacle by one // block unit of attenuation). - attenuation += blockAttenuation + min(blockAttenuation, circularizedPerBlockObstacleAttenuation) * m_pointObstacleBoost; + if (!light.asSpread) + attenuation += min(blockAttenuation, circularizedPerBlockObstacleAttenuation) * m_pointObstacleBoost; - if (attenuation < 1.0f) - setLight(x, y, lvalue + ColoredLightTraits::subtract(light.value, attenuation)); + if (attenuation < 1.0f) { + auto newLight = ColoredLightTraits::subtract(light.value, attenuation); + if (ColoredLightTraits::maxIntensity(newLight) > 0.0001f) { + if (light.asSpread) + setLight(x, y, lvalue + newLight * 0.25f); + else + setLight(x, y, lvalue + newLight); + } + } } } } diff --git a/source/base/StarCellularLightArray.hpp b/source/base/StarCellularLightArray.hpp index 225d42b..587ae1f 100644 --- a/source/base/StarCellularLightArray.hpp +++ b/source/base/StarCellularLightArray.hpp @@ -56,6 +56,7 @@ public: float beam; float beamAngle; float beamAmbience; + bool asSpread; }; void setParameters(unsigned spreadPasses, float spreadMaxAir, float spreadMaxObstacle, diff --git a/source/base/StarCellularLighting.cpp b/source/base/StarCellularLighting.cpp index 579f48a..3e5cf9a 100644 --- a/source/base/StarCellularLighting.cpp +++ b/source/base/StarCellularLighting.cpp @@ -109,12 +109,12 @@ void CellularLightingCalculator::addSpreadLight(Vec2F const& position, Vec3F con m_lightArray.left().addSpreadLight({arrayPosition, light}); } -void CellularLightingCalculator::addPointLight(Vec2F const& position, Vec3F const& light, float beam, float beamAngle, float beamAmbience) { +void CellularLightingCalculator::addPointLight(Vec2F const& position, Vec3F const& light, float beam, float beamAngle, float beamAmbience, bool asSpread) { Vec2F arrayPosition = position - Vec2F(m_calculationRegion.min()); if (m_monochrome) - m_lightArray.right().addPointLight({arrayPosition, light.max(), beam, beamAngle, beamAmbience}); + m_lightArray.right().addPointLight({arrayPosition, light.max(), beam, beamAngle, beamAmbience, asSpread}); else - m_lightArray.left().addPointLight({arrayPosition, light, beam, beamAngle, beamAmbience}); + m_lightArray.left().addPointLight({arrayPosition, light, beam, beamAngle, beamAmbience, asSpread}); } void CellularLightingCalculator::calculate(Image& output) { diff --git a/source/base/StarCellularLighting.hpp b/source/base/StarCellularLighting.hpp index 7cb230f..7c29bb8 100644 --- a/source/base/StarCellularLighting.hpp +++ b/source/base/StarCellularLighting.hpp @@ -136,7 +136,7 @@ public: void setCellIndex(size_t cellIndex, Vec3F const& light, bool obstacle); void addSpreadLight(Vec2F const& position, Vec3F const& light); - void addPointLight(Vec2F const& position, Vec3F const& light, float beam, float beamAngle, float beamAmbience); + void addPointLight(Vec2F const& position, Vec3F const& light, float beam, float beamAngle, float beamAmbience, bool asSpread = false); // Finish the calculation, and put the resulting color data in the given // output image. The image will be reset to the size of the region given in diff --git a/source/game/StarItemDrop.cpp b/source/game/StarItemDrop.cpp index f3a74c7..bc3d15f 100644 --- a/source/game/StarItemDrop.cpp +++ b/source/game/StarItemDrop.cpp @@ -320,7 +320,7 @@ void ItemDrop::render(RenderCallback* renderCallback) { void ItemDrop::renderLightSources(RenderCallback* renderCallback) { LightSource light; - light.pointLight = false; + light.type = LightType::Spread; light.color = Vec3F::filled(20.f / 255.f); light.position = position(); renderCallback->addLightSource(std::move(light)); diff --git a/source/game/StarLightSource.cpp b/source/game/StarLightSource.cpp index 65b7429..b20b15c 100644 --- a/source/game/StarLightSource.cpp +++ b/source/game/StarLightSource.cpp @@ -3,6 +3,12 @@ namespace Star { +EnumMap const LightTypeNames{ + {LightType::Spread, "Spread"}, + {LightType::Point, "Point"}, + {LightType::PointAsSpread, "PointAsSpread"} +}; + void LightSource::translate(Vec2F const& pos) { position += pos; } @@ -10,7 +16,7 @@ void LightSource::translate(Vec2F const& pos) { DataStream& operator<<(DataStream& ds, LightSource const& lightSource) { ds.write(lightSource.position); ds.write(lightSource.color); - ds.write(lightSource.pointLight); + ds.write(lightSource.type); ds.write(lightSource.pointBeam); ds.write(lightSource.beamAngle); ds.write(lightSource.beamAmbience); @@ -21,7 +27,7 @@ DataStream& operator<<(DataStream& ds, LightSource const& lightSource) { DataStream& operator>>(DataStream& ds, LightSource& lightSource) { ds.read(lightSource.position); ds.read(lightSource.color); - ds.read(lightSource.pointLight); + ds.read(lightSource.type); ds.read(lightSource.pointBeam); ds.read(lightSource.beamAngle); ds.read(lightSource.beamAmbience); diff --git a/source/game/StarLightSource.hpp b/source/game/StarLightSource.hpp index a6948cb..673cd56 100644 --- a/source/game/StarLightSource.hpp +++ b/source/game/StarLightSource.hpp @@ -2,14 +2,22 @@ #include "StarVector.hpp" #include "StarDataStream.hpp" +#include "StarBiMap.hpp" namespace Star { +enum class LightType : uint8_t { + Spread = 0, + Point = 1, + PointAsSpread = 2 // Point with spread-like range +}; + +extern EnumMap const LightTypeNames; + struct LightSource { Vec2F position; Vec3F color; - - bool pointLight; + LightType type; // pointBeam of 0.0 means light has no beam component, as pointBeam goes up, // the dropoff from the beamAngle becomes faster and faster. float pointBeam; diff --git a/source/game/StarNetworkedAnimator.cpp b/source/game/StarNetworkedAnimator.cpp index d013c48..ccec4fd 100644 --- a/source/game/StarNetworkedAnimator.cpp +++ b/source/game/StarNetworkedAnimator.cpp @@ -717,7 +717,7 @@ List NetworkedAnimator::lightSources(Vec2F const& translate) const lightSources.append(LightSource{ position + translate, color.toRgbF(), - pair.second.pointLight, + pair.second.pointLight ? LightType::Point : LightType::Spread, pair.second.pointBeam, pointAngle, pair.second.beamAmbience diff --git a/source/game/StarObject.cpp b/source/game/StarObject.cpp index 7bac350..dd19268 100644 --- a/source/game/StarObject.cpp +++ b/source/game/StarObject.cpp @@ -262,7 +262,7 @@ List Object::lightSources() const { LightSource lightSource; lightSource.position = position() + centerOfTile(orientation->lightPosition); lightSource.color = color.toRgbF(); - lightSource.pointLight = m_config->pointLight; + lightSource.type = m_config->lightType; lightSource.pointBeam = m_config->pointBeam; lightSource.beamAngle = orientation->beamAngle; lightSource.beamAmbience = m_config->beamAmbience; diff --git a/source/game/StarObjectDatabase.cpp b/source/game/StarObjectDatabase.cpp index 67a3c67..8ed56e4 100644 --- a/source/game/StarObjectDatabase.cpp +++ b/source/game/StarObjectDatabase.cpp @@ -495,7 +495,10 @@ ObjectConfigPtr ObjectDatabase::readConfig(String const& path) { objectConfig->lightColors[pair.first] = jsonToColor(pair.second); } - objectConfig->pointLight = config.getBool("pointLight", false); + if (auto lightType = config.optString("lightType")) + objectConfig->lightType = LightTypeNames.getLeft(*lightType); + else + objectConfig->lightType = (LightType)config.getBool("pointLight", false); objectConfig->pointBeam = config.getFloat("pointBeam", 0.0f); objectConfig->beamAmbience = config.getFloat("beamAmbience", 0.0f); diff --git a/source/game/StarObjectDatabase.hpp b/source/game/StarObjectDatabase.hpp index 76bae0f..ca44c2e 100644 --- a/source/game/StarObjectDatabase.hpp +++ b/source/game/StarObjectDatabase.hpp @@ -131,7 +131,7 @@ struct ObjectConfig { bool interactive; StringMap lightColors; - bool pointLight; + LightType lightType; float pointBeam; float beamAmbience; Maybe> lightFlickering; diff --git a/source/game/StarProjectile.cpp b/source/game/StarProjectile.cpp index 5a73e8b..d00b76b 100644 --- a/source/game/StarProjectile.cpp +++ b/source/game/StarProjectile.cpp @@ -379,7 +379,7 @@ void Projectile::renderLightSources(RenderCallback* renderCallback) { if (renderable.is()) renderCallback->addLightSource(renderable.get()); } - renderCallback->addLightSource({position(), m_config->lightColor.toRgbF(), m_config->pointLight, 0.0f, 0.0f, 0.0f}); + renderCallback->addLightSource({position(), m_config->lightColor.toRgbF(), m_config->lightType, 0.0f, 0.0f, 0.0f}); } Maybe Projectile::receiveMessage(ConnectionId sendingConnection, String const& message, JsonArray const& args) { @@ -825,7 +825,7 @@ void Projectile::processAction(Json const& action) { m_pendingRenderables.append(LightSource{ position(), jsonToColor(parameters.get("color")).toRgbF(), - parameters.getBool("pointLight", true), + (LightType)parameters.getBool("pointLight", true), 0.0f, 0.0f, 0.0f diff --git a/source/game/StarProjectileDatabase.cpp b/source/game/StarProjectileDatabase.cpp index dd7327b..c2a0c26 100644 --- a/source/game/StarProjectileDatabase.cpp +++ b/source/game/StarProjectileDatabase.cpp @@ -118,7 +118,10 @@ ProjectileConfigPtr ProjectileDatabase::readConfig(String const& path) { 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); + if (auto lightType = config.optString("lightType")) + projectileConfig->lightType = LightTypeNames.getLeft(*lightType); + else + projectileConfig->lightType = (LightType)config.getBool("pointLight", false); projectileConfig->persistentAudio = config.getString("persistentAudio", ""); diff --git a/source/game/StarProjectileDatabase.hpp b/source/game/StarProjectileDatabase.hpp index 833d0eb..d3cdd3d 100644 --- a/source/game/StarProjectileDatabase.hpp +++ b/source/game/StarProjectileDatabase.hpp @@ -68,7 +68,7 @@ struct ProjectileConfig { Color lightColor; Vec2F lightPosition; - bool pointLight = false; + LightType lightType = LightType::Spread; String persistentAudio; diff --git a/source/game/StarWorldClient.cpp b/source/game/StarWorldClient.cpp index df69b94..535980b 100644 --- a/source/game/StarWorldClient.cpp +++ b/source/game/StarWorldClient.cpp @@ -1652,10 +1652,15 @@ void WorldClient::lightingCalc() { for (auto const& light : lights) { Vec2F position = m_geometry.nearestTo(Vec2F(m_lightingCalculator.calculationRegion().min()), light.position); - if (light.pointLight) - m_lightingCalculator.addPointLight(position, light.color, light.pointBeam, light.beamAngle, light.beamAmbience); - else { + if (light.type == LightType::Spread) m_lightingCalculator.addSpreadLight(position, light.color); + else { + if (light.type == LightType::PointAsSpread) { + // hybrid (used for auto-converted object lights) - 75% spread, 25% point (2nd is applied elsewhere) + m_lightingCalculator.addSpreadLight(position, light.color * 0.75f); + m_lightingCalculator.addPointLight(position, light.color, light.pointBeam, light.beamAngle, light.beamAmbience, true); + } else // fully additive point light + m_lightingCalculator.addPointLight(position, light.color, light.pointBeam, light.beamAngle, light.beamAmbience); } } diff --git a/source/game/StarWorldImpl.hpp b/source/game/StarWorldImpl.hpp index dec827f..3e3728b 100644 --- a/source/game/StarWorldImpl.hpp +++ b/source/game/StarWorldImpl.hpp @@ -445,10 +445,10 @@ namespace WorldImpl { for (auto const& entity : entityMap->entityQuery(RectF(lighting.calculationRegion()))) { for (auto const& light : entity->lightSources()) { Vec2F position = worldGeometry.nearestTo(Vec2F(lighting.calculationRegion().min()), light.position); - if (light.pointLight) - lighting.addPointLight(position, light.color.sum() / 3.0f, light.pointBeam, light.beamAngle, light.beamAmbience); - else + if (light.type == LightType::Spread) lighting.addSpreadLight(position, light.color.sum() / 3.0f); + else + lighting.addPointLight(position, light.color.sum() / 3.0f, light.pointBeam, light.beamAngle, light.beamAmbience); } } diff --git a/source/game/items/StarInspectionTool.cpp b/source/game/items/StarInspectionTool.cpp index a9e3109..cdfe6c2 100644 --- a/source/game/items/StarInspectionTool.cpp +++ b/source/game/items/StarInspectionTool.cpp @@ -54,7 +54,7 @@ List InspectionTool::lightSources() const { float angle = world()->geometry().diff(owner()->aimPosition(), owner()->position()).angle(); LightSource lightSource; - lightSource.pointLight = true; + lightSource.type = LightType::Point; lightSource.position = owner()->position() + owner()->handPosition(hand(), m_lightPosition - m_handPosition); lightSource.color = m_lightColor.toRgbF(); lightSource.pointBeam = m_beamWidth; diff --git a/source/game/items/StarTools.cpp b/source/game/items/StarTools.cpp index 0f2781a..cde44b8 100644 --- a/source/game/items/StarTools.cpp +++ b/source/game/items/StarTools.cpp @@ -239,7 +239,7 @@ List Flashlight::lightSources() const { float angle = world()->geometry().diff(owner()->aimPosition(), owner()->position()).angle(); LightSource lightSource; - lightSource.pointLight = true; + lightSource.type = LightType::Point; lightSource.position = owner()->position() + owner()->handPosition(hand(), (m_lightPosition - m_handPosition) / TilePixels); lightSource.color = m_lightColor.toRgbF(); lightSource.pointBeam = m_beamWidth; diff --git a/source/game/scripting/StarLuaAnimationComponent.hpp b/source/game/scripting/StarLuaAnimationComponent.hpp index 8866724..799c76e 100644 --- a/source/game/scripting/StarLuaAnimationComponent.hpp +++ b/source/game/scripting/StarLuaAnimationComponent.hpp @@ -77,7 +77,7 @@ LuaAnimationComponent::LuaAnimationComponent() { m_lightSources.append({ lightSourceTable.get("position"), lightSourceTable.get("color").toRgbF(), - lightSourceTable.get>("pointLight").value(), + (LightType)lightSourceTable.get>("pointLight").value(), lightSourceTable.get>("pointBeam").value(), lightSourceTable.get>("beamAngle").value(), lightSourceTable.get>("beamAmbience").value()