You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

219 lines
5.8 KiB

#include <cassert>
#include <cmath>
#include <SDL2/SDL.h>
#include <glm/glm.hpp>
#include "dumbLog.h"
#include "input.h"
#include "mesh.h"
#include "renderer.h"
#include "util.h"
#include "gooey.h"
#include "orbits.h"
const double SCALING = 0.001;
static orbital_elements g_orbit = {};
static ellipse_3d g_ellipse3d;
static uint g_time_step = 100;
simple_mesh*
constructEllipseMesh(ellipse_3d& e3d, glm::vec3 vertex_color)
{
simple_mesh* sm = meInitMesh(e3d.vert_count);
for (uint i = 0; i < e3d.vert_count; i++) {
sm->vertices[i] = e3d.vertices[i];
sm->vert_colors[i] = vertex_color;
}
return sm;
}
simple_mesh*
constructCircleMesh(float r, uint vert_count, glm::vec3 vertex_color)
{
simple_mesh* sm = meInitMesh(vert_count);
float angle = (float) M_PI * 2 / vert_count;
r = r / SCALING;
for (uint i = 0; i < vert_count; i++) {
sm->vertices[i] = glm::vec3(cos(i * angle) * r, sin(i * angle) * r, 0);
sm->vert_colors[i] = vertex_color;
}
return sm;
}
simple_mesh*
createSatelliteMesh()
{
simple_mesh* sm = meInitMesh(3);
glm::vec3 s_color(255, 0, 0);
sm->vertices[0] = glm::vec3(0, 1 / SCALING, 0);
sm->vert_colors[0] = s_color;
sm->vertices[1] = glm::vec3(-1 / SCALING, -1 / SCALING, 0);
sm->vert_colors[1] = s_color;
sm->vertices[2] = glm::vec3(1 / SCALING, -1 / SCALING, 0);
sm->vert_colors[2] = s_color;
return sm;
}
void
updateSatellitePosition(entity& satellite)
{ const static glm::mat4 xform =
glm::rotate(glm::mat4(1.0), (float) M_PI_2, glm::vec3(1, 0, 0));
// TODO: decouple framerate from time_step
g_orbit.nu = getPropagatedTrueAnomaly(g_orbit, g_orbit.nu, g_time_step);
g_orbit.gamma = orbitGetFlightPathAngle(g_orbit.ep.e, g_orbit.nu);
g_orbit.r = getRadialDistance(g_orbit.ep.e, g_orbit.ep.p, g_orbit.nu);
g_orbit.v = orbitGetVelocity(g_orbit.epsilon, g_orbit.mu, g_orbit.r);
glm::vec2 coords = polarToRect(g_orbit.nu, g_orbit.r);
glm::vec3 v = g_orbit.pos = glm::vec3(coords, 0);
entSetWorldPosition(satellite, xform * glm::vec4(v.x, v.y, v.z, 1));
}
// NOTE: use ellipseValidate(orbit.ep) before calling to avoid failing
// assertions
void
updateOrbit(orbital_elements& orbit, ellipse_3d& e3d, entity& ellipse_entity)
{
orbit.ep = ellipseInitAE(orbit.ep.a, orbit.ep.e);
ellipse3DUpdate(orbit.ep, e3d);
for (uint i = 0; i < e3d.vert_count; i++)
ellipse_entity.mesh->vertices[i] = e3d.vertices[i];
entUpdateSimpleMesh(ellipse_entity, ellipse_entity.mesh, GL_LINE_LOOP);
}
void
preFrameCallback(render_state* rs)
{
// handle input
static input_state is = {};
SDL_Event e;
bool gooey_wants = false;
while (SDL_PollEvent(&e)) {
gooey_wants = gooProcessEvent(e);
if (!gooey_wants) inputProcessEvent(&is, e);
}
if (is.window_closed || is.escape)
rs->running = false;
if (g_time_step > 0)
updateSatellitePosition(rs->render_groups[0].entities[2]);
}
void
postFrameCallback(render_state* rs)
{
static orbital_elements c_orb = {};
c_orb = g_orbit;
gooDraw(rs->handles->window, c_orb, g_time_step);
bool update_if_paused = false;
if (c_orb.nu != g_orbit.nu &&
((c_orb.nu >= 0 && c_orb.nu <= M_PI) ||
(c_orb.nu < 0 && c_orb.nu >= -1 * M_PI)))
{
g_orbit.nu = c_orb.nu;
update_if_paused = true;
}
// TODO: will need more validation from GUI as added
if (!ellipsesEqual(c_orb.ep, g_orbit.ep)) {
// NOTE: handle the case where semimajor axis lowered with low
// eccentricity would fail validation
if (c_orb.ep.a < g_orbit.ep.a
&& c_orb.ep.a > 0
&& c_orb.ep.e == g_orbit.ep.e)
{
c_orb.ep.b = c_orb.ep.a * sqrt(1 - pow(c_orb.ep.e, 2.0));
}
if (ellipseValidate(c_orb.ep)) {
c_orb.ep = ellipseInitAE(c_orb.ep.a, c_orb.ep.e);
g_orbit.ep = c_orb.ep;
entity& ellipse_entity = rs->render_groups[0].entities[0];
updateOrbit(g_orbit, g_ellipse3d, ellipse_entity);
// TODO: would be nice to have an interface for
// updating/constructing an orbit
g_orbit.epsilon = orbitGetSpecificEnergy(g_orbit.ep.a, g_orbit.mu);
g_orbit.h = orbitGetAngularMomentum(g_orbit.ep.p, g_orbit.mu);
update_if_paused = true;
}
}
if (g_time_step == 0 && update_if_paused)
updateSatellitePosition(rs->render_groups[0].entities[2]);
}
int
main()
{
render_state* rs = renInit("orbital shipping",
glm::vec2(1280, 800),
SDL_INIT_TIMER);
if (rs == nullptr) {
LOG(Error) << "Error Initialzing renderer\n";
return 1;
}
if (!gooInit(rs->handles->window, rs->handles->glContext)) {
LOG(Error) << "Error Initialzing gooey\n";
return 1;
}
glm::vec2 dims = renGetWindowDims(rs);
cameraInitPerspective(
rs->cam,
glm::vec3(0, -75 / SCALING, 0),
glm::vec3(0, 0, 0),
glm::vec3(0,0,1),
dims.x / dims.y
);
// NOTE: semi-major axis in km, eccentricity, gravitational parameter
g_orbit = orbitInit(26564.5, 0.7411, 398601.68);
ellipse_parameters ep = ellipseInitAB(g_orbit.ep.a, g_orbit.ep.b);
// TODO: (renderer) this needs to be more convenient
shader_wrapper sw = { SIMPLE_SHADER, nullptr, rs->simple_shader };
rs->render_groups = renAllocateGroup(3, sw);
rs->render_group_count = 1;
entity& ellipse_entity = rs->render_groups[0].entities[0];
g_ellipse3d = ellipseInit3D(ep, 256);
simple_mesh* sm = constructEllipseMesh(g_ellipse3d, glm::vec3(255, 0, 255));
entInitMesh(ellipse_entity, sm, GL_LINE_LOOP);
entRotate(ellipse_entity, (float) M_PI_2, glm::vec3(1, 0, 0));
entity& planet_entity = rs->render_groups[0].entities[1];
sm = constructCircleMesh(3, 24, glm::vec3(255, 255, 0));
entInitMesh(planet_entity, sm, GL_LINE_LOOP);
entRotate(planet_entity, (float) M_PI_2, glm::vec3(1, 0, 0));
entity& satellite_entity = rs->render_groups[0].entities[2];
sm = createSatelliteMesh();
entInitMesh(satellite_entity, sm, GL_TRIANGLES);
entRotate(satellite_entity, (float) M_PI_2, glm::vec3(1, 0, 0));
entSetWorldPosition(satellite_entity, g_ellipse3d.vertices[0]);
renDoRenderLoop(rs, 60 , preFrameCallback, postFrameCallback);
gooFree();
renShutdown(rs);
return 0;
}