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