fix: alot of stuff changed. Mostly bugfixxes / architechture changes
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#ifndef APP_H
|
||||
#define APP_H
|
||||
#include <filesystem>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
|
||||
#include "glm/vec2.hpp"
|
||||
@@ -25,6 +26,7 @@ public:
|
||||
};
|
||||
|
||||
App();
|
||||
virtual ~App();
|
||||
|
||||
void init(const AppParams& params);
|
||||
void run();
|
||||
@@ -33,10 +35,10 @@ public:
|
||||
virtual void customInit() = 0;
|
||||
virtual void customUpdate(float dt) = 0;
|
||||
virtual void customDraw() = 0;
|
||||
virtual void customCleanup() = 0;
|
||||
virtual void customCleanup() {}
|
||||
virtual void customFixedUpdate(float dt) = 0;
|
||||
|
||||
virtual void onWindowResize(int newWidth, int newHeight) {};
|
||||
virtual void onWindowResize(int, int) {};
|
||||
|
||||
protected:
|
||||
SDL_Window* window{nullptr};
|
||||
@@ -51,6 +53,9 @@ protected:
|
||||
Camera camera{glm::vec3(0.f, 0.f, -5.f), glm::vec3(0, 1, 0)};
|
||||
|
||||
bool isRunning{false};
|
||||
bool cleanedUp{false};
|
||||
bool cleaningUp{false};
|
||||
bool customInitStarted{false};
|
||||
bool gamePaused{false};
|
||||
|
||||
bool frameLimit{false};
|
||||
|
||||
@@ -18,11 +18,14 @@ class Animator final: public Component {
|
||||
public:
|
||||
explicit Animator(GameObject& parent);
|
||||
|
||||
void Update() override;
|
||||
using Component::Update;
|
||||
void Update(float dt) override;
|
||||
std::string GetTypeName() const override
|
||||
{
|
||||
return "Animator";
|
||||
}
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void ImGuiInspector() override;
|
||||
|
||||
void addClip(std::shared_ptr<SkeletalAnimation> clip);
|
||||
@@ -66,4 +69,4 @@ private:
|
||||
glm::vec3 sampleScale (const SkeletalAnimation::Track& track, float t);
|
||||
};
|
||||
|
||||
#endif // ANIMATOR_H
|
||||
#endif // ANIMATOR_H
|
||||
|
||||
@@ -10,13 +10,18 @@ public:
|
||||
explicit MeshRendererComponent(GameObject &parent);
|
||||
|
||||
void Start() override;
|
||||
void Update() override;
|
||||
void Destroy() override;
|
||||
void Update(float dt) override;
|
||||
void Render(const RenderContext& ctx) override;
|
||||
|
||||
void SetMeshID(MeshID id) { meshID = id; }
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void ResolveReferences(const ObjectMap& objects) override;
|
||||
|
||||
void SetMeshID(MeshID id);
|
||||
MeshID GetMeshID() const { return meshID; }
|
||||
|
||||
void SetMaterialID(MaterialID id) { materialID = id; }
|
||||
void SetMaterialID(MaterialID id);
|
||||
MaterialID GetMaterialID() const { return materialID; }
|
||||
std::string GetTypeName() const override
|
||||
{
|
||||
@@ -26,6 +31,8 @@ public:
|
||||
private:
|
||||
MeshID meshID{NULL_MESH_ID};
|
||||
MaterialID materialID{NULL_MATERIAL_ID};
|
||||
std::string meshKey;
|
||||
std::string materialKey;
|
||||
|
||||
std::unique_ptr<SkinnedMesh> m_skinnedMesh;
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ class OrbitAndSpin final : public Component {
|
||||
public:
|
||||
OrbitAndSpin(
|
||||
GameObject& parent,
|
||||
float radius,
|
||||
float radius = 5.0f,
|
||||
glm::vec3 center = glm::vec3(0.0f)
|
||||
)
|
||||
: Component(parent, "OrbitAndSpin")
|
||||
@@ -20,9 +20,15 @@ public:
|
||||
// Call after constructing if you want deterministic randomness per object
|
||||
void Randomize(uint32_t seed);
|
||||
|
||||
void Update() override;
|
||||
using Component::Update;
|
||||
void Update(float dt) override;
|
||||
void Start() override;
|
||||
|
||||
std::string GetTypeName() const override { return "OrbitAndSpin"; }
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
|
||||
// optional setters
|
||||
void SetRadius(float r) { m_Radius = r; }
|
||||
void SetCenter(glm::vec3 c) { m_Center = c; }
|
||||
@@ -53,6 +59,7 @@ private:
|
||||
float m_SpinSpeed = 2.0f; // rad/sec
|
||||
|
||||
MaterialID m_MaterialID{0};
|
||||
bool m_BaseScaleLoaded{false};
|
||||
};
|
||||
|
||||
#endif //ORBITANDSPIN_H
|
||||
|
||||
@@ -7,9 +7,12 @@ class BoxCollider final : public Collider {
|
||||
public:
|
||||
explicit BoxCollider(GameObject& owner, const glm::vec3& halfExtents = glm::vec3{0.5f})
|
||||
: Collider(owner)
|
||||
, m_HalfExtents(halfExtents) {}
|
||||
, m_HalfExtents(glm::max(halfExtents, glm::vec3{0.0001f})) {}
|
||||
|
||||
void Update() override {}
|
||||
void Update(float dt) override {}
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
|
||||
std::string GetTypeName() const override
|
||||
{
|
||||
@@ -26,11 +29,12 @@ public:
|
||||
}
|
||||
|
||||
void SetHalfExtents(const glm::vec3& halfExtents) {
|
||||
m_HalfExtents = halfExtents;
|
||||
m_HalfExtents = glm::max(halfExtents, glm::vec3{0.0001f});
|
||||
NotifyPhysicsChanged();
|
||||
}
|
||||
|
||||
private:
|
||||
glm::vec3 m_HalfExtents{0.5f};
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -2,14 +2,37 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <destrum/Components/Collider.h>
|
||||
#include <destrum/Components/Physics/Collider.h>
|
||||
|
||||
class CapsuleCollider final : public Collider {
|
||||
public:
|
||||
explicit CapsuleCollider(GameObject& owner, float radius = 0.5f, float height = 2.0f)
|
||||
: Collider(owner)
|
||||
, m_Radius(radius)
|
||||
, m_Height(height) {}
|
||||
, m_Radius(std::max(radius, 0.0f))
|
||||
, m_Height(std::max(height, std::max(radius, 0.0f) * 2.0f)) {}
|
||||
|
||||
void Update(float dt) override {}
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "CapsuleCollider";
|
||||
}
|
||||
|
||||
nlohmann::json Serialize() const override {
|
||||
auto data = SerializeCollider();
|
||||
data["radius"] = m_Radius;
|
||||
data["height"] = m_Height;
|
||||
return data;
|
||||
}
|
||||
|
||||
void Deserialize(const nlohmann::json& data) override {
|
||||
DeserializeCollider(data);
|
||||
if (data.contains("radius")) {
|
||||
SetRadius(data.at("radius").get<float>());
|
||||
}
|
||||
if (data.contains("height")) {
|
||||
SetHeight(data.at("height").get<float>());
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] PhysicsShapeDesc BuildPhysicsShape() const override {
|
||||
return PhysicsShapeDesc::Capsule(m_Radius, m_Height, m_CenterOffset, m_IsTrigger);
|
||||
@@ -20,7 +43,9 @@ public:
|
||||
}
|
||||
|
||||
void SetRadius(float radius) {
|
||||
m_Radius = std::max(radius, 0.0f);
|
||||
m_Radius = std::max(radius, 0.0001f);
|
||||
m_Height = std::max(m_Height, m_Radius * 2.0f);
|
||||
NotifyPhysicsChanged();
|
||||
}
|
||||
|
||||
[[nodiscard]] float GetHeight() const {
|
||||
@@ -29,6 +54,7 @@ public:
|
||||
|
||||
void SetHeight(float height) {
|
||||
m_Height = std::max(height, m_Radius * 2.0f);
|
||||
NotifyPhysicsChanged();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -15,12 +15,33 @@ public:
|
||||
[[nodiscard]] virtual PhysicsShapeDesc BuildPhysicsShape() const = 0;
|
||||
|
||||
[[nodiscard]] bool IsTrigger() const { return m_IsTrigger; }
|
||||
void SetTrigger(bool trigger) { m_IsTrigger = trigger; }
|
||||
void SetTrigger(bool trigger) { m_IsTrigger = trigger; NotifyPhysicsChanged(); }
|
||||
|
||||
[[nodiscard]] const glm::vec3& GetCenterOffset() const { return m_CenterOffset; }
|
||||
void SetCenterOffset(const glm::vec3& offset) { m_CenterOffset = offset; }
|
||||
void SetCenterOffset(const glm::vec3& offset) { m_CenterOffset = offset; NotifyPhysicsChanged(); }
|
||||
|
||||
protected:
|
||||
[[nodiscard]] nlohmann::json SerializeCollider() const {
|
||||
return {
|
||||
{"centerOffset", {m_CenterOffset.x, m_CenterOffset.y, m_CenterOffset.z}},
|
||||
{"isTrigger", m_IsTrigger}
|
||||
};
|
||||
}
|
||||
|
||||
void DeserializeCollider(const nlohmann::json& data) {
|
||||
if (data.contains("centerOffset")) {
|
||||
const auto& offset = data.at("centerOffset");
|
||||
m_CenterOffset = {
|
||||
offset.at(0).get<float>(),
|
||||
offset.at(1).get<float>(),
|
||||
offset.at(2).get<float>()
|
||||
};
|
||||
}
|
||||
if (data.contains("isTrigger")) {
|
||||
m_IsTrigger = data.at("isTrigger").get<bool>();
|
||||
}
|
||||
}
|
||||
|
||||
bool m_IsTrigger{false};
|
||||
glm::vec3 m_CenterOffset{0.0f};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <destrum/ObjectModel/Component.h>
|
||||
@@ -12,13 +13,18 @@ public:
|
||||
explicit Rigidbody(GameObject& owner)
|
||||
: Component(owner) {}
|
||||
|
||||
~Rigidbody() override = default;
|
||||
~Rigidbody() override;
|
||||
|
||||
void Update() override {}
|
||||
void Update(float dt) override {}
|
||||
void Start() override;
|
||||
void Destroy() override;
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
|
||||
std::string GetTypeName() const override
|
||||
{
|
||||
return "RigidBody";
|
||||
return "Rigidbody";
|
||||
}
|
||||
|
||||
void AttachPhysicsBody(PhysicsWorld* world, PhysicsBodyHandle body);
|
||||
@@ -34,22 +40,22 @@ public:
|
||||
[[nodiscard]] glm::vec3 GetLinearVelocity() const;
|
||||
|
||||
[[nodiscard]] RigidbodyType GetType() const { return m_Type; }
|
||||
void SetType(RigidbodyType type) { m_Type = type; }
|
||||
void SetType(RigidbodyType type) { m_Type = type; NotifyPhysicsChanged(); }
|
||||
|
||||
[[nodiscard]] float GetMass() const { return m_Mass; }
|
||||
void SetMass(float mass) { m_Mass = mass > 0.0f ? mass : 0.0001f; }
|
||||
void SetMass(float mass) { m_Mass = mass > 0.0f ? mass : 0.0001f; NotifyPhysicsChanged(); }
|
||||
|
||||
[[nodiscard]] float GetFriction() const { return m_Friction; }
|
||||
void SetFriction(float friction) { m_Friction = friction; }
|
||||
void SetFriction(float friction) { m_Friction = std::max(friction, 0.0f); NotifyPhysicsChanged(); }
|
||||
|
||||
[[nodiscard]] float GetRestitution() const { return m_Restitution; }
|
||||
void SetRestitution(float restitution) { m_Restitution = restitution; }
|
||||
void SetRestitution(float restitution) { m_Restitution = std::clamp(restitution, 0.0f, 1.0f); NotifyPhysicsChanged(); }
|
||||
|
||||
[[nodiscard]] bool UsesGravity() const { return m_UseGravity; }
|
||||
void SetUseGravity(bool useGravity) { m_UseGravity = useGravity; }
|
||||
void SetUseGravity(bool useGravity) { m_UseGravity = useGravity; NotifyPhysicsChanged(); }
|
||||
|
||||
[[nodiscard]] bool AllowsSleep() const { return m_AllowSleep; }
|
||||
void SetAllowSleep(bool allowSleep) { m_AllowSleep = allowSleep; }
|
||||
void SetAllowSleep(bool allowSleep) { m_AllowSleep = allowSleep; NotifyPhysicsChanged(); }
|
||||
|
||||
[[nodiscard]] PhysicsWorld* GetPhysicsWorld() const { return m_World; }
|
||||
|
||||
|
||||
@@ -8,9 +8,12 @@ class SphereCollider final : public Collider {
|
||||
public:
|
||||
explicit SphereCollider(GameObject& owner, float radius = 0.5f)
|
||||
: Collider(owner)
|
||||
, m_Radius(radius) {}
|
||||
, m_Radius(std::max(radius, 0.0001f)) {}
|
||||
|
||||
void Update() override {}
|
||||
void Update(float dt) override {}
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
std::string GetTypeName() const override
|
||||
{
|
||||
return "SphereCollider";
|
||||
@@ -25,7 +28,8 @@ public:
|
||||
}
|
||||
|
||||
void SetRadius(float radius) {
|
||||
m_Radius = std::max(radius, 0.0f);
|
||||
m_Radius = std::max(radius, 0.0001f);
|
||||
NotifyPhysicsChanged();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -8,14 +8,20 @@
|
||||
|
||||
class Rotator final : public Component {
|
||||
public:
|
||||
explicit Rotator(GameObject& parent, float distance, float speed);
|
||||
explicit Rotator(GameObject& parent, float distance = 0.0f, float speed = 0.0f);
|
||||
|
||||
Rotator(const Rotator& other) = delete;
|
||||
Rotator(Rotator&& other) noexcept = delete;
|
||||
Rotator& operator=(const Rotator& other) = delete;
|
||||
Rotator& operator=(Rotator&& other) noexcept = delete;
|
||||
|
||||
void Update() override;
|
||||
using Component::Update;
|
||||
void Update(float dt) override;
|
||||
|
||||
std::string GetTypeName() const override { return "Rotator"; }
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
|
||||
void SetDistance(float distance);
|
||||
void SetSpeed(float speed) { m_Speed = speed; }
|
||||
|
||||
@@ -6,14 +6,26 @@
|
||||
|
||||
class Spinner final : public Component {
|
||||
public:
|
||||
explicit Spinner(GameObject& parent, glm::vec3 axis, float speedRadPerSec)
|
||||
explicit Spinner(GameObject& parent,
|
||||
glm::vec3 axis = glm::vec3{0.0f, 1.0f, 0.0f},
|
||||
float speedRadPerSec = 1.0f)
|
||||
: Component(parent, "Spinner")
|
||||
, m_Axis(glm::normalize(axis))
|
||||
, m_Axis(glm::dot(axis, axis) > 0.000001f ? glm::normalize(axis) : glm::vec3{0.0f, 1.0f, 0.0f})
|
||||
, m_Speed(speedRadPerSec) {}
|
||||
|
||||
void Update() override;
|
||||
using Component::Update;
|
||||
void Update(float dt) override;
|
||||
|
||||
void SetAxis(const glm::vec3& axis) { m_Axis = glm::normalize(axis); }
|
||||
std::string GetTypeName() const override { return "Spinner"; }
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
|
||||
void SetAxis(const glm::vec3& axis) {
|
||||
m_Axis = glm::dot(axis, axis) > 0.000001f
|
||||
? glm::normalize(axis)
|
||||
: glm::vec3{0.0f, 1.0f, 0.0f};
|
||||
}
|
||||
void SetSpeed(float speedRadPerSec) { m_Speed = speedRadPerSec; }
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#ifndef EVENT_H
|
||||
#define EVENT_H
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
class EventListener;
|
||||
|
||||
@@ -41,7 +43,11 @@ private:
|
||||
|
||||
template <typename... EventArgs>
|
||||
class Event final: public BaseEvent {
|
||||
using EventFunction = std::pair<void*, std::function<void(EventArgs...)>>;
|
||||
struct EventFunction {
|
||||
void* listener{nullptr};
|
||||
std::uint64_t id{0};
|
||||
std::function<void(EventArgs...)> callback;
|
||||
};
|
||||
|
||||
public:
|
||||
Event() = default;
|
||||
@@ -65,28 +71,45 @@ public:
|
||||
listener->AddEvent(this);
|
||||
m_EventListeners.insert(listener);
|
||||
|
||||
m_FunctionBinds.emplace_back(
|
||||
listener, [object, memberFunction] (EventArgs... args) { (object->*memberFunction)(args...); });
|
||||
const auto id = m_NextBindingId++;
|
||||
m_ActiveBindings.insert(id);
|
||||
m_FunctionBinds.push_back({
|
||||
listener,
|
||||
id,
|
||||
[object, memberFunction] (EventArgs... args) { (object->*memberFunction)(args...); }
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
void AddListener(Function function) {
|
||||
m_FunctionBinds.emplace_back(nullptr, [function] (EventArgs... args) { function(args...); });
|
||||
const auto id = m_NextBindingId++;
|
||||
m_ActiveBindings.insert(id);
|
||||
m_FunctionBinds.push_back({
|
||||
nullptr,
|
||||
id,
|
||||
[function] (EventArgs... args) { function(args...); }
|
||||
});
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void Invoke(Args&&... args) {
|
||||
m_Invoking = true;
|
||||
for (auto&& listenerFunction: m_FunctionBinds)
|
||||
listenerFunction.second(args...);
|
||||
m_Invoking = false;
|
||||
// Callbacks are allowed to unregister themselves or register another
|
||||
// callback. Iterate over a snapshot so those mutations cannot
|
||||
// invalidate this invocation.
|
||||
const auto listeners = m_FunctionBinds;
|
||||
for (const auto& listenerFunction: listeners) {
|
||||
if (m_ActiveBindings.contains(listenerFunction.id)) {
|
||||
listenerFunction.callback(args...);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveListener(EventListener* listener) override {
|
||||
m_EventListeners.erase(listener);
|
||||
|
||||
for (auto it = m_FunctionBinds.begin(); it != m_FunctionBinds.end();) {
|
||||
if (it->first == static_cast<void*>(listener)) {
|
||||
if (it->listener == static_cast<void*>(listener)) {
|
||||
m_ActiveBindings.erase(it->id);
|
||||
it = m_FunctionBinds.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
@@ -95,9 +118,10 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_Invoking{false};
|
||||
std::vector<EventFunction> m_FunctionBinds{};
|
||||
std::unordered_set<EventListener*> m_EventListeners{};
|
||||
std::unordered_set<std::uint64_t> m_ActiveBindings{};
|
||||
std::uint64_t m_NextBindingId{1};
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
#define ASSETFS_H
|
||||
|
||||
#include <filesystem>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <destrum/Singleton.h>
|
||||
@@ -20,6 +23,7 @@ struct FSMount {
|
||||
class AssetFS final: public Singleton<AssetFS> {
|
||||
public:
|
||||
void Init(std::filesystem::path exeDir);
|
||||
void Reset();
|
||||
void Mount(std::string scheme, std::filesystem::path root);
|
||||
|
||||
std::vector<uint8_t> ReadBytes(std::string_view vpath);
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#ifndef MANIFEST_H
|
||||
#define MANIFEST_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
struct ManifestAsset {
|
||||
|
||||
@@ -9,7 +9,7 @@ struct GPUImage;
|
||||
|
||||
class BindlessSetManager {
|
||||
public:
|
||||
void init(VkDevice device, float maxAnisotropy);
|
||||
void init(VkDevice device, VkPhysicalDevice physicalDevice, float maxAnisotropy);
|
||||
void cleanup(VkDevice device);
|
||||
|
||||
VkDescriptorSetLayout getDescSetLayout() const { return descSetLayout; }
|
||||
@@ -18,16 +18,21 @@ public:
|
||||
void addImage(VkDevice device, std::uint32_t id, const VkImageView imageView);
|
||||
void addSampler(VkDevice device, std::uint32_t id, VkSampler sampler);
|
||||
|
||||
[[nodiscard]] std::uint32_t getMaxImageCount() const { return maxBindlessResources; }
|
||||
|
||||
private:
|
||||
void initDefaultSamplers(VkDevice device, float maxAnisotropy);
|
||||
|
||||
VkDescriptorPool descPool;
|
||||
VkDescriptorSetLayout descSetLayout;
|
||||
VkDescriptorSet descSet;
|
||||
VkDescriptorPool descPool{VK_NULL_HANDLE};
|
||||
VkDescriptorSetLayout descSetLayout{VK_NULL_HANDLE};
|
||||
VkDescriptorSet descSet{VK_NULL_HANDLE};
|
||||
|
||||
VkSampler nearestSampler;
|
||||
VkSampler linearSampler;
|
||||
VkSampler shadowMapSampler;
|
||||
std::uint32_t maxBindlessResources{0};
|
||||
|
||||
VkSampler nearestSampler{VK_NULL_HANDLE};
|
||||
VkSampler linearSampler{VK_NULL_HANDLE};
|
||||
VkSampler anisotropicSampler{VK_NULL_HANDLE};
|
||||
VkSampler shadowMapSampler{VK_NULL_HANDLE};
|
||||
};
|
||||
|
||||
#endif //BINDLESSSETMANAGER_H
|
||||
|
||||
@@ -30,6 +30,9 @@ public:
|
||||
[[nodiscard]] const GPUImage& getImage(ImageID id) const;
|
||||
|
||||
[[nodiscard]] ImageID getFreeImageId() const;
|
||||
[[nodiscard]] std::uint32_t getMaxImageCount() const {
|
||||
return bindlessSetManager.getMaxImageCount();
|
||||
}
|
||||
|
||||
void destroyImages();
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#define MATERIALCACHE_H
|
||||
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include <destrum/Graphics/ids.h>
|
||||
#include <destrum/Graphics/Material.h>
|
||||
@@ -28,6 +30,8 @@ public:
|
||||
MaterialID addMaterial(Material material);
|
||||
MaterialID addSimpleTextureMaterial(ImageID textureID);
|
||||
[[nodiscard]] const Material& getMaterial(MaterialID id) const;
|
||||
[[nodiscard]] const std::string& getMaterialKey(MaterialID id) const;
|
||||
[[nodiscard]] std::optional<MaterialID> findMaterialByKey(std::string_view key) const;
|
||||
|
||||
[[nodiscard]] MaterialID getFreeMaterialId() const;
|
||||
[[nodiscard]] MaterialID getPlaceholderMaterialId() const;
|
||||
@@ -41,11 +45,13 @@ public:
|
||||
|
||||
private:
|
||||
std::vector<Material> materials;
|
||||
std::vector<std::string> materialKeys;
|
||||
|
||||
static constexpr auto MAX_MATERIALS = 1000;
|
||||
GPUBuffer materialDataBuffer;
|
||||
|
||||
MaterialDefaultTextures defaultTextures;
|
||||
GfxDevice* device{nullptr};
|
||||
|
||||
// material which is used for meshes without materials
|
||||
MaterialID placeholderMaterialId{NULL_MATERIAL_ID};
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
|
||||
#include <destrum/Graphics/Resources/Mesh.h>
|
||||
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "../ids.h"
|
||||
|
||||
class GfxDevice;
|
||||
@@ -14,12 +17,15 @@ public:
|
||||
MeshID addMesh(GfxDevice& gfxDevice, const CPUMesh& cpuMesh);
|
||||
const GPUMesh& getMesh(MeshID id) const;
|
||||
const CPUMesh& getCPUMesh(MeshID id) const;
|
||||
[[nodiscard]] const std::string& getMeshKey(MeshID id) const;
|
||||
[[nodiscard]] std::optional<MeshID> findMeshByKey(std::string_view key) const;
|
||||
|
||||
private:
|
||||
void uploadMesh(GfxDevice& gfxDevice, const CPUMesh& cpuMesh, GPUMesh& gpuMesh) const;
|
||||
|
||||
std::vector<GPUMesh> meshes;
|
||||
std::vector<CPUMesh> cpuMeshes;
|
||||
std::vector<std::string> meshKeys;
|
||||
};
|
||||
|
||||
#endif //MESHCACHE_H
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
#define GPUIMAGE_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <vk_mem_alloc.h>
|
||||
#include <glm/glm.hpp>
|
||||
@@ -10,20 +13,70 @@
|
||||
#include <destrum/Graphics/ids.h>
|
||||
|
||||
struct GPUImage {
|
||||
VkImage image;
|
||||
VkImageView imageView;
|
||||
VmaAllocation allocation;
|
||||
VkFormat format;
|
||||
VkImageUsageFlags usage;
|
||||
VkExtent3D extent;
|
||||
GPUImage() = default;
|
||||
~GPUImage() = default;
|
||||
GPUImage(const GPUImage&) = delete;
|
||||
GPUImage& operator=(const GPUImage&) = delete;
|
||||
|
||||
GPUImage(GPUImage&& other) noexcept {
|
||||
*this = std::move(other);
|
||||
}
|
||||
|
||||
GPUImage& operator=(GPUImage&& other) noexcept {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
image = other.image;
|
||||
imageView = other.imageView;
|
||||
allocation = other.allocation;
|
||||
format = other.format;
|
||||
usage = other.usage;
|
||||
extent = other.extent;
|
||||
layout = other.layout;
|
||||
mipLevels = other.mipLevels;
|
||||
numLayers = other.numLayers;
|
||||
layerLayouts = std::move(other.layerLayouts);
|
||||
isCubemap = other.isCubemap;
|
||||
debugName = std::move(other.debugName);
|
||||
id = other.id;
|
||||
|
||||
other.image = VK_NULL_HANDLE;
|
||||
other.imageView = VK_NULL_HANDLE;
|
||||
other.allocation = VK_NULL_HANDLE;
|
||||
other.id = NULL_BINDLESS_ID;
|
||||
return *this;
|
||||
}
|
||||
|
||||
VkImage image{VK_NULL_HANDLE};
|
||||
VkImageView imageView{VK_NULL_HANDLE};
|
||||
VmaAllocation allocation{VK_NULL_HANDLE};
|
||||
VkFormat format{VK_FORMAT_UNDEFINED};
|
||||
VkImageUsageFlags usage{0};
|
||||
VkExtent3D extent{};
|
||||
mutable VkImageLayout layout{VK_IMAGE_LAYOUT_UNDEFINED};
|
||||
std::uint32_t mipLevels{1};
|
||||
std::uint32_t numLayers{1};
|
||||
mutable std::vector<VkImageLayout> layerLayouts;
|
||||
bool isCubemap{false};
|
||||
std::string debugName{};
|
||||
|
||||
[[nodiscard]] glm::ivec2 getSize2D() const { return glm::ivec2{extent.width, extent.height}; }
|
||||
[[nodiscard]] VkExtent2D getExtent2D() const { return VkExtent2D{extent.width, extent.height}; }
|
||||
|
||||
[[nodiscard]] VkImageLayout getLayout(std::uint32_t layer = 0) const
|
||||
{
|
||||
return layerLayouts.empty() ? layout : layerLayouts.at(layer);
|
||||
}
|
||||
|
||||
void setLayout(VkImageLayout newLayout, std::uint32_t layer = 0) const
|
||||
{
|
||||
layout = newLayout;
|
||||
if (!layerLayouts.empty()) {
|
||||
layerLayouts.at(layer) = newLayout;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] BindlessID getBindlessId() const
|
||||
{
|
||||
assert(id != NULL_BINDLESS_ID && "Image wasn't added to bindless set");
|
||||
@@ -31,10 +84,10 @@ struct GPUImage {
|
||||
}
|
||||
|
||||
// should be called by ImageCache only
|
||||
void setBindlessId(const std::uint32_t id)
|
||||
void setBindlessId(const std::uint32_t bindlessId)
|
||||
{
|
||||
assert(id != NULL_BINDLESS_ID);
|
||||
this->id = id;
|
||||
assert(bindlessId != NULL_BINDLESS_ID);
|
||||
id = bindlessId;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isInitialized() const { return id != NULL_BINDLESS_ID; }
|
||||
|
||||
@@ -10,11 +10,8 @@
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include <VkBootstrap.h>
|
||||
#include <vk_mem_alloc.h>
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <volk.h>
|
||||
#include <vk_mem_alloc.h>
|
||||
|
||||
#include <glm/vec2.hpp>
|
||||
#include <glm/vec4.hpp>
|
||||
@@ -27,6 +24,10 @@
|
||||
|
||||
#include "ImmediateExecuter.h"
|
||||
#include "Util.h"
|
||||
#include "Managers/FrameManager.h"
|
||||
#include "Managers/VulkanInstanceManager.h"
|
||||
#include "Managers/MemoryManager.h"
|
||||
#include "Managers/ImageManager.h"
|
||||
|
||||
class ImguiPass;
|
||||
|
||||
@@ -35,7 +36,6 @@ namespace tracy
|
||||
{
|
||||
class VkCtx;
|
||||
}
|
||||
|
||||
using DestrumTracyVkCtx = tracy::VkCtx*;
|
||||
#else
|
||||
using DestrumTracyVkCtx = void*;
|
||||
@@ -46,22 +46,16 @@ using ImmediateExecuteFunction = std::function<void(VkCommandBuffer)>;
|
||||
class GfxDevice
|
||||
{
|
||||
public:
|
||||
struct FrameData
|
||||
{
|
||||
VkCommandPool commandPool{VK_NULL_HANDLE};
|
||||
VkCommandBuffer commandBuffer{VK_NULL_HANDLE};
|
||||
};
|
||||
|
||||
struct EndFrameProps
|
||||
{
|
||||
VkClearColorValue clearColor{{0.f, 0.f, 0.f, 1.f}};
|
||||
glm::ivec4 drawImageBlitRect{}; // where to blit draw image to
|
||||
glm::ivec4 drawImageBlitRect{};
|
||||
ImguiPass* imguiPass{nullptr};
|
||||
};
|
||||
|
||||
public:
|
||||
GfxDevice();
|
||||
~GfxDevice() = default;
|
||||
~GfxDevice();
|
||||
|
||||
GfxDevice(const GfxDevice&) = delete;
|
||||
GfxDevice& operator=(const GfxDevice&) = delete;
|
||||
@@ -85,23 +79,25 @@ public:
|
||||
return swapchain.isDirty();
|
||||
}
|
||||
|
||||
VulkanImmediateExecutor& GetImmediateExecuter();
|
||||
VulkanImmediateExecutor& getImmediateExecuter();
|
||||
[[deprecated("Use getImmediateExecuter()")]]
|
||||
VulkanImmediateExecutor& GetImmediateExecuter() { return getImmediateExecuter(); }
|
||||
|
||||
void immediateSubmit(ImmediateExecuteFunction&& f) const;
|
||||
|
||||
[[nodiscard]] std::uint32_t getCurrentFrameIndex() const
|
||||
{
|
||||
return frameNumber % FRAMES_IN_FLIGHT;
|
||||
return frameManager.getCurrentFrameIndex();
|
||||
}
|
||||
|
||||
[[nodiscard]] FrameData& getCurrentFrame()
|
||||
[[nodiscard]] FrameManager::FrameData& getCurrentFrame()
|
||||
{
|
||||
return frames[getCurrentFrameIndex()];
|
||||
return frameManager.getCurrentFrame();
|
||||
}
|
||||
|
||||
[[nodiscard]] const FrameData& getCurrentFrame() const
|
||||
[[nodiscard]] const FrameManager::FrameData& getCurrentFrame() const
|
||||
{
|
||||
return frames[getCurrentFrameIndex()];
|
||||
return frameManager.getCurrentFrame();
|
||||
}
|
||||
|
||||
[[nodiscard]] VkExtent2D getSwapchainExtent() const
|
||||
@@ -112,68 +108,94 @@ public:
|
||||
[[nodiscard]] GPUBuffer createBuffer(
|
||||
std::size_t allocSize,
|
||||
VkBufferUsageFlags usage,
|
||||
VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO) const;
|
||||
VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE) const
|
||||
{
|
||||
return memoryManager.createBuffer(allocSize, usage, memoryUsage);
|
||||
}
|
||||
|
||||
void destroyBuffer(const GPUBuffer& buffer) const;
|
||||
void destroyBuffer(GPUBuffer& buffer) const
|
||||
{
|
||||
memoryManager.destroyBuffer(buffer);
|
||||
}
|
||||
|
||||
[[nodiscard]] VkDeviceAddress getBufferAddress(const GPUBuffer& buffer) const;
|
||||
[[nodiscard]] VkDeviceAddress getBufferAddress(const GPUBuffer& buffer) const
|
||||
{
|
||||
return memoryManager.getBufferAddress(buffer);
|
||||
}
|
||||
|
||||
[[nodiscard]] GPUImage createImageRaw(
|
||||
const vkutil::CreateImageInfo& createInfo,
|
||||
std::optional<VmaAllocationCreateInfo> customAllocationCreateInfo = std::nullopt) const;
|
||||
std::optional<VmaAllocationCreateInfo> customAllocationCreateInfo = std::nullopt) const
|
||||
{
|
||||
return imageManager.createImage(createInfo, customAllocationCreateInfo);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<GPUImage> loadImageFromFileRaw(
|
||||
const std::filesystem::path& path,
|
||||
VkImageUsageFlags usage,
|
||||
bool mipMap,
|
||||
TextureIntent intent) const;
|
||||
TextureIntent intent) const
|
||||
{
|
||||
return imageManager.loadImageFromFile(path, usage, mipMap, intent);
|
||||
}
|
||||
|
||||
void uploadImageDataSized(
|
||||
const GPUImage& image,
|
||||
const void* pixelData,
|
||||
std::size_t byteSize,
|
||||
std::uint32_t layer) const;
|
||||
|
||||
void destroyImage(const GPUImage& image) const;
|
||||
|
||||
[[nodiscard]] vkb::Device getDevice() const
|
||||
std::uint32_t layer) const
|
||||
{
|
||||
return device;
|
||||
imageManager.uploadImageData(image, pixelData, byteSize, layer);
|
||||
}
|
||||
|
||||
[[nodiscard]] vkb::Device getVkbDevice() const
|
||||
void destroyImage(GPUImage& image) const
|
||||
{
|
||||
return device;
|
||||
}
|
||||
|
||||
[[nodiscard]] VkInstance getVkInstance() const
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
[[nodiscard]] VkPhysicalDevice getVkPhysicalDevice() const
|
||||
{
|
||||
return physicalDevice;
|
||||
imageManager.destroyImage(image);
|
||||
}
|
||||
|
||||
[[nodiscard]] VkDevice getVkDevice() const
|
||||
{
|
||||
return device;
|
||||
return instanceManager.getDevice();
|
||||
}
|
||||
|
||||
[[nodiscard]] VkDevice getDevice() const
|
||||
{
|
||||
return getVkDevice();
|
||||
}
|
||||
|
||||
[[nodiscard]] vkb::Device getVkbDevice() const
|
||||
{
|
||||
return instanceManager.getVkbDevice();
|
||||
}
|
||||
|
||||
[[nodiscard]] VkInstance getVkInstance() const
|
||||
{
|
||||
return instanceManager.getInstance();
|
||||
}
|
||||
|
||||
[[nodiscard]] VkPhysicalDevice getVkPhysicalDevice() const
|
||||
{
|
||||
return instanceManager.getPhysicalDevice();
|
||||
}
|
||||
|
||||
[[nodiscard]] VmaAllocator getAllocator() const
|
||||
{
|
||||
return allocator;
|
||||
return memoryManager.getAllocator();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint32_t getGraphicsQueueFamily() const
|
||||
{
|
||||
return graphicsQueueFamily;
|
||||
return instanceManager.getGraphicsQueueFamily();
|
||||
}
|
||||
|
||||
[[nodiscard]] VkQueue getGraphicsQueue() const
|
||||
{
|
||||
return graphicsQueue;
|
||||
return instanceManager.getGraphicsQueue();
|
||||
}
|
||||
|
||||
[[nodiscard]] VkQueue getPresentQueue() const
|
||||
{
|
||||
return instanceManager.getPresentQueue();
|
||||
}
|
||||
|
||||
[[nodiscard]] VkFormat getSwapchainFormat() const
|
||||
@@ -193,30 +215,29 @@ public:
|
||||
|
||||
[[nodiscard]] DestrumTracyVkCtx getTracyVkCtx() const
|
||||
{
|
||||
return tracyVkCtx;
|
||||
return instanceManager.getTracyVkCtx();
|
||||
}
|
||||
|
||||
VulkanInstanceManager& getInstanceManager() { return instanceManager; }
|
||||
MemoryManager& getMemoryManager() { return memoryManager; }
|
||||
|
||||
private:
|
||||
vkb::Instance instance;
|
||||
vkb::PhysicalDevice physicalDevice;
|
||||
vkb::Device device;
|
||||
VmaAllocator allocator{VK_NULL_HANDLE};
|
||||
|
||||
DestrumTracyVkCtx tracyVkCtx{nullptr};
|
||||
|
||||
std::uint32_t graphicsQueueFamily{0};
|
||||
VkQueue graphicsQueue{VK_NULL_HANDLE};
|
||||
|
||||
VkSurfaceKHR surface{VK_NULL_HANDLE};
|
||||
VkFormat swapchainFormat{VK_FORMAT_UNDEFINED};
|
||||
Swapchain swapchain;
|
||||
|
||||
std::array<FrameData, FRAMES_IN_FLIGHT> frames{};
|
||||
std::uint32_t frameNumber{0};
|
||||
VulkanInstanceManager instanceManager;
|
||||
MemoryManager memoryManager;
|
||||
FrameManager frameManager;
|
||||
ImageManager imageManager;
|
||||
|
||||
VulkanImmediateExecutor executor;
|
||||
|
||||
Swapchain swapchain;
|
||||
VkFormat swapchainFormat{VK_FORMAT_UNDEFINED};
|
||||
|
||||
std::uint32_t activeFrameIndex{0};
|
||||
std::uint32_t activeSwapchainImageIndex{0};
|
||||
bool frameActive{false};
|
||||
|
||||
bool m_vSync{false};
|
||||
bool initialized{false};
|
||||
};
|
||||
|
||||
#endif // GFXDEVICE_H
|
||||
#endif
|
||||
|
||||
@@ -13,15 +13,17 @@ public:
|
||||
|
||||
void immediateSubmit(std::function<void(VkCommandBuffer cmd)>&& function) const;
|
||||
|
||||
[[nodiscard]] VkCommandBuffer getCommandBuffer() const { return immCommandBuffer; }
|
||||
|
||||
private:
|
||||
bool initialized{false};
|
||||
|
||||
VkDevice device;
|
||||
VkQueue graphicsQueue;
|
||||
VkDevice device{VK_NULL_HANDLE};
|
||||
VkQueue graphicsQueue{VK_NULL_HANDLE};
|
||||
|
||||
VkCommandBuffer immCommandBuffer;
|
||||
VkCommandPool immCommandPool;
|
||||
VkFence immFence;
|
||||
VkCommandBuffer immCommandBuffer{VK_NULL_HANDLE};
|
||||
VkCommandPool immCommandPool{VK_NULL_HANDLE};
|
||||
VkFence immFence{VK_NULL_HANDLE};
|
||||
};
|
||||
|
||||
#endif //IMMEDIATEEXECUTER_H
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
#ifndef FRAMEMANAGER_H
|
||||
#define FRAMEMANAGER_H
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
class FrameManager {
|
||||
public:
|
||||
struct FrameData {
|
||||
VkCommandPool commandPool{VK_NULL_HANDLE};
|
||||
VkCommandBuffer commandBuffer{VK_NULL_HANDLE};
|
||||
};
|
||||
|
||||
FrameManager() = default;
|
||||
~FrameManager();
|
||||
|
||||
FrameManager(const FrameManager&) = delete;
|
||||
FrameManager& operator=(const FrameManager&) = delete;
|
||||
FrameManager(FrameManager&&) = delete;
|
||||
FrameManager& operator=(FrameManager&&) = delete;
|
||||
|
||||
void init(VkDevice device, std::uint32_t queueFamily);
|
||||
void cleanup(VkDevice device);
|
||||
|
||||
[[nodiscard]] VkCommandBuffer beginFrame();
|
||||
void endFrame(VkCommandBuffer cmd);
|
||||
|
||||
void waitIdle() const;
|
||||
|
||||
[[nodiscard]] std::uint32_t getCurrentFrameIndex() const {
|
||||
return frameNumber % 2;
|
||||
}
|
||||
|
||||
[[nodiscard]] FrameData& getCurrentFrame() {
|
||||
return frames[getCurrentFrameIndex()];
|
||||
}
|
||||
|
||||
[[nodiscard]] const FrameData& getCurrentFrame() const {
|
||||
return frames[getCurrentFrameIndex()];
|
||||
}
|
||||
|
||||
[[nodiscard]] VkCommandBuffer getCurrentCommandBuffer() {
|
||||
return frames[getCurrentFrameIndex()].commandBuffer;
|
||||
}
|
||||
|
||||
void nextFrame();
|
||||
|
||||
private:
|
||||
static constexpr std::size_t FRAMES_IN_FLIGHT = 2;
|
||||
std::array<FrameData, FRAMES_IN_FLIGHT> frames{};
|
||||
std::uint32_t frameNumber{0};
|
||||
VkDevice device{VK_NULL_HANDLE};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef IMAGEMANAGER_H
|
||||
#define IMAGEMANAGER_H
|
||||
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include <destrum/Graphics/GPUImage.h>
|
||||
#include <destrum/Graphics/TextureIntent.h>
|
||||
|
||||
#include "destrum/Graphics/Util.h"
|
||||
|
||||
class VulkanImmediateExecutor;
|
||||
class MemoryManager;
|
||||
|
||||
class ImageManager {
|
||||
public:
|
||||
ImageManager() = default;
|
||||
~ImageManager();
|
||||
|
||||
ImageManager(const ImageManager&) = delete;
|
||||
ImageManager& operator=(const ImageManager&) = delete;
|
||||
ImageManager(ImageManager&&) = delete;
|
||||
ImageManager& operator=(ImageManager&&) = delete;
|
||||
|
||||
void init(
|
||||
VkDevice device,
|
||||
VkPhysicalDevice physicalDevice,
|
||||
const MemoryManager& memoryManager,
|
||||
VulkanImmediateExecutor& executor);
|
||||
|
||||
[[nodiscard]] GPUImage createImage(
|
||||
const vkutil::CreateImageInfo& createInfo,
|
||||
std::optional<VmaAllocationCreateInfo> customAllocationCreateInfo = std::nullopt) const;
|
||||
|
||||
[[nodiscard]] std::optional<GPUImage> loadImageFromFile(
|
||||
const std::filesystem::path& path,
|
||||
VkImageUsageFlags usage,
|
||||
bool mipMap,
|
||||
TextureIntent intent) const;
|
||||
|
||||
void uploadImageData(
|
||||
const GPUImage& image,
|
||||
const void* pixelData,
|
||||
std::size_t byteSize,
|
||||
std::uint32_t layer = 0) const;
|
||||
|
||||
void destroyImage(GPUImage& image) const;
|
||||
|
||||
private:
|
||||
VkDevice device{VK_NULL_HANDLE};
|
||||
VkPhysicalDevice physicalDevice{VK_NULL_HANDLE};
|
||||
const MemoryManager* memoryManager{nullptr};
|
||||
VulkanImmediateExecutor* executor{nullptr};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
#ifndef MEMORYMANAGER_H
|
||||
#define MEMORYMANAGER_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <vk_mem_alloc.h>
|
||||
|
||||
#include <destrum/Graphics/Resources/Buffer.h>
|
||||
|
||||
class VulkanInstanceManager;
|
||||
|
||||
class MemoryManager {
|
||||
public:
|
||||
MemoryManager() = default;
|
||||
~MemoryManager();
|
||||
|
||||
MemoryManager(const MemoryManager&) = delete;
|
||||
MemoryManager& operator=(const MemoryManager&) = delete;
|
||||
MemoryManager(MemoryManager&&) = delete;
|
||||
MemoryManager& operator=(MemoryManager&&) = delete;
|
||||
|
||||
void init(const VulkanInstanceManager& instanceManager);
|
||||
void cleanup(VkDevice device);
|
||||
|
||||
[[nodiscard]] VmaAllocator getAllocator() const { return allocator; }
|
||||
[[nodiscard]] VkDevice getDevice() const { return device; }
|
||||
|
||||
[[nodiscard]] GPUBuffer createBuffer(
|
||||
std::size_t allocSize,
|
||||
VkBufferUsageFlags usage,
|
||||
VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO) const;
|
||||
|
||||
void destroyBuffer(GPUBuffer& buffer) const;
|
||||
|
||||
void flushAllocation(
|
||||
const GPUBuffer& buffer,
|
||||
VkDeviceSize offset = 0,
|
||||
VkDeviceSize size = VK_WHOLE_SIZE) const;
|
||||
|
||||
[[nodiscard]] VkDeviceAddress getBufferAddress(const GPUBuffer& buffer) const;
|
||||
|
||||
private:
|
||||
VmaAllocator allocator{VK_NULL_HANDLE};
|
||||
VkDevice device{VK_NULL_HANDLE};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,117 @@
|
||||
#ifndef VULKANINSTANCEMANAGER_H
|
||||
#define VULKANINSTANCEMANAGER_H
|
||||
|
||||
#include <SDL_video.h>
|
||||
|
||||
#include <VkBootstrap.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#if defined(TRACY_ENABLE)
|
||||
namespace tracy
|
||||
{
|
||||
class VkCtx;
|
||||
}
|
||||
using DestrumTracyVkCtx = tracy::VkCtx*;
|
||||
#else
|
||||
using DestrumTracyVkCtx = void*;
|
||||
#endif
|
||||
|
||||
class VulkanInstanceManager
|
||||
{
|
||||
public:
|
||||
struct DeviceFeatures
|
||||
{
|
||||
VkPhysicalDeviceFeatures device{
|
||||
.imageCubeArray = VK_TRUE,
|
||||
.geometryShader = VK_TRUE,
|
||||
.depthClamp = VK_TRUE,
|
||||
.fillModeNonSolid = VK_TRUE,
|
||||
.samplerAnisotropy = VK_TRUE,
|
||||
};
|
||||
|
||||
VkPhysicalDeviceVulkan12Features features12{
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
|
||||
.descriptorIndexing = VK_TRUE,
|
||||
.shaderSampledImageArrayNonUniformIndexing = VK_TRUE,
|
||||
.descriptorBindingSampledImageUpdateAfterBind = VK_TRUE,
|
||||
.descriptorBindingPartiallyBound = VK_TRUE,
|
||||
.runtimeDescriptorArray = VK_TRUE,
|
||||
.scalarBlockLayout = VK_TRUE,
|
||||
.bufferDeviceAddress = VK_TRUE,
|
||||
};
|
||||
|
||||
VkPhysicalDeviceVulkan13Features features13{
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES,
|
||||
.synchronization2 = VK_TRUE,
|
||||
.dynamicRendering = VK_TRUE,
|
||||
};
|
||||
|
||||
VkPhysicalDeviceExtendedDynamicState3FeaturesEXT extendedDynamicState3{
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT,
|
||||
.extendedDynamicState3PolygonMode = VK_TRUE,
|
||||
};
|
||||
};
|
||||
|
||||
VulkanInstanceManager() = default;
|
||||
~VulkanInstanceManager();
|
||||
|
||||
VulkanInstanceManager(const VulkanInstanceManager&) = delete;
|
||||
VulkanInstanceManager& operator=(const VulkanInstanceManager&) = delete;
|
||||
VulkanInstanceManager(VulkanInstanceManager&&) = delete;
|
||||
VulkanInstanceManager& operator=(VulkanInstanceManager&&) = delete;
|
||||
|
||||
void init(
|
||||
SDL_Window* window,
|
||||
const std::string& appName,
|
||||
const DeviceFeatures& features = DeviceFeatures{});
|
||||
|
||||
void cleanup();
|
||||
|
||||
void initTracy(VkCommandBuffer tracyInitCmd);
|
||||
|
||||
void waitIdle() const;
|
||||
|
||||
[[nodiscard]] bool isValid() const { return initialized; }
|
||||
|
||||
[[nodiscard]] VkInstance getInstance() const { return instance; }
|
||||
[[nodiscard]] VkPhysicalDevice getPhysicalDevice() const { return physicalDevice; }
|
||||
[[nodiscard]] VkDevice getDevice() const { return device; }
|
||||
|
||||
[[nodiscard]] const vkb::Instance& getVkbInstance() const { return vkbInstance; }
|
||||
[[nodiscard]] const vkb::PhysicalDevice& getVkbPhysicalDevice() const { return vkbPhysicalDevice; }
|
||||
[[nodiscard]] const vkb::Device& getVkbDevice() const { return vkbDevice; }
|
||||
|
||||
[[nodiscard]] VkSurfaceKHR getSurface() const { return surface; }
|
||||
|
||||
[[nodiscard]] uint32_t getGraphicsQueueFamily() const { return graphicsQueueFamily; }
|
||||
[[nodiscard]] VkQueue getGraphicsQueue() const { return graphicsQueue; }
|
||||
[[nodiscard]] uint32_t getPresentQueueFamily() const { return presentQueueFamily; }
|
||||
[[nodiscard]] VkQueue getPresentQueue() const { return presentQueue; }
|
||||
|
||||
[[nodiscard]] DestrumTracyVkCtx getTracyVkCtx() const { return tracyVkCtx; }
|
||||
|
||||
private:
|
||||
vkb::Instance vkbInstance{};
|
||||
vkb::PhysicalDevice vkbPhysicalDevice{};
|
||||
vkb::Device vkbDevice{};
|
||||
|
||||
VkInstance instance{VK_NULL_HANDLE};
|
||||
VkPhysicalDevice physicalDevice{VK_NULL_HANDLE};
|
||||
VkDevice device{VK_NULL_HANDLE};
|
||||
|
||||
VkSurfaceKHR surface{VK_NULL_HANDLE};
|
||||
|
||||
uint32_t graphicsQueueFamily{VK_QUEUE_FAMILY_IGNORED};
|
||||
VkQueue graphicsQueue{VK_NULL_HANDLE};
|
||||
uint32_t presentQueueFamily{VK_QUEUE_FAMILY_IGNORED};
|
||||
VkQueue presentQueue{VK_NULL_HANDLE};
|
||||
|
||||
DestrumTracyVkCtx tracyVkCtx{nullptr};
|
||||
|
||||
bool initialized{false};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -11,11 +11,11 @@
|
||||
|
||||
|
||||
struct MeshDrawCommand {
|
||||
MeshID meshId;
|
||||
glm::mat4 transformMatrix;
|
||||
MeshID meshId{NULL_MESH_ID};
|
||||
glm::mat4 transformMatrix{1.0f};
|
||||
|
||||
// for frustum culling
|
||||
Sphere worldBoundingSphere;
|
||||
Sphere worldBoundingSphere{};
|
||||
|
||||
// If set - mesh will be drawn with overrideMaterialId
|
||||
// instead of whatever material the mesh has
|
||||
@@ -25,7 +25,7 @@ struct MeshDrawCommand {
|
||||
|
||||
// skinned meshes only
|
||||
const SkinnedMesh* skinnedMesh{nullptr};
|
||||
std::uint32_t jointMatricesStartIndex;
|
||||
std::uint32_t jointMatricesStartIndex{0};
|
||||
};
|
||||
|
||||
#endif //MESHDRAWCOMMAND_H
|
||||
|
||||
@@ -34,6 +34,8 @@ public:
|
||||
[[nodiscard]] bool wantsKeyboard() const;
|
||||
|
||||
private:
|
||||
void initVulkanBackend();
|
||||
|
||||
void transitionToColorAttachment(
|
||||
VkCommandBuffer cmd,
|
||||
VkImage image,
|
||||
@@ -50,6 +52,9 @@ private:
|
||||
|
||||
bool initialized = false;
|
||||
bool frameBegun = false;
|
||||
bool contextCreated = false;
|
||||
bool sdlInitialized = false;
|
||||
bool vulkanInitialized = false;
|
||||
};
|
||||
|
||||
#endif // DESTRUM_IMGUI_PASS_H
|
||||
|
||||
@@ -27,12 +27,16 @@ public:
|
||||
const MeshDrawCommand& dc);
|
||||
|
||||
void beginDrawing(std::size_t frameIndex);
|
||||
void flushCurrentFrame(
|
||||
VkCommandBuffer cmd,
|
||||
GfxDevice& gfxDevice,
|
||||
std::size_t frameIndex);
|
||||
std::size_t appendJointMatrices(
|
||||
std::span<const glm::mat4> jointMatrices,
|
||||
std::size_t frameIndex);
|
||||
|
||||
private:
|
||||
VkPipelineLayout m_pipelineLayout;
|
||||
VkPipelineLayout m_pipelineLayout{VK_NULL_HANDLE};
|
||||
std::unique_ptr<ComputePipeline> skinningPipeline;
|
||||
struct PushConstants {
|
||||
VkDeviceAddress jointMatricesBuffer;
|
||||
|
||||
@@ -113,6 +113,7 @@ private:
|
||||
std::unique_ptr<SkyboxPipeline> skyboxPipeline;
|
||||
|
||||
std::unique_ptr<SkinningPipeline> skinningPipeline;
|
||||
bool initialized{false};
|
||||
};
|
||||
|
||||
#endif //RENDERER_H
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
|
||||
struct GPUBuffer {
|
||||
VkBuffer buffer{VK_NULL_HANDLE};
|
||||
VmaAllocation allocation;
|
||||
VmaAllocationInfo info;
|
||||
VmaAllocation allocation{VK_NULL_HANDLE};
|
||||
VmaAllocationInfo info{};
|
||||
|
||||
VkDeviceAddress address{0};
|
||||
bool hostVisible{false};
|
||||
};
|
||||
|
||||
#endif //BUFFER_H
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <destrum/Graphics/Resources/Buffer.h>
|
||||
|
||||
class GfxDevice;
|
||||
class MemoryManager;
|
||||
|
||||
class NBuffer {
|
||||
public:
|
||||
@@ -33,6 +34,7 @@ private:
|
||||
std::size_t gpuBufferSize{0};
|
||||
std::vector<GPUBuffer> stagingBuffers;
|
||||
GPUBuffer gpuBuffer;
|
||||
const MemoryManager* memoryManager{nullptr};
|
||||
bool initialized{false};
|
||||
};
|
||||
|
||||
|
||||
@@ -3,57 +3,93 @@
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include "VkBootstrap.h"
|
||||
#include <VkBootstrap.h>
|
||||
|
||||
class GfxDevice;
|
||||
static constexpr int FRAMES_IN_FLIGHT = 2;
|
||||
|
||||
class Swapchain {
|
||||
public:
|
||||
struct AcquireResult {
|
||||
VkResult result{VK_SUCCESS};
|
||||
VkImage image{VK_NULL_HANDLE};
|
||||
std::uint32_t imageIndex{0};
|
||||
|
||||
[[nodiscard]] bool hasImage() const {
|
||||
return image != VK_NULL_HANDLE &&
|
||||
(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR);
|
||||
}
|
||||
};
|
||||
|
||||
void initSync(VkDevice device);
|
||||
//Ye ye, passing a pointer is bad bla bla @Kobe
|
||||
void createSwapchain(GfxDevice* gfxDevice, VkFormat format, std::uint32_t width, std::uint32_t height, bool vSync);
|
||||
void recreateSwapchain(const GfxDevice& gfxDevice, VkFormat format, std::uint32_t width, std::uint32_t height, bool vSync);
|
||||
void cleanup();
|
||||
void createSwapchain(
|
||||
VkDevice device,
|
||||
vkb::Device vkbDevice,
|
||||
VkSurfaceKHR surface,
|
||||
VkFormat format,
|
||||
std::uint32_t width,
|
||||
std::uint32_t height,
|
||||
bool vSync);
|
||||
|
||||
void recreateSwapchain(
|
||||
VkDevice device,
|
||||
vkb::Device vkbDevice,
|
||||
VkSurfaceKHR surface,
|
||||
VkFormat format,
|
||||
std::uint32_t width,
|
||||
std::uint32_t height,
|
||||
bool vSync);
|
||||
|
||||
void cleanup(VkDevice device);
|
||||
|
||||
[[nodiscard]] VkExtent2D getExtent() const { return extent; }
|
||||
|
||||
[[nodiscard]] const std::vector<VkImage>& getImages() const { return images; }
|
||||
[[nodiscard]] std::uint32_t getImageCount() const { return static_cast<std::uint32_t>(images.size()); }
|
||||
|
||||
void beginFrame(int index) const;
|
||||
void beginFrame(VkDevice device, int index) const;
|
||||
|
||||
void resetFences(int index) const;
|
||||
void resetFences(VkDevice device, int index) const;
|
||||
|
||||
std::pair<VkImage, int> acquireNextImage(int index);
|
||||
AcquireResult acquireNextImage(VkDevice device, std::uint32_t index);
|
||||
|
||||
void submitAndPresent(VkCommandBuffer cmd, VkQueue graphicsQueue, std::uint32_t imageIndex, std::uint32_t frameIndex);
|
||||
void submitAndPresent(
|
||||
VkDevice device,
|
||||
VkCommandBuffer cmd,
|
||||
VkQueue graphicsQueue,
|
||||
VkQueue presentQueue,
|
||||
std::uint32_t imageIndex,
|
||||
std::uint32_t frameIndex);
|
||||
|
||||
[[nodiscard]] bool isDirty() const { return dirty; }
|
||||
|
||||
[[nodiscard]] VkImageView getImageView(int index) const { return imageViews[index]; }
|
||||
|
||||
|
||||
VkImageView getImageView(std::uint32_t imageIndex) const {
|
||||
[[nodiscard]] VkImageView getImageView(std::uint32_t imageIndex) const {
|
||||
return imageViews.at(imageIndex);
|
||||
}
|
||||
|
||||
[[nodiscard]] VkSurfaceKHR getSurface() const { return surface; }
|
||||
[[nodiscard]] vkb::Swapchain getVkbSwapchain() const { return m_swapchain; }
|
||||
[[nodiscard]] VkFormat getFormat() const { return m_swapchain.image_format; }
|
||||
|
||||
private:
|
||||
struct FrameData {
|
||||
VkSemaphore swapchainSemaphore;
|
||||
VkFence renderFence;
|
||||
VkSemaphore swapchainSemaphore{VK_NULL_HANDLE};
|
||||
VkFence renderFence{VK_NULL_HANDLE};
|
||||
};
|
||||
std::vector<VkSemaphore> imageRenderSemaphores;
|
||||
|
||||
std::vector<VkSemaphore> imageRenderSemaphores;
|
||||
std::array<FrameData, FRAMES_IN_FLIGHT> frames;
|
||||
vkb::Swapchain m_swapchain; //Euuuh, m_ cuz like cpluhpluh
|
||||
vkb::Swapchain m_swapchain;
|
||||
std::vector<VkImage> images;
|
||||
std::vector<VkImageView> imageViews;
|
||||
bool dirty{false};
|
||||
GfxDevice* m_gfxDevice{nullptr};
|
||||
VkSurfaceKHR surface{VK_NULL_HANDLE};
|
||||
VkExtent2D extent{};
|
||||
};
|
||||
|
||||
#endif //SWAPCHAIN_H
|
||||
#endif
|
||||
|
||||
@@ -3,16 +3,31 @@
|
||||
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include "glm/vec4.hpp"
|
||||
|
||||
|
||||
#define VK_CHECK(call) \
|
||||
do { \
|
||||
VkResult result_ = call; \
|
||||
assert(result_ == VK_SUCCESS); \
|
||||
inline void checkVkResult(VkResult result, const char* expression, const char* file, int line)
|
||||
{
|
||||
if (result == VK_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw std::runtime_error(
|
||||
std::string{"Vulkan call failed: "} + expression +
|
||||
" returned " + std::to_string(static_cast<int>(result)) +
|
||||
" at " + file + ":" + std::to_string(line));
|
||||
}
|
||||
|
||||
#define VK_CHECK(call) \
|
||||
do { \
|
||||
const VkResult result_ = (call); \
|
||||
checkVkResult(result_, #call, __FILE__, __LINE__); \
|
||||
} while (0)
|
||||
|
||||
namespace vkutil {
|
||||
@@ -34,6 +49,13 @@ namespace vkutil {
|
||||
VkImageLayout currentLayout,
|
||||
VkImageLayout newLayout);
|
||||
|
||||
void transitionImage(
|
||||
VkCommandBuffer cmd,
|
||||
VkImage image,
|
||||
VkImageLayout currentLayout,
|
||||
VkImageLayout newLayout,
|
||||
const VkImageSubresourceRange& subresourceRange);
|
||||
|
||||
void copyImageToImage(
|
||||
VkCommandBuffer cmd,
|
||||
VkImage source,
|
||||
@@ -59,6 +81,12 @@ namespace vkutil {
|
||||
VkDeviceSize offset = 0,
|
||||
VkDeviceSize size = VK_WHOLE_SIZE);
|
||||
|
||||
void bufferHostWriteToTransferReadBarrier(
|
||||
VkCommandBuffer cmd,
|
||||
VkBuffer buffer,
|
||||
VkDeviceSize offset = 0,
|
||||
VkDeviceSize size = VK_WHOLE_SIZE);
|
||||
|
||||
void addDebugLabel(VkDevice device, VkImage image, const char* label);
|
||||
void addDebugLabel(VkDevice device, VkImageView imageView, const char* label);
|
||||
void addDebugLabel(VkDevice device, VkShaderModule shaderModule, const char* label);
|
||||
@@ -76,9 +104,59 @@ namespace vkutil {
|
||||
};
|
||||
|
||||
struct RenderInfo {
|
||||
VkRenderingAttachmentInfo colorAttachment;
|
||||
VkRenderingAttachmentInfo depthAttachment;
|
||||
VkRenderingInfo renderingInfo;
|
||||
VkRenderingAttachmentInfo colorAttachment{};
|
||||
VkRenderingAttachmentInfo depthAttachment{};
|
||||
VkRenderingInfo renderingInfo{};
|
||||
|
||||
RenderInfo() = default;
|
||||
|
||||
RenderInfo(const RenderInfo& other)
|
||||
: colorAttachment(other.colorAttachment),
|
||||
depthAttachment(other.depthAttachment),
|
||||
renderingInfo(other.renderingInfo)
|
||||
{
|
||||
rebind();
|
||||
}
|
||||
|
||||
RenderInfo& operator=(const RenderInfo& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
colorAttachment = other.colorAttachment;
|
||||
depthAttachment = other.depthAttachment;
|
||||
renderingInfo = other.renderingInfo;
|
||||
rebind();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
RenderInfo(RenderInfo&& other) noexcept
|
||||
: colorAttachment(other.colorAttachment),
|
||||
depthAttachment(other.depthAttachment),
|
||||
renderingInfo(other.renderingInfo)
|
||||
{
|
||||
rebind();
|
||||
}
|
||||
|
||||
RenderInfo& operator=(RenderInfo&& other) noexcept
|
||||
{
|
||||
if (this != &other) {
|
||||
colorAttachment = other.colorAttachment;
|
||||
depthAttachment = other.depthAttachment;
|
||||
renderingInfo = other.renderingInfo;
|
||||
rebind();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void rebind()
|
||||
{
|
||||
renderingInfo.pColorAttachments = renderingInfo.colorAttachmentCount != 0
|
||||
? &colorAttachment
|
||||
: nullptr;
|
||||
renderingInfo.pDepthAttachment = renderingInfo.pDepthAttachment != nullptr
|
||||
? &depthAttachment
|
||||
: nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
RenderInfo createRenderingInfo(const RenderingInfoParams& params);
|
||||
|
||||
@@ -33,9 +33,11 @@ public:
|
||||
virtual void Start();
|
||||
virtual void SetEnabled(bool enabled);
|
||||
|
||||
virtual void Update() = 0;
|
||||
virtual void LateUpdate();
|
||||
virtual void FixedUpdate();
|
||||
// Reason for keeping No DT function -> i am tired and lazy
|
||||
// If im feeling frisky im gonna claim backwards compatibility
|
||||
virtual void Update(float dt);
|
||||
virtual void LateUpdate(float dt);
|
||||
virtual void FixedUpdate(float fixedDt);
|
||||
|
||||
virtual void ImGuiInspector();
|
||||
virtual void ImGuiRender();
|
||||
@@ -49,10 +51,10 @@ public:
|
||||
return {};
|
||||
}
|
||||
|
||||
virtual void Deserialize(const nlohmann::json& data) {
|
||||
virtual void Deserialize(const nlohmann::json&) {
|
||||
}
|
||||
|
||||
virtual void ResolveReferences(const ObjectMap& objects) {
|
||||
virtual void ResolveReferences(const ObjectMap&) {
|
||||
}
|
||||
|
||||
bool HasStarted{false};
|
||||
@@ -60,9 +62,15 @@ public:
|
||||
protected:
|
||||
explicit Component(GameObject& pParent, const std::string& name = "Component");
|
||||
|
||||
[[nodiscard]] float GetLastUpdateDeltaTime() const { return m_LastUpdateDeltaTime; }
|
||||
[[nodiscard]] float GetLastFixedDeltaTime() const { return m_LastFixedDeltaTime; }
|
||||
void NotifyPhysicsChanged();
|
||||
|
||||
private:
|
||||
GameObject* m_ParentGameObjectPtr{};
|
||||
bool m_IsEnabled{true};
|
||||
float m_LastUpdateDeltaTime{0.0f};
|
||||
float m_LastFixedDeltaTime{0.0f};
|
||||
};
|
||||
|
||||
#endif // COMPONENT_H
|
||||
#endif // COMPONENT_H
|
||||
|
||||
@@ -10,20 +10,24 @@
|
||||
#include <destrum/ObjectModel/Transform.h>
|
||||
|
||||
class Scene;
|
||||
class SceneSerializer;
|
||||
|
||||
class GameObject final : public Object {
|
||||
public:
|
||||
friend class Scene;
|
||||
friend class SceneSerializer;
|
||||
friend class Transform;
|
||||
|
||||
void Update();
|
||||
void LateUpdate();
|
||||
void FixedUpdate();
|
||||
void Update(float dt);
|
||||
void LateUpdate(float dt);
|
||||
void FixedUpdate(float fixedDt);
|
||||
|
||||
void Render(const RenderContext& ctx) const;
|
||||
|
||||
void Destroy() override;
|
||||
|
||||
void CleanupComponents();
|
||||
void RefreshPhysics();
|
||||
|
||||
void SetActive(bool active) {
|
||||
if (active == m_Active) {
|
||||
@@ -32,6 +36,7 @@ public:
|
||||
|
||||
m_Active = active;
|
||||
SetActiveDirty();
|
||||
RefreshPhysics();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsActive() const { return m_Active; }
|
||||
@@ -71,14 +76,17 @@ public:
|
||||
auto& addedComponent = m_Components.emplace_back(
|
||||
std::make_unique<TComponent>(*this, std::forward<Args>(args)...));
|
||||
|
||||
RefreshPhysics();
|
||||
return static_cast<TComponent*>(addedComponent.get());
|
||||
}
|
||||
|
||||
template <typename TComponent>
|
||||
[[nodiscard]] TComponent* GetComponent() {
|
||||
for (const auto& component : m_Components) {
|
||||
if (auto casted = dynamic_cast<TComponent*>(component.get())) {
|
||||
return casted;
|
||||
if (component != nullptr && !component->IsBeingDestroyed()) {
|
||||
if (auto casted = dynamic_cast<TComponent*>(component.get())) {
|
||||
return casted;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -87,8 +95,10 @@ public:
|
||||
template <typename TComponent>
|
||||
[[nodiscard]] const TComponent* GetComponent() const {
|
||||
for (const auto& component : m_Components) {
|
||||
if (auto casted = dynamic_cast<const TComponent*>(component.get())) {
|
||||
return casted;
|
||||
if (component != nullptr && !component->IsBeingDestroyed()) {
|
||||
if (auto casted = dynamic_cast<const TComponent*>(component.get())) {
|
||||
return casted;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -97,9 +107,11 @@ public:
|
||||
template <typename TComponent>
|
||||
TComponent* DestroyComponent() {
|
||||
for (const auto& component : m_Components) {
|
||||
if (auto casted = dynamic_cast<TComponent*>(component.get())) {
|
||||
casted->Destroy();
|
||||
return casted;
|
||||
if (component != nullptr && !component->IsBeingDestroyed()) {
|
||||
if (auto casted = dynamic_cast<TComponent*>(component.get())) {
|
||||
casted->Destroy();
|
||||
return casted;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -108,7 +120,8 @@ public:
|
||||
template <typename TComponent>
|
||||
[[nodiscard]] bool HasComponent() const {
|
||||
for (const auto& component : m_Components) {
|
||||
if (dynamic_cast<TComponent*>(component.get())) {
|
||||
if (component != nullptr && !component->IsBeingDestroyed() &&
|
||||
dynamic_cast<TComponent*>(component.get())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -145,6 +158,7 @@ private:
|
||||
|
||||
void SetActiveDirty();
|
||||
void UpdateActiveState();
|
||||
static ObjectId AllocateId();
|
||||
|
||||
inline static ObjectId s_NextId{1};
|
||||
|
||||
@@ -157,4 +171,4 @@ private:
|
||||
|
||||
bool m_ActiveDirty{true};
|
||||
bool m_ActiveInHierarchy{true};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -73,6 +73,9 @@ private:
|
||||
void SetRotationDirty();
|
||||
void SetScaleDirty();
|
||||
|
||||
void SetLocalFromWorldMatrix(const glm::mat4& worldMatrix);
|
||||
void UpdateWorldCache();
|
||||
|
||||
glm::vec3 m_LocalPosition{};
|
||||
glm::quat m_LocalRotation{ glm::mat4{ 1.0f }};
|
||||
glm::vec3 m_LocalScale{ 1, 1, 1 };
|
||||
|
||||
@@ -25,6 +25,7 @@ public:
|
||||
[[nodiscard]] const PhysicsWorld& GetWorld() const { return *m_World; }
|
||||
|
||||
void RegisterGameObject(GameObject& object);
|
||||
void RefreshGameObject(GameObject& object);
|
||||
void UnregisterGameObject(GameObject& object);
|
||||
|
||||
void FixedUpdate(float fixedDt);
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include <destrum/Physics/PhysicsTypes.h>
|
||||
#include <destrum/Components/Physics/Rigidbody.h>
|
||||
|
||||
@@ -16,9 +19,10 @@ struct PhysicsRaycastHit {
|
||||
|
||||
class PhysicsWorld {
|
||||
public:
|
||||
virtual ~PhysicsWorld() = default;
|
||||
virtual ~PhysicsWorld();
|
||||
|
||||
void RegisterRigidbody(Rigidbody& rigidbody);
|
||||
void RefreshRigidbody(Rigidbody& rigidbody);
|
||||
void UnregisterRigidbody(Rigidbody& rigidbody);
|
||||
|
||||
virtual void Step(float fixedDt) = 0;
|
||||
@@ -44,4 +48,7 @@ public:
|
||||
const glm::vec3& direction,
|
||||
float maxDistance,
|
||||
PhysicsRaycastHit& hit) const = 0;
|
||||
|
||||
private:
|
||||
std::unordered_set<Rigidbody*> m_RegisteredRigidbodies;
|
||||
};
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
#include "destrum/Physics/PhysicsSceneBridge.h"
|
||||
|
||||
class GameObject;
|
||||
class SceneSerializer;
|
||||
|
||||
class Scene final {
|
||||
friend Scene& SceneManager::CreateScene(const std::string& name);
|
||||
friend class SceneSerializer;
|
||||
|
||||
public:
|
||||
// void Add(std::shared_ptr<GameObject> object);
|
||||
@@ -23,10 +25,10 @@ public:
|
||||
|
||||
void Load();
|
||||
|
||||
void Update();
|
||||
void Update(float dt);
|
||||
void FixedUpdate(float dt);
|
||||
void LateUpdate();
|
||||
void Render(const RenderContext& ctx) const;
|
||||
void LateUpdate(float dt);
|
||||
void Render(const RenderContext& ctx);
|
||||
void RenderImgui();
|
||||
|
||||
void CleanupDestroyedGameObjects();
|
||||
@@ -36,6 +38,11 @@ public:
|
||||
[[nodiscard]] bool IsBeingUnloaded() const { return m_BeingUnloaded; }
|
||||
|
||||
void CommitPendingAdditions();
|
||||
void RefreshPhysics();
|
||||
|
||||
[[nodiscard]] bool IsIterating() const { return m_IterationDepth != 0; }
|
||||
void BeginIteration();
|
||||
void EndIteration();
|
||||
|
||||
[[nodiscard]] const std::vector<std::shared_ptr<GameObject>>& GetObjects() const {
|
||||
return m_objects;
|
||||
@@ -50,20 +57,40 @@ public:
|
||||
}
|
||||
|
||||
void UnloadBindings() {
|
||||
if (!m_bindingsLoaded) {
|
||||
m_bindingsUnloaded = true;
|
||||
return;
|
||||
}
|
||||
if (m_unregisterBindings) {
|
||||
m_unregisterBindings();
|
||||
}
|
||||
m_bindingsLoaded = false;
|
||||
m_bindingsUnloaded = true;
|
||||
}
|
||||
|
||||
void LoadBindings() {
|
||||
OnSceneLoaded.Invoke();
|
||||
if (m_registerBindings) {
|
||||
m_registerBindings();
|
||||
if (m_BeingUnloaded || m_bindingsLoaded) {
|
||||
return;
|
||||
}
|
||||
m_bindingsLoaded = true;
|
||||
m_bindingsUnloaded = false;
|
||||
try {
|
||||
OnSceneLoaded.Invoke();
|
||||
if (m_registerBindings) {
|
||||
m_registerBindings();
|
||||
}
|
||||
} catch (...) {
|
||||
if (m_unregisterBindings) {
|
||||
m_unregisterBindings();
|
||||
}
|
||||
m_bindingsLoaded = false;
|
||||
m_bindingsUnloaded = true;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string& GetName() const { return m_name; }
|
||||
[[nodiscard]] unsigned int GetId() const { return m_idCounter++; }
|
||||
[[nodiscard]] unsigned int GetId() const { return m_id; }
|
||||
|
||||
~Scene();
|
||||
Scene(const Scene& other) = delete;
|
||||
@@ -84,8 +111,10 @@ private:
|
||||
std::vector<std::shared_ptr<GameObject>> m_objects{};
|
||||
std::vector<std::shared_ptr<GameObject>> m_pendingAdditions{};
|
||||
bool m_BeingUnloaded{false};
|
||||
std::size_t m_IterationDepth{0};
|
||||
|
||||
static unsigned int m_idCounter;
|
||||
unsigned int m_id{0};
|
||||
|
||||
bool m_renderImgui{false};
|
||||
|
||||
@@ -94,6 +123,8 @@ private:
|
||||
|
||||
std::function<void()> m_registerBindings;
|
||||
std::function<void()> m_unregisterBindings;
|
||||
bool m_bindingsUnloaded{false};
|
||||
bool m_bindingsLoaded{false};
|
||||
};
|
||||
|
||||
#endif // SCENE_H
|
||||
|
||||
@@ -15,12 +15,11 @@ class SceneManager final: public Singleton<SceneManager> {
|
||||
public:
|
||||
Scene& CreateScene(const std::string& name);
|
||||
|
||||
//TODO: Verry bad fix
|
||||
Scene& GetCurrentScene() const { return *m_scenes[m_ActiveSceneIndex]; }
|
||||
Scene& GetCurrentScene() const;
|
||||
|
||||
void Update();
|
||||
void Update(float dt);
|
||||
void FixedUpdate(float dt);
|
||||
void LateUpdate();
|
||||
void LateUpdate(float dt);
|
||||
|
||||
void Render(const RenderContext& ctx);
|
||||
void RenderImgui();
|
||||
@@ -35,7 +34,7 @@ public:
|
||||
void Destroy();
|
||||
|
||||
void SwitchScene(int index);
|
||||
int GetActiveSceneId() const { return m_ActiveSceneIndex; }
|
||||
int GetActiveSceneId() const { return m_scenes.empty() ? -1 : m_ActiveSceneIndex; }
|
||||
|
||||
[[nodiscard]] const std::vector<std::shared_ptr<Scene>>& GetScenes() const { return m_scenes; }
|
||||
|
||||
|
||||
@@ -27,6 +27,10 @@ public:
|
||||
return it->second(owner);
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool IsRegistered(const std::string& typeName) {
|
||||
return Registry().contains(typeName);
|
||||
}
|
||||
|
||||
private:
|
||||
static std::unordered_map<std::string, CreateFn>& Registry() {
|
||||
static std::unordered_map<std::string, CreateFn> registry;
|
||||
|
||||
@@ -13,6 +13,7 @@ public:
|
||||
friend class Singleton<GameState>;
|
||||
|
||||
void SetGfxDevice(GfxDevice* device) { m_gfxDevice = device; }
|
||||
[[nodiscard]] bool HasGfxDevice() const { return m_gfxDevice != nullptr; }
|
||||
GfxDevice& Gfx() {
|
||||
assert(m_gfxDevice && "GfxDevice not registered yet!");
|
||||
return *m_gfxDevice;
|
||||
@@ -23,6 +24,7 @@ public:
|
||||
}
|
||||
|
||||
void SetRenderer(GameRenderer* renderer) { m_renderer = renderer; }
|
||||
[[nodiscard]] bool HasRenderer() const { return m_renderer != nullptr; }
|
||||
GameRenderer& Renderer() {
|
||||
assert(m_renderer && "Renderer not registered yet!");
|
||||
return *m_renderer;
|
||||
|
||||
Reference in New Issue
Block a user