From 3861059a238666fbc1792b4d92cedcedefd64a9e Mon Sep 17 00:00:00 2001 From: Isuru Samarathunga Date: Sun, 7 Sep 2025 20:55:54 +0530 Subject: [PATCH] ResourceManager --- Dependencies/IACore | 2 +- Dependencies/IAMath | 2 +- Src/IAESandbox/CMakeLists.txt | 3 + Src/IAESandbox/imp/cpp/Game.cpp | 34 ++ Src/IAESandbox/imp/cpp/Main.cpp | 122 +------- Src/IAESandbox/imp/cpp/Map.cpp | 30 ++ Src/IAESandbox/imp/cpp/Player.cpp | 34 ++ Src/IAESandbox/imp/hpp/Game.hpp | 19 ++ Src/IAESandbox/imp/hpp/Map.hpp | 24 ++ Src/IAESandbox/imp/hpp/Player.hpp | 27 ++ Src/IAEngine/CMakeLists.txt | 2 + Src/IAEngine/imp/cpp/Audio.cpp | 2 +- .../imp/cpp/Components/AtlasRenderer.cpp | 50 +++ .../imp/cpp/Components/SoundEmitter.cpp | 2 +- .../imp/cpp/Components/SpriteRenderer.cpp | 23 +- Src/IAEngine/imp/cpp/Events/Event.cpp | 6 + Src/IAEngine/imp/cpp/IAEngine.cpp | 46 +-- Src/IAEngine/imp/cpp/Input.cpp | 69 ++++ Src/IAEngine/imp/cpp/ResourceManager.cpp | 49 +++ Src/IAEngine/inc/IAEngine/Audio.hpp | 5 - Src/IAEngine/inc/IAEngine/Base.hpp | 8 +- .../inc/IAEngine/Components/AtlasRenderer.hpp | 56 ++++ .../IAEngine/Components/SpriteRenderer.hpp | 2 + Src/IAEngine/inc/IAEngine/Events/Event.hpp | 24 ++ Src/IAEngine/inc/IAEngine/IAEngine.hpp | 7 +- Src/IAEngine/inc/IAEngine/Input.hpp | 295 ++++++++++++++++++ Src/IAEngine/inc/IAEngine/ResourceManager.hpp | 52 +++ Src/IAEngine/inc/IAEngine/Texture.hpp | 1 + 28 files changed, 819 insertions(+), 177 deletions(-) create mode 100644 Src/IAESandbox/imp/cpp/Game.cpp create mode 100644 Src/IAESandbox/imp/cpp/Map.cpp create mode 100644 Src/IAESandbox/imp/cpp/Player.cpp create mode 100644 Src/IAESandbox/imp/hpp/Game.hpp create mode 100644 Src/IAESandbox/imp/hpp/Map.hpp create mode 100644 Src/IAESandbox/imp/hpp/Player.hpp create mode 100644 Src/IAEngine/imp/cpp/Components/AtlasRenderer.cpp create mode 100644 Src/IAEngine/imp/cpp/ResourceManager.cpp create mode 100644 Src/IAEngine/inc/IAEngine/Components/AtlasRenderer.hpp create mode 100644 Src/IAEngine/inc/IAEngine/ResourceManager.hpp diff --git a/Dependencies/IACore b/Dependencies/IACore index 89d9217..b2f276a 160000 --- a/Dependencies/IACore +++ b/Dependencies/IACore @@ -1 +1 @@ -Subproject commit 89d9217b298bb251c229c264d079b423f69b0273 +Subproject commit b2f276a491e78a16656e63581856c0b50a4ad2ef diff --git a/Dependencies/IAMath b/Dependencies/IAMath index 536e9d0..77314b6 160000 --- a/Dependencies/IAMath +++ b/Dependencies/IAMath @@ -1 +1 @@ -Subproject commit 536e9d0e580db2647dd78932c60e29cdcb9b78f8 +Subproject commit 77314b62b72124fe1f6e3c99921b3208ad77519b diff --git a/Src/IAESandbox/CMakeLists.txt b/Src/IAESandbox/CMakeLists.txt index 4b198f6..cbe933d 100644 --- a/Src/IAESandbox/CMakeLists.txt +++ b/Src/IAESandbox/CMakeLists.txt @@ -1,6 +1,9 @@ set(IAESandbox_Sources imp/cpp/Main.cpp + imp/cpp/Game.cpp + imp/cpp/Map.cpp + imp/cpp/Player.cpp ) add_executable(IAESandbox ${IAESandbox_Sources}) diff --git a/Src/IAESandbox/imp/cpp/Game.cpp b/Src/IAESandbox/imp/cpp/Game.cpp new file mode 100644 index 0000000..41c115d --- /dev/null +++ b/Src/IAESandbox/imp/cpp/Game.cpp @@ -0,0 +1,34 @@ +#include +#include +#include + +namespace ia::iae::game +{ + RefPtr scene; + + VOID Game::Initialize() + { + const auto player = MakeRefPtr(m_engine); + player->SetLocalPosition({200, 150, 0}); + + const auto map = MakeRefPtr(m_engine); + + scene = m_engine->CreateScene(); + scene->AddNode(map); + scene->AddNode(player); + + m_engine->ChangeScene(scene); + + + } + + VOID Game::Terminate() + { + + } + + VOID Game::Update() + { + + } +} \ No newline at end of file diff --git a/Src/IAESandbox/imp/cpp/Main.cpp b/Src/IAESandbox/imp/cpp/Main.cpp index 69a9d70..d1d2c01 100644 --- a/Src/IAESandbox/imp/cpp/Main.cpp +++ b/Src/IAESandbox/imp/cpp/Main.cpp @@ -1,118 +1,20 @@ -#include -#include -#include +#include -#include - -#include - -namespace ia -{ - SIZE_T Find(IN CONST Vector &vec, IN SIZE_T start) - { - UINT8 Sig[5] = {0x89, 0x50, 0x4E, 0x47, 0x0D}; - for (SIZE_T i = start; i < vec.size(); i++) - { - if (!memcmp(&vec[i], Sig, sizeof(Sig))) - return i; - } - return SIZE_MAX; - } - - iae::Engine g_engine; - - RefPtr scene; - RefPtr sprite; - - VOID InitializeGame() - { - auto s = iae::Audio::CreateSound(File::ReadToVector("Res/Audio/SFX/gunshot.wav")); - s.LoopTimes() = 0; - - sprite = MakeRefPtr(); - const auto spriteRenderer = sprite->AddComponent(); - - { - const auto data = File::ReadToVector("Res/Graphics/iae/010_1.iae"); - IA_RELEASE_ASSERT(!memcmp(&data[0], "iae.", 4)); - const auto frameCount = *reinterpret_cast(&data[6]); - INT32 off = 10; - for (INT32 i = 0; i < frameCount; i++) - { - const auto t = g_engine.CreateTexture(&data[off], data.size() - off); - spriteRenderer->AddTexture(t); - off = Find(data, off + 1); - if (off == SIZE_MAX) - break; - } - } - - iae::SpriteRendererComponent::Animation anim; - anim.ShouldLoop = false; - - anim.Keys.pushBack( - iae::SpriteRendererComponent::AnimationKeyFrame{.Duration = 500, - .ColorOverlay = iam::Vec4f{0.25f, 0.0f, 0.0f, 1.0f}, - .ShouldInterpolate = true, - .TextureHandle = 0}); - anim.Keys.pushBack( - iae::SpriteRendererComponent::AnimationKeyFrame{.Duration = 500, - .ColorOverlay = iam::Vec4f{0.5f, 0.0f, 0.0f, 1.0f}, - .ShouldInterpolate = true, - .TextureHandle = 1}); - anim.Keys.pushBack( - iae::SpriteRendererComponent::AnimationKeyFrame{.Duration = 500, - .ColorOverlay = iam::Vec4f{0.75f, 0.0f, 0.0f, 1.0f}, - .ShouldInterpolate = true, - .TextureHandle = 2}); - anim.Keys.pushBack( - iae::SpriteRendererComponent::AnimationKeyFrame{.Duration = 500, - .ColorOverlay = iam::Vec4f{1.0f, 0.0f, 0.0f, 1.0f}, - .ShouldInterpolate = true, - .TextureHandle = 3}); - - spriteRenderer->AddAnimation(anim); - - spriteRenderer->BakeAnimations(); - - // const auto soundEmitter = sprite->AddComponent(); - // soundEmitter->SetSound(s); - - sprite->SetLocalPosition({100, 100, 0}); - - scene = g_engine.CreateScene(); - scene->AddNode(sprite); - - g_engine.ChangeScene(scene); - } - - VOID UpdateGame() - { - } - - VOID TerminateGame() - { - } -} // namespace ia +ia::iae::Engine g_engine; int main(int argc, char *argv[]) { - ia::g_engine.Initialize({.GameName = "IAE Sandbox", .WindowWidth = 800, .WindowHeight = 600}); - - ia::InitializeGame(); - - while (!ia::g_engine.ShouldClose()) + g_engine.Initialize({.GameName = "IAE Sandbox", .WindowWidth = 800, .WindowHeight = 600}); + const auto game = new ia::iae::game::Game(&g_engine); + game->Initialize(); + while (!g_engine.ShouldClose()) { - ia::g_engine.BeginFrame(); - - ia::UpdateGame(); - - ia::g_engine.EndFrame(); + g_engine.BeginFrame(); + game->Update(); + g_engine.EndFrame(); } - - ia::TerminateGame(); - - ia::g_engine.Terminate(); - + game->Terminate(); + delete game; + g_engine.Terminate(); return 0; } \ No newline at end of file diff --git a/Src/IAESandbox/imp/cpp/Map.cpp b/Src/IAESandbox/imp/cpp/Map.cpp new file mode 100644 index 0000000..c4c3b36 --- /dev/null +++ b/Src/IAESandbox/imp/cpp/Map.cpp @@ -0,0 +1,30 @@ +#include + +namespace ia::iae::game +{ + TiledMap::TiledMap(IN Engine *engine) : m_engine(engine) + { + m_musicEmitter = AddComponent(); + m_atlasRenderer = AddComponent(); + } + + VOID TiledMap::OnAdded(IN Scene *scene) + { + Node::OnAdded(scene); + } + + VOID TiledMap::OnRemoved() + { + Node::OnRemoved(); + } + + VOID TiledMap::Draw() + { + Node::Draw(); + } + + VOID TiledMap::Update() + { + Node::Update(); + } +} // namespace ia::iae::game \ No newline at end of file diff --git a/Src/IAESandbox/imp/cpp/Player.cpp b/Src/IAESandbox/imp/cpp/Player.cpp new file mode 100644 index 0000000..e157bc9 --- /dev/null +++ b/Src/IAESandbox/imp/cpp/Player.cpp @@ -0,0 +1,34 @@ +#include + +#include + +#include + +namespace ia::iae::game +{ + Player::Player(IN Engine *engine) : m_engine(engine) + { + m_spriteRenderer = AddComponent(); + } + + VOID Player::OnAdded(IN Scene *scene) + { + Node::OnAdded(scene); + } + + VOID Player::OnRemoved() + { + + Node::OnRemoved(); + } + + VOID Player::Draw() + { + Node::Draw(); + } + + VOID Player::Update() + { + Node::Update(); + } +} // namespace ia::iae::game \ No newline at end of file diff --git a/Src/IAESandbox/imp/hpp/Game.hpp b/Src/IAESandbox/imp/hpp/Game.hpp new file mode 100644 index 0000000..ab6afba --- /dev/null +++ b/Src/IAESandbox/imp/hpp/Game.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace ia::iae::game +{ + class Game + { + public: + Game(IN Engine* engine): m_engine(engine) {} + + VOID Initialize(); + VOID Terminate(); + VOID Update(); + + private: + Engine* CONST m_engine; + }; +} \ No newline at end of file diff --git a/Src/IAESandbox/imp/hpp/Map.hpp b/Src/IAESandbox/imp/hpp/Map.hpp new file mode 100644 index 0000000..e8d0ea5 --- /dev/null +++ b/Src/IAESandbox/imp/hpp/Map.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include + +namespace ia::iae::game +{ + class TiledMap : public Node + { + public: + TiledMap(IN Engine* engine); + + VIRTUAL VOID OnAdded(IN Scene *scene) OVERRIDE; + VIRTUAL VOID OnRemoved() OVERRIDE; + VIRTUAL VOID Draw() OVERRIDE; + VIRTUAL VOID Update() OVERRIDE; + + private: + Engine* CONST m_engine; + RefPtr m_musicEmitter; + RefPtr m_atlasRenderer; + }; +} \ No newline at end of file diff --git a/Src/IAESandbox/imp/hpp/Player.hpp b/Src/IAESandbox/imp/hpp/Player.hpp new file mode 100644 index 0000000..4312b66 --- /dev/null +++ b/Src/IAESandbox/imp/hpp/Player.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include + +namespace ia::iae::game +{ + class Player : public Node + { + public: + Player(IN Engine *engine); + + VIRTUAL VOID OnAdded(IN Scene *scene) OVERRIDE; + VIRTUAL VOID OnRemoved() OVERRIDE; + VIRTUAL VOID Draw() OVERRIDE; + VIRTUAL VOID Update() OVERRIDE; + + private: + INT32 m_speed{}; + UINT8 m_direction{}; + + private: + Engine *CONST m_engine; + RefPtr m_spriteRenderer; + }; +} // namespace ia::iae::game \ No newline at end of file diff --git a/Src/IAEngine/CMakeLists.txt b/Src/IAEngine/CMakeLists.txt index e02d42c..115e37f 100644 --- a/Src/IAEngine/CMakeLists.txt +++ b/Src/IAEngine/CMakeLists.txt @@ -7,9 +7,11 @@ set(IAEngine_Sources imp/cpp/Input.cpp imp/cpp/Scene.cpp imp/cpp/Random.cpp + imp/cpp/ResourceManager.cpp imp/cpp/Events/Event.cpp imp/cpp/Nodes/Transform.cpp imp/cpp/Nodes/Node.cpp + imp/cpp/Components/AtlasRenderer.cpp imp/cpp/Components/SpriteRenderer.cpp imp/cpp/Components/SoundEmitter.cpp ) diff --git a/Src/IAEngine/imp/cpp/Audio.cpp b/Src/IAEngine/imp/cpp/Audio.cpp index 542ba31..e82e9d5 100644 --- a/Src/IAEngine/imp/cpp/Audio.cpp +++ b/Src/IAEngine/imp/cpp/Audio.cpp @@ -77,7 +77,7 @@ namespace ia::iae VOID Audio::ClearTrack(IN INT64 trackHandle) { - MIX_StopTrack(g_tracks[trackHandle], 0); + //MIX_StopTrack(g_tracks[trackHandle], 0); } VOID Audio::PauseTrack(IN INT64 trackHandle) diff --git a/Src/IAEngine/imp/cpp/Components/AtlasRenderer.cpp b/Src/IAEngine/imp/cpp/Components/AtlasRenderer.cpp new file mode 100644 index 0000000..fa3e3f8 --- /dev/null +++ b/Src/IAEngine/imp/cpp/Components/AtlasRenderer.cpp @@ -0,0 +1,50 @@ +#include + +#include + +namespace ia::iae +{ + AtlasRendererComponent::AtlasRendererComponent(IN Node *node) : IComponent(node) + { + } + + Handle AtlasRendererComponent::AddTexture(IN RefPtr texture) + { + m_textures.pushBack(texture); + return m_textures.size() - 1; + } + + VOID AtlasRendererComponent::SetGrid(IN CONST TileGrid &grid) + { + m_tileGrid = grid; + m_tileGrid.m_tileTextures.resize(grid.TileCountX * grid.TileCountY); + for (auto &t : m_tileGrid.m_tileTextures) + t = INVALID_HANDLE; + } + + VOID AtlasRendererComponent::SetGridTileTexture(IN INT32 x, IN INT32 y, IN Handle textureHandle) + { + m_tileGrid.m_tileTextures[x + (y * m_tileGrid.TileCountX)] = textureHandle; + } + + VOID AtlasRendererComponent::Update() + { + } + + VOID AtlasRendererComponent::Draw() + { + iam::Vec3f p{m_node->GetPosition().X, m_node->GetPosition().Y, m_node->GetPosition().Z}; + for (INT32 y = 0; y < m_tileGrid.TileCountY; y++) + { + for (INT32 x = 0; x < m_tileGrid.TileCountX; x++) + { + const auto t = m_tileGrid.m_tileTextures[x + (y * m_tileGrid.TileCountX)]; + if (t != INVALID_HANDLE) + m_textures[t]->Draw(p, {1.0f, 1.0f, 1.0f}, 0.0f, false, false, {1.0f, 1.0f, 1.0f, 1.0f}); + p.X += m_tileGrid.TileWidth; + } + p.X = m_node->GetPosition().X; + p.Y += m_tileGrid.TileHeight; + } + } +} // namespace ia::iae \ No newline at end of file diff --git a/Src/IAEngine/imp/cpp/Components/SoundEmitter.cpp b/Src/IAEngine/imp/cpp/Components/SoundEmitter.cpp index 489d33b..96f90cd 100644 --- a/Src/IAEngine/imp/cpp/Components/SoundEmitter.cpp +++ b/Src/IAEngine/imp/cpp/Components/SoundEmitter.cpp @@ -36,7 +36,7 @@ namespace ia::iae VOID SoundEmitterComponent::SetSound(IN CONST Sound &sound) { m_activeSound = sound; - if(m_trackHandle == INVALID_HANDLE) return; + if((m_trackHandle == INVALID_HANDLE) || (m_activeSound.DataHandle() == INVALID_HANDLE)) return; Audio::QueueTrackData(m_trackHandle, sound.DataHandle()); Audio::PlayTrack(m_trackHandle, sound.LoopTimes(), sound.LoopDelay()); } diff --git a/Src/IAEngine/imp/cpp/Components/SpriteRenderer.cpp b/Src/IAEngine/imp/cpp/Components/SpriteRenderer.cpp index 50e566e..b047e99 100644 --- a/Src/IAEngine/imp/cpp/Components/SpriteRenderer.cpp +++ b/Src/IAEngine/imp/cpp/Components/SpriteRenderer.cpp @@ -31,9 +31,17 @@ namespace ia::iae Animation anim; anim.ShouldLoop = shouldLoop; for (const auto &idx : frames) - { anim.Keys.pushBack(AnimationKeyFrame{.Duration = frameDuration, .TextureHandle = idx}); - } + return AddAnimation(anim); + } + + Handle SpriteRendererComponent::AddAnimation(IN INT32 startFrame, IN INT32 endFrame, IN INT32 frameDuration, + IN BOOL shouldLoop) + { + Animation anim; + anim.ShouldLoop = shouldLoop; + for (INT32 i = startFrame; i < endFrame; i++) + anim.Keys.pushBack(AnimationKeyFrame{.Duration = frameDuration, .TextureHandle = i}); return AddAnimation(anim); } @@ -47,21 +55,26 @@ namespace ia::iae } if (m_animations.size()) SetActiveAnimation(0); + else + SetActiveTexture(0); } VOID SpriteRendererComponent::SetActiveTexture(IN Handle texture) { IA_RELEASE_ASSERT((texture != INVALID_HANDLE) && (texture < m_textures.size())); + m_currentAnimationState.TextureHandle = texture; } VOID SpriteRendererComponent::SetActiveAnimation(IN Handle animation) { + if(animation == m_activeAnimationHandle) return; IA_RELEASE_ASSERT((animation != INVALID_HANDLE) && (animation < m_animations.size())); m_prevAnimationKeyFrameIndex = 0; m_activeAnimation = m_animations[animation]; m_prevAnimationKeyFrame = m_activeAnimation.Keys[m_prevAnimationKeyFrameIndex + 0]; m_nextAnimationKeyFrame = m_activeAnimation.Keys[m_prevAnimationKeyFrameIndex + 1]; m_currentAnimationState = m_prevAnimationKeyFrame; + m_activeAnimationHandle = animation; } VOID SpriteRendererComponent::Update() @@ -75,7 +88,7 @@ namespace ia::iae if (animFrame.TextureHandle == INVALID_HANDLE) return; m_textures[animFrame.TextureHandle]->Draw( - m_node->GetPosition() + animFrame.Position, m_node->GetScale() + animFrame.Scale, + m_node->GetPosition() + animFrame.Position, m_node->GetScale() * animFrame.Scale, m_node->GetRotation().Z + animFrame.Rotation.Z, m_isFlippedH, m_isFlippedV, animFrame.ColorOverlay); } @@ -90,7 +103,7 @@ namespace ia::iae const auto t = m_timelinePosition / m_prevAnimationKeyFrame.Duration; #define INTERP_PROPERTY(name) \ m_currentAnimationState.name = iam::Lerp(m_prevAnimationKeyFrame.name, m_nextAnimationKeyFrame.name, t); - + INTERP_PROPERTY(Position); INTERP_PROPERTY(Rotation); INTERP_PROPERTY(Scale); @@ -103,7 +116,7 @@ namespace ia::iae if (m_timelinePosition >= m_prevAnimationKeyFrame.Duration) { m_prevAnimationKeyFrameIndex = (m_prevAnimationKeyFrameIndex + 1) % (keyCount - 1); - if(!m_prevAnimationKeyFrameIndex && !m_activeAnimation.ShouldLoop) + if (!m_prevAnimationKeyFrameIndex && !m_activeAnimation.ShouldLoop) { m_activeAnimation = {}; return; diff --git a/Src/IAEngine/imp/cpp/Events/Event.cpp b/Src/IAEngine/imp/cpp/Events/Event.cpp index e69de29..64e9023 100644 --- a/Src/IAEngine/imp/cpp/Events/Event.cpp +++ b/Src/IAEngine/imp/cpp/Events/Event.cpp @@ -0,0 +1,6 @@ +#include + +namespace ia::iae +{ + +} \ No newline at end of file diff --git a/Src/IAEngine/imp/cpp/IAEngine.cpp b/Src/IAEngine/imp/cpp/IAEngine.cpp index 1464baf..cd6e3bd 100644 --- a/Src/IAEngine/imp/cpp/IAEngine.cpp +++ b/Src/IAEngine/imp/cpp/IAEngine.cpp @@ -1,12 +1,9 @@ #include #include #include +#include #include - -#define STB_IMAGE_IMPLEMENTATION -#include - #include #include @@ -78,6 +75,7 @@ namespace ia::iae Time::Initialize(); Random::Initialize(); + Input::Initialize(); Audio::Initialize(); return true; @@ -142,6 +140,7 @@ namespace ia::iae VOID Engine::ProcessEvents() { + Input::OnEvent(&m_context->Event); } VOID Engine::UpdateGame() @@ -171,42 +170,3 @@ namespace ia::iae return m_context->Renderer; } } // namespace ia::iae - -namespace ia::iae -{ - RefPtr Engine::CreateTexture(IN CONST Span &encodedData) - { - return CreateTexture(encodedData.data(), encodedData.size()); - } - - RefPtr Engine::CreateTexture(IN PCUINT8 encodedData, IN SIZE_T encodedDataSize) - { - INT32 w, h, nrChannels; - const auto pixels = - stbi_load_from_memory(encodedData, encodedDataSize, &w, &h, &nrChannels, STBI_rgb_alpha); - if (!pixels) - THROW_INVALID_DATA("Failed to decode the provided image data"); - const auto result = CreateTexture((PCUINT8) pixels, w, h); - STBI_FREE(pixels); - return result; - } - - RefPtr Engine::CreateTexture(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height) - { - const auto result = MakeRefPtr(this); - - result->m_width = width; - result->m_height = height; - - SDL_Surface *surface = - SDL_CreateSurfaceFrom(width, height, SDL_PIXELFORMAT_RGBA32, (void *) rgbaData, width << 2); - if (!surface) - THROW_UNKNOWN("Failed to create SDL surface: ", SDL_GetError()); - result->m_handle = SDL_CreateTextureFromSurface(m_context->Renderer, surface); - if (!result->m_handle) - THROW_UNKNOWN("Failed to create SDL Texture: ", SDL_GetError()); - SDL_DestroySurface(surface); - - return result; - } -} // namespace ia::iae \ No newline at end of file diff --git a/Src/IAEngine/imp/cpp/Input.cpp b/Src/IAEngine/imp/cpp/Input.cpp index e69de29..e83cede 100644 --- a/Src/IAEngine/imp/cpp/Input.cpp +++ b/Src/IAEngine/imp/cpp/Input.cpp @@ -0,0 +1,69 @@ +#include + +#include + +namespace ia::iae +{ + struct InputDirection + { + iam::Vec2f Velocity{}; + Input::DirectionalInput Direction{Input::DirectionalInput::NONE}; + }; + + STATIC CONSTEXPR InputDirection INPUT_TO_DIRECTION_MAP[] = { + {iam::Vec2f{0.0f, 0.0f}, Input::DirectionalInput::NONE}, /* 0 */ + {iam::Vec2f{1.0f, 0.0f}, Input::DirectionalInput::RIGHT}, /* D */ + {iam::Vec2f{-1.0f, 0.0f}, Input::DirectionalInput::LEFT}, /* A */ + {iam::Vec2f{0.0f, 0.0f}, Input::DirectionalInput::NONE}, /* A, D */ + {iam::Vec2f{0.0f, 1.0f}, Input::DirectionalInput::DOWN}, /* S */ + {iam::Vec2f{1.0f, 1.0f}, Input::DirectionalInput::DOWN_RIGHT}, /* S, D */ + {iam::Vec2f{-1.0f, 1.0f}, Input::DirectionalInput::DOWN_LEFT}, /* S, A */ + {iam::Vec2f{0.0f, 0.0f}, Input::DirectionalInput::NONE}, /* S, A, D */ + {iam::Vec2f{0.0f, -1.0f}, Input::DirectionalInput::UP}, /* W */ + {iam::Vec2f{1.0f, -1.0f}, Input::DirectionalInput::UP_RIGHT}, /* W, D */ + {iam::Vec2f{-1.0f, -1.0f}, Input::DirectionalInput::UP_LEFT}, /* W, A */ + {iam::Vec2f{0.0f, 0.0f}, Input::DirectionalInput::NONE}, /* W, A, D */ + {iam::Vec2f{0.0f, 0.0f}, Input::DirectionalInput::NONE}, /* W, S */ + {iam::Vec2f{0.0f, 0.0f}, Input::DirectionalInput::NONE}, /* W, S, D */ + {iam::Vec2f{0.0f, 0.0f}, Input::DirectionalInput::NONE}, /* W, S, A */ + {iam::Vec2f{0.0f, 0.0f}, Input::DirectionalInput::NONE}, /* W, S, A, D */ + }; + + BOOL Input::s_keys[256]; + BOOL Input::s_prevKeys[256]; + + VOID Input::Initialize() + { + memset(s_keys, 0, sizeof(s_keys)); + memset(s_prevKeys, 0, sizeof(s_prevKeys)); + } + + VOID Input::OnEvent(IN PVOID _event) + { + const auto event = (SDL_Event *) _event; + if (event->type == SDL_EVENT_KEY_DOWN) + { + s_keys[event->key.scancode] = true; + } + else if (event->type == SDL_EVENT_KEY_UP) + { + s_keys[event->key.scancode] = false; + } + memcpy(s_prevKeys, s_keys, sizeof(s_prevKeys)); + } + + iam::Vec2f Input::GetDirectionalInput() + { + return INPUT_TO_DIRECTION_MAP[(IsKeyDown(Input::KEY_W) << 3) | (IsKeyDown(Input::KEY_S) << 2) | + (IsKeyDown(Input::KEY_A) << 1) | (IsKeyDown(Input::KEY_D) << 0)] + .Velocity; + } + + iam::Vec2f Input::GetDirectionalInput(OUT DirectionalInput &direction) + { + const auto dir = INPUT_TO_DIRECTION_MAP[(IsKeyDown(Input::KEY_W) << 3) | (IsKeyDown(Input::KEY_S) << 2) | + (IsKeyDown(Input::KEY_A) << 1) | (IsKeyDown(Input::KEY_D) << 0)]; + direction = dir.Direction; + return dir.Velocity; + } +} // namespace ia::iae \ No newline at end of file diff --git a/Src/IAEngine/imp/cpp/ResourceManager.cpp b/Src/IAEngine/imp/cpp/ResourceManager.cpp new file mode 100644 index 0000000..4323288 --- /dev/null +++ b/Src/IAEngine/imp/cpp/ResourceManager.cpp @@ -0,0 +1,49 @@ +#include +#include + +#include + +#define STB_IMAGE_IMPLEMENTATION +#include + +namespace ia::iae +{ + ResourceManager::ResourceManager(IN Engine *engine) : m_engine(engine) + { + } + + RefPtr ResourceManager::CreateTexture(IN CONST Span &encodedData) + { + return CreateTexture(encodedData.data(), encodedData.size()); + } + + RefPtr ResourceManager::CreateTexture(IN PCUINT8 encodedData, IN SIZE_T encodedDataSize) + { + INT32 w, h, nrChannels; + const auto pixels = stbi_load_from_memory(encodedData, encodedDataSize, &w, &h, &nrChannels, STBI_rgb_alpha); + if (!pixels) + THROW_INVALID_DATA("Failed to decode the provided image data"); + const auto result = CreateTexture((PCUINT8) pixels, w, h); + STBI_FREE(pixels); + return result; + } + + RefPtr ResourceManager::CreateTexture(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height) + { + const auto result = MakeRefPtr(m_engine); + + result->m_width = width; + result->m_height = height; + + SDL_Surface *surface = + SDL_CreateSurfaceFrom(width, height, SDL_PIXELFORMAT_RGBA32, (void *) rgbaData, width << 2); + if (!surface) + THROW_UNKNOWN("Failed to create SDL surface: ", SDL_GetError()); + result->m_handle = SDL_CreateTextureFromSurface((SDL_Renderer *) m_engine->GetRendererHandle(), surface); + if (!result->m_handle) + THROW_UNKNOWN("Failed to create SDL Texture: ", SDL_GetError()); + SDL_DestroySurface(surface); + + return result; + } +} // namespace ia::iae \ No newline at end of file diff --git a/Src/IAEngine/inc/IAEngine/Audio.hpp b/Src/IAEngine/inc/IAEngine/Audio.hpp index 8cceb32..dda5d67 100644 --- a/Src/IAEngine/inc/IAEngine/Audio.hpp +++ b/Src/IAEngine/inc/IAEngine/Audio.hpp @@ -64,11 +64,6 @@ namespace ia::iae STATIC VOID Initialize(); STATIC VOID Terminate(); - STATIC Sound CreateSound(IN CONST Vector &audioData) - { - return CreateSound(audioData.data(), audioData.size()); - } - STATIC Sound CreateSound(IN PCUINT8 audioData, IN SIZE_T audioDataSize); STATIC INT64 CreateTrack(); diff --git a/Src/IAEngine/inc/IAEngine/Base.hpp b/Src/IAEngine/inc/IAEngine/Base.hpp index 4a009a2..8d9311e 100644 --- a/Src/IAEngine/inc/IAEngine/Base.hpp +++ b/Src/IAEngine/inc/IAEngine/Base.hpp @@ -16,10 +16,10 @@ #pragma once -#include -#include -#include -#include +#include +#include +#include +#include #include diff --git a/Src/IAEngine/inc/IAEngine/Components/AtlasRenderer.hpp b/Src/IAEngine/inc/IAEngine/Components/AtlasRenderer.hpp new file mode 100644 index 0000000..1be85bf --- /dev/null +++ b/Src/IAEngine/inc/IAEngine/Components/AtlasRenderer.hpp @@ -0,0 +1,56 @@ +// IAEngine: 2D Game Engine by IA +// Copyright (C) 2025 IAS (ias@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 AtlasRendererComponent : public IComponent + { + public: + struct TileGrid + { + INT32 TileWidth{}; + INT32 TileHeight{}; + INT32 TileCountX{}; + INT32 TileCountY{}; + + Vector m_tileTextures{}; + + friend class AtlasRendererComponent; + }; + + public: + AtlasRendererComponent(IN Node *node); + + public: + Handle AddTexture(IN RefPtr texture); + + VOID SetGrid(IN CONST TileGrid &grid); + VOID SetGridTileTexture(IN INT32 x, IN INT32 y, IN Handle textureHandle); + + public: + VOID Draw(); + VOID Update(); + + private: + TileGrid m_tileGrid{}; + Vector> m_textures; + }; +} // namespace ia::iae \ No newline at end of file diff --git a/Src/IAEngine/inc/IAEngine/Components/SpriteRenderer.hpp b/Src/IAEngine/inc/IAEngine/Components/SpriteRenderer.hpp index eba180a..2db0026 100644 --- a/Src/IAEngine/inc/IAEngine/Components/SpriteRenderer.hpp +++ b/Src/IAEngine/inc/IAEngine/Components/SpriteRenderer.hpp @@ -47,6 +47,7 @@ namespace ia::iae Handle AddTexture(IN RefPtr texture); Handle AddAnimation(IN CONST Animation &animation); Handle AddAnimation(IN initializer_list frames, IN INT32 frameDuration, IN BOOL shouldLoop); + Handle AddAnimation(IN INT32 startFrame, IN INT32 endFrame, IN INT32 frameDuration, IN BOOL shouldLoop); VOID BakeAnimations(); @@ -65,6 +66,7 @@ namespace ia::iae BOOL m_isFlippedH{false}; FLOAT32 m_timelinePosition{}; Animation m_activeAnimation{}; + Handle m_activeAnimationHandle{INVALID_HANDLE}; Vector m_animations; Vector> m_textures; AnimationKeyFrame m_currentAnimationState{}; diff --git a/Src/IAEngine/inc/IAEngine/Events/Event.hpp b/Src/IAEngine/inc/IAEngine/Events/Event.hpp index e69de29..df7fe28 100644 --- a/Src/IAEngine/inc/IAEngine/Events/Event.hpp +++ b/Src/IAEngine/inc/IAEngine/Events/Event.hpp @@ -0,0 +1,24 @@ +// IAEngine: 2D Game Engine by IA +// Copyright (C) 2025 IAS (ias@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 +{ + +} \ No newline at end of file diff --git a/Src/IAEngine/inc/IAEngine/IAEngine.hpp b/Src/IAEngine/inc/IAEngine/IAEngine.hpp index acb116e..3a05752 100644 --- a/Src/IAEngine/inc/IAEngine/IAEngine.hpp +++ b/Src/IAEngine/inc/IAEngine/IAEngine.hpp @@ -45,15 +45,10 @@ namespace ia::iae VOID EndFrame(); BOOL ShouldClose(); - public: - VOID ChangeScene(IN RefPtr scene); - public: RefPtr CreateScene(); - RefPtr CreateTexture(IN CONST Span &encodedData); - RefPtr CreateTexture(IN PCUINT8 encodedData, IN SIZE_T encodedDataSize); - RefPtr CreateTexture(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height); + VOID ChangeScene(IN RefPtr scene); public: PVOID GetRendererHandle() CONST; diff --git a/Src/IAEngine/inc/IAEngine/Input.hpp b/Src/IAEngine/inc/IAEngine/Input.hpp index e69de29..ac3cf4c 100644 --- a/Src/IAEngine/inc/IAEngine/Input.hpp +++ b/Src/IAEngine/inc/IAEngine/Input.hpp @@ -0,0 +1,295 @@ +// IAEngine: 2D Game Engine by IA +// Copyright (C) 2025 IAS (ias@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 Input + { + public: + enum Key: UINT8 + { + KEY_UNKNOWN = 0, + KEY_A = 4, + KEY_B = 5, + KEY_C = 6, + KEY_D = 7, + KEY_E = 8, + KEY_F = 9, + KEY_G = 10, + KEY_H = 11, + KEY_I = 12, + KEY_J = 13, + KEY_K = 14, + KEY_L = 15, + KEY_M = 16, + KEY_N = 17, + KEY_O = 18, + KEY_P = 19, + KEY_Q = 20, + KEY_R = 21, + KEY_S = 22, + KEY_T = 23, + KEY_U = 24, + KEY_V = 25, + KEY_W = 26, + KEY_X = 27, + KEY_Y = 28, + KEY_Z = 29, + + KEY_1 = 30, + KEY_2 = 31, + KEY_3 = 32, + KEY_4 = 33, + KEY_5 = 34, + KEY_6 = 35, + KEY_7 = 36, + KEY_8 = 37, + KEY_9 = 38, + KEY_0 = 39, + + KEY_RETURN = 40, + KEY_ESCAPE = 41, + KEY_BACKSPACE = 42, + KEY_TAB = 43, + KEY_SPACE = 44, + + KEY_MINUS = 45, + KEY_EQUALS = 46, + KEY_LEFTBRACKET = 47, + KEY_RIGHTBRACKET = 48, + KEY_BACKSLASH = 49, + KEY_NONUSHASH = 50, + KEY_SEMICOLON = 51, + KEY_APOSTROPHE = 52, + KEY_GRAVE = 53, + KEY_COMMA = 54, + KEY_PERIOD = 55, + KEY_SLASH = 56, + + KEY_CAPSLOCK = 57, + + KEY_F1 = 58, + KEY_F2 = 59, + KEY_F3 = 60, + KEY_F4 = 61, + KEY_F5 = 62, + KEY_F6 = 63, + KEY_F7 = 64, + KEY_F8 = 65, + KEY_F9 = 66, + KEY_F10 = 67, + KEY_F11 = 68, + KEY_F12 = 69, + + KEY_PRINTSCREEN = 70, + KEY_SCROLLLOCK = 71, + KEY_PAUSE = 72, + KEY_INSERT = 73, + KEY_HOME = 74, + KEY_PAGEUP = 75, + KEY_DELETE = 76, + KEY_END = 77, + KEY_PAGEDOWN = 78, + KEY_RIGHT = 79, + KEY_LEFT = 80, + KEY_DOWN = 81, + KEY_UP = 82, + + KEY_NUMLOCKCLEAR = 83, + KEY_KP_DIVIDE = 84, + KEY_KP_MULTIPLY = 85, + KEY_KP_MINUS = 86, + KEY_KP_PLUS = 87, + KEY_KP_ENTER = 88, + KEY_KP_1 = 89, + KEY_KP_2 = 90, + KEY_KP_3 = 91, + KEY_KP_4 = 92, + KEY_KP_5 = 93, + KEY_KP_6 = 94, + KEY_KP_7 = 95, + KEY_KP_8 = 96, + KEY_KP_9 = 97, + KEY_KP_0 = 98, + KEY_KP_PERIOD = 99, + + KEY_NONUSBACKSLASH = 100, + KEY_APPLICATION = 101, + KEY_POWER = 102, + KEY_KP_EQUALS = 103, + KEY_F13 = 104, + KEY_F14 = 105, + KEY_F15 = 106, + KEY_F16 = 107, + KEY_F17 = 108, + KEY_F18 = 109, + KEY_F19 = 110, + KEY_F20 = 111, + KEY_F21 = 112, + KEY_F22 = 113, + KEY_F23 = 114, + KEY_F24 = 115, + KEY_EXECUTE = 116, + KEY_HELP = 117, + KEY_MENU = 118, + KEY_SELECT = 119, + KEY_STOP = 120, + KEY_AGAIN = 121, + KEY_UNDO = 122, + KEY_CUT = 123, + KEY_COPY = 124, + KEY_PASTE = 125, + KEY_FIND = 126, + KEY_MUTE = 127, + KEY_VOLUMEUP = 128, + KEY_VOLUMEDOWN = 129, + + KEY_KP_COMMA = 133, + KEY_KP_EQUALSAS400 = 134, + + KEY_INTERNATIONAL1 = 135, + KEY_INTERNATIONAL2 = 136, + KEY_INTERNATIONAL3 = 137, + KEY_INTERNATIONAL4 = 138, + KEY_INTERNATIONAL5 = 139, + KEY_INTERNATIONAL6 = 140, + KEY_INTERNATIONAL7 = 141, + KEY_INTERNATIONAL8 = 142, + KEY_INTERNATIONAL9 = 143, + KEY_LANG1 = 144, + KEY_LANG2 = 145, + KEY_LANG3 = 146, + KEY_LANG4 = 147, + KEY_LANG5 = 148, + KEY_LANG6 = 149, + KEY_LANG7 = 150, + KEY_LANG8 = 151, + KEY_LANG9 = 152, + + KEY_ALTERASE = 153, + KEY_SYSREQ = 154, + KEY_CANCEL = 155, + KEY_CLEAR = 156, + KEY_PRIOR = 157, + KEY_RETURN2 = 158, + KEY_SEPARATOR = 159, + KEY_OUT = 160, + KEY_OPER = 161, + KEY_CLEARAGAIN = 162, + KEY_CRSEL = 163, + KEY_EXSEL = 164, + + KEY_KP_00 = 176, + KEY_KP_000 = 177, + KEY_THOUSANDSSEPARATOR = 178, + KEY_DECIMALSEPARATOR = 179, + KEY_CURRENCYUNIT = 180, + KEY_CURRENCYSUBUNIT = 181, + KEY_KP_LEFTPAREN = 182, + KEY_KP_RIGHTPAREN = 183, + KEY_KP_LEFTBRACE = 184, + KEY_KP_RIGHTBRACE = 185, + KEY_KP_TAB = 186, + KEY_KP_BACKSPACE = 187, + KEY_KP_A = 188, + KEY_KP_B = 189, + KEY_KP_C = 190, + KEY_KP_D = 191, + KEY_KP_E = 192, + KEY_KP_F = 193, + KEY_KP_XOR = 194, + KEY_KP_POWER = 195, + KEY_KP_PERCENT = 196, + KEY_KP_LESS = 197, + KEY_KP_GREATER = 198, + KEY_KP_AMPERSAND = 199, + KEY_KP_DBLAMPERSAND = 200, + KEY_KP_VERTICALBAR = 201, + KEY_KP_DBLVERTICALBAR = 202, + KEY_KP_COLON = 203, + KEY_KP_HASH = 204, + KEY_KP_SPACE = 205, + KEY_KP_AT = 206, + KEY_KP_EXCLAM = 207, + KEY_KP_MEMSTORE = 208, + KEY_KP_MEMRECALL = 209, + KEY_KP_MEMCLEAR = 210, + KEY_KP_MEMADD = 211, + KEY_KP_MEMSUBTRACT = 212, + KEY_KP_MEMMULTIPLY = 213, + KEY_KP_MEMDIVIDE = 214, + KEY_KP_PLUSMINUS = 215, + KEY_KP_CLEAR = 216, + KEY_KP_CLEARENTRY = 217, + KEY_KP_BINARY = 218, + KEY_KP_OCTAL = 219, + KEY_KP_DECIMAL = 220, + KEY_KP_HEXADECIMAL = 221, + + KEY_LCTRL = 224, + KEY_LSHIFT = 225, + KEY_LALT = 226, + KEY_LGUI = 227, + KEY_RCTRL = 228, + KEY_RSHIFT = 229, + KEY_RALT = 230, + KEY_RGUI = 231, + }; + + enum class DirectionalInput: UINT8 + { + NONE = 0, + DOWN, + DOWN_LEFT, + LEFT, + UP_LEFT, + UP, + UP_RIGHT, + RIGHT, + DOWN_RIGHT + }; + + public: + STATIC VOID Initialize(); + STATIC VOID OnEvent(IN PVOID event); + + STATIC BOOL IsKeyDown(IN Key key) + { + return s_keys[(UINT8)key]; + } + + STATIC BOOL WasKeyPressed(IN Key key) + { + return !s_prevKeys[key] && s_keys[key]; + } + + STATIC BOOL WasKeyReleased(IN Key key) + { + return s_prevKeys[key] && !s_keys[key]; + } + + STATIC iam::Vec2f GetDirectionalInput(); + STATIC iam::Vec2f GetDirectionalInput(OUT DirectionalInput& direction); + + private: + STATIC BOOL s_keys[256]; + STATIC BOOL s_prevKeys[256]; + }; +} // namespace ia::iae \ No newline at end of file diff --git a/Src/IAEngine/inc/IAEngine/ResourceManager.hpp b/Src/IAEngine/inc/IAEngine/ResourceManager.hpp new file mode 100644 index 0000000..2e911c2 --- /dev/null +++ b/Src/IAEngine/inc/IAEngine/ResourceManager.hpp @@ -0,0 +1,52 @@ +// IAEngine: 2D Game Engine by IA +// Copyright (C) 2025 IAS (ias@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 Engine; + + class ResourceManager + { + public: + RefPtr CreateTexture(IN CONST Span &encodedData); + RefPtr CreateTexture(IN PCUINT8 encodedData, IN SIZE_T encodedDataSize); + RefPtr CreateTexture(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height); + + public: + Sound CreateSound(IN PCUINT8 audioData, IN SIZE_T audioDataSize) + { + return Audio::CreateSound(audioData, audioDataSize); + } + + Sound CreateSound(IN CONST Vector &audioData) + { + return CreateSound(audioData.data(), audioData.size()); + } + + protected: + Engine *CONST m_engine; + + private: + ResourceManager(IN Engine *engine); + + friend class Engine; + }; +} // namespace ia::iae \ No newline at end of file diff --git a/Src/IAEngine/inc/IAEngine/Texture.hpp b/Src/IAEngine/inc/IAEngine/Texture.hpp index fb0a94d..84460c0 100644 --- a/Src/IAEngine/inc/IAEngine/Texture.hpp +++ b/Src/IAEngine/inc/IAEngine/Texture.hpp @@ -50,5 +50,6 @@ namespace ia::iae private: friend class Engine; + friend class ResourceManager; }; } // namespace ia::iae \ No newline at end of file