|
@@ -22,9 +22,15 @@
|
|
#include <crtdbg.h>
|
|
#include <crtdbg.h>
|
|
#include <Input/Win/KeyboardWin.h>
|
|
#include <Input/Win/KeyboardWin.h>
|
|
#include <Input/Win/MouseWin.h>
|
|
#include <Input/Win/MouseWin.h>
|
|
|
|
+ #include <Window/ApplicationWindowWin.h>
|
|
#elif defined(JPH_PLATFORM_LINUX)
|
|
#elif defined(JPH_PLATFORM_LINUX)
|
|
#include <Input/Linux/KeyboardLinux.h>
|
|
#include <Input/Linux/KeyboardLinux.h>
|
|
#include <Input/Linux/MouseLinux.h>
|
|
#include <Input/Linux/MouseLinux.h>
|
|
|
|
+ #include <Window/ApplicationWindowLinux.h>
|
|
|
|
+#elif defined(JPH_PLATFORM_MACOS)
|
|
|
|
+ #include <Input/MacOS/KeyboardMacOS.h>
|
|
|
|
+ #include <Input/MacOS/MouseMacOS.h>
|
|
|
|
+ #include <Window/ApplicationWindowMacOS.h>
|
|
#endif
|
|
#endif
|
|
|
|
|
|
JPH_GCC_SUPPRESS_WARNING("-Wswitch")
|
|
JPH_GCC_SUPPRESS_WARNING("-Wswitch")
|
|
@@ -65,6 +71,18 @@ Application::Application([[maybe_unused]] const String &inCommandLine) :
|
|
// Disable allocation checking
|
|
// Disable allocation checking
|
|
DisableCustomMemoryHook dcmh;
|
|
DisableCustomMemoryHook dcmh;
|
|
|
|
|
|
|
|
+ // Create window
|
|
|
|
+ #ifdef JPH_PLATFORM_WINDOWS
|
|
|
|
+ mWindow = new ApplicationWindowWin;
|
|
|
|
+ #elif defined(JPH_PLATFORM_LINUX)
|
|
|
|
+ mWindow = new ApplicationWindowLinux;
|
|
|
|
+ #elif defined(JPH_PLATFORM_MACOS)
|
|
|
|
+ mWindow = new ApplicationWindowMacOS;
|
|
|
|
+ #else
|
|
|
|
+ #error No window defined
|
|
|
|
+ #endif
|
|
|
|
+ mWindow->Initialize();
|
|
|
|
+
|
|
// Create renderer
|
|
// Create renderer
|
|
#ifdef JPH_ENABLE_VULKAN
|
|
#ifdef JPH_ENABLE_VULKAN
|
|
mRenderer = new RendererVK;
|
|
mRenderer = new RendererVK;
|
|
@@ -73,7 +91,7 @@ Application::Application([[maybe_unused]] const String &inCommandLine) :
|
|
#else
|
|
#else
|
|
#error No renderer defined
|
|
#error No renderer defined
|
|
#endif
|
|
#endif
|
|
- mRenderer->Initialize();
|
|
|
|
|
|
+ mRenderer->Initialize(mWindow);
|
|
|
|
|
|
// Create font
|
|
// Create font
|
|
Font *font = new Font(mRenderer);
|
|
Font *font = new Font(mRenderer);
|
|
@@ -88,20 +106,24 @@ Application::Application([[maybe_unused]] const String &inCommandLine) :
|
|
mKeyboard = new KeyboardWin;
|
|
mKeyboard = new KeyboardWin;
|
|
#elif defined(JPH_PLATFORM_LINUX)
|
|
#elif defined(JPH_PLATFORM_LINUX)
|
|
mKeyboard = new KeyboardLinux;
|
|
mKeyboard = new KeyboardLinux;
|
|
|
|
+ #elif defined(JPH_PLATFORM_MACOS)
|
|
|
|
+ mKeyboard = new KeyboardMacOS;
|
|
#else
|
|
#else
|
|
#error No keyboard defined
|
|
#error No keyboard defined
|
|
#endif
|
|
#endif
|
|
- mKeyboard->Initialize(mRenderer);
|
|
|
|
|
|
+ mKeyboard->Initialize(mWindow);
|
|
|
|
|
|
// Init mouse
|
|
// Init mouse
|
|
#ifdef JPH_PLATFORM_WINDOWS
|
|
#ifdef JPH_PLATFORM_WINDOWS
|
|
mMouse = new MouseWin;
|
|
mMouse = new MouseWin;
|
|
#elif defined(JPH_PLATFORM_LINUX)
|
|
#elif defined(JPH_PLATFORM_LINUX)
|
|
mMouse = new MouseLinux;
|
|
mMouse = new MouseLinux;
|
|
|
|
+ #elif defined(JPH_PLATFORM_MACOS)
|
|
|
|
+ mMouse = new MouseMacOS;
|
|
#else
|
|
#else
|
|
#error No mouse defined
|
|
#error No mouse defined
|
|
#endif
|
|
#endif
|
|
- mMouse->Initialize(mRenderer);
|
|
|
|
|
|
+ mMouse->Initialize(mWindow);
|
|
|
|
|
|
// Init UI
|
|
// Init UI
|
|
mUI = new UIManager(mRenderer);
|
|
mUI = new UIManager(mRenderer);
|
|
@@ -129,6 +151,7 @@ Application::~Application()
|
|
delete mDebugRenderer;
|
|
delete mDebugRenderer;
|
|
mFont = nullptr;
|
|
mFont = nullptr;
|
|
delete mRenderer;
|
|
delete mRenderer;
|
|
|
|
+ delete mWindow;
|
|
}
|
|
}
|
|
|
|
|
|
// Unregisters all types with the factory and cleans up the default material
|
|
// Unregisters all types with the factory and cleans up the default material
|
|
@@ -166,143 +189,147 @@ void Application::Run()
|
|
// Set initial camera position
|
|
// Set initial camera position
|
|
ResetCamera();
|
|
ResetCamera();
|
|
|
|
|
|
- // Main message loop
|
|
|
|
- while (mRenderer->WindowUpdate())
|
|
|
|
- {
|
|
|
|
- // Get new input
|
|
|
|
- mKeyboard->Poll();
|
|
|
|
- mMouse->Poll();
|
|
|
|
|
|
+ // Enter the main loop
|
|
|
|
+ mWindow->MainLoop([this]() { return RenderFrame(); });
|
|
|
|
+}
|
|
|
|
|
|
- // Handle keyboard input
|
|
|
|
- for (EKey key = mKeyboard->GetFirstKey(); key != EKey::Invalid; key = mKeyboard->GetNextKey())
|
|
|
|
- switch (key)
|
|
|
|
- {
|
|
|
|
- case EKey::P:
|
|
|
|
- mIsPaused = !mIsPaused;
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case EKey::O:
|
|
|
|
- mSingleStep = true;
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case EKey::T:
|
|
|
|
- // Dump timing info to file
|
|
|
|
- JPH_PROFILE_DUMP();
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case EKey::Escape:
|
|
|
|
- mDebugUI->ToggleVisibility();
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
|
|
+bool Application::RenderFrame()
|
|
|
|
+{
|
|
|
|
+ // Get new input
|
|
|
|
+ mKeyboard->Poll();
|
|
|
|
+ mMouse->Poll();
|
|
|
|
|
|
- // Calculate delta time
|
|
|
|
- chrono::high_resolution_clock::time_point time = chrono::high_resolution_clock::now();
|
|
|
|
- chrono::microseconds delta = chrono::duration_cast<chrono::microseconds>(time - mLastUpdateTime);
|
|
|
|
- mLastUpdateTime = time;
|
|
|
|
- float clock_delta_time = 1.0e-6f * delta.count();
|
|
|
|
- float world_delta_time = 0.0f;
|
|
|
|
- if (mRequestedDeltaTime <= 0.0f)
|
|
|
|
|
|
+ // Handle keyboard input
|
|
|
|
+ for (EKey key = mKeyboard->GetFirstKey(); key != EKey::Invalid; key = mKeyboard->GetNextKey())
|
|
|
|
+ switch (key)
|
|
{
|
|
{
|
|
- // If no fixed frequency update is requested, update with variable time step
|
|
|
|
- world_delta_time = !mIsPaused || mSingleStep? clock_delta_time : 0.0f;
|
|
|
|
- mResidualDeltaTime = 0.0f;
|
|
|
|
|
|
+ case EKey::P:
|
|
|
|
+ mIsPaused = !mIsPaused;
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case EKey::O:
|
|
|
|
+ mSingleStep = true;
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case EKey::T:
|
|
|
|
+ // Dump timing info to file
|
|
|
|
+ JPH_PROFILE_DUMP();
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case EKey::Escape:
|
|
|
|
+ mDebugUI->ToggleVisibility();
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
- else
|
|
|
|
|
|
+
|
|
|
|
+ // Calculate delta time
|
|
|
|
+ chrono::high_resolution_clock::time_point time = chrono::high_resolution_clock::now();
|
|
|
|
+ chrono::microseconds delta = chrono::duration_cast<chrono::microseconds>(time - mLastUpdateTime);
|
|
|
|
+ mLastUpdateTime = time;
|
|
|
|
+ float clock_delta_time = 1.0e-6f * delta.count();
|
|
|
|
+ float world_delta_time = 0.0f;
|
|
|
|
+ if (mRequestedDeltaTime <= 0.0f)
|
|
|
|
+ {
|
|
|
|
+ // If no fixed frequency update is requested, update with variable time step
|
|
|
|
+ world_delta_time = !mIsPaused || mSingleStep? clock_delta_time : 0.0f;
|
|
|
|
+ mResidualDeltaTime = 0.0f;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ // Else use fixed time steps
|
|
|
|
+ if (mSingleStep)
|
|
{
|
|
{
|
|
- // Else use fixed time steps
|
|
|
|
- if (mSingleStep)
|
|
|
|
|
|
+ // Single step
|
|
|
|
+ world_delta_time = mRequestedDeltaTime;
|
|
|
|
+ }
|
|
|
|
+ else if (!mIsPaused)
|
|
|
|
+ {
|
|
|
|
+ // Calculate how much time has passed since the last render
|
|
|
|
+ world_delta_time = clock_delta_time + mResidualDeltaTime;
|
|
|
|
+ if (world_delta_time < mRequestedDeltaTime)
|
|
{
|
|
{
|
|
- // Single step
|
|
|
|
- world_delta_time = mRequestedDeltaTime;
|
|
|
|
|
|
+ // Too soon, set the residual time and don't update
|
|
|
|
+ mResidualDeltaTime = world_delta_time;
|
|
|
|
+ world_delta_time = 0.0f;
|
|
}
|
|
}
|
|
- else if (!mIsPaused)
|
|
|
|
|
|
+ else
|
|
{
|
|
{
|
|
- // Calculate how much time has passed since the last render
|
|
|
|
- world_delta_time = clock_delta_time + mResidualDeltaTime;
|
|
|
|
- if (world_delta_time < mRequestedDeltaTime)
|
|
|
|
- {
|
|
|
|
- // Too soon, set the residual time and don't update
|
|
|
|
- mResidualDeltaTime = world_delta_time;
|
|
|
|
- world_delta_time = 0.0f;
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- // Update and clamp the residual time to a full update to avoid spiral of death
|
|
|
|
- mResidualDeltaTime = min(mRequestedDeltaTime, world_delta_time - mRequestedDeltaTime);
|
|
|
|
- world_delta_time = mRequestedDeltaTime;
|
|
|
|
- }
|
|
|
|
|
|
+ // Update and clamp the residual time to a full update to avoid spiral of death
|
|
|
|
+ mResidualDeltaTime = min(mRequestedDeltaTime, world_delta_time - mRequestedDeltaTime);
|
|
|
|
+ world_delta_time = mRequestedDeltaTime;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- mSingleStep = false;
|
|
|
|
|
|
+ }
|
|
|
|
+ mSingleStep = false;
|
|
|
|
|
|
- // Clear debug lines if we're going to step
|
|
|
|
- if (world_delta_time > 0.0f)
|
|
|
|
- ClearDebugRenderer();
|
|
|
|
|
|
+ // Clear debug lines if we're going to step
|
|
|
|
+ if (world_delta_time > 0.0f)
|
|
|
|
+ ClearDebugRenderer();
|
|
|
|
|
|
- {
|
|
|
|
- JPH_PROFILE("UpdateFrame");
|
|
|
|
- if (!UpdateFrame(world_delta_time))
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Draw coordinate axis
|
|
|
|
- if (mDebugRendererCleared)
|
|
|
|
- mDebugRenderer->DrawCoordinateSystem(RMat44::sIdentity());
|
|
|
|
|
|
+ {
|
|
|
|
+ JPH_PROFILE("UpdateFrame");
|
|
|
|
+ if (!UpdateFrame(world_delta_time))
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
|
|
- // For next frame: mark that we haven't cleared debug stuff
|
|
|
|
- mDebugRendererCleared = false;
|
|
|
|
|
|
+ // Draw coordinate axis
|
|
|
|
+ if (mDebugRendererCleared)
|
|
|
|
+ mDebugRenderer->DrawCoordinateSystem(RMat44::sIdentity());
|
|
|
|
|
|
- // Update the camera position
|
|
|
|
- if (!mUI->IsVisible())
|
|
|
|
- UpdateCamera(clock_delta_time);
|
|
|
|
|
|
+ // For next frame: mark that we haven't cleared debug stuff
|
|
|
|
+ mDebugRendererCleared = false;
|
|
|
|
|
|
- // Start rendering
|
|
|
|
- mRenderer->BeginFrame(mWorldCamera, GetWorldScale());
|
|
|
|
|
|
+ // Update the camera position
|
|
|
|
+ if (!mUI->IsVisible())
|
|
|
|
+ UpdateCamera(clock_delta_time);
|
|
|
|
|
|
- // Draw from light
|
|
|
|
- static_cast<DebugRendererImp *>(mDebugRenderer)->DrawShadowPass();
|
|
|
|
|
|
+ // Start rendering
|
|
|
|
+ mRenderer->BeginFrame(mWorldCamera, GetWorldScale());
|
|
|
|
|
|
- // Start drawing normally
|
|
|
|
- mRenderer->EndShadowPass();
|
|
|
|
|
|
+ // Draw from light
|
|
|
|
+ static_cast<DebugRendererImp *>(mDebugRenderer)->DrawShadowPass();
|
|
|
|
|
|
- // Draw debug information
|
|
|
|
- static_cast<DebugRendererImp *>(mDebugRenderer)->Draw();
|
|
|
|
|
|
+ // Start drawing normally
|
|
|
|
+ mRenderer->EndShadowPass();
|
|
|
|
|
|
- // Draw the frame rate counter
|
|
|
|
- DrawFPS(clock_delta_time);
|
|
|
|
|
|
+ // Draw debug information
|
|
|
|
+ static_cast<DebugRendererImp *>(mDebugRenderer)->Draw();
|
|
|
|
|
|
- if (mUI->IsVisible())
|
|
|
|
- {
|
|
|
|
- // Send mouse input to UI
|
|
|
|
- bool left_pressed = mMouse->IsLeftPressed();
|
|
|
|
- if (left_pressed && !mLeftMousePressed)
|
|
|
|
- mUI->MouseDown(mMouse->GetX(), mMouse->GetY());
|
|
|
|
- else if (!left_pressed && mLeftMousePressed)
|
|
|
|
- mUI->MouseUp(mMouse->GetX(), mMouse->GetY());
|
|
|
|
- mLeftMousePressed = left_pressed;
|
|
|
|
- mUI->MouseMove(mMouse->GetX(), mMouse->GetY());
|
|
|
|
|
|
+ // Draw the frame rate counter
|
|
|
|
+ DrawFPS(clock_delta_time);
|
|
|
|
|
|
- {
|
|
|
|
- // Disable allocation checking
|
|
|
|
- DisableCustomMemoryHook dcmh;
|
|
|
|
|
|
+ if (mUI->IsVisible())
|
|
|
|
+ {
|
|
|
|
+ // Send mouse input to UI
|
|
|
|
+ bool left_pressed = mMouse->IsLeftPressed();
|
|
|
|
+ if (left_pressed && !mLeftMousePressed)
|
|
|
|
+ mUI->MouseDown(mMouse->GetX(), mMouse->GetY());
|
|
|
|
+ else if (!left_pressed && mLeftMousePressed)
|
|
|
|
+ mUI->MouseUp(mMouse->GetX(), mMouse->GetY());
|
|
|
|
+ mLeftMousePressed = left_pressed;
|
|
|
|
+ mUI->MouseMove(mMouse->GetX(), mMouse->GetY());
|
|
|
|
|
|
- // Update and draw the menu
|
|
|
|
- mUI->Update(clock_delta_time);
|
|
|
|
- mUI->Draw();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
{
|
|
{
|
|
- // Menu not visible, cancel any mouse operations
|
|
|
|
- mUI->MouseCancel();
|
|
|
|
|
|
+ // Disable allocation checking
|
|
|
|
+ DisableCustomMemoryHook dcmh;
|
|
|
|
+
|
|
|
|
+ // Update and draw the menu
|
|
|
|
+ mUI->Update(clock_delta_time);
|
|
|
|
+ mUI->Draw();
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ // Menu not visible, cancel any mouse operations
|
|
|
|
+ mUI->MouseCancel();
|
|
|
|
+ }
|
|
|
|
|
|
- // Show the frame
|
|
|
|
- mRenderer->EndFrame();
|
|
|
|
|
|
+ // Show the frame
|
|
|
|
+ mRenderer->EndFrame();
|
|
|
|
|
|
- // Notify of next frame
|
|
|
|
- JPH_PROFILE_NEXTFRAME();
|
|
|
|
- }
|
|
|
|
|
|
+ // Notify of next frame
|
|
|
|
+ JPH_PROFILE_NEXTFRAME();
|
|
|
|
+
|
|
|
|
+ return true;
|
|
}
|
|
}
|
|
|
|
|
|
void Application::GetCameraLocalHeadingAndPitch(float &outHeading, float &outPitch)
|
|
void Application::GetCameraLocalHeadingAndPitch(float &outHeading, float &outPitch)
|
|
@@ -395,7 +422,7 @@ void Application::DrawFPS(float inDeltaTime)
|
|
int text_h = int(text_size.y * mFont->GetCharHeight());
|
|
int text_h = int(text_size.y * mFont->GetCharHeight());
|
|
|
|
|
|
// Draw FPS counter
|
|
// Draw FPS counter
|
|
- int x = (mRenderer->GetWindowWidth() - text_w) / 2 - 20;
|
|
|
|
|
|
+ int x = (mWindow->GetWindowWidth() - text_w) / 2 - 20;
|
|
int y = 10;
|
|
int y = 10;
|
|
mUI->DrawQuad(x - 5, y - 3, text_w + 10, text_h + 6, UITexturedQuad(), Color(0, 0, 0, 128));
|
|
mUI->DrawQuad(x - 5, y - 3, text_w + 10, text_h + 6, UITexturedQuad(), Color(0, 0, 0, 128));
|
|
mUI->DrawText(x, y, fps, mFont);
|
|
mUI->DrawText(x, y, fps, mFont);
|
|
@@ -409,7 +436,7 @@ void Application::DrawFPS(float inDeltaTime)
|
|
{
|
|
{
|
|
string_view paused_str = "P: Unpause, ESC: Menu";
|
|
string_view paused_str = "P: Unpause, ESC: Menu";
|
|
Float2 pause_size = mFont->MeasureText(paused_str);
|
|
Float2 pause_size = mFont->MeasureText(paused_str);
|
|
- mUI->DrawText(mRenderer->GetWindowWidth() - 5 - int(pause_size.x * mFont->GetCharHeight()), 5, paused_str, mFont);
|
|
|
|
|
|
+ mUI->DrawText(mWindow->GetWindowWidth() - 5 - int(pause_size.x * mFont->GetCharHeight()), 5, paused_str, mFont);
|
|
}
|
|
}
|
|
|
|
|
|
// Restore state
|
|
// Restore state
|