feat: add tracy / various fixes
This commit is contained in:
@@ -47,3 +47,6 @@
|
|||||||
[submodule "destrum/third_party/jolt"]
|
[submodule "destrum/third_party/jolt"]
|
||||||
path = destrum/third_party/jolt
|
path = destrum/third_party/jolt
|
||||||
url = https://github.com/jrouwe/JoltPhysics.git
|
url = https://github.com/jrouwe/JoltPhysics.git
|
||||||
|
[submodule "destrum/third_party/tracy"]
|
||||||
|
path = destrum/third_party/tracy
|
||||||
|
url = https://github.com/wolfpld/tracy.git
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ set(SRC_FILES
|
|||||||
"src/Physics/PhysicsWorld.cpp"
|
"src/Physics/PhysicsWorld.cpp"
|
||||||
"src/Physics/SimplePhysicsWorld.cpp"
|
"src/Physics/SimplePhysicsWorld.cpp"
|
||||||
"src/Physics/PhysicsSceneBridge.cpp"
|
"src/Physics/PhysicsSceneBridge.cpp"
|
||||||
src/Components/Physics/BoxCollider.cpp
|
"src/Physics/JoltPhysicsWorld.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(destrum ${SRC_FILES})
|
add_library(destrum ${SRC_FILES})
|
||||||
@@ -89,6 +89,7 @@ target_link_libraries(destrum
|
|||||||
assimp
|
assimp
|
||||||
imgui
|
imgui
|
||||||
Jolt
|
Jolt
|
||||||
|
Tracy::TracyClient
|
||||||
|
|
||||||
PRIVATE
|
PRIVATE
|
||||||
freetype::freetype
|
freetype::freetype
|
||||||
@@ -99,6 +100,7 @@ target_compile_definitions(destrum
|
|||||||
PUBLIC
|
PUBLIC
|
||||||
VK_NO_PROTOTYPES
|
VK_NO_PROTOTYPES
|
||||||
VMA_VULKAN_VERSION=1003000
|
VMA_VULKAN_VERSION=1003000
|
||||||
|
TRACY_VK_USE_SYMBOL_TABLE
|
||||||
# VOLK_DEFAULT_VISIBILITY # FIXME: doesn't work for some reason
|
# VOLK_DEFAULT_VISIBILITY # FIXME: doesn't work for some reason
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
Binary file not shown.
@@ -60,6 +60,14 @@ protected:
|
|||||||
bool resizePending = false;
|
bool resizePending = false;
|
||||||
std::chrono::steady_clock::time_point lastResizeTime{};
|
std::chrono::steady_clock::time_point lastResizeTime{};
|
||||||
|
|
||||||
|
bool m_PhysicsPaused = false;
|
||||||
|
bool m_PhysicsStepOnce = false;
|
||||||
|
|
||||||
|
float m_PhysicsTimeScale = 1.0f;
|
||||||
|
int m_PhysicsStepsLastFrame = 0;
|
||||||
|
|
||||||
|
void drawPhysicsPanel(float dt, float fixedDt, float accumulator);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,13 @@
|
|||||||
class MeshCache;
|
class MeshCache;
|
||||||
class ImguiPass;
|
class ImguiPass;
|
||||||
|
|
||||||
|
#if defined(TRACY_ENABLE)
|
||||||
|
namespace tracy { class VkCtx; }
|
||||||
|
using DestrumTracyVkCtx = tracy::VkCtx*;
|
||||||
|
#else
|
||||||
|
using DestrumTracyVkCtx = void*;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
using ImmediateExecuteFunction = std::function<void(VkCommandBuffer)>;
|
using ImmediateExecuteFunction = std::function<void(VkCommandBuffer)>;
|
||||||
@@ -126,12 +133,16 @@ public:
|
|||||||
return swapchain.getImageView(imageIndex);
|
return swapchain.getImageView(imageIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DestrumTracyVkCtx getTracyVkCtx() const { return tracyVkCtx; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vkb::Instance instance;
|
vkb::Instance instance;
|
||||||
vkb::PhysicalDevice physicalDevice;
|
vkb::PhysicalDevice physicalDevice;
|
||||||
vkb::Device device;
|
vkb::Device device;
|
||||||
VmaAllocator allocator;
|
VmaAllocator allocator;
|
||||||
|
|
||||||
|
DestrumTracyVkCtx tracyVkCtx = nullptr;
|
||||||
|
|
||||||
std::uint32_t graphicsQueueFamily;
|
std::uint32_t graphicsQueueFamily;
|
||||||
VkQueue graphicsQueue;
|
VkQueue graphicsQueue;
|
||||||
|
|
||||||
@@ -149,6 +160,8 @@ private:
|
|||||||
|
|
||||||
ImageCache imageCache;
|
ImageCache imageCache;
|
||||||
|
|
||||||
|
bool m_vSync = false;
|
||||||
|
|
||||||
static uint32_t BytesPerTexel(VkFormat fmt) {
|
static uint32_t BytesPerTexel(VkFormat fmt) {
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case VK_FORMAT_R8_UNORM: return 1;
|
case VK_FORMAT_R8_UNORM: return 1;
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include <destrum/Physics/PhysicsWorld.h>
|
||||||
|
|
||||||
|
class JoltPhysicsWorld final : public PhysicsWorld {
|
||||||
|
public:
|
||||||
|
struct Settings {
|
||||||
|
std::uint32_t maxBodies{65536};
|
||||||
|
std::uint32_t numBodyMutexes{0};
|
||||||
|
std::uint32_t maxBodyPairs{65536};
|
||||||
|
std::uint32_t maxContactConstraints{10240};
|
||||||
|
|
||||||
|
// Jolt recommends a temp allocator for physics update allocations.
|
||||||
|
// 10 MB is the value used in their HelloWorld sample.
|
||||||
|
std::uint32_t tempAllocatorSizeBytes{10u * 1024u * 1024u};
|
||||||
|
|
||||||
|
// 0 means "hardware_concurrency - 1".
|
||||||
|
std::uint32_t workerThreadCount{0};
|
||||||
|
|
||||||
|
glm::vec3 gravity{0.0f, -9.81f, 0.0f};
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit JoltPhysicsWorld(const Settings& settings = Settings{});
|
||||||
|
~JoltPhysicsWorld() override;
|
||||||
|
|
||||||
|
JoltPhysicsWorld(const JoltPhysicsWorld&) = delete;
|
||||||
|
JoltPhysicsWorld(JoltPhysicsWorld&&) noexcept = delete;
|
||||||
|
JoltPhysicsWorld& operator=(const JoltPhysicsWorld&) = delete;
|
||||||
|
JoltPhysicsWorld& operator=(JoltPhysicsWorld&&) noexcept = delete;
|
||||||
|
|
||||||
|
void Step(float fixedDt) override;
|
||||||
|
|
||||||
|
void SyncKinematicBodiesToPhysics() override;
|
||||||
|
void SyncDynamicBodiesToTransforms() override;
|
||||||
|
|
||||||
|
PhysicsBodyHandle CreateBody(const PhysicsBodyDesc& desc) override;
|
||||||
|
void DestroyBody(PhysicsBodyHandle body) override;
|
||||||
|
|
||||||
|
void SetBodyTransform(PhysicsBodyHandle body, const PhysicsTransform& transform) override;
|
||||||
|
PhysicsTransform GetBodyTransform(PhysicsBodyHandle body) const override;
|
||||||
|
|
||||||
|
void SetLinearVelocity(PhysicsBodyHandle body, const glm::vec3& velocity) override;
|
||||||
|
glm::vec3 GetLinearVelocity(PhysicsBodyHandle body) const override;
|
||||||
|
|
||||||
|
void AddForce(PhysicsBodyHandle body, const glm::vec3& force) override;
|
||||||
|
void AddImpulse(PhysicsBodyHandle body, const glm::vec3& impulse) override;
|
||||||
|
|
||||||
|
bool Raycast(const glm::vec3& origin,
|
||||||
|
const glm::vec3& direction,
|
||||||
|
float maxDistance,
|
||||||
|
PhysicsRaycastHit& hit) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Impl;
|
||||||
|
std::unique_ptr<Impl> m_Impl;
|
||||||
|
};
|
||||||
@@ -25,8 +25,8 @@ public:
|
|||||||
|
|
||||||
// - Kinematic: Transform -> physics body before Step()
|
// - Kinematic: Transform -> physics body before Step()
|
||||||
// - Dynamic: physics body -> Transform after Step()
|
// - Dynamic: physics body -> Transform after Step()
|
||||||
void SyncKinematicBodiesToPhysics();
|
virtual void SyncKinematicBodiesToPhysics();
|
||||||
void SyncDynamicBodiesToTransforms();
|
virtual void SyncDynamicBodiesToTransforms();
|
||||||
|
|
||||||
virtual PhysicsBodyHandle CreateBody(const PhysicsBodyDesc& desc) = 0;
|
virtual PhysicsBodyHandle CreateBody(const PhysicsBodyDesc& desc) = 0;
|
||||||
virtual void DestroyBody(PhysicsBodyHandle body) = 0;
|
virtual void DestroyBody(PhysicsBodyHandle body) = 0;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <destrum/Event.h>
|
#include <destrum/Event.h>
|
||||||
#include <destrum/Scene/SceneManager.h>
|
#include <destrum/Scene/SceneManager.h>
|
||||||
|
|
||||||
|
#include "destrum/Physics/JoltPhysicsWorld.h"
|
||||||
#include "destrum/Physics/PhysicsSceneBridge.h"
|
#include "destrum/Physics/PhysicsSceneBridge.h"
|
||||||
|
|
||||||
class GameObject;
|
class GameObject;
|
||||||
@@ -68,7 +69,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
explicit Scene(const std::string& name);
|
explicit Scene(const std::string& name);
|
||||||
|
|
||||||
PhysicsSceneBridge m_Physics{std::make_unique<SimplePhysicsWorld>()};
|
PhysicsSceneBridge m_Physics{std::make_unique<JoltPhysicsWorld>()};
|
||||||
|
|
||||||
|
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
|
|||||||
+216
-78
@@ -10,7 +10,16 @@
|
|||||||
#include "glm/gtx/transform.hpp"
|
#include "glm/gtx/transform.hpp"
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
#include <Jolt/Jolt.h>
|
#include <tracy/Tracy.hpp>
|
||||||
|
#include <common/TracySystem.hpp>
|
||||||
|
|
||||||
|
struct TracyFrameScope
|
||||||
|
{
|
||||||
|
~TracyFrameScope()
|
||||||
|
{
|
||||||
|
FrameMark;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
App::App()
|
App::App()
|
||||||
{
|
{
|
||||||
@@ -19,7 +28,9 @@ App::App()
|
|||||||
void App::init(const AppParams& params)
|
void App::init(const AppParams& params)
|
||||||
{
|
{
|
||||||
m_params = params;
|
m_params = params;
|
||||||
|
ZoneScopedN("App::init");
|
||||||
|
tracy::SetThreadName("Main Thread");
|
||||||
|
TracySetProgramName(params.appName.c_str());
|
||||||
AssetFS::GetInstance().Init(params.exeDir);
|
AssetFS::GetInstance().Init(params.exeDir);
|
||||||
// AssetFS::GetInstance().Mount("engine", params.exeDir / "assets" / "engine");
|
// AssetFS::GetInstance().Mount("engine", params.exeDir / "assets" / "engine");
|
||||||
// AssetFS::GetInstance().Mount("game", params.exeDir / "assets" / "game");
|
// AssetFS::GetInstance().Mount("game", params.exeDir / "assets" / "game");
|
||||||
@@ -53,16 +64,21 @@ void App::init(const AppParams& params)
|
|||||||
|
|
||||||
void App::run()
|
void App::run()
|
||||||
{
|
{
|
||||||
Time::GetInstance().Update(); // initialize delta timing
|
ZoneScopedN("App::run");
|
||||||
|
|
||||||
|
Time::GetInstance().Update();
|
||||||
|
|
||||||
const float fixedDt = static_cast<float>(Time::GetInstance().FixedDeltaTime());
|
const float fixedDt = static_cast<float>(Time::GetInstance().FixedDeltaTime());
|
||||||
const int maxSteps = 5; // prevent spiral of death
|
const int maxSteps = 5;
|
||||||
float accumulator = 0.0f;
|
float accumulator = 0.0f;
|
||||||
|
|
||||||
isRunning = true;
|
isRunning = true;
|
||||||
|
|
||||||
while (isRunning)
|
while (isRunning)
|
||||||
{
|
{
|
||||||
// ---- Update timing ---
|
TracyFrameScope tracyFrame;
|
||||||
|
ZoneScopedN("App::Frame");
|
||||||
|
|
||||||
Time::GetInstance().Update();
|
Time::GetInstance().Update();
|
||||||
float dt = static_cast<float>(Time::GetInstance().DeltaTime());
|
float dt = static_cast<float>(Time::GetInstance().DeltaTime());
|
||||||
|
|
||||||
@@ -72,117 +88,193 @@ void App::run()
|
|||||||
{
|
{
|
||||||
float newFPS = 1.0f / dt;
|
float newFPS = 1.0f / dt;
|
||||||
avgFPS = std::lerp(avgFPS, newFPS, 0.1f);
|
avgFPS = std::lerp(avgFPS, newFPS, 0.1f);
|
||||||
|
TracyPlot("FPS", avgFPS);
|
||||||
|
TracyPlot("Delta Time ms", dt * 1000.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
accumulator += dt;
|
accumulator += dt;
|
||||||
|
|
||||||
InputManager::GetInstance().BeginFrame();
|
|
||||||
camera.Update(dt);
|
|
||||||
|
|
||||||
|
|
||||||
SDL_Event event;
|
|
||||||
while (SDL_PollEvent(&event))
|
|
||||||
{
|
{
|
||||||
imguiPass.handleEvent(event);
|
ZoneScopedN("Input BeginFrame + Camera");
|
||||||
if (event.type == SDL_QUIT)
|
InputManager::GetInstance().BeginFrame();
|
||||||
|
camera.Update(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ZoneScopedN("SDL Events");
|
||||||
|
|
||||||
|
SDL_Event event;
|
||||||
|
while (SDL_PollEvent(&event))
|
||||||
{
|
{
|
||||||
isRunning = false;
|
ZoneScopedN("SDL Event");
|
||||||
break;
|
|
||||||
}
|
imguiPass.handleEvent(event);
|
||||||
if (event.type == SDL_WINDOWEVENT)
|
|
||||||
{
|
if (event.type == SDL_QUIT)
|
||||||
switch (event.window.event)
|
|
||||||
{
|
{
|
||||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
isRunning = false;
|
||||||
case SDL_WINDOWEVENT_RESIZED:
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == SDL_WINDOWEVENT)
|
||||||
|
{
|
||||||
|
switch (event.window.event)
|
||||||
{
|
{
|
||||||
|
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||||
|
case SDL_WINDOWEVENT_RESIZED:
|
||||||
resizePending = true;
|
resizePending = true;
|
||||||
lastResizeTime = std::chrono::steady_clock::now();
|
lastResizeTime = std::chrono::steady_clock::now();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
const bool mouseEvent =
|
|
||||||
event.type == SDL_MOUSEBUTTONDOWN ||
|
|
||||||
event.type == SDL_MOUSEBUTTONUP ||
|
|
||||||
event.type == SDL_MOUSEMOTION ||
|
|
||||||
event.type == SDL_MOUSEWHEEL;
|
|
||||||
|
|
||||||
const bool keyboardEvent =
|
const bool mouseEvent =
|
||||||
event.type == SDL_KEYDOWN ||
|
event.type == SDL_MOUSEBUTTONDOWN ||
|
||||||
event.type == SDL_KEYUP ||
|
event.type == SDL_MOUSEBUTTONUP ||
|
||||||
event.type == SDL_TEXTINPUT;
|
event.type == SDL_MOUSEMOTION ||
|
||||||
|
event.type == SDL_MOUSEWHEEL;
|
||||||
|
|
||||||
const bool capturedByImgui =
|
const bool keyboardEvent =
|
||||||
(mouseEvent && imguiPass.wantsMouse()) ||
|
event.type == SDL_KEYDOWN ||
|
||||||
(keyboardEvent && imguiPass.wantsKeyboard());
|
event.type == SDL_KEYUP ||
|
||||||
|
event.type == SDL_TEXTINPUT;
|
||||||
|
|
||||||
if (!capturedByImgui)
|
const bool capturedByImgui =
|
||||||
{
|
(mouseEvent && imguiPass.wantsMouse()) ||
|
||||||
if (InputManager::GetInstance().ProcessEvent(event))
|
(keyboardEvent && imguiPass.wantsKeyboard());
|
||||||
|
|
||||||
|
if (!capturedByImgui)
|
||||||
{
|
{
|
||||||
isRunning = false;
|
ZoneScopedN("Input ProcessEvent");
|
||||||
|
|
||||||
|
if (InputManager::GetInstance().ProcessEvent(event))
|
||||||
|
{
|
||||||
|
isRunning = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isRunning) break;
|
if (!isRunning) break;
|
||||||
imguiPass.beginFrame();
|
|
||||||
|
|
||||||
customUpdate(dt);
|
|
||||||
|
|
||||||
ImGui::Begin("Debug");
|
|
||||||
ImGui::Text("FPS: %.2f", avgFPS);
|
|
||||||
ImGui::End();
|
|
||||||
|
|
||||||
imguiPass.endFrame();
|
|
||||||
int steps = 0;
|
|
||||||
while (accumulator >= fixedDt && steps < maxSteps)
|
|
||||||
{
|
{
|
||||||
// physics.Update(fixedDt);
|
ZoneScopedN("ImGui BeginFrame");
|
||||||
customFixedUpdate(fixedDt);
|
imguiPass.beginFrame();
|
||||||
// physics.Step(fixedDt);
|
}
|
||||||
// physics.SyncTransforms();
|
|
||||||
|
|
||||||
accumulator -= fixedDt;
|
{
|
||||||
steps++;
|
ZoneScopedN("customUpdate");
|
||||||
|
customUpdate(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ZoneScopedN("Debug ImGui");
|
||||||
|
ImGui::Begin("Debug");
|
||||||
|
ImGui::Text("FPS: %.2f", avgFPS);
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
drawPhysicsPanel(dt, fixedDt, accumulator);
|
||||||
|
|
||||||
|
TracyPlot("FPS", avgFPS);
|
||||||
|
TracyPlot("Frame Time ms", dt * 1000.0f);
|
||||||
|
TracyPlot("Accumulator ms", accumulator * 1000.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ZoneScopedN("ImGui EndFrame");
|
||||||
|
imguiPass.endFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ZoneScopedN("FixedUpdate");
|
||||||
|
|
||||||
|
int steps = 0;
|
||||||
|
|
||||||
|
if (m_PhysicsPaused)
|
||||||
|
{
|
||||||
|
// Important: prevent physics from building up a huge backlog while paused.
|
||||||
|
accumulator = 0.0f;
|
||||||
|
|
||||||
|
if (m_PhysicsStepOnce)
|
||||||
|
{
|
||||||
|
ZoneScopedN("Single Physics Step");
|
||||||
|
|
||||||
|
customFixedUpdate(fixedDt * m_PhysicsTimeScale);
|
||||||
|
|
||||||
|
steps = 1;
|
||||||
|
m_PhysicsStepOnce = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (accumulator >= fixedDt && steps < maxSteps)
|
||||||
|
{
|
||||||
|
ZoneScopedN("Fixed Step");
|
||||||
|
|
||||||
|
customFixedUpdate(fixedDt * m_PhysicsTimeScale);
|
||||||
|
|
||||||
|
accumulator -= fixedDt;
|
||||||
|
steps++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (steps == maxSteps)
|
||||||
|
{
|
||||||
|
accumulator = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_PhysicsStepsLastFrame = steps;
|
||||||
|
|
||||||
|
TracyPlot("Fixed Steps", static_cast<int64_t>(steps));
|
||||||
}
|
}
|
||||||
if (steps == maxSteps) accumulator = 0.0f;
|
|
||||||
|
|
||||||
const float alpha = accumulator / fixedDt;
|
const float alpha = accumulator / fixedDt;
|
||||||
|
(void)alpha;
|
||||||
|
|
||||||
if (gfxDevice.needsSwapchainRecreate() || resizePending)
|
|
||||||
{
|
{
|
||||||
auto now = std::chrono::steady_clock::now();
|
ZoneScopedN("Swapchain Resize Check");
|
||||||
|
|
||||||
if (resizePending &&
|
if (gfxDevice.needsSwapchainRecreate() || resizePending)
|
||||||
now - lastResizeTime < std::chrono::milliseconds(100))
|
|
||||||
{
|
{
|
||||||
|
auto now = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
if (resizePending &&
|
||||||
|
now - lastResizeTime < std::chrono::milliseconds(100))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int w = 0;
|
||||||
|
int h = 0;
|
||||||
|
SDL_Vulkan_GetDrawableSize(window, &w, &h);
|
||||||
|
|
||||||
|
if (w == 0 || h == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
spdlog::info("Recreating swapchain to size: {}x{}", w, h);
|
||||||
|
|
||||||
|
{
|
||||||
|
ZoneScopedN("Recreate Swapchain");
|
||||||
|
gfxDevice.recreateSwapchain(w, h);
|
||||||
|
onWindowResize(w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
resizePending = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int w = 0;
|
|
||||||
int h = 0;
|
|
||||||
SDL_Vulkan_GetDrawableSize(window, &w, &h);
|
|
||||||
|
|
||||||
if (w == 0 || h == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
spdlog::info("Recreating swapchain to size: {}x{}", w, h);
|
|
||||||
|
|
||||||
gfxDevice.recreateSwapchain(w, h);
|
|
||||||
onWindowResize(w, h);
|
|
||||||
|
|
||||||
resizePending = false;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
customDraw();
|
{
|
||||||
|
ZoneScopedN("customDraw");
|
||||||
|
customDraw();
|
||||||
|
}
|
||||||
|
|
||||||
if (frameLimit)
|
if (frameLimit)
|
||||||
{
|
{
|
||||||
|
ZoneScopedN("Frame Limit Sleep");
|
||||||
|
|
||||||
auto sleepTime = Time::GetInstance().SleepDuration();
|
auto sleepTime = Time::GetInstance().SleepDuration();
|
||||||
if (sleepTime.count() > 0)
|
if (sleepTime.count() > 0)
|
||||||
{
|
{
|
||||||
@@ -199,3 +291,49 @@ void App::cleanup()
|
|||||||
spdlog::info("Cleaning up");
|
spdlog::info("Cleaning up");
|
||||||
customCleanup();
|
customCleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void App::drawPhysicsPanel(float dt, float fixedDt, float accumulator)
|
||||||
|
{
|
||||||
|
ImGui::Begin("Physics");
|
||||||
|
|
||||||
|
ImGui::Text("Frame dt: %.3f ms", dt * 1000.0f);
|
||||||
|
ImGui::Text("Fixed dt: %.3f ms", fixedDt * 1000.0f);
|
||||||
|
ImGui::Text("Accumulator: %.3f ms", accumulator * 1000.0f);
|
||||||
|
ImGui::Text("Steps last frame: %d", m_PhysicsStepsLastFrame);
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
if (ImGui::Button(m_PhysicsPaused ? "Resume Physics" : "Pause Physics"))
|
||||||
|
{
|
||||||
|
m_PhysicsPaused = !m_PhysicsPaused;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if (!m_PhysicsPaused)
|
||||||
|
{
|
||||||
|
ImGui::BeginDisabled();
|
||||||
|
ImGui::Button("Step Physics");
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ImGui::Button("Step Physics"))
|
||||||
|
{
|
||||||
|
m_PhysicsStepOnce = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Checkbox("Paused", &m_PhysicsPaused);
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
ImGui::SliderFloat("Physics Time Scale", &m_PhysicsTimeScale, 0.0f, 2.0f, "%.2fx");
|
||||||
|
|
||||||
|
if (ImGui::Button("Reset Time Scale"))
|
||||||
|
{
|
||||||
|
m_PhysicsTimeScale = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
@@ -19,13 +19,17 @@
|
|||||||
#include "destrum/Graphics/imageLoader.h"
|
#include "destrum/Graphics/imageLoader.h"
|
||||||
#include "destrum/Util/GameState.h"
|
#include "destrum/Util/GameState.h"
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
|
#include "tracy/Tracy.hpp"
|
||||||
|
|
||||||
|
#include "tracy/Tracy.hpp"
|
||||||
|
#include "tracy/TracyVulkan.hpp"
|
||||||
|
|
||||||
GfxDevice::GfxDevice(): imageCache(*this) {
|
GfxDevice::GfxDevice(): imageCache(*this) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GfxDevice::init(SDL_Window* window, const std::string& appName, bool vSync) {
|
void GfxDevice::init(SDL_Window* window, const std::string& appName, bool vSync) {
|
||||||
VK_CHECK(volkInitialize());
|
VK_CHECK(volkInitialize());
|
||||||
|
m_vSync = vSync;
|
||||||
instance = vkb::InstanceBuilder{}
|
instance = vkb::InstanceBuilder{}
|
||||||
.set_app_name(appName.c_str())
|
.set_app_name(appName.c_str())
|
||||||
.set_app_version(1, 0, 0)
|
.set_app_version(1, 0, 0)
|
||||||
@@ -131,6 +135,34 @@ void GfxDevice::init(SDL_Window* window, const std::string& appName, bool vSync)
|
|||||||
VK_CHECK(vkAllocateCommandBuffers(device, &cmdAllocInfo, &mainCommandBuffer));
|
VK_CHECK(vkAllocateCommandBuffers(device, &cmdAllocInfo, &mainCommandBuffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(TRACY_ENABLE)
|
||||||
|
{
|
||||||
|
VkCommandBuffer tracyInitCmd = frames[0].commandBuffer;
|
||||||
|
|
||||||
|
#if defined(TRACY_VK_USE_SYMBOL_TABLE)
|
||||||
|
tracyVkCtx = TracyVkContext(
|
||||||
|
instance,
|
||||||
|
physicalDevice,
|
||||||
|
device,
|
||||||
|
graphicsQueue,
|
||||||
|
tracyInitCmd,
|
||||||
|
vkGetInstanceProcAddr,
|
||||||
|
vkGetDeviceProcAddr
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
tracyVkCtx = TracyVkContext(
|
||||||
|
physicalDevice,
|
||||||
|
device,
|
||||||
|
graphicsQueue,
|
||||||
|
tracyInitCmd
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static constexpr char ctxName[] = "Graphics Queue";
|
||||||
|
TracyVkContextName(tracyVkCtx, ctxName, sizeof(ctxName) - 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
{ // create white texture
|
{ // create white texture
|
||||||
std::uint32_t pixel = 0xFFFFFFFF;
|
std::uint32_t pixel = 0xFFFFFFFF;
|
||||||
whiteImageId = createImage(
|
whiteImageId = createImage(
|
||||||
@@ -166,19 +198,30 @@ void GfxDevice::init(SDL_Window* window, const std::string& appName, bool vSync)
|
|||||||
void GfxDevice::recreateSwapchain(int width, int height) {
|
void GfxDevice::recreateSwapchain(int width, int height) {
|
||||||
assert(width != 0 && height != 0);
|
assert(width != 0 && height != 0);
|
||||||
waitIdle();
|
waitIdle();
|
||||||
swapchain.recreateSwapchain(*this, swapchainFormat, width, height, true);
|
swapchain.recreateSwapchain(*this, swapchainFormat, width, height, m_vSync);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkCommandBuffer GfxDevice::beginFrame() {
|
VkCommandBuffer GfxDevice::beginFrame()
|
||||||
swapchain.beginFrame(getCurrentFrameIndex());
|
{
|
||||||
|
ZoneScopedN("GfxDevice::beginFrame");
|
||||||
|
|
||||||
|
{
|
||||||
|
ZoneScopedN("Swapchain BeginFrame");
|
||||||
|
swapchain.beginFrame(getCurrentFrameIndex());
|
||||||
|
}
|
||||||
|
|
||||||
const auto& frame = getCurrentFrame();
|
const auto& frame = getCurrentFrame();
|
||||||
const auto& cmd = frame.commandBuffer;
|
const auto& cmd = frame.commandBuffer;
|
||||||
|
|
||||||
const auto cmdBeginInfo = VkCommandBufferBeginInfo{
|
const auto cmdBeginInfo = VkCommandBufferBeginInfo{
|
||||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||||
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
||||||
};
|
};
|
||||||
VK_CHECK(vkBeginCommandBuffer(cmd, &cmdBeginInfo));
|
|
||||||
|
{
|
||||||
|
ZoneScopedN("vkBeginCommandBuffer");
|
||||||
|
VK_CHECK(vkBeginCommandBuffer(cmd, &cmdBeginInfo));
|
||||||
|
}
|
||||||
|
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
@@ -188,17 +231,34 @@ VulkanImmediateExecutor& GfxDevice::GetImmediateExecuter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GfxDevice::endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const EndFrameProps& props) {
|
void GfxDevice::endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const EndFrameProps& props) {
|
||||||
|
ZoneScopedN("GfxDevice::endFrame");
|
||||||
|
|
||||||
// get swapchain image
|
// get swapchain image
|
||||||
const auto [swapchainImage, swapchainImageIndex] = swapchain.acquireNextImage(getCurrentFrameIndex());
|
VkImage swapchainImage = VK_NULL_HANDLE;
|
||||||
|
std::uint32_t swapchainImageIndex = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
ZoneScopedN("Swapchain AcquireNextImage");
|
||||||
|
|
||||||
|
const auto result = swapchain.acquireNextImage(getCurrentFrameIndex());
|
||||||
|
swapchainImage = result.first;
|
||||||
|
swapchainImageIndex = result.second;
|
||||||
|
}
|
||||||
|
|
||||||
if (swapchainImage == VK_NULL_HANDLE) {
|
if (swapchainImage == VK_NULL_HANDLE) {
|
||||||
spdlog::info("Swapchain is freaky, skipping frame...");
|
spdlog::info("Swapchain is freaky, skipping frame...");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fences are reset here to prevent the deadlock in case swapchain becomes dirty
|
// Fences are reset here to prevent the deadlock in case swapchain becomes dirty
|
||||||
swapchain.resetFences(getCurrentFrameIndex());
|
{
|
||||||
|
ZoneScopedN("Swapchain ResetFences");
|
||||||
|
swapchain.resetFences(getCurrentFrameIndex());
|
||||||
|
}
|
||||||
|
|
||||||
auto swapchainLayout = VK_IMAGE_LAYOUT_UNDEFINED; {
|
auto swapchainLayout = VK_IMAGE_LAYOUT_UNDEFINED; {
|
||||||
|
ZoneScopedN("Clear Swapchain Image");
|
||||||
|
|
||||||
const VkImageSubresourceRange clearRange = vkinit::imageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT);
|
const VkImageSubresourceRange clearRange = vkinit::imageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
vkutil::transitionImage(cmd, swapchainImage, swapchainLayout, VK_IMAGE_LAYOUT_GENERAL);
|
vkutil::transitionImage(cmd, swapchainImage, swapchainLayout, VK_IMAGE_LAYOUT_GENERAL);
|
||||||
swapchainLayout = VK_IMAGE_LAYOUT_GENERAL;
|
swapchainLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
@@ -208,6 +268,8 @@ void GfxDevice::endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const E
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
|
ZoneScopedN("Copy DrawImage To Swapchain");
|
||||||
|
|
||||||
// copy from draw image into swapchain
|
// copy from draw image into swapchain
|
||||||
vkutil::transitionImage(
|
vkutil::transitionImage(
|
||||||
cmd,
|
cmd,
|
||||||
@@ -248,6 +310,8 @@ void GfxDevice::endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const E
|
|||||||
// swapchainLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
// swapchainLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||||
|
|
||||||
if (props.imguiPass) {
|
if (props.imguiPass) {
|
||||||
|
ZoneScopedN("ImGui Render");
|
||||||
|
|
||||||
props.imguiPass->render(
|
props.imguiPass->render(
|
||||||
cmd,
|
cmd,
|
||||||
swapchainImage,
|
swapchainImage,
|
||||||
@@ -258,18 +322,37 @@ void GfxDevice::endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const E
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prepare for present
|
// prepare for present
|
||||||
vkutil::transitionImage(cmd, swapchainImage, swapchainLayout, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
{
|
||||||
swapchainLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
ZoneScopedN("Transition Swapchain To Present");
|
||||||
|
|
||||||
VK_CHECK(vkEndCommandBuffer(cmd));
|
vkutil::transitionImage(cmd, swapchainImage, swapchainLayout, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||||
|
swapchainLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||||
|
}
|
||||||
|
#if defined(TRACY_ENABLE)
|
||||||
|
TracyVkCollect(tracyVkCtx, cmd);
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
ZoneScopedN("vkEndCommandBuffer");
|
||||||
|
VK_CHECK(vkEndCommandBuffer(cmd));
|
||||||
|
}
|
||||||
|
|
||||||
// swapchain.submitAndPresent(cmd, graphicsQueue, getCurrentFrameIndex(), swapchainImageIndex);
|
// swapchain.submitAndPresent(cmd, graphicsQueue, getCurrentFrameIndex(), swapchainImageIndex);
|
||||||
swapchain.submitAndPresent(cmd, graphicsQueue, swapchainImageIndex, getCurrentFrameIndex());
|
{
|
||||||
|
ZoneScopedN("Swapchain SubmitAndPresent");
|
||||||
|
swapchain.submitAndPresent(cmd, graphicsQueue, swapchainImageIndex, getCurrentFrameIndex());
|
||||||
|
}
|
||||||
|
|
||||||
frameNumber++;
|
frameNumber++;
|
||||||
|
FrameMark;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GfxDevice::cleanup() {
|
void GfxDevice::cleanup() {
|
||||||
|
#if defined(TRACY_ENABLE)
|
||||||
|
if (tracyVkCtx) {
|
||||||
|
TracyVkDestroy(tracyVkCtx);
|
||||||
|
tracyVkCtx = nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void GfxDevice::waitIdle() {
|
void GfxDevice::waitIdle() {
|
||||||
|
|||||||
@@ -98,9 +98,9 @@ void MeshPipeline::draw(VkCommandBuffer cmd,
|
|||||||
for (const auto& dcIdx : drawCommands) {
|
for (const auto& dcIdx : drawCommands) {
|
||||||
const auto& dc = dcIdx;
|
const auto& dc = dcIdx;
|
||||||
|
|
||||||
// if (!edge::isInFrustum(frustum, dc.worldBoundingSphere)) {
|
if (!edge::isInFrustum(frustum, dc.worldBoundingSphere)) {
|
||||||
// continue;
|
continue;
|
||||||
// }
|
}
|
||||||
|
|
||||||
ActualDrawCalls++;
|
ActualDrawCalls++;
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
#include "destrum/Util/GameState.h"
|
#include "destrum/Util/GameState.h"
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
|
#include "tracy/TracyVulkan.hpp"
|
||||||
|
|
||||||
GameRenderer::GameRenderer(MeshCache& meshCache, MaterialCache& matCache): meshCache{meshCache}, materialCache{matCache} {
|
GameRenderer::GameRenderer(MeshCache& meshCache, MaterialCache& matCache): meshCache{meshCache}, materialCache{matCache} {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,13 +43,20 @@ void GameRenderer::endDrawing() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& camera, const SceneData& sceneData) {
|
void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& camera, const SceneData& sceneData) {
|
||||||
|
ZoneScopedN("GameRenderer::draw");
|
||||||
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "GameRenderer::draw");
|
||||||
|
|
||||||
for (const auto& dc : meshDrawCommands) {
|
{
|
||||||
if (!dc.skinnedMesh) {
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Skinning");
|
||||||
continue;
|
|
||||||
|
for (const auto& dc : meshDrawCommands) {
|
||||||
|
if (!dc.skinnedMesh) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
skinningPipeline->doSkinning(cmd, gfxDevice.getCurrentFrameIndex(), meshCache, dc);
|
||||||
}
|
}
|
||||||
skinningPipeline->doSkinning(cmd, gfxDevice.getCurrentFrameIndex(), meshCache, dc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto gpuSceneData = GPUSceneData{
|
const auto gpuSceneData = GPUSceneData{
|
||||||
.view = sceneData.camera.GetViewMatrix(),
|
.view = sceneData.camera.GetViewMatrix(),
|
||||||
.proj = sceneData.camera.GetProjectionMatrix(),
|
.proj = sceneData.camera.GetProjectionMatrix(),
|
||||||
@@ -59,40 +68,71 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
|||||||
.fogDensity = sceneData.fogDensity,
|
.fogDensity = sceneData.fogDensity,
|
||||||
.materialsBuffer = materialCache.getMaterialDataBufferAddress(),
|
.materialsBuffer = materialCache.getMaterialDataBufferAddress(),
|
||||||
};
|
};
|
||||||
vkutil::bufferHostWriteToShaderReadBarrier(
|
|
||||||
cmd,
|
{
|
||||||
materialCache.getMaterialDataBuffer().buffer,
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Material Buffer Barrier");
|
||||||
0,
|
|
||||||
VK_WHOLE_SIZE
|
vkutil::bufferHostWriteToShaderReadBarrier(
|
||||||
);
|
cmd,
|
||||||
sceneDataBuffer.uploadNewData(cmd, gfxDevice.getCurrentFrameIndex(), (void*)&gpuSceneData, sizeof(GPUSceneData));
|
materialCache.getMaterialDataBuffer().buffer,
|
||||||
|
0,
|
||||||
|
VK_WHOLE_SIZE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Upload Scene Data");
|
||||||
|
|
||||||
|
sceneDataBuffer.uploadNewData(
|
||||||
|
cmd,
|
||||||
|
gfxDevice.getCurrentFrameIndex(),
|
||||||
|
(void*)&gpuSceneData,
|
||||||
|
sizeof(GPUSceneData)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const auto& drawImage = gfxDevice.getImage(drawImageId);
|
const auto& drawImage = gfxDevice.getImage(drawImageId);
|
||||||
const auto& depthImage = gfxDevice.getImage(depthImageId);
|
const auto& depthImage = gfxDevice.getImage(depthImageId);
|
||||||
|
|
||||||
// vkutil::cmdBeginLabel(cmd, "Geometry");
|
// vkutil::cmdBeginLabel(cmd, "Geometry");
|
||||||
vkutil::transitionImage(
|
{
|
||||||
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Transition Draw Image");
|
||||||
|
|
||||||
|
vkutil::transitionImage(
|
||||||
cmd,
|
cmd,
|
||||||
drawImage.image,
|
drawImage.image,
|
||||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||||
|
}
|
||||||
|
|
||||||
vkutil::transitionImage(
|
{
|
||||||
cmd,
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Transition Depth Image");
|
||||||
depthImage.image,
|
|
||||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
vkutil::transitionImage(
|
||||||
VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL);
|
cmd,
|
||||||
|
depthImage.image,
|
||||||
|
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL);
|
||||||
|
}
|
||||||
|
|
||||||
const auto renderInfo = vkutil::createRenderingInfo({
|
const auto renderInfo = vkutil::createRenderingInfo({
|
||||||
.renderExtent = drawImage.getExtent2D(),
|
.renderExtent = drawImage.getExtent2D(),
|
||||||
.colorImageView = drawImage.imageView,
|
.colorImageView = drawImage.imageView,
|
||||||
.colorImageClearValue = glm::vec4{0.f, 0.f, 0.f, 1.f},
|
.colorImageClearValue = glm::vec4{0.f, 0.f, 0.f, 1.f},
|
||||||
.depthImageView = depthImage.imageView,
|
.depthImageView = depthImage.imageView,
|
||||||
.depthImageClearValue = 1.f,
|
.depthImageClearValue = 1.f,
|
||||||
});
|
});
|
||||||
|
|
||||||
vkCmdBeginRendering(cmd, &renderInfo.renderingInfo);
|
{
|
||||||
meshPipeline->draw(
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "vkCmdBeginRendering");
|
||||||
|
|
||||||
|
vkCmdBeginRendering(cmd, &renderInfo.renderingInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "MeshPipeline::draw");
|
||||||
|
|
||||||
|
meshPipeline->draw(
|
||||||
cmd,
|
cmd,
|
||||||
drawImage.getExtent2D(),
|
drawImage.getExtent2D(),
|
||||||
gfxDevice,
|
gfxDevice,
|
||||||
@@ -102,14 +142,20 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
|||||||
sceneDataBuffer.getBuffer(),
|
sceneDataBuffer.getBuffer(),
|
||||||
meshDrawCommands,
|
meshDrawCommands,
|
||||||
sortedMeshDrawCommands);
|
sortedMeshDrawCommands);
|
||||||
|
}
|
||||||
|
|
||||||
skyboxPipeline->draw(cmd, gfxDevice, camera);
|
{
|
||||||
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "SkyboxPipeline::draw");
|
||||||
|
|
||||||
|
skyboxPipeline->draw(cmd, gfxDevice, camera);
|
||||||
|
}
|
||||||
|
|
||||||
vkCmdEndRendering(cmd);
|
{
|
||||||
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "vkCmdEndRendering");
|
||||||
|
|
||||||
|
vkCmdEndRendering(cmd);
|
||||||
|
}
|
||||||
// vkutil::cmdEndLabel(cmd);
|
// vkutil::cmdEndLabel(cmd);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameRenderer::cleanup(GfxDevice& gfxDevice) {
|
void GameRenderer::cleanup(GfxDevice& gfxDevice) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <destrum/Graphics/Init.h>
|
#include <destrum/Graphics/Init.h>
|
||||||
|
|
||||||
#include "volk.h"
|
#include "volk.h"
|
||||||
|
#include "tracy/Tracy.hpp"
|
||||||
|
|
||||||
|
|
||||||
void Swapchain::initSync(VkDevice device) {
|
void Swapchain::initSync(VkDevice device) {
|
||||||
@@ -23,30 +24,40 @@ void Swapchain::initSync(VkDevice device) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Swapchain::createSwapchain(GfxDevice* gfxDevice, VkFormat format, std::uint32_t width, std::uint32_t height, bool vSync) {
|
void Swapchain::createSwapchain(GfxDevice* gfxDevice, VkFormat format, std::uint32_t width, std::uint32_t height, bool vSync) {
|
||||||
|
ZoneScopedN("Swapchain::createSwapchain");
|
||||||
|
|
||||||
m_gfxDevice = gfxDevice;
|
m_gfxDevice = gfxDevice;
|
||||||
assert(format == VK_FORMAT_B8G8R8A8_SRGB && "TODO: test other formats");
|
assert(format == VK_FORMAT_B8G8R8A8_SRGB && "TODO: test other formats");
|
||||||
vSync = true;
|
// vSync = true;
|
||||||
|
|
||||||
auto res = vkb::SwapchainBuilder{gfxDevice->getDevice()}
|
{
|
||||||
.set_desired_format(VkSurfaceFormatKHR{
|
ZoneScopedN("vkb::SwapchainBuilder::build");
|
||||||
.format = format,
|
|
||||||
.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
|
auto res = vkb::SwapchainBuilder{gfxDevice->getDevice()}
|
||||||
})
|
.set_desired_format(VkSurfaceFormatKHR{
|
||||||
.add_image_usage_flags(VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
|
.format = format,
|
||||||
.set_desired_present_mode(
|
.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
|
||||||
vSync ? VK_PRESENT_MODE_FIFO_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR)
|
})
|
||||||
.set_desired_extent(width, height)
|
.add_image_usage_flags(VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
|
||||||
.build();
|
.set_desired_present_mode(
|
||||||
if (!res.has_value()) {
|
vSync ? VK_PRESENT_MODE_FIFO_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR)
|
||||||
// throw std::runtime_error(std::format(
|
.set_desired_extent(width, height)
|
||||||
// "failed to create swapchain: error = {}, vk result = {}",
|
.build();
|
||||||
// res.full_error().type.message(),
|
if (!res.has_value()) {
|
||||||
// string_VkResult(res.full_error().vk_result)));
|
// throw std::runtime_error(std::format(
|
||||||
|
// "failed to create swapchain: error = {}, vk result = {}",
|
||||||
|
// res.full_error().type.message(),
|
||||||
|
// string_VkResult(res.full_error().vk_result)));
|
||||||
|
}
|
||||||
|
m_swapchain = res.value();
|
||||||
}
|
}
|
||||||
m_swapchain = res.value();
|
|
||||||
|
|
||||||
images = m_swapchain.get_images().value();
|
{
|
||||||
imageViews = m_swapchain.get_image_views().value();
|
ZoneScopedN("Get Swapchain Images / Views");
|
||||||
|
|
||||||
|
images = m_swapchain.get_images().value();
|
||||||
|
imageViews = m_swapchain.get_image_views().value();
|
||||||
|
}
|
||||||
|
|
||||||
imageRenderSemaphores.resize(images.size());
|
imageRenderSemaphores.resize(images.size());
|
||||||
|
|
||||||
@@ -55,6 +66,8 @@ void Swapchain::createSwapchain(GfxDevice* gfxDevice, VkFormat format, std::uint
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (auto& sem: imageRenderSemaphores) {
|
for (auto& sem: imageRenderSemaphores) {
|
||||||
|
ZoneScopedN("Create Image Render Semaphore");
|
||||||
|
|
||||||
VK_CHECK(vkCreateSemaphore(m_gfxDevice->getDevice(), &sci, nullptr, &sem));
|
VK_CHECK(vkCreateSemaphore(m_gfxDevice->getDevice(), &sci, nullptr, &sem));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,6 +84,8 @@ void Swapchain::recreateSwapchain(
|
|||||||
std::uint32_t height,
|
std::uint32_t height,
|
||||||
bool vSync)
|
bool vSync)
|
||||||
{
|
{
|
||||||
|
ZoneScopedN("Swapchain::recreateSwapchain");
|
||||||
|
|
||||||
if (width == 0 || height == 0) {
|
if (width == 0 || height == 0) {
|
||||||
dirty = true;
|
dirty = true;
|
||||||
return;
|
return;
|
||||||
@@ -78,45 +93,67 @@ void Swapchain::recreateSwapchain(
|
|||||||
|
|
||||||
VkDevice device = gfxDevice.getDevice();
|
VkDevice device = gfxDevice.getDevice();
|
||||||
|
|
||||||
vkDeviceWaitIdle(device);
|
{
|
||||||
|
ZoneScopedN("vkDeviceWaitIdle");
|
||||||
|
vkDeviceWaitIdle(device);
|
||||||
|
}
|
||||||
|
|
||||||
auto oldSwapchain = m_swapchain;
|
auto oldSwapchain = m_swapchain;
|
||||||
|
|
||||||
auto res = vkb::SwapchainBuilder{gfxDevice.getVkbDevice()}
|
{
|
||||||
.set_old_swapchain(oldSwapchain)
|
ZoneScopedN("vkb::SwapchainBuilder::rebuild");
|
||||||
.set_desired_format(VkSurfaceFormatKHR{
|
|
||||||
.format = format,
|
|
||||||
.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
|
|
||||||
})
|
|
||||||
.add_image_usage_flags(VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
|
|
||||||
.set_desired_present_mode(
|
|
||||||
vSync ? VK_PRESENT_MODE_FIFO_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR)
|
|
||||||
.set_desired_extent(width, height)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
if (!res.has_value()) {
|
auto res = vkb::SwapchainBuilder{gfxDevice.getVkbDevice()}
|
||||||
// throw std::runtime_error(std::format(
|
.set_old_swapchain(oldSwapchain)
|
||||||
// "failed to create swapchain: error = {}, vk result = {}",
|
.set_desired_format(VkSurfaceFormatKHR{
|
||||||
// res.full_error().type.message(),
|
.format = format,
|
||||||
// string_VkResult(res.full_error().vk_result)));
|
.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
|
||||||
|
})
|
||||||
|
.add_image_usage_flags(VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
|
||||||
|
.set_desired_present_mode(
|
||||||
|
vSync ? VK_PRESENT_MODE_FIFO_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR)
|
||||||
|
.set_desired_extent(width, height)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
if (!res.has_value()) {
|
||||||
|
// throw std::runtime_error(std::format(
|
||||||
|
// "failed to create swapchain: error = {}, vk result = {}",
|
||||||
|
// res.full_error().type.message(),
|
||||||
|
// string_VkResult(res.full_error().vk_result)));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_swapchain = res.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto sem : imageRenderSemaphores) {
|
{
|
||||||
vkDestroySemaphore(device, sem, nullptr);
|
ZoneScopedN("Destroy Old Image Render Semaphores");
|
||||||
|
|
||||||
|
for (auto sem : imageRenderSemaphores) {
|
||||||
|
vkDestroySemaphore(device, sem, nullptr);
|
||||||
|
}
|
||||||
|
imageRenderSemaphores.clear();
|
||||||
}
|
}
|
||||||
imageRenderSemaphores.clear();
|
|
||||||
|
|
||||||
for (auto imageView : imageViews) {
|
{
|
||||||
vkDestroyImageView(device, imageView, nullptr);
|
ZoneScopedN("Destroy Old Image Views");
|
||||||
|
|
||||||
|
for (auto imageView : imageViews) {
|
||||||
|
vkDestroyImageView(device, imageView, nullptr);
|
||||||
|
}
|
||||||
|
imageViews.clear();
|
||||||
}
|
}
|
||||||
imageViews.clear();
|
|
||||||
|
|
||||||
vkb::destroy_swapchain(oldSwapchain);
|
{
|
||||||
|
ZoneScopedN("Destroy Old Swapchain");
|
||||||
|
vkb::destroy_swapchain(oldSwapchain);
|
||||||
|
}
|
||||||
|
|
||||||
m_swapchain = res.value();
|
{
|
||||||
|
ZoneScopedN("Get New Swapchain Images / Views");
|
||||||
|
|
||||||
images = m_swapchain.get_images().value();
|
images = m_swapchain.get_images().value();
|
||||||
imageViews = m_swapchain.get_image_views().value();
|
imageViews = m_swapchain.get_image_views().value();
|
||||||
|
}
|
||||||
|
|
||||||
VkSemaphoreCreateInfo sci{
|
VkSemaphoreCreateInfo sci{
|
||||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||||
@@ -125,6 +162,8 @@ void Swapchain::recreateSwapchain(
|
|||||||
imageRenderSemaphores.resize(images.size());
|
imageRenderSemaphores.resize(images.size());
|
||||||
|
|
||||||
for (auto& sem : imageRenderSemaphores) {
|
for (auto& sem : imageRenderSemaphores) {
|
||||||
|
ZoneScopedN("Create New Image Render Semaphore");
|
||||||
|
|
||||||
VK_CHECK(vkCreateSemaphore(device, &sci, nullptr, &sem));
|
VK_CHECK(vkCreateSemaphore(device, &sci, nullptr, &sem));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,13 +187,25 @@ void Swapchain::cleanup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Swapchain::beginFrame(int index) const {
|
void Swapchain::beginFrame(int index) const {
|
||||||
|
ZoneScopedN("Swapchain::beginFrame");
|
||||||
|
|
||||||
auto& frame = frames[index];
|
auto& frame = frames[index];
|
||||||
VK_CHECK(vkWaitForFences(m_gfxDevice->getDevice(), 1, &frame.renderFence, true, std::numeric_limits<std::uint64_t>::max()));
|
|
||||||
|
{
|
||||||
|
ZoneScopedN("vkWaitForFences");
|
||||||
|
VK_CHECK(vkWaitForFences(m_gfxDevice->getDevice(), 1, &frame.renderFence, true, std::numeric_limits<std::uint64_t>::max()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Swapchain::resetFences(int index) const {
|
void Swapchain::resetFences(int index) const {
|
||||||
|
ZoneScopedN("Swapchain::resetFences");
|
||||||
|
|
||||||
auto& frame = frames[index];
|
auto& frame = frames[index];
|
||||||
VK_CHECK(vkResetFences(m_gfxDevice->getDevice(), 1, &frame.renderFence));
|
|
||||||
|
{
|
||||||
|
ZoneScopedN("vkResetFences");
|
||||||
|
VK_CHECK(vkResetFences(m_gfxDevice->getDevice(), 1, &frame.renderFence));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SwapchainAcquireResult {
|
struct SwapchainAcquireResult {
|
||||||
@@ -164,14 +215,24 @@ struct SwapchainAcquireResult {
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::pair<VkImage, int> Swapchain::acquireNextImage(int index) {
|
std::pair<VkImage, int> Swapchain::acquireNextImage(int index) {
|
||||||
|
ZoneScopedN("Swapchain::acquireNextImage");
|
||||||
|
|
||||||
std::uint32_t swapchainImageIndex{};
|
std::uint32_t swapchainImageIndex{};
|
||||||
const auto result = vkAcquireNextImageKHR(
|
|
||||||
m_gfxDevice->getDevice(),
|
VkResult result = VK_SUCCESS;
|
||||||
m_swapchain,
|
|
||||||
std::numeric_limits<std::uint64_t>::max(),
|
{
|
||||||
frames[index].swapchainSemaphore,
|
ZoneScopedN("vkAcquireNextImageKHR");
|
||||||
VK_NULL_HANDLE,
|
|
||||||
&swapchainImageIndex);
|
result = vkAcquireNextImageKHR(
|
||||||
|
m_gfxDevice->getDevice(),
|
||||||
|
m_swapchain,
|
||||||
|
std::numeric_limits<std::uint64_t>::max(),
|
||||||
|
frames[index].swapchainSemaphore,
|
||||||
|
VK_NULL_HANDLE,
|
||||||
|
&swapchainImageIndex);
|
||||||
|
}
|
||||||
|
|
||||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
|
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
|
||||||
dirty = true;
|
dirty = true;
|
||||||
return {images[swapchainImageIndex], swapchainImageIndex};
|
return {images[swapchainImageIndex], swapchainImageIndex};
|
||||||
@@ -188,6 +249,8 @@ void Swapchain::submitAndPresent(
|
|||||||
uint32_t imageIndex, // from vkAcquireNextImageKHR
|
uint32_t imageIndex, // from vkAcquireNextImageKHR
|
||||||
uint32_t frameIndex) // 0..FRAMES_IN_FLIGHT-1
|
uint32_t frameIndex) // 0..FRAMES_IN_FLIGHT-1
|
||||||
{
|
{
|
||||||
|
ZoneScopedN("Swapchain::submitAndPresent");
|
||||||
|
|
||||||
auto& frame = frames[frameIndex]; // ✅ per-frame
|
auto& frame = frames[frameIndex]; // ✅ per-frame
|
||||||
|
|
||||||
VkSemaphore renderFinished = imageRenderSemaphores[imageIndex]; // ✅ per-image
|
VkSemaphore renderFinished = imageRenderSemaphores[imageIndex]; // ✅ per-image
|
||||||
@@ -209,7 +272,11 @@ void Swapchain::submitAndPresent(
|
|||||||
renderFinished); // ✅ signal semaphore (per-image)
|
renderFinished); // ✅ signal semaphore (per-image)
|
||||||
|
|
||||||
VkSubmitInfo2 submit = vkinit::submitInfo(&cmdInfo, &waitInfo, &signalInfo);
|
VkSubmitInfo2 submit = vkinit::submitInfo(&cmdInfo, &waitInfo, &signalInfo);
|
||||||
VK_CHECK(vkQueueSubmit2(graphicsQueue, 1, &submit, frame.renderFence)); // ✅ fence (per-frame)
|
|
||||||
|
{
|
||||||
|
ZoneScopedN("vkQueueSubmit2");
|
||||||
|
VK_CHECK(vkQueueSubmit2(graphicsQueue, 1, &submit, frame.renderFence)); // ✅ fence (per-frame)
|
||||||
|
}
|
||||||
|
|
||||||
// present
|
// present
|
||||||
VkPresentInfoKHR presentInfo{
|
VkPresentInfoKHR presentInfo{
|
||||||
@@ -221,7 +288,13 @@ void Swapchain::submitAndPresent(
|
|||||||
.pImageIndices = &imageIndex, // ✅ imageIndex, NOT frameIndex
|
.pImageIndices = &imageIndex, // ✅ imageIndex, NOT frameIndex
|
||||||
};
|
};
|
||||||
|
|
||||||
VkResult res = vkQueuePresentKHR(graphicsQueue, &presentInfo);
|
VkResult res = VK_SUCCESS;
|
||||||
|
|
||||||
|
{
|
||||||
|
ZoneScopedN("vkQueuePresentKHR");
|
||||||
|
res = vkQueuePresentKHR(graphicsQueue, &presentInfo);
|
||||||
|
}
|
||||||
|
|
||||||
if (res == VK_ERROR_OUT_OF_DATE_KHR || res == VK_SUBOPTIMAL_KHR) dirty = true;
|
if (res == VK_ERROR_OUT_OF_DATE_KHR || res == VK_SUBOPTIMAL_KHR) dirty = true;
|
||||||
else if (res != VK_SUCCESS) dirty = true;
|
else if (res != VK_SUCCESS) dirty = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,692 @@
|
|||||||
|
#include <destrum/Physics/JoltPhysicsWorld.h>
|
||||||
|
|
||||||
|
// Jolt/Jolt.h must be included before other Jolt headers.
|
||||||
|
#include <Jolt/Jolt.h>
|
||||||
|
|
||||||
|
#include <Jolt/Core/Factory.h>
|
||||||
|
#include <Jolt/Core/JobSystemThreadPool.h>
|
||||||
|
#include <Jolt/Core/TempAllocator.h>
|
||||||
|
#include <Jolt/Physics/Body/BodyCreationSettings.h>
|
||||||
|
#include <Jolt/Physics/Body/BodyInterface.h>
|
||||||
|
#include <Jolt/Physics/Body/MotionType.h>
|
||||||
|
#include <Jolt/Physics/Collision/BroadPhase/BroadPhaseLayer.h>
|
||||||
|
#include <Jolt/Physics/Collision/CastResult.h>
|
||||||
|
#include <Jolt/Physics/Collision/ObjectLayer.h>
|
||||||
|
#include <Jolt/Physics/Collision/RayCast.h>
|
||||||
|
#include <Jolt/Physics/Collision/Shape/BoxShape.h>
|
||||||
|
#include <Jolt/Physics/Collision/Shape/CapsuleShape.h>
|
||||||
|
#include <Jolt/Physics/Collision/Shape/SphereShape.h>
|
||||||
|
#include <Jolt/Physics/PhysicsSystem.h>
|
||||||
|
#include <Jolt/RegisterTypes.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <atomic>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <memory>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <thread>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <glm/gtx/norm.hpp>
|
||||||
|
|
||||||
|
#include <destrum/Components/Physics/Rigidbody.h>
|
||||||
|
#include <destrum/ObjectModel/GameObject.h>
|
||||||
|
#include <destrum/ObjectModel/Transform.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using namespace JPH;
|
||||||
|
|
||||||
|
static std::atomic_uint32_t g_JoltInstanceCount{0};
|
||||||
|
|
||||||
|
static void TraceImpl(const char* inFMT, ...)
|
||||||
|
{
|
||||||
|
va_list list;
|
||||||
|
va_start(list, inFMT);
|
||||||
|
std::vprintf(inFMT, list);
|
||||||
|
std::printf("\n");
|
||||||
|
va_end(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef JPH_ENABLE_ASSERTS
|
||||||
|
static bool AssertFailedImpl(const char* inExpression,
|
||||||
|
const char* inMessage,
|
||||||
|
const char* inFile,
|
||||||
|
JPH::uint inLine)
|
||||||
|
{
|
||||||
|
std::printf("%s:%u: (%s) %s\n",
|
||||||
|
inFile,
|
||||||
|
inLine,
|
||||||
|
inExpression,
|
||||||
|
inMessage != nullptr ? inMessage : "");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void InitJoltGlobals()
|
||||||
|
{
|
||||||
|
if (g_JoltInstanceCount.fetch_add(1) == 0)
|
||||||
|
{
|
||||||
|
RegisterDefaultAllocator();
|
||||||
|
|
||||||
|
Trace = TraceImpl;
|
||||||
|
JPH_IF_ENABLE_ASSERTS(AssertFailed = AssertFailedImpl;)
|
||||||
|
|
||||||
|
Factory::sInstance = new Factory();
|
||||||
|
|
||||||
|
RegisterTypes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShutdownJoltGlobals()
|
||||||
|
{
|
||||||
|
if (g_JoltInstanceCount.fetch_sub(1) == 1)
|
||||||
|
{
|
||||||
|
UnregisterTypes();
|
||||||
|
|
||||||
|
delete Factory::sInstance;
|
||||||
|
Factory::sInstance = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Layers
|
||||||
|
{
|
||||||
|
static constexpr ObjectLayer NON_MOVING = 0;
|
||||||
|
static constexpr ObjectLayer MOVING = 1;
|
||||||
|
static constexpr ObjectLayer NUM_LAYERS = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace BroadPhaseLayers
|
||||||
|
{
|
||||||
|
static constexpr BroadPhaseLayer NON_MOVING(0);
|
||||||
|
static constexpr BroadPhaseLayer MOVING(1);
|
||||||
|
static constexpr JPH::uint NUM_LAYERS(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ObjectLayerPairFilterImpl final : public ObjectLayerPairFilter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool ShouldCollide(ObjectLayer inObject1, ObjectLayer inObject2) const override
|
||||||
|
{
|
||||||
|
switch (inObject1)
|
||||||
|
{
|
||||||
|
case Layers::NON_MOVING:
|
||||||
|
return inObject2 == Layers::MOVING;
|
||||||
|
|
||||||
|
case Layers::MOVING:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
JPH_ASSERT(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class BPLayerInterfaceImpl final : public BroadPhaseLayerInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BPLayerInterfaceImpl()
|
||||||
|
{
|
||||||
|
m_ObjectToBroadPhase[Layers::NON_MOVING] = BroadPhaseLayers::NON_MOVING;
|
||||||
|
m_ObjectToBroadPhase[Layers::MOVING] = BroadPhaseLayers::MOVING;
|
||||||
|
}
|
||||||
|
|
||||||
|
JPH::uint GetNumBroadPhaseLayers() const override
|
||||||
|
{
|
||||||
|
return BroadPhaseLayers::NUM_LAYERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
BroadPhaseLayer GetBroadPhaseLayer(ObjectLayer inLayer) const override
|
||||||
|
{
|
||||||
|
JPH_ASSERT(inLayer < Layers::NUM_LAYERS);
|
||||||
|
return m_ObjectToBroadPhase[inLayer];
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(JPH_EXTERNAL_PROFILE) || defined(JPH_PROFILE_ENABLED)
|
||||||
|
const char* GetBroadPhaseLayerName(BroadPhaseLayer inLayer) const override
|
||||||
|
{
|
||||||
|
switch ((BroadPhaseLayer::Type)inLayer)
|
||||||
|
{
|
||||||
|
case (BroadPhaseLayer::Type)BroadPhaseLayers::NON_MOVING:
|
||||||
|
return "NON_MOVING";
|
||||||
|
|
||||||
|
case (BroadPhaseLayer::Type)BroadPhaseLayers::MOVING:
|
||||||
|
return "MOVING";
|
||||||
|
|
||||||
|
default:
|
||||||
|
JPH_ASSERT(false);
|
||||||
|
return "INVALID";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
BroadPhaseLayer m_ObjectToBroadPhase[Layers::NUM_LAYERS];
|
||||||
|
};
|
||||||
|
|
||||||
|
class ObjectVsBroadPhaseLayerFilterImpl final : public ObjectVsBroadPhaseLayerFilter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool ShouldCollide(ObjectLayer inLayer1, BroadPhaseLayer inLayer2) const override
|
||||||
|
{
|
||||||
|
switch (inLayer1)
|
||||||
|
{
|
||||||
|
case Layers::NON_MOVING:
|
||||||
|
return inLayer2 == BroadPhaseLayers::MOVING;
|
||||||
|
|
||||||
|
case Layers::MOVING:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
JPH_ASSERT(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] Vec3 ToJoltVec3(const glm::vec3& v)
|
||||||
|
{
|
||||||
|
return Vec3(v.x, v.y, v.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] RVec3 ToJoltRVec3(const glm::vec3& v)
|
||||||
|
{
|
||||||
|
return RVec3(v.x, v.y, v.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Quat ToJoltQuat(const glm::quat& q)
|
||||||
|
{
|
||||||
|
return Quat(q.x, q.y, q.z, q.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] glm::vec3 FromJoltVec3(Vec3Arg v)
|
||||||
|
{
|
||||||
|
return glm::vec3(v.GetX(), v.GetY(), v.GetZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] glm::vec3 FromJoltRVec3(RVec3Arg v)
|
||||||
|
{
|
||||||
|
return glm::vec3(static_cast<float>(v.GetX()),
|
||||||
|
static_cast<float>(v.GetY()),
|
||||||
|
static_cast<float>(v.GetZ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] glm::quat FromJoltQuat(QuatArg q)
|
||||||
|
{
|
||||||
|
return glm::quat(q.GetW(), q.GetX(), q.GetY(), q.GetZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] EMotionType ToJoltMotionType(RigidbodyType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case RigidbodyType::Static:
|
||||||
|
return EMotionType::Static;
|
||||||
|
|
||||||
|
case RigidbodyType::Dynamic:
|
||||||
|
return EMotionType::Dynamic;
|
||||||
|
|
||||||
|
case RigidbodyType::Kinematic:
|
||||||
|
return EMotionType::Kinematic;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return EMotionType::Static;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] ObjectLayer ToJoltObjectLayer(RigidbodyType type)
|
||||||
|
{
|
||||||
|
return type == RigidbodyType::Static ? Layers::NON_MOVING : Layers::MOVING;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] ShapeRefC CreateJoltShape(const PhysicsShapeDesc& desc)
|
||||||
|
{
|
||||||
|
switch (desc.type)
|
||||||
|
{
|
||||||
|
case PhysicsShapeType::Box:
|
||||||
|
{
|
||||||
|
BoxShapeSettings settings(ToJoltVec3(desc.halfExtents));
|
||||||
|
ShapeSettings::ShapeResult result = settings.Create();
|
||||||
|
|
||||||
|
if (!result.IsValid())
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string("Failed to create Jolt box shape: ") + std::string(result.GetError()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
case PhysicsShapeType::Sphere:
|
||||||
|
return new SphereShape(desc.radius);
|
||||||
|
|
||||||
|
case PhysicsShapeType::Capsule:
|
||||||
|
{
|
||||||
|
// Jolt expects half-height of the cylindrical section, not full capsule height.
|
||||||
|
const float halfCylinderHeight = std::max(0.0f, (desc.height * 0.5f) - desc.radius);
|
||||||
|
return new CapsuleShape(halfCylinderHeight, desc.radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
case PhysicsShapeType::None:
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Cannot create Jolt body without a valid shape.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
class JoltPhysicsWorld::Impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Impl(const Settings& settings)
|
||||||
|
: m_Settings(settings)
|
||||||
|
{
|
||||||
|
InitJoltGlobals();
|
||||||
|
|
||||||
|
const JPH::uint hardwareThreads = std::thread::hardware_concurrency();
|
||||||
|
const JPH::uint workerThreads =
|
||||||
|
settings.workerThreadCount != 0
|
||||||
|
? settings.workerThreadCount
|
||||||
|
: std::max<JPH::uint>(1, hardwareThreads > 0 ? hardwareThreads - 1 : 1);
|
||||||
|
|
||||||
|
m_TempAllocator = std::make_unique<TempAllocatorImpl>(settings.tempAllocatorSizeBytes);
|
||||||
|
m_JobSystem = std::make_unique<JobSystemThreadPool>(
|
||||||
|
cMaxPhysicsJobs,
|
||||||
|
cMaxPhysicsBarriers,
|
||||||
|
static_cast<int>(workerThreads));
|
||||||
|
|
||||||
|
m_PhysicsSystem.Init(
|
||||||
|
settings.maxBodies,
|
||||||
|
settings.numBodyMutexes,
|
||||||
|
settings.maxBodyPairs,
|
||||||
|
settings.maxContactConstraints,
|
||||||
|
m_BPLayerInterface,
|
||||||
|
m_ObjectVsBroadPhaseLayerFilter,
|
||||||
|
m_ObjectLayerPairFilter);
|
||||||
|
|
||||||
|
m_PhysicsSystem.SetGravity(ToJoltVec3(settings.gravity));
|
||||||
|
}
|
||||||
|
|
||||||
|
~Impl()
|
||||||
|
{
|
||||||
|
BodyInterface& bodyInterface = m_PhysicsSystem.GetBodyInterface();
|
||||||
|
|
||||||
|
for (auto& [handleId, record] : m_Bodies)
|
||||||
|
{
|
||||||
|
if (!record.alive)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyInterface.RemoveBody(record.bodyID);
|
||||||
|
bodyInterface.DestroyBody(record.bodyID);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Bodies.clear();
|
||||||
|
|
||||||
|
ShutdownJoltGlobals();
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsBodyHandle CreateBody(const PhysicsBodyDesc& desc)
|
||||||
|
{
|
||||||
|
ShapeRefC shape = CreateJoltShape(desc.shape);
|
||||||
|
|
||||||
|
// This first backend ignores centerOffset for now.
|
||||||
|
// Later, use JPH::OffsetCenterOfMassShapeSettings for offset colliders.
|
||||||
|
|
||||||
|
BodyCreationSettings settings(
|
||||||
|
shape,
|
||||||
|
ToJoltRVec3(desc.transform.position),
|
||||||
|
ToJoltQuat(desc.transform.rotation),
|
||||||
|
ToJoltMotionType(desc.type),
|
||||||
|
ToJoltObjectLayer(desc.type));
|
||||||
|
|
||||||
|
settings.mFriction = desc.material.friction;
|
||||||
|
settings.mRestitution = desc.material.restitution;
|
||||||
|
settings.mIsSensor = desc.shape.isTrigger;
|
||||||
|
settings.mAllowSleeping = desc.allowSleep;
|
||||||
|
settings.mGravityFactor = desc.useGravity ? 1.0f : 0.0f;
|
||||||
|
settings.mUserData = reinterpret_cast<JPH::uint64>(desc.owner);
|
||||||
|
|
||||||
|
if (desc.type == RigidbodyType::Dynamic)
|
||||||
|
{
|
||||||
|
settings.mOverrideMassProperties = EOverrideMassProperties::CalculateInertia;
|
||||||
|
settings.mMassPropertiesOverride.mMass = std::max(0.0001f, desc.mass);
|
||||||
|
}
|
||||||
|
|
||||||
|
const EActivation activation =
|
||||||
|
desc.type == RigidbodyType::Dynamic ? EActivation::Activate : EActivation::DontActivate;
|
||||||
|
|
||||||
|
BodyInterface& bodyInterface = m_PhysicsSystem.GetBodyInterface();
|
||||||
|
BodyID bodyID = bodyInterface.CreateAndAddBody(settings, activation);
|
||||||
|
|
||||||
|
if (bodyID.IsInvalid())
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsBodyHandle handle{m_NextHandle++};
|
||||||
|
|
||||||
|
BodyRecord record{};
|
||||||
|
record.alive = true;
|
||||||
|
record.bodyID = bodyID;
|
||||||
|
record.desc = desc;
|
||||||
|
|
||||||
|
m_Bodies.emplace(handle.id, record);
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DestroyBody(PhysicsBodyHandle body)
|
||||||
|
{
|
||||||
|
auto it = m_Bodies.find(body.id);
|
||||||
|
if (it == m_Bodies.end() || !it->second.alive)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BodyInterface& bodyInterface = m_PhysicsSystem.GetBodyInterface();
|
||||||
|
bodyInterface.RemoveBody(it->second.bodyID);
|
||||||
|
bodyInterface.DestroyBody(it->second.bodyID);
|
||||||
|
|
||||||
|
m_Bodies.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Step(float fixedDt)
|
||||||
|
{
|
||||||
|
if (fixedDt <= 0.0f)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int collisionSteps = std::max(1, static_cast<int>(std::ceil(fixedDt / (1.0f / 60.0f))));
|
||||||
|
|
||||||
|
m_PhysicsSystem.Update(
|
||||||
|
fixedDt,
|
||||||
|
collisionSteps,
|
||||||
|
m_TempAllocator.get(),
|
||||||
|
m_JobSystem.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SyncKinematicBodiesToPhysics()
|
||||||
|
{
|
||||||
|
BodyInterface& bodyInterface = m_PhysicsSystem.GetBodyInterface();
|
||||||
|
|
||||||
|
for (auto& [handleId, record] : m_Bodies)
|
||||||
|
{
|
||||||
|
if (!record.alive || record.desc.type != RigidbodyType::Kinematic || !record.desc.owner)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform& transform = record.desc.owner->GetTransform();
|
||||||
|
|
||||||
|
bodyInterface.SetPositionAndRotation(
|
||||||
|
record.bodyID,
|
||||||
|
ToJoltRVec3(transform.GetWorldPosition()),
|
||||||
|
ToJoltQuat(transform.GetWorldRotation()),
|
||||||
|
EActivation::Activate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SyncDynamicBodiesToTransforms()
|
||||||
|
{
|
||||||
|
BodyInterface& bodyInterface = m_PhysicsSystem.GetBodyInterface();
|
||||||
|
|
||||||
|
for (auto& [handleId, record] : m_Bodies)
|
||||||
|
{
|
||||||
|
if (!record.alive || record.desc.type != RigidbodyType::Dynamic || !record.desc.owner)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
RVec3 position{};
|
||||||
|
Quat rotation{};
|
||||||
|
bodyInterface.GetPositionAndRotation(record.bodyID, position, rotation);
|
||||||
|
|
||||||
|
Transform& transform = record.desc.owner->GetTransform();
|
||||||
|
transform.SetWorldPosition(FromJoltRVec3(position));
|
||||||
|
transform.SetWorldRotation(FromJoltQuat(rotation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBodyTransform(PhysicsBodyHandle body, const PhysicsTransform& transform)
|
||||||
|
{
|
||||||
|
if (BodyRecord* record = FindBody(body))
|
||||||
|
{
|
||||||
|
m_PhysicsSystem.GetBodyInterface().SetPositionAndRotation(
|
||||||
|
record->bodyID,
|
||||||
|
ToJoltRVec3(transform.position),
|
||||||
|
ToJoltQuat(transform.rotation),
|
||||||
|
EActivation::Activate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsTransform GetBodyTransform(PhysicsBodyHandle body) const
|
||||||
|
{
|
||||||
|
const BodyRecord* record = FindBody(body);
|
||||||
|
if (!record)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
RVec3 position{};
|
||||||
|
Quat rotation{};
|
||||||
|
m_PhysicsSystem.GetBodyInterface().GetPositionAndRotation(record->bodyID, position, rotation);
|
||||||
|
|
||||||
|
return PhysicsTransform{
|
||||||
|
.position = FromJoltRVec3(position),
|
||||||
|
.rotation = FromJoltQuat(rotation)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetLinearVelocity(PhysicsBodyHandle body, const glm::vec3& velocity)
|
||||||
|
{
|
||||||
|
if (BodyRecord* record = FindBody(body))
|
||||||
|
{
|
||||||
|
m_PhysicsSystem.GetBodyInterface().SetLinearVelocity(record->bodyID, ToJoltVec3(velocity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 GetLinearVelocity(PhysicsBodyHandle body) const
|
||||||
|
{
|
||||||
|
const BodyRecord* record = FindBody(body);
|
||||||
|
if (!record)
|
||||||
|
{
|
||||||
|
return glm::vec3{0.0f};
|
||||||
|
}
|
||||||
|
|
||||||
|
return FromJoltVec3(m_PhysicsSystem.GetBodyInterface().GetLinearVelocity(record->bodyID));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddForce(PhysicsBodyHandle body, const glm::vec3& force)
|
||||||
|
{
|
||||||
|
if (BodyRecord* record = FindBody(body))
|
||||||
|
{
|
||||||
|
m_PhysicsSystem.GetBodyInterface().AddForce(record->bodyID, ToJoltVec3(force));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddImpulse(PhysicsBodyHandle body, const glm::vec3& impulse)
|
||||||
|
{
|
||||||
|
if (BodyRecord* record = FindBody(body))
|
||||||
|
{
|
||||||
|
m_PhysicsSystem.GetBodyInterface().AddImpulse(record->bodyID, ToJoltVec3(impulse));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Raycast(const glm::vec3& origin,
|
||||||
|
const glm::vec3& direction,
|
||||||
|
float maxDistance,
|
||||||
|
PhysicsRaycastHit& hit) const
|
||||||
|
{
|
||||||
|
if (maxDistance <= 0.0f || glm::length2(direction) <= 0.0000001f)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const glm::vec3 directionNormalized = glm::normalize(direction);
|
||||||
|
|
||||||
|
RRayCast ray{
|
||||||
|
ToJoltRVec3(origin),
|
||||||
|
ToJoltVec3(directionNormalized * maxDistance)
|
||||||
|
};
|
||||||
|
|
||||||
|
RayCastResult result{};
|
||||||
|
if (!m_PhysicsSystem.GetNarrowPhaseQuery().CastRay(ray, result))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hit.body = FindHandle(result.mBodyID);
|
||||||
|
hit.distance = result.mFraction * maxDistance;
|
||||||
|
hit.point = origin + directionNormalized * hit.distance;
|
||||||
|
hit.object = nullptr;
|
||||||
|
hit.normal = glm::vec3{0.0f, 1.0f, 0.0f};
|
||||||
|
|
||||||
|
BodyLockRead lock(m_PhysicsSystem.GetBodyLockInterface(), result.mBodyID);
|
||||||
|
if (lock.Succeeded())
|
||||||
|
{
|
||||||
|
const Body& body = lock.GetBody();
|
||||||
|
|
||||||
|
hit.object = reinterpret_cast<GameObject*>(body.GetUserData());
|
||||||
|
hit.normal = FromJoltVec3(
|
||||||
|
body.GetWorldSpaceSurfaceNormal(
|
||||||
|
result.mSubShapeID2,
|
||||||
|
ray.GetPointOnRay(result.mFraction)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct BodyRecord
|
||||||
|
{
|
||||||
|
bool alive{false};
|
||||||
|
BodyID bodyID{};
|
||||||
|
PhysicsBodyDesc desc{};
|
||||||
|
};
|
||||||
|
|
||||||
|
BodyRecord* FindBody(PhysicsBodyHandle body)
|
||||||
|
{
|
||||||
|
auto it = m_Bodies.find(body.id);
|
||||||
|
if (it == m_Bodies.end())
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BodyRecord* FindBody(PhysicsBodyHandle body) const
|
||||||
|
{
|
||||||
|
auto it = m_Bodies.find(body.id);
|
||||||
|
if (it == m_Bodies.end())
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsBodyHandle FindHandle(BodyID bodyID) const
|
||||||
|
{
|
||||||
|
for (const auto& [handleId, record] : m_Bodies)
|
||||||
|
{
|
||||||
|
if (record.alive && record.bodyID == bodyID)
|
||||||
|
{
|
||||||
|
return PhysicsBodyHandle{handleId};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings m_Settings{};
|
||||||
|
|
||||||
|
BPLayerInterfaceImpl m_BPLayerInterface{};
|
||||||
|
ObjectVsBroadPhaseLayerFilterImpl m_ObjectVsBroadPhaseLayerFilter{};
|
||||||
|
ObjectLayerPairFilterImpl m_ObjectLayerPairFilter{};
|
||||||
|
|
||||||
|
PhysicsSystem m_PhysicsSystem{};
|
||||||
|
|
||||||
|
std::unique_ptr<TempAllocatorImpl> m_TempAllocator;
|
||||||
|
std::unique_ptr<JobSystemThreadPool> m_JobSystem;
|
||||||
|
|
||||||
|
std::unordered_map<std::uint32_t, BodyRecord> m_Bodies;
|
||||||
|
std::uint32_t m_NextHandle{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
JoltPhysicsWorld::JoltPhysicsWorld(const Settings& settings)
|
||||||
|
: m_Impl(std::make_unique<Impl>(settings))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
JoltPhysicsWorld::~JoltPhysicsWorld() = default;
|
||||||
|
|
||||||
|
void JoltPhysicsWorld::Step(float fixedDt)
|
||||||
|
{
|
||||||
|
m_Impl->Step(fixedDt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoltPhysicsWorld::SyncKinematicBodiesToPhysics()
|
||||||
|
{
|
||||||
|
m_Impl->SyncKinematicBodiesToPhysics();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoltPhysicsWorld::SyncDynamicBodiesToTransforms()
|
||||||
|
{
|
||||||
|
m_Impl->SyncDynamicBodiesToTransforms();
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsBodyHandle JoltPhysicsWorld::CreateBody(const PhysicsBodyDesc& desc)
|
||||||
|
{
|
||||||
|
return m_Impl->CreateBody(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoltPhysicsWorld::DestroyBody(PhysicsBodyHandle body)
|
||||||
|
{
|
||||||
|
m_Impl->DestroyBody(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoltPhysicsWorld::SetBodyTransform(PhysicsBodyHandle body, const PhysicsTransform& transform)
|
||||||
|
{
|
||||||
|
m_Impl->SetBodyTransform(body, transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsTransform JoltPhysicsWorld::GetBodyTransform(PhysicsBodyHandle body) const
|
||||||
|
{
|
||||||
|
return m_Impl->GetBodyTransform(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoltPhysicsWorld::SetLinearVelocity(PhysicsBodyHandle body, const glm::vec3& velocity)
|
||||||
|
{
|
||||||
|
m_Impl->SetLinearVelocity(body, velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 JoltPhysicsWorld::GetLinearVelocity(PhysicsBodyHandle body) const
|
||||||
|
{
|
||||||
|
return m_Impl->GetLinearVelocity(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoltPhysicsWorld::AddForce(PhysicsBodyHandle body, const glm::vec3& force)
|
||||||
|
{
|
||||||
|
m_Impl->AddForce(body, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoltPhysicsWorld::AddImpulse(PhysicsBodyHandle body, const glm::vec3& impulse)
|
||||||
|
{
|
||||||
|
m_Impl->AddImpulse(body, impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JoltPhysicsWorld::Raycast(const glm::vec3& origin,
|
||||||
|
const glm::vec3& direction,
|
||||||
|
float maxDistance,
|
||||||
|
PhysicsRaycastHit& hit) const
|
||||||
|
{
|
||||||
|
return m_Impl->Raycast(origin, direction, maxDistance, hit);
|
||||||
|
}
|
||||||
@@ -24,12 +24,7 @@ void PhysicsSceneBridge::UnregisterGameObject(GameObject& object) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsSceneBridge::FixedUpdate(float fixedDt) {
|
void PhysicsSceneBridge::FixedUpdate(float fixedDt) {
|
||||||
if (auto* simple = dynamic_cast<SimplePhysicsWorld*>(m_World.get())) {
|
m_World->SyncKinematicBodiesToPhysics();
|
||||||
simple->SyncKinematicBodiesToPhysics();
|
|
||||||
simple->Step(fixedDt);
|
|
||||||
simple->SyncDynamicBodiesToTransforms();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_World->Step(fixedDt);
|
m_World->Step(fixedDt);
|
||||||
|
m_World->SyncDynamicBodiesToTransforms();
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+7
@@ -122,3 +122,10 @@ set(USE_F16C ON CACHE BOOL "" FORCE)
|
|||||||
set(USE_FMADD ON CACHE BOOL "" FORCE)
|
set(USE_FMADD ON CACHE BOOL "" FORCE)
|
||||||
|
|
||||||
add_subdirectory(jolt/Build)
|
add_subdirectory(jolt/Build)
|
||||||
|
|
||||||
|
# 3rdparty/tracy is the Tracy repo
|
||||||
|
option(TRACY_ENABLE "" ON)
|
||||||
|
option(TRACY_ON_DEMAND "" ON)
|
||||||
|
|
||||||
|
add_subdirectory(tracy)
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
Submodule destrum/third_party/assimp updated: e13e0b5b7d...818f73f99a
Vendored
+1
-1
Submodule destrum/third_party/fmt updated: 7ad8004d57...588b3a0f8f
Vendored
+1
-1
Submodule destrum/third_party/freetype updated: 23b6cd27ff...25a08f24cf
Vendored
+1
-1
Submodule destrum/third_party/glfw updated: dbadda2683...567b1ec244
Vendored
+1
-1
Submodule destrum/third_party/glm updated: 8f6213d379...6f14f4792a
Vendored
+1
-1
Submodule destrum/third_party/jolt updated: 33a8797521...f26e382dd0
Vendored
+1
-1
Submodule destrum/third_party/json updated: 30b28175e4...25c58ac6bd
Vendored
+1
-1
Submodule destrum/third_party/sdl updated: 3eba0b6f8a...b8b3f5ef20
Vendored
+1
-1
Submodule destrum/third_party/spdlog updated: 32dd298dc2...f544fce006
Vendored
+1
-1
Submodule destrum/third_party/tinyexr updated: 90a147c711...97b265d8ce
Vendored
+1
-1
Submodule destrum/third_party/tinygltf updated: 81bd50c106...a434ee0206
+1
Submodule destrum/third_party/tracy added at 05cceee0df
Vendored
+1
-1
Submodule destrum/third_party/vk-bootstrap updated: 7028d6f652...95392756ec
Vendored
+1
-1
Submodule destrum/third_party/vma updated: e722e57c89...3aa921224c
Vendored
+1
-1
Submodule destrum/third_party/volk updated: bf84ce9573...477a354c50
+166
-133
@@ -23,13 +23,16 @@
|
|||||||
#include "destrum/Util/ModelDocUtils.h"
|
#include "destrum/Util/ModelDocUtils.h"
|
||||||
|
|
||||||
|
|
||||||
LightKeeper::LightKeeper() : App(), renderer(meshCache, materialCache) {
|
LightKeeper::LightKeeper() : App(), renderer(meshCache, materialCache)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
LightKeeper::~LightKeeper() {
|
LightKeeper::~LightKeeper()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightKeeper::customInit() {
|
void LightKeeper::customInit()
|
||||||
|
{
|
||||||
materialCache.init(gfxDevice);
|
materialCache.init(gfxDevice);
|
||||||
renderer.init(gfxDevice, m_params.renderSize);
|
renderer.init(gfxDevice, m_params.renderSize);
|
||||||
|
|
||||||
@@ -48,7 +51,7 @@ void LightKeeper::customInit() {
|
|||||||
);
|
);
|
||||||
ModelDocUtils::LogModelDocSummary(kittyModel, "kitty.glb");
|
ModelDocUtils::LogModelDocSummary(kittyModel, "kitty.glb");
|
||||||
|
|
||||||
const auto &kittyPrimitive = ModelDocUtils::GetFirstPrimitiveOrThrow(kittyModel, "game://kitty.glb");
|
const auto& kittyPrimitive = ModelDocUtils::GetFirstPrimitiveOrThrow(kittyModel, "game://kitty.glb");
|
||||||
testMesh = kittyPrimitive.mesh;
|
testMesh = kittyPrimitive.mesh;
|
||||||
testMesh.name = "Test Mesh";
|
testMesh.name = "Test Mesh";
|
||||||
|
|
||||||
@@ -75,40 +78,7 @@ void LightKeeper::customInit() {
|
|||||||
|
|
||||||
camera.SetRotation(glm::radians(glm::vec2(90.f, 0.f)));
|
camera.SetRotation(glm::radians(glm::vec2(90.f, 0.f)));
|
||||||
|
|
||||||
auto &scene = SceneManager::GetInstance().CreateScene("Main");
|
auto& scene = SceneManager::GetInstance().CreateScene("Main");
|
||||||
|
|
||||||
// auto testCube = std::make_shared<GameObject>("TestCube");
|
|
||||||
// auto meshComp = testCube->AddComponent<MeshRendererComponent>();
|
|
||||||
// meshComp->SetMeshID(testMeshID);
|
|
||||||
// meshComp->SetMaterialID(testMaterialID);
|
|
||||||
const int count = 100;
|
|
||||||
const float radius = 5.0f;
|
|
||||||
|
|
||||||
const float orbitRadius = 5.0f;
|
|
||||||
|
|
||||||
for (int i = 0; i < count; ++i) {
|
|
||||||
// auto childCube = std::make_shared<GameObject>(fmt::format("ChildCube{}", i));
|
|
||||||
//
|
|
||||||
// auto childMeshComp = childCube->AddComponent<MeshRendererComponent>();
|
|
||||||
// childMeshComp->SetMeshID(testMeshID);
|
|
||||||
// childMeshComp->SetMaterialID(testMaterialID);
|
|
||||||
//
|
|
||||||
// childCube->GetTransform().SetWorldScale(glm::vec3(0.1f));
|
|
||||||
//
|
|
||||||
// // Add orbit + self spin
|
|
||||||
// auto orbit = childCube->AddComponent<OrbitAndSpin>(orbitRadius, glm::vec3(0.0f));
|
|
||||||
// orbit->Randomize(1337u + (uint32_t)i); // stable random per index
|
|
||||||
//
|
|
||||||
// scene.Add(childCube);
|
|
||||||
}
|
|
||||||
// testCube->AddComponent<Spinner>(glm::vec3(0, 1, 0), glm::radians(10.0f)); // spin around Y, rad/sec
|
|
||||||
//rotate 180 around X axis
|
|
||||||
// testCube->GetTransform().SetLocalRotation(glm::quat(glm::vec3(glm::radians(180.0f), 0.0f, 0.0f)));
|
|
||||||
//
|
|
||||||
auto globeRoot = std::make_shared<GameObject>("GlobeRoot");
|
|
||||||
globeRoot->GetTransform().SetWorldPosition(glm::vec3(0.0f));
|
|
||||||
globeRoot->AddComponent<Spinner>(glm::vec3(0, 1, 0), 1.0f); // spin around Y, rad/sec
|
|
||||||
scene.Add(globeRoot);
|
|
||||||
|
|
||||||
// scene.Add(testCube);
|
// scene.Add(testCube);
|
||||||
|
|
||||||
@@ -137,7 +107,7 @@ void LightKeeper::customInit() {
|
|||||||
);
|
);
|
||||||
ModelDocUtils::LogModelDocSummary(planeModel, "plane.glb");
|
ModelDocUtils::LogModelDocSummary(planeModel, "plane.glb");
|
||||||
|
|
||||||
const auto &planePrimitive = ModelDocUtils::GetFirstPrimitiveOrThrow(planeModel, "game://plane.glb");
|
const auto& planePrimitive = ModelDocUtils::GetFirstPrimitiveOrThrow(planeModel, "game://plane.glb");
|
||||||
const auto planeMeshID = meshCache.addMesh(gfxDevice, planePrimitive.mesh);
|
const auto planeMeshID = meshCache.addMesh(gfxDevice, planePrimitive.mesh);
|
||||||
|
|
||||||
const auto planeTexturePath = ModelDocUtils::PickTexturePath(
|
const auto planeTexturePath = ModelDocUtils::PickTexturePath(
|
||||||
@@ -160,6 +130,11 @@ void LightKeeper::customInit() {
|
|||||||
planeMeshComp->SetMaterialID(planeMaterialID);
|
planeMeshComp->SetMaterialID(planeMaterialID);
|
||||||
planeObj->GetTransform().SetWorldPosition(glm::vec3(0.f, -1.0f, 0.f));
|
planeObj->GetTransform().SetWorldPosition(glm::vec3(0.f, -1.0f, 0.f));
|
||||||
planeObj->GetTransform().SetWorldScale(glm::vec3(10.f, 1.f, 10.f));
|
planeObj->GetTransform().SetWorldScale(glm::vec3(10.f, 1.f, 10.f));
|
||||||
|
planeObj->AddComponent<BoxCollider>(glm::vec3{10.0f, 0.5f, 10.0f});
|
||||||
|
|
||||||
|
auto* floorRb = planeObj->AddComponent<Rigidbody>();
|
||||||
|
floorRb->SetType(RigidbodyType::Static);
|
||||||
|
scene.GetPhysics().RegisterGameObject(*planeObj);
|
||||||
scene.Add(planeObj);
|
scene.Add(planeObj);
|
||||||
|
|
||||||
const auto CharObj = std::make_shared<GameObject>("Character");
|
const auto CharObj = std::make_shared<GameObject>("Character");
|
||||||
@@ -284,112 +259,167 @@ void LightKeeper::customInit() {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto CharObj = std::make_shared<GameObject>("Character");
|
||||||
|
|
||||||
|
ModelDoc::LoadOptions characterOptions{};
|
||||||
|
characterOptions.meshImportMode = ModelDoc::MeshImportMode::MergedPerNode;
|
||||||
|
characterOptions.loadMaterials = true;
|
||||||
|
characterOptions.loadSkeleton = true;
|
||||||
|
characterOptions.loadAnimations = false;
|
||||||
|
|
||||||
|
auto charModel = ModelDoc::LoadModel(
|
||||||
|
AssetFS::GetInstance()
|
||||||
|
.GetFullPath("engine://characterMedium.fbx")
|
||||||
|
.generic_string(),
|
||||||
|
characterOptions
|
||||||
|
);
|
||||||
|
|
||||||
|
const auto &charPrimitive =
|
||||||
|
ModelDocUtils::GetFirstSkinnedPrimitiveOrFirstOrThrow(
|
||||||
|
charModel,
|
||||||
|
"engine://characterMedium.fbx"
|
||||||
|
);
|
||||||
|
|
||||||
|
const auto charMeshID = meshCache.addMesh(gfxDevice, charPrimitive.mesh);
|
||||||
|
|
||||||
|
const auto charTextureID = gfxDevice.loadImageFromFile(
|
||||||
|
AssetFS::GetInstance().GetFullPath("engine://textures/criminalMaleA.png")
|
||||||
|
);
|
||||||
|
|
||||||
|
const auto charMaterialID = materialCache.addMaterial(gfxDevice, {
|
||||||
|
.baseColor = ModelDocUtils::GetImportedBaseColor(
|
||||||
|
charModel, charPrimitive),
|
||||||
|
.diffuseTexture = charTextureID,
|
||||||
|
.name = ModelDocUtils::GetImportedMaterialName(
|
||||||
|
charModel,
|
||||||
|
charPrimitive,
|
||||||
|
"CharacterMaterial"
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto charMeshComp = CharObj->AddComponent<MeshRendererComponent>();
|
||||||
|
charMeshComp->SetMeshID(charMeshID);
|
||||||
|
charMeshComp->SetMaterialID(charMaterialID);
|
||||||
|
|
||||||
|
const auto animator = CharObj->AddComponent<Animator>();
|
||||||
|
animator->setSkeleton(charModel.skeleton);
|
||||||
|
|
||||||
|
auto runClips = ModelDoc::LoadAnimationClips(
|
||||||
|
AssetFS::GetInstance()
|
||||||
|
.GetFullPath("engine://run.fbx")
|
||||||
|
.generic_string(),
|
||||||
|
charModel.skeleton
|
||||||
|
);
|
||||||
|
|
||||||
|
for (auto &clip: runClips) {
|
||||||
|
spdlog::info("Loaded animation: '{}' ({:.2f}s)", clip.name, clip.duration);
|
||||||
|
animator->addClip(std::make_shared<SkeletalAnimation>(std::move(clip)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!runClips.empty()) {
|
||||||
|
animator->play("Root|Run");
|
||||||
|
}
|
||||||
|
|
||||||
|
CharObj->GetTransform().SetWorldPosition(glm::vec3(0.f));
|
||||||
|
CharObj->GetTransform().SetWorldPosition(glm::vec3(5, 0, 0));
|
||||||
|
scene.Add(CharObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cubeModel = ModelDoc::LoadModel(
|
||||||
|
AssetFS::GetInstance()
|
||||||
|
.GetFullPath("engine://cube.fbx")
|
||||||
|
.generic_string(),
|
||||||
|
staticModelOptions
|
||||||
|
);
|
||||||
|
ModelDocUtils::LogModelDocSummary(cubeModel, "cube.fbx");
|
||||||
|
|
||||||
|
const auto& cubePrimitive = ModelDocUtils::GetFirstPrimitiveOrThrow(cubeModel, "game://cube.fbx");
|
||||||
|
|
||||||
|
|
||||||
|
const auto eliasTextuerPath = ModelDocUtils::PickTexturePath(
|
||||||
|
cubeModel,
|
||||||
|
cubePrimitive,
|
||||||
|
AssetFS::GetInstance().GetFullPath("game://grass.png")
|
||||||
|
);
|
||||||
|
|
||||||
|
const auto eliasTextueID = gfxDevice.loadImageFromFile(eliasTextuerPath);
|
||||||
|
const auto eliasMaterialID = materialCache.addMaterial(gfxDevice, {
|
||||||
|
.baseColor = ModelDocUtils::GetImportedBaseColor(
|
||||||
|
planeModel, planePrimitive),
|
||||||
|
.textureFilteringMode =
|
||||||
|
TextureFilteringMode::Anisotropic,
|
||||||
|
.diffuseTexture = eliasTextueID,
|
||||||
|
.name = ModelDocUtils::GetImportedMaterialName(
|
||||||
|
planeModel, planePrimitive, "GroundPlaneMaterial"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto cubeMeshID = meshCache.addMesh(gfxDevice, cubePrimitive.mesh);
|
||||||
|
//
|
||||||
|
// for (int i{0}; i < 100; i++)
|
||||||
// {
|
// {
|
||||||
// const auto CharObj = std::make_shared<GameObject>("Character");
|
// auto cube = std::make_shared<GameObject>("Cube");
|
||||||
//
|
//
|
||||||
// ModelDoc::LoadOptions characterOptions{};
|
// cube->AddComponent<BoxCollider>(glm::vec3{0.5f});
|
||||||
// characterOptions.meshImportMode = ModelDoc::MeshImportMode::MergedPerNode;
|
// cube->AddComponent<Rigidbody>();
|
||||||
// characterOptions.loadMaterials = true;
|
|
||||||
// characterOptions.loadSkeleton = true;
|
|
||||||
// characterOptions.loadAnimations = false;
|
|
||||||
//
|
//
|
||||||
// auto charModel = ModelDoc::LoadModel(
|
// auto meshComp = cube->AddComponent<MeshRendererComponent>();
|
||||||
// AssetFS::GetInstance()
|
// meshComp->SetMeshID(cubeMeshID);
|
||||||
// .GetFullPath("engine://characterMedium.fbx")
|
// meshComp->SetMaterialID(eliasMaterialID);
|
||||||
// .generic_string(),
|
|
||||||
// characterOptions
|
|
||||||
// );
|
|
||||||
//
|
//
|
||||||
// const auto &charPrimitive =
|
// cube->GetTransform().SetWorldPosition(glm::vec3(0.0f, i, 0.0f));
|
||||||
// ModelDocUtils::GetFirstSkinnedPrimitiveOrFirstOrThrow(
|
// cube->GetTransform().SetWorldScale(glm::vec3(0.005f));
|
||||||
// charModel,
|
|
||||||
// "engine://characterMedium.fbx"
|
|
||||||
// );
|
|
||||||
//
|
//
|
||||||
// const auto charMeshID = meshCache.addMesh(gfxDevice, charPrimitive.mesh);
|
// scene.Add(cube);
|
||||||
//
|
// scene.GetPhysics().RegisterGameObject(*cube);
|
||||||
// const auto charTextureID = gfxDevice.loadImageFromFile(
|
|
||||||
// AssetFS::GetInstance().GetFullPath("engine://textures/criminalMaleA.png")
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// const auto charMaterialID = materialCache.addMaterial(gfxDevice, {
|
|
||||||
// .baseColor = ModelDocUtils::GetImportedBaseColor(
|
|
||||||
// charModel, charPrimitive),
|
|
||||||
// .diffuseTexture = charTextureID,
|
|
||||||
// .name = ModelDocUtils::GetImportedMaterialName(
|
|
||||||
// charModel,
|
|
||||||
// charPrimitive,
|
|
||||||
// "CharacterMaterial"
|
|
||||||
// ),
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// const auto charMeshComp = CharObj->AddComponent<MeshRendererComponent>();
|
|
||||||
// charMeshComp->SetMeshID(charMeshID);
|
|
||||||
// charMeshComp->SetMaterialID(charMaterialID);
|
|
||||||
//
|
|
||||||
// const auto animator = CharObj->AddComponent<Animator>();
|
|
||||||
// animator->setSkeleton(charModel.skeleton);
|
|
||||||
//
|
|
||||||
// auto runClips = ModelDoc::LoadAnimationClips(
|
|
||||||
// AssetFS::GetInstance()
|
|
||||||
// .GetFullPath("engine://run.fbx")
|
|
||||||
// .generic_string(),
|
|
||||||
// charModel.skeleton
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// for (auto &clip: runClips) {
|
|
||||||
// spdlog::info("Loaded animation: '{}' ({:.2f}s)", clip.name, clip.duration);
|
|
||||||
// animator->addClip(std::make_shared<SkeletalAnimation>(std::move(clip)));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (!runClips.empty()) {
|
|
||||||
// animator->play("Root|Run");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// CharObj->GetTransform().SetWorldPosition(glm::vec3(0.f));
|
|
||||||
// CharObj->GetTransform().SetWorldPosition(glm::vec3(5, 0, 0));
|
|
||||||
// scene.Add(CharObj);
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
{
|
// const int cubeCount = 10;
|
||||||
auto cubeModel = ModelDoc::LoadModel(
|
// const float spacing = 1.0f;
|
||||||
AssetFS::GetInstance()
|
//
|
||||||
.GetFullPath("engine://cube.fbx")
|
// for (int x = 0; x < cubeCount; x++)
|
||||||
.generic_string(),
|
// {
|
||||||
staticModelOptions
|
// for (int y = 0; y < cubeCount; y++)
|
||||||
);
|
// {
|
||||||
ModelDocUtils::LogModelDocSummary(cubeModel, "cube.fbx");
|
// for (int z = 0; z < cubeCount; z++)
|
||||||
|
// {
|
||||||
const auto &cubePrimitive = ModelDocUtils::GetFirstPrimitiveOrThrow(cubeModel, "game://cube.fbx");
|
// auto cube = std::make_shared<GameObject>("Cube");
|
||||||
const auto cubeMeshID = meshCache.addMesh(gfxDevice, cubePrimitive.mesh);
|
//
|
||||||
|
// cube->AddComponent<BoxCollider>(glm::vec3{0.5f});
|
||||||
auto cube = std::make_shared<GameObject>("Cube");
|
// cube->AddComponent<Rigidbody>();
|
||||||
|
//
|
||||||
cube->AddComponent<BoxCollider>(glm::vec3{0.5f});
|
// auto meshComp = cube->AddComponent<MeshRendererComponent>();
|
||||||
cube->AddComponent<Rigidbody>();
|
// meshComp->SetMeshID(cubeMeshID);
|
||||||
|
// meshComp->SetMaterialID(eliasMaterialID);
|
||||||
auto meshComp = cube->AddComponent<MeshRendererComponent>();
|
//
|
||||||
meshComp->SetMeshID(cubeMeshID);
|
// cube->GetTransform().SetWorldPosition(glm::vec3(
|
||||||
meshComp->SetMaterialID(charMaterialID);
|
// (x - cubeCount / 2.0f) * spacing,
|
||||||
|
// y * spacing + 5,
|
||||||
cube->GetTransform().SetWorldPosition(glm::vec3(0.0f, 2.0f, 0.0f));
|
// (z - cubeCount / 2.0f) * spacing
|
||||||
cube->GetTransform().SetWorldScale(glm::vec3(0.005f));
|
// ));
|
||||||
|
//
|
||||||
scene.Add(cube);
|
// cube->GetTransform().SetWorldScale(glm::vec3(0.005f));
|
||||||
scene.GetPhysics().RegisterGameObject(*cube);
|
//
|
||||||
}
|
// scene.Add(cube);
|
||||||
|
// scene.GetPhysics().RegisterGameObject(*cube);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightKeeper::customUpdate(float dt) {
|
void LightKeeper::customUpdate(float dt)
|
||||||
|
{
|
||||||
camera.Update(dt);
|
camera.Update(dt);
|
||||||
SceneManager::GetInstance().Update();
|
SceneManager::GetInstance().Update();
|
||||||
|
|
||||||
if (InputManager::GetInstance().WasKeyPressed(SDL_SCANCODE_1)) {
|
if (InputManager::GetInstance().WasKeyPressed(SDL_SCANCODE_1))
|
||||||
|
{
|
||||||
renderer.setRenderWireframe(!renderer.getRenderWireframe());
|
renderer.setRenderWireframe(!renderer.getRenderWireframe());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightKeeper::customDraw() {
|
void LightKeeper::customDraw()
|
||||||
|
{
|
||||||
renderer.beginDrawing(gfxDevice);
|
renderer.beginDrawing(gfxDevice);
|
||||||
|
|
||||||
const RenderContext ctx{
|
const RenderContext ctx{
|
||||||
@@ -408,7 +438,7 @@ void LightKeeper::customDraw() {
|
|||||||
renderer.endDrawing();
|
renderer.endDrawing();
|
||||||
|
|
||||||
const auto cmd = gfxDevice.beginFrame();
|
const auto cmd = gfxDevice.beginFrame();
|
||||||
const auto &drawImage = renderer.getDrawImage(gfxDevice);
|
const auto& drawImage = renderer.getDrawImage(gfxDevice);
|
||||||
|
|
||||||
renderer.draw(
|
renderer.draw(
|
||||||
cmd, gfxDevice, camera, GameRenderer::SceneData{
|
cmd, gfxDevice, camera, GameRenderer::SceneData{
|
||||||
@@ -423,14 +453,16 @@ void LightKeeper::customDraw() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightKeeper::customCleanup() {
|
void LightKeeper::customCleanup()
|
||||||
|
{
|
||||||
auto device = gfxDevice.getDevice().device;
|
auto device = gfxDevice.getDevice().device;
|
||||||
|
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
|
|
||||||
SceneManager::GetInstance().Destroy();
|
SceneManager::GetInstance().Destroy();
|
||||||
|
|
||||||
if (skyboxCubemap) {
|
if (skyboxCubemap)
|
||||||
|
{
|
||||||
skyboxCubemap.reset();
|
skyboxCubemap.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,7 +477,8 @@ void LightKeeper::customFixedUpdate(float dt)
|
|||||||
SceneManager::GetInstance().FixedUpdate(dt);
|
SceneManager::GetInstance().FixedUpdate(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightKeeper::onWindowResize(int newWidth, int newHeight) {
|
void LightKeeper::onWindowResize(int newWidth, int newHeight)
|
||||||
|
{
|
||||||
renderer.resize(gfxDevice, glm::ivec2{newWidth, newHeight});
|
renderer.resize(gfxDevice, glm::ivec2{newWidth, newHeight});
|
||||||
const float aspectRatio = static_cast<float>(newWidth) / static_cast<float>(newHeight);
|
const float aspectRatio = static_cast<float>(newWidth) / static_cast<float>(newHeight);
|
||||||
camera.setAspectRatio(aspectRatio);
|
camera.setAspectRatio(aspectRatio);
|
||||||
|
|||||||
Reference in New Issue
Block a user