#include #include #include #include using namespace ImGui; #include "gooey.h" #include "orbits.h" const static int G_WIDTH = 400; const static ImVec2 V_SPACER(0, 10); const int H_FLAGS = ImGuiTreeNodeFlags_DefaultOpen; // forward declarations void drawSimulationWindow(bool& running, u64 sim_time_ms, float& sim_speed); void drawOrbitWindow(GameState* gs); void drawEllipseParameters(EllipseParameters& ep); void drawGravitationalBody(GravBody& body); void drawOrbitalElements(OrbitalElements& el); void drawSatelliteWindow(Satellite& sat); void drawSystemWindow(TwoBodySystem& sys); void drawManeuverWindow(GameState* gs); // interface bool gooInit(SDL_Window* window, SDL_GLContext gl_context) { IMGUI_CHECKVERSION(); CreateContext(); ImGuiIO& io = GetIO(); io.IniFilename = NULL; // don't save window state to imgui.ini StyleColorsDark(); bool ret = true; ret = ret && ImGui_ImplSDL2_InitForOpenGL(window, gl_context); ret = ret && ImGui_ImplOpenGL3_Init(); return ret; } void gooFree() { ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplSDL2_Shutdown(); DestroyContext(); } bool gooProcessEvent(SDL_Event& e) { ImGui_ImplSDL2_ProcessEvent(&e); return (GetIO().WantCaptureMouse || GetIO().WantCaptureKeyboard); } void gooDraw(SDL_Window* window, GameState* gs) { ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplSDL2_NewFrame(window); NewFrame(); int x = 0, y = 0; SDL_GetWindowSize(window, &x, &y); SetNextWindowPos(ImVec2(x - G_WIDTH, 0)); SetNextWindowSize(ImVec2(G_WIDTH, y)); Begin("Gooey"); drawSimulationWindow(gs->running, gs->sim_time_ms, gs->sim_speed); Separator(); // FIXME: slit up orbit window into function calls here drawOrbitWindow(gs); BeginChild("impulsive maneuver", ImVec2(G_WIDTH - 20, 300), true); drawManeuverWindow(gs); EndChild(); #if 0 assert(gs->orbits[0].in_use); TwoBodySystem& sys = gs->orbits[0].system; drawSystemWindow(sys); drawSatelliteWindow(sys.sat); drawGravitationalBody(sys.body); drawOrbitalElements(sys.elements); drawEllipseParameters(sys.ep); #endif End(); Render(); ImGui_ImplOpenGL3_RenderDrawData(GetDrawData()); } // internal void drawSimulationWindow(bool& running, u64 sim_time_ms, float& sim_speed) { if (Button("||")) running = false; SameLine(); if (Button("|>")) running = true; SameLine(); Text("running: %s", (running > 0) ? "true" : "false"); Text("sim time: %.2f s", double(double(sim_time_ms) / 1000)); InputFloat("sim speed", &sim_speed, 0.1, 4.0, "%.1f"); } void drawOrbitWindow(GameState* gs) { Text("Orbit Selection"); BeginChild("orbit selection", ImVec2(G_WIDTH - 20, 100), true); static u32 selected = UINT_MAX; for (u32 i = 0; i < gs->num_orbits; i++) { GameOrbit& orbit = gs->orbits[i]; if (orbit.in_use) { static const u32 label_len = 128; char label[label_len]; snprintf(label, label_len, "Orbit %d", i); if (Selectable(label, selected == i)) { selected = i; selectOrbit(gs, &orbit); } } } EndChild(); if (selected < gs->num_orbits && gs->orbits[selected].in_use) { TwoBodySystem& sys = gs->orbits[selected].system; BeginChild("orbit details", ImVec2(G_WIDTH - 20, 400), true); Text("Selected Orbit#: %d", selected); //Text("Orbital Period: %.2fs", sys.orbital_period); drawSystemWindow(sys); Separator(); drawGravitationalBody(sys.body); Separator(); drawSatelliteWindow(sys.sat); EndChild(); } } void drawEllipseParameters(EllipseParameters& ep) { Text("semi_major axis, a: %f km", ep.a); Text("semi_minor axis, b: %f km", ep.b); Text("eccentricity, e: %f ", ep.e); Text("linear eccentricity, c: %f km", ep.c); Text("semilatus rectum, p: %f km", ep.p); } void drawGravitationalBody(GravBody& body) { Text("Grav Body:"); Indent(); Text("mu, gravitational parameter: %.3f", body.mu); Text("r, radius in km: %.3f", body.radius); Unindent(); } void drawOrbitalElements(OrbitalElements& el) { if (CollapsingHeader("Orbital Elements", H_FLAGS)) { Text("semi_major axis, a: %f km", el.a); Text("eccentricity, e: %f", el.e); Text("iota, inclination: %f", el.iota); Text("ohm, longitude ascending node: %f", el.ohm); Text("omega, argument of periapsis: %f", el.omega); Text("nu, true anomaly at T0: %f", el.nu); } } void drawSatelliteWindow(Satellite& sat) { Text("Satellite Parameters:"); Indent(); Text("theta, true anomaly: %f", sat.theta); Text("r, radial distance: %f km", sat.r); Text("position:"); Indent(); Text("x: %f km", sat.position.x); Text("y: %f km", sat.position.y); Text("z: %f km", sat.position.z); Unindent(); Text("velocity, km/s: %f", sat.v); Text("flight path angle: %f", sat.gamma); Unindent(); } void drawSystemWindow(TwoBodySystem& sys) { Text("System Info:"); Indent(); Text("orbital period: %.2f s", sys.orbital_period); Text("epsilon, spec. orb. energy: %f", sys.epsilon); Text("h, angular momentum: %f", sys.h); Text("r_apoapsis: %f km", sys.r_apoapsis); Text("r_periapsis: %f km", sys.r_periapsis); // FIXME: not ideal to call into orbit interface from the gooey double tof_apoapse = orbitGetTimeOfFlight(sys, sys.sat.theta, M_PI); Text("time to apoapsis: %.2f s", tof_apoapse); double tof_periapse = orbitGetTimeOfFlight(sys, sys.sat.theta, 2 * M_PI); Text("time to periapsis: %.2f s", tof_periapse); Unindent(); } void drawManeuverWindow(GameState* gs) { GameOrbit* orbit = getSelectedOrbit(gs); static int item_current_idx = 0; static double anom = 0.f; static float dv = 0.f; if (orbit) { if (orbit->maneuver.active) { Text("Orbital Maneuver"); Indent(); Text("true anomaly: %f", orbit->maneuver.true_anomaly); Text("impulse dv: %f km/s", orbit->maneuver.impulse_delta_v); Unindent(); if (Button("remove")) { removeManeuver(orbit); item_current_idx = 0; anom = 0.f; dv = 0.f; } } else { Text("Add orbital maneuver"); const double min_anom = -M_PI, max_anom = M_PI; SliderScalar("maneuver anomaly", ImGuiDataType_Double, &anom, &min_anom, &max_anom, "%.19f"); // select maneuver vector const char* items[] = { "prograde", "retrograde", "some other vector" }; Combo("thrust vector", &item_current_idx, items, IM_ARRAYSIZE(items)); InputFloat("impulse dv, km/s", &dv, 0.1, 4.0, "%.1f"); if (Button("apply")) { if (!addManeuver(orbit, anom, vec3(), dv)) { // flash a color or something? } } } } }