osb/source/game/StarSky.cpp
Kai Blaschke 431a9c00a5
Fixed a huge amount of Clang warnings
On Linux and macOS, using Clang to compile OpenStarbound produces about 400 MB worth of warnings during the build, making the compiler output unreadable and slowing the build down considerably.

99% of the warnings were unqualified uses of std::move and std::forward, which are now all properly qualified.

Fixed a few other minor warnings about non-virtual destructors and some uses of std::move preventing copy elision on temporary objects.

Most remaining warnings are now unused parameters.
2024-02-19 16:55:19 +01:00

655 lines
20 KiB
C++

#include "StarSky.hpp"
#include "StarJsonExtra.hpp"
#include "StarDataStreamExtra.hpp"
#include "StarRoot.hpp"
#include "StarCelestialDatabase.hpp"
#include "StarCelestialGraphics.hpp"
#include "StarAssets.hpp"
#include "StarTime.hpp"
#include "StarRandomPoint.hpp"
#include "StarMixer.hpp"
#include "StarCompression.hpp"
namespace Star {
Sky::Sky() {
m_settings = Root::singleton().assets()->json("/sky.config");
m_starFrames = m_settings.queryInt("stars.frames");
m_starList = jsonToStringList(m_settings.query("stars.list"));
m_hyperStarList = jsonToStringList(m_settings.query("stars.hyperlist"));
m_netInit = false;
m_netGroup.addNetElement(&m_skyParametersNetState);
m_netGroup.addNetElement(&m_skyTypeNetState);
m_netGroup.addNetElement(&m_timeNetState);
m_netGroup.addNetElement(&m_flyingTypeNetState);
m_netGroup.addNetElement(&m_enterHyperspaceNetState);
m_netGroup.addNetElement(&m_startInWarpNetState);
m_netGroup.addNetElement(&m_worldMoveNetState);
m_netGroup.addNetElement(&m_starMoveNetState);
m_netGroup.addNetElement(&m_warpPhaseNetState);
m_netGroup.addNetElement(&m_flyingTimerNetState);
m_netGroup.setNeedsLoadCallback(bind(&Sky::readNetStates, this));
m_netGroup.setNeedsStoreCallback(bind(&Sky::writeNetStates, this));
}
Sky::Sky(SkyParameters const& skyParameters, bool inOrbit) : Sky() {
m_skyParameters = skyParameters;
m_skyParametersUpdated = true;
if (inOrbit)
m_skyType = SkyType::Orbital;
else
m_skyType = m_skyParameters.skyType;
}
void Sky::startFlying(bool enterHyperspace, bool startInWarp) {
if (startInWarp)
m_flyingType = FlyingType::Warp;
else
m_flyingType = FlyingType::Disembarking;
m_flyingTimer = 0;
m_enterHyperspace = enterHyperspace;
m_startInWarp = startInWarp;
}
void Sky::stopFlyingAt(Maybe<SkyParameters> dest) {
m_destWorld = dest;
}
void Sky::jumpTo(SkyParameters skyParameters) {
m_skyParameters = skyParameters;
m_skyParametersUpdated = true;
}
pair<ByteArray, uint64_t> Sky::writeUpdate(uint64_t fromVersion) {
return m_netGroup.writeNetState(fromVersion);
}
void Sky::readUpdate(ByteArray data) {
m_netGroup.readNetState(std::move(data));
}
void Sky::stateUpdate() {
if (m_lastFlyingType != m_flyingType) {
m_flyingTimer = 0.0f;
if (m_flyingType == FlyingType::Warp) {
m_warpPhase = WarpPhase::SpeedingUp;
if (m_startInWarp) {
if (m_enterHyperspace)
m_warpPhase = WarpPhase::Maintain;
else
m_flyingTimer = speedupTime();
m_lastWarpPhase = m_warpPhase;
}
float maxVelocity = m_settings.queryFloat("flyMaxVelocity");
m_worldMoveOffset = Vec2F::withAngle(m_pathRotation, maxVelocity / 2.0 * speedupTime());
m_starMoveOffset = Vec2F::withAngle(0, (maxVelocity * m_settings.queryFloat("starVelocityFactor")) / 2.0 * speedupTime());
} else if (m_flyingType == FlyingType::Arriving) {
m_sentSFX = false;
m_worldOffset = {};
m_starOffset = {};
}
}
if (m_lastWarpPhase != m_warpPhase) {
m_flyingTimer = 0.0f;
if (m_warpPhase == WarpPhase::SpeedingUp)
m_sentSFX = false;
else if (m_warpPhase == WarpPhase::Maintain)
enterHyperspace();
else if (m_warpPhase == WarpPhase::SlowingDown)
exitHyperspace();
}
m_lastFlyingType = m_flyingType;
m_lastWarpPhase = m_warpPhase;
}
void Sky::update(double dt) {
if (m_referenceClock) {
m_time = m_referenceClock->time();
if (!m_clockTrackingTime) {
m_clockTrackingTime = m_time;
} else {
// If our reference clock is set, and we have a valid tracking time, then
// the dt should be driven by the reference clock.
dt = m_time - *m_clockTrackingTime;
m_clockTrackingTime = m_time;
}
} else {
m_time += dt;
}
m_flashTimer = std::max(0.0, m_flashTimer - dt);
if (flying()) {
m_flyingTimer += dt;
if (m_flyingType == FlyingType::Disembarking) {
bool finished;
if (m_skyParameters.skyType == SkyType::Space)
finished = controlledMovement(m_settings.getArray("spaceDisembarkPath"), m_settings.get("spaceDisembarkOrigin"), m_flyingTimer);
else
finished = controlledMovement(m_settings.getArray("disembarkPath"), m_settings.get("disembarkOrigin"), m_flyingTimer);
if (finished) {
m_flyingType = FlyingType::Warp;
}
} else if (m_flyingType == FlyingType::Arriving) {
bool finished;
if (m_skyParameters.skyType == SkyType::Space)
finished = controlledMovement(m_settings.getArray("spaceArrivalPath"), m_settings.get("spaceArrivalOrigin"), m_flyingTimer);
else
finished = controlledMovement(m_settings.getArray("arrivalPath"), m_settings.get("arrivalOrigin"), m_flyingTimer);
if (finished) {
m_flyingType = FlyingType::None;
}
m_starOffset -= m_starOffset * m_settings.queryFloat("correctionPower");
m_worldOffset -= m_worldOffset * m_settings.queryFloat("correctionPower");
} else if (m_flyingType == FlyingType::Warp) {
float percentage = 0.0;
float dir = (int)m_warpPhase < 0 ? -1.0 : 1.0;
if (m_warpPhase == WarpPhase::SpeedingUp)
percentage = powf(m_flyingTimer / speedupTime(), 2.0);
else if (m_warpPhase == WarpPhase::Maintain)
percentage = 1.0;
else if (m_warpPhase == WarpPhase::SlowingDown)
percentage = powf(1 - m_flyingTimer / slowdownTime(), 2.0);
if (percentage < 1.0) {
m_starOffset = (dir * m_starMoveOffset * percentage).rotate(-getStarRotation());
m_worldOffset = (dir * m_worldMoveOffset * percentage).rotate(-getWorldRotation());
} else {
m_starOffset += Vec2F::withAngle(-getStarRotation(), m_settings.queryFloat("flyMaxVelocity") * dt * m_settings.queryFloat("starVelocityFactor"));
m_worldOffset = m_worldMoveOffset;
}
if (m_warpPhase == WarpPhase::SpeedingUp && m_flyingTimer >= speedupTime()
&& !m_enterHyperspace
&& m_destWorld) {
jumpTo(m_destWorld.take());
m_warpPhase = WarpPhase::SlowingDown;
} else if (m_warpPhase == WarpPhase::SpeedingUp && m_flyingTimer >= speedupTime() && m_enterHyperspace) {
m_warpPhase = WarpPhase::Maintain;
} else if (m_warpPhase == WarpPhase::Maintain && m_flyingTimer >= m_settings.queryFloat("flyingTimer")
&& m_destWorld) {
jumpTo(m_destWorld.take());
m_warpPhase = WarpPhase::SlowingDown;
} else if (m_warpPhase == WarpPhase::SlowingDown && m_flyingTimer >= slowdownTime()) {
m_flyingType = FlyingType::Arriving;
}
}
} else {
m_starOffset = {};
m_worldOffset = {};
m_pathOffset = {};
m_worldRotation = m_pathRotation = 0;
}
stateUpdate();
if (!flying())
m_starRotation = constrainAngle(m_starRotation + dt / dayLength() * 2 * Constants::pi);
else
m_starRotation = 0;
}
void Sky::setType(SkyType skyType) {
m_skyType = skyType;
}
SkyType Sky::type() const {
return m_skyType;
}
bool Sky::inSpace() const {
return m_skyType == SkyType::Orbital || m_skyType == SkyType::Warp || m_skyType == SkyType::Space;
}
uint64_t Sky::seed() const {
return m_skyParameters.seed;
}
float Sky::dayLength() const {
return m_skyParameters.dayLength.value(DefaultDayLength);
}
uint32_t Sky::day() const {
if (!m_skyParameters.dayLength)
return 0;
return floor(epochTime() / dayLength());
}
float Sky::timeOfDay() const {
if (!m_skyParameters.dayLength)
return 0;
return fmod(epochTime(), (double)dayLength());
}
double Sky::epochTime() const {
return m_time;
}
void Sky::setEpochTime(double epochTime) {
m_time = epochTime;
}
float Sky::altitude() const {
return m_altitude;
}
void Sky::setAltitude(float altitude) {
m_altitude = altitude;
}
void Sky::setReferenceClock(ClockConstPtr const& referenceClock) {
m_referenceClock = referenceClock;
m_time = m_referenceClock->time();
m_clockTrackingTime = {};
}
ClockConstPtr Sky::referenceClock() const {
return m_referenceClock;
}
String Sky::ambientNoise() const {
if (flying()) {
if (m_flyingType == FlyingType::Warp && m_warpPhase == WarpPhase::Maintain) {
return m_settings.queryString("hyperspaceAudio");
} else {
return m_settings.queryString("engineAudio");
}
}
return "";
}
List<AudioInstancePtr> Sky::pullSounds() {
List<AudioInstancePtr> res;
if (m_flyingType == FlyingType::Warp) {
if (m_warpPhase == WarpPhase::SpeedingUp && !m_sentSFX) {
float triggerTime = speedupTime() - m_settings.queryFloat("enterHyperspaceAudioLeadIn");
if (triggerTime < 0 || !m_enterHyperspace) {
m_sentSFX = true;
return res;
}
if (m_flyingTimer >= triggerTime) {
auto assets = Root::singleton().assets();
auto SFX = assets->audio(m_settings.queryString("enterHyperspaceAudio"));
m_sentSFX = true;
res.append(make_shared<AudioInstance>(*SFX));
return res;
}
} else if (m_warpPhase == WarpPhase::Maintain && !m_sentSFX) {
float triggerTime = m_settings.queryFloat("flyingTimer") - m_settings.queryFloat("exitHyperspaceAudioLeadIn");
if (triggerTime < 0) {
m_sentSFX = true;
return res;
}
if (m_flyingTimer >= triggerTime) {
auto assets = Root::singleton().assets();
auto SFX = assets->audio(m_settings.queryString("exitHyperspaceAudio"));
m_sentSFX = true;
res.append(make_shared<AudioInstance>(*SFX));
return res;
}
}
} else if (m_flyingType == FlyingType::Arriving) {
if (!m_sentSFX) {
auto assets = Root::singleton().assets();
auto SFX = assets->audio(m_settings.queryString("arrivalAudio"));
m_sentSFX = true;
res.append(make_shared<AudioInstance>(*SFX));
return res;
}
}
return res;
}
float Sky::spaceLevel() const {
if (type() == SkyType::Atmospheric && m_skyParameters.spaceLevel && m_skyParameters.surfaceLevel) {
float altitudeRange = *m_skyParameters.spaceLevel - *m_skyParameters.surfaceLevel;
float relativeAltitude = m_altitude - *m_skyParameters.surfaceLevel;
return clamp(relativeAltitude / altitudeRange, 0.0f, 1.0f);
}
return 1.0f;
}
float Sky::orbitAngle() const {
// TODO: What should we do here? Used to divide by zero. Now is saved by
// DefaultDayLength, but it's a hack
return 2 * Constants::pi * timeOfDay() / dayLength();
}
bool Sky::isDayTime() const {
return dayLevel() >= 0.5;
}
float Sky::dayLevel() const {
// Turn the dayCycle value into a value that blends evenly between 0.0 at
// mid-night and 1.0 at mid-day and then back again.
float dayCycle = Sky::dayCycle();
if (dayCycle < 1.0)
return dayCycle / 2 + 0.5f;
else if (dayCycle > 3.0)
return (dayCycle - 3) / 2;
else
return 1.0 - (dayCycle - 1.0) / 2;
}
float Sky::dayCycle() const {
// Always middle of the night in orbit or warp space.
if (type() == SkyType::Orbital || type() == SkyType::Warp)
return 3.0f;
// This will misbehave badly if dayTransitionTime is greater than dayLength /
// 2
float transitionTime = m_settings.queryFloat("dayTransitionTime") / 2;
float dayLength = Sky::dayLength();
float timeOfDay = Sky::timeOfDay();
// timeOfDay() is defined such that 0.0 is mid-dawn. For convenience, shift
// the time of day forwards such that 0.0 is the beginning of the morning.
float shiftedTime = pfmod(timeOfDay + transitionTime / 2, dayLength);
// There are 5 times here, beginning of the morning, end of the morning,
// beginning of the evening, end of the evening, and then the beginning of
// the morning again (wrapping around).
Array<float, 5> transitionPositions = {
0.0f, transitionTime, dayLength / 2, dayLength / 2 + transitionTime, dayLength};
// The values here are mid-night, mid-day, mid-day, mid-night, mid-night.
Array<float, 5> transitionValues = {-1.0f, 1.0f, 1.0f, 3.0f, 3.0f};
return pfmod(parametricInterpolate2(
transitionPositions, transitionValues, shiftedTime, SinWeightOperator<float>(), BoundMode::Clamp),
4.0f);
}
float Sky::skyAlpha() const {
if (m_skyType != SkyType::Atmospheric) {
return 0.0f;
} else {
float skyLevel = 1.0f - spaceLevel();
return clamp(pow(skyLevel, m_settings.getFloat("skyLevelExponent")), 0.0f, 1.0f);
}
}
Color Sky::environmentLight() const {
if (m_skyType == SkyType::Orbital || m_skyType == SkyType::Warp)
return Color::Black;
if (m_skyParameters.skyColoring.isLeft()) {
auto skyColoring = m_skyParameters.skyColoring.left();
Array<Vec4F, 4> colors;
colors[0] = skyColoring.morningLightColor.toRgbaF();
colors[1] = skyColoring.dayLightColor.toRgbaF();
colors[2] = skyColoring.eveningLightColor.toRgbaF();
colors[3] = skyColoring.nightLightColor.toRgbaF();
return Color::rgbaf(listInterpolate2(colors, dayCycle(), SinWeightOperator<float>(), BoundMode::Wrap));
} else {
return m_skyParameters.skyColoring.right();
}
}
Color Sky::mainSkyColor() const {
if (m_skyParameters.skyColoring.isLeft())
return m_skyParameters.skyColoring.left().mainColor;
return Color::Black;
}
pair<Color, Color> Sky::skyRectColors() const {
if (m_skyParameters.skyColoring.isLeft()) {
auto skyColoring = m_skyParameters.skyColoring.left();
Array<Vec4F, 4> topColorList;
topColorList[0] = skyColoring.morningColors.first.toRgbaF();
topColorList[1] = skyColoring.dayColors.first.toRgbaF();
topColorList[2] = skyColoring.eveningColors.first.toRgbaF();
topColorList[3] = skyColoring.nightColors.first.toRgbaF();
Array<Vec4F, 4> bottomColorList;
bottomColorList[0] = skyColoring.morningColors.second.toRgbaF();
bottomColorList[1] = skyColoring.dayColors.second.toRgbaF();
bottomColorList[2] = skyColoring.eveningColors.second.toRgbaF();
bottomColorList[3] = skyColoring.nightColors.second.toRgbaF();
float cycle = dayCycle();
auto topColor = Color::rgbaf(listInterpolate2(topColorList, cycle, SinWeightOperator<float>(), BoundMode::Wrap));
auto bottomColor = Color::rgbaf(listInterpolate2(bottomColorList, cycle, SinWeightOperator<float>(), BoundMode::Wrap));
float skyAlpha = Sky::skyAlpha();
topColor.setAlpha(topColor.alpha() * skyAlpha);
bottomColor.setAlpha(bottomColor.alpha() * skyAlpha);
return {topColor, bottomColor};
}
return {Color::Clear, Color::Clear};
}
Color Sky::skyFlashColor() const {
Color res = Color::White;
res.setAlphaF(m_flashTimer / m_settings.queryFloat("flashTimer"));
return res;
}
bool Sky::flying() const {
if (m_flyingType == FlyingType::None)
return false;
return true;
}
FlyingType Sky::flyingType() const {
return m_flyingType;
}
float Sky::warpProgress() const {
if (m_flyingType == FlyingType::Warp) {
auto warpTime = speedupTime() + m_settings.queryFloat("flyingTimer") + slowdownTime();
auto timer = m_flyingTimer;
if (m_warpPhase < WarpPhase::SpeedingUp)
timer += speedupTime();
if (m_warpPhase < WarpPhase::Maintain)
timer += m_settings.queryFloat("flyingTimer");
return timer / warpTime;
}
return 0.0;
}
WarpPhase Sky::warpPhase() const {
return m_warpPhase;
}
bool Sky::inHyperspace() const {
return m_flyingType == FlyingType::Warp && m_enterHyperspace;
}
SkyRenderData Sky::renderData() const {
SkyRenderData renderData;
renderData.settings = m_settings;
renderData.skyParameters = m_skyParameters;
renderData.type = m_skyType;
renderData.dayLevel = dayLevel();
renderData.skyAlpha = skyAlpha();
renderData.dayLength = dayLength();
renderData.timeOfDay = timeOfDay();
renderData.epochTime = epochTime();
renderData.starOffset = getStarOffset();
renderData.starRotation = getStarRotation();
renderData.worldOffset = getWorldOffset();
renderData.worldRotation = getWorldRotation();
renderData.orbitAngle = orbitAngle();
renderData.starFrames = m_starFrames;
renderData.starList = m_starList;
renderData.hyperStarList = m_hyperStarList;
renderData.environmentLight = environmentLight();
renderData.mainSkyColor = mainSkyColor();
tie(renderData.topRectColor, renderData.bottomRectColor) = skyRectColors();
renderData.flashColor = skyFlashColor();
return renderData;
}
void Sky::writeNetStates() {
if (take(m_skyParametersUpdated))
m_skyParametersNetState.set(DataStreamBuffer::serialize<Json>(m_skyParameters.toJson()));
m_skyTypeNetState.set((int)m_skyType);
m_timeNetState.set(m_time);
m_enterHyperspaceNetState.set(m_enterHyperspace);
m_startInWarpNetState.set(m_startInWarp);
m_flyingTypeNetState.set((unsigned)m_flyingType);
m_warpPhaseNetState.set((int)m_warpPhase);
m_flyingTimerNetState.set(m_flyingTimer);
m_worldMoveNetState.set(m_worldMoveOffset);
m_starMoveNetState.set(m_starMoveOffset);
}
void Sky::readNetStates() {
if (m_skyParametersNetState.pullUpdated())
m_skyParameters = SkyParameters(DataStreamBuffer::deserialize<Json>(m_skyParametersNetState.get()));
m_skyType = (SkyType)m_skyTypeNetState.get();
m_time = m_timeNetState.get();
m_enterHyperspace = m_enterHyperspaceNetState.get();
m_startInWarp = m_startInWarpNetState.get();
m_flyingType = (FlyingType)m_flyingTypeNetState.get();
m_warpPhase = (WarpPhase)m_warpPhaseNetState.get();
stateUpdate();
if (!m_netInit) {
m_netInit = true;
m_flyingTimer = m_flyingTimerNetState.get();
m_worldMoveOffset = m_worldMoveNetState.get();
m_starMoveOffset = m_starMoveNetState.get();
}
}
void Sky::enterHyperspace() {
m_flashTimer = m_settings.queryFloat("flashTimer");
setType(SkyType::Warp);
m_sentSFX = false;
}
void Sky::exitHyperspace() {
m_flashTimer = m_settings.queryFloat("flashTimer");
setType(SkyType::Orbital);
m_sentSFX = false;
Json originMap;
Json destMap;
if (m_skyParameters.skyType == SkyType::Space) {
originMap = m_settings.getObject("spaceArrivalOrigin");
destMap = m_settings.getArray("spaceArrivalPath")[0];
} else {
originMap = m_settings.getObject("arrivalOrigin");
destMap = m_settings.getArray("arrivalPath")[0];
}
m_pathOffset = jsonToVec2F(originMap.get("offset"));
m_pathRotation = originMap.get("rotation").toFloat() * Constants::deg2rad;
float maxVelocity = m_settings.queryFloat("flyMaxVelocity");
float exitDistance = maxVelocity / 2.0 * slowdownTime();
m_worldMoveOffset = Vec2F::withAngle(0, exitDistance);
m_worldOffset = m_worldMoveOffset;
exitDistance = (maxVelocity * m_settings.queryFloat("starVelocityFactor")) / 2.0 * slowdownTime();
m_starMoveOffset = Vec2F::withAngle(0, exitDistance);
m_starOffset = m_starMoveOffset;
m_worldRotation = m_starRotation = 0;
m_flyingTimer = 0;
}
bool Sky::controlledMovement(JsonArray const& path, Json const& origin, float timeOffset) {
float previousTime = 0;
Vec2F previousOffset = jsonToVec2F(origin.get("offset"));
float previousRotation = origin.getFloat("rotation") * Constants::deg2rad;
float stepTime = 0;
Vec2F stepOffset;
float stepRotation;
for (auto const& entry : path) {
stepOffset = jsonToVec2F(entry.get("offset"));
stepRotation = entry.getFloat("rotation") * Constants::deg2rad;
stepTime += entry.getFloat("time");
if (timeOffset <= stepTime) {
float percentage = (timeOffset - previousTime) / (stepTime - previousTime);
m_pathOffset = lerp(percentage, previousOffset, stepOffset);
m_pathRotation = lerp(percentage, previousRotation, stepRotation);
return false;
}
previousTime = stepTime;
previousOffset = stepOffset;
previousRotation = stepRotation;
}
// if loop wasn't broken
// then we're done with this phase of controlled movement
// signal that we're ready to head out of this system
return true;
}
Vec2F Sky::getStarOffset() const {
return (m_starOffset + m_pathOffset);
}
float Sky::getStarRotation() const {
return m_starRotation + m_pathRotation;
}
Vec2F Sky::getWorldOffset() const {
return m_worldOffset + m_pathOffset;
}
float Sky::getWorldRotation() const {
return m_worldRotation + m_pathRotation;
}
float Sky::speedupTime() const {
if (m_enterHyperspace)
return m_settings.queryFloat("hyperspaceSpeedupTime");
else
return m_settings.queryFloat("speedupTime");
}
float Sky::slowdownTime() const {
if (m_enterHyperspace)
return m_settings.queryFloat("hyperspaceSlowdownTime");
else
return m_settings.queryFloat("slowdownTime");
}
}