mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-19 01:29:21 +02:00
198 lines
8.4 KiB
C++
198 lines
8.4 KiB
C++
/*
|
|
This Source Code Form is subject to the
|
|
terms of the Mozilla Public License, v.
|
|
2.0. If a copy of the MPL was not
|
|
distributed with this file, You can
|
|
obtain one at
|
|
http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <vector>
|
|
|
|
#include <glm/glm.hpp>
|
|
|
|
class cParser;
|
|
|
|
// cloud genera as aviation reports them (WMO), each drawn in its own way. the order is that of the names in cloud_genus_info()
|
|
enum class cloud_type : int
|
|
{
|
|
cumulus = 0,
|
|
towering_cumulus,
|
|
cumulonimbus,
|
|
stratocumulus,
|
|
stratus,
|
|
nimbostratus,
|
|
altocumulus,
|
|
altostratus,
|
|
cirrus,
|
|
cirrostratus,
|
|
cirrocumulus,
|
|
count
|
|
};
|
|
|
|
// what a genus typically looks like, and how it is drawn
|
|
struct cloud_genus
|
|
{
|
|
char const *name; // full name, as in the weather section of a scenery
|
|
char const *abbreviation; // as in reports (Cu, TCu, Cb...)
|
|
float base; // typical height of the base above the ground, metres
|
|
float thickness; // typical depth of the layer, metres
|
|
float extinction; // light taken out per metre inside the cloud at density 1 (1/m); for a flat layer its optical depth
|
|
float cell; // horizontal size of the single clouds or of the lumps of a sheet, metres
|
|
float spread; // horizontal size of the areas the coverage is spread over, metres
|
|
float bottom; // part of the depth over which the density rises from the base: small for the flat base of a cumulus
|
|
float top; // part of the depth from which the density falls towards the top
|
|
float top_variation; // how much the top of single clouds varies (towers of different heights), 0-1
|
|
float anvil; // how far the top spreads out (the anvil of a cumulonimbus), 0-1
|
|
float erosion; // how much the small scale noise eats into the edges, 0-1
|
|
float stretch; // how much the noise is drawn out along the wind (streaks of a cirrus), 1 = not at all
|
|
float opacity; // share of the sky light a full layer holds back, for the overcast the rest of the simulation goes by
|
|
bool flat; // drawn as a thin sheet (high clouds), not ray marched through
|
|
};
|
|
|
|
cloud_genus const &cloud_genus_info(cloud_type Type);
|
|
// genus named by its full name or abbreviation, any case
|
|
std::optional<cloud_type> cloud_type_from_name(std::string_view Name);
|
|
|
|
struct cloud_layer
|
|
{
|
|
cloud_type type{cloud_type::cumulus};
|
|
float coverage{0.f}; // share of the sky the layer covers, 0-1 (oktas / 8)
|
|
float base{1000.f}; // height of the base above the ground reference, metres
|
|
float top{2000.f}; // height of the top above the ground reference, metres
|
|
float density{1.f}; // multiplier of the typical density of the genus
|
|
};
|
|
|
|
enum class precipitation_type : int
|
|
{
|
|
automatic = 0, // rain or snow by the air temperature, as the overcast above 1 always did
|
|
none,
|
|
rain,
|
|
snow
|
|
};
|
|
|
|
// the weather of the scenery: what the simulation keeps and the renderer draws. all heights are above the ground reference
|
|
struct weather_conditions
|
|
{
|
|
static constexpr std::size_t max_cloud_layers{4};
|
|
|
|
std::vector<cloud_layer> clouds; // ordered by the base, at most max_cloud_layers
|
|
// meteorological optical range at the ground, metres: how far a dark object is still seen against the horizon (5% contrast)
|
|
float visibility{10000.f};
|
|
float haze_height{800.f}; // scale height of the haze: its density falls e times every this many metres up
|
|
float groundfog_thickness{0.f}; // fog lying on the ground (in the valleys below the reference too), metres; 0 = none
|
|
float groundfog_visibility{300.f}; // visibility inside it
|
|
float fog_noise{0.3f}; // how patchy the fog is, 0-1
|
|
precipitation_type precipitation{precipitation_type::automatic};
|
|
float precipitation_intensity{0.f}; // 0-1
|
|
float cloud_wind_direction{270.f}; // where the wind at the height of the clouds blows from, degrees from the north, clockwise
|
|
float cloud_wind_speed{8.f}; // m/s
|
|
std::uint32_t seed{0}; // changes the shapes of the clouds
|
|
std::optional<float> temperature; // air temperature a report gave, degrees C; applied with the weather
|
|
|
|
// share of the sky the clouds hold back, 0-1, and the precipitation past it: the overcast the rest of the simulation goes by
|
|
float overcast() const;
|
|
// sorts the layers by their base and keeps them within their limits
|
|
void normalize();
|
|
};
|
|
|
|
// reads a weather report (METAR, the body of it: the station and time may be there or not) into Conditions. what the report does
|
|
// not mention is left as it was, apart from the clouds, which are replaced when it has any cloud group or says there are none.
|
|
// returns false when nothing in it was understood
|
|
bool parse_metar(std::string_view Report, weather_conditions &Conditions);
|
|
// a report of the conditions in the METAR form, for the user interface and the scripting interface
|
|
std::string to_metar(weather_conditions const &Conditions);
|
|
// clouds and precipitation of the old single number of the weather (atmo, the overcast slider, scripts): up to 1 the sky clouds
|
|
// over, past it rain or snow falls
|
|
std::vector<cloud_layer> clouds_from_overcast(float Overcast);
|
|
// visibility of the old fog range (atmo, Global.fFogEnd), as the old fog thickened with the overcast, and back
|
|
float visibility_from_fog_range(float Fogend, float Overcast);
|
|
float fog_range_from_visibility(float Visibility, float Overcast);
|
|
|
|
// the weather of the simulation. the scenery may describe it (the weather section); otherwise, and whenever something sets the
|
|
// old overcast and fog range (atmo, the sliders, the scripting interface, the setweather command of the network), the clouds and
|
|
// the visibility are made from those. while the weather is described, the overcast and fog range are worked out from it, so the
|
|
// rest of the simulation (lights, sounds, precipitation, friction) goes on as before
|
|
class world_weather
|
|
{
|
|
public:
|
|
// forgets the weather of the previous scenery
|
|
void reset();
|
|
// the weather section of a scenery, read before the simulation starts
|
|
void deserialize(cParser &Input);
|
|
// starts the weather of the loaded scenery
|
|
void init();
|
|
// moves the clouds with the wind, goes on with a change of the weather and keeps the old global state in step
|
|
void update(double const Deltatime, glm::dvec3 const &Camera);
|
|
// changes the weather while the simulation runs, over Transition seconds. Quiet: not logged (changes made by a slider)
|
|
void apply(weather_conditions const &Conditions, float const Transition, bool const Quiet = false);
|
|
// changes the weather after a report or a weather section text, as the scripting interface gives it. false when it says nothing
|
|
bool apply_text(std::string_view Text, float const Transition);
|
|
|
|
// the weather as it is now (in the middle of a change, a mix of the old and the new one)
|
|
weather_conditions const &conditions() const
|
|
{
|
|
return m_current;
|
|
}
|
|
// the weather a change goes to, or the current one
|
|
weather_conditions const &target() const
|
|
{
|
|
return m_target;
|
|
}
|
|
// true when the clouds come from a description, false when from the old overcast
|
|
bool described() const
|
|
{
|
|
return m_described_clouds;
|
|
}
|
|
// world height (y) of the ground the heights of the weather are counted from
|
|
float ground() const
|
|
{
|
|
return m_ground;
|
|
}
|
|
// how far the wind carried the clouds, world x and z, metres
|
|
glm::dvec2 const &cloud_offset() const
|
|
{
|
|
return m_cloud_offset;
|
|
}
|
|
// seconds of simulation since the start, for the clouds and fog to change their shapes slowly
|
|
double time() const
|
|
{
|
|
return m_time;
|
|
}
|
|
// world space velocity of the clouds (x, z), m/s
|
|
glm::vec2 cloud_velocity() const;
|
|
// precipitation the description sets, or nullopt when the air temperature decides
|
|
std::optional<precipitation_type> precipitation_override() const;
|
|
|
|
private:
|
|
// the clouds and the visibility of the old global state
|
|
void follow_overcast();
|
|
void follow_fog_range();
|
|
// the old global state of the weather described
|
|
void write_globals();
|
|
|
|
std::optional<weather_conditions> m_scenery; // read from the scenery
|
|
std::optional<float> m_elevation; // ground reference the scenery gives
|
|
weather_conditions m_from; // weather a change started at
|
|
weather_conditions m_target;
|
|
weather_conditions m_current;
|
|
double m_transition{0.0}; // length of the change in progress, seconds
|
|
double m_transition_time{0.0}; // how far it got
|
|
bool m_described_clouds{false};
|
|
bool m_described_fog{false};
|
|
// the overcast and fog range last written or followed, to tell when something else changed them
|
|
float m_known_overcast{-1.f};
|
|
float m_known_fogend{-1.f};
|
|
bool m_ground_set{false};
|
|
float m_ground{0.f};
|
|
glm::dvec2 m_cloud_offset{0.0};
|
|
double m_time{0.0};
|
|
};
|