diff --git a/lib/engine/CMakeLists.txt b/lib/engine/CMakeLists.txt index ded2892..c14bf75 100644 --- a/lib/engine/CMakeLists.txt +++ b/lib/engine/CMakeLists.txt @@ -43,6 +43,7 @@ target_sources(${PROJECT_NAME} PRIVATE include/${target_prefix}/engine/editor/browse_file.hpp include/${target_prefix}/engine/editor/common.hpp include/${target_prefix}/engine/editor/drag_drop_id.hpp + include/${target_prefix}/engine/editor/inspect_data.hpp include/${target_prefix}/engine/editor/inspector.hpp include/${target_prefix}/engine/editor/log.hpp include/${target_prefix}/engine/editor/reflector.hpp diff --git a/lib/engine/include/facade/engine/editor/inspect_data.hpp b/lib/engine/include/facade/engine/editor/inspect_data.hpp new file mode 100644 index 0000000..4a8c5b3 --- /dev/null +++ b/lib/engine/include/facade/engine/editor/inspect_data.hpp @@ -0,0 +1,9 @@ +#pragma once +#include + +namespace facade::editor { +struct InspectData { + std::string input_buffer{}; + int material_type{}; +}; +} // namespace facade::editor diff --git a/lib/engine/include/facade/engine/editor/inspector.hpp b/lib/engine/include/facade/engine/editor/inspector.hpp index 025dc9e..24b0fc5 100644 --- a/lib/engine/include/facade/engine/editor/inspector.hpp +++ b/lib/engine/include/facade/engine/editor/inspector.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #include namespace facade::editor { @@ -20,7 +21,7 @@ class Inspector { NotClosed m_target; Scene& m_scene; - SceneResourcesMut m_resources; + SceneResources& m_resources; }; /// @@ -67,15 +68,17 @@ class ResourceInspector : public Inspector { /// class SceneInspector : public Inspector { public: + using Data = InspectData; + SceneInspector(NotClosed target, Scene& out_scene) : Inspector(target, out_scene) {} /// /// \brief View/edit all resources. - /// \param out_name_buf Persistent buffer for popups + /// \param out_data Persistent data for popups /// /// Uses ResourceInspector. /// - void resources(std::string& out_name_buf) const; + void resources(Data& out_data) const; /// /// \brief Inspect the Scene's camera. /// diff --git a/lib/engine/src/editor/inspector.cpp b/lib/engine/src/editor/inspector.cpp index f8e735b..a4c3ff9 100644 --- a/lib/engine/src/editor/inspector.cpp +++ b/lib/engine/src/editor/inspector.cpp @@ -26,7 +26,7 @@ void edit_material(NotClosed target, SceneResources const& resources, Li make_id_slot(lit.emissive, "Emissive", name.c_str(), {true}); } -void edit_material(SceneResourcesMut resources, UnlitMaterial& unlit) { +void edit_material(SceneResources const& resources, UnlitMaterial& unlit) { auto name = FixedString<128>{}; if (unlit.texture) { name = FixedString<128>{"{} ({})", resources.textures[*unlit.texture].name(), *unlit.texture}; } make_id_slot(unlit.texture, "Texture", name.c_str(), {true}); @@ -57,12 +57,13 @@ void ResourceInspector::view(StaticMesh const& mesh, Id id) const { } void ResourceInspector::edit(Material& out_material, Id id) const { - auto const name = FixedString<128>{"{} ({})", out_material.name, id}; + auto const name = FixedString<128>{"{} ({})", out_material.name(), id}; auto tn = TreeNode{name.c_str()}; drag_payload(id, name.c_str()); if (tn) { - if (auto* lit = dynamic_cast(&out_material)) { return edit_material(m_target, m_resources, *lit); } - if (auto* unlit = dynamic_cast(&out_material)) { return edit_material(m_resources, *unlit); } + auto& mat = out_material.base(); + if (auto* lit = dynamic_cast(&mat)) { return edit_material(m_target, m_resources, *lit); } + if (auto* unlit = dynamic_cast(&mat)) { return edit_material(m_resources, *unlit); } } } @@ -78,7 +79,7 @@ void ResourceInspector::edit(Mesh& out_mesh, Id id) const { make_id_slot(primitive.static_mesh, "Static Mesh", name.c_str()); name = {}; - if (primitive.material) { name = FixedString<128>{"{} ({})", m_resources.materials[*primitive.material]->name, *primitive.material}; } + if (primitive.material) { name = FixedString<128>{"{} ({})", m_resources.materials[*primitive.material].name(), *primitive.material}; } make_id_slot(primitive.material, "Material", name.c_str(), {true}); if (small_button_red("x###remove_primitive")) { to_erase = index; } @@ -95,46 +96,54 @@ void ResourceInspector::edit(Mesh& out_mesh, Id id) const { } } -void SceneInspector::resources(std::string& out_name_buf) const { +void SceneInspector::resources(Data& out_data) const { auto const ri = ResourceInspector{m_target, m_scene}; static constexpr auto flags_v = ImGuiTreeNodeFlags_Framed; bool add_material{}, add_mesh{}; if (auto tn = TreeNode("Textures", flags_v)) { - for (auto [texture, id] : enumerate(m_resources.textures)) { ri.view(texture, id); } + for (auto [texture, id] : enumerate(m_resources.textures.view())) { ri.view(texture, id); } } if (auto tn = TreeNode("Static Meshes", flags_v)) { - for (auto [static_mesh, id] : enumerate(m_resources.static_meshes)) { ri.view(static_mesh, id); } + for (auto [static_mesh, id] : enumerate(m_resources.static_meshes.view())) { ri.view(static_mesh, id); } } if (auto tn = TreeNode("Materials", flags_v)) { - for (auto [material, id] : enumerate(m_resources.materials)) { ri.edit(*material, id); } + for (auto [material, id] : enumerate(m_resources.materials.view())) { ri.edit(material, id); } if (ImGui::Button("Add...")) { add_material = true; } } if (auto tn = TreeNode{"Meshes", flags_v}) { - for (auto [mesh, id] : enumerate(m_resources.meshes)) { ri.edit(mesh, id); } + for (auto [mesh, id] : enumerate(m_resources.meshes.view())) { ri.edit(mesh, id); } if (ImGui::Button("Add...")) { add_mesh = true; } } if (add_material) { Popup::open("Add Material"); } + if (out_data.input_buffer.empty()) { out_data.input_buffer.resize(128, '\0'); } + + if (auto popup = Popup{"Add Mesh"}) { + ImGui::InputText("Name", out_data.input_buffer.data(), out_data.input_buffer.size()); + if (ImGui::Button("Add") && *out_data.input_buffer.c_str()) { + m_scene.add(Mesh{.name = out_data.input_buffer.c_str()}); + Popup::close_current(); + } + } + if (add_mesh) { Popup::open("Add Mesh"); } - if (out_name_buf.empty()) { out_name_buf.resize(128, '\0'); } - auto open_popup = [&out_name_buf](char const* id, auto func) { - if (auto popup = Popup{id}) { - ImGui::InputText("Name", out_name_buf.data(), out_name_buf.size()); - if (ImGui::Button(id)) { - auto str = out_name_buf.c_str(); - if (!*str) { return; } - func(str); - Popup::close_current(); + if (auto popup = Popup{"Add Material"}) { + ImGui::InputText("Name", out_data.input_buffer.data(), out_data.input_buffer.size()); + static constexpr char const* mat_types_v[] = {"Lit", "Unlit"}; + static constexpr auto mat_types_size_v{static_cast(std::size(mat_types_v))}; + char const* mat_type = out_data.material_type >= 0 && out_data.material_type < mat_types_size_v ? mat_types_v[out_data.material_type] : "Invalid"; + ImGui::SliderInt("Type", &out_data.material_type, 0, mat_types_size_v - 1, mat_type); + if (ImGui::Button("Add") && *out_data.input_buffer.c_str()) { + auto mat = std::unique_ptr{}; + switch (out_data.material_type) { + case 0: mat = std::make_unique(); break; + case 1: mat = std::make_unique(); break; } + mat->name = out_data.input_buffer.c_str(); + m_scene.add(Material{std::move(mat)}); + Popup::close_current(); } - }; - auto push_material = [this](std::string name) { - auto mat = std::make_unique(); - mat->name = std::move(name); - m_scene.add(std::move(mat)); - }; - open_popup("Add Material", [&push_material](char const* name) { push_material(name); }); - open_popup("Add Mesh", [this](char const* name) { m_scene.add(Mesh{.name = name}); }); + } } void SceneInspector::camera() const { @@ -218,7 +227,7 @@ void SceneInspector::mesh(Node& out_node) const { auto* mesh_id = out_node.find>(); if (auto tn = TreeNode{"Mesh", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Framed}) { auto name = FixedString<128>{}; - if (mesh_id) { name = FixedString<128>{"{} ({})", m_scene.find(*mesh_id)->name, *mesh_id}; } + if (mesh_id) { name = FixedString<128>{"{} ({})", m_resources.meshes.find(*mesh_id)->name, *mesh_id}; } make_id_slot(out_node, "Mesh", name.c_str()); } } diff --git a/lib/engine/src/scene_renderer.cpp b/lib/engine/src/scene_renderer.cpp index 535a2bd..d61b853 100644 --- a/lib/engine/src/scene_renderer.cpp +++ b/lib/engine/src/scene_renderer.cpp @@ -90,17 +90,17 @@ std::span SceneRenderer::make_instances(Node const& node, glm } void SceneRenderer::render(Renderer& renderer, vk::CommandBuffer cb, Node const& node, glm::mat4 const& parent) { - auto const resources = m_scene->resources(); + auto const& resources = m_scene->resources(); if (auto const* mesh_id = node.find>()) { - static auto const s_default_material = LitMaterial{}; + static auto const s_default_material = Material{std::make_unique()}; auto const& mesh = resources.meshes[*mesh_id]; for (auto const& primitive : mesh.primitives) { - auto const& material = primitive.material ? *resources.materials[primitive.material->value()] : static_cast(s_default_material); + auto const& material = primitive.material ? resources.materials[primitive.material->value()] : static_cast(s_default_material); auto pipeline = renderer.bind_pipeline(cb, m_scene->pipeline_state, material.shader_id()); pipeline.set_line_width(m_scene->pipeline_state.line_width); update_view(pipeline); - auto const store = TextureStore{resources.textures, m_white, m_black}; + auto const store = TextureStore{resources.textures.view(), m_white, m_black}; material.write_sets(pipeline, store); auto const& static_mesh = resources.static_meshes[primitive.static_mesh]; diff --git a/lib/scene/CMakeLists.txt b/lib/scene/CMakeLists.txt index 574fa13..a0011a0 100644 --- a/lib/scene/CMakeLists.txt +++ b/lib/scene/CMakeLists.txt @@ -43,6 +43,7 @@ target_sources(${PROJECT_NAME} PRIVATE include/${target_prefix}/scene/mesh.hpp include/${target_prefix}/scene/node_data.hpp include/${target_prefix}/scene/node.hpp + include/${target_prefix}/scene/resource_array.hpp include/${target_prefix}/scene/scene_resources.hpp include/${target_prefix}/scene/scene.hpp diff --git a/lib/scene/include/facade/scene/material.hpp b/lib/scene/include/facade/scene/material.hpp index 8390fb4..d592f1a 100644 --- a/lib/scene/include/facade/scene/material.hpp +++ b/lib/scene/include/facade/scene/material.hpp @@ -39,27 +39,18 @@ struct TextureStore { }; /// -/// \brief Base Material: stores render parameters for a mesh. +/// \brief Base class for concrete materials. /// -class Material { +class MaterialBase { public: /// - /// \brief The alpha blend mode. + /// \brief Alpha blend mode. /// enum class AlphaMode : std::uint32_t { eOpaque = 0, eBlend, eMask }; - /// - /// \brief Convert sRGB encoded colour to linear. - /// - static glm::vec4 to_linear(glm::vec4 const& srgb); - /// - /// \brief Convert linear encoded colour to sRGB. - /// - static glm::vec4 to_srgb(glm::vec4 const& linear); - inline static std::string const default_shader_id{"default"}; - virtual ~Material() = default; + virtual ~MaterialBase() = default; /// /// \brief Obtain the ID for the shader used by this material. @@ -73,13 +64,46 @@ class Material { /// virtual void write_sets(Pipeline& pipeline, TextureStore const& store) const = 0; + /// + /// \brief Name of this instance. + /// std::string name{"(Unnamed)"}; }; +/// +/// \brief Value-semantic strategy wrapper for concrete materials. +/// +class Material { + public: + using AlphaMode = MaterialBase::AlphaMode; + + Material(std::unique_ptr&& base) : m_base(std::move(base)) {} + + std::string const& shader_id() const { + assert(m_base); + return m_base->shader_id(); + } + + void write_sets(Pipeline& pipeline, TextureStore const& store) const { + assert(m_base); + m_base->write_sets(pipeline, store); + } + + std::string_view name() const { return m_base->name; } + + MaterialBase& base() const { + assert(m_base); + return *m_base; + } + + private: + std::unique_ptr m_base; +}; + /// /// \brief Unlit Material. /// -class UnlitMaterial : public Material { +class UnlitMaterial : public MaterialBase { public: inline static std::string const shader_id_v{"unlit"}; @@ -99,7 +123,7 @@ class UnlitMaterial : public Material { /// /// \brief PBR lit material. /// -class LitMaterial : public Material { +class LitMaterial : public MaterialBase { public: /// /// \brief Base colour factor. diff --git a/lib/scene/include/facade/scene/resource_array.hpp b/lib/scene/include/facade/scene/resource_array.hpp new file mode 100644 index 0000000..d1a0007 --- /dev/null +++ b/lib/scene/include/facade/scene/resource_array.hpp @@ -0,0 +1,82 @@ +#pragma once +#include +#include +#include +#include +#include + +namespace facade { +/// +/// \brief Wrapper over an array of resources, each identified by the index as its Id. +/// +/// Only Scene has access to the underlying vector (via friend). Other types can operate +/// on const / non-const spans, but cannot modify the array itself. +/// +template +class ResourceArray { + public: + /// + /// \brief Obtain an immutable view into the underlying array. + /// \returns Immutable span + /// + std::span view() const { return m_array; } + /// + /// \brief Obtain a mutable view into the underlying array. + /// \returns Mutable span + /// + std::span view() { return m_array; } + + /// + /// \brief Obtain an immutable pointer to the element at index id. + /// \param id Id (index) of element + /// \returns nullptr if id is out of bounds + /// + Ptr find(Id id) const { + if (id >= m_array.size()) { return {}; } + return &m_array[id]; + } + + /// + /// \brief Obtain a mutable pointer to the element at index id. + /// \param id Id (index) of element + /// \returns nullptr if id is out of bounds + /// + Ptr find(Id index) { return const_cast>(std::as_const(*this).find(index)); } + + /// + /// \brief Obtain an immutable reference to the element at index id. + /// \param id Id (index) of element + /// \returns const reference to element + /// + /// id must be valid / in range + /// + T const& operator[](Id id) const { + auto ret = find(id); + assert(ret); + return *ret; + } + + /// + /// \brief Obtain an immutable reference to the element at index id. + /// \param id Id (index) of element + /// \returns const reference to element + /// + /// id must be valid / in range + /// + T& operator[](Id index) { return const_cast(std::as_const(*this).operator[](index)); } + + /// + /// \brief Obtain the size of the underlying array. + /// + constexpr std::size_t size() const { return m_array.size(); } + /// + /// \brief Check if the underlying array is empty. + /// + constexpr bool empty() const { return m_array.empty(); } + + private: + std::vector m_array{}; + + friend class Scene; +}; +} // namespace facade diff --git a/lib/scene/include/facade/scene/scene.hpp b/lib/scene/include/facade/scene/scene.hpp index a832e73..a0b36ae 100644 --- a/lib/scene/include/facade/scene/scene.hpp +++ b/lib/scene/include/facade/scene/scene.hpp @@ -24,7 +24,6 @@ struct DataProvider; class Scene { public: using Resources = SceneResources; - using ResourcesMut = SceneResourcesMut; // defined in loader.hpp class GltfLoader; @@ -66,7 +65,7 @@ class Scene { /// \param material Concrete Material instance to add /// \returns Id to stored Material /// - Id add(std::unique_ptr material); + Id add(Material material); /// /// \brief Add a StaticMesh. /// \param geometry Geometry to initialize StaticMesh with @@ -94,6 +93,23 @@ class Scene { /// Id add(Node node, Id parent); + /// + /// \brief Replace all textures in resources. + /// \param textures Texture instances to swap in + /// \returns Previously stored textures + /// + /// Intended for loaders. + /// + std::vector replace(std::vector&& textures); + /// + /// \brief Replace all static meshes in resources. + /// \param static_meshes StaticMesh instances to swap in + /// \returns Previously stored static meshes + /// + /// Intended for loaders. + /// + std::vector replace(std::vector&& static_meshes); + /// /// \brief Obtain the current Tree Id. /// \returns Current Tree Id @@ -123,37 +139,6 @@ class Scene { /// \returns nullptr if Node with id wasn't found /// Ptr find(Id id); - /// - /// \brief Obtain a mutable pointer to the Material corresponding to its Id. - /// \param id Id of the Material - /// \returns nullptr if id is invalid (out of bounds) - /// - Ptr find(Id id) const; - /// - /// \brief Obtain an immutable pointer to the StaticMesh corresponding to its Id. - /// \param id Id of the StaticMesh - /// \returns nullptr if id is invalid (out of bounds) - /// - Ptr find(Id id) const; - /// - /// \brief Obtain an immutable pointer to the Texture corresponding to its Id. - /// \param id Id of the Texture - /// \returns nullptr if id is invalid (out of bounds) - /// - Ptr find(Id id) const; - /// - /// \brief Obtain a mutable pointer to the Mesh corresponding to its Id. - /// \param id Id of the Mesh - /// \returns nullptr if id is invalid (out of bounds) - /// - Ptr find(Id id); - /// - /// \brief Obtain a mutable pointer to the Camera corresponding to its Id. - /// \param id Id of the Camera - /// \returns nullptr if id is invalid (out of bounds) - /// - Ptr find(Id id); - /// /// \brief Obtain a mutable view into all the root nodes attached to the active Tree. /// \returns Mutable view into the root nodes attached to the active Tree @@ -169,7 +154,7 @@ class Scene { /// \brief Obtain the total count of stored cameras. /// \returns Count of stored cameras (at least 1) /// - std::size_t camera_count() const { return m_storage.cameras.size(); } + std::size_t camera_count() const { return m_storage.resources.cameras.size(); } /// /// \brief Select a Camera by its Id. /// \param id Id of Camera to select @@ -198,11 +183,15 @@ class Scene { Texture make_texture(Image::View image) const; /// - /// \brief Obtain a view into the stored resources. - /// \returns A Resources object + /// \brief Obtain a mutable reference to the scene's resources. + /// \returns Mutable reference to SceneResources + /// + Resources& resources() { return m_storage.resources; } + /// + /// \brief Obtain an immutable reference to the scene's resources. + /// \returns Immutable reference to SceneResources /// - ResourcesMut resources() { return m_storage.resources(); } - Resources resources() const { return m_storage.resources(); } + Resources const& resources() const { return m_storage.resources; } /// /// \brief All the lights in the scene. @@ -233,17 +222,8 @@ class Scene { }; struct Storage { - std::vector cameras{}; - std::vector samplers{}; - std::vector> materials{}; - std::vector static_meshes{}; - std::vector textures{}; - std::vector meshes{}; - + Resources resources{}; Data data{}; - - ResourcesMut resources() { return {cameras, samplers, materials, static_meshes, textures, meshes}; } - Resources resources() const { return {cameras, samplers, materials, static_meshes, textures, meshes}; } }; void add_default_camera(); diff --git a/lib/scene/include/facade/scene/scene_resources.hpp b/lib/scene/include/facade/scene/scene_resources.hpp index 925bc18..8f7c053 100644 --- a/lib/scene/include/facade/scene/scene_resources.hpp +++ b/lib/scene/include/facade/scene/scene_resources.hpp @@ -2,29 +2,20 @@ #include #include #include +#include #include #include -#include namespace facade { /// -/// \brief View of the resources stored in the scene. +/// \brief Collection of all ResourceArray instances used by Scene. /// -template -struct TSceneResources { - template - using View = std::conditional_t, std::span>; - - View cameras{}; - View samplers{}; - View> materials{}; - View static_meshes{}; - View textures{}; - View meshes{}; - - operator TSceneResources() const { return {cameras, samplers, materials, static_meshes, textures, meshes}; } +struct SceneResources { + ResourceArray cameras{}; + ResourceArray samplers{}; + ResourceArray materials{}; + ResourceArray static_meshes{}; + ResourceArray textures{}; + ResourceArray meshes{}; }; - -using SceneResources = TSceneResources; -using SceneResourcesMut = TSceneResources; } // namespace facade diff --git a/lib/scene/src/gltf_loader.cpp b/lib/scene/src/gltf_loader.cpp index f6fb2a3..f97b3e9 100644 --- a/lib/scene/src/gltf_loader.cpp +++ b/lib/scene/src/gltf_loader.cpp @@ -51,7 +51,7 @@ Sampler::CreateInfo to_sampler_info(gltf::Sampler const& sampler) { return ret; } -std::unique_ptr to_material(gltf::Material const& material) { +Material to_material(gltf::Material const& material) { auto ret = std::make_unique(); ret->albedo = material.pbr.base_colour_factor; ret->metallic = material.pbr.metallic_factor; @@ -62,7 +62,7 @@ std::unique_ptr to_material(gltf::Material const& material) { ret->roughness_metallic = material.pbr.metallic_roughness_texture->texture; ret->emissive = material.emissive_texture->texture; ret->emissive_factor = material.emissive_factor; - return ret; + return {std::move(ret)}; } Mesh to_mesh(gltf::Mesh mesh) { @@ -137,8 +137,8 @@ bool Scene::GltfLoader::operator()(dj::Json const& root, DataProvider const& pro for (auto const& sampler : asset.samplers) { m_scene.add(to_sampler_info(sampler)); } auto get_sampler = [this](std::optional sampler_id) { - if (!sampler_id || sampler_id >= m_scene.m_storage.samplers.size()) { return m_scene.default_sampler(); } - return m_scene.m_storage.samplers[*sampler_id].sampler(); + if (!sampler_id || sampler_id >= m_scene.m_storage.resources.samplers.size()) { return m_scene.default_sampler(); } + return m_scene.m_storage.resources.samplers[*sampler_id].sampler(); }; auto textures = std::vector>{}; @@ -157,8 +157,8 @@ bool Scene::GltfLoader::operator()(dj::Json const& root, DataProvider const& pro static_meshes.push_back(make_maybe_future(thread_pool, m_status.done, [g = std::move(geometry), this] { return StaticMesh{m_scene.m_gfx, g}; })); } - m_scene.m_storage.textures = from_maybe_futures(std::move(textures)); - m_scene.m_storage.static_meshes = from_maybe_futures(std::move(static_meshes)); + m_scene.replace(from_maybe_futures(std::move(textures))); + m_scene.replace(from_maybe_futures(std::move(static_meshes))); m_status.stage = LoadStage::eBuildingScenes; if (asset.cameras.empty()) { diff --git a/lib/scene/src/material.cpp b/lib/scene/src/material.cpp index 0701c96..93e239d 100644 --- a/lib/scene/src/material.cpp +++ b/lib/scene/src/material.cpp @@ -16,6 +16,8 @@ float bit_cast_f(Material::AlphaMode const mode) { std::memcpy(&ret, &mode, sizeof(mode)); return ret; } + +glm::vec4 to_linear(glm::vec4 const& srgb) { return glm::convertSRGBToLinear(srgb); } } // namespace Texture const& TextureStore::get(std::optional const index, Texture const& fallback) const { @@ -23,9 +25,6 @@ Texture const& TextureStore::get(std::optional const index, Texture return textures[*index]; } -glm::vec4 Material::to_linear(glm::vec4 const& srgb) { return glm::convertSRGBToLinear(srgb); } -glm::vec4 Material::to_srgb(glm::vec4 const& linear) { return glm::convertLinearToSRGB(linear); } - void UnlitMaterial::write_sets(Pipeline& pipeline, TextureStore const& store) const { auto& set1 = pipeline.next_set(1); set1.update(0, store.get(texture).descriptor_image()); diff --git a/lib/scene/src/scene.cpp b/lib/scene/src/scene.cpp index 7c30892..d252a20 100644 --- a/lib/scene/src/scene.cpp +++ b/lib/scene/src/scene.cpp @@ -69,7 +69,7 @@ struct Scene::TreeBuilder { ret.camera = *camera; } else { // add node with default camera - assert(!out_scene.m_storage.cameras.empty()); + assert(!out_scene.m_storage.resources.cameras.empty()); auto node = Node{}; node.name = "camera"; // TODO @@ -84,39 +84,39 @@ struct Scene::TreeBuilder { Scene::Scene(Gfx const& gfx) : m_gfx(gfx), m_sampler(gfx) { add_default_camera(); } Id Scene::add(Camera camera) { - auto const id = m_storage.cameras.size(); - m_storage.cameras.push_back(std::move(camera)); + auto const id = m_storage.resources.cameras.size(); + m_storage.resources.cameras.m_array.push_back(std::move(camera)); return id; } Id Scene::add(Sampler::CreateInfo const& create_info) { - auto const id = m_storage.samplers.size(); - m_storage.samplers.emplace_back(m_gfx, create_info); + auto const id = m_storage.resources.samplers.size(); + m_storage.resources.samplers.m_array.emplace_back(m_gfx, create_info); return id; } -Id Scene::add(std::unique_ptr material) { - auto const id = m_storage.materials.size(); - m_storage.materials.push_back(std::move(material)); +Id Scene::add(Material material) { + auto const id = m_storage.resources.materials.size(); + m_storage.resources.materials.m_array.push_back(std::move(material)); return id; } Id Scene::add(Geometry const& geometry, std::string name) { - auto const id = m_storage.static_meshes.size(); - m_storage.static_meshes.emplace_back(m_gfx, geometry, std::move(name)); + auto const id = m_storage.resources.static_meshes.size(); + m_storage.resources.static_meshes.m_array.emplace_back(m_gfx, geometry, std::move(name)); return id; } Id Scene::add(Image::View image, Id sampler_id, ColourSpace colour_space) { auto sampler = [&] { - if (sampler_id >= m_storage.samplers.size()) { + if (sampler_id >= m_storage.resources.samplers.size()) { logger::warn("[Scene] Invalid sampler id: [{}], using default", sampler_id.value()); return default_sampler(); } - return m_storage.samplers[sampler_id].sampler(); + return m_storage.resources.samplers[sampler_id].sampler(); }(); - auto const ret = m_storage.textures.size(); - m_storage.textures.emplace_back(m_gfx, sampler, image, Texture::CreateInfo{.colour_space = colour_space}); + auto const ret = m_storage.resources.textures.size(); + m_storage.resources.textures.m_array.emplace_back(m_gfx, sampler, image, Texture::CreateInfo{.colour_space = colour_space}); return ret; } @@ -132,6 +132,12 @@ Id Scene::add(Node node, Id parent) { throw Error{fmt::format("Scene {}: Invalid parent Node Id: {}", m_name, parent)}; } +std::vector Scene::replace(std::vector&& textures) { return std::exchange(m_storage.resources.textures.m_array, std::move(textures)); } + +std::vector Scene::replace(std::vector&& static_meshes) { + return std::exchange(m_storage.resources.static_meshes.m_array, std::move(static_meshes)); +} + bool Scene::load(Id id) { if (id >= tree_count()) { return false; } return load_tree(id); @@ -140,12 +146,6 @@ bool Scene::load(Id id) { Ptr Scene::find(Id id) { return const_cast(std::as_const(*this).find_node(m_tree.roots, id)); } Ptr Scene::find(Id id) const { return find_node(m_tree.roots, id); } -Ptr Scene::find(Id id) const { return id >= m_storage.materials.size() ? nullptr : m_storage.materials[id].get(); } -Ptr Scene::find(Id id) const { return id >= m_storage.static_meshes.size() ? nullptr : &m_storage.static_meshes[id]; } -Ptr Scene::find(Id id) const { return id >= m_storage.textures.size() ? nullptr : &m_storage.textures[id]; } -Ptr Scene::find(Id id) { return id >= m_storage.meshes.size() ? nullptr : &m_storage.meshes[id]; } -Ptr Scene::find(Id id) { return id >= m_storage.cameras.size() ? nullptr : &m_storage.cameras[id]; } - bool Scene::select(Id id) { if (id >= camera_count()) { return false; } *camera().find>() = id; @@ -163,7 +163,7 @@ Node const& Scene::camera() const { Texture Scene::make_texture(Image::View image) const { return Texture{m_gfx, default_sampler(), image}; } void Scene::add_default_camera() { - m_storage.cameras.push_back(Camera{.name = "default"}); + m_storage.resources.cameras.m_array.push_back(Camera{.name = "default"}); auto node = Node{}; node.name = "camera"; node.attach>(0); @@ -177,8 +177,8 @@ bool Scene::load_tree(Id id) { } Id Scene::add_unchecked(Mesh mesh) { - auto const id = m_storage.meshes.size(); - m_storage.meshes.push_back(std::move(mesh)); + auto const id = m_storage.resources.meshes.size(); + m_storage.resources.meshes.m_array.push_back(std::move(mesh)); return id; } @@ -200,20 +200,20 @@ Node const* Scene::find_node(std::span nodes, Id id) { void Scene::check(Mesh const& mesh) const noexcept(false) { for (auto const& primitive : mesh.primitives) { - if (primitive.static_mesh >= m_storage.static_meshes.size()) { + if (primitive.static_mesh >= m_storage.resources.static_meshes.size()) { throw Error{fmt::format("Scene {}: Invalid Static Mesh Id: {}", m_name, primitive.static_mesh)}; } - if (primitive.material && primitive.material->value() >= m_storage.materials.size()) { + if (primitive.material && primitive.material->value() >= m_storage.resources.materials.size()) { throw Error{fmt::format("Scene {}: Invalid Material Id: {}", m_name, *primitive.material)}; } } } void Scene::check(Node const& node) const noexcept(false) { - if (auto const* mesh_id = node.find>(); mesh_id && *mesh_id >= m_storage.meshes.size()) { + if (auto const* mesh_id = node.find>(); mesh_id && *mesh_id >= m_storage.resources.meshes.size()) { throw Error{fmt::format("Scene {}: Invalid mesh [{}] in node", m_name, *mesh_id)}; } - if (auto const* camera_id = node.find>(); camera_id && *camera_id >= m_storage.cameras.size()) { + if (auto const* camera_id = node.find>(); camera_id && *camera_id >= m_storage.resources.cameras.size()) { throw Error{fmt::format("Scene {}: Invalid camera [{}] in node", m_name, *camera_id)}; } for (auto const& child : node.m_children) { check(child); } diff --git a/src/gui/main_menu.cpp b/src/gui/main_menu.cpp index 66cc3bf..f18c31e 100644 --- a/src/gui/main_menu.cpp +++ b/src/gui/main_menu.cpp @@ -118,7 +118,7 @@ bool WindowMenu::display_log() { bool WindowMenu::display_resources(Scene& scene) { bool show{true}; ImGui::SetNextWindowSize({400.0f, 300.0f}, ImGuiCond_FirstUseEver); - if (auto window = editor::Window{"Resources", &show}) { editor::SceneInspector{window, scene}.resources(m_data.name_buf); } + if (auto window = editor::Window{"Resources", &show}) { editor::SceneInspector{window, scene}.resources(m_data.inspect_data); } return show; } diff --git a/src/gui/main_menu.hpp b/src/gui/main_menu.hpp index a2b8974..99c1438 100644 --- a/src/gui/main_menu.hpp +++ b/src/gui/main_menu.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include #include @@ -45,7 +46,7 @@ class WindowMenu : public logger::Accessor { struct { editor::LogState log_state{}; editor::InspectNode inspect{}; - std::string name_buf{}; + editor::InspectData inspect_data{}; Bool unified_scaling{true}; } m_data{}; struct { diff --git a/src/main.cpp b/src/main.cpp index 178fdfb..e8d86d8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -61,7 +61,7 @@ void run(AppOpts const& opts) { auto material = std::make_unique(); material->albedo = {1.0f, 0.0f, 0.0f}; - auto material_id = scene.add(std::move(material)); + auto material_id = scene.add(Material{std::move(material)}); auto static_mesh_id = scene.add(make_cubed_sphere(1.0f, 32)); // auto static_mesh_id = scene.add(make_manipulator(0.125f, 1.0f, 16)); auto mesh_id = scene.add(Mesh{.primitives = {Mesh::Primitive{static_mesh_id, material_id}}});