This commit is contained in:
Isuru Samarathunga
2025-09-14 20:53:38 +05:30
parent ad869ef71d
commit 6974a647f5
16 changed files with 206 additions and 94 deletions

View File

@ -26,6 +26,7 @@ set(IAEngine_Sources
imp/cpp/Nodes/Node.cpp
imp/cpp/Components/AtlasRenderer.cpp
imp/cpp/Components/BoxCollider2D.cpp
imp/cpp/Components/SpriteRenderer.cpp
imp/cpp/Components/SoundEmitter.cpp
imp/cpp/Components/ParticleEmitter.cpp

View File

@ -0,0 +1,51 @@
// 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 <https://www.gnu.org/licenses/>.
#include <IAEngine/Nodes/Node.hpp>
#include <IAEngine/Physics/Physics.hpp>
#include <IAEngine/Components/BoxCollider2D.hpp>
#include <IAEngine/IAEngine.hpp>
#include <IACore/File.hpp>
namespace ia::iae
{
Texture g_debugBoxTexture{};
BoxCollider2DComponent::BoxCollider2DComponent(IN Node *node) : IComponent(node)
{
Physics::AddCollider(this);
g_debugBoxTexture = Engine::CreateTexture(File::ReadToVector("Resources/Engine/debug_box.png"));
}
VOID BoxCollider2DComponent::Draw()
{
//g_debugBoxTexture.Draw(
// 0,
// m_node->GetPosition() + glm::vec3{m_shape.x, m_shape.y, 0},
// {m_shape.z/256.0f, m_shape.w/256.0f, 1},
// m_node->GetRotation().z, false, false, glm::vec4{1.0f, 1.0f, 1.0f, 1.0f});
}
VOID BoxCollider2DComponent::Update()
{
const auto pos = m_node->GetPosition();
m_absoluteShape.x = pos.x + m_shape.x;
m_absoluteShape.y = pos.y + m_shape.y;
m_absoluteShape.z = m_absoluteShape.x + m_shape.z;
m_absoluteShape.w = m_absoluteShape.y + m_shape.w;
}
} // namespace ia::iae

View File

@ -36,12 +36,6 @@ namespace ia::iae
VOID SpriteRendererComponent::BakeAnimations()
{
for (auto &anim : m_animations)
{
auto t = anim.Keys.back();
t.Duration = 0;
anim.Keys.pushBack(t);
}
if (m_animations.size())
SetActiveAnimation(0);
}
@ -54,7 +48,7 @@ namespace ia::iae
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_nextAnimationKeyFrame = m_activeAnimation.Keys[(m_prevAnimationKeyFrameIndex + 1) % m_activeAnimation.Keys.size()];
m_currentAnimationState = m_prevAnimationKeyFrame;
m_activeAnimationHandle = animation;
}
@ -93,19 +87,19 @@ namespace ia::iae
#undef INTERP_PROPERTY
}
m_timelinePosition += Time::GetFrameDeltaTime();
if (m_timelinePosition >= m_prevAnimationKeyFrame.Duration)
{
m_prevAnimationKeyFrameIndex = (m_prevAnimationKeyFrameIndex + 1) % (keyCount - 1);
m_prevAnimationKeyFrameIndex = (m_prevAnimationKeyFrameIndex + 1) % keyCount;
if (!m_prevAnimationKeyFrameIndex && !m_activeAnimation.ShouldLoop)
{
m_activeAnimation = {};
return;
}
m_prevAnimationKeyFrame = m_activeAnimation.Keys[m_prevAnimationKeyFrameIndex + 0];
m_nextAnimationKeyFrame = m_activeAnimation.Keys[m_prevAnimationKeyFrameIndex + 1];
m_nextAnimationKeyFrame = m_activeAnimation.Keys[(m_prevAnimationKeyFrameIndex + 1) % keyCount];
m_currentAnimationState = m_prevAnimationKeyFrame;
m_timelinePosition = 0;
}
m_timelinePosition += Time::GetFrameDeltaTime();
}
} // namespace ia::iae

View File

@ -31,7 +31,7 @@ namespace ia::iae
VOID TextureRendererComponent::Draw()
{
m_texture->Draw(
m_texture.Draw(
m_node->SortOffset(),
m_node->GetPosition() + m_position, m_node->GetScale(),
m_node->GetRotation().z, false, false, glm::vec4{1.0f, 1.0f, 1.0f, 1.0f});

View File

@ -70,15 +70,15 @@ namespace ia::iae
glm::vec2 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)]
return INPUT_TO_DIRECTION_MAP[(IsKeyDown(Input::KEY_UP) << 3) | (IsKeyDown(Input::KEY_DOWN) << 2) |
(IsKeyDown(Input::KEY_LEFT) << 1) | (IsKeyDown(Input::KEY_RIGHT) << 0)]
.Velocity;
}
glm::vec2 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)];
const auto dir = INPUT_TO_DIRECTION_MAP[(IsKeyDown(Input::KEY_UP) << 3) | (IsKeyDown(Input::KEY_DOWN) << 2) |
(IsKeyDown(Input::KEY_LEFT) << 1) | (IsKeyDown(Input::KEY_RIGHT) << 0)];
direction = dir.Direction;
return dir.Velocity;
}

View File

@ -16,9 +16,11 @@
#include <IAEngine/Physics/Physics.hpp>
#include <IAEngine/Nodes/Node.hpp>
namespace ia::iae
{
Vector<BoxCollider2DComponent *> g_colliders;
VOID Physics::Initialize()
{
@ -28,26 +30,40 @@ namespace ia::iae
{
}
INLINE BOOL IsIntersectingH(IN CONST glm::vec4 &shape, IN FLOAT32 x)
{
return (x >= shape.x) && (x <= shape.z);
}
INLINE BOOL IsIntersectingV(IN CONST glm::vec4 &shape, IN FLOAT32 y)
{
return (y >= shape.y) && (y <= shape.w);
}
VOID Physics::Update()
{
for (SIZE_T i = 0; i < g_colliders.size(); i++)
{
for (SIZE_T j = i + 1; j < g_colliders.size(); j++)
{
const auto boxA = g_colliders[i]->AbsoluteShape();
const auto boxB = g_colliders[j]->AbsoluteShape();
const auto nodeA = g_colliders[i]->GetNode();
if(IsIntersectingH(boxB, boxA.z) && (IsIntersectingV(boxB, boxA.y) || IsIntersectingV(boxB, boxA.w)))
nodeA->SetLocalPosition(nodeA->GetLocalPosition() + glm::vec3(-boxA.z + boxB.x, 0, 0));
else if(IsIntersectingH(boxB, boxA.x) && (IsIntersectingV(boxB, boxA.y) || IsIntersectingV(boxB, boxA.w)))
nodeA->SetLocalPosition(nodeA->GetLocalPosition() + glm::vec3(-boxA.x + boxB.z, 0, 0));
else if(IsIntersectingV(boxB, boxA.w) && (IsIntersectingH(boxB, boxA.x) || IsIntersectingH(boxB, boxA.z)))
nodeA->SetLocalPosition(nodeA->GetLocalPosition() + glm::vec3(0, -boxA.w + boxB.y, 0));
else if(IsIntersectingV(boxB, boxA.y) && (IsIntersectingH(boxB, boxA.x) || IsIntersectingH(boxB, boxA.z)))
nodeA->SetLocalPosition(nodeA->GetLocalPosition() + glm::vec3(0, -boxA.y + boxB.w, 0));
}
}
}
Handle Physics::CreateStaticBody(IN glm::vec3 position)
VOID Physics::AddCollider(IN BoxCollider2DComponent *collider)
{
return INVALID_HANDLE;
}
Handle Physics::CreateDynamicBody(IN glm::vec3 position)
{
return INVALID_HANDLE;
}
VOID Physics::AddBoxCollider(IN Handle body, IN glm::vec3 size)
{
}
glm::vec3 Physics::GetBodyPosition(IN Handle body)
{
return {};
g_colliders.pushBack(collider);
}
} // namespace ia::iae

View File

@ -35,6 +35,8 @@ namespace ia::iae
.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE,
.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE,
.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE,
.max_anisotropy = 1.0f,
.enable_anisotropy = true
};
g_defaultSampler = SDL_CreateGPUSampler(g_gpuDevice, &createInfo);
}

View File

@ -25,9 +25,15 @@ namespace ia::iae
VOID QuadMesh::Initialize()
{
Vertex_Mesh vertices[6] = {{glm::vec3{-1, 1, 0}, glm::vec2{0, 0}}, {glm::vec3{1, 1, 0}, glm::vec2{1, 0}},
{glm::vec3{1, -1, 0}, glm::vec2{1, 1}}, {glm::vec3{-1, 1, 0}, glm::vec2{0, 0}},
{glm::vec3{1, -1, 0}, glm::vec2{1, 1}}, {glm::vec3{-1, -1, 0}, glm::vec2{0, 1}}};
Vertex_Mesh vertices[6] = {
{glm::vec3{0, 1, 0}, glm::vec2{0, 1}},
{glm::vec3{1, 1, 0}, glm::vec2{1, 1}},
{glm::vec3{1, 0, 0}, glm::vec2{1, 0}},
{glm::vec3{1, 0, 0}, glm::vec2{1, 0}},
{glm::vec3{0, 0, 0}, glm::vec2{0, 0}},
{glm::vec3{0, 1, 0}, glm::vec2{0, 1}},
};
g_quadMeshVertexBuffer = GPUBuffer::Create(GPUBuffer::Usage::VERTEX, &vertices, sizeof(vertices));
}
@ -37,7 +43,8 @@ namespace ia::iae
g_quadMeshVertexBuffer.reset();
}
VOID QuadMesh::Draw(IN FLOAT32 sortOffset, IN CONST glm::vec3 &position, IN CONST glm::vec3 &scale, IN FLOAT32 rotation)
VOID QuadMesh::Draw(IN FLOAT32 sortOffset, IN CONST glm::vec3 &position, IN CONST glm::vec3 &scale,
IN FLOAT32 rotation)
{
Renderer::Draw(sortOffset, position, scale, rotation, g_quadMeshVertexBuffer->GetHandle(), 6);
}

View File

@ -35,20 +35,14 @@ namespace ia::iae
{
const auto res = MakeRefPtr<Pipeline_UnlitMesh>();
const auto vertexShader = LoadShaderFromMemory(ShaderStage::VERTEX, SHADER_SOURCE_UNLITMESH_VERT, sizeof(SHADER_SOURCE_UNLITMESH_VERT), 0, 3, 0, 0);
const auto pixelShader = LoadShaderFromMemory(ShaderStage::PIXEL, SHADER_SOURCE_UNLITMESH_FRAG, sizeof(SHADER_SOURCE_UNLITMESH_FRAG), 1, 1, 0, 0);
const auto vertexShader = LoadShaderFromMemory(ShaderStage::VERTEX, SHADER_SOURCE_UNLITMESH_VERT,
sizeof(SHADER_SOURCE_UNLITMESH_VERT), 0, 3, 0, 0);
const auto pixelShader = LoadShaderFromMemory(ShaderStage::PIXEL, SHADER_SOURCE_UNLITMESH_FRAG,
sizeof(SHADER_SOURCE_UNLITMESH_FRAG), 1, 1, 0, 0);
SDL_GPUColorTargetDescription colorTargets[] = {
{.format = SDL_GetGPUSwapchainTextureFormat(g_gpuDevice, g_windowHandle),
.blend_state = SDL_GPUColorTargetBlendState{
.src_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE,
.dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
.color_blend_op = SDL_GPU_BLENDOP_ADD,
.src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE,
.dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
.alpha_blend_op = SDL_GPU_BLENDOP_ADD,
.enable_blend = true,
}}};
SDL_GPUColorTargetDescription colorTargets[] = {{
.format = SDL_GetGPUSwapchainTextureFormat(g_gpuDevice, g_windowHandle),
}};
SDL_GPUVertexBufferDescription vertexBuffers[] = {{
.slot = 0,
.pitch = sizeof(Vertex_Mesh),
@ -71,25 +65,18 @@ namespace ia::iae
.num_vertex_attributes =
sizeof(vertexAttributes) / sizeof(vertexAttributes[0])},
.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST,
.rasterizer_state = SDL_GPURasterizerState{
.fill_mode = SDL_GPU_FILLMODE_FILL,
.rasterizer_state = SDL_GPURasterizerState{.fill_mode = SDL_GPU_FILLMODE_FILL,
.cull_mode = SDL_GPU_CULLMODE_NONE,
.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE
},
.depth_stencil_state = SDL_GPUDepthStencilState{
.compare_op = SDL_GPU_COMPAREOP_LESS,
.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE},
.depth_stencil_state = SDL_GPUDepthStencilState{.compare_op = SDL_GPU_COMPAREOP_GREATER_OR_EQUAL,
.write_mask = 0xFF,
.enable_depth_test = true,
.enable_depth_write = true,
.enable_stencil_test = false
},
.target_info =
{
.color_target_descriptions = colorTargets,
.enable_stencil_test = false},
.target_info = {.color_target_descriptions = colorTargets,
.num_color_targets = sizeof(colorTargets) / sizeof(colorTargets[0]),
.depth_stencil_format = SDL_GPU_TEXTUREFORMAT_D16_UNORM,
.has_depth_stencil_target = true
},
.has_depth_stencil_target = true},
};
SDL_GPUGraphicsPipeline *handle{};

View File

@ -100,7 +100,7 @@ namespace ia::iae
{
SDL_GPUTextureCreateInfo createInfo{.type = SDL_GPU_TEXTURETYPE_2D,
.format = SDL_GPU_TEXTUREFORMAT_D16_UNORM,
.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER |
.usage =
SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET,
.width = (UINT32) s_width,
.height = (UINT32) s_height,
@ -193,7 +193,7 @@ namespace ia::iae
SDL_GPUDepthStencilTargetInfo depthStencilTargetInfo = {0};
depthStencilTargetInfo.texture = g_depthBufferTexture;
depthStencilTargetInfo.cycle = true;
depthStencilTargetInfo.clear_depth = 1;
depthStencilTargetInfo.clear_depth = 0;
depthStencilTargetInfo.clear_stencil = 0;
depthStencilTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR;
depthStencilTargetInfo.store_op = SDL_GPU_STOREOP_STORE;

View File

@ -15,8 +15,9 @@ layout(set = 3, binding = 0) uniform UniformBufferObject {
void main()
{
vec2 uv = inTexCoord;
uv.y = 1 - uv.y;
if(ubo.flipH) uv.x = 1 - uv.x;
if(ubo.flipV) uv.y = 1 - uv.y;
outColor = texture(texSampler, uv) * ubo.colorOverlay;
if(outColor.w < 0.1)
discard;
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,49 @@
// 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 <https://www.gnu.org/licenses/>.
#pragma once
#include <IAEngine/Components/Component.hpp>
namespace ia::iae
{
class BoxCollider2DComponent : public IComponent
{
public:
BoxCollider2DComponent(IN Node *node);
BOOL& IsDynamic(){return m_isDynamic;}
glm::vec4& Shape()
{
return m_shape;
}
CONST glm::vec4& AbsoluteShape() CONST
{
return m_absoluteShape;
}
public:
VOID Draw();
VOID Update();
private:
BOOL m_isDynamic{};
glm::vec4 m_shape{};
glm::vec4 m_absoluteShape{};
};
} // namespace ia::iae

View File

@ -25,12 +25,20 @@ namespace ia::iae
class IComponent
{
public:
IComponent(IN Node* node): m_node(node) {}
IComponent(IN Node *node) : m_node(node)
{
}
PURE_VIRTUAL(VOID Draw());
PURE_VIRTUAL(VOID Update());
public:
Node *GetNode()
{
return m_node;
}
protected:
Node *m_node{};
};
}
} // namespace ia::iae

View File

@ -26,7 +26,7 @@ namespace ia::iae
public:
TextureRendererComponent(IN Node *node);
RefPtr<iae::Texture> &Texture()
Texture &Texture()
{
return m_texture;
}
@ -41,7 +41,7 @@ namespace ia::iae
VOID Update();
private:
class Texture m_texture;
glm::vec3 m_position;
RefPtr<iae::Texture> m_texture;
};
} // namespace ia::iae

View File

@ -16,7 +16,7 @@
#pragma once
#include <IAEngine/Base.hpp>
#include <IAEngine/Components/BoxCollider2D.hpp>
namespace ia::iae
{
@ -28,10 +28,6 @@ namespace ia::iae
STATIC VOID Update();
STATIC Handle CreateStaticBody(IN glm::vec3 position);
STATIC Handle CreateDynamicBody(IN glm::vec3 position);
STATIC VOID AddBoxCollider(IN Handle body, IN glm::vec3 size);
STATIC glm::vec3 GetBodyPosition(IN Handle body);
STATIC VOID AddCollider(IN BoxCollider2DComponent* collider);
};
}