diff --git a/CMakeLists.txt b/CMakeLists.txt index d4aa351..bc40e61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ find_package(SDL2 REQUIRED COMPONENTS SDL2::SDL2-static SDL2::SDL2main CONFIG) find_package(OpenAL REQUIRED CONFIG) find_library(physfs REQUIRED NAMES physfs-static PATHS "${CMAKE_PREFIX_PATH}/lib") + # Determine dependencies set(STATIC_LIBS dr_wav diff --git a/src/game/astronomy/apparent-size.cpp b/src/game/astronomy/apparent-size.cpp index f8d2db7..9d60fc5 100644 --- a/src/game/astronomy/apparent-size.cpp +++ b/src/game/astronomy/apparent-size.cpp @@ -23,7 +23,7 @@ namespace ast { -double angular_radius(double radius, double distance) +double find_angular_radius(double radius, double distance) { return std::asin(radius / distance); } diff --git a/src/game/astronomy/apparent-size.hpp b/src/game/astronomy/apparent-size.hpp index d3ec3d0..dfce155 100644 --- a/src/game/astronomy/apparent-size.hpp +++ b/src/game/astronomy/apparent-size.hpp @@ -24,13 +24,13 @@ namespace ast { /** - * Calculates the angular radius of a celestial object. + * Finds the angular radius of a celestial object, given its radius and distance. * * @param radius Radius of the celestial object. * @param distance Distance to the celestial object. * @return Angular radius, in radians. */ -double angular_radius(double radius, double distance); +double find_angular_radius(double radius, double distance); } // namespace ast diff --git a/src/game/astronomy/celestial-coordinates.cpp b/src/game/astronomy/celestial-coordinates.cpp index 7a9aa43..194b798 100644 --- a/src/game/astronomy/celestial-coordinates.cpp +++ b/src/game/astronomy/celestial-coordinates.cpp @@ -58,14 +58,14 @@ double3x3 ecliptic_to_equatorial(double ecl) }; } -double3x3 ecliptic_to_horizontal(double ecl, double lat, double lmst) +double3x3 ecliptic_to_horizontal(double ecl, double lat, double lst) { const double c_ecl = std::cos(ecl); const double s_ecl = std::sin(ecl); const double c_lat = std::cos(lat); const double s_lat = std::sin(lat); - const double c_lst = std::cos(lmst); - const double s_lst = std::sin(lmst); + const double c_lst = std::cos(lst); + const double s_lst = std::sin(lst); return double3x3 { @@ -88,12 +88,12 @@ double3x3 equatorial_to_ecliptic(double ecl) }; } -double3x3 equatorial_to_horizontal(double lat, double lmst) +double3x3 equatorial_to_horizontal(double lat, double lst) { const double c_lat = std::cos(lat); const double s_lat = std::sin(lat); - const double c_lst = std::cos(lmst); - const double s_lst = std::sin(lmst); + const double c_lst = std::cos(lst); + const double s_lst = std::sin(lst); return double3x3 { @@ -103,12 +103,12 @@ double3x3 equatorial_to_horizontal(double lat, double lmst) }; } -double3x3 horizontal_to_equatorial(double lat, double lmst) +double3x3 horizontal_to_equatorial(double lat, double lst) { const double c_lat = std::cos(lat); const double s_lat = std::sin(lat); - const double c_lst = std::cos(lmst); - const double s_lst = std::sin(lmst); + const double c_lst = std::cos(lst); + const double s_lst = std::sin(lst); return double3x3 { @@ -118,14 +118,14 @@ double3x3 horizontal_to_equatorial(double lat, double lmst) }; } -double3x3 horizontal_to_ecliptic(double ecl, double lat, double lmst) +double3x3 horizontal_to_ecliptic(double ecl, double lat, double lst) { const double c_ecl = std::cos(ecl); const double s_ecl = std::sin(ecl); const double c_lat = std::cos(lat); const double s_lat = std::sin(lat); - const double c_lst = std::cos(lmst); - const double s_lst = std::sin(lmst); + const double c_lst = std::cos(lst); + const double s_lst = std::sin(lst); return double3x3 { diff --git a/src/game/astronomy/celestial-coordinates.hpp b/src/game/astronomy/celestial-coordinates.hpp index 7b401a3..b2e4cb5 100644 --- a/src/game/astronomy/celestial-coordinates.hpp +++ b/src/game/astronomy/celestial-coordinates.hpp @@ -54,10 +54,10 @@ double3x3 ecliptic_to_equatorial(double ecl); * * @param ecl Obliquity of the ecliptic, in radians. * @param lat Observer's latitude, in radians. - * @param lmst Local mean sidereal time. + * @param lst Local sidereal time, in radians. * @return Transformation matrix. */ -double3x3 ecliptic_to_horizontal(double ecl, double lat, double lmst); +double3x3 ecliptic_to_horizontal(double ecl, double lat, double lst); /** * Produces a matrix which transforms rectangular coordinates from equatorial space to ecliptic space. @@ -71,29 +71,29 @@ double3x3 equatorial_to_ecliptic(double ecl); * Produces a matrix which transforms rectangular coordinates from equatorial space to horizontal space. * * @param lat Observer's latitude, in radians. - * @param lmst Local mean sidereal time. + * @param lst Local sidereal time, in radians. * @return Transformation matrix. */ -double3x3 equatorial_to_horizontal(double lat, double lmst); +double3x3 equatorial_to_horizontal(double lat, double lst); /** * Produces a matrix which transforms rectangular coordinates from horizontal space to equatorial space. * * @param lat Observer's latitude, in radians. - * @param lmst Local mean sidereal time. + * @param lst Local sidereal time, in radians. * @return Transformation matrix. */ -double3x3 horizontal_to_equatorial(double lat, double lmst); +double3x3 horizontal_to_equatorial(double lat, double lst); /** * Produces a matrix which transforms rectangular coordinates from horizontal space to ecliptic space. * * @param ecl Obliquity of the ecliptic, in radians. * @param lat Observer's latitude, in radians. - * @param lmst Local mean sidereal time. + * @param lst Local sidereal time, in radians. * @return Transformation matrix. */ -double3x3 horizontal_to_ecliptic(double ecl, double lat, double lmst); +double3x3 horizontal_to_ecliptic(double ecl, double lat, double lst); /// Matrix which transforms coordinates from horizontal space to a right-handed coordinate system. constexpr double3x3 horizontal_to_right_handed = diff --git a/src/game/astronomy/celestial-mechanics.cpp b/src/game/astronomy/celestial-mechanics.cpp index 9e4565a..3ac4574 100644 --- a/src/game/astronomy/celestial-mechanics.cpp +++ b/src/game/astronomy/celestial-mechanics.cpp @@ -24,111 +24,6 @@ namespace ast { -double approx_ecliptic_obliquity(double jd) -{ - return math::radians(23.4393 - 3.563e-7 * (jd - 2451545.0)); -} - -double3 approx_sun_ecliptic(double jd) -{ - const double t = (jd - 2451545.0) / 36525.0; - const double m = 6.24 + 628.302 * t; - - const double longitude = 4.895048 + 628.331951 * t + (0.033417 - 0.000084 * t) * std::sin(m) + 0.000351 * std::sin(m * 2.0); - const double latitude = 0.0; - const double distance = 1.000140 - (0.016708 - 0.000042 * t) * std::cos(m) - 0.000141 * std::cos(m * 2.0); - - double3 ecliptic; - ecliptic.x = distance * std::cos(longitude) * std::cos(latitude); - ecliptic.y = distance * std::sin(longitude) * std::cos(latitude); - ecliptic.z = distance * std::sin(latitude); - - return ecliptic; -} - -double3 approx_moon_ecliptic(double jd) -{ - const double t = (jd - 2451545.0) / 36525.0; - const double l1 = 3.8104 + 8399.7091 * t; - const double m1 = 2.3554 + 8328.6911 * t; - const double m = 6.2300 + 628.3019 * t; - const double d = 5.1985 + 7771.3772 * t; - const double d2 = d * 2.0; - const double f = 1.6280 + 8433.4663 * t; - - const double longitude = l1 - + 0.1098 * std::sin(m1) - + 0.0222 * std::sin(d2 - m1) - + 0.0115 * std::sin(d2) - + 0.0037 * std::sin(m1 * 2.0) - - 0.0032 * std::sin(m) - - 0.0020 * std::sin(d2) - + 0.0010 * std::sin(d2 - m1 * 2.0) - + 0.0010 * std::sin(d2 - m - m1) - + 0.0009 * std::sin(d2 + m1) - + 0.0008 * std::sin(d2 - m) - + 0.0007 * std::sin(m1 - m) - - 0.0006 * std::sin(d) - - 0.0005 * std::sin(m + m1); - - const double latitude = 0.0895 * sin(f) - + 0.0049 * std::sin(m1 + f) - + 0.0048 * std::sin(m1 - f) - + 0.0030 * std::sin(d2 - f) - + 0.0010 * std::sin(d2 + f - m1) - + 0.0008 * std::sin(d2 - f - m1) - + 0.0006 * std::sin(d2 + f); - - const double r = 1.0 / (0.016593 - + 0.000904 * std::cos(m1) - + 0.000166 * std::cos(d2 - m1) - + 0.000137 * std::cos(d2) - + 0.000049 * std::cos(m1 * 2.0) - + 0.000015 * std::cos(d2 + m1) - + 0.000009 * std::cos(d2 - m)); - - double3 ecliptic; - ecliptic.x = r * std::cos(longitude) * std::cos(latitude); - ecliptic.y = r * std::sin(longitude) * std::cos(latitude); - ecliptic.z = r * std::sin(latitude); - - return ecliptic; -} - -double3x3 approx_moon_ecliptic_rotation(double jd) -{ - const double t = (jd - 2451545.0) / 36525.0; - const double l1 = 3.8104 + 8399.7091 * t; - const double f = 1.6280 + 8433.4663 * t; - - const double az0 = f + math::pi; - const double ax = 0.026920; - const double az1 = l1 - f; - - double3x3 rz0 = - { - cos(az0), -sin(az0), 0, - sin(az0), cos(az0), 0, - 0, 0, 1 - }; - - double3x3 rx = - { - 1, 0, 0, - 0, cos(ax), -sin(ax), - 0, sin(ax), cos(ax) - }; - - double3x3 rz1 = - { - cos(az1), -sin(az1), 0, - sin(az1), cos(az1), 0, - 0, 0, 1 - }; - - return rz0 * rx * rz1; -} - double solve_kepler(double ec, double ma, double tolerance, std::size_t iterations) { // Approximate eccentric anomaly, E diff --git a/src/game/astronomy/celestial-mechanics.hpp b/src/game/astronomy/celestial-mechanics.hpp index efa0ed8..0422f4b 100644 --- a/src/game/astronomy/celestial-mechanics.hpp +++ b/src/game/astronomy/celestial-mechanics.hpp @@ -47,38 +47,6 @@ struct orbital_state double3 v; ///< Cartesian velocity, v. }; -/** - * Approximates the obliquity of the ecliptic. - * - * @param jd Julian date. - * @return Obliquity of the ecliptic, in radians. - */ -double approx_ecliptic_obliquity(double jd); - -/** - * Approximates the ecliptic coordinates of the Earth's sun. - * - * @param jd Julian date. - * @return Ecliptic rectangular geocentric coordinates of the Earth's sun, with distance in AU. - */ -double3 approx_sun_ecliptic(double jd); - -/** - * Approximates the ecliptic coordinates of the Earth's moon. - * - * @param jd Julian date. - * @return Ecliptic rectangular geocentric coordinates of the Earth's moon, with distance in Earth radii. - */ -double3 approx_moon_ecliptic(double jd); - -/** - * Approximates the ecliptic rotation of the Earth's moon. - * - * @param jd Julian date. - * @return Rotation matrix representing the moon's rotation in ecliptic space. - */ -double3x3 approx_moon_ecliptic_rotation(double jd); - /** * Iteratively solves Kepler's equation for eccentric anomaly, E. * diff --git a/src/game/astronomy/celestial-time.cpp b/src/game/astronomy/celestial-time.cpp deleted file mode 100644 index c67a23f..0000000 --- a/src/game/astronomy/celestial-time.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2020 Christopher J. Howard - * - * This file is part of Antkeeper source code. - * - * Antkeeper source code is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Antkeeper source code is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Antkeeper source code. If not, see . - */ - -#include "celestial-time.hpp" -#include "math/angles.hpp" -#include - -namespace ast -{ - -double ut_to_jd(int year, int month, int day, int hour, int minute, double second) -{ - if (month < 3) - { - month += 12; - year -= 1; - } - - const signed long Y = year; - const signed long M = month; - const signed long D = day; - const signed long JDN = (1461*(Y+4800+(M-14)/12))/4+(367*(M-2-12*((M-14)/12)))/12-(3*((Y+4900+(M-14)/12)/100))/4+D-32075; - - const double h = static_cast(hour - 12) / 24.0; - const double m = static_cast(minute) / 1440.0; - const double s = second / 86400.0; - - return static_cast(JDN) + h + m + s; -} - -double jd_to_gmst(double jd) -{ - return math::wrap_radians(4.894961212 + 6.300388098 * (jd - 2451545.0)); -} - -double jd_to_lmst(double jd, double longitude) -{ - return gmst_to_lmst(jd_to_gmst(jd), longitude); -} - -double gmst_to_lmst(double gmst, double longitude) -{ - return gmst + longitude; -} - -} // namespace ast diff --git a/src/game/astronomy/celestial-time.hpp b/src/game/astronomy/celestial-time.hpp deleted file mode 100644 index 6f3a179..0000000 --- a/src/game/astronomy/celestial-time.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2020 Christopher J. Howard - * - * This file is part of Antkeeper source code. - * - * Antkeeper source code is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Antkeeper source code is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Antkeeper source code. If not, see . - */ - -#ifndef ANTKEEPER_CELESTIAL_TIME_HPP -#define ANTKEEPER_CELESTIAL_TIME_HPP - -namespace ast -{ - -/** - * Calculates the Julian date from a universal time. - * - * @param year Gregorian year, with 1 BC as 0. - * @param month Gregorian month, on [1, 12]. - * @param day Gregorian day, on [1, 31]. - * @param hour Hour, on [0, 23]. - * @param minute Minute, on [0, 59]. - * @param second Second on [0, 60). - * @return Julian date with fractional day. - */ -double ut_to_jd(int year, int month, int day, int hour, int minute, double second); - -/** - * Calculates the Greenwich mean sidereal time (GMST) from a Julian date. - * - * @param jd Julian date. - * @return GMST, in radians. - */ -double jd_to_gmst(double jd); - -/** - * Calculates local mean sidereal time (LMST) from a Julian date. - * - * @param jd Julian date. - * @param longitude Longitude of the observer, in radians. - */ -double jd_to_lmst(double jd, double longitude); - -/** - * Calculates local mean sidereal time (LMST) from Greenwich mean sidereal time (GMST). - * - * @param gmst Greenwich mean sidereal time, in radians. - * @param longitude Longitude of the observer, in radians. - * @return Local mean sidereal time, in radians. - */ -double gmst_to_lmst(double gmst, double longitude); - -} // namespace ast - -#endif // ANTKEEPER_CELESTIAL_TIME_HPP diff --git a/src/game/bootloader.cpp b/src/game/bootloader.cpp index 725b5e6..00c9f63 100644 --- a/src/game/bootloader.cpp +++ b/src/game/bootloader.cpp @@ -80,6 +80,7 @@ #include "game/systems/painting-system.hpp" #include "game/systems/weather-system.hpp" #include "game/systems/astronomy-system.hpp" +#include "game/systems/solar-system.hpp" #include "game/components/marker-component.hpp" #include "game/entity-commands.hpp" #include "utility/paths.hpp" @@ -880,15 +881,16 @@ void setup_systems(game_context* ctx) // Setup weather system ctx->weather_system = new weather_system(*ctx->ecs_registry); - ctx->weather_system->set_ambient_light(ctx->sun_indirect); - ctx->weather_system->set_sun_light(ctx->sun_direct); - ctx->weather_system->set_moon_light(ctx->moon_light); ctx->weather_system->set_sky_pass(ctx->overworld_sky_pass); ctx->weather_system->set_shadow_map_pass(ctx->overworld_shadow_map_pass); ctx->weather_system->set_material_pass(ctx->overworld_material_pass); // Setup solar system + ctx->solar_system = new solar_system(*ctx->ecs_registry); + + // Setup astronomy system ctx->astronomy_system = new astronomy_system(*ctx->ecs_registry); + ctx->astronomy_system->set_sky_pass(ctx->overworld_sky_pass); // Set time scale float time_scale = 60.0f; @@ -897,6 +899,7 @@ void setup_systems(game_context* ctx) time_scale = ctx->config->get("time_scale"); } ctx->weather_system->set_time_scale(time_scale); + ctx->solar_system->set_time_scale(time_scale); ctx->astronomy_system->set_time_scale(time_scale); // Setup render system @@ -1196,6 +1199,7 @@ void setup_controls(game_context* ctx) [ctx, time_scale]() { ctx->weather_system->set_time_scale(time_scale * 50.0f); + ctx->solar_system->set_time_scale(time_scale * 50.0f); ctx->astronomy_system->set_time_scale(time_scale * 50.0f); } ); @@ -1204,6 +1208,7 @@ void setup_controls(game_context* ctx) [ctx, time_scale]() { ctx->weather_system->set_time_scale(time_scale); + ctx->solar_system->set_time_scale(time_scale); ctx->astronomy_system->set_time_scale(time_scale); } ); @@ -1212,6 +1217,7 @@ void setup_controls(game_context* ctx) [ctx, time_scale]() { ctx->weather_system->set_time_scale(time_scale * -50.0f); + ctx->solar_system->set_time_scale(time_scale * -50.0f); ctx->astronomy_system->set_time_scale(time_scale * -50.0f); } ); @@ -1220,6 +1226,7 @@ void setup_controls(game_context* ctx) [ctx, time_scale]() { ctx->weather_system->set_time_scale(time_scale); + ctx->solar_system->set_time_scale(time_scale); ctx->astronomy_system->set_time_scale(time_scale); } ); @@ -1281,6 +1288,7 @@ void setup_callbacks(game_context* ctx) ctx->tracking_system->update(t, dt); ctx->painting_system->update(t, dt); ctx->weather_system->update(t, dt); + ctx->solar_system->update(t, dt); ctx->astronomy_system->update(t, dt); //(*ctx->focal_point_tween)[1] = ctx->orbit_cam->get_focal_point(); diff --git a/src/game/cartography/relief-map.cpp b/src/game/cartography/relief-map.cpp index 79dca15..9e830ad 100644 --- a/src/game/cartography/relief-map.cpp +++ b/src/game/cartography/relief-map.cpp @@ -74,6 +74,7 @@ mesh* map_elevation(const std::function& function, float sc return edge; }; + // Connect vertices with edges and faces const std::vector& vertices = mesh->get_vertices(); for (std::size_t i = 0; i < rows; ++i) { diff --git a/src/game/components/celestial-body-component.hpp b/src/game/components/celestial-body-component.hpp new file mode 100644 index 0000000..0fc112c --- /dev/null +++ b/src/game/components/celestial-body-component.hpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#ifndef ANTKEEPER_ECS_CELESTIAL_BODY_COMPONENT_HPP +#define ANTKEEPER_ECS_CELESTIAL_BODY_COMPONENT_HPP + +#include "game/astronomy/celestial-mechanics.hpp" +#include "utility/fundamental-types.hpp" +#include "math/quaternion-type.hpp" + +namespace ecs { + +struct celestial_body_component +{ + ast::orbital_elements orbital_elements; + ast::orbital_elements orbital_rate; + ast::orbital_state orbital_state; + + double3 position; + double3 velocity; + double3 acceleration; + double mass; + double radius; + math::quaternion orientation; +}; + +struct blackbody_radiator +{ + double temperature; +}; + +struct diffuse_reflector +{ + double albedo; +}; + +} // namespace ecs + +#endif // ANTKEEPER_ECS_CELESTIAL_BODY_COMPONENT_HPP diff --git a/src/game/components/orbit-component.hpp b/src/game/components/orbit-component.hpp index 6468905..812d848 100644 --- a/src/game/components/orbit-component.hpp +++ b/src/game/components/orbit-component.hpp @@ -26,26 +26,11 @@ namespace ecs { struct orbit_component { - double a; ///< Semi-major axis, a - double d_a; - - double ec; ///< Eccentricity, e - double d_ec; - - double w; ///< Argument of periapsis, w (radians) - double d_w; - - double ma; ///< Mean anomaly, M (radians) - double d_ma; - - double i; ///< Inclination, i (radians) - double d_i; - - double om; ///< Longitude of the ascending node, OMEGA (radians) - double d_om; + ast::orbital_elements elements; + ast::orbital_elements rate; + ast::orbital_state state; }; } // namespace ecs #endif // ANTKEEPER_ECS_ORBIT_COMPONENT_HPP - diff --git a/src/game/game-context.hpp b/src/game/game-context.hpp index 9b8c997..affca5f 100644 --- a/src/game/game-context.hpp +++ b/src/game/game-context.hpp @@ -88,6 +88,7 @@ class tracking_system; class painting_system; class weather_system; class astronomy_system; +class solar_system; struct biome; template class animation; template class material_property; @@ -246,6 +247,7 @@ struct game_context painting_system* painting_system; weather_system* weather_system; astronomy_system* astronomy_system; + solar_system* solar_system; // Game biome* biome; diff --git a/src/game/states/map-state.cpp b/src/game/states/map-state.cpp new file mode 100644 index 0000000..da3af23 --- /dev/null +++ b/src/game/states/map-state.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#include "animation/ease.hpp" +#include "animation/screen-transition.hpp" +#include "animation/timeline.hpp" +#include "application.hpp" +#include "debug/logger.hpp" +#include "game/game-context.hpp" +#include "input/input-listener.hpp" +#include "event/input-events.hpp" +#include "rasterizer/rasterizer.hpp" +#include "game/states/game-states.hpp" +#include "renderer/passes/sky-pass.hpp" +#include "scene/billboard.hpp" +#include "scene/scene.hpp" +#include + +void map_state_enter(game_context* ctx) +{ + logger* logger = ctx->logger; + logger->push_task("Entering map state"); + + // Disable sky pass + ctx->overworld_sky_pass->set_enabled(false); + + // Start fade in + ctx->fade_transition->transition(1.0f, true, ease::in_quad); + + logger->pop_task(EXIT_SUCCESS); +} + +void map_state_exit(game_context* ctx) +{ + logger* logger = ctx->logger; + logger->push_task("Exiting map state"); + + logger->pop_task(EXIT_SUCCESS); +} diff --git a/src/game/states/play-state.cpp b/src/game/states/play-state.cpp index f70302a..b5c3c65 100644 --- a/src/game/states/play-state.cpp +++ b/src/game/states/play-state.cpp @@ -56,12 +56,18 @@ #include "game/systems/render-system.hpp" #include "game/systems/tool-system.hpp" #include "game/systems/weather-system.hpp" +#include "game/systems/solar-system.hpp" #include "game/systems/astronomy-system.hpp" #include "game/biome.hpp" #include "utility/fundamental-types.hpp" #include "utility/gamma.hpp" -#include "game/astronomy/celestial-time.hpp" + +#include "utility/bit-math.hpp" +#include "game/genetics/genetics.hpp" #include +#include +#include + void play_state_enter(game_context* ctx) { @@ -84,14 +90,9 @@ void play_state_enter(game_context* ctx) sky_pass->set_sky_model(ctx->resource_manager->load("sky-dome.mdl")); sky_pass->set_moon_model(ctx->resource_manager->load("moon.mdl")); - ctx->weather_system->set_location(ctx->biome->location[0], ctx->biome->location[1], ctx->biome->location[2]); - ctx->weather_system->set_time(2000, 1, 1, 12, 0, 0.0, 0.0); - ctx->weather_system->set_time(0.0); - ctx->weather_system->set_sky_palette(ctx->biome->sky_palette); - ctx->weather_system->set_sun_palette(ctx->biome->sun_palette); - ctx->weather_system->set_ambient_palette(ctx->biome->ambient_palette); - ctx->weather_system->set_moon_palette(ctx->biome->moon_palette); - ctx->weather_system->set_shadow_palette(ctx->biome->shadow_palette); + ctx->weather_system->set_universal_time(0.0); + + ctx->solar_system->set_universal_time(0.0); ctx->astronomy_system->set_observer_location(double3{4.26352e-5, ctx->biome->location[0], ctx->biome->location[1]}); ctx->astronomy_system->set_universal_time(0.0); @@ -102,23 +103,26 @@ void play_state_enter(game_context* ctx) resource_manager* resource_manager = ctx->resource_manager; entt::registry& ecs_registry = *ctx->ecs_registry; + ctx->sun_direct->set_intensity(1.0f); + ctx->sun_direct->set_color({1, 1, 1}); + // Create sun { ecs::orbit_component sun_orbit; - sun_orbit.a = 1.0; - sun_orbit.ec = 0.016709; - sun_orbit.w = math::radians(282.9404); - sun_orbit.ma = math::radians(356.0470); - sun_orbit.i = 0.0; - sun_orbit.om = 0.0; + sun_orbit.elements.a = 1.0; + sun_orbit.elements.ec = 0.016709; + sun_orbit.elements.w = math::radians(282.9404); + sun_orbit.elements.ma = math::radians(356.0470); + sun_orbit.elements.i = 0.0; + sun_orbit.elements.om = 0.0; - sun_orbit.d_a = 0.0; - sun_orbit.d_ec = -1.151e-9; - sun_orbit.d_w = math::radians(4.70935e-5); - sun_orbit.d_ma = math::radians(0.9856002585); - sun_orbit.d_i = 0.0; - sun_orbit.d_om = 0.0; + sun_orbit.rate.a = 0.0; + sun_orbit.rate.ec = -1.151e-9; + sun_orbit.rate.w = math::radians(4.70935e-5); + sun_orbit.rate.ma = math::radians(0.9856002585); + sun_orbit.rate.i = 0.0; + sun_orbit.rate.om = 0.0; ecs::transform_component sun_transform; sun_transform.local = math::identity_transform; @@ -127,6 +131,8 @@ void play_state_enter(game_context* ctx) auto sun_entity = ecs_registry.create(); ecs_registry.assign(sun_entity, sun_transform); ecs_registry.assign(sun_entity, sun_orbit); + + ctx->astronomy_system->set_sun(sun_entity); } // Create moon @@ -134,19 +140,19 @@ void play_state_enter(game_context* ctx) ecs::orbit_component moon_orbit; - moon_orbit.a = 0.00256955529; - moon_orbit.ec = 0.0554; - moon_orbit.w = math::radians(318.15); - moon_orbit.ma = math::radians(135.27); - moon_orbit.i = math::radians(5.16); - moon_orbit.om = math::radians(125.08); + moon_orbit.elements.a = 0.00256955529; + moon_orbit.elements.ec = 0.0554; + moon_orbit.elements.w = math::radians(318.15); + moon_orbit.elements.ma = math::radians(135.27); + moon_orbit.elements.i = math::radians(5.16); + moon_orbit.elements.om = math::radians(125.08); - moon_orbit.d_a = 0.0; - moon_orbit.d_ec = 0.0; - moon_orbit.d_w = math::radians(0.1643573223); - moon_orbit.d_ma = math::radians(13.176358); - moon_orbit.d_i = 0.0; - moon_orbit.d_om = math::radians(-0.0529538083); + moon_orbit.rate.a = 0.0; + moon_orbit.rate.ec = 0.0; + moon_orbit.rate.w = math::radians(0.1643573223); // Argument of periapsis precession period, P_w + moon_orbit.rate.ma = math::radians(13.176358); // Longitude rate, n + moon_orbit.rate.i = 0.0; + moon_orbit.rate.om = math::radians(-18.6 / 365.2422); // Longitude of the ascending node precession period, P_node ecs::transform_component moon_transform; moon_transform.local = math::identity_transform; @@ -155,6 +161,8 @@ void play_state_enter(game_context* ctx) auto moon_entity = ecs_registry.create(); ecs_registry.assign(moon_entity, moon_transform); ecs_registry.assign(moon_entity, moon_orbit); + + ctx->astronomy_system->set_moon(moon_entity); } // Load entity archetypes @@ -395,6 +403,61 @@ void play_state_enter(game_context* ctx) std::string biome_name = (*ctx->strings)[ctx->biome->name]; logger->log("Entered biome \"" + biome_name + "\""); + + + std::srand(std::time(nullptr)); + //auto rng = [](){ return std::rand(); }; + + std::random_device rd; + std::mt19937 rng(rd()); + + + std::string sequence_a = "CCTTGCCCTTTGGGTCGCCCCCCTAG"; + std::string sequence_b = "ATGTTTCCCGAAGGGTAG"; + std::string sequence_c = "AAATGCCCCCCCCCCCCCCCCCCCCCCCCCCCTAGAAAAAAAAA"; + std::string orf_a; + std::string protein_a; + std::string protein_b; + std::string protein_c; + + + std::cout << "sequence a: " << sequence_a << std::endl; + genetics::sequence::transcribe(sequence_a.begin(), sequence_a.end(), sequence_a.begin()); + std::cout << "sequence a: " << sequence_a << std::endl; + + std::string complement; + genetics::sequence::rna::complement(sequence_a.begin(), sequence_a.end(), std::back_inserter(complement)); + std::cout << "complement: " << complement << std::endl; + + auto orf = genetics::sequence::find_orf(sequence_a.begin(), sequence_a.end(), genetics::standard_code); + if (orf.start != sequence_a.end()) + { + std::copy(orf.start, orf.stop, std::back_inserter(orf_a)); + std::cout << "orf a: " << orf_a << std::endl; + + genetics::sequence::translate(orf.start, orf.stop, std::back_inserter(protein_a), genetics::standard_code); + std::cout << "protein a: " << protein_a << std::endl; + } + + protein_b = "MFFFFP"; + protein_c = "MFFFYP"; + int score; + + std::cout << std::endl; + std::cout << "protein_b: " << protein_b << std::endl; + std::cout << "protein_c: " << protein_c << std::endl; + + score = genetics::protein::score(protein_b.begin(), protein_b.end(), protein_c.begin(), genetics::matrix::blosum62); + std::cout << "score blosum62: " << score << std::endl; + + score = genetics::protein::score(protein_b.begin(), protein_b.end(), protein_c.begin(), genetics::matrix::blosum80); + std::cout << "score blosum80: " << score << std::endl; + + + std::cout << "identity : " << genetics::protein::identity(protein_b.begin(), protein_b.end(), protein_c.begin()) << std::endl; + std::cout << "similarity62: " << genetics::protein::similarity(protein_b.begin(), protein_b.end(), protein_c.begin(), genetics::matrix::blosum62) << std::endl; + std::cout << "similarity80: " << genetics::protein::similarity(protein_b.begin(), protein_b.end(), protein_c.begin(), genetics::matrix::blosum80) << std::endl; + } void play_state_exit(game_context* ctx) diff --git a/src/game/systems/astronomy-system.cpp b/src/game/systems/astronomy-system.cpp index 5d75c2b..7587724 100644 --- a/src/game/systems/astronomy-system.cpp +++ b/src/game/systems/astronomy-system.cpp @@ -19,11 +19,10 @@ #include "game/systems/astronomy-system.hpp" #include "game/astronomy/celestial-coordinates.hpp" -#include "game/astronomy/celestial-mechanics.hpp" -#include "game/astronomy/celestial-time.hpp" -#include "game/astronomy/astronomical-constants.hpp" -#include "game/components/orbit-component.hpp" +#include "game/astronomy/apparent-size.hpp" +#include "game/components/celestial-body-component.hpp" #include "game/components/transform-component.hpp" +#include "renderer/passes/sky-pass.hpp" using namespace ecs; @@ -36,49 +35,51 @@ astronomy_system::astronomy_system(entt::registry& registry): observer_location{0.0, 0.0, 0.0}, lst(0.0), obliquity(0.0), - ke_tolerance(1e-6), - ke_iterations(10) + sky_pass(nullptr), + sun(entt::null), + moon(entt::null) {} void astronomy_system::update(double t, double dt) { - const double dt_days = dt * days_per_timestep; - // Add scaled timestep to current time - set_universal_time(universal_time + dt_days); + set_universal_time(universal_time + dt * days_per_timestep); - // Update horizontal (topocentric) positions of orbiting bodies - registry.view().each( - [&](auto entity, auto& orbit, auto& transform) + // Update horizontal (topocentric) positions of intrasolar celestial bodies + registry.view().each( + [&](auto entity, auto& body, auto& transform) { - ast::orbital_elements orbital_elements; - orbital_elements.a = orbit.a + orbit.d_a * universal_time; - orbital_elements.ec = orbit.ec + orbit.d_ec * universal_time; - orbital_elements.w = orbit.w + orbit.d_w * universal_time; - orbital_elements.ma = math::wrap_radians(orbit.ma + orbit.d_ma * universal_time); - orbital_elements.i = orbit.i + orbit.d_i * universal_time; - orbital_elements.om = math::wrap_radians(orbit.om + orbit.d_om * universal_time); - - // Calculate ecliptic orbital position - double3 ecliptic = ast::orbital_elements_to_ecliptic(orbital_elements, ke_tolerance, ke_iterations); - // Transform orbital position from ecliptic space to horizontal space - double3 horizontal = ecliptic_to_horizontal * ecliptic; + double3 horizontal = ecliptic_to_horizontal * body.orbital_state.r; // Subtract observer's radial distance (planet radius + observer's altitude) horizontal.z -= observer_location[0]; - // Calculate azimuth and elevation + // Convert rectangular horizontal coordinates to spherical double3 spherical = ast::rectangular_to_spherical(horizontal); - double2 az_el = {spherical.z - math::pi, spherical.y}; + spherical.z -= math::pi; + + // Find angular radius + double angular_radius = ast::find_angular_radius(body.radius, spherical.x); // Transform into local right-handed coordinates double3 translation = ast::horizontal_to_right_handed * horizontal; double3x3 rotation = ast::horizontal_to_right_handed * ecliptic_to_horizontal; + // Set local transform of transform component transform.local.translation = math::type_cast(translation); transform.local.rotation = math::type_cast(math::quaternion_cast(rotation)); + transform.local.scale = math::type_cast(double3{body.radius, body.radius, body.radius}); }); + + if (sky_pass) + { + sky_pass->set_horizon_color({0, 0, 0}); + sky_pass->set_zenith_color({1, 1, 1}); + sky_pass->set_time_of_day(static_cast(universal_time * 60.0 * 60.0)); + //sky_pass->set_observer_location(location[0], location[1], location[2]); + sky_pass->set_julian_day(static_cast(universal_time)); + } } void astronomy_system::set_universal_time(double time) @@ -115,6 +116,21 @@ void astronomy_system::set_axial_rotation_at_epoch(double angle) update_axial_rotation(); } +void astronomy_system::set_sky_pass(::sky_pass* pass) +{ + this->sky_pass = pass; +} + +void astronomy_system::set_sun(entt::entity entity) +{ + sun = entity; +} + +void astronomy_system::set_moon(entt::entity entity) +{ + moon = entity; +} + void astronomy_system::update_axial_rotation() { axial_rotation = math::wrap_radians(axial_rotation_at_epoch + universal_time * axial_rotation_speed); diff --git a/src/game/systems/astronomy-system.hpp b/src/game/systems/astronomy-system.hpp index 88b3bf2..5f1f53d 100644 --- a/src/game/systems/astronomy-system.hpp +++ b/src/game/systems/astronomy-system.hpp @@ -23,8 +23,10 @@ #include "entity-system.hpp" #include "utility/fundamental-types.hpp" +class sky_pass; + /** - * + * Calculates apparent properties of celestial bodies relative to an observer (magnitude, angular radius, horizontal coordinates) and modifies their model component and/or light component to render them accordingly. */ class astronomy_system: public entity_system @@ -33,7 +35,7 @@ public: astronomy_system(entt::registry& registry); /** - * Scales then adds the timestep `dt` to the current Julian date, then recalculates the positions of celestial bodies. + * Scales then adds the timestep `dt` to the current time, then recalculates the positions of celestial bodies. * * @param t Time, in seconds. * @param dt Delta time, in seconds. @@ -48,7 +50,7 @@ public: void set_universal_time(double time); /** - * Sets the factor by which the timestep `dt` will be scaled before being added to the current Julian date. + * Sets the factor by which the timestep `dt` will be scaled before being added to the current universal time. * * @param scale Factor by which to scale the timestep. */ @@ -61,6 +63,13 @@ public: */ void set_observer_location(const double3& location); + /** + * Sets the obliquity of the ecliptic, a.k.a. axial tilt. + * + * @param angle Angle between the planet's rotational axis and its orbital axis, in radians. + */ + void set_obliquity(double angle); + /** * Sets the rotational speed of the observer's planet. * @@ -70,12 +79,10 @@ public: void set_axial_rotation_at_epoch(double angle); - /** - * Sets the obliquity of the ecliptic, a.k.a. axial tilt. - * - * @param angle Angle between the planet's rotational axis and its orbital axis, in radians. - */ - void set_obliquity(double angle); + void set_sky_pass(::sky_pass* pass); + + void set_sun(entt::entity entity); + void set_moon(entt::entity entity); private: /// Updates the axial rotation angle @@ -88,16 +95,18 @@ private: void update_ecliptic_to_horizontal(); double universal_time; + double days_per_timestep; double lst; double axial_rotation_at_epoch; double axial_rotation_speed; double axial_rotation; - double days_per_timestep; double3 observer_location; double obliquity; double3x3 ecliptic_to_horizontal; - double ke_tolerance; - std::size_t ke_iterations; + sky_pass* sky_pass; + + entt::entity sun; + entt::entity moon; }; #endif // ANTKEEPER_ASTRONOMY_SYSTEM_HPP diff --git a/src/game/systems/solar-system.cpp b/src/game/systems/solar-system.cpp new file mode 100644 index 0000000..0aef294 --- /dev/null +++ b/src/game/systems/solar-system.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2020 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#include "game/systems/solar-system.hpp" +#include "game/astronomy/celestial-coordinates.hpp" +#include "game/astronomy/celestial-mechanics.hpp" +#include "game/astronomy/astronomical-constants.hpp" +#include "game/components/celestial-body-component.hpp" + +using namespace ecs; + +static constexpr double seconds_per_day = 24.0 * 60.0 * 60.0; + +solar_system::solar_system(entt::registry& registry): + entity_system(registry), + universal_time(0.0), + days_per_timestep(1.0 / seconds_per_day), + ke_tolerance(1e-6), + ke_iterations(10) +{} + +void solar_system::update(double t, double dt) +{ + // Add scaled timestep to current time + set_universal_time(universal_time + dt * days_per_timestep); + + // Update orbital state of intrasolar celestial bodies + registry.view().each( + [&](auto entity, auto& body) + { + ast::orbital_elements elements = body.orbital_elements; + elements.a += body.orbital_rate.a * universal_time; + elements.ec += body.orbital_rate.ec * universal_time; + elements.w += body.orbital_rate.w * universal_time; + elements.ma += body.orbital_rate.ma * universal_time; + elements.i += body.orbital_rate.i * universal_time; + elements.om += body.orbital_rate.om * universal_time; + + // Calculate ecliptic orbital position + body.orbital_state.r = ast::orbital_elements_to_ecliptic(elements, ke_tolerance, ke_iterations); + }); +} + +void solar_system::set_universal_time(double time) +{ + universal_time = time; +} + +void solar_system::set_time_scale(double scale) +{ + days_per_timestep = scale / seconds_per_day; +} diff --git a/src/game/systems/solar-system.hpp b/src/game/systems/solar-system.hpp new file mode 100644 index 0000000..4afb7c9 --- /dev/null +++ b/src/game/systems/solar-system.hpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2020 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#ifndef ANTKEEPER_SOLAR_SYSTEM_HPP +#define ANTKEEPER_SOLAR_SYSTEM_HPP + +#include "entity-system.hpp" +#include "utility/fundamental-types.hpp" + +/** + * Updates positions, velocities, and rotations of intrasolar celestial bodies. + */ +class solar_system: + public entity_system +{ +public: + solar_system(entt::registry& registry); + + /** + * Scales then adds the timestep `dt` to the current time, then recalculates the positions of celestial bodies. + * + * @param t Time, in seconds. + * @param dt Delta time, in seconds. + */ + virtual void update(double t, double dt); + + /** + * Sets the current universal time. + * + * @param time Universal time, in days. + */ + void set_universal_time(double time); + + /** + * Sets the factor by which the timestep `dt` will be scaled before being added to the current universal time. + * + * @param scale Factor by which to scale the timestep. + */ + void set_time_scale(double scale); + +private: + double universal_time; + double days_per_timestep; + double ke_tolerance; + std::size_t ke_iterations; +}; + +#endif // ANTKEEPER_SOLAR_SYSTEM_HPP diff --git a/src/game/systems/terrain-system.cpp b/src/game/systems/terrain-system.cpp index 6582915..831f1cb 100644 --- a/src/game/systems/terrain-system.cpp +++ b/src/game/systems/terrain-system.cpp @@ -21,6 +21,7 @@ #include "game/components/model-component.hpp" #include "game/components/collision-component.hpp" #include "game/components/transform-component.hpp" +#include "game/cartography/relief-map.hpp" #include "renderer/model.hpp" #include "geometry/mesh.hpp" #include "geometry/mesh-functions.hpp" @@ -67,102 +68,12 @@ void terrain_system::set_patch_size(float size) mesh* terrain_system::generate_terrain_mesh(float size, int subdivisions) { - // Allocate terrain mesh - mesh* terrain_mesh = new mesh(); - - // Determine vertex count and placement - int columns = static_cast(std::pow(2, subdivisions)); - int rows = columns; - int vertex_count = (columns + 1) * (rows + 1); - float vertex_increment = size / static_cast(columns); - float radius = size * 0.5f; - - // Generate mesh vertices - float3 position = {0.0f, 0.0f, -radius}; - for (int i = 0; i <= rows; ++i) + auto elevation = [](float u, float v) -> float { - position[0] = -radius; - - for (int j = 0; j <= columns; ++j) - { - terrain_mesh->add_vertex(position); - position[0] += vertex_increment; - - } - - position[2] += vertex_increment; - } - - - // Function to eliminate duplicate edges - std::map, mesh::edge*> edge_map; - auto add_or_find_edge = [&](mesh::vertex* start, mesh::vertex* end) -> mesh::edge* - { - mesh::edge* edge; - if (auto it = edge_map.find({start->index, end->index}); it != edge_map.end()) - { - edge = it->second; - } - else - { - edge = terrain_mesh->add_edge(start, end); - edge_map[{start->index, end->index}] = edge; - edge_map[{end->index, start->index}] = edge->symmetric; - } - - return edge; + return 0.0f; }; - - const std::vector& vertices = terrain_mesh->get_vertices(); - for (int i = 0; i < rows; ++i) - { - for (int j = 0; j < columns; ++j) - { - mesh::vertex* a = vertices[i * (columns + 1) + j]; - mesh::vertex* b = vertices[(i + 1) * (columns + 1) + j]; - mesh::vertex* c = vertices[i * (columns + 1) + j + 1]; - mesh::vertex* d = vertices[(i + 1) * (columns + 1) + j + 1]; - - // +---+---+ - // | \ | / | - // |---+---| - // | / | \ | - // +---+---+ - if ((j % 2) == (i % 2)) - { - mesh::edge* ab = add_or_find_edge(a, b); - mesh::edge* bd = add_or_find_edge(b, d); - mesh::edge* da = add_or_find_edge(d, a); - - mesh::edge* ca = add_or_find_edge(c, a); - mesh::edge* ad = da->symmetric; - mesh::edge* dc = add_or_find_edge(d, c); - - // a---c - // | \ | - // b---d - terrain_mesh->add_face({ab, bd, da}); - terrain_mesh->add_face({ca, ad, dc}); - } - else - { - mesh::edge* ab = add_or_find_edge(a, b); - mesh::edge* bc = add_or_find_edge(b, c); - mesh::edge* ca = add_or_find_edge(c, a); - mesh::edge* cb = bc->symmetric; - mesh::edge* bd = add_or_find_edge(b, d); - mesh::edge* dc = add_or_find_edge(d, c); - - // a---c - // | / | - // b---d - terrain_mesh->add_face({ab, bc, ca}); - terrain_mesh->add_face({cb, bd, dc}); - } - } - } - - return terrain_mesh; + + return cart::map_elevation(elevation, size, subdivisions); } model* terrain_system::generate_terrain_model(mesh* terrain_mesh) @@ -385,4 +296,3 @@ void terrain_system::on_terrain_destroy(entt::registry& registry, entt::entity e } */ } - diff --git a/src/game/systems/weather-system.cpp b/src/game/systems/weather-system.cpp index 69838fd..6386cd3 100644 --- a/src/game/systems/weather-system.cpp +++ b/src/game/systems/weather-system.cpp @@ -27,284 +27,47 @@ #include "resources/image.hpp" #include "game/astronomy/celestial-coordinates.hpp" #include "game/astronomy/celestial-mechanics.hpp" -#include "game/astronomy/celestial-time.hpp" #include -static constexpr double hours_per_day = 24.0; -static constexpr double minutes_per_day = hours_per_day * 60.0; -static constexpr double seconds_per_day = minutes_per_day * 60.0; +static constexpr double seconds_per_day = 24.0 * 60.0 * 60.0; weather_system::weather_system(entt::registry& registry): entity_system(registry), - ambient_light(nullptr), - sun_light(nullptr), - moon_light(nullptr), - shadow_light(nullptr), sky_pass(nullptr), shadow_map_pass(nullptr), material_pass(nullptr), - time_scale(1.0f), - sun_direction{0.0f, -1.0f, 0.0f}, - location{0.0f, 0.0f, 0.0f}, - jd(0.0) + universal_time(0.0), + days_per_timestep(1.0 / seconds_per_day) {} void weather_system::update(double t, double dt) { - jd += (dt * time_scale) / seconds_per_day; - - const float latitude = location[0]; - const float longitude = location[1]; - - // Calculate local time - double time_correction = longitude / (math::two_pi / 24.0); - double local_jd = jd + time_correction / 24.0 - 0.5; - double local_time = (local_jd - std::floor(local_jd)) * 24.0; - - double lmst = ast::jd_to_lmst(jd, longitude); - double ecl = ast::approx_ecliptic_obliquity(jd); - double3x3 ecliptic_to_horizontal = ast::ecliptic_to_horizontal(ecl, latitude, lmst); - - - double3 sun_ecliptic = ast::approx_sun_ecliptic(jd); - double3 sun_horizontal = ecliptic_to_horizontal * sun_ecliptic; - sun_horizontal.z -= 4.25875e-5; // Subtract one earth radius (in AU), for positon of observer - double3 sun_spherical = ast::rectangular_to_spherical(sun_horizontal); - double3 sun_positiond = ast::horizontal_to_right_handed * sun_horizontal; - float2 sun_az_el = {static_cast(sun_spherical.z) - math::pi, static_cast(sun_spherical.y)}; - float3 sun_position = math::normalize(float3{static_cast(sun_positiond.x), static_cast(sun_positiond.y), static_cast(sun_positiond.z)}); - - - double3 moon_ecliptic = ast::approx_moon_ecliptic(jd); - double3 moon_horizontal = ecliptic_to_horizontal * moon_ecliptic; - moon_horizontal.z -= 1.0; // Subtract one earth radius, for position of observer - - double3 moon_spherical = ast::rectangular_to_spherical(moon_horizontal); - double3 moon_positiond = ast::horizontal_to_right_handed * moon_horizontal; - float2 moon_az_el = {static_cast(moon_spherical.z) - math::pi, static_cast(moon_spherical.y)}; - float3 moon_position = math::normalize(math::type_cast(moon_positiond)); - - double3x3 moon_rotation_matrix = ast::horizontal_to_right_handed * ecliptic_to_horizontal; - math::quaternion moon_rotationd = math::normalize(math::quaternion_cast(moon_rotation_matrix) * math::angle_axis(math::half_pi, double3{0, 1, 0}) * math::angle_axis(-math::half_pi, double3{0, 0, -1})); - math::quaternion moon_rotation = - { - static_cast(moon_rotationd.w), - static_cast(moon_rotationd.x), - static_cast(moon_rotationd.y), - static_cast(moon_rotationd.z) - }; - - if (sun_light) - { - math::quaternion sun_azimuth_rotation = math::angle_axis(sun_az_el[0], float3{0, 1, 0}); - math::quaternion sun_elevation_rotation = math::angle_axis(sun_az_el[1], float3{-1, 0, 0}); - math::quaternion sun_az_el_rotation = math::normalize(sun_azimuth_rotation * sun_elevation_rotation); - sun_light->set_rotation(sun_az_el_rotation); - } - - if (moon_light) - { - math::quaternion moon_azimuth_rotation = math::angle_axis(moon_az_el[0], float3{0, 1, 0}); - math::quaternion moon_elevation_rotation = math::angle_axis(moon_az_el[1], float3{-1, 0, 0}); - math::quaternion moon_az_el_rotation = math::normalize(moon_azimuth_rotation * moon_elevation_rotation); - moon_light->set_rotation(moon_az_el_rotation); - } - - float sun_gradient_position = static_cast(std::max(0.0, ((sun_az_el[1] + math::half_pi) / math::pi))); - float moon_gradient_position = static_cast(std::max(0.0, ((moon_az_el[1] + math::half_pi) / math::pi))); - float sky_gradient_position = sun_gradient_position; - float ambient_gradient_position = sun_gradient_position; - - if (sky_pass) - { - if (sun_light) - { - float3 sun_color = interpolate_gradient(sun_colors, sun_gradient_position); - sun_light->set_color(sun_color); - sun_light->set_intensity(1.0f); - } - - if (moon_light) - { - float3 moon_color = interpolate_gradient(moon_colors, moon_gradient_position); - moon_light->set_color(moon_color); - moon_light->set_intensity(1.0f); - } - - if (ambient_light) - { - float3 ambient_color = interpolate_gradient(ambient_colors, ambient_gradient_position); - ambient_light->set_color(ambient_color); - ambient_light->set_intensity(0.5f); - } - - float3 horizon_color = interpolate_gradient(horizon_colors, sun_gradient_position); - float3 zenith_color = interpolate_gradient(zenith_colors, sun_gradient_position); - sky_pass->set_horizon_color(horizon_color); - sky_pass->set_zenith_color(zenith_color); - sky_pass->set_time_of_day(static_cast(local_time * 60.0 * 60.0)); - sky_pass->set_observer_location(location[0], location[1], location[2]); - sky_pass->set_sun_coordinates(sun_position, sun_az_el); - sky_pass->set_moon_coordinates(moon_position, moon_az_el); - sky_pass->set_julian_day(static_cast(jd)); - sky_pass->set_moon_rotation(moon_rotation); - } - - shadow_light = sun_light; - if (shadow_map_pass) - { - if (sun_az_el[1] < 0.0f) - { - shadow_map_pass->set_light(moon_light); - } - else - { - shadow_map_pass->set_light(sun_light); - } - } - - if (material_pass) - { - float shadow_strength = interpolate_gradient(shadow_strengths, sun_gradient_position).x; - material_pass->set_shadow_strength(shadow_strength); - } -} - -void weather_system::set_location(float latitude, float longitude, float altitude) -{ - location = {latitude, longitude, altitude}; -} - -void weather_system::set_ambient_light(::ambient_light* light) -{ - ambient_light = light; -} - -void weather_system::set_sun_light(directional_light* light) -{ - sun_light = light; -} - -void weather_system::set_moon_light(directional_light* light) -{ - moon_light = light; + // Add scaled timestep to current time + set_universal_time(universal_time + dt * days_per_timestep); } void weather_system::set_sky_pass(::sky_pass* pass) { sky_pass = pass; - - if (sky_pass) - { - sky_pass->set_moon_angular_radius(math::radians(1.0f)); - sky_pass->set_sun_angular_radius(math::radians(1.1f)); - } } void weather_system::set_shadow_map_pass(::shadow_map_pass* pass) { shadow_map_pass = pass; - - if (shadow_map_pass) - { - shadow_map_pass->set_light(shadow_light); - } } void weather_system::set_material_pass(::material_pass* pass) { material_pass = pass; + material_pass->set_shadow_strength(0.5f); } -void weather_system::set_time(int year, int month, int day, int hour, int minute, double second, double tc) -{ - jd = ast::ut_to_jd(year, month, day, hour, minute, second) - tc / 24.0; -} - -void weather_system::set_time(double time) -{ - jd = time + 2451545.0; -} - -void weather_system::set_time_scale(float scale) -{ - time_scale = scale; -} - -void weather_system::set_sky_palette(const ::image* image) -{ - load_palette(&horizon_colors, image, 0); - load_palette(&zenith_colors, image, 1); -} - -void weather_system::set_sun_palette(const ::image* image) -{ - load_palette(&sun_colors, image, 0); -} - -void weather_system::set_moon_palette(const ::image* image) -{ - load_palette(&moon_colors, image, 0); -} - -void weather_system::set_ambient_palette(const ::image* image) -{ - load_palette(&ambient_colors, image, 0); -} - -void weather_system::set_shadow_palette(const ::image* image) -{ - load_palette(&shadow_strengths, image, 0); -} - -void weather_system::load_palette(std::vector* palette, const ::image* image, unsigned int row) +void weather_system::set_universal_time(double time) { - unsigned int w = image->get_width(); - unsigned int h = image->get_height(); - unsigned int c = image->get_channels(); - unsigned int y = std::min(row, h - 1); - - palette->clear(); - - if (image->is_hdr()) - { - const float* pixels = static_cast(image->get_pixels()); - - for (unsigned int x = 0; x < w; ++x) - { - unsigned int i = y * w * c + x * c; - - float r = pixels[i]; - float g = pixels[i + 1]; - float b = pixels[i + 2]; - - palette->push_back(float3{r, g, b}); - } - } - else - { - const unsigned char* pixels = static_cast(image->get_pixels()); - - for (unsigned int x = 0; x < w; ++x) - { - unsigned int i = y * w * c + x * c; - - float r = srgb_to_linear(static_cast(pixels[i]) / 255.0f); - float g = srgb_to_linear(static_cast(pixels[i + 1]) / 255.0f); - float b = srgb_to_linear(static_cast(pixels[i + 2]) / 255.0f); - - palette->push_back(float3{r, g, b}); - } - } + universal_time = time; } -float3 weather_system::interpolate_gradient(const std::vector& gradient, float position) +void weather_system::set_time_scale(double scale) { - if (gradient.empty()) - return float3{0.0f, 0.0f, 0.0f}; - - position *= static_cast(gradient.size() - 1); - int index0 = static_cast(position) % gradient.size(); - int index1 = (index0 + 1) % gradient.size(); - return math::lerp(gradient[index0], gradient[index1], position - std::floor(position)); + days_per_timestep = scale / seconds_per_day; } diff --git a/src/game/systems/weather-system.hpp b/src/game/systems/weather-system.hpp index c9bffaf..b5dc06a 100644 --- a/src/game/systems/weather-system.hpp +++ b/src/game/systems/weather-system.hpp @@ -45,45 +45,33 @@ public: */ void set_location(float latitude, float longitude, float altitude); - void set_ambient_light(ambient_light* light); - void set_sun_light(directional_light* light); - void set_moon_light(directional_light* light); void set_sky_pass(::sky_pass* pass); void set_shadow_map_pass(::shadow_map_pass* pass); void set_material_pass(::material_pass* pass); - /// @param tc Timezone correction, in hours - void set_time(int year, int month, int day, int hour, int minute, double second, double tc); - void set_time(double time); - void set_time_scale(float scale); + /** + * Sets the current universal time. + * + * @param time Universal time, in days. + */ + void set_universal_time(double time); - void set_sky_palette(const ::image* image); - void set_sun_palette(const ::image* image); - void set_moon_palette(const ::image* image); - void set_ambient_palette(const ::image* image); - void set_shadow_palette(const ::image* image); + /** + * Sets the factor by which the timestep `dt` will be scaled before being added to the current universal time. + * + * @param scale Factor by which to scale the timestep. + */ + void set_time_scale(double scale); private: static void load_palette(std::vector* palette, const ::image* image, unsigned int row); static float3 interpolate_gradient(const std::vector& gradient, float position); - double jd; - float3 location; - float time_scale; - float3 sun_direction; - ambient_light* ambient_light; - directional_light* sun_light; - directional_light* moon_light; - directional_light* shadow_light; + double universal_time; + double days_per_timestep; sky_pass* sky_pass; shadow_map_pass* shadow_map_pass; material_pass* material_pass; - std::vector sun_colors; - std::vector moon_colors; - std::vector ambient_colors; - std::vector shadow_strengths; - std::vector horizon_colors; - std::vector zenith_colors; }; #endif // ANTKEEPER_WEATHER_SYSTEM_HPP