Added a debug controller
Made a default template for cameras. Added delta to mouse state so we can check delta for debug Camera.
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Common/CoreTypes.h>
|
||||
|
||||
constexpr index_t kPlayCamera = 0;
|
||||
constexpr index_t kDebugCamera = 1;
|
||||
@@ -0,0 +1,177 @@
|
||||
#include <Controller/DebugCameraController.h>
|
||||
|
||||
#include <Controller/ControllerUtils.h>
|
||||
#include <Core/Common/CoreUtils.h>
|
||||
#include <Core/HAL/Keyboard/Keyboard.h>
|
||||
#include <Core/HAL/Mouse/Mouse.h>
|
||||
#include <Graphics/Camera.h>
|
||||
#include <imgui.h>
|
||||
#include <math.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool gIsDebugCameraActive = false;
|
||||
index_t gPreviousCameraIndex = 0;
|
||||
|
||||
float gPitch = 0.0f;
|
||||
float gYaw = 0.0f;
|
||||
bool gFirstUpdate = true;
|
||||
bool gIsFpsModeActive = false;
|
||||
bool gWasRightMouseButtonDown = false;
|
||||
} // namespace
|
||||
|
||||
void ActivateDebugController()
|
||||
{
|
||||
Assert(gIsDebugCameraActive == false);
|
||||
|
||||
Juliet::Camera* currentCam = Juliet::GetCurrentCamera();
|
||||
gPreviousCameraIndex = currentCam->Index;
|
||||
|
||||
Juliet::SetCurrentCamera(kDebugCamera);
|
||||
|
||||
gIsDebugCameraActive = true;
|
||||
gFirstUpdate = true;
|
||||
gIsFpsModeActive = false;
|
||||
gWasRightMouseButtonDown = false;
|
||||
}
|
||||
|
||||
void DeactivateDebugController()
|
||||
{
|
||||
Assert(gIsDebugCameraActive);
|
||||
|
||||
gIsDebugCameraActive = false;
|
||||
|
||||
Juliet::SetCurrentCamera(gPreviousCameraIndex);
|
||||
}
|
||||
|
||||
bool IsDebugControllerActive()
|
||||
{
|
||||
return gIsDebugCameraActive;
|
||||
}
|
||||
|
||||
void UpdateDebugController(float dt)
|
||||
{
|
||||
Juliet::Camera* currentCam = Juliet::GetCurrentCamera();
|
||||
|
||||
if (gFirstUpdate)
|
||||
{
|
||||
Juliet::Vector3 dir = Juliet::Vector3{ 0.0f, 0.0f, 0.0f } - currentCam->Position;
|
||||
dir = Juliet::Normalize(dir);
|
||||
gPitch = asinf(dir.z);
|
||||
gYaw = atan2f(dir.y, dir.x);
|
||||
gFirstUpdate = false;
|
||||
|
||||
Juliet::Vector3 forward;
|
||||
forward.x = cosf(gPitch) * cosf(gYaw);
|
||||
forward.y = cosf(gPitch) * sinf(gYaw);
|
||||
forward.z = sinf(gPitch);
|
||||
Juliet::Vector3 right = Juliet::Normalize(Juliet::Cross(Juliet::Vector3{ 0.0f, 0.0f, 1.0f }, forward));
|
||||
currentCam->Target = currentCam->Position + forward;
|
||||
currentCam->Up = Juliet::Cross(forward, right);
|
||||
}
|
||||
|
||||
bool isRightMouseButtonDown = Juliet::IsMouseButtonDown(Juliet::MouseButton::Right);
|
||||
if (isRightMouseButtonDown && !gWasRightMouseButtonDown)
|
||||
{
|
||||
gIsFpsModeActive = !gIsFpsModeActive;
|
||||
}
|
||||
gWasRightMouseButtonDown = isRightMouseButtonDown;
|
||||
|
||||
if (!gIsFpsModeActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Juliet::MousePosition mouseDelta = Juliet::GetMouseDelta();
|
||||
|
||||
float sensitivity = 0.005f;
|
||||
gYaw += mouseDelta.X * sensitivity;
|
||||
gPitch -= mouseDelta.Y * sensitivity;
|
||||
|
||||
if (gPitch > 1.5f)
|
||||
{
|
||||
gPitch = 1.5f;
|
||||
}
|
||||
if (gPitch < -1.5f)
|
||||
{
|
||||
gPitch = -1.5f;
|
||||
}
|
||||
|
||||
if (Juliet::IsKeyDown(Juliet::ScanCode::Q))
|
||||
{
|
||||
gYaw -= 2.0f * dt;
|
||||
}
|
||||
if (Juliet::IsKeyDown(Juliet::ScanCode::E))
|
||||
{
|
||||
gYaw += 2.0f * dt;
|
||||
}
|
||||
|
||||
Juliet::Vector3 forward;
|
||||
forward.x = cosf(gPitch) * cosf(gYaw);
|
||||
forward.y = cosf(gPitch) * sinf(gYaw);
|
||||
forward.z = sinf(gPitch);
|
||||
|
||||
Juliet::Vector3 right = Juliet::Normalize(Juliet::Cross(Juliet::Vector3{ 0.0f, 0.0f, 1.0f }, forward));
|
||||
Juliet::Vector3 defaultUp = Juliet::Cross(forward, right);
|
||||
|
||||
static const float kMovementPerFrame = 10.f; // 10m/s
|
||||
|
||||
float speedPerFrame = kMovementPerFrame;
|
||||
if (Juliet::IsKeyDown(Juliet::ScanCode::LeftShift))
|
||||
{
|
||||
speedPerFrame *= 10.f; // 100m/s
|
||||
}
|
||||
|
||||
if (Juliet::IsKeyDown(Juliet::ScanCode::W))
|
||||
{
|
||||
currentCam->Position = currentCam->Position + forward * (speedPerFrame * dt);
|
||||
}
|
||||
if (Juliet::IsKeyDown(Juliet::ScanCode::S))
|
||||
{
|
||||
currentCam->Position = currentCam->Position - forward * (speedPerFrame * dt);
|
||||
}
|
||||
if (Juliet::IsKeyDown(Juliet::ScanCode::D))
|
||||
{
|
||||
currentCam->Position = currentCam->Position + right * (speedPerFrame * dt);
|
||||
}
|
||||
if (Juliet::IsKeyDown(Juliet::ScanCode::A))
|
||||
{
|
||||
currentCam->Position = currentCam->Position - right * (speedPerFrame * dt);
|
||||
}
|
||||
if (Juliet::IsKeyDown(Juliet::ScanCode::Space))
|
||||
{
|
||||
currentCam->Position = currentCam->Position + defaultUp * (speedPerFrame * dt);
|
||||
}
|
||||
if (Juliet::IsKeyDown(Juliet::ScanCode::LeftControl))
|
||||
{
|
||||
currentCam->Position = currentCam->Position - defaultUp * (speedPerFrame * dt);
|
||||
}
|
||||
|
||||
currentCam->Target = currentCam->Position + forward;
|
||||
currentCam->Up = defaultUp;
|
||||
}
|
||||
|
||||
#if JULIET_DEBUG
|
||||
void RenderImGuiDebugController(float dt)
|
||||
{
|
||||
Juliet::Camera* currentCam = Juliet::GetCurrentCamera();
|
||||
|
||||
ImGui::Text("Delta time: %f", dt);
|
||||
|
||||
ImGui::Text("Camera:");
|
||||
ImGui::Indent();
|
||||
ImGui::BulletText("Index: %zu", (size_t)currentCam->Index);
|
||||
ImGui::BulletText("Position: (%.3f, %.3f, %.3f)", currentCam->Position.x, currentCam->Position.y,
|
||||
currentCam->Position.z);
|
||||
ImGui::BulletText("Target: (%.3f, %.3f, %.3f)", currentCam->Target.x, currentCam->Target.y, currentCam->Target.z);
|
||||
ImGui::BulletText("Up: (%.3f, %.3f, %.3f)", currentCam->Up.x, currentCam->Up.y, currentCam->Up.z);
|
||||
ImGui::BulletText("FOV: %.3f rad", currentCam->FOV);
|
||||
ImGui::BulletText("AspectRatio: %.3f", currentCam->AspectRatio);
|
||||
ImGui::BulletText("NearPlane: %.3f", currentCam->NearPlane);
|
||||
ImGui::BulletText("FarPlane: %.3f", currentCam->FarPlane);
|
||||
ImGui::BulletText("Pitch: %.3f, Yaw: %.3f", gPitch, gYaw);
|
||||
ImGui::BulletText("FPS Mode: %s", gIsFpsModeActive ? "Active" : "Inactive");
|
||||
ImGui::Unindent();
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
// TODO : Should support Debug/Profile/Release properly.
|
||||
// I think debug profile should have this controller but not release
|
||||
void ActivateDebugController();
|
||||
void DeactivateDebugController();
|
||||
bool IsDebugControllerActive();
|
||||
void UpdateDebugController(float dt);
|
||||
|
||||
#if JULIET_DEBUG
|
||||
void RenderImGuiDebugController(float dt);
|
||||
#endif
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <game.h>
|
||||
|
||||
#include <Controller/DebugCameraController.h>
|
||||
#include <Core/Common/EnumUtils.h>
|
||||
#include <Core/HAL/Filesystem/Filesystem.h>
|
||||
#include <Core/HAL/Keyboard/Keyboard.h>
|
||||
@@ -95,6 +96,7 @@ extern "C" JULIET_API void __cdecl GameUpdate(Juliet::GameData* params, [[maybe_
|
||||
printf("Rock has %d health points\n", rock->Health);
|
||||
}
|
||||
|
||||
GameMode previousFrameMode = gGameState->Mode;
|
||||
if (IsKeyPressed(ScanCode::F1))
|
||||
{
|
||||
gGameState->Mode = static_cast<GameMode>((ToUnderlying(gGameState->Mode) + 1) % 2);
|
||||
@@ -107,7 +109,24 @@ extern "C" JULIET_API void __cdecl GameUpdate(Juliet::GameData* params, [[maybe_
|
||||
|
||||
if (gGameState->Mode == GameMode::Debug)
|
||||
{
|
||||
if (previousFrameMode != gGameState->Mode)
|
||||
{
|
||||
ActivateDebugController();
|
||||
}
|
||||
|
||||
UpdateDebugController(deltaTime);
|
||||
|
||||
#if JULIET_DEBUG
|
||||
ImGui::Begin("Debug");
|
||||
RenderImGuiDebugController(deltaTime);
|
||||
ImGui::End();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (previousFrameMode != gGameState->Mode)
|
||||
{
|
||||
DeactivateDebugController();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
namespace Juliet
|
||||
{
|
||||
struct Camera;
|
||||
struct RenderPass;
|
||||
struct CommandList;
|
||||
struct Texture;
|
||||
@@ -25,9 +26,9 @@ namespace Juliet
|
||||
virtual struct GraphicsDevice* GetGraphicsDevice() = 0;
|
||||
|
||||
// Render Lifecycle (Engine-Managed Render Loop)
|
||||
virtual void OnPreRender(CommandList* cmd) = 0;
|
||||
virtual void OnRender(RenderPass* pass, CommandList* cmd) = 0;
|
||||
virtual ColorTargetInfo GetColorTargetInfo(Texture* swapchainTexture) = 0;
|
||||
virtual DepthStencilTargetInfo* GetDepthTargetInfo() = 0;
|
||||
virtual void OnPreRender(CommandList* cmd) = 0;
|
||||
virtual void OnRender(RenderPass* pass, CommandList* cmd, const Camera& camera) = 0;
|
||||
virtual ColorTargetInfo GetColorTargetInfo(Texture* swapchainTexture) = 0;
|
||||
virtual DepthStencilTargetInfo* GetDepthTargetInfo() = 0;
|
||||
};
|
||||
} // namespace Juliet
|
||||
|
||||
@@ -21,7 +21,8 @@ namespace Juliet
|
||||
float Y;
|
||||
};
|
||||
|
||||
extern bool IsMouseButtonDown(MouseButton button);
|
||||
extern MousePosition GetMousePosition();
|
||||
extern MouseButton GetMouseButtonState();
|
||||
JULIET_API extern bool IsMouseButtonDown(MouseButton button);
|
||||
JULIET_API extern MousePosition GetMousePosition();
|
||||
JULIET_API extern MousePosition GetMouseDelta();
|
||||
JULIET_API extern MouseButton GetMouseButtonState();
|
||||
} // namespace Juliet
|
||||
|
||||
@@ -32,9 +32,7 @@ namespace Juliet
|
||||
return Camera_GetProjectionMatrix(cam) * Camera_GetViewMatrix(cam);
|
||||
}
|
||||
|
||||
JULIET_API extern void ReserveCamera(size_t amount);
|
||||
extern Camera* GetCurrentCamera();
|
||||
extern void SetCurrentCamera(index_t index);
|
||||
extern index_t AddCamera();
|
||||
extern void RemoveCamera(index_t index);
|
||||
JULIET_API extern void ReserveCamera(size_t amount);
|
||||
JULIET_API extern Camera* GetCurrentCamera();
|
||||
JULIET_API extern void SetCurrentCamera(index_t index);
|
||||
} // namespace Juliet
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace Juliet
|
||||
evt.Type = type;
|
||||
evt.Data.Keyboard.AssociatedKeyboardID = kGlobalKeyboardID;
|
||||
evt.Data.Keyboard.Key = key;
|
||||
evt.Data.Keyboard.KeyState = { keyPosition };
|
||||
evt.Data.Keyboard.KeyState = { keyPosition, 0.0f };
|
||||
evt.Data.Keyboard.KeyModeState = keyboardState.KeyModState;
|
||||
|
||||
bool evtPosted = AddEvent(evt);
|
||||
|
||||
@@ -55,6 +55,9 @@ namespace Juliet
|
||||
mouseState.X_Previous = x;
|
||||
mouseState.Y_Previous = y;
|
||||
|
||||
mouseState.DeltaX += xDisplacement;
|
||||
mouseState.DeltaY += yDisplacement;
|
||||
|
||||
SystemEvent evt;
|
||||
evt.Type = EventType::Mouse_Move;
|
||||
evt.Timestamp = timestamp;
|
||||
@@ -133,10 +136,23 @@ namespace Juliet
|
||||
return { .X = mouseState.X, .Y = mouseState.Y };
|
||||
}
|
||||
|
||||
MousePosition GetMouseDelta()
|
||||
{
|
||||
auto& mouseState = GetMouseState();
|
||||
return { .X = mouseState.DeltaX, .Y = mouseState.DeltaY };
|
||||
}
|
||||
|
||||
MouseButton GetMouseButtonState()
|
||||
{
|
||||
const auto& mouseState = GetMouseState();
|
||||
return mouseState.ButtonState;
|
||||
}
|
||||
|
||||
void UpdateMouseState()
|
||||
{
|
||||
auto& mouseState = GetMouseState();
|
||||
mouseState.DeltaX = 0.0f;
|
||||
mouseState.DeltaY = 0.0f;
|
||||
}
|
||||
|
||||
} // namespace Juliet
|
||||
|
||||
@@ -14,6 +14,9 @@ namespace Juliet
|
||||
float X_Previous;
|
||||
float Y_Previous;
|
||||
|
||||
float DeltaX;
|
||||
float DeltaY;
|
||||
|
||||
MouseButton ButtonState;
|
||||
|
||||
bool HasPosition : 1;
|
||||
@@ -21,6 +24,7 @@ namespace Juliet
|
||||
|
||||
Mouse& GetMouseState();
|
||||
|
||||
extern void UpdateMouseState();
|
||||
extern void SendMouseMotion(uint64 timestamp, NonNullPtr<Window> window, MouseID ID, float x, float y);
|
||||
extern void SendMouseButton(uint64 timestamp, NonNullPtr<Window> window, MouseID mouseID, MouseButton button, bool pressed);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <Core/HAL/Event/SystemEvent.h>
|
||||
|
||||
#include <Core/HAL/Event/Keyboard_Private.h>
|
||||
#include <Core/HAL/Event/Mouse_Private.h>
|
||||
|
||||
#pragma push_macro("global")
|
||||
#undef global
|
||||
@@ -93,6 +94,7 @@ namespace Juliet
|
||||
void Events_NewFrame(float deltaTime)
|
||||
{
|
||||
UpdateKeyboardstate(deltaTime);
|
||||
UpdateMouseState();
|
||||
}
|
||||
|
||||
} // namespace Juliet
|
||||
|
||||
@@ -132,12 +132,13 @@ namespace Juliet
|
||||
|
||||
RenderPass* pass = BeginRenderPass(cmdList, colorInfo, depthInfo);
|
||||
|
||||
Camera camera = *GetCurrentCamera();
|
||||
|
||||
// Application rendering
|
||||
EngineInstance.Application->OnRender(pass, cmdList);
|
||||
EngineInstance.Application->OnRender(pass, cmdList, camera);
|
||||
|
||||
// Debug display flush (inside render pass)
|
||||
Camera debugCamera = *GetCurrentCamera();
|
||||
DebugDisplay_Flush(cmdList, pass, debugCamera);
|
||||
DebugDisplay_Flush(cmdList, pass, camera);
|
||||
|
||||
// Note: The MeshRenderer and SkyboxRenderer draw calls are still inside Application->OnRender
|
||||
// They shouldn't be moved here directly without an interface since they require PushData.
|
||||
|
||||
@@ -11,6 +11,18 @@ namespace Juliet
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
Camera kDefaultCameraTemplate = {
|
||||
.Index = 0,
|
||||
.Position = { 25.0f, 0.0f, 12.5f },
|
||||
.Target = { cosf(0.f) * cosf(0.f), sinf(0.f) * cosf(0.f), sinf(0.f) },
|
||||
.Up = { 0.0f, 0.0f, 1.0f },
|
||||
.FOV = 1.047f,
|
||||
.AspectRatio = 1200.0f / 800.0f,
|
||||
.NearPlane = 0.1f,
|
||||
.FarPlane = 1000.0f,
|
||||
}; // namespace
|
||||
|
||||
size_t CameraAmount = 0;
|
||||
Camera* CameraArray = nullptr;
|
||||
Camera* CurrentCamera = nullptr;
|
||||
@@ -28,6 +40,7 @@ namespace Juliet
|
||||
for (index_t index = 0; index < CameraAmount; ++index)
|
||||
{
|
||||
Camera* cam = CameraArray + index;
|
||||
*cam = kDefaultCameraTemplate;
|
||||
cam->Index = index;
|
||||
}
|
||||
|
||||
|
||||
+3
-5
@@ -228,7 +228,6 @@ void JulietApplication::Shutdown()
|
||||
void JulietApplication::Update(float deltaTime)
|
||||
{
|
||||
|
||||
|
||||
CameraTime += deltaTime;
|
||||
|
||||
static float fpsTimer = 0.0f;
|
||||
@@ -488,7 +487,7 @@ void JulietApplication::Update(float deltaTime)
|
||||
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 1.0f }, { 0.0f, 0.0f, 1.0f, 1.0f }, true);
|
||||
DebugDisplay_DrawSphere({ 0.0f, 0.0f, 0.0f }, 0.5f, { 1.0f, 1.0f, 0.0f, 1.0f }, true);
|
||||
|
||||
Game.Update(&Data, 0.0f);
|
||||
Game.Update(&Data, deltaTime);
|
||||
|
||||
if (ShouldReloadCode(GameCode))
|
||||
{
|
||||
@@ -540,11 +539,10 @@ void JulietApplication::Update(float deltaTime)
|
||||
|
||||
void JulietApplication::OnPreRender(CommandList* /*cmd*/) {}
|
||||
|
||||
void JulietApplication::OnRender(RenderPass* pass, CommandList* cmd)
|
||||
void JulietApplication::OnRender(RenderPass* pass, CommandList* cmd, const Camera& camera)
|
||||
{
|
||||
Camera cam = {};
|
||||
PushData pushData = {};
|
||||
pushData.ViewProjection = Camera_GetViewProjectionMatrix(cam);
|
||||
pushData.ViewProjection = Camera_GetViewProjectionMatrix(camera);
|
||||
|
||||
#if 0
|
||||
if (enableGlobalLight)
|
||||
|
||||
+2
-2
@@ -27,8 +27,8 @@ class JulietApplication : public Juliet::IApplication
|
||||
Juliet::GraphicsDevice* GetGraphicsDevice() override { return GraphicsDevice; }
|
||||
|
||||
// Render Lifecycle
|
||||
void OnPreRender(Juliet::CommandList* cmd) override;
|
||||
void OnRender(Juliet::RenderPass* pass, Juliet::CommandList* cmd) override;
|
||||
void OnPreRender(Juliet::CommandList* cmd) override;
|
||||
void OnRender(Juliet::RenderPass* pass, Juliet::CommandList* cmd, const Juliet::Camera& camera) override;
|
||||
Juliet::ColorTargetInfo GetColorTargetInfo(Juliet::Texture* swapchainTexture) override;
|
||||
Juliet::DepthStencilTargetInfo* GetDepthTargetInfo() override;
|
||||
|
||||
|
||||
@@ -512,7 +512,7 @@ static void AppendTiming(const char* stepName, double secs)
|
||||
g_TimingsLen += sprintf_s(g_TimingsBuf + g_TimingsLen, sizeof(g_TimingsBuf) - g_TimingsLen, "%s|%.3fs\n", stepName, secs);
|
||||
}
|
||||
|
||||
static int ExecuteIncrementalCompile(const char* srcDir, const char* objDir, const char* baseCmd)
|
||||
static int ExecuteIncrementalCompile(const char* srcDir, const char* objDir, const char* baseCmd, int64_t maxDepTime)
|
||||
{
|
||||
EnsureDirectoryExists(objDir);
|
||||
|
||||
@@ -581,7 +581,8 @@ static int ExecuteIncrementalCompile(const char* srcDir, const char* objDir, con
|
||||
if (!FileExists(objPath)) {
|
||||
dirty = true;
|
||||
} else {
|
||||
if (GetFileModTimeInt64(srcPath) > GetFileModTimeInt64(objPath)) {
|
||||
int64_t objTime = GetFileModTimeInt64(objPath);
|
||||
if (GetFileModTimeInt64(srcPath) > objTime || maxDepTime > objTime) {
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
@@ -870,7 +871,7 @@ static int CommandRunPlan(int argc, char* argv[])
|
||||
{
|
||||
LARGE_INTEGER tStart, tEnd;
|
||||
QueryPerformanceCounter(&tStart);
|
||||
int res = ExecuteIncrementalCompile(step->IncSrc, step->IncObj, step->Command);
|
||||
int res = ExecuteIncrementalCompile(step->IncSrc, step->IncObj, step->Command, maxTime);
|
||||
QueryPerformanceCounter(&tEnd);
|
||||
AppendTiming(step->StepName, (double)(tEnd.QuadPart - tStart.QuadPart) / (double)perfFreq.QuadPart);
|
||||
if (res != 0) {
|
||||
|
||||
Reference in New Issue
Block a user