diff --git a/demo/main.cpp b/demo/main.cpp index b706e42b6b3cabe49a23808b97ff8c1917806e49..83211bb2b92d142e4d0c646fad77b414952288c7 100644 --- a/demo/main.cpp +++ b/demo/main.cpp @@ -1,4 +1,5 @@ #include <filesystem> +#include <glm/geometric.hpp> #include <glm/trigonometric.hpp> #include <iostream> @@ -12,6 +13,10 @@ #include <fggl/debug/debug.h> #include <fggl/data/storage.hpp> +template <typename T> int sgn(T val) { + return (T(0) < val) - (val < T(0)); +} + // prototype of resource discovery void discover(std::filesystem::path base) { @@ -36,6 +41,83 @@ void discover(std::filesystem::path base) { } +struct InputState { + double currCursor[2]; + double lastCursor[2]; + bool buttons[3]; +}; + +void process_inputs(fggl::gfx::Window& window, InputState& state) { + state.lastCursor[0] = state.currCursor[0]; + state.lastCursor[1] = state.currCursor[1]; + glfwGetCursorPos(window.handle(), &state.currCursor[0], &state.currCursor[1]); + + state.buttons[0] = glfwGetMouseButton(window.handle(), GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS; + state.buttons[1] = glfwGetMouseButton(window.handle(), GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS; + state.buttons[2] = glfwGetMouseButton(window.handle(), GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS; +} + +//TODO proper input system +void process_camera(fggl::gfx::Window& window, fggl::ecs::ECS& ecs, InputState& state, fggl::ecs::entity_t cam) { + auto camTransform = ecs.getComponent<fggl::math::Transform>(cam); + auto camComp = ecs.getComponent<fggl::gfx::Camera>(cam); + float moveSpeed = 1.0f; + + glm::vec3 dir = ( camTransform->origin() - camComp->target ); + glm::vec3 forward = glm::normalize( dir ); + + glm::vec3 motion(0.0f); + if ( glfwGetKey(window.handle(), GLFW_KEY_W) == GLFW_PRESS ) { + if ( glm::length( dir ) > 2.5f ) { + motion -= (forward * moveSpeed); + } + } + if ( glfwGetKey(window.handle(), GLFW_KEY_S) == GLFW_PRESS ) { + if ( glm::length( dir ) < 25.0f ) { + motion += (forward * moveSpeed); + } + } + if ( glfwGetKey( window.handle(), GLFW_KEY_A ) == GLFW_PRESS ) { + + } + + camTransform->origin( camTransform->origin() + motion ); +} + +void process_arcball(fggl::gfx::Window& window, fggl::ecs::ECS& ecs, InputState& state, fggl::ecs::entity_t cam) { + // see https://asliceofrendering.com/camera/2019/11/30/ArcballCamera/ + auto camTransform = ecs.getComponent<fggl::math::Transform>(cam); + auto camComp = ecs.getComponent<fggl::gfx::Camera>(cam); + + glm::vec4 position(camTransform->origin(), 1.0f); + glm::vec4 pivot(camComp->target, 1.0f); + glm::mat4 view = glm::lookAt( camTransform->origin(), camComp->target, camTransform->up() ); + glm::vec3 viewDir = -glm::transpose(view)[2]; + glm::vec3 rightDir = glm::transpose(view)[0]; + + float deltaAngleX = ( 2 * M_PI / window.width() ); + float deltaAngleY = ( M_PI / window.height() ); + float xAngle = ( state.lastCursor[0] - state.currCursor[0] ) * deltaAngleX; + float yAngle = ( state.lastCursor[1] - state.currCursor[1] ) * deltaAngleY; + + auto cosAngle = glm::dot( viewDir, fggl::math::UP ); + if ( cosAngle * sgn(deltaAngleY) > 0.99f ) { + deltaAngleY = 0; + } + + // rotate the camera around the pivot on the first axis + glm::mat4x4 rotationMatrixX(1.0f); + rotationMatrixX = glm::rotate( rotationMatrixX, xAngle, fggl::math::UP ); + position = ( rotationMatrixX * ( position - pivot ) ) + pivot; + + // rotate the camera aroud the pivot on the second axis + glm::mat4x4 rotationMatrixY(1.0f); + rotationMatrixY = glm::rotate(rotationMatrixY, yAngle, rightDir ); + glm::vec3 finalPos = ( rotationMatrixY * ( position - pivot ) ) + pivot; + + camTransform->origin( finalPos ); +} + int main(int argc, char* argv[]) { fggl::gfx::Context ctx; @@ -124,6 +206,7 @@ int main(int argc, char* argv[]) { ecs.addComponent<fggl::gfx::MeshToken>(entity, token); } + InputState inputs; float time = 0.0f; float dt = 16.0f; @@ -134,6 +217,12 @@ int main(int argc, char* argv[]) { // update step time += dt; + process_inputs(win, inputs); + process_camera(win, ecs, inputs, camEnt); + if ( inputs.buttons[2] ) { + process_arcball(win, ecs, inputs, camEnt); + } + /* float amount = glm::radians( time / 2048.0f * 360.0f ); auto spinners = ecs.getEntityWith<fggl::math::Transform>(); for ( auto entity : spinners ) { diff --git a/fggl/gfx/window.cpp b/fggl/gfx/window.cpp index 044f1d9b33ae0c6349c87460ae3293382a0cbdbe..f160f039769c087c06dbdb5f71c7437372197280 100644 --- a/fggl/gfx/window.cpp +++ b/fggl/gfx/window.cpp @@ -16,6 +16,9 @@ static void glfw_error(int code, const char* description) { static void framebuffer_resize(GLFWwindow* window, int width, int height) { glfwMakeContextCurrent( window ); glViewport(0, 0, width, height); + + auto fgglWindow = reinterpret_cast<Window*>(glfwGetWindowUserPointer( window )); + fgglWindow->framesize( width, height ); } Context::Context() { @@ -46,6 +49,7 @@ Window::Window() : m_window(nullptr), m_input(nullptr) { return; } + m_framesize = glm::vec2(1920, 1080); glfwSetWindowUserPointer(m_window, this); glfwSetFramebufferSizeCallback( m_window, framebuffer_resize ); } diff --git a/fggl/gfx/window.hpp b/fggl/gfx/window.hpp index 0afc6f1255d146cb92fe95bba54763ac77a89465..3045983f31f28e101d85eed99f9f8caf241ee19e 100644 --- a/fggl/gfx/window.hpp +++ b/fggl/gfx/window.hpp @@ -4,6 +4,7 @@ #include <cassert> #include <string> +#include <fggl/math/types.hpp> #include <fggl/gfx/rendering.hpp> namespace fggl::gfx { @@ -48,6 +49,18 @@ namespace fggl::gfx { void activate() const; void swap(); + inline float width() const { + return m_framesize.x; + } + + inline float height() const { + return m_framesize.y; + } + + inline void framesize(int width, int height) { + m_framesize = math::vec2( width, height ); + } + // window manager stuff [[nodiscard]] inline bool closeRequested() const { @@ -113,6 +126,7 @@ namespace fggl::gfx { private: GLFWwindow* m_window; Input* m_input; + math::vec2 m_framesize; inline void set_hint(int hint, bool state) const { assert( m_window != nullptr );