#include #include #include #include "gfx.hpp" #include "icosphere.hpp" #include "particlevisualizer.hpp" #include "orbitvisualizer.hpp" #include "widget.hpp" #include #include #include #include // INPUT! // // what input do we even want in the first place? // * camera controls - this is a rendering only concern which needn't affect the orbital // * model validation - we want to modify orbits over time to confirm that our model is // working properly // // TODO: input can only be directly handled by static methods, so we need to find a way to collect // input from object instances and handle it at a higher level. in the case of this class, we want // to determine when a configurable key is pressed. alternatively, we can split the behaviour into // multiple sub-classes and run different loops at the top level? // // another idea is to process all input into a well-defined Input struct in the main loop, then // pass this struct into objects' render() method. // // it's possible the first idea makes the most sense if the plan is to ultimately extract the orbit // stuff to a library, since it keeps input a separate concern from the physics model struct Input { bool pauseTime; bool printCartesian; } input; void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { if (action == GLFW_PRESS) { input.pauseTime = key == GLFW_KEY_SPACE; input.printCartesian = key == GLFW_KEY_W; } } void clearInput() { input.pauseTime = false; input.printCartesian = false; } // now should always increase linearly with real world time, this should not be modified by input // for animations etc struct Time { double now; double dt; } engineTime; void updateTime() { std::chrono::duration timeSinceEpoch = std::chrono::steady_clock::now().time_since_epoch(); double now = std::chrono::duration(timeSinceEpoch).count(); double dt = now - engineTime.now; engineTime.dt = dt; engineTime.now = now; } void printVector(const glm::dvec3& vector) { std::cout << "(" << vector.x << ", " << vector.y << ", " << vector.z << ")"; } int main() { GLFWwindow* window = nullptr; if (initGraphics(&window, "skeingl") != 0) return -1; GLuint litProgram = compileShaderProgram("./frag_lit.glsl"); GLuint unlitProgram = compileShaderProgram("./frag_unlit.glsl"); // set parameters of moon's orbit around earth Orbit moonOrbit; double moonOrbitSemiMajorAxis = 3.84748e8; moonOrbit.setSemiMajorAxis(moonOrbitSemiMajorAxis); // metres moonOrbit.setEccentricity(0.055); moonOrbit.setInclination(glm::radians(5.15)); // radians moonOrbit.setArgumentOfPeriapsis(318.15); // in the case of the moon these last two values are moonOrbit.setLongitudeOfAscendingNode(60.0); // pretty much constantly changing so use whatever // set parameters of satellite orbit around moon Orbit stationOrbit; stationOrbit.setSemiMajorAxis(5e7); stationOrbit.setEccentricity(0.6); stationOrbit.setInclination(glm::radians(89.0)); stationOrbit.setArgumentOfPeriapsis(43.2); stationOrbit.setLongitudeOfAscendingNode(239.7); ParticleMap map; map.setParticle({"earth", 5.9e24}); map.setParticle({"moon", 7.3e22}); map.setParticle({"station", 1e6}); map.setRelationship("earth", "moon", moonOrbit); map.setRelationship("moon", "station", stationOrbit); float scale = moonOrbitSemiMajorAxis * 1.1; ParticleVisualizer earthVis(map, "earth", 0.1, litProgram, unlitProgram, scale); ParticleVisualizer moonVis(map, "moon", 0.02, litProgram, unlitProgram, scale); ParticleVisualizer stationVis(map, "station", 0.01, litProgram, unlitProgram, scale); OrbitVisualizer moonOrbitVis(map, "moon", unlitProgram, scale); OrbitVisualizer stationOrbitVis(map, "station", unlitProgram, scale); // register input glfwSetKeyCallback(window, keyCallback); // TODO: convert these to an enum const int MODE_ORBIT = 0; const int MODE_MANEOUVRE = 1; int mode = 0; // simulation time. this can be paused or whatever as animation demands. double time = 0; // Main loop while (!glfwWindowShouldClose(window)) { // receive input - key callback populates input struct defined further up, // clearInput() needs to be called to clear input from previous frame clearInput(); glfwPollEvents(); updateTime(); // apply input if (input.pauseTime) { mode++; if (mode > MODE_MANEOUVRE) { mode = 0; } } // the moon takes like 27 days to orbit earth. to see this in motion, then, we need to // increase the speed of time by 60 * 60 * 24 to see 1 day per second. const double speed = 60 * 60 * 24; // orbit modifications need to be instanteneous if (mode == MODE_ORBIT) { time += engineTime.dt * speed; } else { if (input.printCartesian) { const glm::dvec3 p = map.getParticleLocalPosition("station", time); printVector(p); std::cout << std::endl; // TODO: what unit is this in lol const glm::dvec3 v = map.getParticleLocalVelocity("station", time); const glm::dvec3 newVelocity = v * 0.9; printVector(v); std::cout << " -> "; printVector(newVelocity); std::cout << std::endl; map.setParticleLocalVelocity("station", time, newVelocity); } } // rendering glClearColor(0.2, 0.3, 0.3, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); earthVis.render(time); moonVis.render(time); stationVis.render(time); moonOrbitVis.render(time); stationOrbitVis.render(time); glfwSwapBuffers(window); } glfwTerminate(); return 0; }