diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b4c7e3e7e520b7f478367294ac86c176b5c3a32..e93fc58bc90944b2506e4361b432e92fde1e60ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,8 @@ add_executable(${PROJECT_NAME} src/sph/sph_particle.cpp src/sph/sph_system.h src/sph/sph_system.cpp + src/utility/InputHandler.h + src/utility/InputHandler.cpp ) diff --git a/src/application.cpp b/src/application.cpp index b29ba1d4d26230c7e0ce5bb647641a66c8bcf233..52c1ce1268f8e16d80d8e7617fe2ea3f4442dfea 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -1,5 +1,6 @@ #include "application.h" +InputHandler* Application::inputHandler = InputHandler::GetInstance(); bool Application::dragging = false; Application::Application() { @@ -48,9 +49,15 @@ void Application::key_callback( GLFWwindow *window, int scancode, int action, int mods) { - std::cout << key << " was pressed" << std::endl; +// std::cout << key << " was pressed" << std::endl; if(key == GLFW_KEY_ESCAPE) glfwSetWindowShouldClose(window, GLFW_TRUE); + if(action == GLFW_RELEASE) + InputHandler::KeyRelease(key); + else + InputHandler::KeyPress(key); + + InputHandler::SetModifiers(mods); } @@ -105,6 +112,8 @@ void Application::run() { // TODO think about rendering only in 24 FPS // TODO guarantee delta_time to be infinitesimal scene->update(delta_time); + camera->control(delta_time); + //clear color and depth buffer glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -114,4 +123,3 @@ void Application::run() { } - diff --git a/src/application.h b/src/application.h index ea2e272f3232028b511ceafd87c58cf8ce089a5a..b1a3ec339260f3bf6fb2dbf592cf69f05cbab77b 100644 --- a/src/application.h +++ b/src/application.h @@ -10,10 +10,12 @@ #include "constants.h" #include "scene.h" #include "rendering/camera.h" +#include "utility/InputHandler.h" // TODO make this class a singleton class Application { - int keyArr[350]; + + int width = WIDTH; int height = HEIGHT; @@ -21,7 +23,7 @@ class Application { // Callback functions static void error_callback(int error, const char* description); static void resize_callback(GLFWwindow *window, int w, int h); - static void key_callback(GLFWwindow *window, int key, int scancode, + static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods); static void mouse_click_callback(GLFWwindow *window, int button, int action, int mods); @@ -29,6 +31,8 @@ class Application { std::shared_ptr<Scene> scene = std::make_shared<Scene>(); + static InputHandler *inputHandler; + void run(); double time_since_last_frame; diff --git a/src/rendering/camera.cpp b/src/rendering/camera.cpp index 429007c3d1ecefdb8dea7940817a1ef333fe7bd7..1685c5c9396acb96e3b30cfd0b8ca2c7ba350f2a 100644 --- a/src/rendering/camera.cpp +++ b/src/rendering/camera.cpp @@ -1,33 +1,42 @@ +#include <iostream> #include "camera.h" Camera::Camera(): aspect_ratio(1), - pos(0, 25, -50), + pos(1, 1, -3), forward(0,0,1), right(-1,0,0), speed(10) { + inputHandler = InputHandler::GetInstance(); } Camera::~Camera() { } -void Camera::control(float delta_time, const bool* inputs) { +void Camera::control(float delta_time) { // process camera keys - for(int i = 0; i < 256; i++) { - if(!inputs[i]) continue; - switch(i) - { - case 'w': pos += forward * speed * delta_time; break; - case 's': pos -= forward * speed * delta_time; break; - case 'a': pos -= right * speed * delta_time; break; - case 'd': pos += right * speed * delta_time; break; - case 'q': pos += glm::vec3(0,-1,0) * speed * delta_time; break; - case 'e': pos += glm::vec3(0,1,0) * speed * delta_time; break; - default: break; - } - } + if(InputHandler::IsPressed(GLFW_KEY_W)) + pos += forward * speed * delta_time; + + + if(InputHandler::IsPressed(GLFW_KEY_S)) + pos -= forward * speed * delta_time; + + if(InputHandler::IsPressed(GLFW_KEY_A)) + pos -= right * speed * delta_time; + + if(InputHandler::IsPressed(GLFW_KEY_D)) + pos += right * speed * delta_time; + + if(InputHandler::IsPressed(GLFW_KEY_Q)) + pos += glm::vec3(0,-1,0) * speed * delta_time; + + if(InputHandler::IsPressed(GLFW_KEY_E)) + pos += glm::vec3(0,1,0) * speed * delta_time; + + std::cout << pos.x << pos.y << pos.z << std::endl; } void Camera::startDrag(int x, int y) { diff --git a/src/rendering/camera.h b/src/rendering/camera.h index 8c8ab523559e51343be40d7cc43caa2bc4f5a3eb..185641506f16690eb3b187c67e795c17adb72bcf 100644 --- a/src/rendering/camera.h +++ b/src/rendering/camera.h @@ -3,6 +3,7 @@ #include <glm/glm.hpp> #include "../utility/gl.h" +#include "../utility/InputHandler.h" class Camera { float aspect_ratio; @@ -11,13 +12,15 @@ class Camera { glm::vec3 right; float speed; + InputHandler* inputHandler; + glm::vec2 drag_start = glm::vec2(0,0); public: void setAspectRatio(float ar) { aspect_ratio = ar; } - void control(float delta_time, const bool* inputs); + void control(float delta_time); void startDrag(int x, int y); void drag(int x, int y); diff --git a/src/sph/sph_system.cpp b/src/sph/sph_system.cpp index ce0ef4cae119f121d7416e87f3c42bef0054be4f..597456a61a2a3fd85ae24a5126022d490ed3bed7 100644 --- a/src/sph/sph_system.cpp +++ b/src/sph/sph_system.cpp @@ -1,15 +1,14 @@ #include "sph_system.h" - namespace sph { System::System() { std::cout << "Initializing sph particle system with " << N << " particles." << std::endl; - for(float y = 0; y < HEIGHT/3; y += H) - for(float z = 0; z < 400; z += H) - for (float x = 0; x < WIDTH/4; x += H) + for(float y = 1; y < 5; y += 0.5f) + for(float z = 0; z < 2; z += 0.2f) + for (float x = 0; x < 2; x += 0.2f) if (particles.size() < N) { float x_off = glm::linearRand(.0f, 1.f); @@ -21,8 +20,9 @@ namespace sph { } System::~System() { - for(int i = 0; i < particles.size(); i++) - delete particles[i]; + for(auto & particle : particles) + delete particle; + } void System::compute_density_and_pressure() { @@ -77,36 +77,35 @@ namespace sph { p->pos += DT * p->v; //boundary conditions - if (p->pos.x - EPS < 0) { + if (p->pos.x - EPS <= 0) { p->v.x *= BOUND_DAMPING; - p->pos.x = 0.0f; - std::cout << "bottom: " << p->pos.x << std::endl; + p->pos.x = EPS; } - if(p->pos.x + EPS > WIDTH) { + if(p->pos.x + EPS > 2) { p->v.x *= BOUND_DAMPING; - p->pos.x = WIDTH - EPS; + p->pos.x = 2 - EPS; } - if(p->pos.y - EPS > HEIGHT) { + if(p->pos.y - EPS <= 0) { p->v.y *= BOUND_DAMPING; - p->pos.y = HEIGHT - EPS; + p->pos.y = EPS; } - if(p->pos.y + EPS > HEIGHT) { + if(p->pos.y + EPS >= 51) { p->v.y *= BOUND_DAMPING; - p->pos.y = HEIGHT - EPS; + p->pos.y = 51 - EPS; } //TODO DEPTH CONSTANT VALUE - if(p->pos.z - EPS < 0) { + if(p->pos.z - EPS <= 0) { p->v.z *= BOUND_DAMPING; p->pos.z = EPS; } - if(p->pos.z + EPS > 400) { + if(p->pos.z + EPS >= 2) { p->v.z *= BOUND_DAMPING; - p->pos.z = 400 - EPS; + p->pos.z = 2 - EPS; } } } @@ -123,12 +122,12 @@ namespace sph { } void System::render() { - // TODO MODERN OPENGL!!!! glEnable(GL_POINT_SMOOTH); glPointSize(H / 2.f); glColor4f(0.5f, 0.5f, 0.8f, 1.f); + glBegin(GL_POINTS); for(auto &p : particles) glVertex3f(p->pos.x, p->pos.y, p->pos.z); diff --git a/src/sph/sph_system.h b/src/sph/sph_system.h index b52b6817def228489443b9f6939f6ba11e581d03..caab4f39068c59924948b1e071da2ba9f7348538 100644 --- a/src/sph/sph_system.h +++ b/src/sph/sph_system.h @@ -20,25 +20,25 @@ namespace sph { // const for equation of state const static float GAS_CONST = 2000.0f; // kernel radius - const static float H = 16.f; + const static float H = 4.f; // (kernel radius)^2 for optimization const static float H2 = H * H; // mass of particles - const static float M = 65.f; + const static float M = 60.f; // viscosity constant - const static float MU = 250.f; + const static float MU = 42.f; // TODO decide the place for this // integration timestep const static float DT = 0.0005f; // epsilon (e.g. at boundary check) - const static float EPS = H; + const static float EPS = 0.0001f; // damping when colliding with the boundary const static float BOUND_DAMPING = -0.5f; [[maybe_unused]] const static float PI = glm::pi<float>(); // smoothing kernel as described in the Müller paper - const static float POLY6 = 315.f / (64 * glm::pi<float>() * glm::pow(H, 9)); + const static float POLY6 = 315.f / (64.f * glm::pi<float>() * glm::pow(H, 9)); const static float POLY6_GRAD_PRESS = -45.f / (glm::pi<float>() * glm::pow(H, 6)); const static float POLY6_GRAD_VISC = 45.f / (glm::pi<float>() * glm::pow(H, @@ -46,7 +46,7 @@ namespace sph { // PARTICLES // number of particles - const static int N = 500; + const static int N = 400; } namespace sph { diff --git a/src/utility/InputHandler.cpp b/src/utility/InputHandler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..92a2edf01d99b998e2c92b51e9ee2886e97c1489 --- /dev/null +++ b/src/utility/InputHandler.cpp @@ -0,0 +1,53 @@ +#include "InputHandler.h" + +InputHandler *InputHandler::singleton_ = nullptr; +bool InputHandler::keyPressed[348]; +int InputHandler::modifiers = 0; + +InputHandler *InputHandler::GetInstance() { + if (singleton_ == nullptr) + singleton_ = new InputHandler(); + + return singleton_; +} + +void InputHandler::KeyPress(int key) { + keyPressed[key] = true; +} + +void InputHandler::SetModifiers(int m) { + modifiers = m; +} + +void InputHandler::KeyRelease(int key) { + keyPressed[key] = false; +} + +bool InputHandler::IsPressed(int key) { + return keyPressed[key]; +} + +bool InputHandler::IsShiftPressed() { + return modifiers & GLFW_MOD_SHIFT; +} + +bool InputHandler::IsControlPressed() { + return modifiers & GLFW_MOD_CONTROL; +} + +bool InputHandler::IsAltPressed() { + return modifiers & GLFW_MOD_ALT; +} + +bool InputHandler::IsSuperPressed() { + return modifiers & GLFW_MOD_SUPER; +} + +bool InputHandler::IsCapsLock() { + return modifiers & GLFW_MOD_CAPS_LOCK; +} + +bool InputHandler::IsNumLock() { + return modifiers & GLFW_MOD_NUM_LOCK; +} + diff --git a/src/utility/InputHandler.h b/src/utility/InputHandler.h new file mode 100644 index 0000000000000000000000000000000000000000..12e892f2a462d7a563b5388b25466fee9bbdf921 --- /dev/null +++ b/src/utility/InputHandler.h @@ -0,0 +1,67 @@ +#ifndef MADID_INPUTHANDLER_H +#define MADID_INPUTHANDLER_H + +#include "gl.h" + +/** + * The inputHandler class defines the `GetInstance` method that serves as an + * alternative to constructor and lets clients access the same instance of this + * class over and over. (Singleton pattern) + */ +class InputHandler { + // Input handling + bool aKeyWasPressed; + static bool keyPressed[348]; + static int modifiers; + + /** + * The inputHandler's constructor should always be private to prevent direct + * construction calls with the `new` operator. + */ + InputHandler() { + aKeyWasPressed = false; + modifiers = 0; + for (bool &k : keyPressed) + k = false; + + } + + static InputHandler *singleton_; + +public: + + /** + * Singletons should not be cloneable. + */ + InputHandler(InputHandler &other) = delete; + + /** + * Singletons should not be assignable. + */ + void operator=(const InputHandler &) = delete; + + static InputHandler *GetInstance(); + + static void KeyPress(int key); + + static void SetModifiers(int m); + + static void KeyRelease(int key); + + static bool IsPressed(int key); + + static bool IsShiftPressed() ; + + static bool IsControlPressed(); + + static bool IsAltPressed(); + + static bool IsSuperPressed(); + + static bool IsCapsLock(); + + static bool IsNumLock(); + +}; + +#endif //MADID_INPUTHANDLER_H