From cc934945de7772fad60de7f7720b3075f02fd527 Mon Sep 17 00:00:00 2001 From: cinnaboot Date: Thu, 19 May 2022 17:00:35 -0400 Subject: [PATCH] impletment multiple orbits --- src/main.cpp | 117 +++++++++++++++++++++++++++++++++---------- src/orbits.cpp | 27 +++++----- src/orbits.h | 5 +- tests/orbit_test.cpp | 12 +++-- 4 files changed, 113 insertions(+), 48 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index befb232..905c2ab 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,7 +8,6 @@ * - make an 'overlay' graphic for things like apoapsis, perisapsis, f1, f2, * flight path * - impulsive orbital maneuvers - * - test multiple orbits * - Hohmman transfer orbits * - patched conic method for transferring between 2 grav bodies */ @@ -32,6 +31,17 @@ const vec4 g_light_direction = vec4(-2, 1, 3, 1); const vec4 g_light_color = vec4(0.5, 0.5, 0.5, 1); const uvec4 g_light_intensities = uvec4(1, 0, 0, 0); + +struct GameOrbit +{ + TwoBodySystem system; + + Entity* grav_body; + Entity* ellipse_entity; + Entity* satellite_entity; + bool in_use; +}; + struct GameState { bool running; @@ -41,10 +51,41 @@ struct GameState u64 sim_time_ms; float sim_speed; - TwoBodySystem system; // FIXME: we're going to need more than 1 system... - Entity* satellite_entity; + GameOrbit* orbits; + u32 num_orbits; + u32 max_orbits; }; +GameOrbit* +getFreeOrbit(GameState* gs) +{ + GameOrbit* orbit = nullptr; + + // NOTE: first check if we have a freed orbit to use + for (u32 i = 0; i < gs->num_orbits; i++) { + if (!gs->orbits[i].in_use) + orbit = &gs->orbits[i]; + } + + // NOTE: if we can't re-use a freed orbit, initialize a new one + if (!orbit) { + assert(gs->num_orbits < gs->max_orbits); + orbit = &gs->orbits[gs->num_orbits++]; + } + + orbit->in_use = true; + return orbit; +} + +void +disableGameOrbit(GameOrbit* orbit) +{ + orbit->in_use = false; + orbit->system = {0}; + orbit->grav_body = nullptr; + orbit->ellipse_entity = nullptr; + orbit->satellite_entity = nullptr; +} void initCamera(RenderState* rs, vec3 cam_pos, vec3 cam_focus, vec3 cam_up) @@ -72,6 +113,7 @@ initLights(RenderState* rs) updateGLBuffer(lights_ubo, lb->buffer); } +// FIXME: could pass EllipseParameters and Ellipse3D instead of TwoBodySystem Entity* initEllipseEntity(RenderState* rs, TwoBodySystem* system, @@ -157,37 +199,47 @@ loadScene(GameState* gs, RenderState* rs) { initCamera(rs, vec3(0, -75 / SCALING, 0), vec3(0, 0, 0), vec3(0,0,1)); initLights(rs); - - double a = 26564.5; // NOTE: semi-major axis in km - double e = 0.7411; // NOTE: eccentricity - double mu = 398601.68; // NOTE: gravitational parameter - double r = 6378; // NOTE: body radius in km - gs->system = systemInit(gravBodyInit(mu, r), orbitInit(a, e)); gs->running = true; + double a = 26564.5; // semi-major axis in km + double e = 0.7411; // eccentricity + double mu = 398601.68; // gravitational parameter + double r = 6378; // body radius in km + + GameOrbit* orbit_1 = getFreeOrbit(gs); + systemInit(orbit_1->system, gravBodyInit(mu, r), orbitInit(a, e)); + // TODO: streamline the boilerplate in init_X_Entity functions ShaderProgram* shader = getShaderByName("colored_vertices", rs->gl_ctx); initRenderGroup( getFreeRenderGroup(rs), rs->rg_arena, shader, 256, "manual mesh group"); - //Entity* ellipse_entity = initEllipseEntity(rs, g_sys.ep, 256); - Entity* ellipse_entity = initEllipseEntity(rs, &gs->system, 256); - setEntityPosition(ellipse_entity, vec3(0, 0, 0)); - rotateEntity(ellipse_entity, vec3(1, 0, 0), (float) M_PI / 2); + orbit_1->ellipse_entity = initEllipseEntity(rs, &orbit_1->system, 256); + setEntityPosition(orbit_1->ellipse_entity, vec3(0, 0, 0)); + rotateEntity(orbit_1->ellipse_entity, vec3(1, 0, 0), (float) M_PI / 2); initPlanetEntity(rs, r); - gs->satellite_entity = initSatelliteEntity(rs); - scaleEntity(gs->satellite_entity, 1 / SCALING); - rotateEntity(gs->satellite_entity, vec3(1, 0, 0), (float) M_PI / 2); - setEntityPosition(gs->satellite_entity, gs->system.e3d.vertices[0]); + orbit_1->satellite_entity = initSatelliteEntity(rs); + scaleEntity(orbit_1->satellite_entity, 1 / SCALING); + rotateEntity(orbit_1->satellite_entity, vec3(1, 0, 0), (float) M_PI / 2); + setEntityPosition(orbit_1->satellite_entity, + orbit_1->system.e3d.vertices[0]); + + // NOTE: testing multiple orbits + double a_2 = r + 10000; // km + double e_2 = 0; + GameOrbit* orbit_2 = getFreeOrbit(gs); + systemInit(orbit_2->system, gravBodyInit(mu, r), orbitInit(a_2, e_2)); + orbit_2->ellipse_entity = initEllipseEntity(rs, &orbit_2->system, 256); + setEntityPosition(orbit_2->ellipse_entity, vec3(0, 0, 0)); + rotateEntity(orbit_2->ellipse_entity, vec3(1, 0, 0), (float) M_PI / 2); } void -updateSatelliteModel(const TwoBodySystem& sys, - Satellite& sat, - double time_step) +updateSatelliteModel(TwoBodySystem& sys, double time_step) { + Satellite& sat = sys.sat; sat.theta = orbitGetPropagatedTrueAnomaly(sys, sat.theta, time_step); sat.gamma = orbitGetFlightPathAngle(sys.ep.e, sat.theta); sat.r = orbitGetRadialDistance(sys.ep.e, sys.ep.p, sat.theta); @@ -250,10 +302,16 @@ preFrameCallback(RenderState* rs, void* user_data = nullptr) u32 diff_ms = gs->sim_time_ms - last_game_tick; double time_step = double(diff_ms) / 1000; - updateSatelliteModel(gs->system, gs->system.sat, time_step); - gs->system.ep = ellipseInitAE(gs->system.ep.a, gs->system.ep.e); - updateSatelliteEntity(gs->satellite_entity, gs->system.sat); - //updateOrbit(gs->system, ellipse_entity); + for (u32 i = 0; i < gs->num_orbits; i++) { + GameOrbit& orbit = gs->orbits[i]; + + if (orbit.in_use && orbit.satellite_entity) { + updateSatelliteModel(orbit.system, time_step); + updateSatelliteEntity(orbit.satellite_entity, orbit.system.sat); + // TODO: update EllipseEntity per frame + //updateOrbit(gs->system, ellipse_entity); + } + } } } @@ -262,14 +320,18 @@ postFrameCallback(RenderState* rs, void* user_data = nullptr) { assert(user_data != nullptr); GameState* gs = (GameState*) user_data; + GameOrbit& orbit = gs->orbits[0]; + assert(orbit.in_use); gooDraw(rs->handles.window, - gs->system, + orbit.system, gs->running, gs->sim_time_ms, gs->sim_speed); } #define DEFAULT_SIM_SPEED 2000 +#define GAME_ARENA_SIZE 16 * 1024 * 1024 // 16MB +#define DEFAULT_MAX_ORBITS 10000 int main() { @@ -288,8 +350,11 @@ main() } GameState gs = {0}; - gs.arena = arenaInit(16); + gs.arena = arenaInit(GAME_ARENA_SIZE); gs.sim_speed = DEFAULT_SIM_SPEED; + gs.max_orbits = DEFAULT_MAX_ORBITS; + gs.orbits = ARENA_ALLOC(gs.arena, GameOrbit, DEFAULT_MAX_ORBITS); + loadScene(&gs, rs); doRenderLoop(rs, 60, preFrameCallback, postFrameCallback, &gs); gooFree(); diff --git a/src/orbits.cpp b/src/orbits.cpp index abb7426..d68f0f4 100644 --- a/src/orbits.cpp +++ b/src/orbits.cpp @@ -5,21 +5,18 @@ const static uint ELLIPSE_VERT_COUNT = 256; -TwoBodySystem -systemInit(GravBody gb, OrbitalElements el) -{ - TwoBodySystem s = {0}; - s.body = gb; - s.elements = el; - s.ep = ellipseInitAE(el.a, el.e); - s.e3d = ellipseInit3D(s.ep, ELLIPSE_VERT_COUNT); - s.epsilon = orbitGetSpecificEnergy(s.ep.a, gb.mu); - s.h = orbitGetAngularMomentum(s.ep.p, gb.mu); - s.orbital_period = orbitGetPeriod(s.ep.a, gb.mu); - s.r_apoapsis = s.ep.a - s.ep.c; - s.r_periapsis = 2 * s.ep.a - s.r_apoapsis; - - return s; +void +systemInit(TwoBodySystem& system, GravBody gb, OrbitalElements el) +{ + system.body = gb; + system.elements = el; + system.ep = ellipseInitAE(el.a, el.e); + system.e3d = ellipseInit3D(system.ep, ELLIPSE_VERT_COUNT); + system.epsilon = orbitGetSpecificEnergy(system.ep.a, gb.mu); + system.h = orbitGetAngularMomentum(system.ep.p, gb.mu); + system.orbital_period = orbitGetPeriod(system.ep.a, gb.mu); + system.r_apoapsis = system.ep.a - system.ep.c; + system.r_periapsis = 2 * system.ep.a - system.r_apoapsis; } GravBody diff --git a/src/orbits.h b/src/orbits.h index 0c145cc..5b4c520 100644 --- a/src/orbits.h +++ b/src/orbits.h @@ -69,9 +69,8 @@ struct TwoBodySystem double orbital_period; // in seconds }; - -TwoBodySystem -systemInit(GravBody gb, OrbitalElements el); +void +systemInit(TwoBodySystem& system, GravBody gb, OrbitalElements el); GravBody gravBodyInit(double mu, double r); diff --git a/tests/orbit_test.cpp b/tests/orbit_test.cpp index 7f16133..01bdc69 100644 --- a/tests/orbit_test.cpp +++ b/tests/orbit_test.cpp @@ -50,7 +50,8 @@ TEST_CASE("orbit propagation, example 4.6", "[orbits]") double r = EARTH_RADIUS; double initial_anom = 260 * M_PI / 180; // NOTE: radians double time_step = 60 * 50; // NOTE: seconds - TwoBodySystem sys = systemInit(gravBodyInit(mu, r), orbitInit(a, e)); + TwoBodySystem sys = {0}; + systemInit(sys, gravBodyInit(mu, r), orbitInit(a, e)); double E1 = getEccAnomFromTrueAnom(sys.ep.e, initial_anom); REQUIRE_THAT(E1, WithinAbs(-0.8615, 1e-4)); @@ -71,7 +72,8 @@ TEST_CASE("orbit propagation, example 4.6", "[orbits]") double ecc_anom = getPropagatedEccAnomaly(sys, initial_anom, time_step); REQUIRE_THAT(ecc_anom, WithinAbs(0.481518, 1e-5)); - double true_anom = getPropagatedTrueAnomaly(sys, initial_anom, time_step); + double true_anom = + orbitGetPropagatedTrueAnomaly(sys, initial_anom, time_step); REQUIRE_THAT(true_anom, WithinAbs(1.1339, 1e-4)); double r2 = orbitGetRadialDistance(sys.ep.e, sys.ep.p, true_anom); @@ -97,7 +99,8 @@ TEST_CASE("time of flight example 4.1a", "[orbits]") double e = MOLNIYA_ECCENTRICITY; double mu = EARTH_GRAVITATIONAL_PARAMETER; double r = EARTH_RADIUS; - TwoBodySystem sys = systemInit(gravBodyInit(mu, r), orbitInit(a, e)); + TwoBodySystem sys = {0}; + systemInit(sys, gravBodyInit(mu, r), orbitInit(a, e)); // NOTE: get ToF from periapsis to true anomaly at 154.85 degrees double theta_0 = 0.0; @@ -122,7 +125,8 @@ TEST_CASE("time of flight example 4.2", "[orbits]") double e = MOLNIYA_ECCENTRICITY; double mu = EARTH_GRAVITATIONAL_PARAMETER; double r = EARTH_RADIUS; - TwoBodySystem sys = systemInit(gravBodyInit(mu, r), orbitInit(a, e)); + TwoBodySystem sys = {0}; + systemInit(sys, gravBodyInit(mu, r), orbitInit(a, e)); // NOTE: get ToF from true anom 230 degrees to true anom at 120 degrees double theta_1 = 230 * M_PI / 180;