feat: move editor to project / add post processing etc
This commit is contained in:
@@ -1,29 +1,22 @@
|
||||
#ifndef APP_H
|
||||
#define APP_H
|
||||
#include <filesystem>
|
||||
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "glm/vec2.hpp"
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <glm/vec2.hpp>
|
||||
|
||||
#include <destrum/AppLayer.h>
|
||||
#include <destrum/Window.h>
|
||||
#include <destrum/Graphics/Camera.h>
|
||||
#include <destrum/Graphics/GfxDevice.h>
|
||||
#include <destrum/Graphics/Renderer.h>
|
||||
#include <destrum/Graphics/RenderResources.h>
|
||||
#include <destrum/Graphics/Pipelines/ImguiPass.h>
|
||||
#include <destrum/Graphics/ResourcesInspector.h>
|
||||
#include <destrum/Util/AssetBrowser.h>
|
||||
|
||||
#include <destrum/Input/InputManager.h>
|
||||
|
||||
|
||||
class Scene;
|
||||
|
||||
class App {
|
||||
public:
|
||||
struct AppParams {
|
||||
@@ -32,47 +25,57 @@ public:
|
||||
std::string appName{"Destrum App"};
|
||||
std::string windowTitle;
|
||||
std::filesystem::path exeDir;
|
||||
bool showDebugUi{true};
|
||||
WindowMode windowMode{WindowMode::Windowed};
|
||||
bool startMaximized{false};
|
||||
bool startInEditMode{false};
|
||||
};
|
||||
|
||||
struct SimulationControls {
|
||||
bool paused{false};
|
||||
bool stepOnce{false};
|
||||
float timeScale{1.0f};
|
||||
int stepsLastFrame{0};
|
||||
float accumulator{0.0f};
|
||||
float fixedDeltaTime{0.0f};
|
||||
};
|
||||
|
||||
App();
|
||||
virtual ~App();
|
||||
|
||||
App(const App&) = delete;
|
||||
App& operator=(const App&) = delete;
|
||||
|
||||
void init(const AppParams& params);
|
||||
void attachLayer(std::unique_ptr<AppLayer> layer);
|
||||
void run();
|
||||
void cleanup();
|
||||
|
||||
virtual void customInit() = 0;
|
||||
virtual void customUpdate(float dt) = 0;
|
||||
virtual void customDraw() = 0;
|
||||
virtual void customUpdate(float) {}
|
||||
virtual void customFixedUpdate(float) {}
|
||||
virtual void customRender(GameRenderer&) {}
|
||||
virtual void customCleanup() {}
|
||||
virtual void customFixedUpdate(float dt) = 0;
|
||||
|
||||
virtual void onWindowResize(int, int) {};
|
||||
virtual void onViewportResize(int, int) {}
|
||||
virtual void drawViewportOverlay() {}
|
||||
virtual void onViewportAssetDropped(std::string_view) {}
|
||||
|
||||
virtual void onPlayModeChanged(bool) {}
|
||||
|
||||
[[nodiscard]] bool isPlaying() const { return playing; }
|
||||
[[nodiscard]] bool isPaused() const { return paused; }
|
||||
void requestPlayModeToggle() { playModeToggleRequested = true; }
|
||||
void setPaused(bool pause);
|
||||
|
||||
virtual void customWindowsMenu() {}
|
||||
virtual void onWindowResize(int, int) {}
|
||||
virtual void onPlayModeChanged(bool) {}
|
||||
[[nodiscard]] virtual Camera* gameCamera() { return nullptr; }
|
||||
|
||||
struct ViewportRect {
|
||||
glm::vec2 min{0.0f};
|
||||
glm::vec2 size{0.0f};
|
||||
};
|
||||
[[nodiscard]] bool isPlaying() const;
|
||||
[[nodiscard]] bool isPaused() const;
|
||||
|
||||
[[nodiscard]] bool usesEditorViewport() const { return m_params.showDebugUi; }
|
||||
[[nodiscard]] const ViewportRect& getViewportRect() const { return viewportRect; }
|
||||
void claimViewportMouse() { viewportMouseClaimed = true; }
|
||||
[[nodiscard]] Window& getWindow() { return window; }
|
||||
[[nodiscard]] GfxDevice& getGfxDevice() { return gfxDevice; }
|
||||
[[nodiscard]] GameRenderer& getRenderer() { return renderer; }
|
||||
[[nodiscard]] RenderResources& getResources() { return resources; }
|
||||
[[nodiscard]] ImguiPass& getImguiPass() { return imguiPass; }
|
||||
[[nodiscard]] const AppParams& getParams() const { return m_params; }
|
||||
[[nodiscard]] SimulationControls& getSimulation() { return simulation; }
|
||||
[[nodiscard]] float getAverageFps() const { return avgFPS; }
|
||||
[[nodiscard]] float getRenderAspectRatio() const;
|
||||
|
||||
[[nodiscard]] Camera& getViewCamera();
|
||||
void resizeRenderTarget(const glm::ivec2& size);
|
||||
void collectUnusedResources();
|
||||
void requestQuit() { isRunning = false; }
|
||||
|
||||
protected:
|
||||
Window window;
|
||||
@@ -81,72 +84,28 @@ protected:
|
||||
GfxDevice gfxDevice;
|
||||
GameRenderer renderer;
|
||||
RenderResources resources;
|
||||
|
||||
ImguiPass imguiPass;
|
||||
|
||||
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 frameLimit{false};
|
||||
float frameTime{0.f};
|
||||
float avgFPS{0.f};
|
||||
|
||||
bool resizePending = false;
|
||||
std::chrono::steady_clock::time_point lastResizeTime{};
|
||||
|
||||
bool m_PhysicsPaused = false;
|
||||
bool m_PhysicsStepOnce = false;
|
||||
|
||||
float m_PhysicsTimeScale = 1.0f;
|
||||
int m_PhysicsStepsLastFrame = 0;
|
||||
|
||||
struct DebugWindows {
|
||||
bool stats{true};
|
||||
bool physics{true};
|
||||
bool inspector{true};
|
||||
bool imageCache{false};
|
||||
bool assets{true};
|
||||
};
|
||||
|
||||
DebugWindows m_DebugWindows{};
|
||||
ResourcesInspector m_ResourcesInspector;
|
||||
AssetBrowser m_AssetBrowser;
|
||||
|
||||
void drawWindowsMenu();
|
||||
void drawPhysicsPanel(float dt, float fixedDt, float accumulator);
|
||||
|
||||
private:
|
||||
void drawDockSpace();
|
||||
void drawViewportWindow();
|
||||
void applyViewportResize();
|
||||
void requestSelectionPick();
|
||||
void applySelectionPick();
|
||||
[[nodiscard]] bool canPickInViewport() const { return usesEditorViewport() && (!playing || paused); }
|
||||
void processEvents();
|
||||
void runFixedSteps();
|
||||
void handleSwapchainResize(bool& skipFrame);
|
||||
void renderFrame();
|
||||
|
||||
ViewportRect viewportRect{};
|
||||
glm::ivec2 viewportDesiredSize{0};
|
||||
bool viewportHovered{false};
|
||||
bool viewportFocused{false};
|
||||
bool viewportMouseClaimed{false};
|
||||
bool pickSelectsParent{false};
|
||||
std::unique_ptr<AppLayer> layer;
|
||||
Camera fallbackCamera{glm::vec3{0.0f, 2.0f, -5.0f}, glm::vec3{0.0f, 1.0f, 0.0f}};
|
||||
SimulationControls simulation{};
|
||||
|
||||
void drawPlayControls();
|
||||
void applyPlayModeToggle();
|
||||
bool enterPlayMode();
|
||||
void exitPlayMode();
|
||||
|
||||
bool playing{true};
|
||||
bool paused{false};
|
||||
bool mouseCapturedBeforePause{false};
|
||||
bool playModeToggleRequested{false};
|
||||
std::optional<nlohmann::json> editSnapshot;
|
||||
std::weak_ptr<Scene> editScene;
|
||||
bool isRunning{false};
|
||||
bool cleaningUp{false};
|
||||
bool customInitStarted{false};
|
||||
bool frameLimit{false};
|
||||
float avgFPS{0.0f};
|
||||
|
||||
bool resizePending{false};
|
||||
std::chrono::steady_clock::time_point lastResizeTime{};
|
||||
};
|
||||
|
||||
|
||||
#endif //APP_H
|
||||
#endif // APP_H
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef DESTRUM_APPLAYER_H
|
||||
#define DESTRUM_APPLAYER_H
|
||||
|
||||
class Camera;
|
||||
class GameRenderer;
|
||||
|
||||
class AppLayer {
|
||||
public:
|
||||
struct InputFocus {
|
||||
bool mouse{false};
|
||||
bool keyboard{false};
|
||||
};
|
||||
|
||||
virtual ~AppLayer() = default;
|
||||
|
||||
virtual void onAttach() {}
|
||||
virtual void onDetach() {}
|
||||
|
||||
virtual void onBeginFrame() {}
|
||||
virtual void onImGuiBegin(float) {}
|
||||
virtual void onImGui(float) {}
|
||||
virtual void onEndFrame() {}
|
||||
virtual void onRender(GameRenderer&) {}
|
||||
|
||||
[[nodiscard]] virtual Camera* viewCamera() { return nullptr; }
|
||||
[[nodiscard]] virtual bool hostsViewport() const { return false; }
|
||||
[[nodiscard]] virtual InputFocus gameInputFocus() const { return {}; }
|
||||
};
|
||||
|
||||
#endif // DESTRUM_APPLAYER_H
|
||||
@@ -0,0 +1,64 @@
|
||||
#ifndef DESTRUM_ASSETDATABASE_H
|
||||
#define DESTRUM_ASSETDATABASE_H
|
||||
|
||||
#include <compare>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <destrum/Assets/AssetReference.h>
|
||||
#include <destrum/Singleton.h>
|
||||
|
||||
struct AssetGuid {
|
||||
std::uint64_t high{0};
|
||||
std::uint64_t low{0};
|
||||
|
||||
[[nodiscard]] static AssetGuid Generate();
|
||||
[[nodiscard]] static std::optional<AssetGuid> Parse(std::string_view text);
|
||||
[[nodiscard]] std::string ToString() const;
|
||||
[[nodiscard]] bool IsValid() const { return high != 0 || low != 0; }
|
||||
|
||||
auto operator<=>(const AssetGuid&) const = default;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::hash<AssetGuid> {
|
||||
std::size_t operator()(const AssetGuid& guid) const noexcept
|
||||
{
|
||||
return std::hash<std::uint64_t>{}(guid.high ^ (guid.low * 0x9E3779B97F4A7C15ull));
|
||||
}
|
||||
};
|
||||
|
||||
class AssetDatabase final : public Singleton<AssetDatabase> {
|
||||
public:
|
||||
class MetaFileScope {
|
||||
public:
|
||||
MetaFileScope();
|
||||
~MetaFileScope();
|
||||
MetaFileScope(const MetaFileScope&) = delete;
|
||||
MetaFileScope& operator=(const MetaFileScope&) = delete;
|
||||
};
|
||||
|
||||
void Refresh();
|
||||
void Clear();
|
||||
void Register(std::string_view path, const AssetGuid& guid);
|
||||
|
||||
[[nodiscard]] std::optional<AssetGuid> FindGuid(std::string_view path) const;
|
||||
[[nodiscard]] std::optional<std::string> FindPath(const AssetGuid& guid) const;
|
||||
std::optional<AssetGuid> GuidForSave(std::string_view path);
|
||||
|
||||
[[nodiscard]] nlohmann::json WriteReference(std::string_view path, std::string_view subresource = {});
|
||||
[[nodiscard]] std::optional<AssetReference> ReadReference(const nlohmann::json& reference) const;
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, AssetGuid> m_Guids;
|
||||
std::unordered_map<AssetGuid, std::string> m_Paths;
|
||||
int m_MetaFileScopes{0};
|
||||
};
|
||||
|
||||
#endif // DESTRUM_ASSETDATABASE_H
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifndef DESTRUM_ASSETTYPES_H
|
||||
#define DESTRUM_ASSETTYPES_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <filesystem>
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace AssetTypes {
|
||||
inline constexpr std::string_view MetaExtension = ".meta";
|
||||
inline constexpr std::string_view MaterialExtension = ".dmat";
|
||||
inline constexpr std::string_view SceneExtension = ".scene";
|
||||
inline constexpr std::string_view PrefabExtension = ".prefab";
|
||||
|
||||
[[nodiscard]] inline std::string Extension(std::string_view path)
|
||||
{
|
||||
std::string extension = std::filesystem::path{path}.extension().string();
|
||||
std::ranges::transform(extension, extension.begin(), [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
return extension;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool HasExtension(std::string_view path, std::initializer_list<std::string_view> extensions)
|
||||
{
|
||||
const std::string extension = Extension(path);
|
||||
return std::ranges::find(extensions, extension) != extensions.end();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool IsModel(std::string_view path) { return HasExtension(path, {".fbx", ".glb", ".gltf", ".obj"}); }
|
||||
[[nodiscard]] inline bool IsImage(std::string_view path) { return HasExtension(path, {".png", ".jpg", ".jpeg", ".tga", ".bmp"}); }
|
||||
[[nodiscard]] inline bool IsMaterial(std::string_view path) { return HasExtension(path, {MaterialExtension}); }
|
||||
[[nodiscard]] inline bool IsScene(std::string_view path) { return HasExtension(path, {SceneExtension}); }
|
||||
[[nodiscard]] inline bool IsPrefab(std::string_view path) { return HasExtension(path, {PrefabExtension}); }
|
||||
[[nodiscard]] inline bool IsMeta(std::string_view path) { return HasExtension(path, {MetaExtension}); }
|
||||
}
|
||||
|
||||
#endif // DESTRUM_ASSETTYPES_H
|
||||
@@ -17,7 +17,7 @@ struct FSMount {
|
||||
std::string scheme; // "engine", "game"
|
||||
std::filesystem::path root;
|
||||
std::optional<AssetManifest> manifest;
|
||||
|
||||
std::optional<std::filesystem::path> sourceRoot;
|
||||
};
|
||||
|
||||
class AssetFS final: public Singleton<AssetFS> {
|
||||
@@ -36,6 +36,11 @@ public:
|
||||
|
||||
[[nodiscard]] const std::vector<FSMount>& GetMounts() const { return mounts; }
|
||||
|
||||
void SetSourceRoot(std::string_view scheme, std::filesystem::path sourceRoot);
|
||||
[[nodiscard]] std::optional<std::filesystem::path> GetSourcePath(std::string_view vpath) const;
|
||||
|
||||
bool WriteFile(std::string_view vpath, std::string_view contents);
|
||||
|
||||
private:
|
||||
static std::vector<uint8_t> ReadFile(const std::filesystem::path& fullPath);
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#ifndef MATERIALCACHE_H
|
||||
#define MATERIALCACHE_H
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <destrum/Graphics/ids.h>
|
||||
#include <destrum/Graphics/Material.h>
|
||||
@@ -28,6 +29,8 @@ public:
|
||||
void cleanup(GfxDevice& gfxDevice);
|
||||
|
||||
MaterialID addMaterial(Material material, std::string key = {});
|
||||
void removeMaterial(MaterialID id);
|
||||
[[nodiscard]] bool isValid(MaterialID id) const { return id < materialKeys.size() && !materialKeys[id].empty(); }
|
||||
MaterialID addSimpleColorMaterial(
|
||||
glm::vec3 color,
|
||||
std::string name = {});
|
||||
@@ -55,6 +58,7 @@ private:
|
||||
|
||||
std::vector<Material> materials;
|
||||
std::vector<std::string> materialKeys;
|
||||
std::shared_ptr<std::vector<MaterialID>> freeIds = std::make_shared<std::vector<MaterialID>>();
|
||||
|
||||
static constexpr auto MAX_MATERIALS = 1000;
|
||||
GPUBuffer materialDataBuffer;
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
|
||||
#include <destrum/Graphics/Resources/Mesh.h>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "../ids.h"
|
||||
|
||||
@@ -15,6 +17,9 @@ public:
|
||||
void cleanup(GfxDevice& gfxDevice);
|
||||
|
||||
MeshID addMesh(GfxDevice& gfxDevice, const CPUMesh& cpuMesh);
|
||||
void removeMesh(GfxDevice& gfxDevice, MeshID id);
|
||||
[[nodiscard]] bool isValid(MeshID id) const { return id < meshKeys.size() && !meshKeys[id].empty(); }
|
||||
[[nodiscard]] std::size_t getSlotCount() const { return meshes.size(); }
|
||||
const GPUMesh& getMesh(MeshID id) const;
|
||||
[[nodiscard]] const std::vector<GPUMesh>& getMeshes() const { return meshes; }
|
||||
const CPUMesh& getCPUMesh(MeshID id) const;
|
||||
@@ -26,8 +31,19 @@ public:
|
||||
[[nodiscard]] std::uint32_t getIndexCapacity() const { return indexCapacity; }
|
||||
|
||||
private:
|
||||
struct IndexRange {
|
||||
std::uint32_t first{0};
|
||||
std::uint32_t count{0};
|
||||
};
|
||||
|
||||
struct RecycleBin {
|
||||
std::vector<MeshID> ids;
|
||||
std::vector<IndexRange> indexRanges;
|
||||
};
|
||||
|
||||
void uploadMesh(GfxDevice& gfxDevice, const CPUMesh& cpuMesh, GPUMesh& gpuMesh);
|
||||
void ensureIndexCapacity(GfxDevice& gfxDevice, std::uint32_t requiredIndices);
|
||||
[[nodiscard]] std::uint32_t allocateIndices(GfxDevice& gfxDevice, std::uint32_t count);
|
||||
|
||||
static constexpr std::uint32_t InitialIndexCapacity = 1u << 20;
|
||||
|
||||
@@ -38,6 +54,7 @@ private:
|
||||
std::vector<GPUMesh> meshes;
|
||||
std::vector<CPUMesh> cpuMeshes;
|
||||
std::vector<std::string> meshKeys;
|
||||
std::shared_ptr<RecycleBin> recycleBin = std::make_shared<RecycleBin>();
|
||||
};
|
||||
|
||||
#endif //MESHCACHE_H
|
||||
|
||||
@@ -50,7 +50,6 @@ public:
|
||||
struct EndFrameProps
|
||||
{
|
||||
VkClearColorValue clearColor{{0.f, 0.f, 0.f, 1.f}};
|
||||
glm::ivec4 drawImageBlitRect{};
|
||||
ImguiPass* imguiPass{nullptr};
|
||||
bool copyDrawImageToSwapchain{true};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef DESTRUM_POSTPROCESSPIPELINE_H
|
||||
#define DESTRUM_POSTPROCESSPIPELINE_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <glm/vec2.hpp>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include <destrum/Graphics/Pipeline.h>
|
||||
#include <destrum/Graphics/Tonemapper.h>
|
||||
#include <destrum/Graphics/ids.h>
|
||||
|
||||
class GfxDevice;
|
||||
class RenderResources;
|
||||
|
||||
class PostProcessPipeline final {
|
||||
public:
|
||||
struct Settings {
|
||||
ImageID sceneColor{NULL_IMAGE_ID};
|
||||
std::optional<ImageID> selection;
|
||||
std::optional<glm::ivec2> hoverPixel;
|
||||
Tonemapper tonemapper{Tonemapper::PbrNeutral};
|
||||
float exposure{0.0f};
|
||||
};
|
||||
|
||||
void init(GfxDevice& gfxDevice, RenderResources& resources, VkFormat outputFormat);
|
||||
void cleanup(VkDevice device);
|
||||
|
||||
void draw(VkCommandBuffer cmd, const RenderResources& resources, VkExtent2D extent, const Settings& settings) const;
|
||||
|
||||
private:
|
||||
// Must match PostPushConstants in post.frag
|
||||
struct PushConstants {
|
||||
std::uint32_t sceneColorTexture;
|
||||
std::uint32_t selectionTexture;
|
||||
std::uint32_t tonemapper;
|
||||
float exposure;
|
||||
glm::ivec2 hoverPixel;
|
||||
};
|
||||
|
||||
VkPipelineLayout m_PipelineLayout{VK_NULL_HANDLE};
|
||||
std::unique_ptr<Pipeline> m_Pipeline;
|
||||
};
|
||||
|
||||
#endif // DESTRUM_POSTPROCESSPIPELINE_H
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace ModelDoc { struct MaterialInfo; }
|
||||
|
||||
@@ -45,6 +46,18 @@ public:
|
||||
bool mipMap = true,
|
||||
TextureIntent intent = TextureIntent::ColorSrgb);
|
||||
|
||||
ImageID loadMaterialTexture(GfxDevice& gfxDevice, const std::filesystem::path& path, TextureIntent intent);
|
||||
|
||||
struct ReleaseStats {
|
||||
std::size_t meshes{0};
|
||||
std::size_t materials{0};
|
||||
std::size_t images{0};
|
||||
};
|
||||
ReleaseStats releaseUnused(
|
||||
GfxDevice& gfxDevice,
|
||||
const std::unordered_set<MeshID>& usedMeshes,
|
||||
const std::unordered_set<MaterialID>& usedMaterials);
|
||||
|
||||
ImageID addImageToCache(GPUImage image);
|
||||
void destroyImage(ImageID id);
|
||||
|
||||
@@ -86,6 +99,9 @@ private:
|
||||
std::unique_ptr<MeshCache> meshCache;
|
||||
std::unique_ptr<MaterialCache> materialCache;
|
||||
|
||||
std::unordered_set<ImageID> materialTextures;
|
||||
std::unordered_set<ImageID> pinnedImages;
|
||||
|
||||
ImageID whiteImageId{NULL_IMAGE_ID};
|
||||
ImageID errorImageId{NULL_IMAGE_ID};
|
||||
ImageID defaultNormalImageId{NULL_IMAGE_ID};
|
||||
|
||||
@@ -11,9 +11,11 @@
|
||||
#include <destrum/Graphics/Pipelines/LightCullingPipeline.h>
|
||||
#include <destrum/Graphics/Pipelines/LineRenderingPass.h>
|
||||
#include <destrum/Graphics/Pipelines/MeshPipeline.h>
|
||||
#include <destrum/Graphics/Pipelines/PostProcessPipeline.h>
|
||||
#include <destrum/Graphics/Pipelines/Renderer2DPass.h>
|
||||
#include <destrum/Graphics/Pipelines/ShadowMapPipeline.h>
|
||||
#include <destrum/Graphics/ids.h>
|
||||
#include <destrum/Graphics/Tonemapper.h>
|
||||
#include <destrum/Graphics/MeshDrawCommand.h>
|
||||
#include <destrum/Graphics/Resources/NBuffer.h>
|
||||
#include <destrum/Graphics/RenderResources.h>
|
||||
@@ -22,6 +24,8 @@
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -49,6 +53,8 @@ public:
|
||||
glm::vec3 fogColor;
|
||||
float fogDensity;
|
||||
float skyboxRotation{0.0f}; // radians around the world up axis
|
||||
float exposure{0.0f}; // EV stops, the scene color is multiplied by 2^exposure
|
||||
Tonemapper tonemapper{Tonemapper::PbrNeutral};
|
||||
};
|
||||
|
||||
explicit GameRenderer();
|
||||
@@ -68,14 +74,14 @@ public:
|
||||
|
||||
void resize(GfxDevice& gfxDevice, const glm::ivec2& newSize)
|
||||
{
|
||||
createDrawImage(gfxDevice, newSize, false);
|
||||
createDrawImage(gfxDevice, newSize);
|
||||
lightCullingPipeline->resize(gfxDevice, newSize);
|
||||
}
|
||||
|
||||
Material& getMaterialMutable(MaterialID id);
|
||||
void updateMaterialGPU(MaterialID id);
|
||||
|
||||
void setSkyboxTexture(ImageID skyboxImageId);
|
||||
void setSkyboxTexture(ImageID imageId);
|
||||
|
||||
|
||||
[[nodiscard]] SkinningPipeline& getSkinningPipeline() const
|
||||
@@ -123,6 +129,18 @@ public:
|
||||
requestedPick = pixel;
|
||||
}
|
||||
|
||||
void setHoverPixel(std::optional<glm::ivec2> pixel)
|
||||
{
|
||||
hoverPixel = pixel;
|
||||
}
|
||||
|
||||
void setHighlightedObjects(std::span<const std::uint32_t> objectIds)
|
||||
{
|
||||
highlightedObjects = {objectIds.begin(), objectIds.end()};
|
||||
}
|
||||
|
||||
bool reloadShaders(GfxDevice& gfxDevice);
|
||||
|
||||
[[nodiscard]] std::optional<std::uint32_t> takeSelectionPick()
|
||||
{
|
||||
return std::exchange(pickResult, std::nullopt);
|
||||
@@ -151,7 +169,7 @@ public:
|
||||
const glm::mat4& projection);
|
||||
|
||||
private:
|
||||
void createDrawImage(GfxDevice& gfxDevice, const glm::ivec2& drawImageSize, bool firstCreate);
|
||||
void createDrawImage(GfxDevice& gfxDevice, const glm::ivec2& drawImageSize);
|
||||
void uploadLights(const Camera& camera);
|
||||
void recordSelectionPick(VkCommandBuffer cmd, std::uint32_t frameIndex);
|
||||
[[nodiscard]] std::uint32_t assignShadowIndex(const Light& light, const Frustum& cameraFrustum);
|
||||
@@ -168,11 +186,16 @@ private:
|
||||
IndirectDrawList drawList;
|
||||
DrawStats lastDrawStats;
|
||||
|
||||
VkFormat drawImageFormat{VK_FORMAT_R16G16B16A16_SFLOAT};
|
||||
static constexpr std::uint32_t HighlightedObjectFlag = 0x80000000u;
|
||||
|
||||
VkFormat sceneColorFormat{VK_FORMAT_R16G16B16A16_SFLOAT};
|
||||
VkFormat drawImageFormat{VK_FORMAT_R8G8B8A8_SRGB};
|
||||
VkFormat depthImageFormat{VK_FORMAT_D32_SFLOAT};
|
||||
VkFormat selectionImageFormat{VK_FORMAT_R32_UINT};
|
||||
|
||||
ImageID sceneColorImageId{NULL_IMAGE_ID};
|
||||
ImageID drawImageId{NULL_IMAGE_ID};
|
||||
ImageID skyboxImageId{NULL_IMAGE_ID};
|
||||
ImageID depthImageId{NULL_IMAGE_ID};
|
||||
ImageID selectionImageId{NULL_IMAGE_ID};
|
||||
|
||||
@@ -180,6 +203,8 @@ private:
|
||||
std::array<bool, FRAMES_IN_FLIGHT> pickPending{};
|
||||
std::optional<glm::ivec2> requestedPick;
|
||||
std::optional<std::uint32_t> pickResult;
|
||||
std::optional<glm::ivec2> hoverPixel;
|
||||
std::unordered_set<std::uint32_t> highlightedObjects;
|
||||
bool selectionPassEnabled{false};
|
||||
bool renderSelectionView{false};
|
||||
|
||||
@@ -228,6 +253,7 @@ private:
|
||||
std::unique_ptr<SkinningPipeline> skinningPipeline;
|
||||
std::unique_ptr<LightCullingPipeline> lightCullingPipeline;
|
||||
std::unique_ptr<ShadowMapPipeline> shadowMapPipeline;
|
||||
std::unique_ptr<PostProcessPipeline> postProcessPipeline;
|
||||
|
||||
std::optional<glm::vec3> shadowLightDirection;
|
||||
std::vector<Light> submittedLights;
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
#ifndef RESOURCESINSPECTOR_H
|
||||
#define RESOURCESINSPECTOR_H
|
||||
|
||||
#include <destrum/Graphics/ids.h>
|
||||
|
||||
struct GPUImage;
|
||||
class ImguiPass;
|
||||
class RenderResources;
|
||||
|
||||
// ImGui windows for looking into the render resource caches
|
||||
class ResourcesInspector final
|
||||
{
|
||||
public:
|
||||
void drawImageCacheWindow(bool* open, const RenderResources& resources, ImguiPass& imguiPass);
|
||||
|
||||
private:
|
||||
struct PreviewInfo
|
||||
{
|
||||
bool previewable{false};
|
||||
const char* reason{""};
|
||||
};
|
||||
|
||||
[[nodiscard]] static PreviewInfo getPreviewInfo(const GPUImage& image);
|
||||
|
||||
void drawImagePreview(const GPUImage& image, float maxSize, ImguiPass& imguiPass) const;
|
||||
void drawImageDetails(ImageID id, const RenderResources& resources) const;
|
||||
[[nodiscard]] bool matchesFilter(ImageID id, const RenderResources& resources) const;
|
||||
|
||||
char filter[128]{};
|
||||
float thumbnailSize{48.0f};
|
||||
bool onlyPreviewable{false};
|
||||
ImageID selectedImageId{NULL_IMAGE_ID};
|
||||
};
|
||||
|
||||
#endif //RESOURCESINSPECTOR_H
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef DESTRUM_TONEMAPPER_H
|
||||
#define DESTRUM_TONEMAPPER_H
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
// Must match the TONEMAPPER_ defines in post.frag
|
||||
enum class Tonemapper : std::uint32_t {
|
||||
None,
|
||||
Aces,
|
||||
PbrNeutral,
|
||||
};
|
||||
|
||||
inline constexpr std::array<std::string_view, 3> TonemapperNames{"none", "aces", "pbrNeutral"};
|
||||
|
||||
[[nodiscard]] inline std::string_view ToString(Tonemapper tonemapper)
|
||||
{
|
||||
return TonemapperNames.at(static_cast<std::size_t>(tonemapper));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::optional<Tonemapper> ParseTonemapper(std::string_view name)
|
||||
{
|
||||
for (std::size_t i = 0; i < TonemapperNames.size(); ++i) {
|
||||
if (TonemapperNames[i] == name) {
|
||||
return static_cast<Tonemapper>(i);
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
#endif // DESTRUM_TONEMAPPER_H
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef DESTRUM_RESOURCECOLLECTOR_H
|
||||
#define DESTRUM_RESOURCECOLLECTOR_H
|
||||
|
||||
class GfxDevice;
|
||||
class RenderResources;
|
||||
class SceneManager;
|
||||
|
||||
void CollectUnusedResources(SceneManager& sceneManager, RenderResources& resources, GfxDevice& gfxDevice);
|
||||
|
||||
#endif // DESTRUM_RESOURCECOLLECTOR_H
|
||||
@@ -6,9 +6,9 @@
|
||||
#include <memory>
|
||||
|
||||
#include <destrum/Event.h>
|
||||
#include <destrum/Graphics/Tonemapper.h>
|
||||
#include <destrum/ObjectModel/ObjectId.h>
|
||||
#include <destrum/Scene/SceneManager.h>
|
||||
#include <destrum/Util/SceneInspector.h>
|
||||
|
||||
#include "destrum/Physics/JoltPhysicsWorld.h"
|
||||
#include "destrum/Physics/PhysicsSceneBridge.h"
|
||||
@@ -26,6 +26,9 @@ struct SceneEnvironment {
|
||||
|
||||
float skyboxRotationSpeed{0.01f};
|
||||
float skyboxRotation{0.0f};
|
||||
|
||||
float exposure{0.0f};
|
||||
Tonemapper tonemapper{Tonemapper::PbrNeutral};
|
||||
};
|
||||
class SceneSerializer;
|
||||
class PrefabSerializer;
|
||||
@@ -49,7 +52,6 @@ public:
|
||||
void FixedUpdate(float dt);
|
||||
void LateUpdate(float dt);
|
||||
void Render(const RenderContext& ctx);
|
||||
void RenderImgui(bool* open = nullptr);
|
||||
|
||||
void CleanupDestroyedGameObjects();
|
||||
void Unload();
|
||||
@@ -76,6 +78,9 @@ public:
|
||||
// nullptr. Also reorders the object list so the order survives a save. False if the move isn't allowed.
|
||||
bool MoveInHierarchy(GameObject& object, GameObject* parent, const GameObject* insertBefore = nullptr);
|
||||
void SetSelectedObject(ObjectId id) { m_SelectedObjectId = id; }
|
||||
[[nodiscard]] ObjectId GetSelectedObjectId() const { return m_SelectedObjectId; }
|
||||
|
||||
void DrawSettingsImGui();
|
||||
[[nodiscard]] GameObject* GetSelectedObject() const { return FindGameObject(m_SelectedObjectId); }
|
||||
|
||||
void SetRegisterBindings(std::function<void()> registerBindings) {
|
||||
@@ -159,13 +164,11 @@ private:
|
||||
//Imgui vars
|
||||
bool m_ShowDemoWindow{false};
|
||||
ObjectId m_SelectedObjectId{InvalidObjectId};
|
||||
SceneInspector m_Inspector;
|
||||
|
||||
ObjectId m_CurrentCameraId{InvalidObjectId};
|
||||
|
||||
SceneEnvironment m_Environment{};
|
||||
|
||||
void DrawSettingsImGui();
|
||||
|
||||
std::function<void()> m_registerBindings;
|
||||
std::function<void()> m_unregisterBindings;
|
||||
|
||||
@@ -28,7 +28,6 @@ public:
|
||||
void LateUpdate(float dt);
|
||||
|
||||
void Render(const RenderContext& ctx);
|
||||
void RenderImgui(bool* open = nullptr);
|
||||
|
||||
void HandleGameObjectDestroy();
|
||||
void DestroyGameObjects();
|
||||
|
||||
@@ -4,22 +4,32 @@
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <destrum/Graphics/Material.h>
|
||||
|
||||
class GfxDevice;
|
||||
class RenderResources;
|
||||
|
||||
namespace MaterialSerialization {
|
||||
inline constexpr int CurrentFileVersion = 1;
|
||||
|
||||
using TextureWriter = std::function<nlohmann::json(ImageID)>;
|
||||
using TextureReader = std::function<ImageID(const nlohmann::json&)>;
|
||||
|
||||
[[nodiscard]] nlohmann::json ToJson(const Material& material, const TextureWriter& writeTexture);
|
||||
[[nodiscard]] Material FromJson(const nlohmann::json& data, const TextureReader& readTexture);
|
||||
|
||||
[[nodiscard]] std::optional<std::string> Validate(const nlohmann::json& materials);
|
||||
|
||||
[[nodiscard]] nlohmann::json CollectEmbedded(const nlohmann::json& objects);
|
||||
void RegisterEmbedded(const nlohmann::json& materials, bool overwriteExisting = false);
|
||||
[[nodiscard]] bool IsFileKey(std::string_view key);
|
||||
[[nodiscard]] nlohmann::json ToFile(const Material& material, const RenderResources* resources = nullptr);
|
||||
MaterialID LoadFile(RenderResources& resources, GfxDevice& gfxDevice, std::string_view path);
|
||||
bool SaveFile(const RenderResources& resources, MaterialID id, std::string_view path);
|
||||
|
||||
[[nodiscard]] nlohmann::json EmbedLocalMaterials(nlohmann::json& objects);
|
||||
void LoadLocalMaterials(const nlohmann::json& materials, nlohmann::json& objects);
|
||||
}
|
||||
|
||||
#endif //DESTRUM_MATERIALSERIALIZATION_H
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace ObjectSerialization {
|
||||
using ObjectMap = std::unordered_map<ObjectId, GameObject*>;
|
||||
using ValidationError = std::optional<std::string>;
|
||||
|
||||
constexpr int CurrentObjectVersion = 2;
|
||||
constexpr int CurrentObjectVersion = 3;
|
||||
|
||||
[[nodiscard]] std::optional<std::string> FindNonFinite(const nlohmann::json& value, const std::string& path);
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ class Transform;
|
||||
|
||||
class PrefabSerializer final {
|
||||
public:
|
||||
static constexpr int CurrentPrefabVersion = 1;
|
||||
static constexpr int CurrentPrefabVersion = 2;
|
||||
|
||||
[[nodiscard]] static std::optional<nlohmann::json> Capture(const GameObject& root);
|
||||
static bool Save(const GameObject& root, const std::filesystem::path& path);
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#ifndef DESTRUM_ASSETBROWSER_H
|
||||
#define DESTRUM_ASSETBROWSER_H
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
class AssetBrowser final {
|
||||
public:
|
||||
void Draw(bool* open = nullptr);
|
||||
|
||||
[[nodiscard]] static bool IsModel(std::string_view path);
|
||||
|
||||
private:
|
||||
struct Entry {
|
||||
std::string name;
|
||||
bool directory{false};
|
||||
};
|
||||
|
||||
void Refresh();
|
||||
void Navigate(const std::string& scheme, const std::filesystem::path& folder);
|
||||
bool DrawEntry(const Entry& entry);
|
||||
|
||||
std::string m_Scheme;
|
||||
std::filesystem::path m_Folder;
|
||||
std::vector<Entry> m_Entries;
|
||||
std::string m_Filter;
|
||||
bool m_Dirty{true};
|
||||
};
|
||||
|
||||
#endif // DESTRUM_ASSETBROWSER_H
|
||||
@@ -1,28 +0,0 @@
|
||||
#ifndef DESTRUM_RECTGIZMO_H
|
||||
#define DESTRUM_RECTGIZMO_H
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class GameObject;
|
||||
|
||||
class RectGizmo final {
|
||||
public:
|
||||
[[nodiscard]] static bool CanManipulate(GameObject& object);
|
||||
|
||||
bool Manipulate(GameObject& object, const glm::vec2& drawImageSize, const glm::vec2& viewMin, const glm::vec2& viewSize);
|
||||
|
||||
[[nodiscard]] bool IsUsing() const { return m_ActiveHandle >= 0; }
|
||||
[[nodiscard]] bool IsInteracting() const { return m_ActiveHandle >= 0 || m_Hovered; }
|
||||
|
||||
bool snap{false};
|
||||
float snapStep{5.0f};
|
||||
|
||||
private:
|
||||
int m_ActiveHandle{-1};
|
||||
bool m_Hovered{false};
|
||||
glm::vec2 m_DragStartMouse{0.0f};
|
||||
glm::vec2 m_DragStartPosition{0.0f};
|
||||
glm::vec2 m_DragStartSize{0.0f};
|
||||
};
|
||||
|
||||
#endif // DESTRUM_RECTGIZMO_H
|
||||
@@ -1,60 +0,0 @@
|
||||
#ifndef DESTRUM_SCENEINSPECTOR_H
|
||||
#define DESTRUM_SCENEINSPECTOR_H
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <destrum/ObjectModel/ObjectId.h>
|
||||
|
||||
class Component;
|
||||
class GameObject;
|
||||
class Scene;
|
||||
|
||||
class SceneInspector final {
|
||||
public:
|
||||
void Draw(Scene& scene, ObjectId& selectedObjectId, const std::function<void()>& drawSceneSettings, bool* open);
|
||||
|
||||
private:
|
||||
struct PendingMove {
|
||||
ObjectId object{InvalidObjectId};
|
||||
ObjectId parent{InvalidObjectId};
|
||||
ObjectId anchor{InvalidObjectId};
|
||||
bool after{false};
|
||||
};
|
||||
|
||||
void DrawHierarchy(Scene& scene, ObjectId& selectedObjectId);
|
||||
void DrawNode(Scene& scene, GameObject& object, ObjectId& selectedObjectId, std::unordered_set<const GameObject*>& visited);
|
||||
void DrawRenameField(GameObject& object);
|
||||
void DrawNodeDragDrop(GameObject& object);
|
||||
void DrawObjectMenu(Scene& scene, GameObject* object, ObjectId& selectedObjectId);
|
||||
void HandleShortcuts(Scene& scene, ObjectId& selectedObjectId);
|
||||
void ApplyPendingActions(Scene& scene, ObjectId& selectedObjectId);
|
||||
|
||||
void DrawObject(GameObject& object);
|
||||
void DrawTransform(GameObject& object);
|
||||
void DrawComponents(GameObject& object);
|
||||
void DrawComponentMenu(GameObject& object, Component& component, std::size_t index, bool removable);
|
||||
void DrawAddComponent(GameObject& object);
|
||||
|
||||
void BeginRename(const GameObject& object);
|
||||
|
||||
std::string m_Filter;
|
||||
std::string m_ComponentFilter;
|
||||
|
||||
ObjectId m_RenamingId{InvalidObjectId};
|
||||
std::string m_RenameBuffer;
|
||||
bool m_FocusRename{false};
|
||||
|
||||
ObjectId m_OpenNextFrame{InvalidObjectId};
|
||||
PendingMove m_PendingMove;
|
||||
ObjectId m_PendingDelete{InvalidObjectId};
|
||||
ObjectId m_PendingDuplicate{InvalidObjectId};
|
||||
|
||||
std::string m_ClipboardType;
|
||||
nlohmann::json m_Clipboard;
|
||||
};
|
||||
|
||||
#endif // DESTRUM_SCENEINSPECTOR_H
|
||||
@@ -1,37 +0,0 @@
|
||||
#ifndef DESTRUM_TRANSFORMGIZMO_H
|
||||
#define DESTRUM_TRANSFORMGIZMO_H
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class Camera;
|
||||
class GameObject;
|
||||
|
||||
enum class GizmoOperation {
|
||||
Translate,
|
||||
Rotate,
|
||||
Scale,
|
||||
};
|
||||
|
||||
enum class GizmoSpace {
|
||||
World,
|
||||
Local,
|
||||
};
|
||||
|
||||
class TransformGizmo final {
|
||||
public:
|
||||
void HandleShortcuts();
|
||||
void DrawToolbar();
|
||||
bool Manipulate(GameObject& object, const Camera& camera, const glm::vec2& viewMin, const glm::vec2& viewSize);
|
||||
|
||||
[[nodiscard]] bool IsUsing() const;
|
||||
[[nodiscard]] bool IsOver() const;
|
||||
|
||||
GizmoOperation operation{GizmoOperation::Translate};
|
||||
GizmoSpace space{GizmoSpace::World};
|
||||
bool snap{false};
|
||||
float translationSnap{0.5f};
|
||||
float rotationSnapDegrees{15.0f};
|
||||
float scaleSnap{0.1f};
|
||||
};
|
||||
|
||||
#endif // DESTRUM_TRANSFORMGIZMO_H
|
||||
Reference in New Issue
Block a user