From e0411333fb659645f79b49a41b8fc1a7480e1a69 Mon Sep 17 00:00:00 2001 From: Isuru Samarathunga Date: Sat, 11 Oct 2025 20:18:11 +0530 Subject: [PATCH] SpriteRenderer --- Engine/CMakeLists.txt | 3 +- .../Imp/CPP/Components/SpriteComponent.cpp | 132 ++++++++++++++++++ Engine/Src/Imp/CPP/Nodes/SpriteNode.cpp | 25 ++++ Engine/Src/Inc/IAEngine/Base.hpp | 21 ++- .../IAEngine/Components/SpriteComponent.hpp | 88 ++++++++++++ .../IAEngine/Components/TextureComponent.hpp | 16 +-- Engine/Src/Inc/IAEngine/Nodes/SpriteNode.hpp | 19 ++- 7 files changed, 289 insertions(+), 15 deletions(-) create mode 100644 Engine/Src/Imp/CPP/Nodes/SpriteNode.cpp 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