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

summaryrefslogtreecommitdiff
path: root/source/game/StarParallax.cpp
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
committerKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
commit6352e8e3196f78388b6c771073f9e03eaa612673 (patch)
treee23772f79a7fbc41bc9108951e9e136857484bf4 /source/game/StarParallax.cpp
parent6741a057e5639280d85d0f88ba26f000baa58f61 (diff)
everything everywhere
all at once
Diffstat (limited to 'source/game/StarParallax.cpp')
-rw-r--r--source/game/StarParallax.cpp239
1 files changed, 239 insertions, 0 deletions
diff --git a/source/game/StarParallax.cpp b/source/game/StarParallax.cpp
new file mode 100644
index 0000000..b676e24
--- /dev/null
+++ b/source/game/StarParallax.cpp
@@ -0,0 +1,239 @@
+#include "StarParallax.hpp"
+#include "StarLexicalCast.hpp"
+#include "StarJsonExtra.hpp"
+#include "StarRoot.hpp"
+#include "StarImageMetadataDatabase.hpp"
+#include "StarRandom.hpp"
+#include "StarAssets.hpp"
+#include "StarDataStreamExtra.hpp"
+
+namespace Star {
+
+ParallaxLayer::ParallaxLayer() {
+ timeOfDayCorrelation = "";
+ zLevel = 0;
+ verticalOrigin = 0;
+ speed = 0;
+ unlit = false;
+ lightMapped = false;
+ fadePercent = 0;
+ directives = "";
+ alpha = 1.0f;
+}
+
+ParallaxLayer::ParallaxLayer(Json const& store) : ParallaxLayer() {
+ textures = jsonToStringList(store.get("textures"));
+ directives = store.getString("directives");
+ parallaxValue = jsonToVec2F(store.get("parallaxValue"));
+ repeat = jsonToVec2B(store.get("repeat"));
+ tileLimitTop = store.optFloat("tileLimitTop");
+ tileLimitBottom = store.optFloat("tileLimitBottom");
+ verticalOrigin = store.getFloat("verticalOrigin");
+ zLevel = store.getFloat("zLevel");
+ parallaxOffset = jsonToVec2F(store.get("parallaxOffset"));
+ timeOfDayCorrelation = store.getString("timeOfDayCorrelation");
+ speed = store.getFloat("speed");
+ unlit = store.getBool("unlit");
+ lightMapped = store.getBool("lightMapped");
+ fadePercent = store.getFloat("fadePercent");
+}
+
+Json ParallaxLayer::store() const {
+ return JsonObject{{"textures", jsonFromStringList(textures)},
+ {"directives", directives},
+ {"parallaxValue", jsonFromVec2F(parallaxValue)},
+ {"repeat", jsonFromVec2B(repeat)},
+ {"tileLimitTop", jsonFromMaybe(tileLimitTop)},
+ {"tileLimitBottom", jsonFromMaybe(tileLimitBottom)},
+ {"verticalOrigin", verticalOrigin},
+ {"zLevel", zLevel},
+ {"parallaxOffset", jsonFromVec2F(parallaxOffset)},
+ {"timeOfDayCorrelation", timeOfDayCorrelation},
+ {"speed", speed},
+ {"unlit", unlit},
+ {"lightMapped", lightMapped},
+ {"fadePercent", fadePercent}};
+}
+
+void ParallaxLayer::addImageDirectives(String const& newDirectives) {
+ if (!newDirectives.empty())
+ directives = String::joinWith("?", directives, newDirectives);
+}
+
+void ParallaxLayer::fadeToSkyColor(Color skyColor) {
+ if (fadePercent > 0) {
+ String fade = "fade=" + skyColor.toHex().slice(0, 6) + "=" + toString(fadePercent);
+ addImageDirectives(fade);
+ }
+}
+
+DataStream& operator>>(DataStream& ds, ParallaxLayer& parallaxLayer) {
+ ds.read(parallaxLayer.textures);
+ ds.read(parallaxLayer.directives);
+ ds.read(parallaxLayer.alpha);
+ ds.read(parallaxLayer.parallaxValue);
+ ds.read(parallaxLayer.repeat);
+ ds.read(parallaxLayer.tileLimitTop);
+ ds.read(parallaxLayer.tileLimitBottom);
+ ds.read(parallaxLayer.verticalOrigin);
+ ds.read(parallaxLayer.zLevel);
+ ds.read(parallaxLayer.parallaxOffset);
+ ds.read(parallaxLayer.timeOfDayCorrelation);
+ ds.read(parallaxLayer.speed);
+ ds.read(parallaxLayer.unlit);
+ ds.read(parallaxLayer.lightMapped);
+ ds.read(parallaxLayer.fadePercent);
+ return ds;
+}
+
+DataStream& operator<<(DataStream& ds, ParallaxLayer const& parallaxLayer) {
+ ds.write(parallaxLayer.textures);
+ ds.write(parallaxLayer.directives);
+ ds.write(parallaxLayer.alpha);
+ ds.write(parallaxLayer.parallaxValue);
+ ds.write(parallaxLayer.repeat);
+ ds.write(parallaxLayer.tileLimitTop);
+ ds.write(parallaxLayer.tileLimitBottom);
+ ds.write(parallaxLayer.verticalOrigin);
+ ds.write(parallaxLayer.zLevel);
+ ds.write(parallaxLayer.parallaxOffset);
+ ds.write(parallaxLayer.timeOfDayCorrelation);
+ ds.write(parallaxLayer.speed);
+ ds.write(parallaxLayer.unlit);
+ ds.write(parallaxLayer.lightMapped);
+ ds.write(parallaxLayer.fadePercent);
+ return ds;
+}
+
+Parallax::Parallax(String const& assetFile,
+ uint64_t seed,
+ float verticalOrigin,
+ float hueShift,
+ Maybe<TreeVariant> parallaxTreeVariant) {
+ m_seed = seed;
+ m_verticalOrigin = verticalOrigin;
+ m_parallaxTreeVariant = parallaxTreeVariant;
+ m_hueShift = hueShift;
+ m_imageDirectory = "/parallax/images/";
+
+ auto assets = Root::singleton().assets();
+
+ Json config = assets->json(assetFile);
+
+ m_verticalOrigin += config.getFloat("verticalOrigin", 0);
+
+ RandomSource rnd(m_seed);
+
+ for (auto layerSettings : config.getArray("layers")) {
+ String kind = layerSettings.getString("kind");
+
+ float frequency = layerSettings.getFloat("frequency", 1.0);
+ if (rnd.randf() > frequency)
+ continue;
+
+ buildLayer(layerSettings, kind);
+ }
+
+ // sort with highest Z level first
+ stableSort(m_layers, [](ParallaxLayer const& a, ParallaxLayer const& b) { return a.zLevel > b.zLevel; });
+}
+
+Parallax::Parallax(Json const& store) {
+ m_seed = store.getUInt("seed");
+ m_verticalOrigin = store.getFloat("verticalOrigin");
+ if (auto treeVariant = store.opt("parallaxTreeVariant"))
+ m_parallaxTreeVariant = TreeVariant(*treeVariant);
+ m_hueShift = store.getFloat("hueShift");
+ m_imageDirectory = store.getString("imageDirectory");
+ m_layers = store.getArray("layers").transformed(construct<ParallaxLayer>());
+
+ stableSort(m_layers, [](ParallaxLayer const& a, ParallaxLayer const& b) { return a.zLevel > b.zLevel; });
+}
+
+Json Parallax::store() const {
+ return JsonObject{{"seed", m_seed},
+ {"verticalOrigin", m_verticalOrigin},
+ {"parallaxTreeVariant", m_parallaxTreeVariant ? m_parallaxTreeVariant->toJson() : Json()},
+ {"hueShift", m_hueShift},
+ {"imageDirectory", m_imageDirectory},
+ {"layers", m_layers.transformed(mem_fn(&ParallaxLayer::store))}};
+}
+
+void Parallax::fadeToSkyColor(Color const& skyColor) {
+ for (auto& layer : m_layers) {
+ layer.fadeToSkyColor(skyColor);
+ }
+}
+
+ParallaxLayers const& Parallax::layers() const {
+ return m_layers;
+}
+
+void Parallax::buildLayer(Json const& layerSettings, String const& kind) {
+ bool isFoliage = kind.beginsWith("foliage/");
+ bool isStem = kind.beginsWith("stem/");
+
+ String texPath = m_imageDirectory + kind + "/";
+ if (isFoliage) {
+ // If our tree type has no foliage, don't construct this layer
+ if (!m_parallaxTreeVariant || !m_parallaxTreeVariant->foliageSettings.getBool("parallaxFoliage", false))
+ return;
+
+ texPath = m_parallaxTreeVariant->foliageDirectory + "parallax/" + kind.replace("foliage/", "") + "/";
+ } else if (isStem) {
+ if (!m_parallaxTreeVariant)
+ return;
+
+ texPath = m_parallaxTreeVariant->stemDirectory + "parallax/" + kind.replace("stem/", "") + "/";
+ }
+
+ ParallaxLayer layer;
+ RandomSource rnd(m_seed + m_layers.size());
+ auto imgMetadata = Root::singleton().imageMetadataDatabase();
+
+ int baseCount = layerSettings.getInt("baseCount", 1);
+ int base = rnd.randInt(baseCount - 1) + 1;
+ layer.textures.append(AssetPath::relativeTo(texPath, "base/" + toString<int>(base) + ".png"));
+
+ int modCount = layerSettings.getInt("modCount", 0);
+ int mod = rnd.randInt(modCount);
+ if (mod != 0)
+ layer.textures.append(AssetPath::relativeTo(texPath, "mod/" + toString<int>(mod) + ".png"));
+
+ if (layerSettings.get("parallax").type() == Json::Type::Array)
+ layer.parallaxValue = jsonToVec2F(layerSettings.get("parallax"));
+ else
+ layer.parallaxValue = Vec2F::filled(layerSettings.getFloat("parallax"));
+
+ bool repeatY = layerSettings.getBool("repeatY", false);
+ layer.repeat = {true, repeatY};
+ if (repeatY) {
+ layer.tileLimitTop = layerSettings.optFloat("tileLimitTop");
+ layer.tileLimitBottom = layerSettings.optFloat("tileLimitBottom");
+ }
+
+ layer.verticalOrigin = m_verticalOrigin;
+ layer.zLevel = layer.parallaxValue.sum();
+ layer.parallaxOffset = {layerSettings.getArray("offset", {0, 0})[0].toFloat(),
+ layerSettings.getArray("offset", {0, 0})[1].toFloat()}; // shift from bottom left to horizon level in the image
+ if (!layerSettings.getBool("noRandomOffset", false))
+ layer.parallaxOffset[0] += rnd.randInt(imgMetadata->imageSize(layer.textures[0])[0]);
+ layer.timeOfDayCorrelation = layerSettings.getString("timeOfDayCorrelation", "");
+ layer.speed = rnd.randf(layerSettings.getFloat("minSpeed", 0), layerSettings.getFloat("maxSpeed", 0));
+ layer.unlit = layerSettings.getBool("unlit", false);
+ layer.lightMapped = layerSettings.getBool("lightMapped", false);
+
+ layer.addImageDirectives(layerSettings.getString("directives", ""));
+ if (isFoliage)
+ layer.addImageDirectives(strf("hueshift=%s", m_parallaxTreeVariant->foliageHueShift));
+ else if (isStem)
+ layer.addImageDirectives(strf("hueshift=%s", m_parallaxTreeVariant->stemHueShift));
+ else if (!layerSettings.getBool("nohueshift", false))
+ layer.addImageDirectives(strf("hueshift=%s", m_hueShift));
+
+ layer.fadePercent = layerSettings.getFloat("fadePercent", 0);
+
+ m_layers.append(layer);
+}
+
+}