reactphysics3d/testbed/src/Gui.cpp

452 lines
18 KiB
C++
Raw Normal View History

/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
2016-04-11 18:15:20 +00:00
* Copyright (c) 2010-2016 Daniel Chappuis *
*********************************************************************************
* *
* This software is provided 'as-is', without any express or implied warranty. *
* In no event will the authors be held liable for any damages arising from the *
* use of this software. *
* *
* Permission is granted to anyone to use this software for any purpose, *
* including commercial applications, and to alter it and redistribute it *
* freely, subject to the following restrictions: *
* *
* 1. The origin of this software must not be misrepresented; you must not claim *
* that you wrote the original software. If you use this software in a *
* product, an acknowledgment in the product documentation would be *
* appreciated but is not required. *
* *
* 2. Altered source versions must be plainly marked as such, and must not be *
* misrepresented as being the original software. *
* *
* 3. This notice may not be removed or altered from any source distribution. *
* *
********************************************************************************/
// Libraries
#include "Gui.h"
#include <GLFW/glfw3.h>
#include "TestbedApplication.h"
using namespace nanogui;
//GLFWwindow* Gui::mWindow = NULL;
double Gui::mScrollX = 0.0;
double Gui::mScrollY = 0.0;
2015-08-06 19:06:35 +00:00
double Gui::mTimeSinceLastProfilingDisplay = 0;
double Gui::mCachedFPS = 0;
double Gui::mCachedUpdateTime = 0;
double Gui::mCachedPhysicsUpdateTime = 0;
// Constructor
2016-02-28 20:39:39 +00:00
Gui::Gui(TestbedApplication* app) : mApp(app) {
}
// Destructor
Gui::~Gui() {
}
/// Initialize the GUI
void Gui::init() {
2016-02-28 20:39:39 +00:00
// Create the Simulation panel
createSimulationPanel();
2016-02-28 20:39:39 +00:00
// Create the Settings panel
createSettingsPanel();
2016-02-28 20:39:39 +00:00
// Create the Profiling panel
createProfilingPanel();
2016-02-28 20:39:39 +00:00
mApp->setVisible(true);
mApp->performLayout();
2015-06-30 17:50:17 +00:00
2015-08-06 19:06:35 +00:00
mTimeSinceLastProfilingDisplay = glfwGetTime();
}
2016-02-28 20:39:39 +00:00
// Update the GUI
void Gui::update() {
2015-07-31 19:54:02 +00:00
// Update Profiling GUI every seconds
if ((mApp->mCurrentTime - mTimeSinceLastProfilingDisplay) > TIME_INTERVAL_DISPLAY_PROFILING_INFO) {
mTimeSinceLastProfilingDisplay = mApp->mCurrentTime;
2016-02-28 20:39:39 +00:00
mCachedFPS = mApp->mFPS;
mCachedUpdateTime = mApp->mFrameTime;
mCachedPhysicsUpdateTime = mApp->mPhysicsTime;
}
2016-02-28 20:39:39 +00:00
// Framerate (FPS)
mFPSLabel->setCaption(std::string("FPS : ") + floatToString(mCachedFPS, 0));
// Frame time
mFrameTimeLabel->setCaption(std::string("Frame time : ") + floatToString(mCachedUpdateTime * 1000.0, 1) + std::string(" ms"));
2015-07-11 22:05:49 +00:00
// Physics time
mPhysicsTimeLabel->setCaption(std::string("Physics time : ") + floatToString(mCachedPhysicsUpdateTime * 1000.0, 1) + std::string(" ms"));
}
2016-02-28 20:39:39 +00:00
void Gui::createSimulationPanel() {
mSimulationPanel = new Window(mApp, "Simulation");
mSimulationPanel->setPosition(Vector2i(15, 15));
mSimulationPanel->setLayout(new GroupLayout(10, 5, 10 , 20));
mSimulationPanel->setId("SimulationPanel");
mSimulationPanel->setFixedWidth(220);
// Scenes/Physics/Rendering buttons
new Label(mSimulationPanel, "Controls","sans-bold");
2016-02-28 20:39:39 +00:00
Widget* panelControls = new Widget(mSimulationPanel);
panelControls->setLayout(new BoxLayout(Orientation::Horizontal, Alignment::Middle, 0, 5));
ToolButton* buttonPlay = new ToolButton(panelControls, ENTYPO_ICON_PLAY);
buttonPlay->setFlags(Button::NormalButton);
buttonPlay->setCallback([&] {
mApp->playSimulation();
});
ToolButton* buttonPause = new ToolButton(panelControls, ENTYPO_ICON_PAUS);
buttonPause->setFlags(Button::NormalButton);
buttonPause->setCallback([&] {
mApp->pauseSimulation();
});
ToolButton* buttonPlayStep = new ToolButton(panelControls, ENTYPO_ICON_TO_END);
buttonPlayStep->setFlags(Button::NormalButton);
buttonPlayStep->setCallback([&] {
mApp->toggleTakeSinglePhysicsStep();
});
ToolButton* buttonRestart = new ToolButton(panelControls, ENTYPO_ICON_CCW);
buttonRestart->setFlags(Button::NormalButton);
buttonRestart->setCallback([&] {
mApp->restartSimulation();
});
// Scenes
std::vector<Scene*> scenes = mApp->getScenes();
std::vector<std::string> scenesNames;
2016-03-30 21:01:11 +00:00
for (uint i=0; i<scenes.size(); i++) {
2016-02-28 20:39:39 +00:00
scenesNames.push_back(scenes[i]->getName().c_str());
}
new Label(mSimulationPanel, "Scene","sans-bold");
ComboBox* comboBoxScenes = new ComboBox(mSimulationPanel, scenesNames, [&, scenes](int index) {
2016-02-28 20:39:39 +00:00
mApp->switchScene(scenes[index]);
});
comboBoxScenes->setFixedWidth(150);
}
2016-02-28 20:39:39 +00:00
void Gui::createSettingsPanel() {
mSettingsPanel = new Window(mApp, "Settings");
mSettingsPanel->setPosition(Vector2i(15, 180));
mSettingsPanel->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Middle, 10, 5));
mSettingsPanel->setId("SettingsPanel");
mSettingsPanel->setFixedWidth(220);
// Scenes/Physics/Rendering buttons
Widget* buttonsPanel = new Widget(mSettingsPanel);
buttonsPanel->setLayout(new BoxLayout(Orientation::Horizontal, Alignment::Middle, 5, 5));
Button* buttonPhysics = new Button(buttonsPanel, "Physics");
buttonPhysics->setFlags(Button::RadioButton);
buttonPhysics->setPushed(true);
buttonPhysics->setChangeCallback([&](bool state) {
mPhysicsPanel->setVisible(true);
mRenderingPanel->setVisible(false);
mApp->performLayout();
});
Button* buttonRendering = new Button(buttonsPanel, "Rendering");
buttonRendering->setFlags(Button::RadioButton);
buttonRendering->setChangeCallback([&](bool state) {
mRenderingPanel->setVisible(true);
mPhysicsPanel->setVisible(false);
mApp->performLayout();
});
// ---------- Physics Panel ----------
mPhysicsPanel = new Widget(mSettingsPanel);
mPhysicsPanel->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 0, 5));
// Enable/Disable sleeping
CheckBox* checkboxSleeping = new CheckBox(mPhysicsPanel, "Sleeping enabled");
checkboxSleeping->setChecked(mApp->mEngineSettings.isSleepingEnabled);
checkboxSleeping->setCallback([&](bool value) {
mApp->mEngineSettings.isSleepingEnabled = value;
2018-03-15 22:11:26 +00:00
mApp->notifyEngineSetttingsChanged();
2016-02-28 20:39:39 +00:00
});
// Enabled/Disable Gravity
2016-02-28 20:39:39 +00:00
CheckBox* checkboxGravity = new CheckBox(mPhysicsPanel, "Gravity enabled");
checkboxGravity->setChecked(mApp->mEngineSettings.isGravityEnabled);
checkboxGravity->setCallback([&](bool value) {
mApp->mEngineSettings.isGravityEnabled = value;
2018-03-15 22:11:26 +00:00
mApp->notifyEngineSetttingsChanged();
2016-02-28 20:39:39 +00:00
});
// Timestep
2016-02-28 20:39:39 +00:00
Widget* panelTimeStep = new Widget(mPhysicsPanel);
panelTimeStep->setLayout(new BoxLayout(Orientation::Horizontal, Alignment::Middle, 0, 5));
Label* labelTimeStep = new Label(panelTimeStep, "Time step","sans-bold");
labelTimeStep->setFixedWidth(120);
TextBox* textboxTimeStep = new TextBox(panelTimeStep);
textboxTimeStep->setFixedSize(Vector2i(70, 25));
textboxTimeStep->setEditable(true);
std::ostringstream out;
out << std::setprecision(1) << std::fixed << (mApp->mEngineSettings.timeStep * 1000);
textboxTimeStep->setValue(out.str());
textboxTimeStep->setUnits("ms");
textboxTimeStep->setCallback([&, textboxTimeStep](const std::string &str) {
try {
float value = std::stof(str);
std::ostringstream out;
out << std::setprecision(1) << std::fixed << std::showpoint << value;
float finalValue = std::stof(out.str());
if (finalValue < 1 || finalValue > 1000) return false;
mApp->mEngineSettings.timeStep = finalValue / 1000.0f;
2018-03-15 22:11:26 +00:00
mApp->notifyEngineSetttingsChanged();
2016-02-28 20:39:39 +00:00
textboxTimeStep->setValue(out.str());
}
catch (...) {
return false;
}
2016-02-28 20:39:39 +00:00
return true;
});
textboxTimeStep->setFontSize(16);
textboxTimeStep->setAlignment(TextBox::Alignment::Right);
// Velocity solver iterations
Widget* panelVelocityIterations = new Widget(mPhysicsPanel);
2016-03-03 20:46:45 +00:00
panelVelocityIterations->setLayout(new BoxLayout(Orientation::Horizontal, Alignment::Middle, 0, 5));
2016-02-28 20:39:39 +00:00
Label* labelVelocityIterations = new Label(panelVelocityIterations, "Velocity solver","sans-bold");
labelVelocityIterations->setFixedWidth(120);
TextBox* textboxVelocityIterations = new TextBox(panelVelocityIterations);
textboxVelocityIterations->setFixedSize(Vector2i(70, 25));
textboxVelocityIterations->setEditable(true);
textboxVelocityIterations->setValue(std::to_string(mApp->mEngineSettings.nbVelocitySolverIterations));
textboxVelocityIterations->setUnits("iter");
textboxVelocityIterations->setCallback([&, textboxVelocityIterations](const std::string &str) {
try {
float value = std::stof(str);
2016-03-03 20:46:45 +00:00
std::ostringstream out;
out << std::setprecision(0) << std::fixed << value;
2016-02-28 20:39:39 +00:00
if (value < 1 || value > 1000) return false;
mApp->mEngineSettings.nbVelocitySolverIterations = value;
2018-03-15 22:11:26 +00:00
mApp->notifyEngineSetttingsChanged();
2016-02-28 20:39:39 +00:00
textboxVelocityIterations->setValue(out.str());
}
catch (...) {
return false;
}
2016-02-28 20:39:39 +00:00
return true;
});
textboxVelocityIterations->setFontSize(16);
textboxVelocityIterations->setAlignment(TextBox::Alignment::Right);
// Position solver iterations
Widget* panelPositionIterations = new Widget(mPhysicsPanel);
2016-03-03 20:46:45 +00:00
panelPositionIterations->setLayout(new BoxLayout(Orientation::Horizontal, Alignment::Middle, 0, 5));
2016-02-28 20:39:39 +00:00
Label* labelPositionIterations = new Label(panelPositionIterations, "Position solver","sans-bold");
labelPositionIterations->setFixedWidth(120);
TextBox* textboxPositionIterations = new TextBox(panelPositionIterations);
textboxPositionIterations->setFixedSize(Vector2i(70, 25));
textboxPositionIterations->setEditable(true);
textboxPositionIterations->setValue(std::to_string(mApp->mEngineSettings.nbPositionSolverIterations));
textboxPositionIterations->setUnits("iter");
textboxPositionIterations->setCallback([&, textboxPositionIterations](const std::string &str) {
try {
float value = std::stof(str);
2016-03-03 20:46:45 +00:00
std::ostringstream out;
out << std::setprecision(0) << std::fixed << value;
2016-02-28 20:39:39 +00:00
if (value < 1 || value > 1000) return false;
mApp->mEngineSettings.nbPositionSolverIterations = value;
2018-03-15 22:11:26 +00:00
mApp->notifyEngineSetttingsChanged();
2016-02-28 20:39:39 +00:00
textboxPositionIterations->setValue(out.str());
}
catch (...) {
return false;
}
2016-02-28 20:39:39 +00:00
return true;
});
textboxPositionIterations->setFontSize(16);
textboxPositionIterations->setAlignment(TextBox::Alignment::Right);
2016-02-28 20:39:39 +00:00
// Time before sleep
Widget* panelTimeSleep = new Widget(mPhysicsPanel);
2016-03-03 20:46:45 +00:00
panelTimeSleep->setLayout(new BoxLayout(Orientation::Horizontal, Alignment::Middle, 0, 5));
2016-02-28 20:39:39 +00:00
Label* labelTimeSleep = new Label(panelTimeSleep, "Time before sleep","sans-bold");
labelTimeSleep->setFixedWidth(120);
out.str("");
out << std::setprecision(0) << std::fixed << (mApp->mEngineSettings.timeBeforeSleep * 1000);
TextBox* textboxTimeSleep = new TextBox(panelTimeSleep);
textboxTimeSleep->setFixedSize(Vector2i(70, 25));
textboxTimeSleep->setEditable(true);
textboxTimeSleep->setValue(out.str());
textboxTimeSleep->setUnits("ms");
textboxTimeSleep->setCallback([&, textboxTimeSleep](const std::string &str) {
try {
float value = std::stof(str);
std::ostringstream out;
out << std::setprecision(0) << std::fixed << std::showpoint << value;
float finalValue = std::stof(out.str());
if (finalValue < 1 || finalValue > 100000) return false;
mApp->mEngineSettings.timeBeforeSleep = finalValue / 1000.0f;
2018-03-15 22:11:26 +00:00
mApp->notifyEngineSetttingsChanged();
2016-02-28 20:39:39 +00:00
textboxTimeSleep->setValue(out.str());
}
catch (...) {
return false;
}
2016-02-28 20:39:39 +00:00
return true;
});
textboxTimeSleep->setFontSize(16);
textboxTimeSleep->setAlignment(TextBox::Alignment::Right);
2016-02-28 20:39:39 +00:00
// Sleep linear velocity
Widget* panelSleepLinearVel = new Widget(mPhysicsPanel);
2016-03-03 20:46:45 +00:00
panelSleepLinearVel->setLayout(new GridLayout(Orientation::Horizontal, 2, Alignment::Middle, 0, 5));
2016-02-28 20:39:39 +00:00
Label* labelSleepLinearVel = new Label(panelSleepLinearVel, "Sleep linear velocity","sans-bold");
labelSleepLinearVel->setFixedWidth(120);
out.str("");
out << std::setprecision(2) << std::fixed << (mApp->mEngineSettings.sleepLinearVelocity);
2016-02-28 20:39:39 +00:00
TextBox* textboxSleepLinearVel = new TextBox(panelSleepLinearVel);
textboxSleepLinearVel->setFixedSize(Vector2i(70, 25));
textboxSleepLinearVel->setEditable(true);
textboxSleepLinearVel->setValue(out.str());
textboxSleepLinearVel->setUnits("m/s");
textboxSleepLinearVel->setCallback([&, textboxSleepLinearVel](const std::string &str) {
try {
float value = std::stof(str);
std::ostringstream out;
out << std::setprecision(2) << std::fixed << std::showpoint << value;
2016-02-28 20:39:39 +00:00
float finalValue = std::stof(out.str());
if (finalValue < 0 || finalValue > 10000) return false;
mApp->mEngineSettings.sleepLinearVelocity = finalValue;
2018-03-15 22:11:26 +00:00
mApp->notifyEngineSetttingsChanged();
2016-02-28 20:39:39 +00:00
textboxSleepLinearVel->setValue(out.str());
}
catch (...) {
return false;
}
2015-08-06 19:06:35 +00:00
2016-02-28 20:39:39 +00:00
return true;
});
textboxSleepLinearVel->setFontSize(16);
textboxSleepLinearVel->setAlignment(TextBox::Alignment::Right);
2016-02-28 20:39:39 +00:00
// Sleep angular velocity
Widget* panelSleepAngularVel = new Widget(mPhysicsPanel);
2016-03-03 20:46:45 +00:00
panelSleepAngularVel->setLayout(new GridLayout(Orientation::Horizontal, 2, Alignment::Middle, 0, 5));
2016-02-28 20:39:39 +00:00
Label* labelSleepAngularVel = new Label(panelSleepAngularVel, "Sleep angular velocity","sans-bold");
labelSleepAngularVel->setFixedWidth(120);
out.str("");
out << std::setprecision(2) << std::fixed << (mApp->mEngineSettings.sleepAngularVelocity);
2016-02-28 20:39:39 +00:00
TextBox* textboxSleepAngularVel = new TextBox(panelSleepAngularVel);
textboxSleepAngularVel->setFixedSize(Vector2i(70, 25));
textboxSleepAngularVel->setEditable(true);
textboxSleepAngularVel->setValue(out.str());
textboxSleepAngularVel->setUnits("rad/s");
2016-02-28 20:39:39 +00:00
textboxSleepAngularVel->setCallback([&, textboxSleepAngularVel](const std::string &str) {
try {
float value = std::stof(str);
std::ostringstream out;
out << std::setprecision(2) << std::fixed << std::showpoint << value;
2016-02-28 20:39:39 +00:00
float finalValue = std::stof(out.str());
if (finalValue < 0 || finalValue > 10000) return false;
mApp->mEngineSettings.sleepAngularVelocity = finalValue;
2018-03-15 22:11:26 +00:00
mApp->notifyEngineSetttingsChanged();
2016-02-28 20:39:39 +00:00
textboxSleepAngularVel->setValue(out.str());
}
catch (...) {
return false;
}
2015-08-06 19:06:35 +00:00
2016-02-28 20:39:39 +00:00
return true;
});
textboxSleepAngularVel->setFontSize(16);
textboxSleepAngularVel->setAlignment(TextBox::Alignment::Right);
2015-08-06 19:06:35 +00:00
2016-02-28 20:39:39 +00:00
// ---------- Rendering Panel ----------
mRenderingPanel = new Widget(mSettingsPanel);
mRenderingPanel->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 0, 5));
2015-08-06 19:06:35 +00:00
2015-08-11 16:32:45 +00:00
// Display/Hide contact points
2016-02-28 20:39:39 +00:00
CheckBox* checkboxContactPoints = new CheckBox(mRenderingPanel, "Contact points");
checkboxContactPoints->setChecked(mApp->mIsContactPointsDisplayed);
checkboxContactPoints->setCallback([&](bool value) {
mApp->mIsContactPointsDisplayed = value;
});
2015-08-11 16:32:45 +00:00
// Display/Hide the AABBs
CheckBox* checkboxAABBs = new CheckBox(mRenderingPanel, "AABBs");
checkboxAABBs->setChecked(mApp->mIsAABBsDisplayed);
checkboxAABBs->setCallback([&](bool value) {
mApp->mIsAABBsDisplayed = value;
});
2015-08-06 19:06:35 +00:00
// Enabled/Disable VSync
2016-02-28 20:39:39 +00:00
CheckBox* checkboxVSync = new CheckBox(mRenderingPanel, "V-Sync");
checkboxVSync->setChecked(mApp->mIsVSyncEnabled);
checkboxVSync->setCallback([&](bool value) {
mApp->enableVSync(value);
2016-02-28 20:39:39 +00:00
});
2015-08-06 19:06:35 +00:00
// Enabled/Disable Shadows
2016-02-28 20:39:39 +00:00
CheckBox* checkboxShadows = new CheckBox(mRenderingPanel, "Shadows");
checkboxShadows->setChecked(mApp->mIsShadowMappingEnabled);
checkboxShadows->setCallback([&](bool value) {
mApp->mIsShadowMappingEnabled = value;
});
// Enable/Disable wireframe mode
CheckBox* checkboxWireframe = new CheckBox(mRenderingPanel, "Wireframe");
checkboxWireframe->setChecked(mApp->mIsWireframeEnabled);
checkboxWireframe->setCallback([&](bool value) {
mApp->mIsWireframeEnabled = value;
});
2016-02-28 20:39:39 +00:00
mPhysicsPanel->setVisible(true);
mRenderingPanel->setVisible(false);
}
2016-02-28 20:39:39 +00:00
void Gui::createProfilingPanel() {
2015-08-06 19:06:35 +00:00
2016-02-28 20:39:39 +00:00
Widget* profilingPanel = new Window(mApp, "Profiling");
2016-03-03 20:46:45 +00:00
profilingPanel->setPosition(Vector2i(15, 525));
2016-02-28 20:39:39 +00:00
profilingPanel->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 5));
profilingPanel->setId("SettingsPanel");
profilingPanel->setFixedWidth(220);
2015-08-06 19:06:35 +00:00
// Framerate (FPS)
2016-02-28 20:39:39 +00:00
mFPSLabel = new Label(profilingPanel, std::string("FPS : ") + floatToString(mCachedFPS, 0),"sans-bold");
2015-08-06 19:06:35 +00:00
// Update time
mFrameTimeLabel = new Label(profilingPanel, std::string("Frame time : ") + floatToString(mCachedUpdateTime * 1000.0, 1) + std::string(" ms"),"sans-bold");
2016-02-28 20:39:39 +00:00
// Update time
mPhysicsTimeLabel = new Label(profilingPanel, std::string("Physics time : ") + floatToString(mCachedPhysicsUpdateTime * 1000.0, 1) + std::string(" ms"),"sans-bold");
2016-02-28 20:39:39 +00:00
profilingPanel->setVisible(true);
}
2016-02-28 20:39:39 +00:00