Ajout de Jolt Physics + 1ere version des factory entitecomposants - camera, transform, rigidbody, collider, renderer
This commit is contained in:
433
lib/All/JoltPhysics/TestFramework/Application/Application.cpp
Normal file
433
lib/All/JoltPhysics/TestFramework/Application/Application.cpp
Normal file
@@ -0,0 +1,433 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <TestFramework.h>
|
||||
|
||||
#include <Application/Application.h>
|
||||
#include <UI/UIManager.h>
|
||||
#include <Application/DebugUI.h>
|
||||
#include <Utils/Log.h>
|
||||
#include <Utils/CustomMemoryHook.h>
|
||||
#include <Jolt/Core/Factory.h>
|
||||
#include <Jolt/RegisterTypes.h>
|
||||
#include <Renderer/DebugRendererImp.h>
|
||||
#ifdef JPH_PLATFORM_WINDOWS
|
||||
#include <crtdbg.h>
|
||||
#include <Input/Win/KeyboardWin.h>
|
||||
#include <Input/Win/MouseWin.h>
|
||||
#include <Window/ApplicationWindowWin.h>
|
||||
#elif defined(JPH_PLATFORM_LINUX)
|
||||
#include <Input/Linux/KeyboardLinux.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
|
||||
|
||||
JPH_GCC_SUPPRESS_WARNING("-Wswitch")
|
||||
|
||||
// Constructor
|
||||
Application::Application(const char *inApplicationName, [[maybe_unused]] const String &inCommandLine) :
|
||||
mDebugRenderer(nullptr),
|
||||
mRenderer(nullptr),
|
||||
mKeyboard(nullptr),
|
||||
mMouse(nullptr),
|
||||
mUI(nullptr),
|
||||
mDebugUI(nullptr)
|
||||
{
|
||||
#if defined(JPH_PLATFORM_WINDOWS) && defined(_DEBUG)
|
||||
// Enable leak detection
|
||||
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
||||
#endif
|
||||
|
||||
// Register trace implementation
|
||||
Trace = TraceImpl;
|
||||
|
||||
#ifdef JPH_ENABLE_ASSERTS
|
||||
// Register assert failed handler
|
||||
AssertFailed = [](const char *inExpression, const char *inMessage, const char *inFile, uint inLine)
|
||||
{
|
||||
Trace("%s (%d): Assert Failed: %s", inFile, inLine, inMessage != nullptr? inMessage : inExpression);
|
||||
return true;
|
||||
};
|
||||
#endif // JPH_ENABLE_ASSERTS
|
||||
|
||||
// Create factory
|
||||
Factory::sInstance = new Factory;
|
||||
|
||||
// Register physics types with the factory
|
||||
RegisterTypes();
|
||||
|
||||
{
|
||||
// Disable allocation checking
|
||||
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(inApplicationName);
|
||||
|
||||
// Create renderer
|
||||
mRenderer = Renderer::sCreate();
|
||||
mRenderer->Initialize(mWindow);
|
||||
|
||||
// Create font
|
||||
Font *font = new Font(mRenderer);
|
||||
font->Create("Roboto-Regular", 24);
|
||||
mFont = font;
|
||||
|
||||
// Init debug renderer
|
||||
mDebugRenderer = new DebugRendererImp(mRenderer, mFont);
|
||||
|
||||
// Init keyboard
|
||||
#ifdef JPH_PLATFORM_WINDOWS
|
||||
mKeyboard = new KeyboardWin;
|
||||
#elif defined(JPH_PLATFORM_LINUX)
|
||||
mKeyboard = new KeyboardLinux;
|
||||
#elif defined(JPH_PLATFORM_MACOS)
|
||||
mKeyboard = new KeyboardMacOS;
|
||||
#else
|
||||
#error No keyboard defined
|
||||
#endif
|
||||
mKeyboard->Initialize(mWindow);
|
||||
|
||||
// Init mouse
|
||||
#ifdef JPH_PLATFORM_WINDOWS
|
||||
mMouse = new MouseWin;
|
||||
#elif defined(JPH_PLATFORM_LINUX)
|
||||
mMouse = new MouseLinux;
|
||||
#elif defined(JPH_PLATFORM_MACOS)
|
||||
mMouse = new MouseMacOS;
|
||||
#else
|
||||
#error No mouse defined
|
||||
#endif
|
||||
mMouse->Initialize(mWindow);
|
||||
|
||||
// Init UI
|
||||
mUI = new UIManager(mRenderer);
|
||||
mUI->SetVisible(false);
|
||||
|
||||
// Init debug UI
|
||||
mDebugUI = new DebugUI(mUI, mFont);
|
||||
}
|
||||
|
||||
// Get initial time
|
||||
mLastUpdateTime = chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
// Destructor
|
||||
Application::~Application()
|
||||
{
|
||||
{
|
||||
// Disable allocation checking
|
||||
DisableCustomMemoryHook dcmh;
|
||||
|
||||
delete mDebugUI;
|
||||
delete mUI;
|
||||
delete mMouse;
|
||||
delete mKeyboard;
|
||||
delete mDebugRenderer;
|
||||
mFont = nullptr;
|
||||
delete mRenderer;
|
||||
delete mWindow;
|
||||
}
|
||||
|
||||
// Unregisters all types with the factory and cleans up the default material
|
||||
UnregisterTypes();
|
||||
|
||||
delete Factory::sInstance;
|
||||
Factory::sInstance = nullptr;
|
||||
}
|
||||
|
||||
String Application::sCreateCommandLine(int inArgC, char **inArgV)
|
||||
{
|
||||
String command_line;
|
||||
for (int i = 0; i < inArgC; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
command_line += " ";
|
||||
command_line += inArgV[i];
|
||||
}
|
||||
return command_line;
|
||||
}
|
||||
|
||||
// Clear debug lines / triangles / texts that have been accumulated
|
||||
void Application::ClearDebugRenderer()
|
||||
{
|
||||
JPH_PROFILE_FUNCTION();
|
||||
|
||||
static_cast<DebugRendererImp *>(mDebugRenderer)->Clear();
|
||||
|
||||
mDebugRendererCleared = true;
|
||||
}
|
||||
|
||||
// Main loop
|
||||
void Application::Run()
|
||||
{
|
||||
// Set initial camera position
|
||||
ResetCamera();
|
||||
|
||||
// Enter the main loop
|
||||
mWindow->MainLoop([this]() { return RenderFrame(); });
|
||||
}
|
||||
|
||||
bool Application::RenderFrame()
|
||||
{
|
||||
// Get new input
|
||||
mKeyboard->Poll();
|
||||
mMouse->Poll();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
mSingleStep = false;
|
||||
|
||||
// Clear debug lines if we're going to step
|
||||
if (world_delta_time > 0.0f)
|
||||
ClearDebugRenderer();
|
||||
|
||||
{
|
||||
JPH_PROFILE("UpdateFrame");
|
||||
if (!UpdateFrame(world_delta_time))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Draw coordinate axis
|
||||
if (mDebugRendererCleared)
|
||||
mDebugRenderer->DrawCoordinateSystem(RMat44::sIdentity());
|
||||
|
||||
// For next frame: mark that we haven't cleared debug stuff
|
||||
mDebugRendererCleared = false;
|
||||
|
||||
// Update the camera position
|
||||
if (!mUI->IsVisible())
|
||||
UpdateCamera(clock_delta_time);
|
||||
|
||||
// Start rendering
|
||||
if (!mRenderer->BeginFrame(mWorldCamera, GetWorldScale()))
|
||||
return true;
|
||||
|
||||
// Draw from light
|
||||
static_cast<DebugRendererImp *>(mDebugRenderer)->DrawShadowPass();
|
||||
|
||||
// Start drawing normally
|
||||
mRenderer->EndShadowPass();
|
||||
|
||||
// Draw debug information
|
||||
static_cast<DebugRendererImp *>(mDebugRenderer)->Draw();
|
||||
|
||||
// Draw the frame rate counter
|
||||
DrawFPS(clock_delta_time);
|
||||
|
||||
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());
|
||||
|
||||
{
|
||||
// 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();
|
||||
|
||||
// Notify of next frame
|
||||
JPH_PROFILE_NEXTFRAME();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Application::GetCameraLocalHeadingAndPitch(float &outHeading, float &outPitch)
|
||||
{
|
||||
outHeading = ATan2(mLocalCamera.mForward.GetZ(), mLocalCamera.mForward.GetX());
|
||||
outPitch = ATan2(mLocalCamera.mForward.GetY(), Vec3(mLocalCamera.mForward.GetX(), 0, mLocalCamera.mForward.GetZ()).Length());
|
||||
}
|
||||
|
||||
void Application::ConvertCameraLocalToWorld(float inCameraHeading, float inCameraPitch)
|
||||
{
|
||||
// Convert local to world space using the camera pivot
|
||||
RMat44 pivot = GetCameraPivot(inCameraHeading, inCameraPitch);
|
||||
mWorldCamera = mLocalCamera;
|
||||
mWorldCamera.mPos = pivot * mLocalCamera.mPos;
|
||||
mWorldCamera.mForward = pivot.Multiply3x3(mLocalCamera.mForward);
|
||||
mWorldCamera.mUp = pivot.Multiply3x3(mLocalCamera.mUp);
|
||||
}
|
||||
|
||||
void Application::ResetCamera()
|
||||
{
|
||||
// Get local space camera state
|
||||
mLocalCamera = CameraState();
|
||||
GetInitialCamera(mLocalCamera);
|
||||
|
||||
// Convert to world space
|
||||
float heading, pitch;
|
||||
GetCameraLocalHeadingAndPitch(heading, pitch);
|
||||
ConvertCameraLocalToWorld(heading, pitch);
|
||||
}
|
||||
|
||||
// Update camera position
|
||||
void Application::UpdateCamera(float inDeltaTime)
|
||||
{
|
||||
JPH_PROFILE_FUNCTION();
|
||||
|
||||
// Determine speed
|
||||
float speed = 20.0f * GetWorldScale() * inDeltaTime;
|
||||
bool shift = mKeyboard->IsKeyPressed(EKey::LShift) || mKeyboard->IsKeyPressed(EKey::RShift);
|
||||
bool control = mKeyboard->IsKeyPressed(EKey::LControl) || mKeyboard->IsKeyPressed(EKey::RControl);
|
||||
bool alt = mKeyboard->IsKeyPressed(EKey::LAlt) || mKeyboard->IsKeyPressed(EKey::RAlt);
|
||||
if (shift) speed *= 10.0f;
|
||||
else if (control) speed /= 25.0f;
|
||||
else if (alt) speed = 0.0f;
|
||||
|
||||
// Position
|
||||
Vec3 right = mLocalCamera.mForward.Cross(mLocalCamera.mUp);
|
||||
if (mKeyboard->IsKeyPressed(EKey::A)) mLocalCamera.mPos -= speed * right;
|
||||
if (mKeyboard->IsKeyPressed(EKey::D)) mLocalCamera.mPos += speed * right;
|
||||
if (mKeyboard->IsKeyPressed(EKey::W)) mLocalCamera.mPos += speed * mLocalCamera.mForward;
|
||||
if (mKeyboard->IsKeyPressed(EKey::S)) mLocalCamera.mPos -= speed * mLocalCamera.mForward;
|
||||
|
||||
// Forward
|
||||
float heading, pitch;
|
||||
GetCameraLocalHeadingAndPitch(heading, pitch);
|
||||
heading += DegreesToRadians(mMouse->GetDX() * 0.5f);
|
||||
pitch = Clamp(pitch - DegreesToRadians(mMouse->GetDY() * 0.5f), -0.49f * JPH_PI, 0.49f * JPH_PI);
|
||||
mLocalCamera.mForward = Vec3(Cos(pitch) * Cos(heading), Sin(pitch), Cos(pitch) * Sin(heading));
|
||||
|
||||
// Convert to world space
|
||||
ConvertCameraLocalToWorld(heading, pitch);
|
||||
}
|
||||
|
||||
void Application::DrawFPS(float inDeltaTime)
|
||||
{
|
||||
JPH_PROFILE_FUNCTION();
|
||||
|
||||
// Don't divide by zero
|
||||
if (inDeltaTime <= 0.0f)
|
||||
return;
|
||||
|
||||
// Switch tho ortho mode
|
||||
mRenderer->SetOrthoMode();
|
||||
|
||||
// Update stats
|
||||
mTotalDeltaTime += inDeltaTime;
|
||||
mNumFrames++;
|
||||
if (mNumFrames > 10)
|
||||
{
|
||||
mFPS = mNumFrames / mTotalDeltaTime;
|
||||
mNumFrames = 0;
|
||||
mTotalDeltaTime = 0.0f;
|
||||
}
|
||||
|
||||
// Create string
|
||||
String fps = StringFormat("%.1f", (double)mFPS);
|
||||
|
||||
// Get size of text on screen
|
||||
Float2 text_size = mFont->MeasureText(fps);
|
||||
int text_w = int(text_size.x * mFont->GetCharHeight());
|
||||
int text_h = int(text_size.y * mFont->GetCharHeight());
|
||||
|
||||
// Draw FPS counter
|
||||
int x = (mWindow->GetWindowWidth() - text_w) / 2 - 20;
|
||||
int y = 10;
|
||||
mUI->DrawQuad(x - 5, y - 3, text_w + 10, text_h + 6, UITexturedQuad(), Color(0, 0, 0, 128));
|
||||
mUI->DrawText(x, y, fps, mFont);
|
||||
|
||||
// Draw status string
|
||||
if (!mStatusString.empty())
|
||||
mUI->DrawText(5, 5, mStatusString, mFont);
|
||||
|
||||
// Draw paused string if the app is paused
|
||||
if (mIsPaused)
|
||||
{
|
||||
string_view paused_str = "P: Unpause, ESC: Menu";
|
||||
Float2 pause_size = mFont->MeasureText(paused_str);
|
||||
mUI->DrawText(mWindow->GetWindowWidth() - 5 - int(pause_size.x * mFont->GetCharHeight()), 5, paused_str, mFont);
|
||||
}
|
||||
|
||||
// Restore state
|
||||
mRenderer->SetProjectionMode();
|
||||
}
|
||||
121
lib/All/JoltPhysics/TestFramework/Application/Application.h
Normal file
121
lib/All/JoltPhysics/TestFramework/Application/Application.h
Normal file
@@ -0,0 +1,121 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <Renderer/Renderer.h>
|
||||
#include <Renderer/Font.h>
|
||||
#include <Input/Keyboard.h>
|
||||
#include <Input/Mouse.h>
|
||||
#include <Jolt/Core/Reference.h>
|
||||
|
||||
// STL includes
|
||||
JPH_SUPPRESS_WARNINGS_STD_BEGIN
|
||||
#include <chrono>
|
||||
JPH_SUPPRESS_WARNINGS_STD_END
|
||||
|
||||
class UIManager;
|
||||
class DebugUI;
|
||||
namespace JPH {
|
||||
class DebugRenderer;
|
||||
}
|
||||
|
||||
class Application
|
||||
{
|
||||
private:
|
||||
/// Camera state
|
||||
CameraState mLocalCamera;
|
||||
CameraState mWorldCamera;
|
||||
|
||||
protected:
|
||||
/// Debug renderer module
|
||||
DebugRenderer * mDebugRenderer;
|
||||
|
||||
/// Main window
|
||||
ApplicationWindow * mWindow;
|
||||
|
||||
/// Render module
|
||||
Renderer * mRenderer;
|
||||
|
||||
/// Default font
|
||||
RefConst<Font> mFont;
|
||||
|
||||
/// Input
|
||||
Keyboard * mKeyboard;
|
||||
Mouse * mMouse;
|
||||
|
||||
/// Menu
|
||||
UIManager * mUI;
|
||||
DebugUI * mDebugUI;
|
||||
|
||||
/// A string that is shown on screen to indicate the status of the application
|
||||
String mStatusString;
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
Application(const char *inApplicationName, const String &inCommandLine);
|
||||
virtual ~Application();
|
||||
|
||||
/// Create a single string command line
|
||||
static String sCreateCommandLine(int inArgC, char **inArgV);
|
||||
|
||||
/// Enter the main loop
|
||||
void Run();
|
||||
|
||||
protected:
|
||||
/// Update the application
|
||||
virtual bool UpdateFrame(float inDeltaTime) { return false; }
|
||||
|
||||
/// Pause / unpause the simulation
|
||||
void Pause(bool inPaused) { mIsPaused = inPaused; }
|
||||
|
||||
/// Programmatically single step the simulation
|
||||
void SingleStep() { mIsPaused = true; mSingleStep = true; }
|
||||
|
||||
/// Set the frequency at which we want to render frames
|
||||
void SetRenderFrequency(float inFrequency) { mRequestedDeltaTime = 1.0f / inFrequency; }
|
||||
|
||||
/// Will restore camera position to that returned by GetInitialCamera
|
||||
void ResetCamera();
|
||||
|
||||
/// Override to specify the initial camera state (local to GetCameraPivot)
|
||||
virtual void GetInitialCamera(CameraState &ioState) const { }
|
||||
|
||||
/// Override to specify a camera pivot point and orientation (world space)
|
||||
virtual RMat44 GetCameraPivot(float inCameraHeading, float inCameraPitch) const { return RMat44::sIdentity(); }
|
||||
|
||||
/// Get scale factor for this world, used to boost camera speed and to scale detail of the shadows
|
||||
virtual float GetWorldScale() const { return 1.0f; }
|
||||
|
||||
/// Get current state of the camera (world space)
|
||||
const CameraState & GetCamera() const { return mWorldCamera; }
|
||||
|
||||
/// Clear debug lines / triangles / texts that have been accumulated
|
||||
void ClearDebugRenderer();
|
||||
|
||||
private:
|
||||
/// Render a frame
|
||||
bool RenderFrame();
|
||||
|
||||
/// Extract heading and pitch from the local space (relative to the camera pivot) camera forward
|
||||
void GetCameraLocalHeadingAndPitch(float &outHeading, float &outPitch);
|
||||
|
||||
/// Convert local space camera to world space camera
|
||||
void ConvertCameraLocalToWorld(float inCameraHeading, float inCameraPitch);
|
||||
|
||||
/// Update the local and world space camera transform
|
||||
void UpdateCamera(float inDeltaTime);
|
||||
|
||||
/// Draw the frame rate counter
|
||||
void DrawFPS(float inDeltaTime);
|
||||
|
||||
chrono::high_resolution_clock::time_point mLastUpdateTime;
|
||||
bool mIsPaused = false;
|
||||
bool mSingleStep = false;
|
||||
bool mDebugRendererCleared = true;
|
||||
bool mLeftMousePressed = false;
|
||||
float mFPS = 0.0f;
|
||||
float mRequestedDeltaTime = 0.0f;
|
||||
float mResidualDeltaTime = 0.0f;
|
||||
float mTotalDeltaTime = 0.0f;
|
||||
int mNumFrames = 0;
|
||||
};
|
||||
215
lib/All/JoltPhysics/TestFramework/Application/DebugUI.cpp
Normal file
215
lib/All/JoltPhysics/TestFramework/Application/DebugUI.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <TestFramework.h>
|
||||
|
||||
#include <Application/DebugUI.h>
|
||||
#include <Renderer/Texture.h>
|
||||
#include <UI/UIManager.h>
|
||||
#include <UI/UIImage.h>
|
||||
#include <UI/UIStaticText.h>
|
||||
#include <UI/UICheckBox.h>
|
||||
#include <UI/UIHorizontalStack.h>
|
||||
#include <UI/UIVerticalStack.h>
|
||||
#include <UI/UITextButton.h>
|
||||
#include <Image/LoadTGA.h>
|
||||
#include <Utils/Log.h>
|
||||
#include <Utils/AssetStream.h>
|
||||
|
||||
JPH_SUPPRESS_WARNINGS_STD_BEGIN
|
||||
#include <fstream>
|
||||
JPH_SUPPRESS_WARNINGS_STD_END
|
||||
|
||||
DebugUI::DebugUI(UIManager *inUIManager, const Font *inFont) :
|
||||
mUI(inUIManager),
|
||||
mFont(inFont)
|
||||
{
|
||||
// Load UI texture with commonly used UI elements
|
||||
AssetStream texture_stream("UI.tga", std::ios::in | std::ios::binary);
|
||||
Ref<Surface> texture_surface = LoadTGA(texture_stream.Get());
|
||||
if (texture_surface == nullptr)
|
||||
FatalError("Failed to load UI.tga");
|
||||
mUITexture = mUI->GetRenderer()->CreateTexture(texture_surface);
|
||||
|
||||
// Install callback that pops a layer when the deactivate animation finishes
|
||||
mUI->SetDeactivatedAction([this]() {
|
||||
mUI->PopLayer();
|
||||
});
|
||||
|
||||
// Don't want to draw any layers that are not active
|
||||
mUI->SetDrawInactiveLayers(false);
|
||||
}
|
||||
|
||||
UIElement *DebugUI::CreateMenu()
|
||||
{
|
||||
mUI->PushLayer();
|
||||
|
||||
UIImage *background = new UIImage();
|
||||
background->SetRelativeX(10);
|
||||
background->SetRelativeY(10);
|
||||
background->SetImage(UITexturedQuad(mUITexture, 0, 0, 33, 30, 4, 4, 24, 21));
|
||||
mUI->Add(background);
|
||||
|
||||
UIVerticalStack *stack = new UIVerticalStack();
|
||||
stack->SetRelativeX(10);
|
||||
stack->SetRelativeY(10);
|
||||
stack->SetPaddingRight(10);
|
||||
stack->SetPaddingBottom(10);
|
||||
background->Add(stack);
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
UIStaticText *DebugUI::CreateStaticText(UIElement *inMenu, const string_view &inText)
|
||||
{
|
||||
UIStaticText *text = new UIStaticText();
|
||||
text->SetText(inText);
|
||||
text->SetFont(mFont);
|
||||
inMenu->Add(text);
|
||||
return text;
|
||||
}
|
||||
|
||||
UITextButton *DebugUI::CreateTextButton(UIElement *inMenu, const string_view &inName, UITextButton::ClickAction inAction)
|
||||
{
|
||||
UITextButton *button = new UITextButton();
|
||||
button->SetText(inName);
|
||||
button->SetFont(mFont);
|
||||
button->SetClickAction(inAction);
|
||||
button->SetTextPadding(0, 24, 0, 0);
|
||||
button->SetPaddingRight(24);
|
||||
inMenu->Add(button);
|
||||
return button;
|
||||
}
|
||||
|
||||
UICheckBox *DebugUI::CreateCheckBox(UIElement *inMenu, const string_view &inName, bool inInitiallyChecked, UICheckBox::ClickAction inAction)
|
||||
{
|
||||
UICheckBox *check_box = new UICheckBox();
|
||||
check_box->SetUncheckedStateQuad(UITexturedQuad(mUITexture, 48, 0, 16, 16));
|
||||
check_box->SetCheckedStateQuad(UITexturedQuad(mUITexture, 65, 0, 16, 16));
|
||||
check_box->SetFont(mFont);
|
||||
check_box->SetText(inName);
|
||||
check_box->SetClickAction(inAction);
|
||||
check_box->SetState(inInitiallyChecked? UICheckBox::STATE_CHECKED : UICheckBox::STATE_UNCHECKED);
|
||||
check_box->SetPaddingRight(24);
|
||||
inMenu->Add(check_box);
|
||||
return check_box;
|
||||
}
|
||||
|
||||
UISlider *DebugUI::CreateSlider(UIElement *inMenu, const string_view &inName, float inInitialValue, float inMinValue, float inMaxValue, float inStepValue, UISlider::ValueChangedAction inAction)
|
||||
{
|
||||
UIHorizontalStack *horiz = new UIHorizontalStack();
|
||||
horiz->SetPaddingRight(24);
|
||||
inMenu->Add(horiz);
|
||||
|
||||
UIStaticText *text = new UIStaticText();
|
||||
text->SetFont(mFont);
|
||||
text->SetTextPadding(0, 24, 0, 0);
|
||||
text->SetText(inName);
|
||||
text->SetPaddingRight(20);
|
||||
horiz->Add(text);
|
||||
|
||||
UISlider *slider = new UISlider();
|
||||
slider->SetHeight(24);
|
||||
slider->SetWidth(250);
|
||||
slider->SetPaddingRight(20);
|
||||
slider->SetValue(inInitialValue);
|
||||
slider->SetRange(inMinValue, inMaxValue, inStepValue);
|
||||
slider->SetValueChangedAction(inAction);
|
||||
slider->SetSlider(UITexturedQuad(mUITexture, 44, 37, 1, 9));
|
||||
slider->SetThumb(UITexturedQuad(mUITexture, 31, 32, 11, 19));
|
||||
horiz->Add(slider);
|
||||
|
||||
UIButton *decr_button = new UIButton();
|
||||
decr_button->SetRepeat(0.5f, 0.2f);
|
||||
decr_button->SetButtonQuad(UITexturedQuad(mUITexture, 0, 31, 17, 21));
|
||||
slider->Add(decr_button);
|
||||
slider->SetDecreaseButton(decr_button);
|
||||
|
||||
UIButton *incr_button = new UIButton();
|
||||
incr_button->SetRepeat(0.5f, 0.2f);
|
||||
incr_button->SetButtonQuad(UITexturedQuad(mUITexture, 13, 31, 17, 21));
|
||||
slider->Add(incr_button);
|
||||
slider->SetIncreaseButton(incr_button);
|
||||
|
||||
UIImage *image = new UIImage();
|
||||
image->SetImage(UITexturedQuad(mUITexture, 34, 0, 13, 24, 36, 2, 9, 20));
|
||||
horiz->Add(image);
|
||||
|
||||
UIStaticText *value = new UIStaticText();
|
||||
value->SetWidth(75);
|
||||
value->SetTextPadding(0, 5, 0, 5);
|
||||
value->SetWrap(true);
|
||||
value->SetTextAlignment(UIElement::RIGHT);
|
||||
value->SetFont(mFont);
|
||||
image->Add(value);
|
||||
slider->SetStaticText(value);
|
||||
|
||||
return slider;
|
||||
}
|
||||
|
||||
UIComboBox *DebugUI::CreateComboBox(UIElement *inMenu, const string_view &inName, const Array<String> &inItems, int inInitialItem, UIComboBox::ItemChangedAction inAction)
|
||||
{
|
||||
UIHorizontalStack *horiz = new UIHorizontalStack();
|
||||
horiz->SetPaddingRight(24);
|
||||
inMenu->Add(horiz);
|
||||
|
||||
UIStaticText *text = new UIStaticText();
|
||||
text->SetFont(mFont);
|
||||
text->SetTextPadding(0, 24, 0, 0);
|
||||
text->SetText(inName);
|
||||
text->SetPaddingRight(20);
|
||||
horiz->Add(text);
|
||||
|
||||
UIComboBox *combo = new UIComboBox();
|
||||
combo->SetHeight(24);
|
||||
combo->SetWidth(250);
|
||||
combo->SetPaddingRight(20);
|
||||
combo->SetItems(inItems);
|
||||
combo->SetCurrentItem(inInitialItem);
|
||||
combo->SetItemChangedAction(inAction);
|
||||
horiz->Add(combo);
|
||||
|
||||
UIButton *prev_button = new UIButton();
|
||||
prev_button->SetRepeat(0.5f, 0.2f);
|
||||
prev_button->SetButtonQuad(UITexturedQuad(mUITexture, 0, 31, 17, 21));
|
||||
combo->Add(prev_button);
|
||||
combo->SetPreviousButton(prev_button);
|
||||
|
||||
UIButton *next_button = new UIButton();
|
||||
next_button->SetRepeat(0.5f, 0.2f);
|
||||
next_button->SetButtonQuad(UITexturedQuad(mUITexture, 13, 31, 17, 21));
|
||||
combo->Add(next_button);
|
||||
combo->SetNextButton(next_button);
|
||||
|
||||
UIStaticText *value = new UIStaticText();
|
||||
value->SetTextPadding(0, 5, 0, 5);
|
||||
value->SetWrap(false);
|
||||
value->SetTextAlignment(UIElement::CENTER);
|
||||
value->SetFont(mFont);
|
||||
combo->Add(value);
|
||||
combo->SetStaticText(value);
|
||||
|
||||
return combo;
|
||||
}
|
||||
|
||||
void DebugUI::ShowMenu(UIElement *inMenu)
|
||||
{
|
||||
UIHorizontalStack::sUniformChildWidth(inMenu);
|
||||
mUI->AutoLayout();
|
||||
mUI->SwitchToState(UIManager::STATE_ACTIVATING);
|
||||
}
|
||||
|
||||
void DebugUI::BackToMain()
|
||||
{
|
||||
while (mUI->GetNumLayers() > 2)
|
||||
mUI->PopLayer();
|
||||
}
|
||||
|
||||
void DebugUI::ToggleVisibility()
|
||||
{
|
||||
if (mUI->GetNumLayers() > 2)
|
||||
mUI->SwitchToState(UIManager::STATE_DEACTIVATING);
|
||||
else
|
||||
mUI->SetVisible(!mUI->IsVisible());
|
||||
}
|
||||
48
lib/All/JoltPhysics/TestFramework/Application/DebugUI.h
Normal file
48
lib/All/JoltPhysics/TestFramework/Application/DebugUI.h
Normal file
@@ -0,0 +1,48 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Jolt/Core/Reference.h>
|
||||
#include <UI/UICheckBox.h>
|
||||
#include <UI/UITextButton.h>
|
||||
#include <UI/UISlider.h>
|
||||
#include <UI/UIComboBox.h>
|
||||
#include <UI/UIStaticText.h>
|
||||
|
||||
class UIManager;
|
||||
class Texture;
|
||||
class Font;
|
||||
class Keyboard;
|
||||
|
||||
class DebugUI
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
DebugUI(UIManager *inUIManager, const Font *inFont);
|
||||
|
||||
/// Create a new (sub) menu
|
||||
UIElement * CreateMenu();
|
||||
|
||||
/// Add items to the menu
|
||||
UIStaticText * CreateStaticText(UIElement *inMenu, const string_view &inText);
|
||||
UITextButton * CreateTextButton(UIElement *inMenu, const string_view &inName, UITextButton::ClickAction inAction);
|
||||
UICheckBox * CreateCheckBox(UIElement *inMenu, const string_view &inName, bool inInitiallyChecked, UICheckBox::ClickAction inAction);
|
||||
UISlider * CreateSlider(UIElement *inMenu, const string_view &inName, float inInitialValue, float inMinValue, float inMaxValue, float inStepValue, UISlider::ValueChangedAction inAction);
|
||||
UIComboBox * CreateComboBox(UIElement *inMenu, const string_view &inName, const Array<String> &inItems, int inInitialItem, UIComboBox::ItemChangedAction inAction);
|
||||
|
||||
/// Show it
|
||||
void ShowMenu(UIElement *inMenu);
|
||||
|
||||
/// Go back to the main menu
|
||||
void BackToMain();
|
||||
|
||||
/// Show or hide the entire menu
|
||||
void ToggleVisibility();
|
||||
|
||||
private:
|
||||
UIManager * mUI;
|
||||
RefConst<Font> mFont;
|
||||
RefConst<Texture> mUITexture;
|
||||
};
|
||||
74
lib/All/JoltPhysics/TestFramework/Application/EntryPoint.h
Normal file
74
lib/All/JoltPhysics/TestFramework/Application/EntryPoint.h
Normal file
@@ -0,0 +1,74 @@
|
||||
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
||||
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Jolt/Core/FPException.h>
|
||||
|
||||
#if defined(JPH_PLATFORM_WINDOWS)
|
||||
|
||||
#define ENTRY_POINT(AppName, RegisterAllocator) \
|
||||
\
|
||||
int WINAPI wWinMain(_In_ HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) \
|
||||
{ \
|
||||
RegisterAllocator(); \
|
||||
\
|
||||
JPH_PROFILE_START("Main"); \
|
||||
\
|
||||
FPExceptionsEnable enable_exceptions; \
|
||||
JPH_UNUSED(enable_exceptions); \
|
||||
\
|
||||
{ \
|
||||
AppName app(GetCommandLineA()); \
|
||||
app.Run(); \
|
||||
} \
|
||||
\
|
||||
JPH_PROFILE_END(); \
|
||||
\
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
int __cdecl main(int inArgC, char **inArgV) \
|
||||
{ \
|
||||
RegisterAllocator(); \
|
||||
\
|
||||
JPH_PROFILE_START("Main"); \
|
||||
\
|
||||
FPExceptionsEnable enable_exceptions; \
|
||||
JPH_UNUSED(enable_exceptions); \
|
||||
\
|
||||
{ \
|
||||
AppName app(Application::sCreateCommandLine(inArgC, inArgV)); \
|
||||
app.Run(); \
|
||||
} \
|
||||
\
|
||||
JPH_PROFILE_END(); \
|
||||
\
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define ENTRY_POINT(AppName, RegisterAllocator) \
|
||||
\
|
||||
int main(int inArgC, char **inArgV) \
|
||||
{ \
|
||||
RegisterAllocator(); \
|
||||
\
|
||||
JPH_PROFILE_START("Main"); \
|
||||
\
|
||||
FPExceptionsEnable enable_exceptions; \
|
||||
JPH_UNUSED(enable_exceptions); \
|
||||
\
|
||||
{ \
|
||||
AppName app(Application::sCreateCommandLine(inArgC, inArgV)); \
|
||||
app.Run(); \
|
||||
} \
|
||||
\
|
||||
JPH_PROFILE_END(); \
|
||||
\
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user