feat: move editor to project / add post processing etc

This commit is contained in:
2026-10-23 20:54:12 +02:00
parent f7e7c56392
commit a3d3da4a67
104 changed files with 11750 additions and 2675 deletions
+56 -97
View File
@@ -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
+30
View File
@@ -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
+6 -1
View File
@@ -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};
+30 -4
View File
@@ -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
+7 -4
View File
@@ -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
-28
View File
@@ -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