diff --git a/Engine/CMakeLists.txt b/Engine/CMakeLists.txt
index b6e5b12..c75e01d 100644
--- a/Engine/CMakeLists.txt
+++ b/Engine/CMakeLists.txt
@@ -19,8 +19,9 @@ set(SRC_FILES
"Src/Imp/CPP/Renderer/GPUResourceManager.cpp"
"Src/Imp/CPP/Nodes/Node2D.cpp"
- "Src/Imp/CPP/Nodes/TextureNode.cpp"
"Src/Imp/CPP/Nodes/CameraNode.cpp"
+ "Src/Imp/CPP/Nodes/SpriteNode.cpp"
+ "Src/Imp/CPP/Nodes/TextureNode.cpp"
"Src/Imp/CPP/Components/CameraComponent.cpp"
"Src/Imp/CPP/Components/PhysicsComponent.cpp"
diff --git a/Engine/Src/Imp/CPP/Components/SpriteComponent.cpp b/Engine/Src/Imp/CPP/Components/SpriteComponent.cpp
index e69de29..caa8e35 100644
--- a/Engine/Src/Imp/CPP/Components/SpriteComponent.cpp
+++ b/Engine/Src/Imp/CPP/Components/SpriteComponent.cpp
@@ -0,0 +1,132 @@
+// 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
+{
+ SpriteComponent::SpriteComponent(IN Node2D *node) : TextureComponent(node)
+ {
+ }
+
+ VOID SpriteComponent::Draw()
+ {
+ const auto &animFrame = m_currentAnimationState;
+ PositionOffset() = animFrame.Position;
+ ScaleOffset() = animFrame.Scale;
+ RotationOffset() = animFrame.Rotation;
+ ColorOverlay() = animFrame.ColorOverlay;
+ SetTexture(animFrame.Texture);
+ TextureComponent::Draw();
+ }
+
+ VOID SpriteComponent::DebugDraw()
+ {
+ TextureComponent::DebugDraw();
+ }
+
+ VOID SpriteComponent::Update()
+ {
+ TextureComponent::Update();
+
+ UpdateAnimation();
+ }
+
+ VOID SpriteComponent::FixedUpdate()
+ {
+ TextureComponent::FixedUpdate();
+ }
+
+ Handle SpriteComponent::AddAnimation(IN CONST Animation &animation)
+ {
+ if (animation.Keys.empty())
+ return INVALID_HANDLE;
+ m_animations.pushBack(animation);
+ if(m_animations.size() == 1)
+ ForceSetActiveAnimation(0);
+ return m_animations.size() - 1;
+ }
+
+ VOID SpriteComponent::SetActiveAnimation(IN Handle animation)
+ {
+ if (animation == m_activeAnimationHandle)
+ return;
+ ForceSetActiveAnimation(animation);
+ }
+
+ VOID SpriteComponent::ForceSetActiveAnimation(IN Handle animation)
+ {
+ IA_RELEASE_ASSERT((animation != INVALID_HANDLE) && (animation < m_animations.size()));
+ m_prevAnimationKeyFrameIndex = 0;
+ m_activeAnimation = m_animations[animation];
+
+ m_prevAnimationKeyFrame = GetKeyFrame(m_prevAnimationKeyFrameIndex + 0);
+ m_nextAnimationKeyFrame = GetKeyFrame(m_prevAnimationKeyFrameIndex + 1);
+
+ m_currentAnimationState = m_prevAnimationKeyFrame;
+ m_activeAnimationHandle = animation;
+
+ SetTexture(m_currentAnimationState.Texture);
+ }
+
+ VOID SpriteComponent::SetAnimationFrame(IN INT32 animation, IN INT32 frame)
+ {
+ m_activeAnimation = {};
+ m_currentAnimationState = m_animations[animation].Keys[frame];
+ }
+
+ VOID SpriteComponent::UpdateAnimation()
+ {
+ const auto keyCount = m_activeAnimation.Keys.size();
+ if (keyCount <= 1)
+ return;
+
+ if (m_currentAnimationState.ShouldInterpolate)
+ {
+ const auto t = m_timelinePosition / m_prevAnimationKeyFrame.Duration;
+#define INTERP_PROPERTY(name) \
+ m_currentAnimationState.name = \
+ m_prevAnimationKeyFrame.name + (m_nextAnimationKeyFrame.name - m_prevAnimationKeyFrame.name) * t;
+
+ INTERP_PROPERTY(Position);
+ INTERP_PROPERTY(Rotation);
+ INTERP_PROPERTY(Scale);
+ INTERP_PROPERTY(ColorOverlay);
+
+#undef INTERP_PROPERTY
+ }
+
+ if (m_timelinePosition >= m_prevAnimationKeyFrame.Duration)
+ {
+ m_prevAnimationKeyFrameIndex = (m_prevAnimationKeyFrameIndex + 1) % keyCount;
+ if (!m_prevAnimationKeyFrameIndex && !m_activeAnimation.ShouldLoop)
+ {
+ m_activeAnimation = {};
+ return;
+ }
+ m_prevAnimationKeyFrame = GetKeyFrame(m_prevAnimationKeyFrameIndex + 0);
+ m_nextAnimationKeyFrame = GetKeyFrame(m_prevAnimationKeyFrameIndex + 1);
+ m_currentAnimationState = m_prevAnimationKeyFrame;
+ m_timelinePosition = 0;
+ }
+ m_timelinePosition += Engine::GetFrameDeltaTime() * 1000;
+ }
+
+ SpriteComponent::AnimationKeyFrame SpriteComponent::GetKeyFrame(IN INT32 index)
+ {
+ return m_activeAnimation.Keys[index % m_activeAnimation.Keys.size()];
+ }
+} // namespace ia::iae
\ No newline at end of file
diff --git a/Engine/Src/Imp/CPP/Nodes/SpriteNode.cpp b/Engine/Src/Imp/CPP/Nodes/SpriteNode.cpp
new file mode 100644
index 0000000..f5ead54
--- /dev/null
+++ b/Engine/Src/Imp/CPP/Nodes/SpriteNode.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
+{
+ SpriteNode::SpriteNode(IN CONST String &name) : Node2D(name), m_spriteComponent(AddComponent())
+ {
+ }
+} // namespace ia::iae
\ No newline at end of file
diff --git a/Engine/Src/Inc/IAEngine/Base.hpp b/Engine/Src/Inc/IAEngine/Base.hpp
index e56a235..5890c69 100644
--- a/Engine/Src/Inc/IAEngine/Base.hpp
+++ b/Engine/Src/Inc/IAEngine/Base.hpp
@@ -16,12 +16,12 @@
#pragma once
-#include
+#include
#include
+#include
#include
#include
#include
-#include
#include
#include
@@ -111,7 +111,22 @@ namespace ia::iae
Vec4 GetAsFloatVec() CONST
{
- return {(FLOAT32)R/255.0f, (FLOAT32)G/255.0f, (FLOAT32)B/255.0f, (FLOAT32)A/255.0f};
+ return {(FLOAT32) R / 255.0f, (FLOAT32) G / 255.0f, (FLOAT32) B / 255.0f, (FLOAT32) A / 255.0f};
+ }
+
+ Color operator+(IN CONST Color &other) CONST
+ {
+ return Color{(UINT8) (R + other.R), (UINT8) (G + other.G), (UINT8) (B + other.B), (UINT8) (A + other.A)};
+ }
+
+ Color operator-(IN CONST Color &other) CONST
+ {
+ return Color{(UINT8) (R - other.R), (UINT8) (G - other.G), (UINT8) (B - other.B), (UINT8) (A - other.A)};
+ }
+
+ Color operator*(IN FLOAT32 v) CONST
+ {
+ return Color{(UINT8) (R * v), (UINT8) (G * v), (UINT8) (B * v), (UINT8) (A * v)};
}
};
diff --git a/Engine/Src/Inc/IAEngine/Components/SpriteComponent.hpp b/Engine/Src/Inc/IAEngine/Components/SpriteComponent.hpp
index e69de29..183386c 100644
--- a/Engine/Src/Inc/IAEngine/Components/SpriteComponent.hpp
+++ b/Engine/Src/Inc/IAEngine/Components/SpriteComponent.hpp
@@ -0,0 +1,88 @@
+// 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 SpriteComponent : public TextureComponent
+ {
+ public:
+ struct AnimationKeyFrame
+ {
+ Handle Texture;
+ INT32 Duration{100};
+ BOOL ShouldInterpolate{};
+
+ FLOAT32 Rotation{};
+ Vec2 Position{};
+ Vec2 Scale{1.0f, 1.0f};
+ Color ColorOverlay{0xFF, 0xFF, 0xFF, 0xFF};
+ };
+
+ struct Animation
+ {
+ BOOL ShouldLoop{false};
+ Vector Keys;
+ };
+
+ public:
+ SpriteComponent(IN Node2D *node);
+
+ public:
+ VIRTUAL VOID Draw();
+ VIRTUAL VOID DebugDraw();
+
+ VIRTUAL VOID Update();
+ VIRTUAL VOID FixedUpdate();
+
+ public:
+ Handle AddAnimation(IN CONST Animation &animation);
+
+ VOID SetActiveAnimation(IN Handle animation);
+ VOID ForceSetActiveAnimation(IN Handle animation);
+
+ VOID SetAnimationFrame(IN INT32 animation, IN INT32 frame);
+
+ public:
+ Vector &Animations()
+ {
+ return m_animations;
+ }
+
+ CONST Vector &Animations() CONST
+ {
+ return m_animations;
+ }
+
+ private:
+ VOID UpdateAnimation();
+
+ AnimationKeyFrame GetKeyFrame(IN INT32 index);
+
+ private:
+ FLOAT32 m_timelinePosition{};
+ Animation m_activeAnimation{};
+ Handle m_activeAnimationHandle{INVALID_HANDLE};
+ Vector m_animations;
+ AnimationKeyFrame m_currentAnimationState{};
+ AnimationKeyFrame m_nextAnimationKeyFrame{};
+ AnimationKeyFrame m_prevAnimationKeyFrame{};
+ INT32 m_prevAnimationKeyFrameIndex{};
+ };
+} // namespace ia::iae
\ No newline at end of file
diff --git a/Engine/Src/Inc/IAEngine/Components/TextureComponent.hpp b/Engine/Src/Inc/IAEngine/Components/TextureComponent.hpp
index a21c04f..a7606ca 100644
--- a/Engine/Src/Inc/IAEngine/Components/TextureComponent.hpp
+++ b/Engine/Src/Inc/IAEngine/Components/TextureComponent.hpp
@@ -23,17 +23,17 @@ namespace ia::iae
class TextureComponent : public IComponent
{
public:
- TextureComponent(IN Node2D *node);
+ TextureComponent(IN Node2D *node);
public:
- VOID Draw();
- VOID DebugDraw();
-
- VOID Update();
- VOID FixedUpdate();
+ VIRTUAL VOID Draw();
+ VIRTUAL VOID DebugDraw();
+
+ VIRTUAL VOID Update();
+ VIRTUAL VOID FixedUpdate();
public:
- VOID SetTexture(IN Handle image);
+ VOID SetTexture(IN Handle image);
Handle GetTexture() CONST
{
@@ -97,6 +97,6 @@ namespace ia::iae
Vec2 m_drawnSize{};
Vec2 m_textureExtent{};
- Handle m_texture{INVALID_HANDLE};
+ Handle m_texture{0};
};
} // namespace ia::iae
\ No newline at end of file
diff --git a/Engine/Src/Inc/IAEngine/Nodes/SpriteNode.hpp b/Engine/Src/Inc/IAEngine/Nodes/SpriteNode.hpp
index 759df24..d0c06b7 100644
--- a/Engine/Src/Inc/IAEngine/Nodes/SpriteNode.hpp
+++ b/Engine/Src/Inc/IAEngine/Nodes/SpriteNode.hpp
@@ -16,10 +16,23 @@
#pragma once
-#include
#include
+#include
namespace ia::iae
{
-
-}
\ No newline at end of file
+ class SpriteNode : public Node2D
+ {
+ public:
+ SpriteNode(IN CONST String &name);
+
+ public:
+ SpriteComponent *GetSpriteComponent()
+ {
+ return m_spriteComponent;
+ }
+
+ protected:
+ SpriteComponent *CONST m_spriteComponent{};
+ };
+} // namespace ia::iae
\ No newline at end of file