Refactor the rendering of GUI and other improvements of testbed application
This commit is contained in:
parent
7ff7b129e9
commit
1b7cadc245
|
@ -55,7 +55,12 @@ Gui::~Gui() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize the 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
|
// Create the Simulation panel
|
||||||
createSimulationPanel();
|
createSimulationPanel();
|
||||||
|
@ -66,12 +71,31 @@ void Gui::init() {
|
||||||
// Create the Profiling panel
|
// Create the Profiling panel
|
||||||
createProfilingPanel();
|
createProfilingPanel();
|
||||||
|
|
||||||
mApp->set_visible(true);
|
mScreen->set_visible(true);
|
||||||
mApp->perform_layout();
|
mScreen->perform_layout();
|
||||||
|
|
||||||
mTimeSinceLastProfilingDisplay = glfwGetTime();
|
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
|
// Update the GUI values with the engine settings from the current scene
|
||||||
void Gui::resetWithValuesFromCurrentScene() {
|
void Gui::resetWithValuesFromCurrentScene() {
|
||||||
|
|
||||||
|
@ -126,7 +150,7 @@ void Gui::update() {
|
||||||
|
|
||||||
void Gui::createSimulationPanel() {
|
void Gui::createSimulationPanel() {
|
||||||
|
|
||||||
mSimulationPanel = new Window(mApp, "Simulation");
|
mSimulationPanel = new Window(mScreen, "Simulation");
|
||||||
mSimulationPanel->set_position(Vector2i(15, 15));
|
mSimulationPanel->set_position(Vector2i(15, 15));
|
||||||
mSimulationPanel->set_layout(new GroupLayout(10, 5, 10 , 20));
|
mSimulationPanel->set_layout(new GroupLayout(10, 5, 10 , 20));
|
||||||
//mSimulationPanel->setId("SimulationPanel");
|
//mSimulationPanel->setId("SimulationPanel");
|
||||||
|
@ -164,17 +188,16 @@ void Gui::createSimulationPanel() {
|
||||||
scenesNames.push_back(scenes[i]->getName().c_str());
|
scenesNames.push_back(scenes[i]->getName().c_str());
|
||||||
}
|
}
|
||||||
new Label(mSimulationPanel, "Scene","sans-bold");
|
new Label(mSimulationPanel, "Scene","sans-bold");
|
||||||
ComboBox* comboBoxScenes = new ComboBox(mSimulationPanel, scenesNames);
|
|
||||||
comboBoxScenes->set_fixed_width(150);
|
mComboBoxScenes = new ComboBox(mSimulationPanel, scenesNames);
|
||||||
comboBoxScenes->popup()->child_at(0)->set_fixed_height(800);
|
mComboBoxScenes->set_callback([&, scenes](int index) {
|
||||||
comboBoxScenes->set_callback([&, scenes](int index) {
|
|
||||||
mApp->switchScene(scenes[index]);
|
mApp->switchScene(scenes[index]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gui::createSettingsPanel() {
|
void Gui::createSettingsPanel() {
|
||||||
|
|
||||||
mSettingsPanel = new Window(mApp, "Settings");
|
mSettingsPanel = new Window(mScreen, "Settings");
|
||||||
mSettingsPanel->set_position(Vector2i(15, 180));
|
mSettingsPanel->set_position(Vector2i(15, 180));
|
||||||
mSettingsPanel->set_layout(new BoxLayout(Orientation::Vertical, Alignment::Middle, 10, 5));
|
mSettingsPanel->set_layout(new BoxLayout(Orientation::Vertical, Alignment::Middle, 10, 5));
|
||||||
//mSettingsPanel->setId("SettingsPanel");
|
//mSettingsPanel->setId("SettingsPanel");
|
||||||
|
@ -189,14 +212,14 @@ void Gui::createSettingsPanel() {
|
||||||
buttonPhysics->set_change_callback([&](bool state) {
|
buttonPhysics->set_change_callback([&](bool state) {
|
||||||
mPhysicsPanel->set_visible(true);
|
mPhysicsPanel->set_visible(true);
|
||||||
mRenderingPanel->set_visible(false);
|
mRenderingPanel->set_visible(false);
|
||||||
mApp->perform_layout();
|
mScreen->perform_layout();
|
||||||
});
|
});
|
||||||
Button* buttonRendering = new Button(buttonsPanel, "Rendering");
|
Button* buttonRendering = new Button(buttonsPanel, "Rendering");
|
||||||
buttonRendering->set_flags(Button::RadioButton);
|
buttonRendering->set_flags(Button::RadioButton);
|
||||||
buttonRendering->set_change_callback([&](bool state) {
|
buttonRendering->set_change_callback([&](bool state) {
|
||||||
mRenderingPanel->set_visible(true);
|
mRenderingPanel->set_visible(true);
|
||||||
mPhysicsPanel->set_visible(false);
|
mPhysicsPanel->set_visible(false);
|
||||||
mApp->perform_layout();
|
mScreen->perform_layout();
|
||||||
});
|
});
|
||||||
|
|
||||||
// ---------- Physics Panel ----------
|
// ---------- Physics Panel ----------
|
||||||
|
@ -509,7 +532,7 @@ void Gui::createSettingsPanel() {
|
||||||
|
|
||||||
void Gui::createProfilingPanel() {
|
void Gui::createProfilingPanel() {
|
||||||
|
|
||||||
Widget* profilingPanel = new Window(mApp, "Profiling");
|
Widget* profilingPanel = new Window(mScreen, "Profiling");
|
||||||
profilingPanel->set_position(Vector2i(15, 525));
|
profilingPanel->set_position(Vector2i(15, 525));
|
||||||
profilingPanel->set_layout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 5));
|
profilingPanel->set_layout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 5));
|
||||||
//profilingPanel->setId("SettingsPanel");
|
//profilingPanel->setId("SettingsPanel");
|
||||||
|
@ -530,3 +553,33 @@ void Gui::createProfilingPanel() {
|
||||||
profilingPanel->set_visible(true);
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -56,6 +56,11 @@ class Gui {
|
||||||
// Pointer to the application
|
// Pointer to the application
|
||||||
TestbedApplication* mApp;
|
TestbedApplication* mApp;
|
||||||
|
|
||||||
|
// Screen
|
||||||
|
Screen* mScreen;
|
||||||
|
|
||||||
|
GLFWwindow* mWindow;
|
||||||
|
|
||||||
static double mScrollX, mScrollY;
|
static double mScrollX, mScrollY;
|
||||||
|
|
||||||
// Simulation panel
|
// Simulation panel
|
||||||
|
@ -81,7 +86,11 @@ class Gui {
|
||||||
TextBox* mTextboxSleepLinearVel;
|
TextBox* mTextboxSleepLinearVel;
|
||||||
TextBox* mTextboxSleepAngularVel;
|
TextBox* mTextboxSleepAngularVel;
|
||||||
|
|
||||||
|
ToolButton* mButtonPause;
|
||||||
|
Widget* mPanelControls;
|
||||||
|
|
||||||
std::vector<CheckBox*> mCheckboxesScenes;
|
std::vector<CheckBox*> mCheckboxesScenes;
|
||||||
|
ComboBox* mComboBoxScenes;
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
|
@ -124,18 +133,31 @@ class Gui {
|
||||||
~Gui();
|
~Gui();
|
||||||
|
|
||||||
/// Initialize the GUI
|
/// Initialize the GUI
|
||||||
void init();
|
void init(GLFWwindow* window);
|
||||||
|
|
||||||
/// Update the GUI
|
/// Update the GUI
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
/// Display the GUI
|
void drawAll();
|
||||||
void render();
|
|
||||||
|
void draw();
|
||||||
|
|
||||||
|
void drawTearDown();
|
||||||
|
|
||||||
/// Update the GUI values with the engine settings from the current scene
|
/// Update the GUI values with the engine settings from the current scene
|
||||||
void resetWithValuesFromCurrentScene();
|
void resetWithValuesFromCurrentScene();
|
||||||
|
|
||||||
static void setScroll(double scrollX, double scrollY);
|
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() {
|
inline void Gui::resetScroll() {
|
||||||
|
|
|
@ -26,39 +26,35 @@
|
||||||
// Libraries
|
// Libraries
|
||||||
#include "TestbedApplication.h"
|
#include "TestbedApplication.h"
|
||||||
#include "nanogui/nanogui.h"
|
#include "nanogui/nanogui.h"
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
using namespace nanogui;
|
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 <glad/glad.h>
|
||||||
|
# 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
|
// Main function
|
||||||
int main(int /*argc*/, char** /*argv*/) {
|
int main(int /*argc*/, char** /*argv*/) {
|
||||||
|
|
||||||
nanogui::init();
|
// Create and start the testbed application
|
||||||
|
TestbedApplication application;
|
||||||
{
|
application.start();
|
||||||
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<TestbedApplication> application = new TestbedApplication(isFullscreen, windowWidth, windowHeight);
|
|
||||||
application->set_visible(true);
|
|
||||||
|
|
||||||
nanogui::mainloop(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
nanogui::shutdown();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,8 @@ using namespace openglframework;
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Scene::Scene(const std::string& name, EngineSettings& engineSettings, bool isShadowMappingEnabled)
|
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),
|
mViewportWidth(0), mViewportHeight(0), mIsShadowMappingEnabled(isShadowMappingEnabled),
|
||||||
mAreContactPointsDisplayed(true), mAreContactNormalsDisplayed(false), mAreBroadPhaseAABBsDisplayed(false),
|
mAreContactPointsDisplayed(true), mAreContactNormalsDisplayed(false), mAreBroadPhaseAABBsDisplayed(false),
|
||||||
mAreCollidersAABBsDisplayed(false), mAreCollisionShapesDisplayed(false), mIsWireframeEnabled(false) {
|
mAreCollidersAABBsDisplayed(false), mAreCollisionShapesDisplayed(false), mIsWireframeEnabled(false) {
|
||||||
|
@ -97,10 +98,6 @@ bool Scene::mouseButtonEvent(int button, bool down, int mods, double mousePosX,
|
||||||
if (down) {
|
if (down) {
|
||||||
mLastMouseX = mousePosX;
|
mLastMouseX = mousePosX;
|
||||||
mLastMouseY = mousePosY;
|
mLastMouseY = mousePosY;
|
||||||
mIsLastPointOnSphereValid = mapMouseCoordinatesToSphere(mousePosX, mousePosY, mLastPointOnSphere);
|
|
||||||
}
|
|
||||||
else { // If the mouse button is released
|
|
||||||
mIsLastPointOnSphereValid = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -133,7 +130,6 @@ bool Scene::mouseMotionEvent(double xMouse, double yMouse, int leftButtonState,
|
||||||
// Remember the mouse position
|
// Remember the mouse position
|
||||||
mLastMouseX = xMouse;
|
mLastMouseX = xMouse;
|
||||||
mLastMouseY = yMouse;
|
mLastMouseY = yMouse;
|
||||||
mIsLastPointOnSphereValid = mapMouseCoordinatesToSphere(xMouse, yMouse, mLastPointOnSphere);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -165,23 +161,25 @@ void Scene::translate(int xMouse, int yMouse) {
|
||||||
// Rotate the camera
|
// Rotate the camera
|
||||||
void Scene::rotate(int xMouse, int yMouse) {
|
void Scene::rotate(int xMouse, int yMouse) {
|
||||||
|
|
||||||
if (mIsLastPointOnSphereValid) {
|
const double deltaXMouse = mLastMouseX - xMouse;
|
||||||
|
const double deltaYMouse = mLastMouseY - yMouse;
|
||||||
|
|
||||||
Vector3 newPoint3D;
|
double deltaHorizRotationAngle = deltaXMouse / mWindowWidth * MOUSE_CAMERA_ROTATION_SCALING_FACTOR * M_PI;
|
||||||
bool isNewPointOK = mapMouseCoordinatesToSphere(xMouse, yMouse, newPoint3D);
|
double deltaVertRotationAngle = deltaYMouse / mWindowHeight * MOUSE_CAMERA_ROTATION_SCALING_FACTOR * M_PI;
|
||||||
|
|
||||||
if (isNewPointOK) {
|
const double newVerticalAngle = mCurrentCameraVerticalAngle + deltaVertRotationAngle;
|
||||||
Vector3 axis = mLastPointOnSphere.cross(newPoint3D);
|
|
||||||
float cosAngle = mLastPointOnSphere.dot(newPoint3D);
|
|
||||||
|
|
||||||
float epsilon = std::numeric_limits<float>::epsilon();
|
// Limit Vertical angle
|
||||||
if (std::abs(cosAngle) < 1.0f && axis.length() > epsilon) {
|
constexpr double piOver2 = M_PI * 0.5f;
|
||||||
axis.normalize();
|
if (newVerticalAngle > piOver2 || newVerticalAngle < -piOver2) {
|
||||||
float angle = 2.0f * std::acos(cosAngle);
|
deltaVertRotationAngle = 0;
|
||||||
|
|
||||||
// Rotate the camera around the center of the scene
|
|
||||||
mCamera.rotateAroundLocalPoint(axis, -angle, mCenterScene);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,10 @@ class Scene : public rp3d::EventListener {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
// -------------------- Constants -------------------- //
|
||||||
|
|
||||||
|
static constexpr float MOUSE_CAMERA_ROTATION_SCALING_FACTOR = 1.0f;
|
||||||
|
|
||||||
// -------------------- Attributes -------------------- //
|
// -------------------- Attributes -------------------- //
|
||||||
|
|
||||||
/// Scene name
|
/// Scene name
|
||||||
|
@ -118,12 +122,12 @@ class Scene : public rp3d::EventListener {
|
||||||
/// Last point computed on a sphere (for camera rotation)
|
/// Last point computed on a sphere (for camera rotation)
|
||||||
openglframework::Vector3 mLastPointOnSphere;
|
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
|
/// Interpolation factor for the bodies in the current frame
|
||||||
float mInterpolationFactor;
|
float mInterpolationFactor;
|
||||||
|
|
||||||
|
/// Current camera vertical angle around the horizontal axis (in radians)
|
||||||
|
double mCurrentCameraVerticalAngle;
|
||||||
|
|
||||||
/// Viewport x,y, width and height values
|
/// Viewport x,y, width and height values
|
||||||
int mViewportX, mViewportY, mViewportWidth, mViewportHeight;
|
int mViewportX, mViewportY, mViewportWidth, mViewportHeight;
|
||||||
|
|
||||||
|
|
|
@ -76,13 +76,11 @@ using namespace ropescene;
|
||||||
const float TestbedApplication::SCROLL_SENSITIVITY = 0.08f;
|
const float TestbedApplication::SCROLL_SENSITIVITY = 0.08f;
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
TestbedApplication::TestbedApplication(bool isFullscreen, int windowWidth, int windowHeight)
|
TestbedApplication::TestbedApplication()
|
||||||
: Screen(Vector2i(windowWidth, windowHeight), "Testbed ReactPhysics3D v" + rp3d::RP3D_VERSION, true, isFullscreen, true, true, false, 4, 1),
|
: mIsInitialized(false), mGui(this), mCurrentScene(nullptr),
|
||||||
mIsInitialized(false), mGui(this), mCurrentScene(nullptr),
|
|
||||||
mDefaultEngineSettings(EngineSettings::defaultSettings()),
|
mDefaultEngineSettings(EngineSettings::defaultSettings()),
|
||||||
mFPS(0), mNbFrames(0), mPreviousTime(0),
|
mFPS(0), mNbFrames(0), mPreviousTime(0),
|
||||||
mLastTimeComputedFPS(0), mFrameTime(0), mTotalPhysicsTime(0), mPhysicsStepTime(0),
|
mLastTimeComputedFPS(0), mFrameTime(0), mTotalPhysicsTime(0), mPhysicsStepTime(0),
|
||||||
mWidth(windowWidth), mHeight(windowHeight),
|
|
||||||
mSinglePhysicsStepEnabled(false), mSinglePhysicsStepDone(false),
|
mSinglePhysicsStepEnabled(false), mSinglePhysicsStepDone(false),
|
||||||
mWindowToFramebufferRatio(Vector2(1, 1)), mIsShadowMappingEnabled(true),
|
mWindowToFramebufferRatio(Vector2(1, 1)), mIsShadowMappingEnabled(true),
|
||||||
mAreContactPointsDisplayed(false), mAreContactNormalsDisplayed(false),
|
mAreContactPointsDisplayed(false), mAreContactNormalsDisplayed(false),
|
||||||
|
@ -91,8 +89,6 @@ TestbedApplication::TestbedApplication(bool isFullscreen, int windowWidth, int w
|
||||||
mIsVSyncEnabled(false), mIsDebugRendererEnabled(false) {
|
mIsVSyncEnabled(false), mIsDebugRendererEnabled(false) {
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
|
||||||
resize_event(Vector2i(0, 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
|
@ -103,7 +99,62 @@ TestbedApplication::~TestbedApplication() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the viewer
|
// 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
|
// Logger
|
||||||
rp3d::PhysicsCommon::setLogger(&mLogger);
|
rp3d::PhysicsCommon::setLogger(&mLogger);
|
||||||
|
@ -112,12 +163,22 @@ void TestbedApplication::init() {
|
||||||
createScenes();
|
createScenes();
|
||||||
|
|
||||||
// Initialize the GUI
|
// 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
|
// Select the initial scene
|
||||||
const int firstSceneIndex = 0;
|
const int firstSceneIndex = 0;
|
||||||
switchScene(mScenes[firstSceneIndex]);
|
switchScene(mScenes[firstSceneIndex]);
|
||||||
|
|
||||||
|
mGui.drawAll();
|
||||||
|
|
||||||
mTimer.start();
|
mTimer.start();
|
||||||
|
|
||||||
int glMajorVersion, glMinorVersion;
|
int glMajorVersion, glMinorVersion;
|
||||||
|
@ -134,7 +195,68 @@ void TestbedApplication::init() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
glfwSetWindowUserPointer(mWindow, this);
|
||||||
|
|
||||||
|
glfwSetCursorPosCallback(mWindow, [](GLFWwindow* window, double x, double y) {
|
||||||
|
TestbedApplication* app = static_cast<TestbedApplication*>(glfwGetWindowUserPointer(window));
|
||||||
|
app->mouse_motion_event(x, y);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
glfwSetMouseButtonCallback(mWindow, [](GLFWwindow* window, int button, int action, int modifiers) {
|
||||||
|
TestbedApplication* app = static_cast<TestbedApplication*>(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<TestbedApplication*>(glfwGetWindowUserPointer(window));
|
||||||
|
app->keyboard_event(key, scancode, action, mods);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
glfwSetScrollCallback(mWindow, [](GLFWwindow* window, double x, double y) {
|
||||||
|
TestbedApplication* app = static_cast<TestbedApplication*>(glfwGetWindowUserPointer(window));
|
||||||
|
app->scroll_event(x, y);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
glfwSetFramebufferSizeCallback(mWindow, [](GLFWwindow* window, int width, int height) {
|
||||||
|
TestbedApplication* app = static_cast<TestbedApplication*>(glfwGetWindowUserPointer(window));
|
||||||
|
app->onWindowResized(width, height);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
mCurrentScene->reshape(mWidth, mHeight);
|
||||||
|
mCurrentScene->setWindowDimension(mWidth, mHeight);
|
||||||
|
|
||||||
mIsInitialized = true;
|
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
|
// Create all the scenes
|
||||||
|
@ -357,44 +479,39 @@ void TestbedApplication::update() {
|
||||||
|
|
||||||
// Update the scene
|
// Update the scene
|
||||||
mCurrentScene->update();
|
mCurrentScene->update();
|
||||||
|
|
||||||
|
// Compute the current framerate
|
||||||
|
computeFPS();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestbedApplication::draw_contents() {
|
void TestbedApplication::render() {
|
||||||
|
|
||||||
update();
|
|
||||||
|
|
||||||
int bufferWidth, bufferHeight;
|
int bufferWidth, bufferHeight;
|
||||||
glfwMakeContextCurrent(m_glfw_window);
|
glfwMakeContextCurrent(mWindow);
|
||||||
glfwGetFramebufferSize(m_glfw_window, &bufferWidth, &bufferHeight);
|
glfwGetFramebufferSize(mWindow, &bufferWidth, &bufferHeight);
|
||||||
|
|
||||||
// Set the viewport of the scene
|
// Set the viewport of the scene
|
||||||
mCurrentScene->setViewport(0, 0, bufferWidth, bufferHeight);
|
mCurrentScene->setViewport(0, 0, bufferWidth, bufferHeight);
|
||||||
|
|
||||||
// Render the scene
|
// Render the scene
|
||||||
mCurrentScene->render();
|
mCurrentScene->render();
|
||||||
|
|
||||||
mGui.update();
|
|
||||||
|
|
||||||
// Compute the current framerate
|
|
||||||
computeFPS();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Window resize event handler
|
/// Window resize event handler
|
||||||
bool TestbedApplication::resize_event(const Vector2i &size) {
|
bool TestbedApplication::onWindowResized(int width, int height) {
|
||||||
|
|
||||||
if (!mIsInitialized) return false;
|
if (!mIsInitialized) return false;
|
||||||
|
|
||||||
// Get the framebuffer dimension
|
mGui.onWindowResizeEvent(width, height);
|
||||||
int width, height;
|
|
||||||
glfwGetFramebufferSize(m_glfw_window, &width, &height);
|
|
||||||
|
|
||||||
// Resize the camera viewport
|
// Resize the camera viewport
|
||||||
mCurrentScene->reshape(width, height);
|
mCurrentScene->reshape(width, height);
|
||||||
|
|
||||||
// Update the window size of the scene
|
// Update the window size of the scene
|
||||||
int windowWidth, windowHeight;
|
mCurrentScene->setWindowDimension(width, height);
|
||||||
glfwGetWindowSize(m_glfw_window, &windowWidth, &windowHeight);
|
|
||||||
mCurrentScene->setWindowDimension(windowWidth, windowHeight);
|
mWidth = width;
|
||||||
|
mHeight = height;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -408,13 +525,18 @@ void TestbedApplication::switchScene(Scene* newScene) {
|
||||||
|
|
||||||
mTimer.reset();
|
mTimer.reset();
|
||||||
|
|
||||||
|
// Resize the camera viewport
|
||||||
|
mCurrentScene->reshape(mWidth, mHeight);
|
||||||
|
|
||||||
|
// Update the window size of the scene
|
||||||
|
mCurrentScene->setWindowDimension(mWidth, mHeight);
|
||||||
|
|
||||||
// Reset the scene
|
// Reset the scene
|
||||||
mCurrentScene->reset();
|
mCurrentScene->reset();
|
||||||
|
|
||||||
mGui.resetWithValuesFromCurrentScene();
|
|
||||||
mCurrentScene->updateEngineSettings();
|
mCurrentScene->updateEngineSettings();
|
||||||
|
|
||||||
resize_event(Vector2i(0, 0));
|
mGui.resetWithValuesFromCurrentScene();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify that the engine settings have changed
|
// Notify that the engine settings have changed
|
||||||
|
@ -472,16 +594,14 @@ void TestbedApplication::computeFPS() {
|
||||||
mPreviousTime = mCurrentTime;
|
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)) {
|
mGui.onKeyboardEvent(key, scancode, action, modifiers);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close application on escape key
|
// Close application on escape key
|
||||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
|
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
|
||||||
glfwSetWindowShouldClose(m_glfw_window, GL_TRUE);
|
glfwSetWindowShouldClose(mWindow, GL_TRUE);
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close application on escape key
|
// Close application on escape key
|
||||||
|
@ -494,48 +614,45 @@ bool TestbedApplication::keyboard_event(int key, int scancode, int action, int m
|
||||||
playSimulation();
|
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)
|
// 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)) {
|
mGui.onMouseButtonEvent(button, action, modifiers);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the mouse cursor position
|
// Get the mouse cursor position
|
||||||
double x, y;
|
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)
|
// 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)) {
|
mGui.onMouseMotionEvent(x, y);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int leftButtonState = glfwGetMouseButton(m_glfw_window, GLFW_MOUSE_BUTTON_LEFT);
|
int leftButtonState = glfwGetMouseButton(mWindow, GLFW_MOUSE_BUTTON_LEFT);
|
||||||
int rightButtonState = glfwGetMouseButton(m_glfw_window, GLFW_MOUSE_BUTTON_RIGHT);
|
int rightButtonState = glfwGetMouseButton(mWindow, GLFW_MOUSE_BUTTON_RIGHT);
|
||||||
int middleButtonState = glfwGetMouseButton(m_glfw_window, GLFW_MOUSE_BUTTON_MIDDLE);
|
int middleButtonState = glfwGetMouseButton(mWindow, GLFW_MOUSE_BUTTON_MIDDLE);
|
||||||
int altKeyState = glfwGetKey(m_glfw_window, GLFW_KEY_LEFT_ALT);
|
int altKeyState = glfwGetKey(mWindow, GLFW_KEY_LEFT_ALT);
|
||||||
|
|
||||||
return mCurrentScene->mouseMotionEvent(p[0], p[1], leftButtonState, rightButtonState,
|
mCurrentScene->mouseMotionEvent(x, y, leftButtonState, rightButtonState, middleButtonState, altKeyState);
|
||||||
middleButtonState, altKeyState);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle a mouse scroll event (default implementation: propagate to children)
|
// Handle a mouse scroll event
|
||||||
bool TestbedApplication::scroll_event(const Vector2i &p, const Vector2f &rel) {
|
void TestbedApplication::scroll_event(double x, double y) {
|
||||||
|
|
||||||
if (Screen::scroll_event(p, rel)) {
|
if (mGui.onScrollEvent(x, y)) {
|
||||||
return true;
|
return;
|
||||||
}
|
};
|
||||||
|
|
||||||
return mCurrentScene->scrollingEvent(rel[0], rel[1], SCROLL_SENSITIVITY);
|
mCurrentScene->scrollingEvent(x, y, SCROLL_SENSITIVITY);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,22 +36,27 @@
|
||||||
|
|
||||||
using namespace nanogui;
|
using namespace nanogui;
|
||||||
|
|
||||||
|
|
||||||
// Macro for OpenGL errors
|
// Macro for OpenGL errors
|
||||||
#define checkOpenGLErrors() checkOpenGLErrorsInternal(__FILE__,__LINE__)
|
#define checkOpenGLErrors() checkOpenGLErrorsInternal(__FILE__,__LINE__)
|
||||||
|
|
||||||
/// Class TestbedApplication
|
/// Class TestbedApplication
|
||||||
class TestbedApplication : public Screen {
|
class TestbedApplication {
|
||||||
|
|
||||||
private :
|
private :
|
||||||
|
|
||||||
// -------------------- Constants -------------------- //
|
// -------------------- Constants -------------------- //
|
||||||
|
|
||||||
static const float SCROLL_SENSITIVITY;
|
static const float SCROLL_SENSITIVITY;
|
||||||
|
static constexpr bool IS_FULLSCREEN = false;
|
||||||
|
|
||||||
// -------------------- Attributes -------------------- //
|
// -------------------- Attributes -------------------- //
|
||||||
|
|
||||||
bool mIsInitialized;
|
bool mIsInitialized;
|
||||||
|
|
||||||
|
GLFWwindow* mWindow;
|
||||||
|
Screen* mScreen;
|
||||||
|
|
||||||
Gui mGui;
|
Gui mGui;
|
||||||
|
|
||||||
/// Timer
|
/// Timer
|
||||||
|
@ -186,31 +191,31 @@ class TestbedApplication : public Screen {
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
/// Private constructor (for the singleton class)
|
/// Private constructor (for the singleton class)
|
||||||
TestbedApplication(bool isFullscreen, int windowWidth, int windowHeight);
|
TestbedApplication();
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
virtual ~TestbedApplication() override;
|
~TestbedApplication();
|
||||||
|
|
||||||
/// Render the content of the application
|
/// Render the content of the application
|
||||||
virtual void draw_contents() override;
|
void render();
|
||||||
|
|
||||||
/// Window resize event handler
|
/// Window resize event handler
|
||||||
virtual bool resize_event(const Vector2i& size) override;
|
bool onWindowResized(int width, int height);
|
||||||
|
|
||||||
/// Default keyboard event handler
|
/// 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)
|
/// 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)
|
/// 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)
|
/// Handle a mouse scroll event
|
||||||
virtual bool scroll_event(const Vector2i &p, const Vector2f &rel) override;
|
void scroll_event(double x, double y);
|
||||||
|
|
||||||
/// Initialize the application
|
/// Start the application
|
||||||
void init();
|
void start();
|
||||||
|
|
||||||
/// Change the current scene
|
/// Change the current scene
|
||||||
void switchScene(Scene* newScene);
|
void switchScene(Scene* newScene);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user