diff --git a/Samples/RPG/Assets/Assets.xml b/Samples/RPG/Assets/Assets.xml index 5fda775..d20b17c 100644 --- a/Samples/RPG/Assets/Assets.xml +++ b/Samples/RPG/Assets/Assets.xml @@ -9,26 +9,6 @@ - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/Samples/RPG/Assets/Scenes/GameMap.xml b/Samples/RPG/Assets/Scenes/GameMap.xml index d256593..9c7b0ae 100644 --- a/Samples/RPG/Assets/Scenes/GameMap.xml +++ b/Samples/RPG/Assets/Scenes/GameMap.xml @@ -25,84 +25,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Src/Editor/CMakeLists.txt b/Src/Editor/CMakeLists.txt index 0575ea5..4d6f361 100644 --- a/Src/Editor/CMakeLists.txt +++ b/Src/Editor/CMakeLists.txt @@ -10,12 +10,14 @@ set(SRC_FILES "imp/cpp/UI/TabContainer.cpp" "imp/cpp/UI/View/IView.cpp" - "imp/cpp/UI/View/Asset.cpp" + "imp/cpp/UI/View/FilePreview.cpp" "imp/cpp/UI/View/AssetBrowser.cpp" "imp/cpp/UI/View/Console.cpp" "imp/cpp/UI/View/Nodes.cpp" "imp/cpp/UI/View/Package.cpp" "imp/cpp/UI/View/Scene.cpp" + "imp/cpp/UI/View/Game.cpp" + "imp/cpp/UI/View/Asset.cpp" "imp/cpp/UI/View/Properties.cpp" # imgui diff --git a/Src/Editor/imp/cpp/Editor.cpp b/Src/Editor/imp/cpp/Editor.cpp index 8fda88f..5f8ebd4 100644 --- a/Src/Editor/imp/cpp/Editor.cpp +++ b/Src/Editor/imp/cpp/Editor.cpp @@ -26,6 +26,7 @@ #include #include +#include #include @@ -41,15 +42,46 @@ namespace ia::iae ImDrawData *g_imDrawData{}; IVec2 g_windowExtent{800, 600}; + Map g_assetNameMap; + + SIZE_T g_uniqueNameCounter{0}; + + String generate_unique_asset_name() + { + return BuildString("Asset_", g_uniqueNameCounter++); + } + VOID Editor::LoadProject(IN CONST String &directory) { m_activeProject = Project::Load(directory); } - VOID Editor::OpenAsset(IN Path path) + VOID Editor::OpenFile(IN Path path) + { + const auto assetName = AssetManager::GetAssetName(path.string().c_str()); + if (assetName.size()) + { + UI::GetAssetView()->Open(assetName); + UI::OpenAssetView(); + } + else + { + UI::GetFilePreviewView()->Open(path); + UI::OpenFilePreviewView(); + } + } + + VOID Editor::MarkAsAsset(IN Path path) + { + const auto assetName = generate_unique_asset_name(); + AssetManager::AssignAssetName(AssetManager::LoadTexture(path.string().c_str()), assetName); + UI::CloseFilePreviewView(); + UI::GetAssetView()->Open(assetName); + UI::OpenAssetView(); + } + + VOID Editor::RemoveFromAssets(IN CONST String &assetName) { - UI::GetAssetView()->Open(path); - UI::FocusAssetView(); } INT32 Editor::Run(IN INT32 argc, IN PCCHAR argv[]) diff --git a/Src/Editor/imp/cpp/UI/TabContainer.cpp b/Src/Editor/imp/cpp/UI/TabContainer.cpp index d8a57e1..ed38ee5 100644 --- a/Src/Editor/imp/cpp/UI/TabContainer.cpp +++ b/Src/Editor/imp/cpp/UI/TabContainer.cpp @@ -20,7 +20,9 @@ namespace ia::iae { INT32 g_tabContainerCount{0}; - TabContainer::TabContainer() : m_containerID(BuildString("TabContainer##", g_tabContainerCount++)), m_tabBarID(BuildString("TabBar##", g_tabContainerCount++)) + TabContainer::TabContainer() + : m_containerID(BuildString("TabContainer##", g_tabContainerCount++)), + m_tabBarID(BuildString("TabBar##", g_tabContainerCount++)) { } @@ -52,9 +54,10 @@ namespace ia::iae m_pendingActiveTabName = nullptr; } - if (ImGui::BeginTabItem(v->Value->IconAndName().c_str(), nullptr, flags)) + BOOL* isOpen = v->Value.IsCloseable ? &v->Value.IsOpen : nullptr; + if (ImGui::BeginTabItem(v->Value.View->IconAndName().c_str(), isOpen, flags)) { - v->Value->Render(); + v->Value.View->Render(); ImGui::EndTabItem(); m_activeTabName = v->Key.c_str(); @@ -68,20 +71,20 @@ namespace ia::iae VOID TabContainer::Update() { for (const auto &t : m_tabViews) - t->Value->Update(); + t->Value.View->Update(); } VOID TabContainer::ProcessEvent(IN SDL_Event *event) { for (const auto &t : m_tabViews) - t->Value->ProcessEvent(event); + t->Value.View->ProcessEvent(event); } - VOID TabContainer::AddTab(IN CONST String &name, IN IView *view) + VOID TabContainer::AddTab(IN CONST String &name, IN IView *view, IN BOOL isCloseable) { RemoveTab(name); view->Initialize(); - m_tabViews[name] = view; + m_tabViews[name] = Tab{.View = view, .IsCloseable = isCloseable}; if (!m_activeTabName) m_activeTabName = name.c_str(); } @@ -90,10 +93,25 @@ namespace ia::iae { if (!m_tabViews.contains(name)) return; - if (m_tabViews[name]) - m_tabViews[name]->Terminate(); - delete m_tabViews[name]; - m_tabViews[name] = nullptr; + m_tabViews[name].IsOpen = false; + if (m_tabViews[name].View) + m_tabViews[name].View->Terminate(); + delete m_tabViews[name].View; + m_tabViews[name] = {}; + } + + VOID TabContainer::OpenTab(IN CONST String &name) + { + if (!m_tabViews.contains(name)) + return; + m_tabViews[name].IsOpen = true; + } + + VOID TabContainer::CloseTab(IN CONST String &name) + { + if (!m_tabViews.contains(name)) + return; + m_tabViews[name].IsOpen = false; } VOID TabContainer::ChangeActiveTab(IN PCCHAR name) @@ -103,6 +121,6 @@ namespace ia::iae IView *TabContainer::GetTab(IN CONST String &name) { - return m_tabViews[name]; + return m_tabViews[name].View; } } // namespace ia::iae \ No newline at end of file diff --git a/Src/Editor/imp/cpp/UI/UI.cpp b/Src/Editor/imp/cpp/UI/UI.cpp index 4f25588..72aae66 100644 --- a/Src/Editor/imp/cpp/UI/UI.cpp +++ b/Src/Editor/imp/cpp/UI/UI.cpp @@ -21,22 +21,26 @@ #include #include #include +#include #include #include #include #include +#include #include namespace ia::iae { STATIC CONSTEXPR PCCHAR VIEW_NAME_ASSET_BROWSER = "AssetBrowser"; + STATIC CONSTEXPR PCCHAR VIEW_NAME_FILE_PREVIEW = "FilePreview"; STATIC CONSTEXPR PCCHAR VIEW_NAME_ASSET = "Asset"; STATIC CONSTEXPR PCCHAR VIEW_NAME_CONSOLE = "Console"; STATIC CONSTEXPR PCCHAR VIEW_NAME_NODES = "Nodes"; STATIC CONSTEXPR PCCHAR VIEW_NAME_PACKAGE = "Package"; STATIC CONSTEXPR PCCHAR VIEW_NAME_PROPERTIES = "Properties"; - STATIC CONSTEXPR PCCHAR VIEW_NAME_SCENE = "SCENE"; + STATIC CONSTEXPR PCCHAR VIEW_NAME_SCENE = "Scene"; + STATIC CONSTEXPR PCCHAR VIEW_NAME_GAME = "Game"; EXTERN IVec2 g_windowExtent; @@ -47,14 +51,36 @@ namespace ia::iae TabContainer g_tabContainerTM; TabContainer g_tabContainerTR; - VOID UI::FocusAssetView() + VOID UI::OpenFilePreviewView() { + g_tabContainerTR.OpenTab(VIEW_NAME_FILE_PREVIEW); + g_tabContainerTR.ChangeActiveTab(VIEW_NAME_FILE_PREVIEW); + } + + VOID UI::CloseFilePreviewView() + { + g_tabContainerTR.CloseTab(VIEW_NAME_FILE_PREVIEW); + } + + VOID UI::OpenAssetView() + { + g_tabContainerTR.OpenTab(VIEW_NAME_ASSET); g_tabContainerTR.ChangeActiveTab(VIEW_NAME_ASSET); } + VOID UI::CloseAssetView() + { + g_tabContainerTR.CloseTab(VIEW_NAME_ASSET); + } + class View_Asset *UI::GetAssetView() { - return (View_Asset*)g_tabContainerTR.GetTab(VIEW_NAME_ASSET); + return (View_Asset *) g_tabContainerTR.GetTab(VIEW_NAME_ASSET); + } + + class View_FilePreview *UI::GetFilePreviewView() + { + return (View_FilePreview *) g_tabContainerTR.GetTab(VIEW_NAME_FILE_PREVIEW); } VOID UI::Initialize() @@ -71,9 +97,14 @@ namespace ia::iae g_tabContainerTL.AddTab(VIEW_NAME_PACKAGE); g_tabContainerTM.AddTab(VIEW_NAME_SCENE); + g_tabContainerTM.AddTab(VIEW_NAME_GAME); g_tabContainerTR.AddTab(VIEW_NAME_PROPERTIES); - g_tabContainerTR.AddTab(VIEW_NAME_ASSET); + g_tabContainerTR.AddTab(VIEW_NAME_ASSET, true); + g_tabContainerTR.AddTab(VIEW_NAME_FILE_PREVIEW, true); + + g_tabContainerTR.CloseTab(VIEW_NAME_ASSET); + g_tabContainerTR.CloseTab(VIEW_NAME_FILE_PREVIEW); } VOID UI::Terminate() @@ -180,4 +211,13 @@ namespace ia::iae { ImGui::SetCursorPosY((rect.GetHeight() - height) / 2.0f); } + + VOID UI::DrawTextCentered(IN CONST ImVec2 &viewExtent, IN CONST String &text) + { + ImRect rect{{}, viewExtent}; + const auto textSize = ImGui::CalcTextSize(text.c_str()); + UI::AlignCursorHCenter(rect, textSize.x); + UI::AlignCursorVCenter(rect, textSize.y); + ImGui::Text("%s", text.c_str()); + } } // namespace ia::iae diff --git a/Src/Editor/imp/cpp/UI/View/Asset.cpp b/Src/Editor/imp/cpp/UI/View/Asset.cpp index 074adea..3094908 100644 --- a/Src/Editor/imp/cpp/UI/View/Asset.cpp +++ b/Src/Editor/imp/cpp/UI/View/Asset.cpp @@ -16,13 +16,13 @@ #include +#include +#include + +#include + namespace ia::iae { - struct AssetCacheEntry - { - - }; - VOID View_Asset::Initialize() { SetName("Asset"); @@ -37,13 +37,47 @@ namespace ia::iae { PreRender(); - if(m_assetPath.empty()) + if (!m_asset) { PostRender(); return; } - ImGui::Text("%s", m_assetPath.filename().string().c_str()); + STATIC CHAR NAME_BUFFER[256]; + + memcpy(NAME_BUFFER, m_assetName.c_str(), m_assetName.size() + 1); + ImGui::Text("Name: "); + ImGui::SameLine(); + ImGui::InputText("##name", NAME_BUFFER, sizeof(NAME_BUFFER)); + m_assetName = NAME_BUFFER; + + DrawAssetTypePicker(); + + switch (m_asset->GetType()) + { + case EAssetType::TEXTURE: + RenderTextureAsset(); + break; + + case EAssetType::SPRITE: + RenderSpriteAsset(); + break; + + case EAssetType::TILESHEET: + RenderTileSheetAsset(); + break; + + case EAssetType::SPRITESHEET: + RenderSpriteSheetAsset(); + break; + + case EAssetType::INVALID: + case EAssetType::SOUND: + case EAssetType::SCENE: + case EAssetType::PLUGIN: + case EAssetType::PACKAGE: + break; + } PostRender(); } @@ -56,14 +90,125 @@ namespace ia::iae { } - VOID View_Asset::Open(IN Path path) + VOID View_Asset::Open(IN String assetName) { - Close(); - m_assetPath = path; + m_assetName = assetName; + const auto asset = AssetManager::GetAssetByName(m_assetName); + m_assetImageHandle = RDC::BakeTexture(asset->GetHandle()->ImagePtr); + m_assetImageExtent = {asset->GetHandle()->ImagePtr->Width, asset->GetHandle()->ImagePtr->Height}; + m_asset = asset; + m_assetType = asset->GetType(); } VOID View_Asset::Close() { - m_assetPath = Path(); + m_assetName = ""; + m_asset = nullptr; + m_assetImageHandle = 0; + m_assetImageExtent = {}; + m_assetType = EAssetType::INVALID; + } + + VOID View_Asset::RenderTextureAsset() + { + const auto asset = (Asset_Texture *) m_asset; + DrawAssetImage(0.75f, {0, 0}); + } + + VOID View_Asset::RenderSpriteAsset() + { + const auto asset = (Asset_Sprite *) m_asset; + DrawAssetImage(0.75f, {0, 0}); + } + + VOID View_Asset::RenderTileSheetAsset() + { + const auto asset = (Asset_TileSheet *) m_asset; + + ImGui::Text("Tile Width: "); + ImGui::SameLine(); + ImGui::InputInt("##TileWidth", &asset->TileWidth()); + if (asset->TileWidth() < 1) + asset->TileWidth() = 1; + if (asset->TileWidth() > m_assetImageExtent.x) + asset->TileWidth() = m_assetImageExtent.x; + + ImGui::Text("Tile Height: "); + ImGui::SameLine(); + ImGui::InputInt("##TileHeight", &asset->TileHeight()); + if (asset->TileHeight() < 1) + asset->TileHeight() = 1; + if (asset->TileHeight() > m_assetImageExtent.y) + asset->TileHeight() = m_assetImageExtent.y; + + DrawAssetImage(0.75f, {asset->TileWidth(), asset->TileHeight()}); + } + + VOID View_Asset::RenderSpriteSheetAsset() + { + const auto asset = (Asset_SpriteSheet *) m_asset; + } + + VOID View_Asset::DrawAssetImage(IN FLOAT32 relativeWidth, IN IVec2 gridSize) + { + ImVec2 base_pos = ImGui::GetCursorScreenPos(); + + const auto ImageWidth = m_extent.x * relativeWidth; + const auto aspectRatio = + static_cast(m_assetImageExtent.y) / static_cast(m_assetImageExtent.x); + const auto ImageHeight = aspectRatio * ImageWidth; + + ImGui::Image((ImTextureRef) m_assetImageHandle, {ImageWidth, ImageHeight}); + + if((!gridSize.x) || (!gridSize.y)) + return; + + gridSize.x *= ImageWidth/m_assetImageExtent.x; + gridSize.y *= ImageHeight/m_assetImageExtent.y; + + ImDrawList *draw_list = ImGui::GetWindowDrawList(); + + auto gridCountX = ImageWidth / gridSize.x; + auto gridCountY = ImageHeight / gridSize.y; + + ImU32 grid_color = IM_COL32(200, 200, 200, 50); + float grid_thickness = 1.0f; + + ImGui::Dummy(ImVec2(ImageWidth, ImageHeight)); + + for (int i = 0; i <= gridCountX; ++i) + { + ImVec2 p1 = ImVec2(base_pos.x + i * gridSize.x, base_pos.y); + ImVec2 p2 = ImVec2(base_pos.x + i * gridSize.x, base_pos.y + ImageHeight); + draw_list->AddLine(p1, p2, grid_color, grid_thickness); + } + + for (int i = 0; i <= gridCountY; ++i) + { + ImVec2 p1 = ImVec2(base_pos.x, base_pos.y + i * gridSize.y); + ImVec2 p2 = ImVec2(base_pos.x + ImageWidth, base_pos.y + i * gridSize.y); + draw_list->AddLine(p1, p2, grid_color, grid_thickness); + } + } + + VOID View_Asset::DrawAssetTypePicker() + { + ImGui::Text("Asset Type: "); + ImGui::SameLine(); + ImGui::Combo("##", (INT32 *) &m_assetType, "None\0Texture\0Sprite\0TileSheet\0SpriteSheet\0"); + if (m_assetType != m_asset->GetType()) + { + ImGui::SameLine(); + if (ImGui::Button("Apply")) + { + if (m_assetType == EAssetType::INVALID) + { + Editor::Instance().RemoveFromAssets(m_assetName); + Close(); + UI::CloseAssetView(); + } + m_asset = AssetManager::ChangeAssetType(m_assetName, m_assetType); + } + } } } // namespace ia::iae \ No newline at end of file diff --git a/Src/Editor/imp/cpp/UI/View/AssetBrowser.cpp b/Src/Editor/imp/cpp/UI/View/AssetBrowser.cpp index 66d2503..18ea126 100644 --- a/Src/Editor/imp/cpp/UI/View/AssetBrowser.cpp +++ b/Src/Editor/imp/cpp/UI/View/AssetBrowser.cpp @@ -147,6 +147,6 @@ namespace ia::iae VOID View_AssetBrowser::OpenAsset(IN CONST std::filesystem::path &path) { - Editor::Instance().OpenAsset(path); + Editor::Instance().OpenFile(path); } } // namespace ia::iae \ No newline at end of file diff --git a/Src/Editor/imp/cpp/UI/View/FilePreview.cpp b/Src/Editor/imp/cpp/UI/View/FilePreview.cpp new file mode 100644 index 0000000..7644a3d --- /dev/null +++ b/Src/Editor/imp/cpp/UI/View/FilePreview.cpp @@ -0,0 +1,170 @@ +// IAEngine: 2D Game Engine by IA +// Copyright (C) 2025 IASoft (PVT) LTD (oss@iasoft.dev) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include + +#include +#include + +#include + +#include + +namespace ia::iae +{ + BOOL is_extension_one_of(IN PCCHAR ext, IN std::initializer_list values) + { + for (const auto &t : values) + { + if (!strcmp(ext, t)) + return true; + } + return false; + } + + Vector get_lines_of_file(IN CONST Path &path) + { + Vector result; + std::string line; + std::ifstream file(path); + while (std::getline(file, line)) + result.pushBack(line.c_str()); + return result; + } + + VOID View_FilePreview::Initialize() + { + SetName("File Preview"); + SetIcon(ICON_FA_MAGNIFYING_GLASS); + } + + VOID View_FilePreview::Terminate() + { + } + + VOID View_FilePreview::Render() + { + PreRender(); + + if (m_filePath.empty()) + { + PostRender(); + return; + } + + switch (m_fileType) + { + case EFileType::UNKNOWN: + RenderUnknownFile(); + break; + + case EFileType::TEXT: + RenderTextFile(); + break; + + case EFileType::IMAGE: + RenderImageFile(); + break; + } + + PostRender(); + } + + VOID View_FilePreview::Update() + { + } + + VOID View_FilePreview::OnEvent(IN SDL_Event *event) + { + } + + VOID View_FilePreview::Open(IN Path path) + { + Close(); + m_filePath = path; + m_fileType = EFileType::UNKNOWN; + + const auto ext = path.extension().string(); + if (is_extension_one_of(&ext[1], {"txt", "xml", "md", "cpp", "c", "hpp", "h"})) + { + m_fileType = EFileType::TEXT; + const auto lines = get_lines_of_file(path); + m_fileDataSize = lines.size(); + const auto fileData = new String[m_fileDataSize]; + for (SIZE_T i = 0; i < m_fileDataSize; i++) + fileData[i] = lines[i]; + m_fileData = fileData; + } + else if (is_extension_one_of(&ext[1], {"png", "jpg", "webp"})) + { + m_fileType = EFileType::IMAGE; + m_fileDataSize = SIZE_MAX; + const auto image = AssetManager::LoadTexture(path.string().c_str())->GetHandle()->ImagePtr; + m_fileDataExtent = IVec2{image->Width, image->Height}; + m_fileData = (PVOID)RDC::BakeTexture(image); + } + } + + VOID View_FilePreview::Close() + { + switch (m_fileType) + { + case EFileType::UNKNOWN: + break; + + case EFileType::TEXT: + delete[] ((String *) m_fileData); + m_fileDataSize = 0; + m_fileData = nullptr; + break; + + case EFileType::IMAGE: + m_fileDataSize = 0; + m_fileData = nullptr; + m_fileDataExtent = {}; + break; + } + + m_filePath = Path(); + m_fileType = EFileType::UNKNOWN; + } + + VOID View_FilePreview::RenderTextFile() + { + const auto lines = (String*)m_fileData; + for(SIZE_T i = 0; i < m_fileDataSize; i++) + ImGui::Text("%s", lines[i].c_str()); + } + + VOID View_FilePreview::RenderImageFile() + { + UI::PadX(); + UI::PadY(); + if(ImGui::Button("Mark as Asset")) + Editor::Instance().MarkAsAsset(m_filePath); + UI::PadY(); + + const auto ImageWidth = m_extent.x * 0.75f; + UI::AlignCursorHCenter(ImRect{{}, m_extent}, ImageWidth); + const auto aspectRatio = static_cast(m_fileDataExtent.y)/static_cast(m_fileDataExtent.x); + ImGui::Image((ImTextureRef)m_fileData, {ImageWidth, aspectRatio * ImageWidth}); + } + + VOID View_FilePreview::RenderUnknownFile() + { + UI::DrawTextCentered(m_extent, "Unsupported File Format"); + } +} // namespace ia::iae \ No newline at end of file diff --git a/Src/Editor/imp/cpp/UI/View/Game.cpp b/Src/Editor/imp/cpp/UI/View/Game.cpp new file mode 100644 index 0000000..886d405 --- /dev/null +++ b/Src/Editor/imp/cpp/UI/View/Game.cpp @@ -0,0 +1,99 @@ +// IAEngine: 2D Game Engine by IA +// Copyright (C) 2025 IASoft (PVT) LTD (oss@iasoft.dev) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include + +#include + +#include + +namespace ia::iae +{ + VOID View_Game::Initialize() + { + SetName("Game"); + SetIcon(ICON_FA_GAMEPAD); + + IAEngine::__Initialize(SCENE_EDITOR_RESOULTION, Editor::Instance().GetActiveProject()->AssetDirectory()); + + m_gameRenderTexture = new RDC_Texture(RDC_Texture::EType::SAMPLED, SCENE_EDITOR_RESOULTION.x, SCENE_EDITOR_RESOULTION.y); + } + + VOID View_Game::Terminate() + { + delete m_gameRenderTexture; + } + + VOID View_Game::Render() + { + PreRender(); + + ImGui::Image(m_gameRenderTexture->GetHandle(), m_extent); + + PostRender(); + } + + VOID View_Game::Update() + { + STATIC INT32 frameCounter{0}; + + IAEngine::__Update(); + + frameCounter++; + if (frameCounter >= 60) + { + frameCounter = 0; + IAEngine::__FixedUpdate(); + } + + IAEngine::__RenderToTexture(m_gameRenderTexture->GetHandle()); + } + + VOID View_Game::OnEvent(IN SDL_Event *event) + { + IAEngine::__ProcessEvent(event); + } +} // namespace ia::iae + +C_DECL(GameRequestedConfig *Game_GetConfigRequest()) +{ + return nullptr; +} + +C_DECL(VOID Game_OnInitialize()) +{ +} + +C_DECL(VOID Game_OnTerminate()) +{ +} + +C_DECL(VOID Game_OnDebugDraw()) +{ +} + +C_DECL(VOID Game_OnFixedUpdate()) +{ +} + +C_DECL(VOID Game_OnUpdate(IN FLOAT32 deltaTime)) +{ +} + +C_DECL(VOID Game_OnResize(IN INT32 newWidth, IN INT32 newHeight)) +{ +} \ No newline at end of file diff --git a/Src/Editor/imp/cpp/UI/View/Scene.cpp b/Src/Editor/imp/cpp/UI/View/Scene.cpp index 485cea3..f9e8ae3 100644 --- a/Src/Editor/imp/cpp/UI/View/Scene.cpp +++ b/Src/Editor/imp/cpp/UI/View/Scene.cpp @@ -19,8 +19,6 @@ #include -#include - namespace ia::iae { VOID View_Scene::Initialize() @@ -28,21 +26,16 @@ namespace ia::iae SetName("Scene"); SetIcon(ICON_FA_HASHTAG); - IAEngine::__Initialize(SCENE_EDITOR_RESOULTION, Editor::Instance().GetActiveProject()->AssetDirectory()); - - m_gamePreviewTexture = new RDC_Texture(RDC_Texture::EType::SAMPLED, SCENE_EDITOR_RESOULTION.x, SCENE_EDITOR_RESOULTION.y); } VOID View_Scene::Terminate() { - delete m_gamePreviewTexture; } VOID View_Scene::Render() { PreRender(); - ImGui::Image(m_gamePreviewTexture->GetHandle(), {SCENE_EDITOR_RESOULTION.x, SCENE_EDITOR_RESOULTION.y}); PostRender(); } @@ -51,49 +44,9 @@ namespace ia::iae { STATIC INT32 frameCounter{0}; - IAEngine::__Update(); - - frameCounter++; - if (frameCounter >= 60) - { - frameCounter = 0; - IAEngine::__FixedUpdate(); - } - - IAEngine::__RenderToTexture(m_gamePreviewTexture->GetHandle()); } VOID View_Scene::OnEvent(IN SDL_Event *event) { - IAEngine::__ProcessEvent(event); } } // namespace ia::iae - -C_DECL(GameRequestedConfig *Game_GetConfigRequest()) -{ - return nullptr; -} - -C_DECL(VOID Game_OnInitialize()) -{ -} - -C_DECL(VOID Game_OnTerminate()) -{ -} - -C_DECL(VOID Game_OnDebugDraw()) -{ -} - -C_DECL(VOID Game_OnFixedUpdate()) -{ -} - -C_DECL(VOID Game_OnUpdate(IN FLOAT32 deltaTime)) -{ -} - -C_DECL(VOID Game_OnResize(IN INT32 newWidth, IN INT32 newHeight)) -{ -} \ No newline at end of file diff --git a/Src/Editor/imp/hpp/Editor.hpp b/Src/Editor/imp/hpp/Editor.hpp index 1bf04cd..172febc 100644 --- a/Src/Editor/imp/hpp/Editor.hpp +++ b/Src/Editor/imp/hpp/Editor.hpp @@ -33,7 +33,9 @@ namespace ia::iae public: VOID LoadProject(IN CONST String &directory); - VOID OpenAsset(IN Path path); + VOID OpenFile(IN Path path); + VOID MarkAsAsset(IN Path path); + VOID RemoveFromAssets(IN CONST String& assetName); public: CONST Project *GetActiveProject() CONST diff --git a/Src/Editor/imp/hpp/UI/TabContainer.hpp b/Src/Editor/imp/hpp/UI/TabContainer.hpp index b685908..d6bb748 100644 --- a/Src/Editor/imp/hpp/UI/TabContainer.hpp +++ b/Src/Editor/imp/hpp/UI/TabContainer.hpp @@ -22,6 +22,13 @@ namespace ia::iae { class TabContainer { + struct Tab + { + IView* View{}; + BOOL IsOpen{true}; + BOOL IsCloseable{false}; + }; + public: TabContainer(); @@ -31,10 +38,13 @@ namespace ia::iae VOID Update(); VOID ProcessEvent(IN SDL_Event *event); - template INLINE VOID AddTab(IN CONST String &name); + template INLINE VOID AddTab(IN CONST String &name, IN BOOL isCloseable = false); IView *GetTab(IN CONST String &name); VOID RemoveTab(IN CONST String &name); + VOID OpenTab(IN CONST String& name); + VOID CloseTab(IN CONST String& name); + VOID ChangeActiveTab(IN PCCHAR name); private: @@ -42,14 +52,14 @@ namespace ia::iae CONST String m_containerID; PCCHAR m_activeTabName{}; PCCHAR m_pendingActiveTabName{}; - Map m_tabViews; + Map m_tabViews; private: - VOID AddTab(IN CONST String &name, IN IView *view); + VOID AddTab(IN CONST String &name, IN IView *view, IN BOOL isCloseable); }; - template VOID TabContainer::AddTab(IN CONST String &name) + template VOID TabContainer::AddTab(IN CONST String &name, IN BOOL isCloseable) { - AddTab(name, new ViewType()); + AddTab(name, new ViewType(), isCloseable); } } // namespace ia::iae \ No newline at end of file diff --git a/Src/Editor/imp/hpp/UI/UI.hpp b/Src/Editor/imp/hpp/UI/UI.hpp index f518496..d0ab6b1 100644 --- a/Src/Editor/imp/hpp/UI/UI.hpp +++ b/Src/Editor/imp/hpp/UI/UI.hpp @@ -33,10 +33,16 @@ namespace ia::iae STATIC VOID AlignCursorHCenter(IN CONST ImRect &rect, IN FLOAT32 width); STATIC VOID AlignCursorVCenter(IN CONST ImRect &rect, IN FLOAT32 height); - public: - STATIC VOID FocusAssetView(); + STATIC VOID DrawTextCentered(IN CONST ImVec2& viewExtent, IN CONST String& text); - STATIC class View_Asset *GetAssetView(); + public: + STATIC VOID OpenFilePreviewView(); + STATIC VOID CloseFilePreviewView(); + STATIC VOID OpenAssetView(); + STATIC VOID CloseAssetView(); + + STATIC class View_Asset* GetAssetView(); + STATIC class View_FilePreview *GetFilePreviewView(); STATIC class IView *GetFocusedView() { diff --git a/Src/Editor/imp/hpp/UI/View/Asset.hpp b/Src/Editor/imp/hpp/UI/View/Asset.hpp index 9dfcf4a..1fcae21 100644 --- a/Src/Editor/imp/hpp/UI/View/Asset.hpp +++ b/Src/Editor/imp/hpp/UI/View/Asset.hpp @@ -18,12 +18,14 @@ #include +#include + namespace ia::iae { class View_Asset : public IView { public: - VOID Open(IN Path path); + VOID Open(IN String assetName); VOID Close(); public: @@ -36,6 +38,19 @@ namespace ia::iae VOID OnEvent(IN SDL_Event *event); private: - Path m_assetPath{}; + VOID RenderTextureAsset(); + VOID RenderSpriteAsset(); + VOID RenderTileSheetAsset(); + VOID RenderSpriteSheetAsset(); + + VOID DrawAssetTypePicker(); + VOID DrawAssetImage(IN FLOAT32 relativeWidth, IN IVec2 gridSize); + + private: + class IAsset *m_asset{}; + String m_assetName{}; + Handle m_assetImageHandle{}; + IVec2 m_assetImageExtent{}; + EAssetType m_assetType{}; }; } // namespace ia::iae \ No newline at end of file diff --git a/Src/Editor/imp/hpp/UI/View/FilePreview.hpp b/Src/Editor/imp/hpp/UI/View/FilePreview.hpp new file mode 100644 index 0000000..54425bc --- /dev/null +++ b/Src/Editor/imp/hpp/UI/View/FilePreview.hpp @@ -0,0 +1,58 @@ +// IAEngine: 2D Game Engine by IA +// Copyright (C) 2025 IASoft (PVT) LTD (oss@iasoft.dev) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include + +namespace ia::iae +{ + class View_FilePreview : public IView + { + enum class EFileType + { + UNKNOWN, + + TEXT, + IMAGE, + }; + + public: + VOID Open(IN Path path); + VOID Close(); + + public: + VOID Initialize(); + VOID Terminate(); + VOID Render(); + VOID Update(); + + protected: + VOID OnEvent(IN SDL_Event *event); + + private: + VOID RenderTextFile(); + VOID RenderImageFile(); + VOID RenderUnknownFile(); + + private: + Path m_filePath{}; + EFileType m_fileType{EFileType::UNKNOWN}; + PVOID m_fileData{}; + SIZE_T m_fileDataSize{}; + IVec2 m_fileDataExtent{}; + }; +} // namespace ia::iae \ No newline at end of file diff --git a/Src/Editor/imp/hpp/UI/View/Game.hpp b/Src/Editor/imp/hpp/UI/View/Game.hpp new file mode 100644 index 0000000..5a820d2 --- /dev/null +++ b/Src/Editor/imp/hpp/UI/View/Game.hpp @@ -0,0 +1,43 @@ +// IAEngine: 2D Game Engine by IA +// Copyright (C) 2025 IASoft (PVT) LTD (oss@iasoft.dev) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include + +namespace ia::iae +{ + class View_Game : public IView + { + public: + VOID Initialize(); + VOID Terminate(); + VOID Render(); + VOID Update(); + + protected: + VOID OnEvent(IN SDL_Event *event); + + public: + VOID ProcessEvent(IN SDL_Event *event) + { + OnEvent(event); + } + + private: + class RDC_Texture* m_gameRenderTexture; + }; +} // namespace ia::iae \ No newline at end of file diff --git a/Src/Editor/imp/hpp/UI/View/IView.hpp b/Src/Editor/imp/hpp/UI/View/IView.hpp index 7c4f8c3..83294cb 100644 --- a/Src/Editor/imp/hpp/UI/View/IView.hpp +++ b/Src/Editor/imp/hpp/UI/View/IView.hpp @@ -71,7 +71,7 @@ namespace ia::iae VOID IView::PreRender() { - m_extent = ImGui::GetWindowSize(); + m_extent = ImGui::GetContentRegionAvail(); ImGui::BeginChild("##"); } diff --git a/Src/Editor/imp/hpp/UI/View/Scene.hpp b/Src/Editor/imp/hpp/UI/View/Scene.hpp index dc58119..894243a 100644 --- a/Src/Editor/imp/hpp/UI/View/Scene.hpp +++ b/Src/Editor/imp/hpp/UI/View/Scene.hpp @@ -36,8 +36,5 @@ namespace ia::iae { OnEvent(event); } - - private: - class RDC_Texture* m_gamePreviewTexture; }; } // namespace ia::iae \ No newline at end of file diff --git a/Src/IAEngine/imp/cpp/Asset/AssetManager.cpp b/Src/IAEngine/imp/cpp/Asset/AssetManager.cpp index f5f2ad1..b62b9fa 100644 --- a/Src/IAEngine/imp/cpp/Asset/AssetManager.cpp +++ b/Src/IAEngine/imp/cpp/Asset/AssetManager.cpp @@ -26,13 +26,18 @@ #include +#include + namespace ia::iae { + Map g_assetNameToPathMap; + Map g_assetPathToNameMap; + String AssetManager::s_assetDirectory; Vector AssetManager::s_assets; Map AssetManager::s_assetNames; - Handle CreateTextureFromFile(IN PCCHAR path, IN INT32 tileWidth = -1, IN INT32 tileHeight = -1) + ImageView *CreateTextureFromFile(IN PCCHAR path, IN INT32 tileWidth = -1, IN INT32 tileHeight = -1) { const auto data = AssetManager::ReadBinaryAsset(path); @@ -40,8 +45,8 @@ namespace ia::iae auto pixels = stbi_load_from_memory(data.data(), data.size(), &w, &h, &n, STBI_rgb_alpha); if (!pixels) THROW_INVALID_DATA(path); - const auto t = - RDC::CreateImage(pixels, w, h, tileWidth == -1 ? 1 : w / tileWidth, tileHeight == -1 ? 1 : h / tileHeight); + const auto t = RDC::CreateImageView(RDC::CreateImage(pixels, w, h), tileWidth == -1 ? 1 : w / tileWidth, + tileHeight == -1 ? 1 : h / tileHeight); stbi_image_free(pixels); return t; } @@ -56,6 +61,65 @@ namespace ia::iae DestroyAsset(s_assets[i]); } + String get_relative_asset_path(IN CONST String& _path) + { + std::string __path = _path.c_str(); + const auto t = std::filesystem::path(_path.c_str()); + return t.is_absolute() ? String(__path.substr(__path.find("Assets") + 7).c_str()) : _path; + } + + String AssetManager::GetAssetName(IN CONST String &_path) + { + const auto path = get_relative_asset_path(_path); + if(g_assetPathToNameMap.contains(path)) + return g_assetPathToNameMap[path]; + return ""; + } + + IAsset* AssetManager::ChangeAssetType(IN CONST String& assetName, IN EAssetType newType) + { + if(!s_assetNames.contains(assetName)) + return nullptr; + + const auto currentAsset = (Asset_Texture*)s_assetNames[assetName]; + + if(newType == currentAsset->GetType()) + return currentAsset; + + IAsset* asset{}; + switch(newType) + { + case EAssetType::TEXTURE: + asset = new Asset_Texture(currentAsset->GetHandle()); + break; + + case EAssetType::SPRITE: + asset = new Asset_Sprite(currentAsset->GetHandle()); + break; + + case EAssetType::TILESHEET: + asset = new Asset_TileSheet(currentAsset->GetHandle(), currentAsset->GetHandle()->ImagePtr->Width, currentAsset->GetHandle()->ImagePtr->Height); + break; + + case EAssetType::SPRITESHEET: + asset = new Asset_SpriteSheet(currentAsset->GetHandle(), currentAsset->GetHandle()->ImagePtr->Width, currentAsset->GetHandle()->ImagePtr->Height, {}); + break; + + case EAssetType::INVALID: + case EAssetType::SOUND: + case EAssetType::SCENE: + case EAssetType::PLUGIN: + case EAssetType::PACKAGE: + break; + } + + DestroyAsset(s_assetNames[assetName]); + + s_assetNames[assetName] = asset; + + return asset; + } + VOID AssetManager::SetAssetDirectory(IN CONST String &path) { s_assetDirectory = path; @@ -63,7 +127,8 @@ namespace ia::iae String AssetManager::ReadTextAsset(IN CONST String &path) { - const auto t = BuildString(s_assetDirectory, "/", path); + const auto t = + std::filesystem::path(path.c_str()).is_absolute() ? path : BuildString(s_assetDirectory, "/", path); SDL_IOStream *f = SDL_IOFromFile(t.c_str(), "r"); if (!f) THROW_FILE_OPEN_READ(t); @@ -79,7 +144,8 @@ namespace ia::iae Vector AssetManager::ReadBinaryAsset(IN CONST String &path) { - const auto t = BuildString(s_assetDirectory, "/", path); + const auto t = + std::filesystem::path(path.c_str()).is_absolute() ? path : BuildString(s_assetDirectory, "/", path); SDL_IOStream *f = SDL_IOFromFile(t.c_str(), "rb"); if (!f) THROW_FILE_OPEN_READ(t); @@ -94,25 +160,19 @@ namespace ia::iae Asset_Texture *AssetManager::LoadTexture(IN CONST String &path) { - const auto t = new Asset_Sprite(CreateTextureFromFile(path.c_str())); + const auto t = new Asset_Texture(CreateTextureFromFile(path.c_str())); + t->SetPath(get_relative_asset_path(path)); s_assets.pushBack(t); return t; } Asset_Sprite *AssetManager::LoadSprite(IN CONST String &path) { - const auto t = new Asset_Sprite(CreateTextureFromFile(path.c_str())); - s_assets.pushBack(t); - return t; + return nullptr; } Asset_SpriteSheet *AssetManager::LoadSpriteSheet(IN CONST String &path) { - // const auto t = new Asset_SpriteSheet(); - // t->m_frameCounts = frameCounts; - // t->m_texture = CreateTextureFromFile(path.c_str(), spriteWidth, spriteHeight); - // s_assets.pushBack(t); - // return t; return nullptr; } @@ -128,16 +188,22 @@ namespace ia::iae Asset_Texture *AssetManager::CreateTexture(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height) { - return nullptr; + return new Asset_Texture(RDC::CreateImageView(RDC::CreateImage(rgbaData, width, height))); } - Asset_Sprite *AssetManager::CreateSprite(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height) + Asset_Sprite *AssetManager::CreateSprite(IN CONST Asset_Texture *texture) + { + return new Asset_Sprite(texture->m_handle); + } + + Asset_SpriteSheet *AssetManager::CreateSpriteSheet(IN CONST Vector &sprites, + IN CONST Map &animations) { return nullptr; } - Asset_SpriteSheet *AssetManager::CreateSpriteSheet(IN CONST Asset_Texture *texture, IN INT32 spriteWidth, - IN INT32 spriteHeight, IN CONST Vector &frameCounts) + Asset_SpriteSheet *AssetManager::CreateSpriteSheet(IN CONST Asset_Texture *texture, IN INT32 frameWidth, + IN INT32 frameHeight, IN CONST Map &animations) { return nullptr; } @@ -145,7 +211,9 @@ namespace ia::iae Asset_TileSheet *AssetManager::CreateTileSheet(IN CONST Asset_Texture *texture, IN INT32 tileWidth, IN INT32 tileHeight) { - const auto t = new Asset_TileSheet(texture->m_handle, tileWidth, tileHeight); + const auto image = texture->m_handle->ImagePtr; + const auto t = new Asset_TileSheet( + RDC::CreateImageView(image, image->Width / tileWidth, image->Height / tileHeight), tileWidth, tileHeight); s_assets.pushBack(t); return t; } @@ -172,6 +240,8 @@ namespace ia::iae VOID AssetManager::AssignAssetName(IN IAsset *asset, IN CONST String &name) { s_assetNames[name] = asset; + g_assetNameToPathMap[name] = asset->GetPath(); + g_assetPathToNameMap[asset->GetPath()] = name; } Asset_Scene *AssetManager::CreateScene(IN IVec2 extent) diff --git a/Src/IAEngine/imp/cpp/GameData.cpp b/Src/IAEngine/imp/cpp/GameData.cpp index 336d822..3e21b1a 100644 --- a/Src/IAEngine/imp/cpp/GameData.cpp +++ b/Src/IAEngine/imp/cpp/GameData.cpp @@ -86,7 +86,7 @@ namespace ia::iae else if (!strcmp(entry.name(), "TileSheet")) { AssetManager::AssignAssetName( - AssetManager::CreateTileSheet(entry.attribute("path").as_string(), + AssetManager::CreateTileSheet(AssetManager::LoadTexture(entry.attribute("path").as_string()), entry.attribute("tileWidth").as_int(), entry.attribute("tileHeight").as_int()), entry.attribute("name").as_string()); diff --git a/Src/IAEngine/inc/IAEngine/Asset/AssetManager.hpp b/Src/IAEngine/inc/IAEngine/Asset/AssetManager.hpp index 980654e..2309476 100644 --- a/Src/IAEngine/inc/IAEngine/Asset/AssetManager.hpp +++ b/Src/IAEngine/inc/IAEngine/Asset/AssetManager.hpp @@ -44,14 +44,18 @@ namespace ia::iae STATIC Asset_Scene *CreateScene(IN IVec2 extent); STATIC Asset_Texture *CreateTexture(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height); - STATIC Asset_Sprite *CreateSprite(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height); - STATIC Asset_SpriteSheet *CreateSpriteSheet(IN CONST Asset_Texture *texture, IN INT32 spriteWidth, - IN INT32 spriteHeight, IN CONST Vector &frameCounts); + STATIC Asset_Sprite *CreateSprite(IN CONST Asset_Texture *texture); + STATIC Asset_SpriteSheet *CreateSpriteSheet(IN CONST Vector& sprites, IN CONST Map &animations); + STATIC Asset_SpriteSheet *CreateSpriteSheet(IN CONST Asset_Texture *texture, IN INT32 frameWidth, + IN INT32 frameHeight, IN CONST Map &animations); STATIC Asset_TileSheet *CreateTileSheet(IN CONST Asset_Texture *texture, IN INT32 tileWidth, IN INT32 tileHeight); STATIC VOID DestroyAsset(IN IAsset *asset); STATIC VOID AssignAssetName(IN IAsset *asset, IN CONST String &name); + STATIC String GetAssetName(IN CONST String& path); + + STATIC IAsset* ChangeAssetType(IN CONST String& assetName, IN EAssetType newType); template requires std::is_base_of::value diff --git a/Src/IAEngine/inc/IAEngine/Asset/IAsset.hpp b/Src/IAEngine/inc/IAEngine/Asset/IAsset.hpp index e730afd..aad9e6e 100644 --- a/Src/IAEngine/inc/IAEngine/Asset/IAsset.hpp +++ b/Src/IAEngine/inc/IAEngine/Asset/IAsset.hpp @@ -20,7 +20,7 @@ namespace ia::iae { - enum class EAssetType + enum class EAssetType: INT32 { INVALID, @@ -43,7 +43,24 @@ namespace ia::iae PURE_VIRTUAL(VOID Compile()); PURE_VIRTUAL(VOID Destroy()); + public: + String GetPath() CONST + { + return m_path; + } + + VOID SetPath(IN CONST String &path) + { + m_path = path; + } + + EAssetType GetType() CONST + { + return m_type; + } + protected: + String m_path; CONST EAssetType m_type; }; -} \ No newline at end of file +} // namespace ia::iae \ No newline at end of file diff --git a/Src/IAEngine/inc/IAEngine/Asset/Sprite.hpp b/Src/IAEngine/inc/IAEngine/Asset/Sprite.hpp index 6bc9d7f..e501bc3 100644 --- a/Src/IAEngine/inc/IAEngine/Asset/Sprite.hpp +++ b/Src/IAEngine/inc/IAEngine/Asset/Sprite.hpp @@ -23,7 +23,7 @@ namespace ia::iae class Asset_Sprite : public Asset_Texture { public: - Asset_Sprite(IN Handle textureHandle) : Asset_Texture(textureHandle, EAssetType::SPRITE) + Asset_Sprite(IN ImageView* textureHandle) : Asset_Texture(textureHandle, EAssetType::SPRITE) { } diff --git a/Src/IAEngine/inc/IAEngine/Asset/SpriteSheet.hpp b/Src/IAEngine/inc/IAEngine/Asset/SpriteSheet.hpp index 20e90bd..d0beafd 100644 --- a/Src/IAEngine/inc/IAEngine/Asset/SpriteSheet.hpp +++ b/Src/IAEngine/inc/IAEngine/Asset/SpriteSheet.hpp @@ -30,20 +30,35 @@ namespace ia::iae }; public: - Asset_SpriteSheet(IN Handle textureHandle, IN INT32 frameWidth, IN INT32 frameHeight, + Asset_SpriteSheet(IN ImageView *textureHandle, IN INT32 frameWidth, IN INT32 frameHeight, IN Map &&animations) - : Asset_Texture(textureHandle, EAssetType::SPRITESHEET), m_frameWidth(frameWidth), m_frameHeight(frameHeight), - m_animations(IA_MOVE(animations)) + : Asset_Texture(textureHandle, EAssetType::SPRITESHEET), m_frameWidth(frameWidth), + m_frameHeight(frameHeight), m_animations(IA_MOVE(animations)) { } VIRTUAL VOID Compile(); VIRTUAL VOID Destroy(); + INT32 &FrameWidth() + { + return m_frameWidth; + } + + INT32 &FrameHeight() + { + return m_frameHeight; + } + + Map &Animations() + { + return m_animations; + } + protected: - CONST INT32 m_frameWidth; - CONST INT32 m_frameHeight; - CONST Map m_animations; + INT32 m_frameWidth; + INT32 m_frameHeight; + Map m_animations; friend class AssetManager; }; diff --git a/Src/IAEngine/inc/IAEngine/Asset/Texture.hpp b/Src/IAEngine/inc/IAEngine/Asset/Texture.hpp index 144a0a7..89f6c10 100644 --- a/Src/IAEngine/inc/IAEngine/Asset/Texture.hpp +++ b/Src/IAEngine/inc/IAEngine/Asset/Texture.hpp @@ -23,26 +23,26 @@ namespace ia::iae class Asset_Texture : public IAsset { public: - Asset_Texture(IN Handle handle) : IAsset(EAssetType::TEXTURE), m_handle(handle) + Asset_Texture(IN ImageView* handle) : IAsset(EAssetType::TEXTURE), m_handle(handle) { } - Asset_Texture(IN Handle handle, IN EAssetType type) : IAsset(type), m_handle(handle) + Asset_Texture(IN ImageView* handle, IN EAssetType type) : IAsset(type), m_handle(handle) { } VIRTUAL VOID Compile(); VIRTUAL VOID Destroy(); - INLINE Handle GetHandle(); + INLINE ImageView* GetHandle(); protected: - CONST Handle m_handle; + ImageView* CONST m_handle; friend class AssetManager; }; - INLINE Handle Asset_Texture::GetHandle() + INLINE ImageView* Asset_Texture::GetHandle() { return m_handle; } diff --git a/Src/IAEngine/inc/IAEngine/Asset/TileSheet.hpp b/Src/IAEngine/inc/IAEngine/Asset/TileSheet.hpp index 1859a3b..1cf045b 100644 --- a/Src/IAEngine/inc/IAEngine/Asset/TileSheet.hpp +++ b/Src/IAEngine/inc/IAEngine/Asset/TileSheet.hpp @@ -23,7 +23,7 @@ namespace ia::iae class Asset_TileSheet : public Asset_Texture { public: - Asset_TileSheet(IN Handle textureHandle, IN INT32 tileWidth, IN INT32 tileHeight) + Asset_TileSheet(IN ImageView *textureHandle, IN INT32 tileWidth, IN INT32 tileHeight) : Asset_Texture(textureHandle, EAssetType::TILESHEET), m_tileWidth(tileWidth), m_tileHeight(tileHeight) { } @@ -31,9 +31,19 @@ namespace ia::iae VIRTUAL VOID Compile(); VIRTUAL VOID Destroy(); + INT32 &TileWidth() + { + return m_tileWidth; + } + + INT32 &TileHeight() + { + return m_tileHeight; + } + protected: - CONST INT32 m_tileWidth; - CONST INT32 m_tileHeight; + INT32 m_tileWidth; + INT32 m_tileHeight; friend class AssetManager; }; } // namespace ia::iae \ No newline at end of file diff --git a/Src/RenderCore/imp/cpp/RenderCore.cpp b/Src/RenderCore/imp/cpp/RenderCore.cpp index fa9e90c..4e5bbf3 100644 --- a/Src/RenderCore/imp/cpp/RenderCore.cpp +++ b/Src/RenderCore/imp/cpp/RenderCore.cpp @@ -50,9 +50,11 @@ namespace ia::iae INT32 RDC::s_primitiveInstanceCount{}; GeometryVertex RDC::s_primitiveInstances[RDC::MAX_PRIMITIVE_COUNT]; + Vector g_managedBakedTextures; + VOID RDC::Initialize(IN IVec2 viewportExtent, IN SDL_Window *windowHandle, IN BOOL isDebugMode) { - if(s_windowHandle) + if (s_windowHandle) return; EmbeddedResources::Initialize(); @@ -77,6 +79,9 @@ namespace ia::iae RDC_Device::DestroyGeometry(s_quadGeometry); + for (const auto &t : g_managedBakedTextures) + delete t; + SDL_ReleaseGPUSampler(RDC_Device::GetHandle(), s_linearClampSampler); SDL_ReleaseGPUSampler(RDC_Device::GetHandle(), s_linearRepeatSampler); @@ -190,29 +195,26 @@ namespace ia::iae RDC_Device::WaitForIdle(); } - Vec2 RDC::DrawSpriteTopLeft(IN Handle _image, IN INT32 tileIndexX, IN INT32 tileIndexY, IN Vec2 position, + Vec2 RDC::DrawSpriteTopLeft(IN ImageView *imageView, IN INT32 tileIndexX, IN INT32 tileIndexY, IN Vec2 position, IN Vec2 scale, IN FLOAT32 rotation, IN BOOL flipH, IN BOOL flipV, IN Vec2 uvOffset) { - const auto image = (ImageData *) _image; - - const auto _s = Vec2{scale.x * image->TileWidth, scale.y * image->TileHeight}; + const auto _s = Vec2{scale.x * imageView->TileWidth, scale.y * imageView->TileHeight}; Mat4 transform = glm::translate(glm::mat4(1.0f), glm::vec3{position.x, position.y, 0}); transform = glm::rotate(transform, rotation, glm::vec3(0.0f, 0.0f, 1.0f)); transform = glm::scale(transform, glm::vec3(_s, 1.0f)); s_spriteInstances[s_spriteInstanceCount++] = { .Transform = transform, .TexCoords = s_dynamicSpriteAtlas ? s_dynamicSpriteAtlas->GetTextureCoordinates( - _image, tileIndexX, tileIndexY, flipH, flipV, uvOffset) + imageView, tileIndexX, tileIndexY, flipH, flipV, uvOffset) : Vec4{0.0f, 0.0f, 1.0f, 1.0f}, .Color = {1.0f, 1.0f, 1.0f, 1.0f}}; return _s; } - Vec2 RDC::DrawSpriteCentered(IN Handle _image, IN INT32 tileIndexX, IN INT32 tileIndexY, IN Vec2 position, + Vec2 RDC::DrawSpriteCentered(IN ImageView *imageView, IN INT32 tileIndexX, IN INT32 tileIndexY, IN Vec2 position, IN Vec2 scale, IN FLOAT32 rotation, IN BOOL flipH, IN BOOL flipV, IN Vec2 uvOffset) { - const auto image = (ImageData *) _image; - const auto _s = Vec2{scale.x * image->TileWidth, scale.y * image->TileHeight}; + const auto _s = Vec2{scale.x * imageView->TileWidth, scale.y * imageView->TileHeight}; Mat4 transform = glm::translate(glm::mat4(1.0f), glm::vec3{position.x - _s.x / 2.0f, position.y - _s.y / 2.0f, 0}); transform = glm::rotate(transform, rotation, glm::vec3(0.0f, 0.0f, 1.0f)); @@ -220,7 +222,7 @@ namespace ia::iae s_spriteInstances[s_spriteInstanceCount++] = { .Transform = transform, .TexCoords = s_dynamicSpriteAtlas ? s_dynamicSpriteAtlas->GetTextureCoordinates( - _image, tileIndexX, tileIndexY, flipH, flipV, uvOffset) + imageView, tileIndexX, tileIndexY, flipH, flipV, uvOffset) : Vec4{0.0f, 0.0f, 1.0f, 1.0f}, .Color = {1.0f, 1.0f, 1.0f, 1.0f}}; return _s; @@ -263,34 +265,50 @@ namespace ia::iae s_viewMatrix = glm::lookAtLH(glm::vec3{s_cameraPosition, -1.0f}, {s_cameraPosition, 0.0f}, {0.0f, 1.0f, 0.0f}); } - Handle RDC::CreateImage(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height, IN INT32 tileCountX, - IN INT32 tileCountY) + Image *RDC::CreateImage(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height) { const auto pixelDataSize = width * height * 4; - const auto image = new ImageData{ - .Pixels = new UINT8[pixelDataSize], - .Width = width, - .Height = height, - .TileWidth = width / tileCountX, - .TileHeight = height / tileCountY, + const auto image = new Image{.Pixels = new UINT8[pixelDataSize], .Width = width, .Height = height}; + + ia_memcpy(image->Pixels, rgbaData, pixelDataSize); + + return image; + } + + ImageView *RDC::CreateImageView(IN Image *image, IN INT32 tileCountX, IN INT32 tileCountY) + { + const auto imageView = new ImageView{ + .ImagePtr = image, + .TileWidth = image->Width / tileCountX, + .TileHeight = image->Height / tileCountY, .TileCountX = tileCountX, .TileCountY = tileCountY, }; - ia_memcpy(image->Pixels, rgbaData, pixelDataSize); - - return (Handle) image; + return imageView; } - VOID RDC::DestroyImage(IN Handle _image) + VOID RDC::DestroyImage(IN Image *image) { - const auto image = (ImageData *) _image; delete[] image->Pixels; delete image; } - VOID RDC::CompileTextures(IN CONST Vector &images) + VOID RDC::DestroyImageView(IN ImageView *imageView) + { + delete imageView; + } + + Handle RDC::BakeTexture(IN Image *image) + { + const auto texture = new RDC_Texture(RDC_Texture::EType::SAMPLED, image->Width, image->Height); + texture->SetImageData(image->Pixels); + g_managedBakedTextures.pushBack(texture); + return (Handle)texture->GetHandle(); + } + + VOID RDC::CompileTextures(IN CONST Vector &images) { if (!images.size()) return; diff --git a/Src/RenderCore/imp/cpp/TextureAtlas.cpp b/Src/RenderCore/imp/cpp/TextureAtlas.cpp index 7d1fc62..5462e2e 100644 --- a/Src/RenderCore/imp/cpp/TextureAtlas.cpp +++ b/Src/RenderCore/imp/cpp/TextureAtlas.cpp @@ -18,19 +18,18 @@ namespace ia::iae { - RDC_TextureAtlas::RDC_TextureAtlas(IN CONST Vector &images) + RDC_TextureAtlas::RDC_TextureAtlas(IN CONST Vector &images) { if (images.empty()) return; m_atlasSize.x = 0; m_atlasSize.y = 0; - for (const auto &_image : images) + for (const auto &image : images) { - const auto d = (ImageData *) _image; - m_atlasSize.x += d->Width; - if (d->Height > m_atlasSize.y) - m_atlasSize.y = d->Height; + m_atlasSize.x += image->Width; + if (image->Height > m_atlasSize.y) + m_atlasSize.y = image->Height; } m_inverseAtlasSize = {1.0f / ((FLOAT32) m_atlasSize.x), 1.0f / ((FLOAT32) m_atlasSize.y)}; @@ -38,13 +37,12 @@ namespace ia::iae const auto pixels = new UINT8[m_atlasSize.x * m_atlasSize.y * 4]; INT32 atlasCursor{0}; - for (const auto &_image : images) + for (const auto &image : images) { - const auto d = (ImageData *) _image; - for (INT32 y = 0; y < d->Height; y++) - ia_memcpy(&pixels[(atlasCursor + (y * m_atlasSize.x)) * 4], &d->Pixels[y * d->Width * 4], d->Width * 4); - m_texCoordMap[_image] = Vec2(((FLOAT32) atlasCursor) / ((FLOAT32) m_atlasSize.x), 0.0f); - atlasCursor += d->Width; + for (INT32 y = 0; y < image->Height; y++) + ia_memcpy(&pixels[(atlasCursor + (y * m_atlasSize.x)) * 4], &image->Pixels[y * image->Width * 4], image->Width * 4); + m_texCoordMap[(Handle)(image)] = Vec2(((FLOAT32) atlasCursor) / ((FLOAT32) m_atlasSize.x), 0.0f); + atlasCursor += image->Width; } m_texture = new RDC_Texture(RDC_Texture::EType::SAMPLED, m_atlasSize.x, m_atlasSize.y); @@ -58,15 +56,14 @@ namespace ia::iae delete m_texture; } - Vec4 RDC_TextureAtlas::GetTextureCoordinates(IN Handle _image, IN INT32 tileIndexX, IN INT32 tileIndexY, IN BOOL flipH, + Vec4 RDC_TextureAtlas::GetTextureCoordinates(IN ImageView* imageView, IN INT32 tileIndexX, IN INT32 tileIndexY, IN BOOL flipH, IN BOOL flipV, IN Vec2 uvOffset) { - const auto d = (ImageData *) _image; - const auto &t = m_texCoordMap[_image]; - const auto pX = ((tileIndexX + uvOffset.x) * ((FLOAT32) d->TileWidth)) * m_inverseAtlasSize.x; - const auto pY = ((tileIndexY + uvOffset.y) * ((FLOAT32) d->TileHeight)) * m_inverseAtlasSize.y; - auto texCoords = Vec4(t.x + pX, t.y + pY, d->TileWidth * m_inverseAtlasSize.x, - d->TileHeight * m_inverseAtlasSize.y); + const auto &t = m_texCoordMap[(Handle)(imageView->ImagePtr)]; + const auto pX = ((tileIndexX + uvOffset.x) * ((FLOAT32) imageView->TileWidth)) * m_inverseAtlasSize.x; + const auto pY = ((tileIndexY + uvOffset.y) * ((FLOAT32) imageView->TileHeight)) * m_inverseAtlasSize.y; + auto texCoords = Vec4(t.x + pX, t.y + pY, imageView->TileWidth * m_inverseAtlasSize.x, + imageView->TileHeight * m_inverseAtlasSize.y); if (flipH) { texCoords.x += texCoords.z; diff --git a/Src/RenderCore/inc/RenderCore/Base.hpp b/Src/RenderCore/inc/RenderCore/Base.hpp index 98fe90d..2f3e501 100644 --- a/Src/RenderCore/inc/RenderCore/Base.hpp +++ b/Src/RenderCore/inc/RenderCore/Base.hpp @@ -27,11 +27,16 @@ namespace ia::iae { - struct ImageData + struct Image { PUINT8 Pixels{}; INT32 Width{}; INT32 Height{}; + }; + + struct ImageView + { + Image* ImagePtr{}; INT32 TileWidth{}; INT32 TileHeight{}; INT32 TileCountX{}; diff --git a/Src/RenderCore/inc/RenderCore/RenderCore.hpp b/Src/RenderCore/inc/RenderCore/RenderCore.hpp index 3f9798a..aa695d9 100644 --- a/Src/RenderCore/inc/RenderCore/RenderCore.hpp +++ b/Src/RenderCore/inc/RenderCore/RenderCore.hpp @@ -17,10 +17,11 @@ #pragma once #include -#include #include +#include #include + namespace ia::iae { #pragma pack(push, 1) @@ -47,25 +48,30 @@ namespace ia::iae STATIC VOID ResizeScreen(IN IVec2 newExtent); STATIC VOID RenderToWindow(); - STATIC VOID RenderToTexture(IN SDL_GPUTexture* texture); + STATIC VOID RenderToTexture(IN SDL_GPUTexture *texture); public: STATIC Vec2 GetCameraPosition(); STATIC VOID SetCameraPosition(IN Vec2 position); - STATIC Vec2 DrawSpriteTopLeft(IN Handle image, IN INT32 tileIndexX, IN INT32 tileIndexY, - IN Vec2 position, IN Vec2 scale, IN FLOAT32 rotation, IN BOOL flipH = false, IN BOOL flipV = false, IN Vec2 uvOffset = {}); - STATIC Vec2 DrawSpriteCentered(IN Handle image, IN INT32 tileIndexX, IN INT32 tileIndexY, - IN Vec2 position, IN Vec2 scale, IN FLOAT32 rotation, IN BOOL flipH = false, IN BOOL flipV = false, IN Vec2 uvOffset = {}); + STATIC Vec2 DrawSpriteTopLeft(IN ImageView* imageView, IN INT32 tileIndexX, IN INT32 tileIndexY, IN Vec2 position, + IN Vec2 scale, IN FLOAT32 rotation, IN BOOL flipH = false, IN BOOL flipV = false, + IN Vec2 uvOffset = {}); + STATIC Vec2 DrawSpriteCentered(IN ImageView* imageView, IN INT32 tileIndexX, IN INT32 tileIndexY, IN Vec2 position, + IN Vec2 scale, IN FLOAT32 rotation, IN BOOL flipH = false, IN BOOL flipV = false, + IN Vec2 uvOffset = {}); STATIC VOID DrawLine(IN Vec2 start, IN Vec2 end, IN Vec4 color); STATIC VOID DrawRect(IN Vec2 start, IN Vec2 end, IN Vec4 color); - STATIC Handle CreateImage(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height, IN INT32 tileCountX = 1, - IN INT32 tileCountY = 1); - STATIC VOID DestroyImage(IN Handle image); + STATIC Image* CreateImage(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height); + STATIC ImageView* CreateImageView(IN Image* image, IN INT32 tileCountX = 1, IN INT32 tileCountY = 1); + STATIC VOID DestroyImage(IN Image* image); + STATIC VOID DestroyImageView(IN ImageView* imageView); - STATIC VOID CompileTextures(IN CONST Vector& images); + STATIC Handle BakeTexture(IN Image* image); + + STATIC VOID CompileTextures(IN CONST Vector &images); private: STATIC VOID InitializeSamplers(); @@ -74,7 +80,7 @@ namespace ia::iae STATIC VOID InitializePipelines(); STATIC VOID InitializeGeometries(); - STATIC VOID Render(IN SDL_GPURenderPass* renderPass, IN SDL_GPUCommandBuffer* commandBuffer); + STATIC VOID Render(IN SDL_GPURenderPass *renderPass, IN SDL_GPUCommandBuffer *commandBuffer); private: STATIC Mat4 s_viewMatrix; @@ -83,7 +89,7 @@ namespace ia::iae STATIC IVec2 s_viewportExtent; STATIC Mat4 s_projectionMatrix; STATIC SDL_Window *s_windowHandle; - STATIC RDC_Texture* s_defaultTexture; + STATIC RDC_Texture *s_defaultTexture; STATIC RDC_Pipeline *s_primitiveDrawPipeline; STATIC RDC_Pipeline *s_dynamicSpritePipeline; @@ -93,9 +99,9 @@ namespace ia::iae STATIC RDC_TextureAtlas *s_staticSpriteAtlas; STATIC RDC_TextureAtlas *s_dynamicSpriteAtlas; - STATIC RDC_HostVisibleBuffer* s_primitiveInstanceBuffer; - STATIC RDC_HostVisibleBuffer* s_staticSpriteInstanceBuffer; - STATIC RDC_HostVisibleBuffer* s_dynamicSpriteInstanceBuffer; + STATIC RDC_HostVisibleBuffer *s_primitiveInstanceBuffer; + STATIC RDC_HostVisibleBuffer *s_staticSpriteInstanceBuffer; + STATIC RDC_HostVisibleBuffer *s_dynamicSpriteInstanceBuffer; STATIC INT32 s_spriteInstanceCount; STATIC RDC_SpriteInstanceData s_spriteInstances[MAX_SPRITE_COUNT]; diff --git a/Src/RenderCore/inc/RenderCore/TextureAtlas.hpp b/Src/RenderCore/inc/RenderCore/TextureAtlas.hpp index f582ad3..5cbaa69 100644 --- a/Src/RenderCore/inc/RenderCore/TextureAtlas.hpp +++ b/Src/RenderCore/inc/RenderCore/TextureAtlas.hpp @@ -23,10 +23,10 @@ namespace ia::iae class RDC_TextureAtlas { public: - RDC_TextureAtlas(IN CONST Vector &images); + RDC_TextureAtlas(IN CONST Vector &images); ~RDC_TextureAtlas(); - Vec4 GetTextureCoordinates(IN Handle image, IN INT32 tileIndexX, IN INT32 tileIndexY, IN BOOL flipH, + Vec4 GetTextureCoordinates(IN ImageView* imageView, IN INT32 tileIndexX, IN INT32 tileIndexY, IN BOOL flipH, IN BOOL flipV, IN Vec2 uvOffset); public: