#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 cycleAnimation; } input; void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { if (key == GLFW_KEY_C && action == GLFW_PRESS) { input.cycleAnimation = true; } } void clearInput() { input.cycleAnimation = false; } double getTime() { auto now = std::chrono::steady_clock::now().time_since_epoch(); return std::chrono::duration(now).count(); } 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 orbit; double semiMajorAxis = 3.84748e8; orbit.setSemiMajorAxis(semiMajorAxis); // metres orbit.setEccentricity(0.055); orbit.setInclination(glm::radians(5.15)); // radians orbit.setArgumentOfPeriapsis(318.15); // in the case of the moon these last two values are orbit.setLongitudeOfAscendingNode(60.0); // pretty much constantly changing so use whatever // TODO: add something in a nice eccentric orbit around the moon // make the earth-moon system ParticleMap map; map.setParticle({"earth", 5.9e24}); map.setParticle({"moon", 7.3e22}); map.setRelationship("earth", "moon", orbit); float scale = semiMajorAxis * 1.1; ParticleVisualizer earthVis(map, "earth", 0.2, litProgram, unlitProgram, scale); ParticleVisualizer moonVis(map, "moon", 0.1, litProgram, unlitProgram, scale); OrbitVisualizer orbitVis(orbit, unlitProgram, scale); // register input glfwSetKeyCallback(window, keyCallback); // TODO: convert these to an enum const int ANIM_ORBITING = 0; const int ANIM_ECCENTRICITY = 1; int animation = 0; double time = getTime(); // 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(); // apply input if (input.cycleAnimation) { animation++; if (animation > ANIM_ECCENTRICITY) { animation = 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; // only update time if playing the orbiting animation if (animation == ANIM_ORBITING) { time = getTime() * speed; } else { double e = .25 + .2 * sin(getTime()); orbit.setEccentricity(e); } // 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); orbitVis.render(time); glfwSwapBuffers(window); } glfwTerminate(); return 0; }