Switch the Testbed GUI architecture pattern to MVVM (Model-View-ModelView).
This commit is contained in:
Irlan 2018-04-13 14:18:02 -03:00
parent b9b23de3a0
commit 4570c971c0
12 changed files with 475 additions and 504 deletions

View File

@ -24,15 +24,19 @@
// error
#endif
#include <glfw/glfw3.h>
#include <testbed/framework/model.h>
#include <testbed/framework/view.h>
#include <testbed/framework/view_model.h>
//
GLFWwindow* g_window;
static GLFWwindow* g_window;
//
Model* g_model;
View* g_view;
static Model* g_model;
static View* g_view;
static ViewModel* g_viewModel;
static void WindowSize(GLFWwindow* ww, int w, int h)
{
@ -103,9 +107,9 @@ static void Run()
g_profiler->PushEvent("Frame");
g_view->Command_PreDraw();
g_view->BeginInterface();
if (g_settings->pause)
if (g_model->IsPaused())
{
g_draw->DrawString(b3Color_white, "*PAUSED*");
}
@ -124,11 +128,11 @@ static void Run()
}
}
g_view->Command_Draw();
g_view->Interface();
g_model->Command_Step();
g_model->Update();
g_view->Command_PostDraw();
g_view->EndInterface();
g_profiler->PopEvent();
@ -183,12 +187,16 @@ int main(int argc, char** args)
//
g_model = new Model();
g_view = new View(g_window, g_model);
g_view = new View(g_window);
g_viewModel = new ViewModel(g_model, g_view);
// Run
Run();
//
delete g_viewModel;
g_viewModel = nullptr;
delete g_view;
g_view = nullptr;

View File

@ -17,13 +17,12 @@
*/
#include <testbed/framework/model.h>
Settings* g_settings = nullptr;
#include <testbed/framework/view_model.h>
#include <testbed/framework/test.h>
Model::Model()
{
g_settings = &m_settings;
g_testSettings = &m_testSettings;
m_viewModel = nullptr;
g_draw = &m_draw;
g_camera = &m_camera;
g_profiler = &m_profiler;
@ -42,43 +41,80 @@ Model::Model()
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
glClearDepth(1.0f);
Action_DefaultCamera();
Action_ResetCamera();
m_setTest = true;
m_pause = true;
m_singlePlay = false;
}
Model::~Model()
{
g_testSettings = nullptr;
g_draw = nullptr;
g_camera = nullptr;
g_profiler = nullptr;
g_profilerRecorder = nullptr;
g_profilerListener = nullptr;
g_testSettings = nullptr;
delete m_test;
}
void Model::Command_Step()
void Model::Action_SaveTest()
{
m_test->Save();
}
void Model::Command_Press_Key(int button)
{
m_test->KeyDown(button);
}
void Model::Command_Release_Key(int button)
{
m_test->KeyUp(button);
}
void Model::Command_Press_Mouse_Left(const b3Vec2& ps)
{
Ray3 pw = m_camera.ConvertScreenToWorld(ps);
m_test->MouseLeftDown(pw);
}
void Model::Command_Release_Mouse_Left(const b3Vec2& ps)
{
Ray3 pw = m_camera.ConvertScreenToWorld(ps);
m_test->MouseLeftUp(pw);
}
void Model::Command_Move_Cursor(const b3Vec2& ps)
{
Ray3 pw = m_camera.ConvertScreenToWorld(ps);
m_test->MouseMove(pw);
}
void Model::Update()
{
g_drawFlags = 0;
g_drawFlags += m_settings.drawPoints * DrawFlags::e_pointsFlag;
g_drawFlags += m_settings.drawLines * DrawFlags::e_linesFlag;
g_drawFlags += m_settings.drawTriangles * DrawFlags::e_trianglesFlag;
g_drawFlags += g_settings->drawPoints * DrawFlags::e_pointsFlag;
g_drawFlags += g_settings->drawLines * DrawFlags::e_linesFlag;
g_drawFlags += g_settings->drawTriangles * DrawFlags::e_trianglesFlag;
glViewport(0, 0, GLsizei(m_camera.m_width), GLsizei(m_camera.m_height));
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (m_settings.testID != m_settings.lastTestID)
if (m_setTest)
{
delete m_test;
m_settings.lastTestID = m_settings.testID;
m_test = g_tests[m_settings.testID].create();
m_settings.pause = true;
Action_DefaultCamera();
m_test = g_tests[g_settings->testID].create();
m_setTest = false;
m_pause = true;
Action_ResetCamera();
}
if (m_settings.drawGrid)
if (g_settings->drawGrid)
{
b3Color color(0.2f, 0.2f, 0.2f, 1.0f);
@ -114,19 +150,25 @@ void Model::Command_Step()
}
//
m_testSettings.inv_hertz = m_testSettings.hertz != 0.0f ? 1.0f / m_testSettings.hertz : 0.0f;
if (m_settings.pause)
if (m_pause)
{
if (m_settings.singleStep)
if (m_singlePlay)
{
m_settings.singleStep = false;
// !
g_testSettings->inv_hertz = g_testSettings->hertz > 0.0f ? 1.0f / g_testSettings->hertz : 0.0f;
m_singlePlay = false;
}
else
{
m_testSettings.inv_hertz = 0.0f;
// !
g_testSettings->inv_hertz = 0.0f;
}
}
else
{
// !
g_testSettings->inv_hertz = g_testSettings->hertz > 0.0f ? 1.0f / g_testSettings->hertz : 0.0f;
}
m_test->Step();

View File

@ -21,40 +21,10 @@
#include <testbed/framework/draw.h>
#include <testbed/framework/testbed_listener.h>
#include <testbed/framework/test.h>
struct Settings
{
Settings()
{
lastTestID = -1;
testID = 0;
pause = false;
singleStep = false;
drawPoints = true;
drawLines = true;
drawTriangles = true;
drawGrid = true;
drawProfile = false;
drawStats = false;
}
class Test;
int lastTestID;
int testID;
bool pause;
bool singleStep;
bool drawPoints;
bool drawLines;
bool drawTriangles;
bool drawGrid;
bool drawProfile;
bool drawStats;
};
//
extern Settings* g_settings;
class ViewModel;
class Model
{
@ -64,88 +34,59 @@ public:
~Model();
void Action_SaveTest();
void Action_SelectTest(int selection);
void Action_RestartTest();
void Action_PreviousTest();
void Action_NextTest();
void Action_SetTest();
void Action_PlayPause();
void Action_SingleStep();
void Action_DefaultCamera();
void Action_LeftCamera();
void Action_RightCamera();
void Action_BottomCamera();
void Action_TopCamera();
void Action_BackCamera();
void Action_FrontCamera();
void Action_SinglePlay();
void Action_ResetCamera();
void Command_Step();
void Command_Press_Key(int button);
void Command_Release_Key(int button);
void Command_Press_Mouse_Left(const b3Vec2& ps);
void Command_Release_Mouse_Left(const b3Vec2& ps);
void Command_Move_Cursor(const b3Vec2& ps);
void Command_ResizeCamera(float32 w, float32 h);
void Command_RotateCameraX(float32 angle);
void Command_RotateCameraY(float32 angle);
void Command_TranslateCameraX(float32 d);
void Command_TranslateCameraY(float32 d);
void Command_ZoomCamera(float32 d);
void Update();
bool IsPaused() const { return m_pause; }
private:
friend class View;
friend class ViewModel;
// UI State
Settings m_settings;
TestSettings m_testSettings;
ViewModel* m_viewModel;
// App State
Draw m_draw;
Camera m_camera;
Profiler m_profiler;
TestbedListener m_profilerListener;
Test* m_test;
bool m_setTest;
bool m_pause;
bool m_singlePlay;
};
inline void Model::Action_SelectTest(int selection)
inline void Model::Action_SetTest()
{
m_settings.testID = selection;
m_settings.lastTestID = -1;
}
inline void Model::Action_RestartTest()
{
m_settings.lastTestID = -1;
}
inline void Model::Action_PreviousTest()
{
m_settings.testID = b3Clamp(m_settings.testID - 1, 0, int(g_testCount) - 1);
m_settings.lastTestID = -1;
}
inline void Model::Action_NextTest()
{
m_settings.testID = b3Clamp(m_settings.testID + 1, 0, int(g_testCount) - 1);
m_settings.lastTestID = -1;
}
inline void Model::Action_SaveTest()
{
m_test->Save();
m_setTest = true;
}
inline void Model::Action_PlayPause()
{
m_settings.pause = !m_settings.pause;
m_pause = !m_pause;
}
inline void Model::Action_SingleStep()
inline void Model::Action_SinglePlay()
{
m_settings.pause = true;
m_settings.singleStep = true;
m_pause = true;
m_singlePlay = true;
}
inline void Model::Action_DefaultCamera()
inline void Model::Action_ResetCamera()
{
m_camera.m_q = b3QuatRotationX(-0.125f * B3_PI);
@ -157,79 +98,6 @@ inline void Model::Action_DefaultCamera()
m_camera.m_zoom = 50.0f;
}
inline void Model::Action_LeftCamera()
{
m_camera.m_q = b3QuatRotationX(0.5f * B3_PI);
m_camera.m_center.SetZero();
m_camera.m_zoom = 50.0f;
}
inline void Model::Action_RightCamera()
{
m_camera.m_q = b3QuatRotationX(-0.5f * B3_PI);
m_camera.m_center.SetZero();
m_camera.m_zoom = 50.0f;
}
inline void Model::Action_BottomCamera()
{
m_camera.m_q = b3QuatRotationX(0.5f * B3_PI);
m_camera.m_center.SetZero();
m_camera.m_zoom = 50.0f;
}
inline void Model::Action_TopCamera()
{
m_camera.m_q = b3QuatRotationX(-0.5f * B3_PI);
m_camera.m_center.SetZero();
m_camera.m_zoom = 50.0f;
}
inline void Model::Action_BackCamera()
{
m_camera.m_q = b3QuatRotationX(-B3_PI);
m_camera.m_center.SetZero();
m_camera.m_zoom = 50.0f;
}
inline void Model::Action_FrontCamera()
{
m_camera.m_q.SetIdentity();
m_camera.m_center.SetZero();
m_camera.m_zoom = 50.0f;
}
inline void Model::Command_Press_Key(int button)
{
m_test->KeyDown(button);
}
inline void Model::Command_Release_Key(int button)
{
m_test->KeyUp(button);
}
inline void Model::Command_Press_Mouse_Left(const b3Vec2& ps)
{
Ray3 pw = m_camera.ConvertScreenToWorld(ps);
m_test->MouseLeftDown(pw);
}
inline void Model::Command_Release_Mouse_Left(const b3Vec2& ps)
{
Ray3 pw = m_camera.ConvertScreenToWorld(ps);
m_test->MouseLeftUp(pw);
}
inline void Model::Command_Move_Cursor(const b3Vec2& ps)
{
Ray3 pw = m_camera.ConvertScreenToWorld(ps);
m_test->MouseMove(pw);
}
inline void Model::Command_ResizeCamera(float32 w, float32 h)
{
m_camera.m_width = w;

View File

@ -1,143 +0,0 @@
/*
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
*
* 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.
*/
#include <testbed/framework/presenter.h>
#include <testbed/framework/model.h>
#include <testbed/framework/view.h>
// !
static inline b3Vec2 GetCursorPosition()
{
extern GLFWwindow* g_window;
double x, y;
glfwGetCursorPos(g_window, &x, &y);
return b3Vec2(float32(x), float32(y));
}
Presenter::Presenter(Model* model, View* view)
{
m_model = model;
m_view = view;
}
Presenter::~Presenter()
{
}
void Presenter::Event_SetWindowSize(float w, float h)
{
m_model->Command_ResizeCamera(w, h);
}
void Presenter::Event_Press_Key(int button)
{
if (m_view->m_shiftDown)
{
if (button == GLFW_KEY_DOWN)
{
m_model->Command_ZoomCamera(1.0f);
}
if (button == GLFW_KEY_UP)
{
m_model->Command_ZoomCamera(-1.0f);
}
}
else
{
m_model->Command_Press_Key(button);
}
}
void Presenter::Event_Release_Key(int button)
{
if (!m_view->m_shiftDown)
{
m_model->Command_Release_Key(button);
}
}
void Presenter::Event_Press_Mouse(int button)
{
if (button == GLFW_MOUSE_BUTTON_LEFT)
{
if (!m_view->m_shiftDown)
{
m_model->Command_Press_Mouse_Left(GetCursorPosition());
}
}
}
void Presenter::Event_Release_Mouse(int button)
{
if (button == GLFW_MOUSE_BUTTON_LEFT)
{
if (!m_view->m_shiftDown)
{
m_model->Command_Release_Mouse_Left(GetCursorPosition());
}
}
}
void Presenter::Event_Move_Cursor(float x, float y)
{
b3Vec2 ps;
ps.Set(x, y);
b3Vec2 dp = ps - m_view->m_ps0;
float32 ndx = b3Clamp(dp.x, -1.0f, 1.0f);
float32 ndy = b3Clamp(dp.y, -1.0f, 1.0f);
if (m_view->m_shiftDown)
{
if (m_view->m_leftDown)
{
float32 ax = -0.005f * B3_PI * ndx;
float32 ay = -0.005f * B3_PI * ndy;
m_model->Command_RotateCameraY(ax);
m_model->Command_RotateCameraX(ay);
}
if (m_view->m_rightDown)
{
float32 tx = 0.2f * ndx;
float32 ty = -0.2f * ndy;
m_model->Command_TranslateCameraX(tx);
m_model->Command_TranslateCameraY(ty);
}
}
else
{
m_model->Command_Move_Cursor(GetCursorPosition());
}
}
void Presenter::Event_Scroll(float dx, float dy)
{
if (m_view->m_shiftDown)
{
float32 ny = b3Clamp(dy, -1.0f, 1.0f);
m_model->Command_ZoomCamera(1.0f * ny);
}
}

View File

@ -1,47 +0,0 @@
/*
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
*
* 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.
*/
#ifndef PRESENTER_H
#define PRESENTER_H
class Model;
class View;
class Presenter
{
public:
Presenter(Model* model, View* view);
~Presenter();
void Event_SetWindowSize(float w, float h);
void Event_Press_Key(int button);
void Event_Release_Key(int button);
void Event_Press_Mouse(int button);
void Event_Release_Mouse(int button);
void Event_Move_Cursor(float x, float y);
void Event_Scroll(float dx, float dy);
private:
friend class Model;
friend class View;
Model* m_model;
View* m_view;
};
#endif

View File

@ -17,7 +17,8 @@
*/
#include <testbed/framework/test.h>
#include <testbed/framework/model.h>
#include <testbed/framework/profiler.h>
#include <imgui/imgui.h>
extern u32 b3_allocCalls, b3_maxAllocCalls;
extern u32 b3_gjkCalls, b3_gjkIters, b3_gjkMaxIters;
@ -34,8 +35,6 @@ void b3PopProfileScope()
g_profiler->PopEvent();
}
TestSettings* g_testSettings = nullptr;
Test::Test() : m_bodyDragger(&m_bodyRay, &m_world)
{
b3_allocCalls = 0;

View File

@ -20,13 +20,10 @@
#define TEST_H
#include <glfw/glfw3.h>
#include <imgui/imgui.h>
#include <bounce/bounce.h>
#include <testbed/framework/draw.h>
#include <testbed/framework/profiler.h>
#include <testbed/framework/recorder_profiler.h>
#include <testbed/framework/view_model.h>
inline float32 RandomFloat(float32 a, float32 b)
{
@ -36,46 +33,6 @@ inline float32 RandomFloat(float32 a, float32 b)
return a + r;
}
struct TestSettings
{
TestSettings()
{
hertz = 60.0f;
inv_hertz = 1.0f / hertz;
velocityIterations = 8;
positionIterations = 2;
sleep = false;
warmStart = true;
convexCache = true;
drawCenterOfMasses = true;
drawShapes = true;
drawBounds = false;
drawJoints = true;
drawContactPoints = true;
drawContactNormals = false;
drawContactTangents = false;
drawContactPolygons = false;
}
float hertz, inv_hertz;
int velocityIterations;
int positionIterations;
bool sleep;
bool warmStart;
bool convexCache;
bool drawCenterOfMasses;
bool drawBounds;
bool drawShapes;
bool drawJoints;
bool drawContactPoints;
bool drawContactNormals;
bool drawContactTangents;
bool drawContactPolygons;
};
extern TestSettings* g_testSettings;
class RayCastListener : public b3RayCastListener
{
public:

View File

@ -17,8 +17,10 @@
*/
#include <testbed/framework/view.h>
#include <testbed/framework/model.h>
#include <testbed/framework/view_model.h>
#include <testbed/framework/test.h>
#include <imgui/imgui.h>
#if defined (U_OPENGL_2)
#include <imgui/imgui_impl_glfw_gl2.h>
#elif defined (U_OPENGL_4)
@ -28,7 +30,7 @@
#include <glfw/glfw3.h>
static bool GetTestName(void* userData, int idx, const char** name)
static inline bool GetTestName(void* userData, int idx, const char** name)
{
assert(u32(idx) < g_testCount);
*name = g_tests[idx].name;
@ -111,8 +113,9 @@ static inline void ImGui_GLFW_GL_RenderDrawData(ImDrawData* draw_data)
}
View::View(GLFWwindow* window, Model* model) : m_presenter(model, this)
View::View(GLFWwindow* window)
{
m_viewModel = nullptr;
m_window = window;
// Create UI
@ -127,9 +130,6 @@ View::View(GLFWwindow* window, Model* model) : m_presenter(model, this)
ImGui::StyleColorsDark();
m_leftDown = false;
m_rightDown = false;
m_shiftDown = false;
m_ps0.SetZero();
}
@ -141,88 +141,60 @@ View::~View()
ImGui::DestroyContext();
}
b3Vec2 View::GetCursorPosition() const
{
double x, y;
glfwGetCursorPos(m_window, &x, &y);
return b3Vec2(float32(x), float32(y));
}
void View::Event_SetWindowSize(int w, int h)
{
m_presenter.Event_SetWindowSize(float32(w), float32(h));
m_viewModel->Event_SetWindowSize(w, h);
}
void View::Event_Press_Key(int button)
{
if (button == GLFW_KEY_LEFT_SHIFT)
{
m_shiftDown = true;
}
m_presenter.Event_Press_Key(button);
m_viewModel->Event_Press_Key(button);
}
void View::Event_Release_Key(int button)
{
if (button == GLFW_KEY_LEFT_SHIFT)
{
m_shiftDown = false;
}
m_presenter.Event_Release_Key(button);
m_viewModel->Event_Release_Key(button);
}
void View::Event_Press_Mouse(int button)
{
if (button == GLFW_MOUSE_BUTTON_LEFT)
{
m_leftDown = true;
}
if (button == GLFW_MOUSE_BUTTON_RIGHT)
{
m_rightDown = true;
}
m_presenter.Event_Press_Mouse(button);
m_viewModel->Event_Press_Mouse(button);
}
void View::Event_Release_Mouse(int button)
{
if (button == GLFW_MOUSE_BUTTON_LEFT)
{
m_leftDown = false;
}
if (button == GLFW_MOUSE_BUTTON_RIGHT)
{
m_rightDown = false;
}
m_presenter.Event_Release_Mouse(button);
m_viewModel->Event_Release_Mouse(button);
}
void View::Event_Move_Cursor(float x, float y)
{
b3Vec2 ps(x, y);
m_presenter.Event_Move_Cursor(ps.x, ps.y);
m_ps0 = ps;
m_viewModel->Event_Move_Cursor(x, y);
m_ps0.Set(x, y);
}
void View::Event_Scroll(float dx, float dy)
{
m_presenter.Event_Scroll(dx, dy);
m_viewModel->Event_Scroll(dx, dy);
}
void View::Command_PreDraw()
void View::BeginInterface()
{
ImGui_GLFW_GL_NewFrame();
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
}
void View::Command_Draw()
void View::Interface()
{
Model* model = m_presenter.m_model;
Settings& settings = model->m_settings;
TestSettings& testSettings = model->m_testSettings;
Camera& camera = model->m_camera;
Settings& settings = m_viewModel->m_settings;
TestSettings& testSettings = m_viewModel->m_testSettings;
bool openControls = false;
bool openAbout = false;
@ -232,7 +204,7 @@ void View::Command_Draw()
{
if (ImGui::MenuItem("Save"))
{
model->Action_SaveTest();
m_viewModel->Action_SaveTest();
}
ImGui::Separator();
@ -354,7 +326,7 @@ void View::Command_Draw()
if (ImGui::Combo("##Test", &settings.testID, GetTestName, NULL, g_testCount, g_testCount))
{
model->Action_SelectTest(settings.testID);
m_viewModel->Action_SetTest();
}
ImGui::PopItemWidth();
@ -365,38 +337,38 @@ void View::Command_Draw()
if (ImGui::Button("Previous", menuButtonSize))
{
model->Action_PreviousTest();
m_viewModel->Action_PreviousTest();
}
if (ImGui::Button("Next", menuButtonSize))
{
model->Action_NextTest();
m_viewModel->Action_NextTest();
}
ImGui::Separator();
if (ImGui::Button("Play/Pause", menuButtonSize))
{
model->Action_PlayPause();
m_viewModel->Action_PlayPause();
}
if (ImGui::Button("Single Step", menuButtonSize))
if (ImGui::Button("Single Play", menuButtonSize))
{
model->Action_SingleStep();
m_viewModel->Action_SinglePlay();
}
ImGui::Separator();
if (ImGui::Button("Restart", menuButtonSize))
{
model->Action_RestartTest();
m_viewModel->Action_SetTest();
}
ImGui::Separator();
if (ImGui::Button("Reset Camera", menuButtonSize))
{
model->Action_DefaultCamera();
m_viewModel->Action_ResetCamera();
}
ImGui::EndMenuBar();
@ -406,8 +378,8 @@ void View::Command_Draw()
ImGui::PopStyleVar();
ImGui::SetNextWindowPos(ImVec2(camera.m_width - 250.0f, 40.0f));
ImGui::SetNextWindowSize(ImVec2(250.0f, camera.m_height - 40.0f));
ImGui::SetNextWindowPos(ImVec2(g_camera->m_width - 250.0f, 40.0f));
ImGui::SetNextWindowSize(ImVec2(250.0f, g_camera->m_height - 40.0f));
ImGui::Begin("Test Settings", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize);
ImGui::PushItemWidth(-1.0f);
@ -430,7 +402,7 @@ void View::Command_Draw()
ImGui::End();
}
void View::Command_PostDraw()
void View::EndInterface()
{
ImGui::PopStyleVar();

View File

@ -20,17 +20,15 @@
#define VIEW_H
#include <bounce/common/math/vec2.h>
#include <testbed/framework/presenter.h>
struct GLFWwindow;
class Model;
class ViewModel;
class View
{
public:
View(GLFWwindow* window, Model* model);
View(GLFWwindow* window);
~View();
void Event_SetWindowSize(int w, int h);
@ -41,20 +39,18 @@ public:
void Event_Move_Cursor(float x, float y);
void Event_Scroll(float dx, float dy);
void Command_PreDraw();
void Command_Draw();
void Command_PostDraw();
void BeginInterface();
void Interface();
void EndInterface();
private:
friend class Presenter;
friend class ViewModel;
Presenter m_presenter;
b3Vec2 GetCursorPosition() const;
ViewModel* m_viewModel;
GLFWwindow* m_window;
bool m_leftDown;
bool m_rightDown;
bool m_shiftDown;
b3Vec2 m_ps0;
// Ray3 m_ray0;
};
#endif

View File

@ -0,0 +1,192 @@
/*
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
*
* 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.
*/
#include <testbed/framework/view_model.h>
#include <testbed/framework/model.h>
#include <testbed/framework/view.h>
#include <testbed/framework/test.h>
#include <glfw/glfw3.h>
TestSettings* g_testSettings = nullptr;
Settings* g_settings = nullptr;
ViewModel::ViewModel(Model* model, View* view)
{
m_model = model;
assert(m_model->m_viewModel == nullptr);
m_model->m_viewModel = this;
m_view = view;
assert(m_view->m_viewModel == nullptr);
m_view->m_viewModel = this;
g_settings = &m_settings;
g_testSettings = &m_testSettings;
}
ViewModel::~ViewModel()
{
g_settings = nullptr;
g_testSettings = nullptr;
}
void ViewModel::Action_SaveTest()
{
m_model->Action_SaveTest();
}
void ViewModel::Action_SetTest()
{
m_model->Action_SetTest();
}
void ViewModel::Action_PreviousTest()
{
m_settings.testID = b3Clamp(m_settings.testID - 1, 0, int(g_testCount) - 1);
m_model->Action_SetTest();
}
void ViewModel::Action_NextTest()
{
m_settings.testID = b3Clamp(m_settings.testID + 1, 0, int(g_testCount) - 1);
m_model->Action_SetTest();
}
void ViewModel::Action_PlayPause()
{
m_model->Action_PlayPause();
}
void ViewModel::Action_SinglePlay()
{
m_model->Action_SinglePlay();
}
void ViewModel::Action_ResetCamera()
{
m_model->Action_ResetCamera();
}
void ViewModel::Event_SetWindowSize(int w, int h)
{
m_model->Command_ResizeCamera(float32(w), float32(h));
}
void ViewModel::Event_Press_Key(int button)
{
bool shiftDown = glfwGetKey(m_view->m_window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS;
if (shiftDown)
{
if (button == GLFW_KEY_DOWN)
{
m_model->Command_ZoomCamera(1.0f);
}
if (button == GLFW_KEY_UP)
{
m_model->Command_ZoomCamera(-1.0f);
}
}
else
{
m_model->Command_Press_Key(button);
}
}
void ViewModel::Event_Release_Key(int button)
{
bool shiftDown = glfwGetKey(m_view->m_window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS;
if (!shiftDown)
{
m_model->Command_Release_Key(button);
}
}
void ViewModel::Event_Press_Mouse(int button)
{
if (button == GLFW_MOUSE_BUTTON_LEFT)
{
bool shiftDown = glfwGetKey(m_view->m_window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS;
if (!shiftDown)
{
m_model->Command_Press_Mouse_Left(m_view->GetCursorPosition());
}
}
}
void ViewModel::Event_Release_Mouse(int button)
{
if (button == GLFW_MOUSE_BUTTON_LEFT)
{
bool shiftDown = glfwGetKey(m_view->m_window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS;
if (!shiftDown)
{
m_model->Command_Release_Mouse_Left(m_view->GetCursorPosition());
}
}
}
void ViewModel::Event_Move_Cursor(float x, float y)
{
b3Vec2 ps;
ps.Set(x, y);
b3Vec2 dp = ps - m_view->m_ps0;
float32 ndx = b3Clamp(dp.x, -1.0f, 1.0f);
float32 ndy = b3Clamp(dp.y, -1.0f, 1.0f);
bool shiftDown = glfwGetKey(m_view->m_window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS;
bool leftDown = glfwGetMouseButton(m_view->m_window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS;
bool rightDown = glfwGetMouseButton(m_view->m_window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS;
if (shiftDown)
{
if (leftDown)
{
float32 ax = -0.005f * B3_PI * ndx;
float32 ay = -0.005f * B3_PI * ndy;
m_model->Command_RotateCameraY(ax);
m_model->Command_RotateCameraX(ay);
}
if (rightDown)
{
float32 tx = 0.2f * ndx;
float32 ty = -0.2f * ndy;
m_model->Command_TranslateCameraX(tx);
m_model->Command_TranslateCameraY(ty);
}
}
else
{
m_model->Command_Move_Cursor(m_view->GetCursorPosition());
}
}
void ViewModel::Event_Scroll(float dx, float dy)
{
bool shiftDown = glfwGetKey(m_view->m_window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS;
if (shiftDown)
{
float32 ny = b3Clamp(dy, -1.0f, 1.0f);
m_model->Command_ZoomCamera(1.0f * ny);
}
}

View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
*
* 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.
*/
#ifndef VIEW_MODEL_H
#define VIEW_MODEL_H
class Model;
class View;
//
struct Settings
{
Settings()
{
testID = 0;
drawPoints = true;
drawLines = true;
drawTriangles = true;
drawGrid = true;
drawProfile = false;
drawStats = false;
}
int testID;
bool drawPoints;
bool drawLines;
bool drawTriangles;
bool drawGrid;
bool drawProfile;
bool drawStats;
};
//
extern Settings* g_settings;
//
struct TestSettings
{
TestSettings()
{
hertz = 60.0f;
inv_hertz = 1.0f / hertz;
velocityIterations = 8;
positionIterations = 2;
sleep = false;
warmStart = true;
convexCache = true;
drawCenterOfMasses = true;
drawShapes = true;
drawBounds = false;
drawJoints = true;
drawContactPoints = true;
drawContactNormals = false;
drawContactTangents = false;
drawContactPolygons = false;
}
float hertz, inv_hertz;
int velocityIterations;
int positionIterations;
bool sleep;
bool warmStart;
bool convexCache;
bool drawCenterOfMasses;
bool drawBounds;
bool drawShapes;
bool drawJoints;
bool drawContactPoints;
bool drawContactNormals;
bool drawContactTangents;
bool drawContactPolygons;
};
//
extern TestSettings* g_testSettings;
class ViewModel
{
public:
ViewModel(Model* model, View* view);
~ViewModel();
void Action_SaveTest();
void Action_SetTest();
void Action_PreviousTest();
void Action_NextTest();
void Action_PlayPause();
void Action_SinglePlay();
void Action_ResetCamera();
void Event_SetWindowSize(int w, int h);
void Event_Press_Key(int button);
void Event_Release_Key(int button);
void Event_Press_Mouse(int button);
void Event_Release_Mouse(int button);
void Event_Move_Cursor(float x, float y);
void Event_Scroll(float dx, float dy);
private:
friend class Model;
friend class View;
Settings m_settings;
TestSettings m_testSettings;
Model* m_model;
View* m_view;
};
#endif

View File

@ -269,7 +269,7 @@ solution (solution_name)
examples_inc_dir .. "/testbed/framework/model.h",
examples_inc_dir .. "/testbed/framework/view.h",
examples_inc_dir .. "/testbed/framework/presenter.h",
examples_inc_dir .. "/testbed/framework/view_model.h",
examples_src_dir .. "/testbed/framework/test.h",
@ -282,7 +282,7 @@ solution (solution_name)
examples_inc_dir .. "/testbed/framework/model.cpp",
examples_inc_dir .. "/testbed/framework/view.cpp",
examples_inc_dir .. "/testbed/framework/presenter.cpp",
examples_inc_dir .. "/testbed/framework/view_model.cpp",
examples_src_dir .. "/testbed/framework/test.cpp",
examples_src_dir .. "/testbed/framework/test_entries.cpp",