#include "StarSkyRenderData.hpp" #include "StarJsonExtra.hpp" #include "StarDataStreamExtra.hpp" #include "StarRandomPoint.hpp" #include "StarDrawable.hpp" namespace Star { StringList SkyRenderData::starTypes() const { if (type == SkyType::Warp) return hyperStarList; else return starList; } List SkyRenderData::backOrbiters(Vec2F const& viewSize) const { if (!settings) return {}; float planetScale = settings.queryFloat("satellite.planetScale"); float moonScale = settings.queryFloat("satellite.moonScale"); List>, Vec2F, float>> orbitingCelestialObjects; // Gather up all the CelestialParameters and scales for all the celestial // objects to draw in the sky, we should draw the parent planet if we are a // satellite, as well as all the other satellites. if (skyParameters.nearbyPlanet) orbitingCelestialObjects.append(tuple_cat(*skyParameters.nearbyPlanet, tie(planetScale))); for (auto moon : skyParameters.nearbyMoons) orbitingCelestialObjects.append(tuple_cat(moon, tie(moonScale))); Vec2F satelliteArea = jsonToVec2F(settings.query("satellite.area")); auto planetCenter = Vec2F(viewSize[0] / 2, 0) - worldOffset; auto rotMatrix = Mat3F::rotation(worldRotation, planetCenter); List orbiters; for (auto const& object : orbitingCelestialObjects) { auto const& layers = get<0>(object); Vec2F pos = get<1>(object); pos = pos.piecewiseMultiply(satelliteArea); pos -= worldOffset; pos = rotMatrix.transformVec2(pos); for (auto const& l : layers) orbiters.append(SkyOrbiter{SkyOrbiterType::Moon, get<2>(object) * l.second, 0.0f, l.first, pos}); } return orbiters; } SkyWorldHorizon SkyRenderData::worldHorizon(Vec2F const& viewSize) const { if (!settings) return {}; SkyWorldHorizon worldHorizon; if (type == SkyType::Orbital) { worldHorizon.center = Vec2F(viewSize[0] / 2, 0) - worldOffset; worldHorizon.scale = settings.queryFloat("planetHorizon.scale"); worldHorizon.rotation = worldRotation; worldHorizon.layers = skyParameters.horizonImages; } return worldHorizon; } List SkyRenderData::frontOrbiters(Vec2F const& viewSize) const { if (!settings) return {}; struct HorizonCloud { float startAngle; String image; float speed; float radius; }; List horizonClouds; if (skyParameters.horizonClouds) { Vec2I cloudCountRange = jsonToVec2I(settings.query("planetHorizon.cloudCount")); Vec2F cloudRadiusRange = jsonToVec2F(settings.query("planetHorizon.cloudRadius")); Vec2F cloudSpeedRange = jsonToVec2F(settings.query("planetHorizon.cloudSpeed")); StringList cloudList = jsonToStringList(settings.query("planetHorizon.clouds")); int numClouds = staticRandomI32Range(cloudCountRange[0], cloudCountRange[1], "HorizonCloudCount"); for (int i = 0; i < numClouds; ++i) { horizonClouds.append({staticRandomFloatRange(0, 2 * Constants::pi, i, "CloudStartAngle"), staticRandomFrom(cloudList, i, "Cloud"), staticRandomFloatRange(cloudSpeedRange[0], cloudSpeedRange[1], i, "CloudSpeed"), staticRandomFloatRange(cloudRadiusRange[0], cloudRadiusRange[1], i, "CloudRadius")}); } } List orbiters; if (type == SkyType::Atmospheric || type == SkyType::Atmosphereless) { String image; if (settings.queryBool("sun.dynamicImage.enabled", false) && !skyParameters.sunType.empty()) image = settings.queryString("sun.dynamicImage.images." + skyParameters.sunType, settings.queryString("sun.image")); else image = settings.queryString("sun.image"); orbiters.append({SkyOrbiterType::Sun, settings.queryFloat("sun.scale", 1.0f), 0.0f, image, Vec2F::withAngle(orbitAngle, settings.queryFloat("sun.radius")) + viewSize / 2}); } else if (type == SkyType::Orbital) { auto planetCenter = Vec2F(viewSize[0] / 2, 0) - Vec2F::withAngle(worldRotation - Constants::pi / 2, settings.queryFloat("planetHorizon.yCenter")) - worldOffset; float scale = settings.queryFloat("planetHorizon.scale"); auto rotMatrix = Mat3F::rotation(worldRotation, planetCenter); if (skyParameters.horizonClouds) { for (auto const& horizonCloud : horizonClouds) { Vec2F position = Vec2F::withAngle(horizonCloud.startAngle + orbitAngle * horizonCloud.speed, horizonCloud.radius) + planetCenter; position = rotMatrix.transformVec2(position); orbiters.append({SkyOrbiterType::HorizonCloud, scale, worldRotation, horizonCloud.image, position}); } } } return orbiters; } DataStream& operator>>(DataStream& ds, SkyRenderData& skyRenderData) { ds.read(skyRenderData.settings); ds.read(skyRenderData.skyParameters); ds.read(skyRenderData.type); ds.read(skyRenderData.dayLevel); ds.read(skyRenderData.skyAlpha); ds.read(skyRenderData.dayLength); ds.read(skyRenderData.timeOfDay); ds.read(skyRenderData.epochTime); ds.read(skyRenderData.starOffset); ds.read(skyRenderData.starRotation); ds.read(skyRenderData.worldOffset); ds.read(skyRenderData.worldRotation); ds.read(skyRenderData.orbitAngle); ds.readVlqS(skyRenderData.starFrames); ds.read(skyRenderData.starList); ds.read(skyRenderData.hyperStarList); ds.read(skyRenderData.environmentLight); ds.read(skyRenderData.mainSkyColor); ds.read(skyRenderData.topRectColor); ds.read(skyRenderData.bottomRectColor); ds.read(skyRenderData.flashColor); return ds; } DataStream& operator<<(DataStream& ds, SkyRenderData const& skyRenderData) { ds.write(skyRenderData.settings); ds.write(skyRenderData.skyParameters); ds.write(skyRenderData.type); ds.write(skyRenderData.dayLevel); ds.write(skyRenderData.skyAlpha); ds.write(skyRenderData.dayLength); ds.write(skyRenderData.timeOfDay); ds.write(skyRenderData.epochTime); ds.write(skyRenderData.starOffset); ds.write(skyRenderData.starRotation); ds.write(skyRenderData.worldOffset); ds.write(skyRenderData.worldRotation); ds.write(skyRenderData.orbitAngle); ds.writeVlqS(skyRenderData.starFrames); ds.write(skyRenderData.starList); ds.write(skyRenderData.hyperStarList); ds.write(skyRenderData.environmentLight); ds.write(skyRenderData.mainSkyColor); ds.write(skyRenderData.topRectColor); ds.write(skyRenderData.bottomRectColor); ds.write(skyRenderData.flashColor); return ds; } }