diff --git a/Engine/CMakeLists.txt b/Engine/CMakeLists.txt index 1ba0f0b..6172137 100644 --- a/Engine/CMakeLists.txt +++ b/Engine/CMakeLists.txt @@ -8,11 +8,13 @@ set(SRC_FILES "Src/Imp/CPP/Physics.cpp" "Src/Imp/CPP/InternalEngine.cpp" + "Src/Imp/CPP/FontManager.cpp" "Src/Imp/CPP/InputManager.cpp" - "Src/Imp/CPP/ResourceManager.cpp" + "Src/Imp/CPP/SceneManager.cpp" "Src/Imp/CPP/EventManager.cpp" "Src/Imp/CPP/WorldManager.cpp" "Src/Imp/CPP/AudioManager.cpp" + "Src/Imp/CPP/ResourceManager.cpp" "Src/Imp/CPP/Renderer/DebugDraw.cpp" "Src/Imp/CPP/Renderer/Pipeline.cpp" @@ -24,7 +26,17 @@ set(SRC_FILES "Src/Imp/CPP/Nodes/SpriteNode.cpp" "Src/Imp/CPP/Nodes/TextureNode.cpp" "Src/Imp/CPP/Nodes/TileMapNode.cpp" + + "Src/Imp/CPP/Nodes/UINode.cpp" + "Src/Imp/CPP/Nodes/UILabelNode.cpp" + "Src/Imp/CPP/Nodes/UITextNode.cpp" + "Src/Imp/CPP/Nodes/UIImageNode.cpp" + "Src/Imp/CPP/Nodes/UIButtonNode.cpp" + "Src/Imp/CPP/Components/UILabelComponent.cpp" + "Src/Imp/CPP/Components/UITextComponent.cpp" + "Src/Imp/CPP/Components/UIImageComponent.cpp" + "Src/Imp/CPP/Components/UIButtonComponent.cpp" "Src/Imp/CPP/Components/CameraComponent.cpp" "Src/Imp/CPP/Components/PhysicsComponent.cpp" "Src/Imp/CPP/Components/SpriteComponent.cpp" @@ -51,4 +63,4 @@ target_include_directories(IAEngine PUBLIC Src/Inc) target_include_directories(IAEngine PRIVATE Src/Imp/HPP) target_link_libraries(IAEngine PUBLIC IACore) -target_link_libraries(IAEngine PRIVATE ZLIB::ZLIBSTATIC SDL3::SDL3 SDL3_mixer::SDL3_mixer RmlUi::RmlUi STB) +target_link_libraries(IAEngine PRIVATE ZLIB::ZLIBSTATIC SDL3::SDL3 SDL3_mixer::SDL3_mixer RmlUi::RmlUi STB Freetype::Freetype) diff --git a/Engine/Src/Imp/CPP/Components/CameraComponent.cpp b/Engine/Src/Imp/CPP/Components/CameraComponent.cpp index 78733d7..89fe9a7 100644 --- a/Engine/Src/Imp/CPP/Components/CameraComponent.cpp +++ b/Engine/Src/Imp/CPP/Components/CameraComponent.cpp @@ -34,7 +34,7 @@ namespace ia::iae m_viewport.w = height; m_projectionMatrix = - glm::orthoLH(0.0f, (FLOAT32) width, (FLOAT32) height, 0.0f, Renderer::MIN_DEPTH, Renderer::MAX_DEPTH); + glm::orthoLH(0.0f, (FLOAT32) width, (FLOAT32) height, 0.0f, -1.0f, 1.0f); } CONST Mat4 *CameraComponent::GetViewMatrix() diff --git a/Engine/Src/Imp/CPP/Components/UIButtonComponent.cpp b/Engine/Src/Imp/CPP/Components/UIButtonComponent.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Engine/Src/Imp/CPP/Components/UIImageComponent.cpp b/Engine/Src/Imp/CPP/Components/UIImageComponent.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Engine/Src/Imp/CPP/Components/UILabelComponent.cpp b/Engine/Src/Imp/CPP/Components/UILabelComponent.cpp new file mode 100644 index 0000000..f42ee8b --- /dev/null +++ b/Engine/Src/Imp/CPP/Components/UILabelComponent.cpp @@ -0,0 +1,49 @@ +// 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 + +namespace ia::iae +{ + UILabelComponent::UILabelComponent(IN UINode *node) : IUIComponent(node) + { + } + + VOID UILabelComponent::Draw() + { + Engine::SetRenderState_Texture(0); + Engine::SetRenderState_FlippedH(false); + Engine::SetRenderState_FlippedV(false); + Engine::SetRenderState_ColorOverlay({0xFF, 0xFF, 0xFF, 0xFF}); + Engine::SetRenderState_TextureOffset({}); + Engine::SetRenderState_CameraRelative(false); + Engine::DrawText(m_label, m_node->GetPosition(), m_node->GetScale(), m_node->GetRotation(), 0xFF, 0); + } + + VOID UILabelComponent::DebugDraw() + { + } + + VOID UILabelComponent::Update() + { + } + + VOID UILabelComponent::FixedUpdate() + { + } +} // namespace ia::iae \ No newline at end of file diff --git a/Engine/Src/Imp/CPP/Components/UITextComponent.cpp b/Engine/Src/Imp/CPP/Components/UITextComponent.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Engine/Src/Imp/CPP/FontManager.cpp b/Engine/Src/Imp/CPP/FontManager.cpp new file mode 100644 index 0000000..fbfe1b1 --- /dev/null +++ b/Engine/Src/Imp/CPP/FontManager.cpp @@ -0,0 +1,97 @@ +// 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 FT_FREETYPE_H + +namespace ia::iae +{ + Map FontManager::s_fonts; + + FT_Library g_freetype; + + VOID FontManager::Initialize() + { + if (FT_Init_FreeType(&g_freetype)) + THROW_UNKNOWN("Failed to initialize the FreeType font library"); + + LoadFont("Roboto", "Resources/Fonts/Roboto-Black.ttf"); + } + + VOID FontManager::Terminate() + { + for(const auto& f: s_fonts) + { + for(const auto& t: f->Value.Chars) + GPUResourceManager::DestroyTexture(t.Texture); + } + + FT_Done_FreeType(g_freetype); + } + + VOID FontManager::LoadFont(IN CONST String &name, IN CONST String &path) + { + STATIC Vector GLYPH_PIXEL_DATA; + + Font result; + + const auto fontSize = 16; + + FT_Face face; + if (FT_New_Face(g_freetype, path.c_str(), 0, &face)) + THROW_UNKNOWN("Failed to load the TrueType font '", path, "'"); + + FT_Set_Pixel_Sizes(face, 0, fontSize); + + const auto charCount = static_cast(sizeof(result.Chars) / sizeof(result.Chars[0])); + for (UINT8 c = 0; c < charCount; c++) + { + if (FT_Load_Char(face, c, FT_LOAD_RENDER)) + THROW_UNKNOWN("Failed to load character '", (CHAR) c, "' of TrueType font '", path, "'"); + + const auto glyphSize = face->glyph->bitmap.pitch * face->glyph->bitmap.rows; + if(!glyphSize) continue; + + GLYPH_PIXEL_DATA.clear(); + GLYPH_PIXEL_DATA.resize(glyphSize << 2); + + for(SIZE_T t = 0; t < glyphSize; t++) + { + const auto pi= t<<2; + const auto p = face->glyph->bitmap.buffer[t]; + GLYPH_PIXEL_DATA[pi + 0] = p; + GLYPH_PIXEL_DATA[pi + 1] = p; + GLYPH_PIXEL_DATA[pi + 2] = p; + GLYPH_PIXEL_DATA[pi + 3] = p; + } + + result.Chars[c] = { + IVec2(face->glyph->bitmap.width, face->glyph->bitmap.rows), + IVec2(face->glyph->bitmap_left, face->glyph->bitmap_top), + static_cast(face->glyph->advance.x) >> 6, + GPUResourceManager::CreateTexture(SDL_GPU_TEXTUREUSAGE_SAMPLER | SDL_GPU_TEXTUREUSAGE_COLOR_TARGET, face->glyph->bitmap.width, face->glyph->bitmap.rows, GLYPH_PIXEL_DATA.data()), + }; + } + + FT_Done_Face(face); + + s_fonts[name] = IA_MOVE(result); + } +} // namespace ia::iae \ No newline at end of file diff --git a/Engine/Src/Imp/CPP/InputManager.cpp b/Engine/Src/Imp/CPP/InputManager.cpp index 4db4a9f..a959bd1 100644 --- a/Engine/Src/Imp/CPP/InputManager.cpp +++ b/Engine/Src/Imp/CPP/InputManager.cpp @@ -23,10 +23,18 @@ namespace ia::iae BOOL InputManager::s_keys[256]; BOOL InputManager::s_prevKeys[256]; - InputKey InputManager::s_axisInputs[4]; Vec2 InputManager::s_pointerPosition{}; - Map InputManager::s_actionNames; - Vector> InputManager::s_actions; + InputManager::KeyboardGamePadMapping InputManager::s_keyboardGamePadMapping{}; + + BOOL InputManager::s_buttonA{}; + BOOL InputManager::s_buttonB{}; + BOOL InputManager::s_buttonC{}; + BOOL InputManager::s_buttonD{}; + INT16 InputManager::s_verticalAxis{}; + INT16 InputManager::s_horizontalAxis{}; + + BOOL InputManager::s_onScreenGamePadEnabled{}; + BOOL InputManager::s_keyboardGamePadEnabled{}; VOID InputManager::Initialize() { @@ -60,12 +68,6 @@ namespace ia::iae } } - Vec2 InputManager::GetAxis() - { - return Vec2{IsKeyDown(s_axisInputs[3]) + IsKeyDown(s_axisInputs[2]) * -1, - IsKeyDown(s_axisInputs[1]) + IsKeyDown(s_axisInputs[0]) * -1}; - } - VOID InputManager::SwitchModeToText() { SDL_StartTextInput(g_windowHandle); @@ -96,202 +98,232 @@ namespace ia::iae return s_prevKeys[(UINT8) key] && !s_keys[(UINT8) key]; } - BOOL InputManager::IsActionDown(IN Handle action) + VOID InputManager::SetupOnScreenGamePad() { - const auto &t = s_actions[action]; - for (const auto &k : t) - if (IsKeyDown(k)) - return true; - return false; + s_onScreenGamePadEnabled = true; } - BOOL InputManager::WasActionPressed(IN Handle action) + VOID InputManager::SetupKeyboardGamePad(IN CONST KeyboardGamePadMapping &mapping) { - const auto &t = s_actions[action]; - for (const auto &k : t) - if (WasKeyPressed(k)) - return true; - return false; + s_keyboardGamePadEnabled = true; + s_keyboardGamePadMapping = mapping; } - BOOL InputManager::WasActionReleased(IN Handle action) + BOOL InputManager::GetButtonA() { - const auto &t = s_actions[action]; - for (const auto &k : t) - if (WasKeyReleased(k)) - return true; - return false; + return s_buttonA; } - BOOL InputManager::IsActionDown(IN CONST String &action) + BOOL InputManager::GetButtonB() { - return IsActionDown(s_actionNames[action]); + return s_buttonB; } - BOOL InputManager::WasActionPressed(IN CONST String &action) + BOOL InputManager::GetButtonC() { - return WasActionPressed(s_actionNames[action]); + return s_buttonC; } - BOOL InputManager::WasActionReleased(IN CONST String &action) + BOOL InputManager::GetButtonD() { - return WasActionReleased(s_actionNames[action]); + return s_buttonD; } - Handle InputManager::BindAction(IN CONST String &name, IN InputKey key) + INT16 InputManager::GetVerticalAxis() { - s_actions.pushBack({key}); - const auto handle = s_actions.size() - 1; - s_actionNames[name] = handle; - return handle; + return s_verticalAxis; } - VOID InputManager::BindAxis(IN InputKey upKey, IN InputKey downKey, IN InputKey leftKey, IN InputKey rightKey) + INT16 InputManager::GetHorizontalAxis() { - s_axisInputs[0] = upKey; - s_axisInputs[1] = downKey; - s_axisInputs[2] = leftKey; - s_axisInputs[3] = rightKey; + return s_horizontalAxis; } - VOID InputManager::SetKey(IN InputKey key, IN BOOL state) + IVec2 InputManager::GetDirectionalInput() { - s_keys[(UINT8) key] = state; + return IVec2{GetHorizontalAxis(), GetVerticalAxis()}; } - VOID InputManager::SetAxis(IN BOOL up, IN BOOL down, IN BOOL left, IN BOOL right) + VOID InputManager::SetButtonA(IN BOOL value) { - s_keys[(UINT8) s_axisInputs[0]] = up; - s_keys[(UINT8) s_axisInputs[1]] = down; - s_keys[(UINT8) s_axisInputs[2]] = left; - s_keys[(UINT8) s_axisInputs[3]] = right; + s_buttonA = value; } - VOID InputManager::SetAxisUp(IN BOOL v) + VOID InputManager::SetButtonB(IN BOOL value) { - s_keys[(UINT8) s_axisInputs[0]] = v; + s_buttonB = value; } - VOID InputManager::SetAxisDown(IN BOOL v) + VOID InputManager::SetButtonC(IN BOOL value) { - s_keys[(UINT8) s_axisInputs[1]] = v; + s_buttonC = value; } - VOID InputManager::SetAxisLeft(IN BOOL v) + VOID InputManager::SetButtonD(IN BOOL value) { - s_keys[(UINT8) s_axisInputs[2]] = v; + s_buttonD = value; } - VOID InputManager::SetAxisRight(IN BOOL v) + VOID InputManager::SetVerticalAxis(IN INT16 value) { - s_keys[(UINT8) s_axisInputs[3]] = v; + s_verticalAxis = value; + } + + VOID InputManager::SetHorizontalAxis(IN INT16 value) + { + s_horizontalAxis = value; + } + + VOID InputManager::Draw() + { + if (s_onScreenGamePadEnabled) + { + //Engine::SetRenderState_Texture(0); + //Engine::SetRenderState_FlippedH(false); + //Engine::SetRenderState_FlippedV(false); + //Engine::SetRenderState_ColorOverlay({0xFF, 0xFF, 0xFF, 0xFF}); + //Engine::SetRenderState_TextureOffset({0, 0}); + //Engine::SetRenderState_CameraRelative(false); + //Engine::SetRenderState_Transform({300.0f, 500.0f}, + // {100.0f, 100.0f}, + // 0); + //Engine::DrawGeometry(Engine::GetGeometry_Circle(), 0xFF, 0); + } + } + + VOID InputManager::Update() + { + s_buttonA = false; + s_buttonB = false; + s_buttonC = false; + s_buttonD = false; + s_verticalAxis = 0; + s_horizontalAxis = 0; + + if (s_onScreenGamePadEnabled) + { + } + + if (s_keyboardGamePadEnabled) + { + s_buttonA |= IsKeyDown(s_keyboardGamePadMapping.ButtonA); + s_buttonB |= IsKeyDown(s_keyboardGamePadMapping.ButtonB); + s_buttonC |= IsKeyDown(s_keyboardGamePadMapping.ButtonC); + s_buttonD |= IsKeyDown(s_keyboardGamePadMapping.ButtonD); + s_verticalAxis += + IsKeyDown(s_keyboardGamePadMapping.AxisDown) + IsKeyDown(s_keyboardGamePadMapping.AxisUp) * -1; + s_horizontalAxis += + IsKeyDown(s_keyboardGamePadMapping.AxisRight) + IsKeyDown(s_keyboardGamePadMapping.AxisLeft) * -1; + } } } // namespace ia::iae namespace ia::iae { - Vec2 Engine::GetInputAxis() - { - return InputManager::GetAxis(); - } - - VOID Engine::SwitchInputModeToText() + VOID Engine::Input_SwitchModeToText() { InputManager::SwitchModeToText(); } - VOID Engine::SwitchInputModeToAction() + VOID Engine::Input_SwitchModeToAction() { InputManager::SwitchModeToAction(); } - Vec2 Engine::GetInputPointerPosition() + Vec2 Engine::Input_GetPointerPosition() { return InputManager::GetPointerPosition(); } - BOOL Engine::IsInputKeyDown(IN InputKey key) + BOOL Engine::Input_IsKeyDown(IN InputKey key) { return InputManager::IsKeyDown(key); } - BOOL Engine::WasInputKeyPressed(IN InputKey key) + BOOL Engine::Input_WasKeyPressed(IN InputKey key) { return InputManager::WasKeyPressed(key); } - BOOL Engine::WasInputKeyReleased(IN InputKey key) + BOOL Engine::Input_WasKeyReleased(IN InputKey key) { return InputManager::WasKeyReleased(key); } - BOOL Engine::IsInputActionDown(IN Handle action) + VOID Engine::Input_SetupOnScreenGamePad() { - return InputManager::IsActionDown(action); + InputManager::SetupOnScreenGamePad(); } - BOOL Engine::WasInputActionPressed(IN Handle action) + VOID Engine::Input_SetupKeyboardGamePad(IN InputKey axisLeft, IN InputKey axisRight, IN InputKey axisDown, + IN InputKey axisUp, IN InputKey buttonA, IN InputKey buttonB, + IN InputKey buttonC, IN InputKey buttonD) { - return InputManager::WasActionPressed(action); + InputManager::SetupKeyboardGamePad({axisLeft, axisRight, axisDown, axisUp, buttonA, buttonB, buttonC, buttonD}); } - BOOL Engine::WasInputActionReleased(IN Handle action) + BOOL Engine::Input_GetButtonA() { - return InputManager::WasActionReleased(action); + return InputManager::GetButtonA(); } - BOOL Engine::IsInputActionDown(IN CONST String &action) + BOOL Engine::Input_GetButtonB() { - return InputManager::IsActionDown(action); + return InputManager::GetButtonB(); } - BOOL Engine::WasInputActionPressed(IN CONST String &action) + BOOL Engine::Input_GetButtonC() { - return InputManager::WasActionPressed(action); + return InputManager::GetButtonC(); } - BOOL Engine::WasInputActionReleased(IN CONST String &action) + BOOL Engine::Input_GetButtonD() { - return InputManager::WasActionReleased(action); + return InputManager::GetButtonD(); } - Handle Engine::BindInputAction(IN CONST String &name, IN InputKey key) + INT16 Engine::Input_GetVerticalAxis() { - return InputManager::BindAction(name, key); + return InputManager::GetVerticalAxis(); } - VOID Engine::BindInputAxis(IN InputKey upKey, IN InputKey downKey, IN InputKey leftKey, IN InputKey rightKey) + INT16 Engine::Input_GetHorizontalAxis() { - InputManager::BindAxis(upKey, downKey, leftKey, rightKey); + return InputManager::GetHorizontalAxis(); } - VOID Engine::SetKey(IN InputKey key, IN BOOL state) + IVec2 Engine::Input_GetDirectionalInput() { - InputManager::SetKey(key, state); + return InputManager::GetDirectionalInput(); } - VOID Engine::SetAxis(IN BOOL up, IN BOOL down, IN BOOL left, IN BOOL right) + VOID Engine::Input_SetButtonA(IN BOOL value) { - InputManager::SetAxis(up, down, left, right); + InputManager::SetButtonA(value); } - VOID Engine::SetAxisUp(IN BOOL v) + VOID Engine::Input_SetButtonB(IN BOOL value) { - InputManager::SetAxisUp(v); + InputManager::SetButtonB(value); } - VOID Engine::SetAxisDown(IN BOOL v) + VOID Engine::Input_SetButtonC(IN BOOL value) { - InputManager::SetAxisDown(v); + InputManager::SetButtonC(value); } - VOID Engine::SetAxisLeft(IN BOOL v) + VOID Engine::Input_SetButtonD(IN BOOL value) { - InputManager::SetAxisLeft(v); + InputManager::SetButtonD(value); } - VOID Engine::SetAxisRight(IN BOOL v) + VOID Engine::Input_SetVerticalAxis(IN INT16 value) { - InputManager::SetAxisRight(v); + InputManager::SetVerticalAxis(value); + } + + VOID Engine::Input_SetHorizontalAxis(IN INT16 value) + { + InputManager::SetHorizontalAxis(value); } } // namespace ia::iae \ No newline at end of file diff --git a/Engine/Src/Imp/CPP/InternalEngine.cpp b/Engine/Src/Imp/CPP/InternalEngine.cpp index 94d9b0a..e0e026b 100644 --- a/Engine/Src/Imp/CPP/InternalEngine.cpp +++ b/Engine/Src/Imp/CPP/InternalEngine.cpp @@ -16,13 +16,14 @@ #include #include +#include #include #include +#include #include #include #include #include -#include #include #include @@ -52,15 +53,14 @@ namespace ia::iae if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD)) THROW_UNKNOWN("Failed to intialize SDL: ", SDL_GetError()); - if (!(g_windowHandle = SDL_CreateWindow(g_gameName.c_str(), config->ScreenWidth, config->ScreenHeight, + if (!(g_windowHandle = SDL_CreateWindow(g_gameName.c_str(), config->WindowWidth, config->WindowHeight, SDL_WINDOW_RESIZABLE))) THROW_UNKNOWN("Failed to create the SDL window: ", SDL_GetError()); // SDL_SetWindowResizable(g_windowHandle, false); const auto gameVersion = g_gameVersion; - SDL_SetAppMetadata(g_gameName.c_str(), IA_STRINGIFY_VERSION(gameVersion).c_str(), - g_gamePackageName.c_str()); + SDL_SetAppMetadata(g_gameName.c_str(), IA_STRINGIFY_VERSION(gameVersion).c_str(), g_gamePackageName.c_str()); Time::Initialize(); Random::Initialize(); @@ -70,12 +70,13 @@ namespace ia::iae InputManager::Initialize(); ResourceManager::Initialize(); WorldManager::Initialize(); + FontManager::Initialize(); UI::Initialize(); Physics::Initialize(); Game_OnInitialize(); - Engine::ResizeDisplay(config->ScreenWidth, config->ScreenHeight); + Engine::ResizeDisplay(config->WindowWidth, config->WindowHeight); } VOID __Internal_Engine::Terminate() @@ -84,6 +85,7 @@ namespace ia::iae Physics::Terminate(); UI::Terminate(); + FontManager::Terminate(); WorldManager::Terminate(); ResourceManager::Terminate(); InputManager::Terminate(); @@ -102,6 +104,7 @@ namespace ia::iae { UI::Update(); Physics::Update(); + InputManager::Update(); WorldManager::Update(); WorldManager::FixedUpdate(); Game_OnUpdate(Time::GetFrameDeltaTime()); @@ -110,6 +113,7 @@ namespace ia::iae Renderer::BeginFrame(); WorldManager::Draw(); UI::Draw(); + InputManager::Draw(); Renderer::EndFrame(); } @@ -132,7 +136,8 @@ namespace ia::iae return (FLOAT32) m_value + ((FLOAT32) m_value * (Random::Get() * m_randomAdjustment) / 100.0f); } - INT32 Run(IN CONST String& name, IN CONST String& packageName, IN CONST String& developerName, IN CONST String& publisherName, IN IA_VERSION_TYPE version) + INT32 Run(IN CONST String &name, IN CONST String &packageName, IN CONST String &developerName, + IN CONST String &publisherName, IN IA_VERSION_TYPE version) { g_gameName = name; g_gameVersion = version; diff --git a/Engine/Src/Imp/CPP/Nodes/UIButtonNode.cpp b/Engine/Src/Imp/CPP/Nodes/UIButtonNode.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Engine/Src/Imp/CPP/Nodes/UIImageNode.cpp b/Engine/Src/Imp/CPP/Nodes/UIImageNode.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Engine/Src/Imp/CPP/Nodes/UILabelNode.cpp b/Engine/Src/Imp/CPP/Nodes/UILabelNode.cpp new file mode 100644 index 0000000..164b155 --- /dev/null +++ b/Engine/Src/Imp/CPP/Nodes/UILabelNode.cpp @@ -0,0 +1,25 @@ +// 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 + +namespace ia::iae +{ + UILabelNode::UILabelNode(IN CONST String &name) : UINode(name), m_labelComponent(AddComponent()) + { + } +} // namespace ia::iae \ No newline at end of file diff --git a/Engine/Src/Imp/CPP/Nodes/UINode.cpp b/Engine/Src/Imp/CPP/Nodes/UINode.cpp new file mode 100644 index 0000000..a313418 --- /dev/null +++ b/Engine/Src/Imp/CPP/Nodes/UINode.cpp @@ -0,0 +1,62 @@ +// 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 + +namespace ia::iae +{ + UINode::UINode(IN CONST String &name): INode(name) + { + } + + UINode::~UINode() + { + for(auto& t: m_components) + delete t; + } + + VOID UINode::Draw() + { + for(auto& t: m_components) + t->Draw(); + for(auto& t: m_children) + t->Draw(); + } + + VOID UINode::DebugDraw() + { + for(auto& t: m_components) + t->DebugDraw(); + for(auto& t: m_children) + t->DebugDraw(); + } + + VOID UINode::Update() + { + for(auto& t: m_components) + t->Update(); + for(auto& t: m_children) + t->Update(); + } + + VOID UINode::FixedUpdate() + { + for(auto& t: m_components) + t->FixedUpdate(); + for(auto& t: m_children) + t->FixedUpdate(); + } +} // namespace ia::iae \ No newline at end of file diff --git a/Engine/Src/Imp/CPP/Nodes/UITextNode.cpp b/Engine/Src/Imp/CPP/Nodes/UITextNode.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Engine/Src/Imp/CPP/Physics.cpp b/Engine/Src/Imp/CPP/Physics.cpp index b87287c..f3eafb6 100644 --- a/Engine/Src/Imp/CPP/Physics.cpp +++ b/Engine/Src/Imp/CPP/Physics.cpp @@ -33,7 +33,7 @@ namespace ia::iae VOID Physics::Update() { - if(Engine::WasInputKeyPressed(InputKey::F6)) + if(Engine::Input_WasKeyPressed(InputKey::F6)) g_physicsDebugDrawEnabled = !g_physicsDebugDrawEnabled; } diff --git a/Engine/Src/Imp/CPP/Renderer/GPUResourceManager.cpp b/Engine/Src/Imp/CPP/Renderer/GPUResourceManager.cpp index f89e85f..311f806 100644 --- a/Engine/Src/Imp/CPP/Renderer/GPUResourceManager.cpp +++ b/Engine/Src/Imp/CPP/Renderer/GPUResourceManager.cpp @@ -67,7 +67,7 @@ namespace ia::iae IN INT32 height, IN PCUINT8 rgbaData, IN SDL_GPUTextureFormat format, IN BOOL generateMipmaps) { - const auto mipLevels = generateMipmaps ? floor(log2(ia_max(width, height))) + 1 : 1; + const auto mipLevels = 1;//generateMipmaps ? ia_max((UINT32)(floor(log2(ia_max(width, height))) + 1), (UINT32)1) : (UINT32)1; STATIC Vector TMP_COLOR_BUFFER; diff --git a/Engine/Src/Imp/CPP/Renderer/Renderer.cpp b/Engine/Src/Imp/CPP/Renderer/Renderer.cpp index 59b9839..c5f2fd5 100644 --- a/Engine/Src/Imp/CPP/Renderer/Renderer.cpp +++ b/Engine/Src/Imp/CPP/Renderer/Renderer.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -45,6 +46,7 @@ namespace ia::iae Pipeline *Renderer::s_postprocessPipeline{}; Renderer::Geometry *Renderer::s_quadGeometry{}; + Renderer::Geometry *Renderer::s_circleGeometry{}; Vector Renderer::s_drawEntries; @@ -123,6 +125,125 @@ namespace ia::iae {glm::vec3{0, 0, 0}, glm::vec2{0, 0}, glm::vec4{1.0f, 1.0f, 1.0f, 1.0f}}, }, {0, 1, 2, 2, 3, 0}); + + s_circleGeometry = CreateGeometry( + { + {{0.0000000f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.0000000f}, + {0.5000000f, 0.5000000f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 0 Center + {{1.0000000f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.0000000f}, + {1.0000000f, 0.5000000f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 1 + {{0.9848078f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.1736482f}, + {0.9924039f, 0.5868241f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 2 + {{0.9396926f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.3420201f}, + {0.9698463f, 0.6710101f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 3 + {{0.8660254f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.5000000f}, + {0.9330127f, 0.7500000f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 4 + {{0.7660444f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.6427876f}, + {0.8830222f, 0.8213938f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 5 + {{0.6427876f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.7660444f}, + {0.8213938f, 0.8830222f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 6 + {{0.5000000f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.8660254f}, + {0.7500000f, 0.9330127f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 7 + {{0.3420201f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.9396926f}, + {0.6710101f, 0.9698463f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 8 + {{0.1736482f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.9848078f}, + {0.5868241f, 0.9924039f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 9 + {{0.0000000f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 1.0000000f}, + {0.5000000f, 1.0000000f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 10 + {{-0.1736482f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.9848078f}, + {0.4131759f, 0.9924039f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 11 + {{-0.3420201f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.9396926f}, + {0.3289899f, 0.9698463f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 12 + {{-0.5000000f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.8660254f}, + {0.2500000f, 0.9330127f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 13 + {{-0.6427876f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.7660444f}, + {0.1786062f, 0.8830222f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 14 + {{-0.7660444f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.6427876f}, + {0.1169778f, 0.8213938f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 15 + {{-0.8660254f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.5000000f}, + {0.0669873f, 0.7500000f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 16 + {{-0.9396926f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.3420201f}, + {0.0301537f, 0.6710101f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 17 + {{-0.9848078f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.1736482f}, + {0.0075961f, 0.5868241f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 18 + {{-1.0000000f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * 0.0000000f}, + {0.0000000f, 0.5000000f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 19 + {{-0.9848078f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * -0.1736482f}, + {0.0075961f, 0.4131759f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 20 + {{-0.9396926f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * -0.3420201f}, + {0.0301537f, 0.3289899f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 21 + {{-0.8660254f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * -0.5000000f}, + {0.0669873f, 0.2500000f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 22 + {{-0.7660444f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * -0.6427876f}, + {0.1169778f, 0.1786062f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 23 + {{-0.6427876f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * -0.7660444f}, + {0.1786062f, 0.1169778f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 24 + {{-0.5000000f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * -0.8660254f}, + {0.2500000f, 0.0669873f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 25 + {{-0.3420201f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * -0.9396926f}, + {0.3289899f, 0.0301537f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 26 + {{-0.1736482f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * -0.9848078f}, + {0.4131759f, 0.0075961f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 27 + {{-0.0000000f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * -1.0000000f}, + {0.5000000f, 0.0000000f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 28 + {{0.1736482f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * -0.9848078f}, + {0.5868241f, 0.0075961f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 29 + {{0.3420201f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * -0.9396926f}, + {0.6710101f, 0.0301537f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 30 + {{0.5000000f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * -0.8660254f}, + {0.7500000f, 0.0669873f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 31 + {{0.6427876f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * -0.7660444f}, + {0.8213938f, 0.1169778f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 32 + {{0.7660444f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * -0.6427876f}, + {0.8830222f, 0.1786062f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 33 + {{0.8660254f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * -0.5000000f}, + {0.9330127f, 0.2500000f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 34 + {{0.9396926f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * -0.3420201f}, + {0.9698463f, 0.3289899f}, + {1.0f, 1.0f, 1.0f, 1.0f}}, // 35 + {{0.9848078f, (1.0f / Engine::GetDisplayAspectRatio()) * 0.75f * -0.1736482f}, + {0.9924039f, 0.4131759f}, + {1.0f, 1.0f, 1.0f, 1.0f}} // 36 + }, + {0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 7, 0, 7, 8, 0, 8, 9, 0, 9, 10, + 0, 10, 11, 0, 11, 12, 0, 12, 13, 0, 13, 14, 0, 14, 15, 0, 15, 16, 0, 16, 17, 0, 17, 18, 0, 18, 19, + 0, 19, 20, 0, 20, 21, 0, 21, 22, 0, 22, 23, 0, 23, 24, 0, 24, 25, 0, 25, 26, 0, 26, 27, 0, 27, 28, + 0, 28, 29, 0, 29, 30, 0, 30, 31, 0, 31, 32, 0, 32, 33, 0, 33, 34, 0, 34, 35, 0, 35, 36, 0, 36, 1}); } VOID Renderer::Terminate() @@ -130,6 +251,7 @@ namespace ia::iae SDL_WaitForGPUIdle(s_gpuDevice); DestroyGeometry(s_quadGeometry); + DestroyGeometry(s_circleGeometry); DebugDraw::Terminate(); @@ -321,6 +443,36 @@ namespace ia::iae DrawEntry{.Layer = layer, .SortIndex = t, .DrawState = s_state, .GeometryHandle = handle}); } + VOID Renderer::DrawText(IN CONST String &text, IN Vec2 position, IN FLOAT32 scale, IN FLOAT32 rotation, + IN UINT8 layer, IN UINT16 sortIndex) + { + const auto &font = FontManager::GetFont("Roboto"); + const auto t = (UINT16) (sortIndex + ((UINT16) s_state.PositionY * s_state.YSortingEnabled)); + Vec3 p{}; + Vec3 s{}; + for (const auto &c : text) + { + if (!c) + break; + const auto glyph = font.Chars[(UINT8) c]; + + p = Vec3(position.x, position.y, 0.0f) + + Vec3(glyph.Bearing.x, glyph.Size.y - glyph.Bearing.y, 0.0f) * scale; + p.y += (16 - glyph.Size.y) * scale; + s = Vec3(scale * glyph.Size.x, scale * glyph.Size.y, 1.0f); + + s_state.ActiveTexture = glyph.Texture; + s_state.PositionY = position.y; + s_state.ModelMatrix = glm::translate(glm::mat4(1.0f), p); + s_state.ModelMatrix = glm::rotate(s_state.ModelMatrix, rotation, glm::vec3(0.0f, 0.0f, 1.0f)); + s_state.ModelMatrix = glm::scale(s_state.ModelMatrix, s); + s_drawEntries.pushBack( + DrawEntry{.Layer = layer, .SortIndex = t, .DrawState = s_state, .GeometryHandle = s_quadGeometry}); + + position.x += glyph.Advance * scale; + } + } + VOID Renderer::WaitForGPUIdle() { SDL_WaitForGPUIdle(s_gpuDevice); @@ -334,6 +486,11 @@ namespace ia::iae return IVec2(Renderer::s_screenWidth, Renderer::s_screenHeight); } + FLOAT32 Engine::GetDisplayAspectRatio() + { + return (FLOAT32) Renderer::s_screenHeight / (FLOAT32) Renderer::s_screenWidth; + } + VOID Engine::SetActiveCamera(IN CameraComponent *cameraComponent) { Renderer::s_activeCamera = cameraComponent; @@ -365,6 +522,12 @@ namespace ia::iae Renderer::DrawGeometry((Renderer::Geometry *) handle, layer, sortIndex); } + VOID Engine::DrawText(IN CONST String &text, IN Vec2 position, IN FLOAT32 scale, IN FLOAT32 rotation, + IN UINT8 layer, IN UINT16 sortIndex) + { + Renderer::DrawText(text, position, scale, rotation, layer, sortIndex); + } + VOID Engine::SetRenderState_Scissor(IN IVec4 rect) { Renderer::s_scissor = rect.z ? SDL_Rect{0, 0, Renderer::s_screenWidth, Renderer::s_screenHeight} @@ -431,4 +594,9 @@ namespace ia::iae { return (Handle) Renderer::s_quadGeometry; } + + Handle Engine::GetGeometry_Circle() + { + return (Handle) Renderer::s_circleGeometry; + } } // namespace ia::iae \ No newline at end of file diff --git a/Engine/Src/Imp/CPP/Scene.cpp b/Engine/Src/Imp/CPP/Scene.cpp index ad5b2b6..9cef93a 100644 --- a/Engine/Src/Imp/CPP/Scene.cpp +++ b/Engine/Src/Imp/CPP/Scene.cpp @@ -17,31 +17,13 @@ #include #include -#include - namespace ia::iae { - // ----------------------------------------------- - // getInnerXML and xml_string_writer were taken from https://stackoverflow.com/a/60337372 - struct xml_string_writer : pugi::xml_writer + Scene::Scene() { - std::string result; - - virtual void write(const void *data, size_t size) - { - result.append(static_cast(data), size); - } - }; - - const auto getInnerXML = [](pugi::xml_node target) { - xml_string_writer writer; - for (pugi::xml_node child = target.first_child(); child; child = child.next_sibling()) - child.print(writer, ""); - return writer.result; - }; - - // ----------------------------------------------- + } + RefPtr Scene::Create() { const auto scene = MakeRefPtr(); @@ -52,106 +34,6 @@ namespace ia::iae return scene; } - RefPtr Scene::Create(IN CONST String &sceneXML, - IN std::function(IN CONST String &, IN Handle)> getCustomNode, - IN std::function getResource) - { - const auto scene = Create(); - - pugi::xml_document doc; - doc.load_string(sceneXML.c_str()); - const auto sceneRoot = doc.child("Scene"); - - Map resources; - - // Process Resources - const auto resRoot = sceneRoot.child("Resources"); - if (!resRoot) - THROW_INVALID_DATA("Scene file is missing 'Resources' tag"); - { - for (const auto &t : resRoot.children()) - { - if (!strcmp(t.name(), "Image")) - { - resources[t.attribute("name").as_string()] = getResource( - ResourceType::IMAGE, t.attribute("path").as_string(), t.attribute("index").as_llong()); - } - else if (!strcmp(t.name(), "Audio")) - { - resources[t.attribute("name").as_string()] = - getResource(ResourceType::SOUND, t.attribute("path").as_string(), 0); - } - } - } - - // Process Properties - const auto propRoot = sceneRoot.child("Properties"); - if (!propRoot) - THROW_INVALID_DATA("Scene file is missing 'Properties' tag"); - { - auto t = propRoot.child("Extent"); - scene->Extent() = Vec2{t.attribute("width").as_float(), t.attribute("height").as_float()}; - - t = propRoot.child("Viewport"); - scene->Viewport() = Vec2{t.attribute("width").as_float(), t.attribute("height").as_float()}; - } - - // Process Nodes - const auto nodeRoot = sceneRoot.child("Nodes"); - if (!nodeRoot) - THROW_INVALID_DATA("Scene file is missing 'Nodes' tag"); - { - for (const auto &t : nodeRoot) - { - Node2D* n{}; - if (!strcmp(t.name(), "TextureNode")) - { - const auto node = MakeRefPtr(Engine::GetUniqueResourceName()); - node->GetTextureComponent()->SetTexture(resources[t.attribute("texture").as_string()]); - scene->AddNode(node); - n = node.get(); - } - else - { - Handle id{INVALID_HANDLE}; - const auto attrID = t.attribute("id"); - if(attrID) - id = (Handle)attrID.as_ullong(); - const auto node = getCustomNode(t.name(), id); - scene->AddNode(node); - n = node.get(); - } - - if(!n) continue; - if(t.attribute("X") && t.attribute("Y")) - { - n->SetLocalPosition({ - t.attribute("X").as_float(), - t.attribute("Y").as_float() - }); - } - } - } - - // Process UI - const auto uiRoot = sceneRoot.child("UI"); - if (!uiRoot) - THROW_INVALID_DATA("Scene file is missing 'UI' tag"); - { - scene->UIMarkupStyles() = getInnerXML(uiRoot.child("CSS")).c_str(); - auto html = String(getInnerXML(uiRoot.child("HTML")).c_str()); - html = - Utils::RegexReplaceGroups(html, "UIMarkup() = html; - } - - return scene; - } - VOID Scene::Draw() { for (auto &t : m_nodes) diff --git a/Engine/Src/Imp/CPP/SceneManager.cpp b/Engine/Src/Imp/CPP/SceneManager.cpp new file mode 100644 index 0000000..2ab3b88 --- /dev/null +++ b/Engine/Src/Imp/CPP/SceneManager.cpp @@ -0,0 +1,160 @@ +// 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 + +namespace ia::iae +{ + // ----------------------------------------------- + // getInnerXML and xml_string_writer were taken from https://stackoverflow.com/a/60337372 + struct xml_string_writer : pugi::xml_writer + { + std::string result; + + virtual void write(const void *data, size_t size) + { + result.append(static_cast(data), size); + } + }; + + const auto getInnerXML = [](pugi::xml_node target) { + xml_string_writer writer; + for (pugi::xml_node child = target.first_child(); child; child = child.next_sibling()) + child.print(writer, ""); + return writer.result; + }; + // ----------------------------------------------- +} + +namespace ia::iae +{ + SceneManager::SceneManager(IN std::function(IN CONST String &, IN CONST Vector&)> getCustomNode, + IN std::function getResource): + m_customNodeGetter(getCustomNode), m_resourceGetter(getResource) + { + } + + SceneManager::~SceneManager() + { + for(const auto& t: m_scenes) + delete t->Value; + } + + VOID SceneManager::SwitchTo(IN CONST String &name) + { + Engine::ChangeActiveScene(m_scenes[name]); + } + + Scene *SceneManager::GetScene(IN CONST String &name) + { + return m_scenes[name]; + } + + VOID SceneManager::AddScene(IN Scene *scene, IN CONST String &name, IN CONST String &xml) + { + pugi::xml_document doc; + doc.load_string(xml.c_str()); + const auto sceneRoot = doc.child("Scene"); + + Map resources; + + // Process Resources + const auto resRoot = sceneRoot.child("Resources"); + if (!resRoot) + THROW_INVALID_DATA("Scene file is missing 'Resources' tag"); + { + for (const auto &t : resRoot.children()) + { + if (!strcmp(t.name(), "Image")) + { + resources[t.attribute("name").as_string()] = m_resourceGetter( + ResourceType::IMAGE, t.attribute("path").as_string(), t.attribute("index").as_llong()); + } + else if (!strcmp(t.name(), "Audio")) + { + resources[t.attribute("name").as_string()] = + m_resourceGetter(ResourceType::SOUND, t.attribute("path").as_string(), 0); + } + } + } + + // Process Properties + const auto propRoot = sceneRoot.child("Properties"); + if (!propRoot) + THROW_INVALID_DATA("Scene file is missing 'Properties' tag"); + { + auto t = propRoot.child("Extent"); + scene->Extent() = Vec2{t.attribute("width").as_float(), t.attribute("height").as_float()}; + + t = propRoot.child("Viewport"); + scene->Viewport() = Vec2{t.attribute("width").as_float(), t.attribute("height").as_float()}; + } + + // Process Nodes + const auto nodeRoot = sceneRoot.child("Nodes"); + if (!nodeRoot) + THROW_INVALID_DATA("Scene file is missing 'Nodes' tag"); + { + for (const auto &t : nodeRoot) + { + Node2D* n{}; + if (!strcmp(t.name(), "TextureNode")) + { + const auto node = MakeRefPtr(Engine::GetUniqueResourceName()); + node->GetTextureComponent()->SetTexture(resources[t.attribute("texture").as_string()]); + scene->AddNode(node); + n = node.get(); + } + else + { + const auto node = m_customNodeGetter(t.name(), String(t.attribute("id").as_string()).split(';')); + scene->AddNode(node); + n = node.get(); + } + + if(!n) continue; + if(t.attribute("X") && t.attribute("Y")) + { + n->SetLocalPosition({ + t.attribute("X").as_float(), + t.attribute("Y").as_float() + }); + } + } + } + + // Process UI + const auto uiRoot = sceneRoot.child("UI"); + if (!uiRoot) + THROW_INVALID_DATA("Scene file is missing 'UI' tag"); + { + scene->UIMarkupStyles() = getInnerXML(uiRoot.child("CSS")).c_str(); + auto html = String(getInnerXML(uiRoot.child("HTML")).c_str()); + html = + Utils::RegexReplaceGroups(html, "UIMarkup() = html; + } + + m_scenes[name] = scene; + } +} // namespace ia::iae \ No newline at end of file diff --git a/Engine/Src/Imp/CPP/UI.cpp b/Engine/Src/Imp/CPP/UI.cpp index 3366e72..37cd05b 100644 --- a/Engine/Src/Imp/CPP/UI.cpp +++ b/Engine/Src/Imp/CPP/UI.cpp @@ -391,16 +391,29 @@ namespace ia::iae namespace ia::iae { + INT64 UI::s_numericVariables[MAX_VARIABLE_COUNT]; + std::string UI::s_stringVariables[MAX_VARIABLE_COUNT]; + + Rml::DataModelConstructor g_dataModel; + VOID UI::Initialize() { Rml::SetRenderInterface(&g_rmlUIRenderInterface); Rml::Initialise(); + Rml::LoadFontFace("Resources/Fonts/Roboto-Black.ttf"); + const auto displayExtent = Engine::GetDisplayExtent(); g_context = Rml::CreateContext("main", Rml::Vector2i(displayExtent.x, displayExtent.y)); Rml::Debugger::Initialise(g_context); Rml::Debugger::SetVisible(false); g_document = g_context->CreateDocument(); + + g_dataModel = g_context->CreateDataModel("ui_data"); + for (INT32 i = 0; i < MAX_VARIABLE_COUNT; i++) + g_dataModel.Bind(BuildString("NumVar", i).c_str(), &s_numericVariables[i]); + for (INT32 i = 0; i < MAX_VARIABLE_COUNT; i++) + g_dataModel.Bind(BuildString("StrVar", i).c_str(), &s_stringVariables[i]); } VOID UI::Terminate() @@ -410,7 +423,7 @@ namespace ia::iae VOID UI::Update() { - if (Engine::WasInputKeyPressed(InputKey::F8)) + if (Engine::Input_WasKeyPressed(InputKey::F8)) Rml::Debugger::SetVisible(g_debuggerEnabled = !g_debuggerEnabled); g_context->Update(); @@ -483,7 +496,9 @@ namespace ia::iae VOID UI::SetMarkup(IN CONST String &markup, IN CONST String &styles) { g_styleSheetContainer = Rml::Factory::InstanceStyleSheetString(styles.c_str()); - g_markup = BuildString("", markup, ""); + g_markup = BuildString("
", + markup, "
"); g_document->SetStyleSheetContainer(g_styleSheetContainer); g_document->SetInnerRML(g_markup.c_str()); } @@ -512,6 +527,46 @@ namespace ia::iae { g_eventListener.AddPointerEnterListener(g_document->GetElementById(elementId), callback); } + + VOID UI::SetNumericVariable(IN UINT8 index, IN INT64 value) + { + s_numericVariables[index] = value; + } + + VOID UI::SetStringVariable(IN UINT8 index, IN CONST String &value) + { + s_stringVariables[index] = value.c_str(); + } + + INT64 UI::GetNumericVariable(IN UINT8 index) + { + return s_numericVariables[index]; + } + + String UI::GetStringVariable(IN UINT8 index) + { + return s_stringVariables[index].c_str(); + } + + VOID UI::SetElementWidth(IN CONST String &elementId, IN INT32 value) + { + g_document->GetElementById(elementId.c_str())->SetProperty("width", BuildString(value, "px").c_str()); + } + + INT32 UI::GetElementWidth(IN CONST String &elementId) + { + return g_document->GetElementById(elementId.c_str())->GetClientWidth(); + } + + VOID UI::SetElementHeight(IN CONST String &elementId, IN INT32 value) + { + g_document->GetElementById(elementId.c_str())->SetProperty("height", BuildString(value, "px").c_str()); + } + + INT32 UI::GetElementHeight(IN CONST String &elementId) + { + return g_document->GetElementById(elementId.c_str())->GetClientHeight(); + } } // namespace ia::iae namespace ia::iae @@ -540,7 +595,7 @@ namespace ia::iae Engine::SetRenderState_ColorOverlay({255, 255, 255, 255}); Engine::SetRenderState_TextureOffset({0, 0}); Engine::SetRenderState_CameraRelative(false); - Engine::SetRenderState_TransformUI({translation.x, translation.y}, {1.0f, 1.0f}, 0); + Engine::SetRenderState_Transform({translation.x, translation.y}, {1.0f, 1.0f}, 0); Engine::DrawGeometry((Handle) geometry, 0xFF, 0); } diff --git a/Engine/Src/Imp/CPP/WorldManager.cpp b/Engine/Src/Imp/CPP/WorldManager.cpp index bbd6726..fc5557f 100644 --- a/Engine/Src/Imp/CPP/WorldManager.cpp +++ b/Engine/Src/Imp/CPP/WorldManager.cpp @@ -19,16 +19,18 @@ namespace ia::iae { - RefPtr WorldManager::s_activeScene{}; + RefPtr g_defaultScene; + + Scene* WorldManager::s_activeScene{}; VOID WorldManager::Initialize() { - s_activeScene = Scene::Create(); + g_defaultScene = Scene::Create(); + s_activeScene = g_defaultScene.get(); } VOID WorldManager::Terminate() { - s_activeScene.reset(); } VOID WorldManager::Draw() @@ -51,7 +53,7 @@ namespace ia::iae s_activeScene->FixedUpdate(); } - VOID WorldManager::ChangeActiveScene(IN RefPtr scene) + VOID WorldManager::ChangeActiveScene(IN Scene* scene) { s_activeScene = scene; scene->OnActivate(); @@ -74,7 +76,7 @@ namespace ia::iae Scene *WorldManager::GetActiveScene() { - return s_activeScene.get(); + return s_activeScene; } } // namespace ia::iae @@ -85,7 +87,7 @@ namespace ia::iae return WorldManager::GetActiveScene(); } - VOID Engine::ChangeActiveScene(IN RefPtr scene) + VOID Engine::ChangeActiveScene(IN Scene* scene) { WorldManager::ChangeActiveScene(scene); } diff --git a/Engine/Src/Imp/HPP/FontManager.hpp b/Engine/Src/Imp/HPP/FontManager.hpp new file mode 100644 index 0000000..b774147 --- /dev/null +++ b/Engine/Src/Imp/HPP/FontManager.hpp @@ -0,0 +1,54 @@ +// 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 +#include + +namespace ia::iae +{ + class FontManager + { + public: + struct Character + { + IVec2 Size; + IVec2 Bearing; // Offset from baseline to left/top of glyph + UINT32 Advance; // Horizontal offset to advance to next glyph + SDL_GPUTexture *Texture{}; + }; + + struct Font + { + Character Chars[0x80]; + }; + + public: + STATIC VOID Initialize(); + STATIC VOID Terminate(); + + STATIC VOID LoadFont(IN CONST String &name, IN CONST String &path); + + STATIC CONST Font &GetFont(IN CONST String &name) + { + return s_fonts[name]; + } + + private: + STATIC Map s_fonts; + }; +} // namespace ia::iae \ No newline at end of file diff --git a/Engine/Src/Imp/HPP/InputManager.hpp b/Engine/Src/Imp/HPP/InputManager.hpp index 8d09c2d..b9868c3 100644 --- a/Engine/Src/Imp/HPP/InputManager.hpp +++ b/Engine/Src/Imp/HPP/InputManager.hpp @@ -24,41 +24,70 @@ namespace ia::iae { class InputManager { + public: + struct KeyboardGamePadMapping + { + IN InputKey AxisLeft; + IN InputKey AxisRight; + IN InputKey AxisDown; + IN InputKey AxisUp; + IN InputKey ButtonA; + IN InputKey ButtonB; + IN InputKey ButtonC; + IN InputKey ButtonD; + }; + public: - STATIC VOID Initialize(); - STATIC VOID Terminate(); - - STATIC VOID OnSDLEvent(IN SDL_Event *event); - - STATIC Vec2 GetAxis(); STATIC VOID SwitchModeToText(); STATIC VOID SwitchModeToAction(); + STATIC Vec2 GetPointerPosition(); + STATIC BOOL IsKeyDown(IN InputKey key); STATIC BOOL WasKeyPressed(IN InputKey key); STATIC BOOL WasKeyReleased(IN InputKey key); - STATIC BOOL IsActionDown(IN Handle action); - STATIC BOOL WasActionPressed(IN Handle action); - STATIC BOOL WasActionReleased(IN Handle action); - STATIC BOOL IsActionDown(IN CONST String& action); - STATIC BOOL WasActionPressed(IN CONST String& action); - STATIC BOOL WasActionReleased(IN CONST String& action); - STATIC Handle BindAction(IN CONST String &name, IN InputKey key); - STATIC VOID BindAxis(IN InputKey upKey, IN InputKey downKey, IN InputKey leftKey, IN InputKey rightKey); - STATIC VOID SetAxisUp(IN BOOL v); - STATIC VOID SetAxisDown(IN BOOL v); - STATIC VOID SetAxisLeft(IN BOOL v); - STATIC VOID SetAxisRight(IN BOOL v); - STATIC VOID SetKey(IN InputKey key, IN BOOL state); - STATIC VOID SetAxis(IN BOOL up, IN BOOL down, IN BOOL left, IN BOOL right); - + STATIC VOID SetupOnScreenGamePad(); + STATIC VOID SetupKeyboardGamePad(IN CONST KeyboardGamePadMapping& mapping); + + STATIC BOOL GetButtonA(); + STATIC BOOL GetButtonB(); + STATIC BOOL GetButtonC(); + STATIC BOOL GetButtonD(); + STATIC INT16 GetVerticalAxis(); + STATIC INT16 GetHorizontalAxis(); + STATIC IVec2 GetDirectionalInput(); + + STATIC VOID SetButtonA(IN BOOL value); + STATIC VOID SetButtonB(IN BOOL value); + STATIC VOID SetButtonC(IN BOOL value); + STATIC VOID SetButtonD(IN BOOL value); + STATIC VOID SetVerticalAxis(IN INT16 value); + STATIC VOID SetHorizontalAxis(IN INT16 value); + private: + STATIC BOOL s_buttonA; + STATIC BOOL s_buttonB; + STATIC BOOL s_buttonC; + STATIC BOOL s_buttonD; + STATIC INT16 s_verticalAxis; + STATIC INT16 s_horizontalAxis; STATIC BOOL s_keys[256]; STATIC BOOL s_prevKeys[256]; STATIC Vec2 s_pointerPosition; - STATIC InputKey s_axisInputs[4]; - STATIC Map s_actionNames; - STATIC Vector> s_actions; + STATIC BOOL s_onScreenGamePadEnabled; + STATIC BOOL s_keyboardGamePadEnabled; + STATIC KeyboardGamePadMapping s_keyboardGamePadMapping; + + private: + STATIC VOID Initialize(); + STATIC VOID Terminate(); + + STATIC VOID Draw(); + STATIC VOID Update(); + + STATIC VOID OnSDLEvent(IN SDL_Event *event); + + friend class __Internal_Engine; }; } // namespace ia::iae \ No newline at end of file diff --git a/Engine/Src/Imp/HPP/Renderer/Renderer.hpp b/Engine/Src/Imp/HPP/Renderer/Renderer.hpp index 57948f3..30460ac 100644 --- a/Engine/Src/Imp/HPP/Renderer/Renderer.hpp +++ b/Engine/Src/Imp/HPP/Renderer/Renderer.hpp @@ -71,6 +71,7 @@ namespace ia::iae STATIC VOID DestroyGeometry(IN Geometry* handle); STATIC VOID DrawGeometry(IN Geometry* handle, IN UINT8 layer, IN UINT16 sortIndex); + STATIC VOID DrawText(IN CONST String& text, IN Vec2 position, IN FLOAT32 scale, IN FLOAT32 rotation, IN UINT8 layer, IN UINT16 sortIndex); STATIC SDL_GPUTextureFormat GetRenderTargetFormat(); @@ -89,6 +90,7 @@ namespace ia::iae STATIC Pipeline* s_geometryPipeline; STATIC Pipeline* s_postprocessPipeline; STATIC Geometry* s_quadGeometry; + STATIC Geometry* s_circleGeometry; STATIC Vector s_drawEntries; STATIC SDL_GPURenderPass* s_activeRenderPass; STATIC SDL_GPUCommandBuffer* s_activeCommandBuffer; diff --git a/Engine/Src/Imp/HPP/WorldManager.hpp b/Engine/Src/Imp/HPP/WorldManager.hpp index 0eb1e42..031f76b 100644 --- a/Engine/Src/Imp/HPP/WorldManager.hpp +++ b/Engine/Src/Imp/HPP/WorldManager.hpp @@ -37,12 +37,12 @@ namespace ia::iae public: STATIC Scene *GetActiveScene(); - STATIC VOID ChangeActiveScene(IN RefPtr scene); + STATIC VOID ChangeActiveScene(IN Scene* scene); STATIC VOID AddNodeToActiveScene(IN RefPtr node); STATIC INode *GetNodeFromActiveScene(IN CONST String &name); STATIC VOID RemoveNodeFromActiveScene(IN CONST String &name); private: - STATIC RefPtr s_activeScene; + STATIC Scene* s_activeScene; }; } // namespace ia::iae \ No newline at end of file diff --git a/Engine/Src/Inc/IAEngine/Components/IUIComponent.hpp b/Engine/Src/Inc/IAEngine/Components/IUIComponent.hpp new file mode 100644 index 0000000..007e4d0 --- /dev/null +++ b/Engine/Src/Inc/IAEngine/Components/IUIComponent.hpp @@ -0,0 +1,51 @@ +// 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 UINode; + + class IUIComponent + { + public: + PURE_VIRTUAL(VOID Draw()); + PURE_VIRTUAL(VOID DebugDraw()); + PURE_VIRTUAL(VOID Update()); + PURE_VIRTUAL(VOID FixedUpdate()); + + public: + IUIComponent(IN UINode *node) : m_node(node) + { + } + + UINode *GetNode() + { + return m_node; + } + + CONST UINode *GetNode() CONST + { + return m_node; + } + + protected: + UINode *CONST m_node{}; + }; +} \ No newline at end of file diff --git a/Engine/Src/Inc/IAEngine/Components/UIButtonComponent.hpp b/Engine/Src/Inc/IAEngine/Components/UIButtonComponent.hpp new file mode 100644 index 0000000..e69de29 diff --git a/Engine/Src/Inc/IAEngine/Components/UIImageComponent.hpp b/Engine/Src/Inc/IAEngine/Components/UIImageComponent.hpp new file mode 100644 index 0000000..e69de29 diff --git a/Engine/Src/Inc/IAEngine/Components/UILabelComponent.hpp b/Engine/Src/Inc/IAEngine/Components/UILabelComponent.hpp new file mode 100644 index 0000000..1dd8a11 --- /dev/null +++ b/Engine/Src/Inc/IAEngine/Components/UILabelComponent.hpp @@ -0,0 +1,48 @@ +// 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 UILabelComponent : public IUIComponent + { + public: + UILabelComponent(IN UINode* node); + + String &Label() + { + return m_label; + } + + CONST String &Label() CONST + { + return m_label; + } + + public: + VOID Draw(); + VOID DebugDraw(); + + VOID Update(); + VOID FixedUpdate(); + + private: + String m_label{}; + }; +} // namespace ia::iae \ No newline at end of file diff --git a/Engine/Src/Inc/IAEngine/Components/UITextComponent.hpp b/Engine/Src/Inc/IAEngine/Components/UITextComponent.hpp new file mode 100644 index 0000000..e69de29 diff --git a/Engine/Src/Inc/IAEngine/Engine.hpp b/Engine/Src/Inc/IAEngine/Engine.hpp index 9992e17..3eb62b4 100644 --- a/Engine/Src/Inc/IAEngine/Engine.hpp +++ b/Engine/Src/Inc/IAEngine/Engine.hpp @@ -44,11 +44,14 @@ namespace ia::iae // Renderer Functions STATIC Handle GetGeometry_Quad(); + STATIC Handle GetGeometry_Circle(); STATIC Handle CreateGeometry(IN CONST Vector &vertices, IN CONST Vector &indices); STATIC VOID DestroyGeometry(IN Handle geometry); STATIC VOID DrawGeometry(IN Handle handle, IN UINT8 layer, IN UINT16 sortIndex); STATIC IVec2 GetDisplayExtent(); + STATIC FLOAT32 GetDisplayAspectRatio(); STATIC VOID ResizeDisplay(IN INT32 newWidth, IN INT32 newHeight); + STATIC VOID DrawText(IN CONST String& text, IN Vec2 position, IN FLOAT32 scale, IN FLOAT32 rotation, IN UINT8 layer, IN UINT16 sortIndex); // Renderer State Functions STATIC VOID SetRenderState_Scissor(IN IVec4 rect); @@ -96,33 +99,35 @@ namespace ia::iae // Scene Functions STATIC Scene *GetActiveScene(); - STATIC VOID ChangeActiveScene(IN RefPtr scene); + STATIC VOID ChangeActiveScene(IN Scene* scene); STATIC VOID AddNodeToActiveScene(IN RefPtr node); STATIC INode *GetNodeFromActiveScene(IN CONST String &name); STATIC VOID RemoveNodeFromActiveScene(IN CONST String &name); // Input Functions - STATIC Vec2 GetInputAxis(); - STATIC VOID SwitchInputModeToText(); - STATIC VOID SwitchInputModeToAction(); - STATIC Vec2 GetInputPointerPosition(); - STATIC BOOL IsInputKeyDown(IN InputKey key); - STATIC BOOL WasInputKeyPressed(IN InputKey key); - STATIC BOOL WasInputKeyReleased(IN InputKey key); - STATIC BOOL IsInputActionDown(IN Handle action); - STATIC BOOL WasInputActionPressed(IN Handle action); - STATIC BOOL WasInputActionReleased(IN Handle action); - STATIC BOOL IsInputActionDown(IN CONST String &action); - STATIC BOOL WasInputActionPressed(IN CONST String &action); - STATIC BOOL WasInputActionReleased(IN CONST String &action); - STATIC Handle BindInputAction(IN CONST String &name, IN InputKey key); - STATIC VOID BindInputAxis(IN InputKey upKey, IN InputKey downKey, IN InputKey leftKey, IN InputKey rightKey); - STATIC VOID SetAxisUp(IN BOOL v); - STATIC VOID SetAxisDown(IN BOOL v); - STATIC VOID SetAxisLeft(IN BOOL v); - STATIC VOID SetAxisRight(IN BOOL v); - STATIC VOID SetKey(IN InputKey key, IN BOOL state); - STATIC VOID SetAxis(IN BOOL up, IN BOOL down, IN BOOL left, IN BOOL right); + STATIC VOID Input_SwitchModeToText(); + STATIC VOID Input_SwitchModeToAction(); + STATIC Vec2 Input_GetPointerPosition(); + STATIC BOOL Input_IsKeyDown(IN InputKey key); + STATIC BOOL Input_WasKeyPressed(IN InputKey key); + STATIC BOOL Input_WasKeyReleased(IN InputKey key); + STATIC VOID Input_SetupOnScreenGamePad(); + STATIC VOID Input_SetupKeyboardGamePad(IN InputKey axisLeft, IN InputKey axisRight, IN InputKey axisDown, + IN InputKey axisUp, IN InputKey buttonA, IN InputKey buttonB, + IN InputKey buttonC, IN InputKey buttonD); + STATIC BOOL Input_GetButtonA(); + STATIC BOOL Input_GetButtonB(); + STATIC BOOL Input_GetButtonC(); + STATIC BOOL Input_GetButtonD(); + STATIC INT16 Input_GetVerticalAxis(); + STATIC INT16 Input_GetHorizontalAxis(); + STATIC IVec2 Input_GetDirectionalInput(); + STATIC VOID Input_SetButtonA(IN BOOL value); + STATIC VOID Input_SetButtonB(IN BOOL value); + STATIC VOID Input_SetButtonC(IN BOOL value); + STATIC VOID Input_SetButtonD(IN BOOL value); + STATIC VOID Input_SetVerticalAxis(IN INT16 value); + STATIC VOID Input_SetHorizontalAxis(IN INT16 value); // Utility Functions STATIC String ReadTextAsset(IN CONST String& path); diff --git a/Engine/Src/Inc/IAEngine/EngineLibraryInterface.hpp b/Engine/Src/Inc/IAEngine/EngineLibraryInterface.hpp index 933c5c7..2d74f3a 100644 --- a/Engine/Src/Inc/IAEngine/EngineLibraryInterface.hpp +++ b/Engine/Src/Inc/IAEngine/EngineLibraryInterface.hpp @@ -23,8 +23,10 @@ using namespace ia::iae; struct GameRequestedConfig { - INT32 ScreenWidth{}; - INT32 ScreenHeight{}; + INT32 DesignWidth{}; + INT32 DesignHeight{}; + INT32 WindowWidth{}; + INT32 WindowHeight{}; }; C_DECL(GameRequestedConfig* Game_GetConfigRequest()); diff --git a/Engine/Src/Inc/IAEngine/Nodes/UIButtonNode.hpp b/Engine/Src/Inc/IAEngine/Nodes/UIButtonNode.hpp new file mode 100644 index 0000000..e69de29 diff --git a/Engine/Src/Inc/IAEngine/Nodes/UIImageNode.hpp b/Engine/Src/Inc/IAEngine/Nodes/UIImageNode.hpp new file mode 100644 index 0000000..e69de29 diff --git a/Engine/Src/Inc/IAEngine/Nodes/UILabelNode.hpp b/Engine/Src/Inc/IAEngine/Nodes/UILabelNode.hpp new file mode 100644 index 0000000..6ed5aa8 --- /dev/null +++ b/Engine/Src/Inc/IAEngine/Nodes/UILabelNode.hpp @@ -0,0 +1,38 @@ +// 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 +#include + +namespace ia::iae +{ + class UILabelNode : public UINode + { + public: + UILabelNode(IN CONST String &name); + + public: + UILabelComponent *GetLabelComponent() + { + return m_labelComponent; + } + + protected: + UILabelComponent *CONST m_labelComponent{}; + }; +} // namespace ia::iae \ No newline at end of file diff --git a/Engine/Src/Inc/IAEngine/Nodes/UINode.hpp b/Engine/Src/Inc/IAEngine/Nodes/UINode.hpp index 0d4d965..d5450e3 100644 --- a/Engine/Src/Inc/IAEngine/Nodes/UINode.hpp +++ b/Engine/Src/Inc/IAEngine/Nodes/UINode.hpp @@ -17,8 +17,161 @@ #pragma once #include +#include namespace ia::iae { - + class UINode : public INode + { + public: + UINode(IN CONST String &name); + ~UINode(); + + public: + template _component_type *AddComponent() + { + const auto t = new _component_type(this); + m_components.pushBack(t); + return t; + } + + template _component_type *GetComponent() + { + for (auto &c : m_components) + { + _component_type *comp = dynamic_cast<_component_type *>(c); + if (comp) + return comp; + } + return nullptr; + } + + template Vector<_component_type *> GetComponents() + { + Vector<_component_type *> result; + for (auto &c : m_components) + { + _component_type *comp = dynamic_cast<_component_type *>(c); + if (comp) + result.pushBack(comp); + } + return result; + } + + VOID AddChild(IN RefPtr node) + { + node->m_parent = this; + m_children.pushBack(node); + } + + public: + VOID Translate(IN Vec2 v) + { + m_local.Position += v; + RecalculatePosition(); + } + + VOID Scale(IN FLOAT32 v) + { + m_local.Scale *= v; + RecalculateScale(); + } + + VOID Rotate(IN FLOAT32 v) + { + m_local.Rotation += v; + RecalculateRotation(); + } + + VOID SetLocalPosition(IN CONST Vec2 &v) + { + m_local.Position = v; + RecalculatePosition(); + } + + VOID SetLocalScale(IN CONST FLOAT32 &v) + { + m_local.Scale = v; + RecalculateScale(); + } + + VOID SetLocalRotation(IN FLOAT32 v) + { + m_local.Rotation = v; + RecalculateRotation(); + } + + public: + CONST Vec2 &GetPosition() CONST + { + return m_global.Position; + } + + CONST FLOAT32 &GetScale() CONST + { + return m_global.Scale; + } + + CONST FLOAT32 &GetRotation() CONST + { + return m_global.Rotation; + } + + CONST Vec2 &GetLocalPosition() CONST + { + return m_local.Position; + } + + CONST FLOAT32 &GetLocalScale() CONST + { + return m_local.Scale; + } + + CONST FLOAT32 &GetLocalRotation() CONST + { + return m_local.Rotation; + } + + protected: + VOID RecalculatePosition() + { + m_global.Position = (m_parent ? m_parent->GetPosition() : Vec2{}) + m_local.Position; + for (auto &c : m_children) + c->RecalculatePosition(); + } + + VOID RecalculateRotation() + { + m_global.Rotation = (m_parent ? m_parent->GetRotation() : 0) + m_local.Rotation; + for (auto &c : m_children) + c->RecalculateRotation(); + } + + VOID RecalculateScale() + { + m_global.Scale = (m_parent ? m_parent->GetScale() : 0.0f) + m_local.Scale; + for (auto &c : m_children) + c->RecalculateScale(); + } + + protected: + UINode* m_parent{}; + Vector m_components; + Vector> m_children{}; + + private: + struct + { + FLOAT32 Rotation{0.0f}; + Vec2 Position{0.0f, 0.0f}; + FLOAT32 Scale{1.0f}; + } m_local{}, m_global{}; + + public: + VOID Draw(); + VOID DebugDraw(); + + VOID Update(); + VOID FixedUpdate(); + }; } \ No newline at end of file diff --git a/Engine/Src/Inc/IAEngine/Nodes/UITextNode.hpp b/Engine/Src/Inc/IAEngine/Nodes/UITextNode.hpp new file mode 100644 index 0000000..e69de29 diff --git a/Engine/Src/Inc/IAEngine/Scene.hpp b/Engine/Src/Inc/IAEngine/Scene.hpp index 68c13a6..2ffbdcd 100644 --- a/Engine/Src/Inc/IAEngine/Scene.hpp +++ b/Engine/Src/Inc/IAEngine/Scene.hpp @@ -24,10 +24,8 @@ namespace ia::iae class Scene { public: + Scene(); STATIC RefPtr Create(); - STATIC RefPtr Create( - IN CONST String &sceneXML, IN std::function(IN CONST String &, IN Handle)> getCustomNode, - IN std::function getResource); public: VOID AddNode(IN RefPtr node); @@ -70,11 +68,11 @@ namespace ia::iae Map> m_nodes; public: - VOID Draw(); - VOID DebugDraw(); - - VOID FixedUpdate(); - VOID Update(); + VIRTUAL VOID Draw(); + VIRTUAL VOID DebugDraw(); + + VIRTUAL VOID FixedUpdate(); + VIRTUAL VOID Update(); private: VOID OnActivate(); diff --git a/Engine/Src/Inc/IAEngine/SceneManager.hpp b/Engine/Src/Inc/IAEngine/SceneManager.hpp new file mode 100644 index 0000000..8dbcc63 --- /dev/null +++ b/Engine/Src/Inc/IAEngine/SceneManager.hpp @@ -0,0 +1,50 @@ +// 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 SceneManager + { + public: + SceneManager(IN std::function(IN CONST String &, IN CONST Vector&)> getCustomNode, + IN std::function getResource); + ~SceneManager(); + + VOID SwitchTo(IN CONST String &name); + + Scene *GetScene(IN CONST String &name); + + public: + template SceneType* AddScene(IN CONST String &name, IN CONST String &xml) + { + const auto t = (Scene*)new SceneType(); + AddScene(t, name, xml); + return (SceneType*)t; + } + + private: + VOID AddScene(IN Scene *scene, IN CONST String &name, IN CONST String &xml); + + private: + Map m_scenes; + std::function(IN CONST String &, IN CONST Vector&)> m_customNodeGetter; + std::function m_resourceGetter; + }; +} // namespace ia::iae \ No newline at end of file diff --git a/Engine/Src/Inc/IAEngine/UI.hpp b/Engine/Src/Inc/IAEngine/UI.hpp index 7392ec3..e89311f 100644 --- a/Engine/Src/Inc/IAEngine/UI.hpp +++ b/Engine/Src/Inc/IAEngine/UI.hpp @@ -22,6 +22,9 @@ namespace ia::iae { class UI { + public: + STATIC CONSTEXPR UINT8 MAX_VARIABLE_COUNT = 10; + public: STATIC VOID AddFontFromFile(IN CONST String &path); @@ -33,6 +36,18 @@ namespace ia::iae STATIC VOID AddPointerExitEvent(IN PCCHAR elementId, IN std::function callback); STATIC VOID AddPointerEnterEvent(IN PCCHAR elementId, IN std::function callback); + STATIC VOID SetNumericVariable(IN UINT8 index, IN INT64 value); + STATIC VOID SetStringVariable(IN UINT8 index, IN CONST String &value); + + STATIC INT64 GetNumericVariable(IN UINT8 index); + STATIC String GetStringVariable(IN UINT8 index); + + STATIC INT32 GetElementWidth(IN CONST String &elementId); + STATIC VOID SetElementWidth(IN CONST String &elementId, IN INT32 value); + + STATIC INT32 GetElementHeight(IN CONST String &elementId); + STATIC VOID SetElementHeight(IN CONST String &elementId, IN INT32 value); + public: STATIC VOID Initialize(); STATIC VOID Terminate(); @@ -42,5 +57,9 @@ namespace ia::iae STATIC VOID OnSDLEvent(IN PVOID event); STATIC VOID OnScreenResize(IN INT32 newWidth, IN INT32 newHeight); + + private: + STATIC INT64 s_numericVariables[MAX_VARIABLE_COUNT]; + STATIC std::string s_stringVariables[MAX_VARIABLE_COUNT]; }; } // namespace ia::iae \ No newline at end of file