v1.4.4
This commit is contained in:
commit
9c94d113d3
10260 changed files with 1237388 additions and 0 deletions
288
source/game/StarCelestialGraphics.cpp
Normal file
288
source/game/StarCelestialGraphics.cpp
Normal file
|
@ -0,0 +1,288 @@
|
|||
#include "StarCelestialGraphics.hpp"
|
||||
#include "StarJsonExtra.hpp"
|
||||
#include "StarLexicalCast.hpp"
|
||||
#include "StarFormat.hpp"
|
||||
#include "StarImageProcessing.hpp"
|
||||
#include "StarCelestialDatabase.hpp"
|
||||
#include "StarParallax.hpp"
|
||||
#include "StarRoot.hpp"
|
||||
#include "StarBiomeDatabase.hpp"
|
||||
#include "StarTerrainDatabase.hpp"
|
||||
#include "StarLiquidsDatabase.hpp"
|
||||
#include "StarAssets.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
List<pair<String, float>> CelestialGraphics::drawSystemPlanetaryObject(CelestialParameters const& parameters) {
|
||||
return {{parameters.getParameter("smallImage").toString(), parameters.getParameter("smallImageScale").toFloat()}};
|
||||
}
|
||||
|
||||
List<pair<String, float>> CelestialGraphics::drawSystemCentralBody(CelestialParameters const& parameters) {
|
||||
return {{parameters.getParameter("image").toString(), parameters.getParameter("imageScale").toFloat()}};
|
||||
}
|
||||
|
||||
List<pair<String, float>> CelestialGraphics::drawWorld(
|
||||
CelestialParameters const& celestialParameters, Maybe<CelestialParameters> const& overrideShadowParameters) {
|
||||
auto& root = Root::singleton();
|
||||
auto assets = root.assets();
|
||||
auto liquidsDatabase = root.liquidsDatabase();
|
||||
|
||||
CelestialParameters shadowParameters = overrideShadowParameters.value(celestialParameters);
|
||||
|
||||
String type = celestialParameters.getParameter("worldType").toString();
|
||||
|
||||
List<pair<String, float>> layers;
|
||||
|
||||
if (type == "Terrestrial") {
|
||||
auto terrestrialParameters = as<TerrestrialWorldParameters>(celestialParameters.visitableParameters());
|
||||
if (!terrestrialParameters)
|
||||
return {};
|
||||
|
||||
auto gfxConfig = jsonMerge(assets->json("/celestial.config:terrestrialGraphics").get("default"),
|
||||
assets->json("/celestial.config:terrestrialGraphics").get(terrestrialParameters->typeName, JsonObject()));
|
||||
|
||||
auto liquidImages = gfxConfig.getString("liquidImages", "");
|
||||
auto baseImages = gfxConfig.getString("baseImages", "");
|
||||
auto shadowImages = gfxConfig.getString("shadowImages", "");
|
||||
auto baseCount = gfxConfig.getInt("baseCount", 0);
|
||||
auto dynamicsImages = gfxConfig.getString("dynamicsImages", "");
|
||||
float imageScale = celestialParameters.getParameter("imageScale", 1.0f).toFloat();
|
||||
|
||||
// If the planet has water, then draw the corresponding water image as the
|
||||
// base layer, otherwise use the bottom most mask image.
|
||||
if (terrestrialParameters->primarySurfaceLiquid != EmptyLiquidId && !liquidImages.empty()) {
|
||||
String liquidBaseImage = liquidImages.replace("<liquid>", liquidsDatabase->liquidName(terrestrialParameters->primarySurfaceLiquid));
|
||||
layers.append({move(liquidBaseImage), imageScale});
|
||||
} else {
|
||||
if (baseCount > 0) {
|
||||
String baseLayer = strf("%s?hueshift=%s", baseImages.replace("<biome>",
|
||||
terrestrialParameters->primaryBiome).replace("<num>", toString(baseCount)), terrestrialParameters->hueShift);
|
||||
layers.append({move(baseLayer), imageScale});
|
||||
}
|
||||
}
|
||||
|
||||
// Then draw all the biome layers
|
||||
for (int i = 0; i < baseCount; ++i) {
|
||||
String baseImage = baseImages.replace("<num>", toString(baseCount - i));
|
||||
String hueShiftString, dynamicMaskString;
|
||||
if (!dynamicsImages.empty())
|
||||
dynamicMaskString = "?addmask=" + dynamicsImages.replace("<num>", toString(celestialParameters.randomizeParameterRange(gfxConfig.getArray("dynamicsRange"), i).toInt()));
|
||||
if (terrestrialParameters->hueShift != 0)
|
||||
hueShiftString = strf("?hueshift=%s", terrestrialParameters->hueShift);
|
||||
String layer = baseImage + hueShiftString + dynamicMaskString;
|
||||
layers.append({move(layer), imageScale});
|
||||
}
|
||||
|
||||
if (!shadowImages.empty()) {
|
||||
String shadow = shadowImages.replace("<num>", toString(shadowParameters.randomizeParameterRange(gfxConfig.getArray("shadowNumber")).toInt()));
|
||||
layers.append({move(shadow), imageScale});
|
||||
}
|
||||
|
||||
} else if (type == "Asteroids") {
|
||||
String maskImages = celestialParameters.getParameter("maskImages").toString();
|
||||
int maskCount = celestialParameters.getParameter("masks").toInt();
|
||||
String dynamicsImages = celestialParameters.getParameter("dynamicsImages").toString();
|
||||
float imageScale = celestialParameters.getParameter("imageScale", 1.0f).toFloat();
|
||||
|
||||
for (int i = 0; i < maskCount; ++i) {
|
||||
String biomeMaskBase = maskImages.replace("<num>", toString(maskCount - i));
|
||||
String dynamicMask = dynamicsImages.replace("<num>", toString(celestialParameters.randomizeParameterRange("dynamicsRange", i).toInt()));
|
||||
String layer = strf("%s?addmask=%s", biomeMaskBase, dynamicMask);
|
||||
layers.append({move(layer), imageScale});
|
||||
}
|
||||
|
||||
} else if (type == "FloatingDungeon") {
|
||||
String image = celestialParameters.getParameter("image").toString();
|
||||
float imageScale = celestialParameters.getParameter("imageScale", 1.0f).toFloat();
|
||||
layers.append({move(image), imageScale});
|
||||
|
||||
if (!celestialParameters.getParameter("dynamicsImages").toString().empty()) {
|
||||
String dynamicsImages = celestialParameters.getParameter("dynamicsImages", "").toString();
|
||||
String dynamicsImage = dynamicsImages.replace("<num>", toString(celestialParameters.randomizeParameterRange("dynamicsRange").toInt()));
|
||||
layers.append({move(dynamicsImage), imageScale});
|
||||
}
|
||||
|
||||
} else if (type == "GasGiant") {
|
||||
auto gfxConfig = assets->json("/celestial.config:gasGiantGraphics");
|
||||
|
||||
auto baseImage = gfxConfig.getString("baseImage", "");
|
||||
auto shadowImages = gfxConfig.getString("shadowImages", "");
|
||||
auto dynamicsImages = gfxConfig.getString("dynamicsImages", "");
|
||||
auto overlayImages = gfxConfig.getString("overlayImages", "");
|
||||
auto overlayCount = gfxConfig.getInt("overlayCount", 0);
|
||||
float imageScale = celestialParameters.getParameter("imageScale", 1.0f).toFloat();
|
||||
|
||||
float hueShift = celestialParameters.randomizeParameterRange(gfxConfig.getArray("primaryHueShiftRange")).toFloat();
|
||||
if (!baseImage.empty())
|
||||
layers.append({strf("%s?hueshift=%s", baseImage, hueShift), imageScale});
|
||||
|
||||
if (!overlayImages.empty()) {
|
||||
for (int i = 0; i < overlayCount; ++i) {
|
||||
hueShift += celestialParameters.randomizeParameterRange(gfxConfig.getArray("hueShiftOffsetRange")).toFloat();
|
||||
String maskImage = dynamicsImages.replace("<num>", toString(celestialParameters.randomizeParameterRange(gfxConfig.getArray("dynamicsRange"), i).toInt()));
|
||||
String overlayImage = overlayImages.replace("<num>", toString(i));
|
||||
layers.append({strf("%s?hueshift=%s?addmask=%s", overlayImage, hueShift, maskImage), imageScale});
|
||||
}
|
||||
}
|
||||
|
||||
if (!shadowImages.empty()) {
|
||||
String shadow = shadowImages.replace("<num>", toString(shadowParameters.randomizeParameterRange(gfxConfig.getArray("shadowNumber")).toInt()));
|
||||
layers.append({move(shadow), imageScale});
|
||||
}
|
||||
}
|
||||
|
||||
return layers;
|
||||
}
|
||||
|
||||
List<pair<String, String>> CelestialGraphics::worldHorizonImages(CelestialParameters const& celestialParameters) {
|
||||
auto& root = Root::singleton();
|
||||
auto assets = root.assets();
|
||||
auto liquidsDatabase = root.liquidsDatabase();
|
||||
|
||||
auto getLR = [](String const& base) -> pair<String, String> {
|
||||
return pair<String, String>(base.replace("<selector>", "l"), base.replace("<selector>", "r"));
|
||||
};
|
||||
|
||||
String type = celestialParameters.getParameter("worldType").toString();
|
||||
|
||||
List<pair<String, String>> res;
|
||||
|
||||
if (type == "Terrestrial") {
|
||||
auto terrestrialParameters = as<TerrestrialWorldParameters>(celestialParameters.visitableParameters());
|
||||
if (!terrestrialParameters)
|
||||
return {};
|
||||
|
||||
auto gfxConfig = jsonMerge(assets->json("/celestial.config:terrestrialHorizonGraphics").get("default"),
|
||||
assets->json("/celestial.config:terrestrialHorizonGraphics").get(terrestrialParameters->typeName, JsonObject()));
|
||||
|
||||
String baseImages = gfxConfig.getString("baseImages");
|
||||
String atmoTextures = gfxConfig.getString("atmosphereTextures");
|
||||
String shadowTextures = gfxConfig.getString("shadowTextures");
|
||||
String maskTextures = gfxConfig.getString("maskTextures");
|
||||
String liquidTextures = gfxConfig.getString("liquidTextures");
|
||||
auto numMasks = jsonToVec2I(gfxConfig.get("maskRange"));
|
||||
auto maskPerPlanetRange = jsonToVec2I(gfxConfig.get("maskPerPlanetRange"));
|
||||
|
||||
auto biomeHueShift = "?" + imageOperationToString(HueShiftImageOperation::hueShiftDegrees(terrestrialParameters->hueShift));
|
||||
|
||||
if (terrestrialParameters->primarySurfaceLiquid != EmptyLiquidId) {
|
||||
auto seed = celestialParameters.seed();
|
||||
RandomSource rand(seed);
|
||||
|
||||
int numPlanetMasks = rand.randInt(maskPerPlanetRange[0], maskPerPlanetRange[1]);
|
||||
List<int> masks;
|
||||
for (int i = 0; i < numPlanetMasks; ++i)
|
||||
masks.append(rand.randInt(numMasks[0], numMasks[1]));
|
||||
|
||||
String liquidBase = liquidTextures.replace("<liquid>", liquidsDatabase->liquidName(terrestrialParameters->primarySurfaceLiquid));
|
||||
res.append(getLR(liquidBase));
|
||||
|
||||
StringList planetMaskListL;
|
||||
StringList planetMaskListR;
|
||||
for (auto m : masks) {
|
||||
String base = maskTextures.replace("<mask>", toString(m));
|
||||
auto lr = getLR(base);
|
||||
planetMaskListL.append(lr.first);
|
||||
planetMaskListR.append(lr.second);
|
||||
}
|
||||
|
||||
String leftMask, rightMask;
|
||||
if (!planetMaskListL.empty())
|
||||
leftMask = "?" + imageOperationToString(AlphaMaskImageOperation{AlphaMaskImageOperation::Additive, planetMaskListL, {0, 0}});
|
||||
if (!planetMaskListR.empty())
|
||||
rightMask = "?" + imageOperationToString(AlphaMaskImageOperation{AlphaMaskImageOperation::Additive, planetMaskListR, {0, 0}});
|
||||
|
||||
auto toAppend = getLR(baseImages + biomeHueShift);
|
||||
res.append({toAppend.first + leftMask, toAppend.second + rightMask});
|
||||
} else {
|
||||
res.append(getLR(baseImages + biomeHueShift));
|
||||
}
|
||||
|
||||
if (celestialParameters.getParameter("atmosphere", true).toBool())
|
||||
res.append(getLR(atmoTextures));
|
||||
|
||||
res.append(getLR(shadowTextures));
|
||||
|
||||
} else if (type == "Asteroids") {
|
||||
res.append(getLR(assets->json("/celestial.config:asteroidsHorizons").toString()));
|
||||
|
||||
} else if (type == "FloatingDungeon") {
|
||||
auto dungeonParameters = as<FloatingDungeonWorldParameters>(celestialParameters.visitableParameters());
|
||||
auto dungeonHorizons = assets->json("/celestial.config:floatingDungeonHorizons");
|
||||
if (dungeonHorizons.contains(dungeonParameters->primaryDungeon))
|
||||
res.append(getLR(dungeonHorizons.get(dungeonParameters->primaryDungeon).toString()));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int CelestialGraphics::worldRadialPosition(CelestialParameters const& parameters) {
|
||||
if (parameters.coordinate().isPlanetaryBody())
|
||||
return staticRandomU32(parameters.seed(), "RadialNumber") % planetRadialPositions();
|
||||
if (parameters.coordinate().isSatelliteBody())
|
||||
return staticRandomU32(parameters.seed(), "RadialNumber") % satelliteRadialPositions();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CelestialGraphics::planetRadialPositions() {
|
||||
return Root::singleton().assets()->json("/celestial.config:planetRadialSlots").toInt();
|
||||
}
|
||||
|
||||
int CelestialGraphics::satelliteRadialPositions() {
|
||||
return Root::singleton().assets()->json("/celestial.config:satelliteRadialSlots").toInt();
|
||||
}
|
||||
|
||||
List<pair<String, float>> CelestialGraphics::drawSystemTwinkle(CelestialDatabasePtr celestialDatabase, CelestialCoordinate const& system, double time) {
|
||||
auto parameters = celestialDatabase->parameters(system);
|
||||
if (!parameters)
|
||||
return {};
|
||||
|
||||
auto assets = Root::singleton().assets();
|
||||
|
||||
int twinkleFrameCount = assets->json("/celestial.config:twinkleFrames").toInt();
|
||||
float twinkleScale = assets->json("/celestial.config:twinkleScale").toFloat();
|
||||
String twinkleFrameset = parameters->getParameter("twinkleFrames").toString();
|
||||
float twinkleTime = parameters->randomizeParameterRange("twinkleTime").toFloat();
|
||||
String twinkleBackground = parameters->getParameter("twinkleBackground").toString();
|
||||
|
||||
String twinkleFrame = strf("%s:%s", twinkleFrameset, (int)(std::fmod<double>(time / twinkleTime, 1.0f) * twinkleFrameCount));
|
||||
|
||||
return {{move(twinkleBackground), 1.0f}, {move(twinkleFrame), twinkleScale}};
|
||||
}
|
||||
|
||||
List<pair<String, float>> CelestialGraphics::drawSystemPlanetaryObject(CelestialDatabasePtr celestialDatabase, CelestialCoordinate const& coordinate) {
|
||||
if (auto params = celestialDatabase->parameters(coordinate))
|
||||
return drawSystemPlanetaryObject(params.take());
|
||||
return {};
|
||||
}
|
||||
|
||||
List<pair<String, float>> CelestialGraphics::drawSystemCentralBody(CelestialDatabasePtr celestialDatabase, CelestialCoordinate const& coordinate) {
|
||||
if (auto params = celestialDatabase->parameters(coordinate))
|
||||
return drawSystemCentralBody(params.take());
|
||||
return {};
|
||||
}
|
||||
|
||||
List<pair<String, float>> CelestialGraphics::drawWorld(CelestialDatabasePtr celestialDatabase, CelestialCoordinate const& coordinate) {
|
||||
auto params = celestialDatabase->parameters(coordinate);
|
||||
if (!params)
|
||||
return {};
|
||||
|
||||
if (coordinate.isSatelliteBody())
|
||||
return drawWorld(params.take(), celestialDatabase->parameters(coordinate.parent()));
|
||||
else
|
||||
return drawWorld(params.take());
|
||||
}
|
||||
|
||||
List<pair<String, String>> CelestialGraphics::worldHorizonImages(CelestialDatabasePtr celestialDatabase, CelestialCoordinate const& coordinate) {
|
||||
if (auto params = celestialDatabase->parameters(coordinate))
|
||||
return worldHorizonImages(params.take());
|
||||
return {};
|
||||
}
|
||||
|
||||
int CelestialGraphics::worldRadialPosition(CelestialDatabasePtr celestialDatabase, CelestialCoordinate const& coordinate) {
|
||||
if (auto params = celestialDatabase->parameters(coordinate))
|
||||
return worldRadialPosition(params.take());
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue