diff --git a/Tetragrama/CMakeLists.txt b/Tetragrama/CMakeLists.txt
index 521c366d..e8e64d2b 100644
--- a/Tetragrama/CMakeLists.txt
+++ b/Tetragrama/CMakeLists.txt
@@ -45,6 +45,7 @@ target_include_directories (${TARGET_NAME}
./Helpers
./Importers
./Serializers
+ ./Managers
${ENLISTMENT_ROOT}/ZEngine
)
diff --git a/Tetragrama/Components/DockspaceUIComponent.cpp b/Tetragrama/Components/DockspaceUIComponent.cpp
index babb4246..b84884a8 100644
--- a/Tetragrama/Components/DockspaceUIComponent.cpp
+++ b/Tetragrama/Components/DockspaceUIComponent.cpp
@@ -15,11 +15,15 @@ using namespace ZEngine::Helpers;
namespace Tetragrama::Components
{
- ImVec4 DockspaceUIComponent::s_asset_importer_report_msg_color = {1, 1, 1, 1};
- char DockspaceUIComponent::s_asset_importer_input_buffer[1024] = {0};
- char DockspaceUIComponent::s_save_as_input_buffer[1024] = {0};
- std::string DockspaceUIComponent::s_asset_importer_report_msg = "";
- float DockspaceUIComponent::s_editor_scene_serializer_progress = 0.0f;
+ ImVec4 DockspaceUIComponent::s_asset_importer_report_msg_color = {1, 1, 1, 1};
+ char DockspaceUIComponent::s_asset_importer_input_buffer[1024] = {0};
+ char DockspaceUIComponent::s_save_as_input_buffer[1024] = {0};
+ std::string DockspaceUIComponent::s_asset_importer_report_msg = "";
+ float DockspaceUIComponent::s_editor_scene_serializer_progress = 0.0f;
+
+ static bool s_is_scene_loading = false;
+ static char s_scene_serializer_log[DEFAULT_STR_BUFFER] = {0};
+ static ImVec4 s_scene_serializer_log_color = {1, 1, 1, 1};
DockspaceUIComponent::DockspaceUIComponent() {}
@@ -29,35 +33,30 @@ namespace Tetragrama::Components
{
UIComponent::Initialize(parent, name, visibility, closed);
+ parent->LayerArena.CreateSubArena(ZMega(10), &LocalArena);
+
m_asset_importer = ZPushStructCtor(&(parent->LayerArena), Importers::AssimpImporter);
m_editor_serializer = ZPushStructCtor(&(parent->LayerArena), Serializers::EditorSceneSerializer);
m_editor_serializer->Initialize(&(parent->LayerArena));
m_asset_importer->Initialize(&(parent->LayerArena));
- m_editor_serializer->AssetImporter = m_asset_importer;
-
- m_dockspace_node_flag = ImGuiDockNodeFlags_NoWindowMenuButton | ImGuiDockNodeFlags_PassthruCentralNode;
- m_window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
-
- auto context = reinterpret_cast(ParentLayer->ParentContext);
- m_editor_serializer->Context = context;
- m_asset_importer->Context = context;
+ m_dockspace_node_flag = ImGuiDockNodeFlags_NoWindowMenuButton | ImGuiDockNodeFlags_PassthruCentralNode;
+ m_window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
- const auto& editor_config = *context->ConfigurationPtr;
+ auto context = reinterpret_cast(ParentLayer->ParentContext);
+ m_editor_serializer->Context = context;
+ m_asset_importer->Context = context;
- m_default_import_configuration = {};
- m_default_import_configuration.OutputWorkingSpacePath.init(&(parent->LayerArena), editor_config.WorkingSpacePath.c_str());
- m_default_import_configuration.OutputModelFilePath.init(&(parent->LayerArena), editor_config.SceneDataPath.c_str());
- m_default_import_configuration.OutputMeshFilePath.init(&(parent->LayerArena), editor_config.SceneDataPath.c_str());
- m_default_import_configuration.OutputMaterialsPath.init(&(parent->LayerArena), editor_config.SceneDataPath.c_str());
- m_default_import_configuration.OutputTextureFilesPath.init(&(parent->LayerArena), editor_config.DefaultImportTexturePath.c_str());
+ const auto& editor_config = *context->ConfigurationPtr;
- auto editor_serializer_default_output = fmt::format("{0}{1}{2}", editor_config.WorkingSpacePath.c_str(), PLATFORM_OS_BACKSLASH, editor_config.ScenePath.c_str());
+ auto editor_serializer_default_output = fmt::format("{0}{1}{2}", editor_config.WorkingSpacePath.c_str(), PLATFORM_OS_BACKSLASH, editor_config.ScenePath.c_str());
m_editor_serializer->SetDefaultOutput(editor_serializer_default_output);
m_editor_serializer->SetOnProgressCallback(OnEditorSceneSerializerProgress);
+ m_editor_serializer->SetOnCompleteCallback(OnEditorSceneSerializerComplete);
m_editor_serializer->SetOnDeserializeCompleteCallback(OnEditorSceneSerializerDeserializeComplete);
+ m_editor_serializer->SetOnLogCallback(OnEditorSceneSerializerLog);
m_editor_serializer->SetOnErrorCallback(OnEditorSceneSerializerError);
m_asset_importer->SetOnCompleteCallback(OnAssetImporterComplete);
@@ -118,19 +117,22 @@ namespace Tetragrama::Components
}
RenderMenuBar();
- RenderImporter();
- RenderExitPopup();
+ RenderLoadScene();
RenderSaveScene();
RenderSaveSceneAs();
+ RenderImporter();
+
+ RenderExitPopup();
+
ImGui::End();
auto ctx = reinterpret_cast(ParentLayer->ParentContext);
- if (ctx->CurrentScenePtr && ctx->CurrentScenePtr->RenderScene->IsDrawDataDirty)
- {
- ctx->CurrentScenePtr->RenderScene->InitOrResetDrawBuffer(renderer->Device, renderer->RenderGraph, renderer->AsyncLoader);
- }
+ // if (ctx->CurrentScenePtr && ctx->CurrentScenePtr->RenderScene->IsDrawDataDirty)
+ //{
+ // ctx->CurrentScenePtr->RenderScene->InitOrResetDrawBuffer(renderer->Device, renderer->RenderGraph, renderer->AsyncLoader);
+ // }
}
void DockspaceUIComponent::RenderImporter()
@@ -145,84 +147,117 @@ namespace Tetragrama::Components
return;
}
+ const char* str_id = "Model Importer";
+ ImGui::OpenPopup(str_id);
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
ImGui::SetNextWindowPos(center, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::SetNextWindowSize(ImVec2(700, 100), ImGuiCond_Always);
- if (!ImGui::Begin("Model Importer", NULL, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse))
- {
- ImGui::End();
- return;
- }
-
bool is_import_button_enabled = !m_asset_importer->IsImporting();
- ImGui::PushItemWidth(620);
- ImGui::InputText("##ModelImporterUI", s_asset_importer_input_buffer, IM_ARRAYSIZE(s_asset_importer_input_buffer), ImGuiInputTextFlags_ReadOnly);
- ImGui::PopItemWidth();
-
- ImGui::SameLine();
-
- if (ImGui::Button("...", ImVec2(50, 0)) && is_import_button_enabled)
+ if (ImGui::BeginPopupModal(str_id, NULL, ImGuiWindowFlags_AlwaysAutoResize))
{
- Helpers::UIDispatcher::RunAsync([this]() -> std::future {
- if (ParentLayer && ParentLayer->ParentWindow)
- {
- auto window = ParentLayer->ParentWindow;
- std::vector filters{".obj", ".gltf"};
- std::string filename = co_await window->OpenFileDialogAsync(filters);
+ ImGui::PushItemWidth(620);
+ ImGui::InputText("##ModelImporterUI", s_asset_importer_input_buffer, IM_ARRAYSIZE(s_asset_importer_input_buffer), ImGuiInputTextFlags_ReadOnly);
+ ImGui::PopItemWidth();
- if (!filename.empty())
+ ImGui::SameLine();
+
+ if (ImGui::Button("...", ImVec2(50, 0)) && is_import_button_enabled)
+ {
+ Helpers::UIDispatcher::RunAsync([this]() -> std::future {
+ if (ParentLayer && ParentLayer->ParentWindow)
{
- ZEngine::Helpers::secure_memset(s_asset_importer_input_buffer, 0, IM_ARRAYSIZE(s_asset_importer_input_buffer), IM_ARRAYSIZE(s_asset_importer_input_buffer));
- ZEngine::Helpers::secure_memcpy(s_asset_importer_input_buffer, IM_ARRAYSIZE(s_asset_importer_input_buffer), filename.c_str(), filename.size());
- }
- }
- });
- }
+ auto window = ParentLayer->ParentWindow;
+ std::vector filters{".obj", ".gltf"};
+ std::string filename = co_await window->OpenFileDialogAsync(filters);
- ImGui::Separator();
+ if (!filename.empty())
+ {
+ ZEngine::Helpers::secure_memset(s_asset_importer_input_buffer, 0, IM_ARRAYSIZE(s_asset_importer_input_buffer), IM_ARRAYSIZE(s_asset_importer_input_buffer));
+ ZEngine::Helpers::secure_memcpy(s_asset_importer_input_buffer, IM_ARRAYSIZE(s_asset_importer_input_buffer), filename.c_str(), filename.size());
+ }
+ }
+ });
+ }
- ImGui::SetCursorPosX(ImGui::GetWindowSize().x - 180);
- ImGui::SetCursorPosY(ImGui::GetWindowSize().y - ImGui::GetFrameHeightWithSpacing() - 5);
+ ImGui::Separator();
- if (!is_import_button_enabled || std::string_view(s_asset_importer_input_buffer).empty())
- {
- ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.5f, 0.5f, 0.5f, 1.0f)); // Grayed out color
- ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.5f, 0.5f, 0.5f, 1.0f));
- ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.5f, 0.5f, 0.5f, 1.0f));
- }
+ ImGui::SetCursorPosX(ImGui::GetWindowSize().x - 180);
+ ImGui::SetCursorPosY(ImGui::GetWindowSize().y - ImGui::GetFrameHeightWithSpacing() - 5);
- if (ImGui::Button("Launch", ImVec2(80, 0)) && is_import_button_enabled)
- {
- Helpers::UIDispatcher::RunAsync([this] { OnImportAssetAsync(s_asset_importer_input_buffer); });
- }
+ if (!is_import_button_enabled || std::string_view(s_asset_importer_input_buffer).empty())
+ {
+ ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.5f, 0.5f, 0.5f, 1.0f)); // Grayed out color
+ ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.5f, 0.5f, 0.5f, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.5f, 0.5f, 0.5f, 1.0f));
+ }
- if (!is_import_button_enabled || std::string_view(s_asset_importer_input_buffer).empty())
- {
- ImGui::PopStyleColor(3); // Pop the grayed out color
- }
+ if (ImGui::Button("Launch", ImVec2(80, 0)) && is_import_button_enabled)
+ {
+ OnImportAssetAsync(s_asset_importer_input_buffer);
+ }
- ImGui::SameLine();
- if (ImGui::Button("Close", ImVec2(80, 0)))
- {
- if (m_asset_importer->IsImporting())
+ if (!is_import_button_enabled || std::string_view(s_asset_importer_input_buffer).empty())
{
- ZENGINE_CORE_WARN("Import in progress : {}", s_asset_importer_input_buffer)
+ ImGui::PopStyleColor(3); // Pop the grayed out color
}
- else
+
+ ImGui::SameLine();
+ if (ImGui::Button("Close", ImVec2(80, 0)))
{
- m_open_asset_importer = false;
- ResetImporterBuffers();
+ if (m_asset_importer->IsImporting())
+ {
+ ZENGINE_CORE_WARN("Import in progress : {}", s_asset_importer_input_buffer)
+ }
+ else
+ {
+ m_open_asset_importer = false;
+ ResetImporterBuffers();
+ ImGui::CloseCurrentPopup();
+ }
}
+
+ ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[0]);
+ ImGui::SetCursorPos(ImVec2(10, ImGui::GetWindowSize().y - 30));
+ ImGui::TextColored(s_asset_importer_report_msg_color, s_asset_importer_report_msg.c_str());
+ ImGui::PopFont();
+
+ ImGui::EndPopup();
}
+ }
- ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[0]);
- ImGui::SetCursorPos(ImVec2(10, ImGui::GetWindowSize().y - 30));
- ImGui::TextColored(s_asset_importer_report_msg_color, s_asset_importer_report_msg.c_str());
- ImGui::PopFont();
+ void DockspaceUIComponent::RenderLoadScene()
+ {
+ if (!s_is_scene_loading)
+ {
+ return;
+ }
- ImGui::End();
+ const char* str_id = "Loading Scene";
+ ImGui::OpenPopup(str_id);
+ ImVec2 center = ImGui::GetMainViewport()->GetCenter();
+ ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
+ ImGui::SetNextWindowSize(ImVec2(700, 100), ImGuiCond_Always);
+
+ if (ImGui::BeginPopupModal(str_id, NULL, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize))
+ {
+ // Calculate position for the progress bar
+ ImVec2 wind_size = ImGui::GetWindowSize();
+ ImVec2 reg_available = ImGui::GetContentRegionAvail();
+ ImVec2 progress_bar_pos = ImVec2((wind_size.x - reg_available.x) * 0.5f, (wind_size.y - reg_available.y));
+
+ // Display the progress bar
+ ImGui::SetCursorPos(progress_bar_pos);
+ ImGui::ProgressBar(s_editor_scene_serializer_progress, ImVec2(reg_available.x, 20.0f), " ");
+
+ ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[0]);
+ ImGui::SetCursorPos(ImVec2(10, wind_size.y - 30));
+ ImGui::TextColored(s_scene_serializer_log_color, s_scene_serializer_log);
+ ImGui::PopFont();
+
+ ImGui::EndPopup();
+ }
}
void DockspaceUIComponent::RenderSaveScene()
@@ -400,16 +435,17 @@ namespace Tetragrama::Components
ZEngine::Helpers::secure_memset(s_save_as_input_buffer, 0, IM_ARRAYSIZE(s_save_as_input_buffer), IM_ARRAYSIZE(s_save_as_input_buffer));
}
- void DockspaceUIComponent::OnAssetImporterComplete(void* const context, Importers::ImporterData&& data)
+ void DockspaceUIComponent::OnAssetImporterComplete(void* const context, ZEngine::Core::Containers::ArrayView result)
{
+ auto ctx = reinterpret_cast(context);
+
+ for (unsigned i = 0; i < result.size(); ++i)
+ {
+ ctx->CurrentScenePtr->PushAssetFile(result[i]);
+ }
+
s_asset_importer_report_msg_color = {0.0f, 1.0f, 0.0f, 1.0f};
s_asset_importer_report_msg = "Completed";
-
- auto context_ptr = reinterpret_cast(context);
- /*
- * Removing the WorkingSpace Path
- */
- context_ptr->CurrentScenePtr->Push(&(context_ptr->Arena), data.SerializedMeshesPath.c_str(), data.SerializedModelPath.c_str(), data.SerializedMaterialsPath.c_str());
}
void DockspaceUIComponent::OnAssetImporterProgress(void* const context, float value)
@@ -429,6 +465,11 @@ namespace Tetragrama::Components
ZENGINE_CORE_ERROR("{}", msg)
}
+ void DockspaceUIComponent::OnEditorSceneSerializerLog(void* const, std::string_view msg)
+ {
+ ZEngine::Helpers::secure_strcpy(s_scene_serializer_log, DEFAULT_STR_BUFFER, msg.data());
+ }
+
void DockspaceUIComponent::OnAssetImporterLog(void* const, std::string_view msg)
{
s_asset_importer_report_msg_color = {1.0f, 1.0f, 1.0f, 1.0f};
@@ -492,25 +533,37 @@ namespace Tetragrama::Components
s_editor_scene_serializer_progress = value;
}
- void DockspaceUIComponent::OnEditorSceneSerializerComplete(void* const) {}
+ void DockspaceUIComponent::OnEditorSceneSerializerComplete(void* const context)
+ {
+ auto ctx = reinterpret_cast(context);
+ ctx->CurrentScenePtr->HasPendingChanges.store(false, std::memory_order_release);
+ }
void DockspaceUIComponent::OnEditorSceneSerializerDeserializeComplete(void* const context, EditorScene&& scene)
{
auto ctx = reinterpret_cast(context);
// Todo : Ensure no data race on CurrentScenePtr
- ctx->ConfigurationPtr->ActiveSceneName.reserve(ZEngine::Helpers::secure_strlen(scene.Name));
ctx->ConfigurationPtr->ActiveSceneName.clear();
ctx->ConfigurationPtr->ActiveSceneName.append(scene.Name);
- ctx->CurrentScenePtr->Name = ctx->ConfigurationPtr->ActiveSceneName.c_str();
- ctx->CurrentScenePtr->Data = scene.Data;
- ctx->CurrentScenePtr->MeshFiles = scene.MeshFiles;
- ctx->CurrentScenePtr->ModelFiles = scene.ModelFiles;
- ctx->CurrentScenePtr->MaterialFiles = scene.MaterialFiles;
- ctx->CurrentScenePtr->RenderScene = scene.RenderScene;
+ ctx->CurrentScenePtr->MarkDirty(true);
+ ctx->SelectedSceneNode.store(-1, std::memory_order_release);
+ ctx->CurrentScenePtr->Reset();
+ ctx->CurrentScenePtr->ExtractAsync(scene);
+
+ ctx->CurrentScenePtr->Name = ctx->ConfigurationPtr->ActiveSceneName.c_str();
+
+ ctx->CurrentScenePtr->MarkDirty(false);
+
+ {
+ auto msg = fmt::format("Scene {} deserialized successfully", ctx->CurrentScenePtr->Name);
+ ZEngine::Helpers::secure_strcpy(s_scene_serializer_log, DEFAULT_STR_BUFFER, msg.data());
+
+ ZENGINE_CORE_INFO("{}", msg.c_str())
+ }
- ZENGINE_CORE_INFO("Scene {} deserialized successfully", ctx->CurrentScenePtr->Name)
+ s_is_scene_loading = false;
}
std::future DockspaceUIComponent::OnNewSceneAsync()
@@ -528,24 +581,38 @@ namespace Tetragrama::Components
if (!scene_filename.empty())
{
+ s_is_scene_loading = true;
m_editor_serializer->Deserialize(scene_filename);
}
}
co_return;
}
- std::future DockspaceUIComponent::OnImportAssetAsync(std::string_view filename)
+ std::future DockspaceUIComponent::OnImportAssetAsync(const char* filename)
{
- if (!filename.empty())
+ if (ZEngine::Helpers::secure_strlen(filename) == 0)
{
- auto parent_path = std::filesystem::path(filename).parent_path().string();
- auto asset_name = fs::path(filename).filename().replace_extension().string();
- auto import_config = m_default_import_configuration;
- import_config.AssetFilename.init(&(ParentLayer->LayerArena), asset_name.c_str());
- import_config.InputBaseAssetFilePath.init(&(ParentLayer->LayerArena), parent_path.c_str());
- co_await m_asset_importer->ImportAsync(filename, import_config);
+ co_return;
}
- co_return;
+
+ LocalArena.Clear();
+
+ auto context = reinterpret_cast(ParentLayer->ParentContext);
+ auto arena = &LocalArena;
+ const auto& editor_config = *context->ConfigurationPtr;
+ auto parent_path = std::filesystem::path(filename).parent_path().string();
+ auto asset_name = fs::path(filename).filename().replace_extension().string();
+ auto output_asset_file = fmt::format("{}.zemesh", asset_name.c_str());
+
+ Importers::ImportConfiguration config = {};
+ config.OutputWorkingSpacePath.init(arena, editor_config.WorkingSpacePath.c_str());
+ config.OutputTextureFilesPath.init(arena, editor_config.DefaultImportTexturePath.c_str());
+ config.OutputAssetsPath.init(arena, editor_config.SceneDataPath.c_str());
+ config.AssetName.init(arena, asset_name.c_str());
+ config.OutputAssetFile.init(arena, output_asset_file.c_str());
+ config.InputBaseAssetFilePath.init(arena, parent_path.c_str());
+
+ co_await m_asset_importer->ImportAsync(filename, config);
}
std::future DockspaceUIComponent::OnExitAsync()
diff --git a/Tetragrama/Components/DockspaceUIComponent.h b/Tetragrama/Components/DockspaceUIComponent.h
index 879264c4..db19cbc8 100644
--- a/Tetragrama/Components/DockspaceUIComponent.h
+++ b/Tetragrama/Components/DockspaceUIComponent.h
@@ -13,39 +13,43 @@ namespace Tetragrama::Components
DockspaceUIComponent();
virtual ~DockspaceUIComponent();
- void Initialize(Layers::ImguiLayer* parent = nullptr, const char* name = "Dockspace", bool visibility = true, bool closed = false) override;
+ ZEngine::Core::Memory::ArenaAllocator LocalArena = {};
- void Update(ZEngine::Core::TimeStep dt) override;
- virtual void Render(ZEngine::Rendering::Renderers::GraphicRenderer* const renderer, ZEngine::Hardwares::CommandBuffer* const command_buffer) override;
+ void Initialize(Layers::ImguiLayer* parent = nullptr, const char* name = "Dockspace", bool visibility = true, bool closed = false) override;
- void RenderMenuBar();
- void RenderSaveScene();
- void RenderSaveSceneAs();
- void ResetSaveAsBuffers();
- void RenderExitPopup();
+ void Update(ZEngine::Core::TimeStep dt) override;
+ virtual void Render(ZEngine::Rendering::Renderers::GraphicRenderer* const renderer, ZEngine::Hardwares::CommandBuffer* const command_buffer) override;
+
+ void RenderMenuBar();
+ void ResetSaveAsBuffers();
+ void RenderExitPopup();
/*
* Model Importer Funcs
*/
- void RenderImporter();
- void ResetImporterBuffers();
- static void OnAssetImporterComplete(void* const, Importers::ImporterData&&);
- static void OnAssetImporterProgress(void* const, float value);
- static void OnAssetImporterError(void* const, std::string_view);
- static void OnAssetImporterLog(void* const, std::string_view);
+ void RenderImporter();
+ void ResetImporterBuffers();
+ static void OnAssetImporterComplete(void* const context, ZEngine::Core::Containers::ArrayView result);
+ static void OnAssetImporterProgress(void* const, float value);
+ static void OnAssetImporterError(void* const, std::string_view);
+ static void OnAssetImporterLog(void* const, std::string_view);
/*
* Editor Scene Funcs
*/
- static void OnEditorSceneSerializerProgress(void* const, float value);
- static void OnEditorSceneSerializerComplete(void* const);
- static void OnEditorSceneSerializerDeserializeComplete(void* const, EditorScene&&);
- static void OnEditorSceneSerializerError(void* const, std::string_view);
+ void RenderLoadScene();
+ void RenderSaveScene();
+ void RenderSaveSceneAs();
+ static void OnEditorSceneSerializerProgress(void* const, float value);
+ static void OnEditorSceneSerializerComplete(void* const);
+ static void OnEditorSceneSerializerDeserializeComplete(void* const, EditorScene&&);
+ static void OnEditorSceneSerializerError(void* const, std::string_view);
+ static void OnEditorSceneSerializerLog(void* const, std::string_view);
- std::future OnNewSceneAsync();
- std::future OnOpenSceneAsync();
- std::future OnImportAssetAsync(std::string_view filename);
- std::future OnExitAsync();
+ std::future OnNewSceneAsync();
+ std::future OnOpenSceneAsync();
+ std::future OnImportAssetAsync(const char* filename);
+ std::future OnExitAsync();
private:
static ImVec4 s_asset_importer_report_msg_color;
diff --git a/Tetragrama/Components/HierarchyViewUIComponent.cpp b/Tetragrama/Components/HierarchyViewUIComponent.cpp
index dc8281d8..46fa4b2a 100644
--- a/Tetragrama/Components/HierarchyViewUIComponent.cpp
+++ b/Tetragrama/Components/HierarchyViewUIComponent.cpp
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
using namespace ZEngine;
using namespace ZEngine::Helpers;
@@ -58,15 +59,15 @@ namespace Tetragrama::Components
void HierarchyViewUIComponent::Render(ZEngine::Rendering::Renderers::GraphicRenderer* const renderer, ZEngine::Hardwares::CommandBuffer* const command_buffer)
{
- auto ctx = reinterpret_cast(ParentLayer->ParentContext);
- auto render_scene = ctx->CurrentScenePtr->RenderScene;
+ auto ctx = reinterpret_cast(ParentLayer->ParentContext);
+ auto current_scene = ctx->CurrentScenePtr;
ImGui::Begin(Name, (CanBeClosed ? &CanBeClosed : NULL), ImGuiWindowFlags_NoCollapse);
if (ImGui::BeginPopupContextWindow(Name))
{
if (ImGui::MenuItem("Create Empty"))
{
- render_scene->CreateEntityAsync();
+ current_scene->CreateSceneNode();
}
ImGui::EndPopup();
}
@@ -76,8 +77,8 @@ namespace Tetragrama::Components
// 0 means left buttom
if (ImGui::IsMouseDown(0) && ImGui::IsWindowHovered())
{
- m_selected_node_identifier = -1;
- Messengers::IMessenger::SendAsync(EDITOR_COMPONENT_HIERARCHYVIEW_NODE_UNSELECTED, Messengers::EmptyMessage{});
+ ctx->SelectedSceneNode.store(-1, std::memory_order_release);
+ // Messengers::IMessenger::SendAsync(EDITOR_COMPONENT_HIERARCHYVIEW_NODE_UNSELECTED, Messengers::EmptyMessage{});
}
RenderGuizmo();
@@ -87,27 +88,38 @@ namespace Tetragrama::Components
void HierarchyViewUIComponent::RenderTreeNodes()
{
- auto ctx = reinterpret_cast(ParentLayer->ParentContext);
- auto render_scene = ctx->CurrentScenePtr->RenderScene;
+ auto ctx = reinterpret_cast(ParentLayer->ParentContext);
+ auto current_scene = ctx->CurrentScenePtr;
- auto root_nodes = render_scene->GetRootSceneNodes();
+ if (current_scene->IsDirty())
+ {
+ return;
+ }
- for (int node : root_nodes)
+ for (int i = 0; i < (int) current_scene->Hierarchies.size(); ++i)
{
- RenderSceneNodeTree(node);
+ if (!current_scene->IsSceneNodeDeleted(i) && current_scene->Hierarchies[i].Parent == -1)
+ {
+ RenderNode(current_scene, i, ctx->SelectedSceneNode);
+ }
}
}
void HierarchyViewUIComponent::RenderGuizmo()
{
- if (m_selected_node_identifier <= -1)
+ auto ctx = reinterpret_cast(ParentLayer->ParentContext);
+ auto current_scene = ctx->CurrentScenePtr;
+
+ if (current_scene->IsDirty())
{
return;
}
- // auto entity_wrapper = GraphicScene::GetSceneNodeEntityWrapper(m_selected_node_identifier);
- auto ctx = reinterpret_cast(ParentLayer->ParentContext);
- auto render_scene = ctx->CurrentScenePtr->RenderScene;
+ int selected_node = ctx->SelectedSceneNode.load(std::memory_order_acquire);
+ if (selected_node == -1)
+ {
+ return;
+ }
if (auto active_editor_camera = ctx->CameraControllerPtr)
{
@@ -115,9 +127,9 @@ namespace Tetragrama::Components
const auto camera_projection = camera->GetPerspectiveMatrix();
const auto camera_view_matrix = camera->GetViewMatrix();
- auto& global_transform = render_scene->GetSceneNodeGlobalTransform(m_selected_node_identifier);
+ auto& global_transform = current_scene->GlobalTransforms[selected_node];
auto initial_transform = global_transform;
- auto& local_transform = render_scene->GetSceneNodeLocalTransform(m_selected_node_identifier);
+ auto& local_transform = current_scene->LocalTransforms[selected_node];
if (camera && IDevice::As()->IsKeyPressed(ZENGINE_KEY_F, Engine::GetWindow()))
{
@@ -140,7 +152,7 @@ namespace Tetragrama::Components
auto delta_transform = glm::inverse(initial_transform) * global_transform;
local_transform = local_transform * delta_transform;
- render_scene->MarkSceneNodeAsChanged(m_selected_node_identifier);
+ // current_scene->MarkSceneNodeAsChanged(m_selected_node_identifier);
if (ImGuizmo::IsUsing())
{
@@ -154,72 +166,139 @@ namespace Tetragrama::Components
}
}
- void HierarchyViewUIComponent::RenderSceneNodeTree(int node_identifier)
+ void HierarchyViewUIComponent::RenderNode(EditorScene* scene, int root_id, std::atomic_int& selected_node)
{
- if (node_identifier < 0)
+ struct StackEntry
{
- return;
- }
+ int node_id;
+ bool open;
+ };
- auto ctx = reinterpret_cast(ParentLayer->ParentContext);
- auto render_scene = ctx->CurrentScenePtr->RenderScene;
+ std::stack stack;
+ stack.push({root_id, false});
- const auto& node_hierarchy = render_scene->GetSceneNodeHierarchy(node_identifier);
- auto node_name = render_scene->GetSceneNodeName(node_identifier);
- auto node_identifier_string = fmt::format("SceneNode_{0}", node_identifier);
- auto flags = (node_hierarchy.FirstChild < 0) ? (ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | m_node_flag) : m_node_flag;
- flags |= (m_selected_node_identifier == node_identifier) ? ImGuiTreeNodeFlags_Selected : 0;
- auto label = (!node_name.empty()) ? std::string(node_name) : fmt::format("Node_{0}", node_identifier);
- bool is_node_opened = ImGui::TreeNodeEx(node_identifier_string.c_str(), flags, "%s", label.c_str());
-
- if (ImGui::IsItemClicked())
+ while (!stack.empty())
{
- m_selected_node_identifier = node_identifier;
+ auto entry = stack.top();
+ stack.pop();
- auto entity = render_scene->GetSceneNodeEntityWrapper(m_selected_node_identifier);
- Messengers::IMessenger::SendAsync>(EDITOR_COMPONENT_HIERARCHYVIEW_NODE_SELECTED, Messengers::GenericMessage{std::move(entity)});
- }
+ // Handle manual TreePop marker
+ if (entry.node_id == -1)
+ {
+ ImGui::TreePop();
+ continue;
+ }
- if (is_node_opened)
- {
- /*
- * Popup features
- */
- bool request_entity_removal = false;
- if (ImGui::BeginPopupContextItem(node_identifier_string.c_str()))
+ if (scene->IsSceneNodeDeleted(entry.node_id))
+ {
+ continue;
+ }
+ const auto& node = scene->Hierarchies[entry.node_id];
+
+ auto name_id = scene->NodeNames[entry.node_id];
+
+ bool is_selected = (selected_node == entry.node_id);
+ bool has_children = (node.FirstChild != -1);
+
+ ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_SpanFullWidth;
+ if (!has_children)
+ flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen;
+ if (is_selected)
+ flags |= ImGuiTreeNodeFlags_Selected;
+
+ auto node_id = fmt::format("SceneNode_{0}", entry.node_id);
+ bool open = ImGui::TreeNodeEx(node_id.c_str(), flags, "%s", scene->Names[name_id].c_str());
+
+ if (ImGui::IsItemClicked(ImGuiMouseButton_Left))
+ {
+ selected_node.store(entry.node_id, std::memory_order_release);
+ }
+
+ // === Drag source ===
+ if (ImGui::BeginDragDropSource())
+ {
+ ImGui::SetDragDropPayload("NODE_DRAG", &entry.node_id, sizeof(int));
+ ImGui::EndDragDropSource();
+ }
+
+ // === Drop target ===
+ if (ImGui::BeginDragDropTarget())
+ {
+ if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("NODE_DRAG"))
+ {
+ int dragged_id = *(const int*) payload->Data;
+ if (dragged_id != entry.node_id && !scene->IsSceneNodeDeleted(dragged_id))
+ {
+ // prevent making it a child of itself or its descendants
+ int test = entry.node_id;
+ bool is_descendant = false;
+ while (test != -1)
+ {
+ if (test == dragged_id)
+ {
+ is_descendant = true;
+ break;
+ }
+ test = scene->Hierarchies[test].Parent;
+ }
+
+ if (!is_descendant)
+ {
+ scene->ReparentNode(dragged_id, entry.node_id);
+ }
+ }
+ }
+ ImGui::EndDragDropTarget();
+ }
+
+ if (ImGui::BeginPopupContextItem(node_id.c_str()))
{
if (ImGui::MenuItem("Create Empty child"))
{
- render_scene->CreateEntityAsync("Empty Entity", m_selected_node_identifier, node_hierarchy.DepthLevel + 1);
+ scene->CreateSceneNode(entry.node_id, node.DepthLevel + 1);
}
if (ImGui::MenuItem("Rename"))
{
}
+
if (ImGui::MenuItem("Delete"))
{
- Messengers::IMessenger::SendAsync(EDITOR_COMPONENT_HIERARCHYVIEW_NODE_DELETED, Messengers::EmptyMessage{});
- request_entity_removal = true;
+ scene->RemoveSceneNode(entry.node_id);
}
ImGui::EndPopup();
}
- if (request_entity_removal)
+ if (open && has_children)
{
- render_scene->RemoveNodeAsync(node_identifier);
- }
+ // Push TreePop manually
+ stack.push({-1, 0}); // Marker for TreePop
- if (node_hierarchy.FirstChild > -1)
- {
- auto sibling_scene_node_collection = render_scene->GetSceneNodeSiblingCollection(node_hierarchy.FirstChild);
- // We consider first child as sibling node
- sibling_scene_node_collection.emplace(std::begin(sibling_scene_node_collection), node_hierarchy.FirstChild);
- for (auto sibling_identifier : sibling_scene_node_collection)
+ // Push children in reverse order
+ auto scratch = ZGetScratch(&ParentLayer->LayerArena);
+ ZEngine::Core::Containers::Array children;
+ children.init(scratch.Arena, 5);
+
+ for (int child = node.FirstChild; child != -1; child = scene->Hierarchies[child].RightSibling)
{
- RenderSceneNodeTree(sibling_identifier);
+ if (!scene->IsSceneNodeDeleted(child))
+ {
+ children.push(child);
+ }
}
+
+ for (int i = static_cast(children.size()) - 1; i >= 0; --i)
+ {
+ stack.push({children[i], false});
+ }
+
+ ZReleaseScratch(scratch);
+ }
+ else if (!has_children && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
+ {
+ // Only pop if not marked as Leaf
+ ImGui::TreePop();
}
- ImGui::TreePop();
}
}
} // namespace Tetragrama::Components
diff --git a/Tetragrama/Components/HierarchyViewUIComponent.h b/Tetragrama/Components/HierarchyViewUIComponent.h
index 5b2054c4..2817dcbd 100644
--- a/Tetragrama/Components/HierarchyViewUIComponent.h
+++ b/Tetragrama/Components/HierarchyViewUIComponent.h
@@ -22,12 +22,11 @@ namespace Tetragrama::Components
void RenderTreeNodes();
void RenderGuizmo();
- void RenderSceneNodeTree(int node_identifier);
+ void RenderNode(EditorScene* scene, int root_id, std::atomic_int& selected);
private:
ImGuiTreeNodeFlags m_node_flag;
bool m_is_node_opened{false};
- int m_selected_node_identifier{-1};
int m_gizmo_operation{-1};
};
} // namespace Tetragrama::Components
diff --git a/Tetragrama/Editor.cpp b/Tetragrama/Editor.cpp
index 85bd44ba..4e000c67 100644
--- a/Tetragrama/Editor.cpp
+++ b/Tetragrama/Editor.cpp
@@ -12,15 +12,19 @@ using namespace ZEngine::Helpers;
using namespace Tetragrama::Layers;
using namespace Tetragrama::Messengers;
using namespace Tetragrama::Controllers;
+using namespace Tetragrama::Managers;
namespace Tetragrama
{
void Editor::Initialize(ArenaAllocator* arena, const char* file)
{
+ AssetManager::Initialize(arena);
+
Context = ZPushStruct(arena, EditorContext);
- arena->CreateSubArena(ZMega(50), &(Context->Arena));
+ arena->CreateSubArena(ZMega(800), &(Context->Arena));
+ Context->AssetManagerPtr = AssetManager::Instance();
Context->ConfigurationPtr = ZPushStructCtor(&(Context->Arena), EditorConfiguration);
Context->CameraControllerPtr = ZPushStructCtor(&(Context->Arena), EditorCameraController);
UILayer = ZPushStructCtor(&(Context->Arena), ImguiLayer);
@@ -28,7 +32,7 @@ namespace Tetragrama
Context->CurrentScenePtr = ZPushStructCtor(&(Context->Arena), EditorScene);
- if (Helpers::secure_strlen(file))
+ if (ZEngine::Helpers::secure_strlen(file))
{
Context->ConfigurationPtr->ReadConfig(arena, file);
@@ -59,61 +63,14 @@ namespace Tetragrama
void Editor::Dispose()
{
- ZEngine::Engine::Dispose();
+ Engine::Dispose();
+ AssetManager::Shutdown();
}
void Editor::Run()
{
- ZEngine::Engine::Run();
- }
-
- void EditorScene::Initialize(ZEngine::Core::Memory::ArenaAllocator* arena, const char* name)
- {
- Name = name;
-
- RenderScene = ZPushStructCtor(arena, ZEngine::Rendering::Scenes::GraphicScene);
- RenderScene->IsDrawDataDirty = true;
-
- MeshFiles.init(arena, 1);
- ModelFiles.init(arena, 1);
- MaterialFiles.init(arena, 1);
- Hashes.init(arena, 1);
- }
-
- void EditorScene::Push(ZEngine::Core::Memory::ArenaAllocator* arena, const char* mesh, const char* model, const char* material)
- {
- uint16_t mesh_file_id = MeshFiles.size();
- uint16_t model_file_id = ModelFiles.size();
- uint16_t material_file_id = MaterialFiles.size();
-
- String mesh_file = {};
- String model_file = {};
- String mat_file = {};
-
- mesh_file.init(arena, mesh);
- model_file.init(arena, model);
- mat_file.init(arena, material);
-
- MeshFiles.push(mesh_file);
- ModelFiles.push(model_file);
- MaterialFiles.push(mat_file);
-
- std::stringstream ss;
- ss << mesh_file_id << ":" << model_file_id << ":" << material_file_id;
- auto hash = ss.str();
-
- String hash_str = {};
- hash_str.init(arena, hash.c_str());
- Hashes.push(hash_str);
-
- Data[hash_str.c_str()] = {.MeshFileIndex = mesh_file_id, .ModelPathIndex = model_file_id, .MaterialPathIndex = material_file_id};
-
- m_has_pending_change = true;
- }
-
- bool EditorScene::HasPendingChange() const
- {
- return m_has_pending_change;
+ AssetManager::Run();
+ Engine::Run();
}
void EditorConfiguration::ReadConfig(ZEngine::Core::Memory::ArenaAllocator* arena, const char* file)
diff --git a/Tetragrama/Editor.h b/Tetragrama/Editor.h
index 4be89633..3ccae214 100644
--- a/Tetragrama/Editor.h
+++ b/Tetragrama/Editor.h
@@ -1,5 +1,8 @@
#pragma once
+#include
#include
+#include
+#include
#include
#include
#include
@@ -16,38 +19,6 @@ namespace Tetragrama::Serializers
namespace Tetragrama
{
- class EditorScene
- {
- public:
- struct Model;
-
- EditorScene() = default;
-
- void Initialize(ZEngine::Core::Memory::ArenaAllocator* arena, const char* scene_name = "");
- void Push(ZEngine::Core::Memory::ArenaAllocator* arena, const char* mesh, const char* model, const char* material);
- bool HasPendingChange() const;
-
- const char* Name = "";
- ZEngine::Core::Containers::Array MeshFiles = {};
- ZEngine::Core::Containers::Array ModelFiles = {};
- ZEngine::Core::Containers::Array MaterialFiles = {};
-
- ZEngine::Core::Containers::Array Hashes = {};
- std::map Data = {};
-
- ZRawPtr(ZEngine::Rendering::Scenes::GraphicScene) RenderScene = nullptr;
-
- private:
- std::atomic_bool m_has_pending_change;
- friend struct Serializers::EditorSceneSerializer;
- };
-
- struct EditorScene::Model
- {
- uint16_t MeshFileIndex = 0xFFFF;
- uint16_t ModelPathIndex = 0xFFFF;
- uint16_t MaterialPathIndex = 0xFFFF;
- };
struct EditorConfiguration
{
@@ -65,9 +36,11 @@ namespace Tetragrama
struct EditorContext
{
ZEngine::Core::Memory::ArenaAllocator Arena = {};
+ std::atomic_int SelectedSceneNode = -1;
ZRawPtr(EditorConfiguration) ConfigurationPtr = nullptr;
ZRawPtr(EditorScene) CurrentScenePtr = nullptr;
ZRawPtr(Controllers::EditorCameraController) CameraControllerPtr = nullptr;
+ ZRawPtr(Managers::AssetManager) AssetManagerPtr = nullptr;
};
struct Editor
diff --git a/Tetragrama/EditorScene.cpp b/Tetragrama/EditorScene.cpp
new file mode 100644
index 00000000..0394a7e4
--- /dev/null
+++ b/Tetragrama/EditorScene.cpp
@@ -0,0 +1,324 @@
+#include
+#include
+#include
+#include
+
+namespace Tetragrama
+{
+ void EditorScene::Initialize(ZEngine::Core::Memory::ArenaAllocator* arena, const char* name)
+ {
+ arena->CreateSubArena(ZMega(200), &LocalArena);
+
+ Name = name;
+
+ AssetFiles.init(&LocalArena, 500);
+ HashToAssetFile.init(&LocalArena, 500);
+
+ Hierarchies.init(&LocalArena, 1000);
+ Names.init(&LocalArena, 1000);
+ LocalTransforms.init(&LocalArena, 1000);
+ GlobalTransforms.init(&LocalArena, 1000);
+ NodeMeshes.init(&LocalArena, 1000);
+ NodeNames.init(&LocalArena, 1000);
+
+ /*
+ * Root Scene node
+ */
+ Reset();
+
+ InitRootNode();
+
+ RenderScene = ZPushStructCtor(&LocalArena, ZEngine::Rendering::Scenes::GraphicScene);
+ RenderScene->IsDrawDataDirty = true;
+ }
+
+ bool EditorScene::HasPendingChange() const
+ {
+ return HasPendingChanges.load(std::memory_order_acquire);
+ }
+
+ int EditorScene::AddHierarchyNode(int parent, int depth)
+ {
+ if (depth < 0)
+ {
+ return -1;
+ }
+
+ int node_id = static_cast(Hierarchies.size());
+
+ // Create new node
+ EditorSceneNodeHierarchy new_node = {};
+ new_node.Parent = parent;
+ new_node.DepthLevel = depth;
+
+ Hierarchies.push(new_node);
+ LocalTransforms.push(glm::mat4(1.0f));
+ GlobalTransforms.push(glm::mat4(1.0f));
+
+ if (parent >= 0)
+ {
+ auto& parent_node = Hierarchies[parent];
+
+ if (parent_node.FirstChild == -1)
+ {
+ // First child
+ parent_node.FirstChild = node_id;
+ parent_node.LastChild = node_id;
+ }
+ else
+ {
+ // Append to last child's sibling list in O(1)
+ Hierarchies[parent_node.LastChild].RightSibling = node_id;
+ parent_node.LastChild = node_id;
+ }
+ }
+
+ HasPendingChanges.store(true, std::memory_order_release);
+
+ return node_id;
+ }
+
+ void EditorScene::CreateSceneNode(int parent, int depth)
+ {
+ int node_id = AddHierarchyNode(parent, depth);
+ if (node_id < 0)
+ {
+ ZENGINE_CORE_ERROR("EditorScene::CreateSceneNode, failed to create scene node")
+ return;
+ }
+
+ NodeNames[node_id] = Names.size();
+ auto& name = Names.push_use({});
+ name.init(&LocalArena, "Empty entity");
+
+ NodeMeshes.insert(node_id, uuids::uuid{});
+
+ HasPendingChanges.store(true, std::memory_order_release);
+ }
+
+ void EditorScene::RemoveSceneNode(int node_id)
+ {
+ if (node_id < 0 || node_id >= static_cast(Hierarchies.size()))
+ return;
+
+ if (IsSceneNodeDeleted(node_id))
+ return;
+
+ auto& node = Hierarchies[node_id];
+
+ // Unlink from parent's child list
+ if (node.Parent >= 0)
+ {
+ auto& parent = Hierarchies[node.Parent];
+ int prev = -1;
+ int current = parent.FirstChild;
+
+ while (current != -1)
+ {
+ if (current == node_id)
+ {
+ if (prev == -1)
+ parent.FirstChild = node.RightSibling;
+ else
+ Hierarchies[prev].RightSibling = node.RightSibling;
+ break;
+ }
+
+ prev = current;
+ current = Hierarchies[current].RightSibling;
+ }
+ }
+
+ std::stack to_delete;
+ to_delete.push(node_id);
+
+ while (!to_delete.empty())
+ {
+ int current_id = to_delete.top();
+ to_delete.pop();
+
+ auto& current_node = Hierarchies[current_id];
+
+ // Push children to delete stack
+ int child = current_node.FirstChild;
+ while (child != -1)
+ {
+ int next_sibling = Hierarchies[child].RightSibling;
+ to_delete.push(child);
+ child = next_sibling;
+ }
+
+ // Mark as deleted
+ current_node.Parent = -2;
+ current_node.FirstChild = -1;
+ current_node.RightSibling = -1;
+ current_node.DepthLevel = -1;
+
+ Names[current_id].clear();
+ Names[current_id].append("(deleted)");
+ }
+
+ HasPendingChanges.store(true, std::memory_order_release);
+ }
+
+ void EditorScene::ReparentNode(int node_id, int new_parent)
+ {
+ auto& node = Hierarchies[node_id];
+ int old_parent = node.Parent;
+
+ // unlink from old parent
+ if (old_parent >= 0)
+ {
+ auto& parent = Hierarchies[old_parent];
+ int prev = -1;
+ int current = parent.FirstChild;
+
+ while (current != -1)
+ {
+ if (current == node_id)
+ {
+ if (prev == -1)
+ parent.FirstChild = node.RightSibling;
+ else
+ Hierarchies[prev].RightSibling = node.RightSibling;
+ break;
+ }
+
+ prev = current;
+ current = Hierarchies[current].RightSibling;
+ }
+ }
+
+ // link to new parent
+ node.Parent = new_parent;
+ node.RightSibling = Hierarchies[new_parent].FirstChild;
+ Hierarchies[new_parent].FirstChild = node_id;
+ node.DepthLevel = Hierarchies[new_parent].DepthLevel + 1;
+ }
+
+ bool EditorScene::IsSceneNodeDeleted(int node)
+ {
+ if (node < 0)
+ {
+ return true;
+ }
+ return Hierarchies[node].Parent == -2;
+ }
+
+ void EditorScene::PushAssetFile(const Importers::AssetImporterOutput& data)
+ {
+ if (data.Type == Importers::AssetFileType::UNKNOWN)
+ {
+ return;
+ }
+
+ EditorAssetSceneFiles asset_file = {};
+ asset_file.Type = data.Type;
+ asset_file.Hash = ZEngine::Core::Containers::hash_compute(data.Path.c_str());
+ asset_file.Path.init(&(LocalArena), data.Path.c_str());
+ asset_file.RootPath.init(&(LocalArena), data.RootPath.c_str());
+
+ if (HashToAssetFile.contains(asset_file.Hash))
+ {
+ ZENGINE_CORE_WARN("Asset file already exist at that location : {}", asset_file.Path.c_str())
+ return;
+ }
+
+ auto index = AssetFiles.size();
+ AssetFiles.push(asset_file);
+ HashToAssetFile.insert(asset_file.Hash, index);
+
+ HasPendingChanges.store(true, std::memory_order_release);
+ }
+
+ void EditorScene::MarkDirty(bool value)
+ {
+ Dirty.store(value, std::memory_order_release);
+ }
+
+ bool EditorScene::IsDirty()
+ {
+ return Dirty.load(std::memory_order_acquire);
+ }
+
+ void EditorScene::Reset()
+ {
+ AssetFiles.clear();
+ HashToAssetFile.clear();
+
+ Hierarchies.clear();
+ Names.clear();
+ LocalTransforms.clear();
+ GlobalTransforms.clear();
+ NodeMeshes.clear();
+ NodeNames.clear();
+
+ Dirty.store(false, std::memory_order_release);
+ }
+
+ void EditorScene::InitRootNode()
+ {
+ NodeNames.insert(0, 0);
+ auto& root_name = Names.push_use({});
+ root_name.init(&LocalArena, Name);
+
+ LocalTransforms.push(glm::mat4(1.0f));
+ GlobalTransforms.push(glm::mat4(1.0f));
+
+ auto& node = Hierarchies.push_use(EditorSceneNodeHierarchy{});
+ node.DepthLevel = 0;
+ NodeMeshes.insert(0, uuids::uuid{});
+ }
+
+ void EditorScene::ExtractAsync(EditorScene& scene)
+ {
+ for (const auto& file : scene.AssetFiles)
+ {
+ auto& f = AssetFiles.push_use({});
+ f.Hash = file.Hash;
+ f.Type = file.Type;
+ f.Path.init(&(LocalArena), file.Path.c_str());
+ f.RootPath.init(&(LocalArena), file.RootPath.c_str());
+ }
+
+ for (const auto& name : scene.Names)
+ {
+ auto& n = Names.push_use({});
+ n.init(&(LocalArena), name.c_str());
+ }
+
+ for (const auto& h : scene.Hierarchies)
+ {
+ Hierarchies.push(h);
+ }
+
+ for (const auto& lt : scene.LocalTransforms)
+ {
+ LocalTransforms.push(lt);
+ }
+
+ for (const auto& gt : scene.GlobalTransforms)
+ {
+ GlobalTransforms.push(gt);
+ }
+
+ auto node_mesh_view = scene.NodeMeshes.view();
+ for (const auto& [k, v] : node_mesh_view)
+ {
+ NodeMeshes.insert(k, v);
+ }
+
+ auto node_name_view = scene.NodeNames.view();
+ for (const auto& [k, v] : node_name_view)
+ {
+ NodeNames.insert(k, v);
+ }
+
+ auto asset_manager = Managers::AssetManager::Instance();
+
+ for (const auto& file : AssetFiles)
+ {
+ asset_manager->LoadAssetFile(Importers::AssetImporterOutput{.Type = file.Type, .Path = file.Path.c_str(), .RootPath = file.RootPath.c_str()});
+ }
+ }
+} // namespace Tetragrama
\ No newline at end of file
diff --git a/Tetragrama/EditorScene.h b/Tetragrama/EditorScene.h
new file mode 100644
index 00000000..c4fe915d
--- /dev/null
+++ b/Tetragrama/EditorScene.h
@@ -0,0 +1,81 @@
+#pragma once
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace Tetragrama::Serializers
+{
+ struct EditorSceneSerializer;
+} // namespace Tetragrama::Serializers
+
+namespace Tetragrama
+{
+ struct EditorAssetSceneFiles
+ {
+ Importers::AssetFileType Type = Importers::AssetFileType::UNKNOWN;
+ uint64_t Hash = {};
+ ZEngine::Core::Containers::String Path = {};
+ ZEngine::Core::Containers::String RootPath = {};
+ };
+
+ struct EditorSceneNodeHierarchy : public Helpers::NodeHierarchy
+ {
+ /*
+ * NodeRef serves as a mapping between Scene NodeHierarchy & Asset NodeHierarchy
+ */
+ Importers::AssetNodeRef NodeRef = {};
+ };
+
+ struct EditorScene
+ {
+ void Initialize(ZEngine::Core::Memory::ArenaAllocator* arena, const char* scene_name = "");
+
+ bool HasPendingChange() const;
+
+ std::atomic_bool Dirty = false;
+ std::atomic_bool HasPendingChanges = false;
+
+ const char* Name = "";
+ ZEngine::Core::Containers::Array Hierarchies = {};
+ ZEngine::Core::Containers::Array Names = {};
+ ZEngine::Core::Containers::Array LocalTransforms = {};
+ ZEngine::Core::Containers::Array GlobalTransforms = {};
+ ZEngine::Core::Containers::HashMap NodeMeshes = {};
+ ZEngine::Core::Containers::HashMap NodeNames = {};
+
+ ZEngine::Core::Containers::Array Vertices = {};
+ ZEngine::Core::Containers::Array Indices = {};
+
+ ZEngine::Core::Containers::HashMap HashToAssetFile = {};
+ ZEngine::Core::Containers::Array AssetFiles = {};
+
+ ZEngine::Core::Memory::ArenaAllocator LocalArena = {};
+
+ int AddHierarchyNode(int parent, int depth);
+
+ void CreateSceneNode(int parent = 0, int depth = 1);
+ void RemoveSceneNode(int node_id);
+ void ReparentNode(int node_id, int new_parent);
+ bool IsSceneNodeDeleted(int node_id);
+
+ void PushAssetFile(const Importers::AssetImporterOutput&);
+
+ void MarkDirty(bool value);
+ bool IsDirty();
+
+ void Reset();
+ void InitRootNode();
+
+ void ExtractAsync(EditorScene& scene); // Todo : this should be const EditorScene& ... the map::view() props prevents us to do it... def a impl issue
+
+ ZRawPtr(ZEngine::Rendering::Scenes::GraphicScene) RenderScene = nullptr;
+ };
+
+} // namespace Tetragrama
\ No newline at end of file
diff --git a/Tetragrama/EntryPoint.cpp b/Tetragrama/EntryPoint.cpp
index c52dd9e8..48110598 100644
--- a/Tetragrama/EntryPoint.cpp
+++ b/Tetragrama/EntryPoint.cpp
@@ -22,7 +22,7 @@ int applicationEntryPoint(int argc, char* argv[])
CLI11_PARSE(app, argc, argv);
MemoryManager manager = {};
- MemoryConfiguration config = {.DefaultSize = ZGiga(1)};
+ MemoryConfiguration config = {.DefaultSize = ZGiga(3u)};
manager.Initialize(config);
auto arena = &(manager.ArenaAllocator);
diff --git a/Tetragrama/Helpers/NodeHierarchyHelper.h b/Tetragrama/Helpers/NodeHierarchyHelper.h
new file mode 100644
index 00000000..c3624ffd
--- /dev/null
+++ b/Tetragrama/Helpers/NodeHierarchyHelper.h
@@ -0,0 +1,13 @@
+#pragma once
+
+namespace Tetragrama::Helpers
+{
+ struct NodeHierarchy
+ {
+ int Parent = -1; // -2 <-> node deleted
+ int FirstChild = -1;
+ int LastChild = -1;
+ int RightSibling = -1;
+ int DepthLevel = -1;
+ };
+} // namespace Tetragrama::Helpers
\ No newline at end of file
diff --git a/Tetragrama/Helpers/SerializerCommonHelper.cpp b/Tetragrama/Helpers/SerializerCommonHelper.cpp
index 41dee762..3589fac9 100644
--- a/Tetragrama/Helpers/SerializerCommonHelper.cpp
+++ b/Tetragrama/Helpers/SerializerCommonHelper.cpp
@@ -2,87 +2,8 @@
#include
#include
-#define DEFAULT_STR_BUFFER 256
-
using namespace ZEngine::Core::Containers;
namespace Tetragrama::Helpers
{
- void SerializeStringData(std::ostream& os, ZEngine::Core::Containers::StringView str)
- {
- size_t f_count = str.size();
- os.write(reinterpret_cast(&f_count), sizeof(size_t));
- os.write(str.data(), f_count + 1);
- }
-
- void DeserializeStringData(ZEngine::Core::Memory::ArenaAllocator* Arena, std::istream& in, ZEngine::Core::Containers::String& d)
- {
- size_t v_count;
- char buf[DEFAULT_STR_BUFFER] = {0};
- in.read(reinterpret_cast(&v_count), sizeof(size_t));
- in.read(buf, v_count + 1);
-
- d.init(Arena, buf);
- }
-
- void SerializeStringArrayData(std::ostream& os, ZEngine::Core::Containers::ArrayView str_view)
- {
- size_t count = str_view.size();
- os.write(reinterpret_cast(&count), sizeof(size_t));
- for (unsigned i = 0; i < count; ++i)
- {
- size_t f_count = str_view[i].size();
- os.write(reinterpret_cast(&f_count), sizeof(size_t));
- os.write(str_view[i].data(), f_count + 1);
- }
- }
-
- void SerializeMapData(std::ostream& os, const std::unordered_map& data)
- {
- std::vector flat_data = {};
- flat_data.reserve(data.size() * 2);
- for (auto d : data)
- {
- flat_data.push_back(d.first);
- flat_data.push_back(d.second);
- }
-
- size_t data_count = flat_data.size();
- os.write(reinterpret_cast(&data_count), sizeof(size_t));
- os.write(reinterpret_cast(flat_data.data()), sizeof(uint32_t) * flat_data.size());
- }
-
- void DeserializeStringArrayData(ZEngine::Core::Memory::ArenaAllocator* Arena, std::istream& in, ZEngine::Core::Containers::Array& data)
- {
- size_t data_count;
- in.read(reinterpret_cast(&data_count), sizeof(size_t));
- data.init(Arena, data_count);
-
- for (int i = 0; i < data_count; ++i)
- {
- size_t v_count;
- char buf[DEFAULT_STR_BUFFER] = {0};
- in.read(reinterpret_cast(&v_count), sizeof(size_t));
- in.read(buf, v_count + 1);
-
- String v;
- v.init(Arena, buf);
- data.push(v);
- }
- }
-
- void DeserializeMapData(ZEngine::Core::Memory::ArenaAllocator* Arena, std::istream& in, std::unordered_map& data)
- {
- size_t data_count;
- in.read(reinterpret_cast(&data_count), sizeof(size_t));
-
- std::vector flat_data = {};
- flat_data.resize(data_count);
- in.read(reinterpret_cast(flat_data.data()), sizeof(uint32_t) * data_count);
-
- for (int i = 0; i < data_count; i += 2)
- {
- data[flat_data[i]] = flat_data[i + 1];
- }
- }
} // namespace Tetragrama::Helpers
\ No newline at end of file
diff --git a/Tetragrama/Helpers/SerializerCommonHelper.h b/Tetragrama/Helpers/SerializerCommonHelper.h
index 2ab41dea..ec7c5dcf 100644
--- a/Tetragrama/Helpers/SerializerCommonHelper.h
+++ b/Tetragrama/Helpers/SerializerCommonHelper.h
@@ -1,17 +1,169 @@
#pragma once
#include
+#include
#include
#include
+#include
#include
-#include
+#include
namespace Tetragrama::Helpers
{
- void SerializeStringData(std::ostream&, ZEngine::Core::Containers::StringView);
- void SerializeStringArrayData(std::ostream&, ZEngine::Core::Containers::ArrayView);
- void SerializeMapData(std::ostream&, const std::unordered_map&);
+ template
+ static void WriteBinary(std::ostream& writer, const T& data)
+ {
+ writer.write(reinterpret_cast(&data), sizeof(T));
+ }
- void DeserializeStringData(ZEngine::Core::Memory::ArenaAllocator*, std::istream& in, ZEngine::Core::Containers::String& data);
- void DeserializeStringArrayData(ZEngine::Core::Memory::ArenaAllocator*, std::istream&, ZEngine::Core::Containers::Array&);
- void DeserializeMapData(ZEngine::Core::Memory::ArenaAllocator*, std::istream&, std::unordered_map&);
+ template || std::is_same_v>>
+ static void WriteBinaryString(std::ostream& writer, const T& str)
+ {
+ if constexpr (std::is_same_v)
+
+ {
+ size_t count = str.size();
+ writer.write(reinterpret_cast(&count), sizeof(size_t));
+ if (count > 0)
+ {
+ writer.write(str.c_str(), count + 1);
+ }
+ }
+ else if constexpr (std::is_same_v)
+
+ {
+ size_t count = ZEngine::Helpers::secure_strlen(str);
+ writer.write(reinterpret_cast(&count), sizeof(size_t));
+
+ if (count > 0)
+ {
+ writer.write(str, count);
+ }
+ }
+ }
+
+ template
+ static void WriteBinaryArray(std::ostream& writer, ZEngine::Core::Containers::ArrayView arr)
+ {
+ size_t count = arr.size();
+ writer.write(reinterpret_cast(&count), sizeof(size_t));
+
+ if constexpr (std::is_same_v)
+
+ {
+ for (unsigned i = 0; i < count; ++i)
+ {
+ WriteBinaryString(writer, arr[i]);
+ }
+ }
+
+ else
+ {
+ if (count > 0)
+ {
+ writer.write(reinterpret_cast(arr.data()), sizeof(T) * count);
+ }
+ }
+ }
+
+ template
+ static void WriteBinaryHashMap(std::ostream& writer, ZEngine::Core::Containers::HashMap& map)
+ {
+ size_t size = map.size();
+ WriteBinary(writer, size);
+
+ auto view = map.view();
+ for (const auto& [key, val] : view)
+ {
+ WriteBinary(writer, key);
+ WriteBinary(writer, val);
+ }
+ }
+
+ template
+ static void ReadBinary(std::istream& in, T& value)
+ {
+ in.read(reinterpret_cast(&value), sizeof(T));
+ }
+
+ static void ReadBinaryString(ZEngine::Core::Memory::ArenaAllocator* arena, std::istream& in, ZEngine::Core::Containers::String& str)
+ {
+ size_t size = 0;
+ char buf[DEFAULT_STR_BUFFER] = {0};
+ in.read(reinterpret_cast(&size), sizeof(size_t));
+
+ if (size > 0)
+ {
+ in.read(buf, size + 1);
+ str.init(arena, buf);
+ }
+ }
+
+ static void ReadBinaryCString(ZEngine::Core::Memory::ArenaAllocator* arena, std::istream& in, char* str)
+ {
+ size_t size = 0;
+ in.read(reinterpret_cast(&size), sizeof(size_t));
+
+ if (size > 0)
+ {
+ in.read(str, size);
+ }
+ }
+
+ template
+ static void ReadBinaryArray(ZEngine::Core::Memory::ArenaAllocator* arena, std::istream& in, ZEngine::Core::Containers::Array& arr)
+ {
+ size_t size = 0;
+ ReadBinary(in, size);
+ arr.init(arena, size, size);
+
+ if constexpr (std::is_same_v)
+
+ {
+ for (unsigned i = 0; i < size; ++i)
+ {
+ auto& str = arr[i];
+ ReadBinaryString(arena, in, str);
+ }
+ }
+ else
+ {
+ if (size > 0)
+ {
+ in.read(reinterpret_cast(arr.data()), sizeof(T) * size);
+ }
+ }
+ }
+
+ template
+ static void ReadHashMap(ZEngine::Core::Memory::ArenaAllocator* arena, std::istream& in, ZEngine::Core::Containers::HashMap& map)
+ {
+ size_t size = 0;
+ ReadBinary(in, size);
+ map.init(arena, size);
+
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ T key;
+ U val;
+
+ if constexpr (std::is_same_v)
+ {
+ ReadBinaryString(arena, in, key);
+ }
+ else
+ {
+ ReadBinary(in, key);
+ }
+
+ if constexpr (std::is_same_v)
+ {
+ ReadBinaryString(arena, in, val);
+ }
+ else
+ {
+ ReadBinary(in, val);
+ }
+ map.insert(key, val);
+ }
+ }
} // namespace Tetragrama::Helpers
\ No newline at end of file
diff --git a/Tetragrama/Importers/AssetTypes.h b/Tetragrama/Importers/AssetTypes.h
new file mode 100644
index 00000000..293e00a7
--- /dev/null
+++ b/Tetragrama/Importers/AssetTypes.h
@@ -0,0 +1,97 @@
+#pragma once
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace Tetragrama::Importers
+{
+ enum AssetFileType : uint8_t
+ {
+ UNKNOWN = 0,
+ MESH,
+ MATERIAL,
+ TEXTURES
+ };
+
+ struct AssetSubMesh
+ {
+ uuids::uuid MaterialUUID = {};
+ uint32_t VertexCount = 0;
+ uint32_t IndexCount = 0;
+ uint32_t VertexOffset = 0;
+ uint32_t IndexOffset = 0;
+ uint32_t StreamOffset = 0;
+ uint32_t IndexStreamOffset = 0;
+ uint32_t VertexUnitStreamSize = 0;
+ uint32_t IndexUnitStreamSize = 0;
+ uint32_t TotalByteSize = 0;
+ };
+
+ struct AssetMesh
+ {
+ uuids::uuid MeshUUID = {};
+ ZEngine::Core::Containers::Array Vertices = {};
+ ZEngine::Core::Containers::Array Indices = {};
+ ZEngine::Core::Containers::Array SubMeshes = {};
+ };
+
+ struct AssetMaterial
+ {
+ ZEngine::Core::Containers::String Name = {};
+ uuids::uuid MaterialUUID = {};
+ uuids::uuid AlbedoTexUUID = {};
+ uuids::uuid EmissiveTexUUID = {};
+ uuids::uuid NormalTexUUID = {};
+ uuids::uuid OpacityTexUUID = {};
+ uuids::uuid SpecularTexUUID = {};
+ float AmbientColor[4] = {0};
+ float AlbedoColor[4] = {0};
+ float EmissiveColor[4] = {0};
+ float RoughnessColor[4] = {0};
+ float SpecularColor[4] = {0};
+ float Factors[4] = {0};
+ };
+
+ struct AssetTexture
+ {
+ uuids::uuid TextureUUID = {};
+ ZEngine::Core::Containers::String Path = {};
+ };
+
+ struct AssetNodeHierarchy
+ {
+ uuids::uuid NodeHierarchyUUID = {};
+ uuids::uuid MeshUUID = {};
+ ZEngine::Core::Containers::Array Hierarchies = {};
+ ZEngine::Core::Containers::Array LocalTransforms = {};
+ ZEngine::Core::Containers::Array GlobalTransforms = {};
+ ZEngine::Core::Containers::Array Names = {};
+ ZEngine::Core::Containers::Array MaterialNames = {};
+ ZEngine::Core::Containers::HashMap NodeNames = {};
+ ZEngine::Core::Containers::HashMap NodeMeshes = {};
+ ZEngine::Core::Containers::HashMap NodeMaterials = {};
+ };
+
+ struct AssetNodeRef
+ {
+ uint32_t AssetNodeHandle = 0xFFFFFFFF;
+ int NodeHierarchyIndex = -1;
+
+ bool IsValid() const
+ {
+ return (AssetNodeHandle != 0xFFFFFFFF) && (NodeHierarchyIndex != -1);
+ }
+ };
+
+ struct AssetFile
+ {
+ const char* Name = nullptr;
+ AssetNodeHierarchy Hierarchy = {};
+ AssetMesh Mesh = {};
+ ZEngine::Core::Containers::Array Materials = {};
+ ZEngine::Core::Containers::Array Textures = {};
+ };
+} // namespace Tetragrama::Importers
diff --git a/Tetragrama/Importers/AssimpImporter.cpp b/Tetragrama/Importers/AssimpImporter.cpp
index c5c205c2..e8cf98f9 100644
--- a/Tetragrama/Importers/AssimpImporter.cpp
+++ b/Tetragrama/Importers/AssimpImporter.cpp
@@ -2,7 +2,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -12,6 +11,7 @@ using namespace Tetragrama::Helpers;
using namespace ZEngine::Rendering::Meshes;
using namespace ZEngine::Rendering::Scenes;
using namespace ZEngine::Core::Containers;
+using namespace uuids;
namespace fs = std::filesystem;
@@ -24,11 +24,11 @@ namespace Tetragrama::Importers
AssimpImporter::~AssimpImporter() {}
- std::future AssimpImporter::ImportAsync(std::string_view filename, ImportConfiguration config)
+ std::future AssimpImporter::ImportAsync(const char* filename, ImportConfiguration& config)
{
- ThreadPoolHelper::Submit([this, path = std::string(filename.data()), config] {
+ ThreadPoolHelper::Submit([this, path = filename, config] {
std::unique_lock l(m_mutex);
- Arena.Clear();
+
m_is_importing.store(true, std::memory_order_release);
Assimp::Importer importer{};
@@ -45,21 +45,42 @@ namespace Tetragrama::Importers
}
else
{
- ImporterData import_data = {};
-
- ExtractMeshes(scene, import_data);
- ExtractMaterials(scene, import_data);
- ExtractTextures(scene, import_data);
- CreateHierachyScene(scene, import_data);
- /*
- * Serialization of ImporterData
- */
- REPORT_LOG(Context, "Serializing model...")
- SerializeImporterData(&Arena, import_data, config);
+ std::random_device rd;
+ std::mt19937 generator(rd());
+ uuid_random_generator gen(&generator);
+
+ AssetMesh mesh = {};
+ AssetNodeHierarchy hierarchies = {};
+ Array materials = {};
+ Array textures = {};
+
+ ExtractMeshes(&Arena, scene, gen, mesh);
+ ExtractMaterials(&Arena, scene, gen, materials, hierarchies);
+ ExtractTextures(&Arena, scene, gen, materials, textures);
+ CreateHierachy(&Arena, scene, gen, hierarchies, mesh, materials);
+ CopyTextureFiles(&Arena, textures, config);
+
+ Array outputs = {};
+ outputs.init(&Arena, 100);
+
+ auto out_m = SerializeMeshAssetFile(&Arena, mesh, hierarchies, config);
+ outputs.push(out_m);
+
+ for (unsigned i = 0; i < materials.size(); ++i)
+ {
+ auto& material = materials[i];
+ auto out_mat = SerializeMaterialAssetFile(&Arena, material, config);
+ outputs.push(out_mat);
+ }
+
+ auto out_tex = SerializeTextureAssetFiles(&Arena, ArrayView{textures}, config);
+ outputs.push(out_tex);
+
+ auto result = fmt::format("{0}{1}{2}", config.OutputAssetsPath.c_str(), PLATFORM_OS_BACKSLASH, config.OutputAssetFile.c_str());
if (m_complete_callback)
{
- m_complete_callback(Context, std::move(import_data));
+ m_complete_callback(Context, ArrayView{outputs});
}
}
@@ -67,25 +88,42 @@ namespace Tetragrama::Importers
importer.FreeScene();
m_is_importing.store(false, std::memory_order_release);
+
+ Arena.Clear();
});
co_return;
}
- void AssimpImporter::ExtractMeshes(const aiScene* scene, ImporterData& importer_data)
+ void AssimpImporter::ExtractMeshes(ZEngine::Core::Memory::ArenaAllocator* arena, const aiScene* scene, uuids::uuid_random_generator& generator, AssetMesh& mesh)
{
if ((!scene) || (!scene->HasMeshes()))
{
return;
}
- uint32_t number_of_meshes = scene->mNumMeshes;
- importer_data.Scene.Meshes.reserve(number_of_meshes);
+ unsigned int t_vertices = 0;
+ unsigned int t_indices = 0;
+ unsigned int t_meshes = scene->mNumMeshes;
- for (uint32_t m = 0; m < number_of_meshes; ++m)
+ for (unsigned int i = 0; i < t_meshes; ++i)
{
+ aiMesh* mesh = scene->mMeshes[i];
+ t_vertices += mesh->mNumVertices;
+ t_indices += mesh->mNumFaces * 3; // assuming triangulated
+ }
+
+ mesh.MeshUUID = generator();
+ mesh.SubMeshes.init(arena, t_meshes);
+ mesh.Vertices.init(arena, t_vertices);
+ mesh.Indices.init(arena, t_indices);
- REPORT_LOG(Context, fmt::format("Extrating Meshes : {0}/{1} ", (m + 1), number_of_meshes).c_str())
+ uint32_t VertexOffset = 0;
+ uint32_t IndexOffset = 0;
+
+ for (uint32_t m = 0; m < t_meshes; ++m)
+ {
+ REPORT_LOG(Context, fmt::format("Extrating Meshes : {0}/{1} ", (m + 1), t_meshes).c_str())
aiMesh* ai_mesh = scene->mMeshes[m];
@@ -98,16 +136,16 @@ namespace Tetragrama::Importers
const aiVector3D normal = ai_mesh->mNormals[v];
const aiVector3D texture = ai_mesh->HasTextureCoords(0) ? ai_mesh->mTextureCoords[0][v] : aiVector3D{};
- importer_data.Scene.Vertices.push_back(position.x);
- importer_data.Scene.Vertices.push_back(position.y);
- importer_data.Scene.Vertices.push_back(position.z);
+ mesh.Vertices.push(position.x);
+ mesh.Vertices.push(position.y);
+ mesh.Vertices.push(position.z);
- importer_data.Scene.Vertices.push_back(normal.x);
- importer_data.Scene.Vertices.push_back(normal.y);
- importer_data.Scene.Vertices.push_back(normal.z);
+ mesh.Vertices.push(normal.x);
+ mesh.Vertices.push(normal.y);
+ mesh.Vertices.push(normal.z);
- importer_data.Scene.Vertices.push_back(texture.x);
- importer_data.Scene.Vertices.push_back(texture.y);
+ mesh.Vertices.push(texture.x);
+ mesh.Vertices.push(texture.y);
vertex_count++;
}
@@ -120,30 +158,30 @@ namespace Tetragrama::Importers
for (int fidx = 0; fidx < ai_face.mNumIndices; ++fidx)
{
- importer_data.Scene.Indices.push_back(ai_face.mIndices[fidx]);
+ mesh.Indices.push(ai_face.mIndices[fidx]);
index_count++;
}
}
- MeshVNext& mesh = importer_data.Scene.Meshes.emplace_back();
- mesh.VertexCount = vertex_count;
- mesh.VertexOffset = importer_data.VertexOffset;
- mesh.VertexUnitStreamSize = sizeof(float) * (3 + 3 + 2) /*pos-cmp + normal-cmp + tex-cmp*/;
- mesh.StreamOffset = (mesh.VertexUnitStreamSize * mesh.VertexOffset);
- mesh.IndexOffset = importer_data.IndexOffset;
- mesh.IndexCount = index_count;
- mesh.IndexUnitStreamSize = sizeof(uint32_t);
- mesh.IndexStreamOffset = (mesh.IndexUnitStreamSize * mesh.IndexOffset);
- mesh.TotalByteSize = (mesh.VertexCount * mesh.VertexUnitStreamSize) + (mesh.IndexCount * mesh.IndexUnitStreamSize);
+ auto& subMesh = mesh.SubMeshes.push_use({});
+ subMesh.VertexCount = vertex_count;
+ subMesh.VertexOffset = VertexOffset;
+ subMesh.VertexUnitStreamSize = sizeof(float) * (3 + 3 + 2) /*pos-cmp + normal-cmp + tex-cmp*/;
+ subMesh.StreamOffset = (subMesh.VertexUnitStreamSize * subMesh.VertexOffset);
+ subMesh.IndexOffset = IndexOffset;
+ subMesh.IndexCount = index_count;
+ subMesh.IndexUnitStreamSize = sizeof(uint32_t);
+ subMesh.IndexStreamOffset = (subMesh.IndexUnitStreamSize * subMesh.IndexOffset);
+ subMesh.TotalByteSize = (subMesh.VertexCount * subMesh.VertexUnitStreamSize) + (subMesh.IndexCount * subMesh.IndexUnitStreamSize);
/* Computing offset data */
- importer_data.VertexOffset += ai_mesh->mNumVertices;
- importer_data.IndexOffset += index_count;
+ VertexOffset += ai_mesh->mNumVertices;
+ IndexOffset += index_count;
}
}
- void AssimpImporter::ExtractMaterials(const aiScene* scene, ImporterData& importer_data)
+ void AssimpImporter::ExtractMaterials(ZEngine::Core::Memory::ArenaAllocator* arena, const aiScene* scene, uuids::uuid_random_generator& generator, ZEngine::Core::Containers::Array& materials, AssetNodeHierarchy& model)
{
if (!scene)
{
@@ -151,43 +189,64 @@ namespace Tetragrama::Importers
}
uint32_t number_of_materials = scene->mNumMaterials;
- importer_data.Scene.Materials.resize(number_of_materials);
- importer_data.Scene.MaterialFiles.resize(number_of_materials);
- importer_data.Scene.MaterialNames.resize(number_of_materials);
+ materials.init(arena, number_of_materials, number_of_materials);
+ model.MaterialNames.init(arena, number_of_materials, number_of_materials);
for (uint32_t m = 0; m < number_of_materials; ++m)
{
REPORT_LOG(Context, fmt::format("Extrating materials : {0}/{1}", (m + 1), number_of_materials).c_str())
- aiColor4D color;
- aiMaterial* ai_material = scene->mMaterials[m];
- aiString mat_name = ai_material->GetName();
- MeshMaterial& material = importer_data.Scene.Materials[m];
+ aiColor4D color;
+ aiMaterial* ai_material = scene->mMaterials[m];
+ aiString mat_name = ai_material->GetName();
+ AssetMaterial& material = materials[m];
+
+ material.MaterialUUID = generator();
+
+ {
+ std::stringstream ss;
+ ss << material.MaterialUUID;
+ auto mat_uuid = ss.str();
+ material.Name.init(arena, (mat_name.C_Str() ? mat_name.C_Str() : mat_uuid.c_str()));
+ ss.clear();
+ }
- importer_data.Scene.MaterialNames[m] = (mat_name.C_Str() ? std::string(mat_name.C_Str()) : std::string(""));
+ model.MaterialNames[m].init(arena, material.Name.c_str());
if (aiGetMaterialColor(ai_material, AI_MATKEY_COLOR_AMBIENT, &color) == AI_SUCCESS)
{
- material.AmbientColor = ZEngine::Rendering::gpuvec4{color.r, color.g, color.b, color.a};
- material.AmbientColor.w = glm::min(material.AmbientColor.w, 1.0f);
+ material.AmbientColor[0] = color.r;
+ material.AmbientColor[1] = color.g;
+ material.AmbientColor[2] = color.b;
+ material.AmbientColor[3] = color.a;
+ material.AmbientColor[3] = glm::min(material.AmbientColor[3], 1.0f);
}
if (aiGetMaterialColor(ai_material, AI_MATKEY_COLOR_DIFFUSE, &color) == AI_SUCCESS)
{
- material.AlbedoColor = ZEngine::Rendering::gpuvec4{color.r, color.g, color.b, color.a};
- material.AlbedoColor.w = std::min(material.AlbedoColor.w, 1.0f);
+ material.AlbedoColor[0] = color.r;
+ material.AlbedoColor[1] = color.g;
+ material.AlbedoColor[2] = color.b;
+ material.AlbedoColor[3] = color.a;
+ material.AlbedoColor[3] = glm::min(material.AlbedoColor[3], 1.0f);
}
if (aiGetMaterialColor(ai_material, AI_MATKEY_COLOR_SPECULAR, &color) == AI_SUCCESS)
{
- material.SpecularColor = ZEngine::Rendering::gpuvec4{color.r, color.g, color.b, color.a};
- material.SpecularColor.w = std::min(material.SpecularColor.w, 1.0f);
+ material.SpecularColor[0] = color.r;
+ material.SpecularColor[1] = color.g;
+ material.SpecularColor[2] = color.b;
+ material.SpecularColor[3] = color.a;
+ material.SpecularColor[3] = glm::min(material.SpecularColor[3], 1.0f);
}
if (aiGetMaterialColor(ai_material, AI_MATKEY_COLOR_EMISSIVE, &color) == AI_SUCCESS)
{
- material.EmissiveColor = ZEngine::Rendering::gpuvec4{color.r, color.g, color.b, color.a};
- material.EmissiveColor.w = std::min(material.EmissiveColor.w, 1.0f);
+ material.EmissiveColor[0] = color.r;
+ material.EmissiveColor[1] = color.g;
+ material.EmissiveColor[2] = color.b;
+ material.EmissiveColor[3] = color.a;
+ material.EmissiveColor[3] = glm::min(material.EmissiveColor[3], 1.0f);
}
float opacity = 1.0f;
@@ -195,27 +254,27 @@ namespace Tetragrama::Importers
if (aiGetMaterialFloat(ai_material, AI_MATKEY_OPACITY, &opacity) == AI_SUCCESS)
{
- material.Factors.x = glm::clamp(1.f - opacity, 0.0f, 1.0f);
- if (material.Factors.x >= (1.0f - opaqueness_threshold))
+ material.Factors[0] = glm::clamp(1.f - opacity, 0.0f, 1.0f);
+ if (material.Factors[0] >= (1.0f - opaqueness_threshold))
{
- material.Factors.x = 0.0f;
+ material.Factors[0] = 0.0f;
}
}
if (aiGetMaterialColor(ai_material, AI_MATKEY_COLOR_TRANSPARENT, &color) == AI_SUCCESS)
{
const float component_as_opacity = std::max(std::max(color.r, color.g), color.b);
- material.Factors.x = glm::clamp(component_as_opacity, 0.0f, 1.0f);
- if (material.Factors.x >= (1.0f - opaqueness_threshold))
+ material.Factors[0] = glm::clamp(component_as_opacity, 0.0f, 1.0f);
+ if (material.Factors[0] >= (1.0f - opaqueness_threshold))
{
- material.Factors.x = 0.0f;
+ material.Factors[0] = 0.0f;
}
- material.Factors.z = 0.5f;
+ material.Factors[2] = 0.5f;
}
}
}
- void AssimpImporter::ExtractTextures(const aiScene* scene, ImporterData& importer_data)
+ void AssimpImporter::ExtractTextures(ZEngine::Core::Memory::ArenaAllocator* arena, const aiScene* scene, uuids::uuid_random_generator& generator, ZEngine::Core::Containers::Array& materials, ZEngine::Core::Containers::Array& textures)
{
if (!scene)
{
@@ -231,418 +290,208 @@ namespace Tetragrama::Importers
uint32_t texture_flags = 0;
uint32_t number_of_materials = scene->mNumMaterials;
+
+ textures.init(arena, number_of_materials);
+
for (uint32_t m = 0; m < number_of_materials; ++m)
{
REPORT_LOG(Context, fmt::format("Extrating Material's textures: {0}/{1} materials", (m + 1), number_of_materials).c_str())
- aiMaterial* ai_material = scene->mMaterials[m];
+ aiMaterial* ai_material = scene->mMaterials[m];
+ AssetMaterial& material = materials[m];
if (aiGetMaterialTexture(ai_material, aiTextureType_DIFFUSE, 0, &texture_filename, &texture_mapping, &uv_index, &blend, &texture_operation, texture_map_mode, &texture_flags) == AI_SUCCESS)
{
- secure_strcpy(importer_data.Scene.MaterialFiles[m].AlbedoTexture, MAX_FILE_PATH_COUNT, texture_filename.C_Str());
+ AssetTexture& texture = textures.push_use({});
+ texture.TextureUUID = generator();
+ material.AlbedoTexUUID = texture.TextureUUID;
+ texture.Path.init(arena, texture_filename.C_Str());
}
if (aiGetMaterialTexture(ai_material, aiTextureType_SPECULAR, 0, &texture_filename, &texture_mapping, &uv_index, &blend, &texture_operation, texture_map_mode, &texture_flags) == AI_SUCCESS)
{
- secure_strcpy(importer_data.Scene.MaterialFiles[m].SpecularTexture, MAX_FILE_PATH_COUNT, texture_filename.C_Str());
+ AssetTexture& texture = textures.push_use({});
+ texture.TextureUUID = generator();
+ material.SpecularTexUUID = texture.TextureUUID;
+ texture.Path.init(arena, texture_filename.C_Str());
}
if (aiGetMaterialTexture(ai_material, aiTextureType_EMISSIVE, 0, &texture_filename, &texture_mapping, &uv_index, &blend, &texture_operation, texture_map_mode, &texture_flags) == AI_SUCCESS)
{
- secure_strcpy(importer_data.Scene.MaterialFiles[m].EmissiveTexture, MAX_FILE_PATH_COUNT, texture_filename.C_Str());
+ AssetTexture& texture = textures.push_use({});
+ texture.TextureUUID = generator();
+ material.EmissiveTexUUID = texture.TextureUUID;
+ texture.Path.init(arena, texture_filename.C_Str());
}
if (aiGetMaterialTexture(ai_material, aiTextureType_NORMALS, 0, &texture_filename, &texture_mapping, &uv_index, &blend, &texture_operation, texture_map_mode, &texture_flags) == AI_SUCCESS)
{
- secure_strcpy(importer_data.Scene.MaterialFiles[m].NormalTexture, MAX_FILE_PATH_COUNT, texture_filename.C_Str());
+ AssetTexture& texture = textures.push_use({});
+ texture.TextureUUID = generator();
+ material.NormalTexUUID = texture.TextureUUID;
+ texture.Path.init(arena, texture_filename.C_Str());
}
- if (importer_data.Scene.Materials[m].NormalMap == 0xFFFFFFFF)
+ if (material.NormalTexUUID.is_nil())
{
if (aiGetMaterialTexture(ai_material, aiTextureType_HEIGHT, 0, &texture_filename, &texture_mapping, &uv_index, &blend, &texture_operation, texture_map_mode, &texture_flags) == AI_SUCCESS)
{
- secure_strcpy(importer_data.Scene.MaterialFiles[m].NormalTexture, MAX_FILE_PATH_COUNT, texture_filename.C_Str());
+ AssetTexture& texture = textures.push_use({});
+ texture.TextureUUID = generator();
+ material.NormalTexUUID = texture.TextureUUID;
+ texture.Path.init(arena, texture_filename.C_Str());
}
}
if (aiGetMaterialTexture(ai_material, aiTextureType_OPACITY, 0, &texture_filename, &texture_mapping, &uv_index, &blend, &texture_operation, texture_map_mode, &texture_flags) == AI_SUCCESS)
{
- secure_strcpy(importer_data.Scene.MaterialFiles[m].OpacityTexture, MAX_FILE_PATH_COUNT, texture_filename.C_Str());
- importer_data.Scene.Materials[m].Factors.z = 0.5f;
+ AssetTexture& texture = textures.push_use({});
+ texture.TextureUUID = generator();
+ material.OpacityTexUUID = texture.TextureUUID;
+ texture.Path.init(arena, texture_filename.C_Str());
+ material.Factors[2] = 0.5f;
}
}
}
- void AssimpImporter::CreateHierachyScene(const aiScene* scene, ImporterData& importer_data)
+ void AssimpImporter::CreateHierachy(ZEngine::Core::Memory::ArenaAllocator* arena, const aiScene* scene, uuids::uuid_random_generator& generator, AssetNodeHierarchy& AssetNode, AssetMesh& asset_mesh, ZEngine::Core::Containers::Array& materials)
{
if (!scene || !(scene->mRootNode))
{
return;
}
- TraverseNode(scene, &(importer_data.Scene), scene->mRootNode, -1, 0);
+ AssetNode.NodeHierarchyUUID = generator();
+ AssetNode.MeshUUID = asset_mesh.MeshUUID;
+
+ AssetNode.Hierarchies.init(arena, 10);
+ AssetNode.LocalTransforms.init(arena, 10);
+ AssetNode.GlobalTransforms.init(arena, 10);
+ AssetNode.Names.init(arena, 10);
+ AssetNode.NodeNames.init(arena, 10);
+ AssetNode.NodeMeshes.init(arena, 10);
+ AssetNode.NodeMaterials.init(arena, 10);
+
+ TraverseNode(arena, scene, scene->mRootNode, AssetNode, asset_mesh, materials, -1, 0);
}
- void AssimpImporter::TraverseNode(const aiScene* ai_scene, SceneRawData* const scene, const aiNode* node, int parent_node_id, int depth_level)
+ void AssimpImporter::TraverseNode(ZEngine::Core::Memory::ArenaAllocator* arena, const aiScene* ai_scene, const aiNode* node, AssetNodeHierarchy& hierarchy, AssetMesh& asset_mesh, ZEngine::Core::Containers::Array& materials, int parent_node_id, int depth_level)
{
- auto node_id = scene->AddNode(parent_node_id, depth_level);
- scene->NodeNames[node_id] = scene->Names.size();
- scene->Names.push_back(node->mName.C_Str() ? std::string(node->mName.C_Str()) : std::string{""});
+ auto node_id = AddNode(hierarchy, parent_node_id, depth_level);
+ hierarchy.NodeNames[node_id] = hierarchy.Names.size();
+ auto& name = hierarchy.Names.push_use({});
+ name.init(arena, node->mName.C_Str() ? node->mName.C_Str() : "");
- scene->GlobalTransforms[node_id] = glm::mat4(1.0f);
- scene->LocalTransforms[node_id] = ConvertToMat4(node->mTransformation);
+ hierarchy.GlobalTransforms[node_id] = glm::mat4(1.0f);
+ hierarchy.LocalTransforms[node_id] = ConvertToMat4(node->mTransformation);
for (uint32_t i = 0; i < node->mNumMeshes; ++i)
{
- auto sub_node_id = scene->AddNode(node_id, depth_level + 1);
- uint32_t mesh = node->mMeshes[i];
- aiString mesh_name = ai_scene->mMeshes[mesh]->mName;
-
- scene->NodeNames[sub_node_id] = scene->Names.size();
- scene->Names.push_back(mesh_name.C_Str() ? std::string(mesh_name.C_Str()) : std::string{""});
-
- scene->NodeMeshes[sub_node_id] = mesh;
- scene->NodeMaterials[sub_node_id] = ai_scene->mMeshes[mesh]->mMaterialIndex;
- scene->GlobalTransforms[sub_node_id] = glm::mat4(1.0f);
- scene->LocalTransforms[sub_node_id] = glm::mat4(1.0f);
+ auto sub_node_id = AddNode(hierarchy, node_id, depth_level + 1);
+ uint32_t mesh = node->mMeshes[i];
+ uint32_t material_id = ai_scene->mMeshes[mesh]->mMaterialIndex;
+
+ hierarchy.NodeNames[sub_node_id] = hierarchy.Names.size();
+ auto& n = hierarchy.Names.push_use({});
+ aiString mesh_name = ai_scene->mMeshes[mesh]->mName;
+ n.init(arena, mesh_name.C_Str() ? mesh_name.C_Str() : "");
+
+ hierarchy.NodeMeshes[sub_node_id] = mesh;
+ hierarchy.NodeMaterials[sub_node_id] = material_id;
+ hierarchy.GlobalTransforms[sub_node_id] = glm::mat4(1.0f);
+ hierarchy.LocalTransforms[sub_node_id] = glm::mat4(1.0f);
+
+ auto& asset_mat = materials[material_id];
+ auto& sub_mesh = asset_mesh.SubMeshes[mesh];
+ sub_mesh.MaterialUUID = asset_mat.MaterialUUID;
}
for (uint32_t child = 0; child < node->mNumChildren; ++child)
{
- TraverseNode(ai_scene, scene, node->mChildren[child], node_id, (depth_level + 1));
+ TraverseNode(arena, ai_scene, node->mChildren[child], hierarchy, asset_mesh, materials, node_id, (depth_level + 1));
}
}
- void AssimpImporter::SerializeImporterData(ZEngine::Core::Memory::ArenaAllocator* arena, ImporterData& importer_data, const ImportConfiguration& config)
+ void AssimpImporter::CopyTextureFiles(ZEngine::Core::Memory::ArenaAllocator* arena, ZEngine::Core::Containers::Array& textures, const ImportConfiguration& config)
{
- importer_data.Name = config.AssetFilename;
+ /*
+ * Normalize file naming
+ */
+ auto dst_dir = fmt::format("{0}{1}{2}{3}{4}", config.OutputWorkingSpacePath.c_str(), PLATFORM_OS_BACKSLASH, config.OutputTextureFilesPath.c_str(), PLATFORM_OS_BACKSLASH, config.AssetName.c_str());
- if (!config.OutputMeshFilePath.empty())
- {
- std::string output_mesh_file = fmt::format("{}.zemeshes", config.AssetFilename.c_str());
- std::string fullname_path = fmt::format("{0}{1}{2}{3}{4}", config.OutputWorkingSpacePath.c_str(), PLATFORM_OS_BACKSLASH, config.OutputMeshFilePath.c_str(), PLATFORM_OS_BACKSLASH, output_mesh_file.c_str());
- std::ofstream out(fullname_path, std::ios::binary | std::ios::trunc);
+ auto CreateBaseDirectoryFn = [](std::string_view filename) -> void {
+ auto base_dir = fs::absolute(filename).parent_path();
- if (out.is_open())
+ std::error_code err = {};
+ if (!fs::exists(base_dir))
{
- out.seekp(std::ios::beg);
-
- size_t mesh_count = importer_data.Scene.Meshes.size();
- out.write(reinterpret_cast(&mesh_count), sizeof(size_t));
- out.write(reinterpret_cast(importer_data.Scene.Meshes.data()), sizeof(ZEngine::Rendering::Meshes::MeshVNext) * mesh_count);
-
- size_t indices_count = importer_data.Scene.Indices.size();
- out.write(reinterpret_cast(&indices_count), sizeof(size_t));
- out.write(reinterpret_cast(importer_data.Scene.Indices.data()), sizeof(uint32_t) * indices_count);
-
- size_t vertice_count = importer_data.Scene.Vertices.size();
- out.write(reinterpret_cast(&vertice_count), sizeof(size_t));
- out.write(reinterpret_cast(importer_data.Scene.Vertices.data()), sizeof(float) * vertice_count);
+ fs::create_directories(base_dir, err);
}
- out.close();
+ };
- importer_data.SerializedMeshesPath.init(arena, output_mesh_file.c_str());
- }
+ auto scratch = ZGetScratch(arena);
+ Array src_tex_files = {};
+ Array dst_tex_files = {};
+ src_tex_files.init(scratch.Arena, textures.size());
+ dst_tex_files.init(scratch.Arena, textures.size());
- if (!config.OutputMaterialsPath.empty() && !config.OutputTextureFilesPath.empty())
+ for (auto& tex : textures)
{
- /*
- * Normalize file naming
- */
- auto dst_dir = fmt::format("{0}{1}{2}{3}{4}", config.OutputWorkingSpacePath.c_str(), PLATFORM_OS_BACKSLASH, config.OutputTextureFilesPath.c_str(), PLATFORM_OS_BACKSLASH, config.AssetFilename.c_str());
-
- auto create_base_dir_fn = [](std::string_view filename) -> void {
- auto base_dir = fs::absolute(filename).parent_path();
-
- std::error_code err = {};
- if (!fs::exists(base_dir))
- {
- fs::create_directories(base_dir, err);
- }
- };
-
- auto scratch = ZGetScratch(arena);
- Array src_tex_files = {};
- Array dst_tex_files = {};
- src_tex_files.init(scratch.Arena, 10);
- dst_tex_files.init(scratch.Arena, 10);
-
- for (auto& mat_file : importer_data.Scene.MaterialFiles)
- {
- if (!std::string_view(mat_file.AlbedoTexture).empty())
- {
- auto src_file = fmt::format("{0}{1}{2}", config.InputBaseAssetFilePath.c_str(), PLATFORM_OS_BACKSLASH, mat_file.AlbedoTexture);
- auto dst_file = fmt::format("{0}{1}{2}", dst_dir, PLATFORM_OS_BACKSLASH, mat_file.AlbedoTexture);
- create_base_dir_fn(dst_file);
-
- ZEngine::Helpers::secure_strcpy(mat_file.AlbedoTexture, MAX_FILE_PATH_COUNT, dst_file.c_str());
-
- auto& sf = src_tex_files.push_use({});
- auto& df = dst_tex_files.push_use({});
-
- sf.init(scratch.Arena, src_file.c_str());
- df.init(scratch.Arena, dst_file.c_str());
- }
-
- if (!std::string_view(mat_file.EmissiveTexture).empty())
- {
- auto src_file = fmt::format("{0}{1}{2}", config.InputBaseAssetFilePath.c_str(), PLATFORM_OS_BACKSLASH, mat_file.EmissiveTexture);
- auto dst_file = fmt::format("{0}{1}{2}", dst_dir, PLATFORM_OS_BACKSLASH, mat_file.EmissiveTexture);
-
- create_base_dir_fn(dst_file);
-
- ZEngine::Helpers::secure_strcpy(mat_file.EmissiveTexture, MAX_FILE_PATH_COUNT, dst_file.c_str());
-
- auto& sf = src_tex_files.push_use({});
- auto& df = dst_tex_files.push_use({});
-
- sf.init(scratch.Arena, src_file.c_str());
- df.init(scratch.Arena, dst_file.c_str());
- }
-
- if (!std::string_view(mat_file.NormalTexture).empty())
- {
- auto src_file = fmt::format("{0}{1}{2}", config.InputBaseAssetFilePath.c_str(), PLATFORM_OS_BACKSLASH, mat_file.NormalTexture);
- auto dst_file = fmt::format("{0}{1}{2}", dst_dir, PLATFORM_OS_BACKSLASH, mat_file.NormalTexture);
-
- create_base_dir_fn(dst_file);
- ZEngine::Helpers::secure_strcpy(mat_file.NormalTexture, MAX_FILE_PATH_COUNT, dst_file.c_str());
-
- auto& sf = src_tex_files.push_use({});
- auto& df = dst_tex_files.push_use({});
-
- sf.init(scratch.Arena, src_file.c_str());
- df.init(scratch.Arena, dst_file.c_str());
- }
-
- if (!std::string_view(mat_file.OpacityTexture).empty())
- {
- auto src_file = fmt::format("{0}{1}{2}", config.InputBaseAssetFilePath.c_str(), PLATFORM_OS_BACKSLASH, mat_file.OpacityTexture);
- auto dst_file = fmt::format("{0}{1}{2}", dst_dir, PLATFORM_OS_BACKSLASH, mat_file.OpacityTexture);
-
- create_base_dir_fn(dst_file);
-
- ZEngine::Helpers::secure_strcpy(mat_file.OpacityTexture, MAX_FILE_PATH_COUNT, dst_file.c_str());
-
- auto& sf = src_tex_files.push_use({});
- auto& df = dst_tex_files.push_use({});
-
- sf.init(scratch.Arena, src_file.c_str());
- df.init(scratch.Arena, dst_file.c_str());
- }
-
- if (!std::string_view(mat_file.SpecularTexture).empty())
- {
- auto src_file = fmt::format("{0}{1}{2}", config.InputBaseAssetFilePath.c_str(), PLATFORM_OS_BACKSLASH, mat_file.SpecularTexture);
- auto dst_file = fmt::format("{0}{1}{2}", dst_dir, PLATFORM_OS_BACKSLASH, mat_file.SpecularTexture);
-
- create_base_dir_fn(dst_file);
-
- ZEngine::Helpers::secure_strcpy(mat_file.SpecularTexture, MAX_FILE_PATH_COUNT, dst_file.c_str());
-
- auto& sf = src_tex_files.push_use({});
- auto& df = dst_tex_files.push_use({});
-
- sf.init(scratch.Arena, src_file.c_str());
- df.init(scratch.Arena, dst_file.c_str());
- }
- }
- /*
- * Texture files processing
- * (1) Ensuring Scene sub-dir is created
- * (2) Copying files to destination
- */
-
- ZENGINE_VALIDATE_ASSERT(src_tex_files.size() == dst_tex_files.size(), "source files count can't be diff of destination files count")
- for (int i = 0; i < src_tex_files.size(); ++i)
+ if (tex.Path.empty())
{
- auto src = fs::absolute(src_tex_files[i].c_str());
- auto dst = fs::absolute(dst_tex_files[i].c_str());
-
- std::ifstream in(src.c_str(), std::ios::binary);
- std::ofstream out(dst.c_str(), std::ios::binary);
-
- if (!in.is_open() || !out.is_open())
- {
- in.close();
- out.close();
- continue;
- }
-
- out << in.rdbuf();
-
- in.close();
- out.close();
+ continue;
}
- ZReleaseScratch(scratch);
+ auto src_file = fmt::format("{0}{1}{2}", config.InputBaseAssetFilePath.c_str(), PLATFORM_OS_BACKSLASH, tex.Path.c_str());
+ auto dst_file = fmt::format("{0}{1}{2}", dst_dir, PLATFORM_OS_BACKSLASH, tex.Path.c_str());
- std::string output_material_file = fmt::format("{}.zematerials", config.AssetFilename.c_str());
- std::string fullname_path = fmt::format("{0}{1}{2}{3}{4}", config.OutputWorkingSpacePath.c_str(), PLATFORM_OS_BACKSLASH, config.OutputMaterialsPath.c_str(), PLATFORM_OS_BACKSLASH, output_material_file.c_str());
- std::ofstream out(fullname_path, std::ios::binary | std::ios::trunc);
+ CreateBaseDirectoryFn(dst_file);
- if (out.is_open())
- {
- out.seekp(std::ios::beg);
+ auto& sf = src_tex_files.push_use({});
+ auto& df = dst_tex_files.push_use({});
- size_t material_total_count = importer_data.Scene.Materials.size();
- out.write(reinterpret_cast(&material_total_count), sizeof(size_t));
- out.write(reinterpret_cast(importer_data.Scene.Materials.data()), sizeof(ZEngine::Rendering::Meshes::MeshMaterial) * material_total_count);
-
- size_t mat_file_count = importer_data.Scene.MaterialFiles.size();
- out.write(reinterpret_cast(&mat_file_count), sizeof(size_t));
- for (auto& mat_file : importer_data.Scene.MaterialFiles)
- {
- Tetragrama::Helpers::SerializeStringData(out, mat_file.AlbedoTexture);
- Tetragrama::Helpers::SerializeStringData(out, mat_file.EmissiveTexture);
- Tetragrama::Helpers::SerializeStringData(out, mat_file.NormalTexture);
- Tetragrama::Helpers::SerializeStringData(out, mat_file.OpacityTexture);
- Tetragrama::Helpers::SerializeStringData(out, mat_file.SpecularTexture);
- }
- }
- out.close();
-
- importer_data.SerializedMaterialsPath.init(arena, output_material_file.c_str());
+ sf.init(scratch.Arena, src_file.c_str());
+ df.init(scratch.Arena, dst_file.c_str());
}
-
- if (!config.OutputModelFilePath.empty())
+ /*
+ * Texture files processing
+ * (1) Ensuring Scene sub-dir is created
+ * (2) Copying files to destination
+ */
+
+ ZENGINE_VALIDATE_ASSERT(src_tex_files.size() == dst_tex_files.size(), "source files count can't be diff of destination files count")
+ for (int i = 0; i < src_tex_files.size(); ++i)
{
- std::string output_model_file = fmt::format("{}.zemodel", config.AssetFilename.c_str());
- std::string fullname_path = fmt::format("{0}{1}{2}{3}{4}", config.OutputWorkingSpacePath.c_str(), PLATFORM_OS_BACKSLASH, config.OutputModelFilePath.c_str(), PLATFORM_OS_BACKSLASH, output_model_file.c_str());
- std::ofstream out(fullname_path, std::ios::binary | std::ios::trunc);
+ auto src = fs::absolute(src_tex_files[i].c_str());
+ auto dst = fs::absolute(dst_tex_files[i].c_str());
- if (out.is_open())
- {
- out.seekp(std::ios::beg);
-
- size_t local_transform_count = importer_data.Scene.LocalTransforms.size();
- out.write(reinterpret_cast(&local_transform_count), sizeof(size_t));
- out.write(reinterpret_cast(importer_data.Scene.LocalTransforms.data()), sizeof(glm::mat4) * local_transform_count);
-
- size_t gobal_transform_count = importer_data.Scene.GlobalTransforms.size();
- out.write(reinterpret_cast(&gobal_transform_count), sizeof(size_t));
- out.write(reinterpret_cast(importer_data.Scene.GlobalTransforms.data()), sizeof(glm::mat4) * gobal_transform_count);
-
- size_t node_hierarchy_count = importer_data.Scene.NodeHierarchies.size();
- out.write(reinterpret_cast(&node_hierarchy_count), sizeof(size_t));
- out.write(reinterpret_cast(importer_data.Scene.NodeHierarchies.data()), sizeof(ZEngine::Rendering::Scenes::SceneNodeHierarchy) * node_hierarchy_count);
-
- // Todo Kernel : This should be part of Move Engine to Arena
- //
- // Tetragrama::Helpers::SerializeStringArrayData(out, importer_data.Scene.Names);
- // Tetragrama::Helpers::SerializeStringArrayData(out, importer_data.Scene.MaterialNames);
- Tetragrama::Helpers::SerializeMapData(out, importer_data.Scene.NodeNames);
- Tetragrama::Helpers::SerializeMapData(out, importer_data.Scene.NodeMeshes);
- Tetragrama::Helpers::SerializeMapData(out, importer_data.Scene.NodeMaterials);
- }
-
- out.close();
+ std::ifstream in(src.c_str(), std::ios::binary);
+ std::ofstream out(dst.c_str(), std::ios::binary);
- importer_data.SerializedModelPath.init(arena, output_model_file.c_str());
- }
- }
-
- ImporterData AssimpImporter::DeserializeImporterData(ZEngine::Core::Memory::ArenaAllocator* arena, std::string_view model_path, std::string_view mesh_path, std::string_view material_path)
- {
- ImporterData deserialized_data = {};
-
- if (!mesh_path.empty())
- {
- std::ifstream in(mesh_path.data(), std::ios::binary);
-
- if (in.is_open())
+ if (!in.is_open() || !out.is_open())
{
- in.seekg(0, std::ios::beg);
-
- size_t mesh_count;
- in.read(reinterpret_cast(&mesh_count), sizeof(size_t));
- deserialized_data.Scene.Meshes.resize(mesh_count);
- in.read(reinterpret_cast(deserialized_data.Scene.Meshes.data()), sizeof(ZEngine::Rendering::Meshes::MeshVNext) * mesh_count);
-
- size_t indices_count;
- in.read(reinterpret_cast(&indices_count), sizeof(size_t));
- deserialized_data.Scene.Indices.resize(indices_count);
- in.read(reinterpret_cast(deserialized_data.Scene.Indices.data()), sizeof(uint32_t) * indices_count);
-
- size_t vertice_count;
- in.read(reinterpret_cast(&vertice_count), sizeof(size_t));
- deserialized_data.Scene.Vertices.resize(vertice_count);
- in.read(reinterpret_cast(deserialized_data.Scene.Vertices.data()), sizeof(float) * vertice_count);
+ in.close();
+ out.close();
+ continue;
}
- in.close();
- }
- if (!material_path.empty())
- {
- std::ifstream in(material_path.data(), std::ios::binary);
-
- if (in.is_open())
- {
- in.seekg(0, std::ios::beg);
-
- size_t material_total_count;
- in.read(reinterpret_cast(&material_total_count), sizeof(size_t));
- deserialized_data.Scene.Materials.resize(material_total_count);
- in.read(reinterpret_cast(deserialized_data.Scene.Materials.data()), sizeof(ZEngine::Rendering::Meshes::MeshMaterial) * material_total_count);
+ out << in.rdbuf();
- size_t mat_file_count;
- in.read(reinterpret_cast(&mat_file_count), sizeof(size_t));
- deserialized_data.Scene.MaterialFiles.resize(mat_file_count);
-
- Array textures = {};
- textures.init(arena, 5, 5);
- for (auto& mat_file : deserialized_data.Scene.MaterialFiles)
- {
- Tetragrama::Helpers::DeserializeStringData(arena, in, textures[0]);
- Tetragrama::Helpers::DeserializeStringData(arena, in, textures[1]);
- Tetragrama::Helpers::DeserializeStringData(arena, in, textures[2]);
- Tetragrama::Helpers::DeserializeStringData(arena, in, textures[3]);
- Tetragrama::Helpers::DeserializeStringData(arena, in, textures[4]);
-
- ZEngine::Helpers::secure_strcpy(mat_file.AlbedoTexture, MAX_FILE_PATH_COUNT, textures[0].c_str());
- ZEngine::Helpers::secure_strcpy(mat_file.EmissiveTexture, MAX_FILE_PATH_COUNT, textures[1].c_str());
- ZEngine::Helpers::secure_strcpy(mat_file.NormalTexture, MAX_FILE_PATH_COUNT, textures[2].c_str());
- ZEngine::Helpers::secure_strcpy(mat_file.OpacityTexture, MAX_FILE_PATH_COUNT, textures[3].c_str());
- ZEngine::Helpers::secure_strcpy(mat_file.SpecularTexture, MAX_FILE_PATH_COUNT, textures[4].c_str());
- }
- }
in.close();
+ out.close();
}
- if (!model_path.empty())
+ ZReleaseScratch(scratch);
+
+ /*
+ * Update texture path
+ */
+ for (auto& tex : textures)
{
- std::ifstream in(model_path.data(), std::ios::binary);
- if (in.is_open())
- {
- in.seekg(0, std::ios::beg);
-
- size_t local_transform_count;
- in.read(reinterpret_cast(&local_transform_count), sizeof(size_t));
- deserialized_data.Scene.LocalTransforms.resize(local_transform_count);
- in.read(reinterpret_cast(deserialized_data.Scene.LocalTransforms.data()), sizeof(glm::mat4) * local_transform_count);
-
- size_t gobal_transform_count;
- in.read(reinterpret_cast(&gobal_transform_count), sizeof(size_t));
- deserialized_data.Scene.GlobalTransforms.resize(gobal_transform_count);
- in.read(reinterpret_cast(deserialized_data.Scene.GlobalTransforms.data()), sizeof(glm::mat4) * gobal_transform_count);
-
- size_t node_hierarchy_count;
- in.read(reinterpret_cast(&node_hierarchy_count), sizeof(size_t));
- deserialized_data.Scene.NodeHierarchies.resize(node_hierarchy_count);
- in.read(reinterpret_cast(deserialized_data.Scene.NodeHierarchies.data()), sizeof(ZEngine::Rendering::Scenes::SceneNodeHierarchy) * node_hierarchy_count);
-
- // Todo Kernel : This should be part of Move Engine to Arena
- //
- // DeserializeStringArrayData(arena, in, deserialized_data.Scene.Names);
- // DeserializeStringArrayData(arena, in, deserialized_data.Scene.MaterialNames);
- DeserializeMapData(arena, in, deserialized_data.Scene.NodeNames);
- DeserializeMapData(arena, in, deserialized_data.Scene.NodeMeshes);
- DeserializeMapData(arena, in, deserialized_data.Scene.NodeMaterials);
- }
- in.close();
+ auto new_path = fmt::format("{0}{1}{2}{3}{4}", config.OutputTextureFilesPath.c_str(), PLATFORM_OS_BACKSLASH, config.AssetName.c_str(), PLATFORM_OS_BACKSLASH, tex.Path.c_str());
+ tex.Path.clear();
+ tex.Path.append(new_path.c_str());
}
-
- return deserialized_data;
}
glm::mat4 AssimpImporter::ConvertToMat4(const aiMatrix4x4& m)
diff --git a/Tetragrama/Importers/AssimpImporter.h b/Tetragrama/Importers/AssimpImporter.h
index b9159f77..bb538677 100644
--- a/Tetragrama/Importers/AssimpImporter.h
+++ b/Tetragrama/Importers/AssimpImporter.h
@@ -1,8 +1,10 @@
#pragma once
+#include
#include
#include
#include
#include
+#include
namespace Tetragrama::Importers
{
@@ -24,9 +26,8 @@ namespace Tetragrama::Importers
AssimpImporter();
virtual ~AssimpImporter();
- virtual std::future ImportAsync(std::string_view filename, ImportConfiguration config = {}) override;
- virtual void SerializeImporterData(ZEngine::Core::Memory::ArenaAllocator* arena, ImporterData& data, const ImportConfiguration&) override;
- virtual ImporterData DeserializeImporterData(ZEngine::Core::Memory::ArenaAllocator* arena, std::string_view model_path, std::string_view mesh_path, std::string_view material_path) override;
+ virtual std::future ImportAsync(const char* filename, ImportConfiguration& config) override;
+ void CopyTextureFiles(ZEngine::Core::Memory::ArenaAllocator*, ZEngine::Core::Containers::Array&, const ImportConfiguration&);
private:
uint32_t m_flags;
@@ -34,12 +35,12 @@ namespace Tetragrama::Importers
friend struct AssimpProgressHandler;
- void ExtractMeshes(const aiScene*, ImporterData&);
- void ExtractMaterials(const aiScene*, ImporterData&);
- void ExtractTextures(const aiScene*, ImporterData&);
- void CreateHierachyScene(const aiScene*, ImporterData&);
+ void ExtractMeshes(ZEngine::Core::Memory::ArenaAllocator*, const aiScene*, uuids::uuid_random_generator&, AssetMesh&);
+ void ExtractMaterials(ZEngine::Core::Memory::ArenaAllocator*, const aiScene*, uuids::uuid_random_generator&, ZEngine::Core::Containers::Array&, AssetNodeHierarchy&);
+ void ExtractTextures(ZEngine::Core::Memory::ArenaAllocator* arena, const aiScene*, uuids::uuid_random_generator&, ZEngine::Core::Containers::Array&, ZEngine::Core::Containers::Array&);
+ void CreateHierachy(ZEngine::Core::Memory::ArenaAllocator* arena, const aiScene*, uuids::uuid_random_generator&, AssetNodeHierarchy&, AssetMesh&, ZEngine::Core::Containers::Array&);
- void TraverseNode(const aiScene*, ZEngine::Rendering::Scenes::SceneRawData* const, const aiNode*, int parent_node_id, int depth_level);
+ void TraverseNode(ZEngine::Core::Memory::ArenaAllocator* arena, const aiScene*, const aiNode*, AssetNodeHierarchy&, AssetMesh&, ZEngine::Core::Containers::Array&, int parent_node_id, int depth_level);
glm::mat4 ConvertToMat4(const aiMatrix4x4& m);
};
} // namespace Tetragrama::Importers
\ No newline at end of file
diff --git a/Tetragrama/Importers/IAssetImporter.cpp b/Tetragrama/Importers/IAssetImporter.cpp
new file mode 100644
index 00000000..0dc23524
--- /dev/null
+++ b/Tetragrama/Importers/IAssetImporter.cpp
@@ -0,0 +1,396 @@
+#include
+#include
+#include
+#include
+
+using namespace uuids;
+using namespace ZEngine::Helpers;
+using namespace Tetragrama::Helpers;
+using namespace ZEngine::Core::Containers;
+
+namespace Tetragrama::Importers
+{
+ int AddNode(AssetNodeHierarchy& hierarchy, int parent, int depth)
+ {
+ if (depth < 0)
+ {
+ return -1;
+ }
+
+ int node_id = (int) hierarchy.Hierarchies.size();
+
+ hierarchy.Hierarchies.push({.Parent = parent});
+ hierarchy.LocalTransforms.push(glm::mat4(1.0f));
+ hierarchy.GlobalTransforms.push(glm::mat4(1.0f));
+
+ if (parent > -1)
+ {
+ int first_child = hierarchy.Hierarchies[parent].FirstChild;
+
+ if (first_child == -1)
+ {
+ hierarchy.Hierarchies[parent].FirstChild = node_id;
+ }
+ else
+ {
+ int right_sibling = hierarchy.Hierarchies[first_child].RightSibling;
+ if (right_sibling > -1)
+ {
+ // iterate nextSibling_ indices
+ for (right_sibling = first_child; hierarchy.Hierarchies[right_sibling].RightSibling != -1; right_sibling = hierarchy.Hierarchies[right_sibling].RightSibling)
+ {
+ }
+ hierarchy.Hierarchies[right_sibling].RightSibling = node_id;
+ }
+ else
+ {
+ hierarchy.Hierarchies[first_child].RightSibling = node_id;
+ }
+ }
+ }
+ hierarchy.Hierarchies[node_id].DepthLevel = depth;
+ hierarchy.Hierarchies[node_id].RightSibling = -1;
+ hierarchy.Hierarchies[node_id].FirstChild = -1;
+
+ return node_id;
+ }
+
+ void IAssetImporter::Initialize(ZEngine::Core::Memory::ArenaAllocator* arena)
+ {
+ arena->CreateSubArena(ZMega(150), &Arena);
+ }
+
+ void IAssetImporter::SetOnCompleteCallback(on_import_complete_fn callback)
+ {
+ m_complete_callback = callback;
+ }
+
+ void IAssetImporter::SetOnProgressCallback(on_import_progress_fn callback)
+ {
+ m_progress_callback = callback;
+ }
+
+ void IAssetImporter::SetOnErrorCallback(on_import_error_fn callback)
+ {
+ m_error_callback = callback;
+ }
+
+ void IAssetImporter::SetOnLogCallback(on_import_log_fn callback)
+ {
+ m_log_callback = callback;
+ }
+
+ bool IAssetImporter::IsImporting()
+ {
+ return m_is_importing.load(std::memory_order_acquire);
+ }
+
+ AssetImporterOutput IAssetImporter::SerializeMeshAssetFile(ZEngine::Core::Memory::ArenaAllocator* arena, AssetMesh& mesh, AssetNodeHierarchy& hierarchies, const ImportConfiguration& config)
+ {
+ AssetImporterOutput output = {};
+
+ if (config.OutputAssetFile.empty())
+ {
+ return output;
+ }
+
+ std::string fullname_path = fmt::format("{0}{1}{2}{3}{4}", config.OutputWorkingSpacePath.c_str(), PLATFORM_OS_BACKSLASH, config.OutputAssetsPath.c_str(), PLATFORM_OS_BACKSLASH, config.OutputAssetFile.c_str());
+ std::ofstream out(fullname_path, std::ios::binary | std::ios::trunc);
+
+ if (!out.is_open())
+ {
+ out.close();
+ return output;
+ }
+
+ out.seekp(std::ios::beg);
+ /*
+ * Magic Headers
+ */
+ WriteBinary(out, ZEMESH_MAGIC);
+ WriteBinary(out, ASSET_FILE_VERSION);
+ /*
+ * Asset Mesh
+ */
+ WriteBinary(out, mesh.MeshUUID);
+ WriteBinaryArray(out, ArrayView{mesh.Vertices});
+ WriteBinaryArray(out, ArrayView{mesh.Indices});
+ WriteBinaryArray(out, ArrayView{mesh.SubMeshes});
+
+ /*
+ * Asset AssetNodeHierarchy
+ */
+ WriteBinary(out, hierarchies.NodeHierarchyUUID);
+ WriteBinary(out, hierarchies.MeshUUID);
+ WriteBinaryArray(out, ArrayView{hierarchies.Hierarchies});
+ WriteBinaryArray(out, ArrayView{hierarchies.LocalTransforms});
+ WriteBinaryArray(out, ArrayView{hierarchies.GlobalTransforms});
+
+ uint32_t name_count = static_cast(hierarchies.Names.size());
+ WriteBinary(out, name_count);
+ for (const auto& name : hierarchies.Names)
+ {
+ WriteBinaryString(out, name);
+ }
+
+ uint32_t material_name_count = static_cast(hierarchies.MaterialNames.size());
+ WriteBinary(out, material_name_count);
+ for (const auto& name : hierarchies.MaterialNames)
+ {
+ WriteBinaryString(out, name);
+ }
+
+ WriteBinaryHashMap(out, hierarchies.NodeNames);
+ WriteBinaryHashMap(out, hierarchies.NodeMeshes);
+ WriteBinaryHashMap(out, hierarchies.NodeMaterials);
+
+ out.close();
+
+ output = {.Type = AssetFileType::MESH, .Path = fmt::format("{0}{1}{2}", config.OutputAssetsPath.c_str(), PLATFORM_OS_BACKSLASH, config.OutputAssetFile.c_str()), .RootPath = config.OutputWorkingSpacePath.c_str()};
+ return output;
+ }
+
+ AssetImporterOutput IAssetImporter::SerializeMaterialAssetFile(ZEngine::Core::Memory::ArenaAllocator* arena, AssetMaterial& material, const ImportConfiguration& config)
+ {
+
+ AssetImporterOutput output = {};
+
+ std::string asset_mat_filename = fmt::format("{0}{1}", material.Name.c_str(), ".zematerial");
+ std::string fullname_path = fmt::format("{0}{1}{2}{3}{4}", config.OutputWorkingSpacePath.c_str(), PLATFORM_OS_BACKSLASH, config.OutputAssetsPath.c_str(), PLATFORM_OS_BACKSLASH, asset_mat_filename.c_str());
+ std::ofstream out(fullname_path, std::ios::binary | std::ios::trunc);
+
+ if (!out.is_open())
+ {
+ out.close();
+ return output;
+ }
+
+ out.seekp(std::ios::beg);
+ /*
+ * Magic Headers
+ */
+ WriteBinary(out, ZEMATERIAL_MAGIC);
+ WriteBinary(out, ASSET_FILE_VERSION);
+
+ /*
+ * Asset Materials
+ */
+ WriteBinaryString(out, material.Name);
+ WriteBinary(out, material.MaterialUUID);
+ WriteBinary(out, material.AlbedoTexUUID);
+ WriteBinary(out, material.EmissiveTexUUID);
+ WriteBinary(out, material.NormalTexUUID);
+ WriteBinary(out, material.OpacityTexUUID);
+ WriteBinary(out, material.SpecularTexUUID);
+ out.write(reinterpret_cast(material.AmbientColor), sizeof(material.AmbientColor));
+ out.write(reinterpret_cast(material.AlbedoColor), sizeof(material.AlbedoColor));
+ out.write(reinterpret_cast(material.EmissiveColor), sizeof(material.EmissiveColor));
+ out.write(reinterpret_cast(material.RoughnessColor), sizeof(material.RoughnessColor));
+ out.write(reinterpret_cast(material.SpecularColor), sizeof(material.SpecularColor));
+ out.write(reinterpret_cast(material.Factors), sizeof(material.Factors));
+
+ out.close();
+
+ output = {.Type = AssetFileType::MATERIAL, .Path = fmt::format("{0}{1}{2}", config.OutputAssetsPath.c_str(), PLATFORM_OS_BACKSLASH, asset_mat_filename.c_str()), .RootPath = config.OutputWorkingSpacePath.c_str()};
+ return output;
+ }
+
+ AssetImporterOutput IAssetImporter::SerializeTextureAssetFiles(ZEngine::Core::Memory::ArenaAllocator* arena, ArrayView textures, const ImportConfiguration& config)
+ {
+ AssetImporterOutput output = {};
+
+ std::string asset_tex_filename = fmt::format("{0}{1}", config.AssetName.c_str(), ".zetextures");
+ std::string fullname_path = fmt::format("{0}{1}{2}{3}{4}", config.OutputWorkingSpacePath.c_str(), PLATFORM_OS_BACKSLASH, config.OutputAssetsPath.c_str(), PLATFORM_OS_BACKSLASH, asset_tex_filename.c_str());
+ std::ofstream out(fullname_path, std::ios::binary | std::ios::trunc);
+
+ if (!out.is_open())
+ {
+ out.close();
+ return output;
+ }
+
+ out.seekp(std::ios::beg);
+ /*
+ * Magic Headers
+ */
+ WriteBinary(out, ZETEXTURES_MAGIC);
+ WriteBinary(out, ASSET_FILE_VERSION);
+ /*
+ * Asset Textures
+ */
+ uint32_t texture_count = (uint32_t) textures.size();
+ WriteBinary(out, texture_count);
+ for (unsigned i = 0; i < texture_count; ++i)
+ {
+ auto& tex = textures[i];
+ WriteBinary(out, tex.TextureUUID);
+ WriteBinaryString(out, tex.Path);
+ }
+
+ out.close();
+
+ output = {.Type = AssetFileType::TEXTURES, .Path = fmt::format("{0}{1}{2}", config.OutputAssetsPath.c_str(), PLATFORM_OS_BACKSLASH, asset_tex_filename.c_str()), .RootPath = config.OutputWorkingSpacePath.c_str()};
+ return output;
+ }
+
+ void IAssetImporter::DeserializeMeshAssetFile(ZEngine::Core::Memory::ArenaAllocator* arena, const char* asset_file, AssetMesh& mesh, AssetNodeHierarchy& hierarchies)
+ {
+ if (!ZEngine::Helpers::secure_strlen(asset_file))
+ {
+ return;
+ }
+
+ std::ifstream in(asset_file, std::ios::binary);
+
+ if (!in.is_open())
+ {
+ in.close();
+ return;
+ }
+
+ in.seekg(std::ios::beg);
+
+ uint32_t scene_magic;
+ uint32_t scene_version;
+ ReadBinary(in, scene_magic);
+ ReadBinary(in, scene_version);
+
+ if (scene_magic != ZEMESH_MAGIC && scene_version != ASSET_FILE_VERSION)
+ {
+ in.close();
+ return;
+ }
+
+ /*
+ * Asset Mesh
+ */
+ ReadBinary(in, mesh.MeshUUID);
+ ReadBinaryArray(arena, in, mesh.Vertices);
+ ReadBinaryArray(arena, in, mesh.Indices);
+ ReadBinaryArray(arena, in, mesh.SubMeshes);
+
+ /*
+ * Asset AssetNodeHierarchy
+ */
+ ReadBinary(in, hierarchies.NodeHierarchyUUID);
+ ReadBinary(in, hierarchies.MeshUUID);
+ ReadBinaryArray(arena, in, hierarchies.Hierarchies);
+ ReadBinaryArray(arena, in, hierarchies.LocalTransforms);
+ ReadBinaryArray(arena, in, hierarchies.GlobalTransforms);
+
+ uint32_t name_count = 0;
+ ReadBinary(in, name_count);
+ hierarchies.Names.init(arena, name_count, name_count);
+ for (int i = 0; i < name_count; ++i)
+ {
+ auto& name = hierarchies.Names[i];
+ ReadBinaryString(arena, in, name);
+ }
+
+ uint32_t material_name_count = 0;
+ ReadBinary(in, material_name_count);
+ hierarchies.MaterialNames.init(arena, material_name_count, material_name_count);
+ for (int i = 0; i < material_name_count; ++i)
+ {
+ auto& name = hierarchies.MaterialNames[i];
+ ReadBinaryString(arena, in, name);
+ }
+
+ ReadHashMap(arena, in, hierarchies.NodeNames);
+ ReadHashMap(arena, in, hierarchies.NodeMeshes);
+ ReadHashMap(arena, in, hierarchies.NodeMaterials);
+
+ in.close();
+ }
+
+ void IAssetImporter::DeserializeMaterialAssetFile(ZEngine::Core::Memory::ArenaAllocator* arena, const char* asset_file, AssetMaterial& material)
+ {
+ if (!ZEngine::Helpers::secure_strlen(asset_file))
+ {
+ return;
+ }
+
+ std::ifstream in(asset_file, std::ios::binary);
+
+ if (!in.is_open())
+ {
+ in.close();
+ return;
+ }
+
+ in.seekg(std::ios::beg);
+
+ uint32_t scene_magic;
+ uint32_t scene_version;
+ ReadBinary(in, scene_magic);
+ ReadBinary(in, scene_version);
+
+ if (scene_magic != ZEMATERIAL_MAGIC && scene_version != ASSET_FILE_VERSION)
+ {
+ in.close();
+ return;
+ }
+
+ /*
+ * Asset Materials
+ */
+ ReadBinary(in, material.MaterialUUID);
+ ReadBinary(in, material.AlbedoTexUUID);
+ ReadBinary(in, material.EmissiveTexUUID);
+ ReadBinary(in, material.NormalTexUUID);
+ ReadBinary(in, material.OpacityTexUUID);
+ ReadBinary(in, material.SpecularTexUUID);
+ in.read(reinterpret_cast(material.AmbientColor), sizeof(material.AmbientColor));
+ in.read(reinterpret_cast(material.AlbedoColor), sizeof(material.AlbedoColor));
+ in.read(reinterpret_cast(material.EmissiveColor), sizeof(material.EmissiveColor));
+ in.read(reinterpret_cast(material.RoughnessColor), sizeof(material.RoughnessColor));
+ in.read(reinterpret_cast(material.SpecularColor), sizeof(material.SpecularColor));
+ in.read(reinterpret_cast(material.Factors), sizeof(material.Factors));
+
+ in.close();
+ }
+
+ void IAssetImporter::DeserializeTextureAssetFile(ZEngine::Core::Memory::ArenaAllocator* arena, const char* asset_file, ZEngine::Core::Containers::Array& textures)
+ {
+ if (!ZEngine::Helpers::secure_strlen(asset_file))
+ {
+ return;
+ }
+
+ std::ifstream in(asset_file, std::ios::binary);
+
+ if (!in.is_open())
+ {
+ in.close();
+ return;
+ }
+
+ in.seekg(std::ios::beg);
+
+ uint32_t scene_magic;
+ uint32_t scene_version;
+ ReadBinary(in, scene_magic);
+ ReadBinary(in, scene_version);
+
+ if (scene_magic != ZETEXTURES_MAGIC && scene_version != ASSET_FILE_VERSION)
+ {
+ in.close();
+ return;
+ }
+
+ /*
+ * Asset Textures
+ */
+ uint32_t texture_count = 0;
+ ReadBinary(in, texture_count);
+ textures.init(arena, texture_count, texture_count);
+ for (int i = 0; i < texture_count; ++i)
+ {
+ auto& tex = textures[i];
+ ReadBinary(in, tex.TextureUUID);
+ ReadBinaryString(arena, in, tex.Path);
+ }
+
+ in.close();
+ }
+} // namespace Tetragrama::Importers
\ No newline at end of file
diff --git a/Tetragrama/Importers/IAssetImporter.h b/Tetragrama/Importers/IAssetImporter.h
index 19962424..f3f74812 100644
--- a/Tetragrama/Importers/IAssetImporter.h
+++ b/Tetragrama/Importers/IAssetImporter.h
@@ -1,4 +1,5 @@
#pragma once
+#include
#include
#include