From 1b7cadc245c179265d83f586012b9c09d6d24c65 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 26 Oct 2021 17:01:50 +0200 Subject: [PATCH] Refactor the rendering of GUI and other improvements of testbed application --- testbed/src/Gui.cpp | 77 ++++++++-- testbed/src/Gui.h | 28 +++- testbed/src/Main.cpp | 50 +++---- testbed/src/Scene.cpp | 40 +++-- testbed/src/Scene.h | 10 +- testbed/src/TestbedApplication.cpp | 231 ++++++++++++++++++++++------- testbed/src/TestbedApplication.h | 29 ++-- 7 files changed, 330 insertions(+), 135 deletions(-) diff --git a/testbed/src/Gui.cpp b/testbed/src/Gui.cpp index e554314a..082ed4b5 100644 --- a/testbed/src/Gui.cpp +++ b/testbed/src/Gui.cpp @@ -55,7 +55,12 @@ Gui::~Gui() { } /// Initialize the GUI -void Gui::init() { +void Gui::init(GLFWwindow* window) { + + mWindow = window; + + mScreen = new Screen(); + mScreen->initialize(window, true); // Create the Simulation panel createSimulationPanel(); @@ -66,12 +71,31 @@ void Gui::init() { // Create the Profiling panel createProfilingPanel(); - mApp->set_visible(true); - mApp->perform_layout(); + mScreen->set_visible(true); + mScreen->perform_layout(); mTimeSinceLastProfilingDisplay = glfwGetTime(); } +void Gui::drawAll() { + mScreen->clear(); + mScreen->draw_all(); +} + +void Gui::draw() { + + mScreen->draw_setup(); + mScreen->clear(); + mScreen->draw_contents(); +} + +void Gui::drawTearDown() { + + mScreen->draw_widgets(); + mScreen->draw_teardown(); +} + + // Update the GUI values with the engine settings from the current scene void Gui::resetWithValuesFromCurrentScene() { @@ -126,7 +150,7 @@ void Gui::update() { void Gui::createSimulationPanel() { - mSimulationPanel = new Window(mApp, "Simulation"); + mSimulationPanel = new Window(mScreen, "Simulation"); mSimulationPanel->set_position(Vector2i(15, 15)); mSimulationPanel->set_layout(new GroupLayout(10, 5, 10 , 20)); //mSimulationPanel->setId("SimulationPanel"); @@ -164,17 +188,16 @@ void Gui::createSimulationPanel() { scenesNames.push_back(scenes[i]->getName().c_str()); } new Label(mSimulationPanel, "Scene","sans-bold"); - ComboBox* comboBoxScenes = new ComboBox(mSimulationPanel, scenesNames); - comboBoxScenes->set_fixed_width(150); - comboBoxScenes->popup()->child_at(0)->set_fixed_height(800); - comboBoxScenes->set_callback([&, scenes](int index) { + + mComboBoxScenes = new ComboBox(mSimulationPanel, scenesNames); + mComboBoxScenes->set_callback([&, scenes](int index) { mApp->switchScene(scenes[index]); }); } void Gui::createSettingsPanel() { - mSettingsPanel = new Window(mApp, "Settings"); + mSettingsPanel = new Window(mScreen, "Settings"); mSettingsPanel->set_position(Vector2i(15, 180)); mSettingsPanel->set_layout(new BoxLayout(Orientation::Vertical, Alignment::Middle, 10, 5)); //mSettingsPanel->setId("SettingsPanel"); @@ -189,14 +212,14 @@ void Gui::createSettingsPanel() { buttonPhysics->set_change_callback([&](bool state) { mPhysicsPanel->set_visible(true); mRenderingPanel->set_visible(false); - mApp->perform_layout(); + mScreen->perform_layout(); }); Button* buttonRendering = new Button(buttonsPanel, "Rendering"); buttonRendering->set_flags(Button::RadioButton); buttonRendering->set_change_callback([&](bool state) { mRenderingPanel->set_visible(true); mPhysicsPanel->set_visible(false); - mApp->perform_layout(); + mScreen->perform_layout(); }); // ---------- Physics Panel ---------- @@ -509,7 +532,7 @@ void Gui::createSettingsPanel() { void Gui::createProfilingPanel() { - Widget* profilingPanel = new Window(mApp, "Profiling"); + Widget* profilingPanel = new Window(mScreen, "Profiling"); profilingPanel->set_position(Vector2i(15, 525)); profilingPanel->set_layout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 5)); //profilingPanel->setId("SettingsPanel"); @@ -530,3 +553,33 @@ void Gui::createProfilingPanel() { profilingPanel->set_visible(true); } +void Gui::onWindowResizeEvent(int width, int height) { + mScreen->resize_callback_event(width, height); +} + +void Gui::onMouseMotionEvent(double x, double y) { + mScreen->cursor_pos_callback_event(x, y); +} + +bool Gui::onScrollEvent(double x, double y) { + + double xMouse, yMouse; + glfwGetCursorPos(mWindow, &xMouse, &yMouse); + + // If the mouse cursor is over the scenes choice scrolling menu + const float pixelRatio = mScreen->pixel_ratio(); + if (mComboBoxScenes->visible() && mComboBoxScenes->popup()->contains(Vector2i(xMouse, yMouse) / pixelRatio)) { + mScreen->scroll_callback_event(x, y); + return true; + } + + return false; +} + +void Gui::onMouseButtonEvent(int button, int action, int modifiers) { + mScreen->mouse_button_callback_event(button, action, modifiers); +} + +void Gui::onKeyboardEvent(int key, int scancode, int action, int modifiers) { + mScreen->key_callback_event(key, scancode, action, modifiers); +} diff --git a/testbed/src/Gui.h b/testbed/src/Gui.h index 8c1cbaa3..10063637 100644 --- a/testbed/src/Gui.h +++ b/testbed/src/Gui.h @@ -56,6 +56,11 @@ class Gui { // Pointer to the application TestbedApplication* mApp; + // Screen + Screen* mScreen; + + GLFWwindow* mWindow; + static double mScrollX, mScrollY; // Simulation panel @@ -81,7 +86,11 @@ class Gui { TextBox* mTextboxSleepLinearVel; TextBox* mTextboxSleepAngularVel; + ToolButton* mButtonPause; + Widget* mPanelControls; + std::vector mCheckboxesScenes; + ComboBox* mComboBoxScenes; // -------------------- Methods -------------------- // @@ -124,18 +133,31 @@ class Gui { ~Gui(); /// Initialize the GUI - void init(); + void init(GLFWwindow* window); /// Update the GUI void update(); - /// Display the GUI - void render(); + void drawAll(); + + void draw(); + + void drawTearDown(); /// Update the GUI values with the engine settings from the current scene void resetWithValuesFromCurrentScene(); static void setScroll(double scrollX, double scrollY); + + void onWindowResizeEvent(int width, int height); + + void onMouseMotionEvent(double x, double y); + + bool onScrollEvent(double x, double y); + + void onMouseButtonEvent(int button, int action, int modifiers); + + void onKeyboardEvent(int key, int scancode, int action, int modifiers); }; inline void Gui::resetScroll() { diff --git a/testbed/src/Main.cpp b/testbed/src/Main.cpp index d532f375..b9608cbd 100644 --- a/testbed/src/Main.cpp +++ b/testbed/src/Main.cpp @@ -26,39 +26,35 @@ // Libraries #include "TestbedApplication.h" #include "nanogui/nanogui.h" +#include using namespace nanogui; +// GLFW +// +#if defined(NANOGUI_USE_OPENGL) +# if defined(NANOGUI_GLAD) +# if defined(NANOGUI_SHARED) && !defined(GLAD_GLAPI_EXPORT) +# define GLAD_GLAPI_EXPORT +# endif +# include +# else +# if defined(__APPLE__) +# define GLFW_INCLUDE_GLCOREARB +# else +# define GL_GLEXT_PROTOTYPES +# endif +# endif +#elif defined(NANOGUI_USE_GLES) +# define GLFW_INCLUDE_ES2 +#endif + // Main function int main(int /*argc*/, char** /*argv*/) { - nanogui::init(); - - { - bool isFullscreen = false; - - // Get the primary monitor - GLFWmonitor* monitor = glfwGetPrimaryMonitor(); - const GLFWvidmode* mode = glfwGetVideoMode(monitor); - - // Window size - int windowWidth = mode->width; - int windowHeight = mode->height; - - if (!isFullscreen) { - - windowWidth *= 0.9; - windowHeight *= 0.9; - } - - // Create and start the testbed application - nanogui::ref application = new TestbedApplication(isFullscreen, windowWidth, windowHeight); - application->set_visible(true); - - nanogui::mainloop(10); - } - - nanogui::shutdown(); + // Create and start the testbed application + TestbedApplication application; + application.start(); return 0; } diff --git a/testbed/src/Scene.cpp b/testbed/src/Scene.cpp index 9c6ec92f..db5ec8ae 100644 --- a/testbed/src/Scene.cpp +++ b/testbed/src/Scene.cpp @@ -31,7 +31,8 @@ using namespace openglframework; // Constructor Scene::Scene(const std::string& name, EngineSettings& engineSettings, bool isShadowMappingEnabled) - : mName(name), mEngineSettings(engineSettings), mLastMouseX(0), mLastMouseY(0), mInterpolationFactor(0.0f), mViewportX(0), mViewportY(0), + : mName(name), mEngineSettings(engineSettings), mLastMouseX(0), mLastMouseY(0), mInterpolationFactor(0.0f), + mCurrentCameraVerticalAngle(0.0), mViewportX(0), mViewportY(0), mViewportWidth(0), mViewportHeight(0), mIsShadowMappingEnabled(isShadowMappingEnabled), mAreContactPointsDisplayed(true), mAreContactNormalsDisplayed(false), mAreBroadPhaseAABBsDisplayed(false), mAreCollidersAABBsDisplayed(false), mAreCollisionShapesDisplayed(false), mIsWireframeEnabled(false) { @@ -97,10 +98,6 @@ bool Scene::mouseButtonEvent(int button, bool down, int mods, double mousePosX, if (down) { mLastMouseX = mousePosX; mLastMouseY = mousePosY; - mIsLastPointOnSphereValid = mapMouseCoordinatesToSphere(mousePosX, mousePosY, mLastPointOnSphere); - } - else { // If the mouse button is released - mIsLastPointOnSphereValid = false; } return true; @@ -133,7 +130,6 @@ bool Scene::mouseMotionEvent(double xMouse, double yMouse, int leftButtonState, // Remember the mouse position mLastMouseX = xMouse; mLastMouseY = yMouse; - mIsLastPointOnSphereValid = mapMouseCoordinatesToSphere(xMouse, yMouse, mLastPointOnSphere); return true; } @@ -165,23 +161,25 @@ void Scene::translate(int xMouse, int yMouse) { // Rotate the camera void Scene::rotate(int xMouse, int yMouse) { - if (mIsLastPointOnSphereValid) { + const double deltaXMouse = mLastMouseX - xMouse; + const double deltaYMouse = mLastMouseY - yMouse; - Vector3 newPoint3D; - bool isNewPointOK = mapMouseCoordinatesToSphere(xMouse, yMouse, newPoint3D); + double deltaHorizRotationAngle = deltaXMouse / mWindowWidth * MOUSE_CAMERA_ROTATION_SCALING_FACTOR * M_PI; + double deltaVertRotationAngle = deltaYMouse / mWindowHeight * MOUSE_CAMERA_ROTATION_SCALING_FACTOR * M_PI; - if (isNewPointOK) { - Vector3 axis = mLastPointOnSphere.cross(newPoint3D); - float cosAngle = mLastPointOnSphere.dot(newPoint3D); + const double newVerticalAngle = mCurrentCameraVerticalAngle + deltaVertRotationAngle; - float epsilon = std::numeric_limits::epsilon(); - if (std::abs(cosAngle) < 1.0f && axis.length() > epsilon) { - axis.normalize(); - float angle = 2.0f * std::acos(cosAngle); - - // Rotate the camera around the center of the scene - mCamera.rotateAroundLocalPoint(axis, -angle, mCenterScene); - } - } + // Limit Vertical angle + constexpr double piOver2 = M_PI * 0.5f; + if (newVerticalAngle > piOver2 || newVerticalAngle < -piOver2) { + deltaVertRotationAngle = 0; } + + Vector3 localVertAxis = mCamera.getTransformMatrix().getUpperLeft3x3Matrix().getInverse() * Vector3(0, 1, 0); + mCamera.rotateAroundLocalPoint(Vector3(1, 0, 0), deltaVertRotationAngle, mCenterScene); + mCamera.rotateAroundLocalPoint(localVertAxis, deltaHorizRotationAngle, mCenterScene); + + mCurrentCameraVerticalAngle += deltaVertRotationAngle; + std::cout << "Delta angle: " << deltaVertRotationAngle << std::endl; + std::cout << "Horizon angle: " << mCurrentCameraVerticalAngle << std::endl; } diff --git a/testbed/src/Scene.h b/testbed/src/Scene.h index 04740479..4e46e30b 100644 --- a/testbed/src/Scene.h +++ b/testbed/src/Scene.h @@ -95,6 +95,10 @@ class Scene : public rp3d::EventListener { protected: + // -------------------- Constants -------------------- // + + static constexpr float MOUSE_CAMERA_ROTATION_SCALING_FACTOR = 1.0f; + // -------------------- Attributes -------------------- // /// Scene name @@ -118,12 +122,12 @@ class Scene : public rp3d::EventListener { /// Last point computed on a sphere (for camera rotation) openglframework::Vector3 mLastPointOnSphere; - /// True if the last point computed on a sphere (for camera rotation) is valid - bool mIsLastPointOnSphereValid; - /// Interpolation factor for the bodies in the current frame float mInterpolationFactor; + /// Current camera vertical angle around the horizontal axis (in radians) + double mCurrentCameraVerticalAngle; + /// Viewport x,y, width and height values int mViewportX, mViewportY, mViewportWidth, mViewportHeight; diff --git a/testbed/src/TestbedApplication.cpp b/testbed/src/TestbedApplication.cpp index a72c5fb4..72f4f699 100755 --- a/testbed/src/TestbedApplication.cpp +++ b/testbed/src/TestbedApplication.cpp @@ -76,13 +76,11 @@ using namespace ropescene; const float TestbedApplication::SCROLL_SENSITIVITY = 0.08f; // Constructor -TestbedApplication::TestbedApplication(bool isFullscreen, int windowWidth, int windowHeight) - : Screen(Vector2i(windowWidth, windowHeight), "Testbed ReactPhysics3D v" + rp3d::RP3D_VERSION, true, isFullscreen, true, true, false, 4, 1), - mIsInitialized(false), mGui(this), mCurrentScene(nullptr), +TestbedApplication::TestbedApplication() + : mIsInitialized(false), mGui(this), mCurrentScene(nullptr), mDefaultEngineSettings(EngineSettings::defaultSettings()), mFPS(0), mNbFrames(0), mPreviousTime(0), mLastTimeComputedFPS(0), mFrameTime(0), mTotalPhysicsTime(0), mPhysicsStepTime(0), - mWidth(windowWidth), mHeight(windowHeight), mSinglePhysicsStepEnabled(false), mSinglePhysicsStepDone(false), mWindowToFramebufferRatio(Vector2(1, 1)), mIsShadowMappingEnabled(true), mAreContactPointsDisplayed(false), mAreContactNormalsDisplayed(false), @@ -91,8 +89,6 @@ TestbedApplication::TestbedApplication(bool isFullscreen, int windowWidth, int w mIsVSyncEnabled(false), mIsDebugRendererEnabled(false) { init(); - - resize_event(Vector2i(0, 0)); } // Destructor @@ -103,7 +99,62 @@ TestbedApplication::~TestbedApplication() { } // Initialize the viewer -void TestbedApplication::init() { +void TestbedApplication::start() { + + glfwInit(); + glfwSetTime(0); + + // Get the primary monitor + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + + // Window size + mWidth = mode->width; + mHeight = mode->height; + +#if defined(NANOGUI_USE_OPENGL) + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); +#elif defined(NANOGUI_USE_GLES) + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); + + glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API); +#elif defined(NANOGUI_USE_METAL) + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + + metal_init(); +#endif + + glfwWindowHint(GLFW_SAMPLES, 0); + glfwWindowHint(GLFW_RED_BITS, 8); + glfwWindowHint(GLFW_GREEN_BITS, 8); + glfwWindowHint(GLFW_BLUE_BITS, 8); + glfwWindowHint(GLFW_ALPHA_BITS, 8); + glfwWindowHint(GLFW_STENCIL_BITS, 8); + glfwWindowHint(GLFW_DEPTH_BITS, 24); + glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); + + // Create a the GLFW window object + std::string title = "Testbed - ReactPhysics3D v" + rp3d::RP3D_VERSION; + mWindow = glfwCreateWindow(mWidth, mHeight, title.c_str(), IS_FULLSCREEN ? monitor : nullptr, nullptr); + if (mWindow == nullptr) { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + } + glfwMakeContextCurrent(mWindow); + +#if defined(NANOGUI_GLAD) + if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) + throw std::runtime_error("Could not initialize GLAD!"); + glGetError(); // pull and ignore unhandled errors like GL_INVALID_ENUM +#endif + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); // Logger rp3d::PhysicsCommon::setLogger(&mLogger); @@ -112,12 +163,22 @@ void TestbedApplication::init() { createScenes(); // Initialize the GUI - mGui.init(); + mGui.init(mWindow); + +#if defined(NANOGUI_USE_OPENGL) || defined(NANOGUI_USE_GLES) + int width, height; + glfwGetFramebufferSize(mWindow, &width, &height); + glViewport(0, 0, width, height); + glfwSwapInterval(0); + glfwSwapBuffers(mWindow); +#endif // Select the initial scene const int firstSceneIndex = 0; switchScene(mScenes[firstSceneIndex]); + mGui.drawAll(); + mTimer.start(); int glMajorVersion, glMinorVersion; @@ -134,7 +195,68 @@ void TestbedApplication::init() { } #endif + glfwSetWindowUserPointer(mWindow, this); + + glfwSetCursorPosCallback(mWindow, [](GLFWwindow* window, double x, double y) { + TestbedApplication* app = static_cast(glfwGetWindowUserPointer(window)); + app->mouse_motion_event(x, y); + } + ); + + glfwSetMouseButtonCallback(mWindow, [](GLFWwindow* window, int button, int action, int modifiers) { + TestbedApplication* app = static_cast(glfwGetWindowUserPointer(window)); + app->mouse_button_event(button, action, modifiers); + } + ); + + glfwSetKeyCallback(mWindow, [](GLFWwindow* window, int key, int scancode, int action, int mods) { + TestbedApplication* app = static_cast(glfwGetWindowUserPointer(window)); + app->keyboard_event(key, scancode, action, mods); + } + ); + + glfwSetScrollCallback(mWindow, [](GLFWwindow* window, double x, double y) { + TestbedApplication* app = static_cast(glfwGetWindowUserPointer(window)); + app->scroll_event(x, y); + } + ); + + glfwSetFramebufferSizeCallback(mWindow, [](GLFWwindow* window, int width, int height) { + TestbedApplication* app = static_cast(glfwGetWindowUserPointer(window)); + app->onWindowResized(width, height); + } + ); + + mCurrentScene->reshape(mWidth, mHeight); + mCurrentScene->setWindowDimension(mWidth, mHeight); + mIsInitialized = true; + + // Game loop + while (!glfwWindowShouldClose(mWindow)) { + + // Check if any events have been activated (key pressed, mouse moved etc.) and call corresponding response functions + glfwPollEvents(); + + update(); + + mGui.update(); + + // Draw nanogui + mGui.draw(); + + render(); + + mGui.drawTearDown(); + } + + // Terminate GLFW, clearing any resources allocated by GLFW. + glfwTerminate(); + +#if defined(NANOGUI_USE_METAL) + metal_shutdown(); +#endif + } // Create all the scenes @@ -357,44 +479,39 @@ void TestbedApplication::update() { // Update the scene mCurrentScene->update(); + + // Compute the current framerate + computeFPS(); } -void TestbedApplication::draw_contents() { - - update(); +void TestbedApplication::render() { int bufferWidth, bufferHeight; - glfwMakeContextCurrent(m_glfw_window); - glfwGetFramebufferSize(m_glfw_window, &bufferWidth, &bufferHeight); + glfwMakeContextCurrent(mWindow); + glfwGetFramebufferSize(mWindow, &bufferWidth, &bufferHeight); // Set the viewport of the scene mCurrentScene->setViewport(0, 0, bufferWidth, bufferHeight); // Render the scene mCurrentScene->render(); - - mGui.update(); - - // Compute the current framerate - computeFPS(); } /// Window resize event handler -bool TestbedApplication::resize_event(const Vector2i &size) { +bool TestbedApplication::onWindowResized(int width, int height) { if (!mIsInitialized) return false; - // Get the framebuffer dimension - int width, height; - glfwGetFramebufferSize(m_glfw_window, &width, &height); + mGui.onWindowResizeEvent(width, height); // Resize the camera viewport mCurrentScene->reshape(width, height); // Update the window size of the scene - int windowWidth, windowHeight; - glfwGetWindowSize(m_glfw_window, &windowWidth, &windowHeight); - mCurrentScene->setWindowDimension(windowWidth, windowHeight); + mCurrentScene->setWindowDimension(width, height); + + mWidth = width; + mHeight = height; return true; } @@ -408,13 +525,18 @@ void TestbedApplication::switchScene(Scene* newScene) { mTimer.reset(); + // Resize the camera viewport + mCurrentScene->reshape(mWidth, mHeight); + + // Update the window size of the scene + mCurrentScene->setWindowDimension(mWidth, mHeight); + // Reset the scene mCurrentScene->reset(); - mGui.resetWithValuesFromCurrentScene(); mCurrentScene->updateEngineSettings(); - resize_event(Vector2i(0, 0)); + mGui.resetWithValuesFromCurrentScene(); } // Notify that the engine settings have changed @@ -472,16 +594,14 @@ void TestbedApplication::computeFPS() { mPreviousTime = mCurrentTime; } -bool TestbedApplication::keyboard_event(int key, int scancode, int action, int modifiers) { +void TestbedApplication::keyboard_event(int key, int scancode, int action, int modifiers) { - if (Screen::keyboard_event(key, scancode, action, modifiers)) { - return true; - } + mGui.onKeyboardEvent(key, scancode, action, modifiers); // Close application on escape key if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { - glfwSetWindowShouldClose(m_glfw_window, GL_TRUE); - return true; + glfwSetWindowShouldClose(mWindow, GL_TRUE); + return; } // Close application on escape key @@ -494,48 +614,45 @@ bool TestbedApplication::keyboard_event(int key, int scancode, int action, int m playSimulation(); } - return true; + return; } - return mCurrentScene->keyboardEvent(key, scancode, action, modifiers); + mCurrentScene->keyboardEvent(key, scancode, action, modifiers); } // Handle a mouse button event (default implementation: propagate to children) -bool TestbedApplication::mouse_button_event(const Vector2i &p, int button, bool down, int modifiers) { +void TestbedApplication::mouse_button_event(int button, int action, int modifiers) { - if (Screen::mouse_button_event(p, button, down, modifiers)) { - return true; - } + mGui.onMouseButtonEvent(button, action, modifiers); // Get the mouse cursor position double x, y; - glfwGetCursorPos(m_glfw_window, &x, &y); + glfwGetCursorPos(mWindow, &x, &y); - return mCurrentScene->mouseButtonEvent(button, down, modifiers, x, y); + bool down = action == GLFW_PRESS; + + mCurrentScene->mouseButtonEvent(button, down, modifiers, x, y); } // Handle a mouse motion event (default implementation: propagate to children) -bool TestbedApplication::mouse_motion_event(const Vector2i &p, const Vector2i &rel, int button, int modifiers) { +void TestbedApplication::mouse_motion_event(double x, double y) { - if (Screen::mouse_motion_event(p, rel, button, modifiers)) { - return true; - } + mGui.onMouseMotionEvent(x, y); - int leftButtonState = glfwGetMouseButton(m_glfw_window, GLFW_MOUSE_BUTTON_LEFT); - int rightButtonState = glfwGetMouseButton(m_glfw_window, GLFW_MOUSE_BUTTON_RIGHT); - int middleButtonState = glfwGetMouseButton(m_glfw_window, GLFW_MOUSE_BUTTON_MIDDLE); - int altKeyState = glfwGetKey(m_glfw_window, GLFW_KEY_LEFT_ALT); + int leftButtonState = glfwGetMouseButton(mWindow, GLFW_MOUSE_BUTTON_LEFT); + int rightButtonState = glfwGetMouseButton(mWindow, GLFW_MOUSE_BUTTON_RIGHT); + int middleButtonState = glfwGetMouseButton(mWindow, GLFW_MOUSE_BUTTON_MIDDLE); + int altKeyState = glfwGetKey(mWindow, GLFW_KEY_LEFT_ALT); - return mCurrentScene->mouseMotionEvent(p[0], p[1], leftButtonState, rightButtonState, - middleButtonState, altKeyState); + mCurrentScene->mouseMotionEvent(x, y, leftButtonState, rightButtonState, middleButtonState, altKeyState); } -// Handle a mouse scroll event (default implementation: propagate to children) -bool TestbedApplication::scroll_event(const Vector2i &p, const Vector2f &rel) { +// Handle a mouse scroll event +void TestbedApplication::scroll_event(double x, double y) { - if (Screen::scroll_event(p, rel)) { - return true; - } + if (mGui.onScrollEvent(x, y)) { + return; + }; - return mCurrentScene->scrollingEvent(rel[0], rel[1], SCROLL_SENSITIVITY); + mCurrentScene->scrollingEvent(x, y, SCROLL_SENSITIVITY); } diff --git a/testbed/src/TestbedApplication.h b/testbed/src/TestbedApplication.h index 1c683cc5..e2a5e078 100644 --- a/testbed/src/TestbedApplication.h +++ b/testbed/src/TestbedApplication.h @@ -36,22 +36,27 @@ using namespace nanogui; + // Macro for OpenGL errors #define checkOpenGLErrors() checkOpenGLErrorsInternal(__FILE__,__LINE__) /// Class TestbedApplication -class TestbedApplication : public Screen { +class TestbedApplication { private : // -------------------- Constants -------------------- // static const float SCROLL_SENSITIVITY; + static constexpr bool IS_FULLSCREEN = false; // -------------------- Attributes -------------------- // bool mIsInitialized; + GLFWwindow* mWindow; + Screen* mScreen; + Gui mGui; /// Timer @@ -186,31 +191,31 @@ class TestbedApplication : public Screen { // -------------------- Methods -------------------- // /// Private constructor (for the singleton class) - TestbedApplication(bool isFullscreen, int windowWidth, int windowHeight); + TestbedApplication(); /// Destructor - virtual ~TestbedApplication() override; + ~TestbedApplication(); /// Render the content of the application - virtual void draw_contents() override; + void render(); /// Window resize event handler - virtual bool resize_event(const Vector2i& size) override; + bool onWindowResized(int width, int height); /// Default keyboard event handler - virtual bool keyboard_event(int key, int scancode, int action, int modifiers) override; + void keyboard_event(int key, int scancode, int action, int modifiers); /// Handle a mouse button event (default implementation: propagate to children) - virtual bool mouse_button_event(const Vector2i &p, int button, bool down, int modifiers) override; + void mouse_button_event(int button, int action, int modifiers); /// Handle a mouse motion event (default implementation: propagate to children) - virtual bool mouse_motion_event(const Vector2i &p, const Vector2i &rel, int button, int modifiers) override; + void mouse_motion_event(double x, double y); - /// Handle a mouse scroll event (default implementation: propagate to children) - virtual bool scroll_event(const Vector2i &p, const Vector2f &rel) override; + /// Handle a mouse scroll event + void scroll_event(double x, double y); - /// Initialize the application - void init(); + /// Start the application + void start(); /// Change the current scene void switchScene(Scene* newScene);