Compare commits
26 Commits
28ca737c21
...
old
| Author | SHA1 | Date | |
|---|---|---|---|
| 8b308db058 | |||
| 6a87771d8f | |||
| f6c022f38e | |||
| 0d5c2e639e | |||
| ae20f51e9a | |||
| 9038fa54b0 | |||
| 9269306146 | |||
| b18bfe873f | |||
| 5f112f7531 | |||
| 3380eb993e | |||
| fe88538e3c | |||
| 3c5792e975 | |||
| 2bd9fb91fc | |||
| e4e6a2ed3c | |||
| ddf162b6a6 | |||
| 21d4357081 | |||
| f5693ef0fa | |||
| 1573644c51 | |||
| 3db1904ba4 | |||
| d4e0d3b3a1 | |||
| 860beab3a2 | |||
| 70bf71d2da | |||
| 0e7474d4e4 | |||
| 60c40c45a8 | |||
| afaced62d4 | |||
| 8793554994 |
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
#include <IAEngine/Input.hpp>
|
#include <IAEngine/Input.hpp>
|
||||||
#include <IAEngine/Rendering/Camera.hpp>
|
#include <IAEngine/Rendering/Camera.hpp>
|
||||||
#include <IAEngine/Components/PhysicsBody2D.hpp>
|
#include <IAEngine/Rendering/DebugDraw.hpp>
|
||||||
#include <IAEngine/Components/BoxCollider2D.hpp>
|
|
||||||
#include <IAEngine/Components/SpriteRenderer.hpp>
|
#include <IAEngine/Components/SpriteRenderer.hpp>
|
||||||
|
#include <IAEngine/Components/Physics.hpp>
|
||||||
|
|
||||||
#include <IACore/File.hpp>
|
#include <IACore/File.hpp>
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ namespace ia::iae::game
|
|||||||
RefPtr<Scene> scene;
|
RefPtr<Scene> scene;
|
||||||
|
|
||||||
RefPtr<Node> g_player;
|
RefPtr<Node> g_player;
|
||||||
PhysicsBody2DComponent* g_playerPhysicsBody{};
|
PhysicsComponent* g_playerPhysics;
|
||||||
|
|
||||||
VOID Game::Initialize()
|
VOID Game::Initialize()
|
||||||
{
|
{
|
||||||
@ -34,20 +34,19 @@ namespace ia::iae::game
|
|||||||
});
|
});
|
||||||
t->BakeAnimations();
|
t->BakeAnimations();
|
||||||
}
|
}
|
||||||
{
|
g_playerPhysics = g_player->AddComponent<PhysicsComponent>();
|
||||||
g_playerPhysicsBody = g_player->AddComponent<PhysicsBody2DComponent>();
|
g_playerPhysics->IsDynamic() = true;
|
||||||
g_playerPhysicsBody->IsDynamic() = true;
|
g_playerPhysics->AddCollider({
|
||||||
const auto collider = g_player->AddComponent<BoxCollider2DComponent>();
|
.IsTrigger = false,
|
||||||
collider->Rect() = {
|
.Position = {
|
||||||
0,
|
0.0f, 0.0f,
|
||||||
0,
|
},
|
||||||
g_player->DrawnSize().x,
|
.Size = {
|
||||||
g_player->DrawnSize().y/2.0f,
|
25.0f, 25.0f
|
||||||
};
|
|
||||||
collider->IsDebugDrawEnabled() = true;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
g_player->Tags() = NODE_TAG_PLAYER;
|
g_player->Tags() = NODE_TAG_PLAYER;
|
||||||
g_player->SetLocalPosition({200, 200});
|
g_player->SetLocalPosition({200, 300});
|
||||||
|
|
||||||
const auto obstacle = MakeRefPtr<Node>();
|
const auto obstacle = MakeRefPtr<Node>();
|
||||||
{
|
{
|
||||||
@ -56,23 +55,23 @@ namespace ia::iae::game
|
|||||||
.ShouldLoop = true,
|
.ShouldLoop = true,
|
||||||
.Keys = {
|
.Keys = {
|
||||||
SpriteRendererComponent::AnimationKeyFrame {
|
SpriteRendererComponent::AnimationKeyFrame {
|
||||||
.Scale = {3.0f, 0.5f},
|
.Scale = {1.0f, 0.5f},
|
||||||
.ColorOverlay = {0.75f, 0.0f, 0.0f, 1.0f}
|
.ColorOverlay = {0.75f, 0.0f, 0.0f, 1.0f}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
t->BakeAnimations();
|
t->BakeAnimations();
|
||||||
}
|
}
|
||||||
{
|
const auto obstaclePhysics = obstacle->AddComponent<PhysicsComponent>();
|
||||||
obstacle->AddComponent<PhysicsBody2DComponent>();
|
obstaclePhysics->AddCollider({
|
||||||
const auto collider = obstacle->AddComponent<BoxCollider2DComponent>();
|
.IsTrigger = false,
|
||||||
collider->Rect() = {
|
.Position = {
|
||||||
0, 0,
|
0.0f, 0.0f,
|
||||||
obstacle->DrawnSize().x,
|
},
|
||||||
obstacle->DrawnSize().y
|
.Size = {
|
||||||
};
|
100.0f, 50.0f
|
||||||
collider->IsDebugDrawEnabled() = true;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
obstacle->Tags() = NODE_TAG_GROUND;
|
obstacle->Tags() = NODE_TAG_GROUND;
|
||||||
obstacle->SetLocalSortIndex(20);
|
obstacle->SetLocalSortIndex(20);
|
||||||
obstacle->SetLocalPosition({200, 400});
|
obstacle->SetLocalPosition({200, 400});
|
||||||
@ -89,8 +88,7 @@ namespace ia::iae::game
|
|||||||
|
|
||||||
VOID Game::Update()
|
VOID Game::Update()
|
||||||
{
|
{
|
||||||
if(Input::WasKeyPressed(Input::KEY_SPACE))
|
const auto d = Input::GetDirectionalInput();
|
||||||
g_playerPhysicsBody->Jump(200.0f);
|
g_playerPhysics->Move(d);
|
||||||
g_playerPhysicsBody->SetVelocityX(Input::GetDirectionalInput().x * 100.0f);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -13,9 +13,11 @@ set(IAEngine_Sources
|
|||||||
imp/cpp/Rendering/Renderer.cpp
|
imp/cpp/Rendering/Renderer.cpp
|
||||||
imp/cpp/Rendering/GPUBuffer.cpp
|
imp/cpp/Rendering/GPUBuffer.cpp
|
||||||
imp/cpp/Rendering/GPUTexture.cpp
|
imp/cpp/Rendering/GPUTexture.cpp
|
||||||
|
imp/cpp/Rendering/DebugDraw.cpp
|
||||||
|
|
||||||
imp/cpp/Rendering/Pipeline/Pipeline.cpp
|
imp/cpp/Rendering/Pipeline/Pipeline.cpp
|
||||||
imp/cpp/Rendering/Pipeline/UnlitMesh.cpp
|
imp/cpp/Rendering/Pipeline/UnlitMesh.cpp
|
||||||
|
imp/cpp/Rendering/Pipeline/PostProcess.cpp
|
||||||
|
|
||||||
imp/cpp/Physics/Physics.cpp
|
imp/cpp/Physics/Physics.cpp
|
||||||
|
|
||||||
@ -25,12 +27,11 @@ set(IAEngine_Sources
|
|||||||
imp/cpp/Nodes/Node.cpp
|
imp/cpp/Nodes/Node.cpp
|
||||||
|
|
||||||
imp/cpp/Components/AtlasRenderer.cpp
|
imp/cpp/Components/AtlasRenderer.cpp
|
||||||
imp/cpp/Components/BoxCollider2D.cpp
|
|
||||||
imp/cpp/Components/SpriteRenderer.cpp
|
imp/cpp/Components/SpriteRenderer.cpp
|
||||||
imp/cpp/Components/SoundEmitter.cpp
|
imp/cpp/Components/SoundEmitter.cpp
|
||||||
imp/cpp/Components/ParticleEmitter.cpp
|
imp/cpp/Components/ParticleEmitter.cpp
|
||||||
imp/cpp/Components/PhysicsBody2D.cpp
|
|
||||||
imp/cpp/Components/TextureRenderer.cpp
|
imp/cpp/Components/TextureRenderer.cpp
|
||||||
|
imp/cpp/Components/Physics.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(IAEngine STATIC ${IAEngine_Sources})
|
add_library(IAEngine STATIC ${IAEngine_Sources})
|
||||||
@ -39,4 +40,4 @@ target_include_directories(IAEngine PUBLIC inc/)
|
|||||||
target_include_directories(IAEngine PRIVATE imp/hpp)
|
target_include_directories(IAEngine PRIVATE imp/hpp)
|
||||||
|
|
||||||
target_link_libraries(IAEngine PUBLIC IACore ImGui glm::glm)
|
target_link_libraries(IAEngine PUBLIC IACore ImGui glm::glm)
|
||||||
target_link_libraries(IAEngine PRIVATE SDL3::SDL3 SDL3_mixer::SDL3_mixer box2d RmlUi::RmlUi)
|
target_link_libraries(IAEngine PRIVATE SDL3::SDL3 SDL3_mixer::SDL3_mixer RmlUi::RmlUi)
|
||||||
|
|||||||
@ -19,12 +19,26 @@
|
|||||||
#include <SDL3/SDL_iostream.h>
|
#include <SDL3/SDL_iostream.h>
|
||||||
#include <SDL3_mixer/SDL_mixer.h>
|
#include <SDL3_mixer/SDL_mixer.h>
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
namespace ia::iae
|
namespace ia::iae
|
||||||
{
|
{
|
||||||
|
struct TrackData
|
||||||
|
{
|
||||||
|
BOOL IsActive{};
|
||||||
|
MIX_Track *Track{};
|
||||||
|
INT32 LoopTimes{};
|
||||||
|
TimePeriod LoopDelay{};
|
||||||
|
std::thread *PlaybackThread;
|
||||||
|
|
||||||
|
std::mutex Mutex;
|
||||||
|
std::condition_variable CV;
|
||||||
|
};
|
||||||
|
|
||||||
MIX_Mixer *g_mixer{};
|
MIX_Mixer *g_mixer{};
|
||||||
Vector<MIX_Track *> g_tracks;
|
Vector<TrackData*> g_tracks;
|
||||||
|
Vector<INT64> g_destroyQueue;
|
||||||
Vector<MIX_Audio *> g_audioData;
|
Vector<MIX_Audio *> g_audioData;
|
||||||
|
|
||||||
VOID Audio::Initialize()
|
VOID Audio::Initialize()
|
||||||
@ -38,7 +52,48 @@ namespace ia::iae
|
|||||||
|
|
||||||
VOID Audio::Terminate()
|
VOID Audio::Terminate()
|
||||||
{
|
{
|
||||||
|
for (SIZE_T i = 0; i < g_tracks.size(); i++)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(g_tracks[i]->Mutex);
|
||||||
|
g_tracks[i]->IsActive = false;
|
||||||
|
}
|
||||||
|
g_tracks[i]->CV.notify_one();
|
||||||
|
g_tracks[i]->PlaybackThread->join();
|
||||||
|
delete g_tracks[i];
|
||||||
|
}
|
||||||
|
MIX_StopAllTracks(g_mixer, 0);
|
||||||
g_audioData.clear();
|
g_audioData.clear();
|
||||||
|
g_tracks.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID Audio::Update()
|
||||||
|
{
|
||||||
|
for (SIZE_T i = 0; i < g_tracks.size(); i++)
|
||||||
|
{
|
||||||
|
auto &t = g_tracks[i];
|
||||||
|
if (!t->IsActive && !MIX_TrackPlaying(t->Track))
|
||||||
|
DestroyTrack(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [IATODO]: IMPL: Destroy queue
|
||||||
|
}
|
||||||
|
|
||||||
|
INT64 Audio::CreateTrack()
|
||||||
|
{
|
||||||
|
g_tracks.pushBack(new TrackData{true, MIX_CreateTrack(g_mixer)});
|
||||||
|
return g_tracks.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID Audio::DestroyTrack(IN INT64 trackHandle)
|
||||||
|
{
|
||||||
|
if(trackHandle >= g_tracks.size())
|
||||||
|
return;
|
||||||
|
auto& t = g_tracks[trackHandle];
|
||||||
|
ClearTrack(trackHandle);
|
||||||
|
MIX_StopTrack(t->Track, 0);
|
||||||
|
t->IsActive = false;
|
||||||
|
g_destroyQueue.pushBack(trackHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sound Audio::CreateSound(IN PCUINT8 audioData, IN SIZE_T audioDataSize)
|
Sound Audio::CreateSound(IN PCUINT8 audioData, IN SIZE_T audioDataSize)
|
||||||
@ -47,62 +102,55 @@ namespace ia::iae
|
|||||||
return Sound(g_audioData.size() - 1);
|
return Sound(g_audioData.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
INT64 Audio::CreateTrack()
|
|
||||||
{
|
|
||||||
g_tracks.pushBack(MIX_CreateTrack(g_mixer));
|
|
||||||
return g_tracks.size() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID Audio::DestroyTrack(IN INT64 trackHandle)
|
|
||||||
{
|
|
||||||
ClearTrack(trackHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID Audio::QueueTrackData(IN INT64 trackHandle, IN INT64 dataHandle)
|
VOID Audio::QueueTrackData(IN INT64 trackHandle, IN INT64 dataHandle)
|
||||||
{
|
{
|
||||||
MIX_SetTrackAudio(g_tracks[trackHandle], g_audioData[dataHandle]);
|
MIX_SetTrackAudio(g_tracks[trackHandle]->Track, g_audioData[dataHandle]);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID Audio::PlayTrack(IN INT64 trackHandle, IN INT32 loopTimes, IN TimePeriod loopDelay)
|
VOID Audio::PlayTrack(IN INT64 trackHandle, IN INT32 loopTimes, IN TimePeriod loopDelay)
|
||||||
{
|
{
|
||||||
struct __callback_data
|
auto &t = g_tracks[trackHandle];
|
||||||
{
|
t->LoopTimes = loopTimes;
|
||||||
INT32 loopTimes;
|
t->LoopDelay = loopDelay;
|
||||||
TimePeriod loopDelay;
|
if (t->LoopTimes == 0)
|
||||||
};
|
t->IsActive = false;
|
||||||
|
|
||||||
const auto callbackData = new __callback_data{.loopTimes = loopTimes, .loopDelay = loopDelay};
|
|
||||||
|
|
||||||
MIX_PlayTrack(g_tracks[trackHandle], 0);
|
|
||||||
MIX_SetTrackStoppedCallback(
|
|
||||||
g_tracks[trackHandle],
|
|
||||||
[](PVOID _callbackData, MIX_Track *track) {
|
|
||||||
const auto callbackData = (__callback_data *) _callbackData;
|
|
||||||
if (callbackData->loopTimes < 0)
|
|
||||||
goto loop_next_iteration;
|
|
||||||
else if (callbackData->loopTimes == 0)
|
|
||||||
return;
|
|
||||||
else
|
else
|
||||||
callbackData->loopTimes -= 1;
|
t->PlaybackThread = new std::thread([trackHandle]() {
|
||||||
|
auto &t = g_tracks[trackHandle];
|
||||||
|
while (t->IsActive)
|
||||||
|
{
|
||||||
|
if (MIX_TrackPlaying(t->Track))
|
||||||
|
continue;
|
||||||
|
if (t->LoopTimes < 0)
|
||||||
|
goto loop_next_iteration;
|
||||||
|
else if (!t->LoopTimes)
|
||||||
|
{
|
||||||
|
t->IsActive = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t->LoopTimes--;
|
||||||
loop_next_iteration:
|
loop_next_iteration:
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds((INT32) (callbackData->loopDelay.GetValue() * 1000)));
|
std::unique_lock<std::mutex> lock(t->Mutex);
|
||||||
MIX_PlayTrack(track, 0);
|
t->CV.wait_for(lock, std::chrono::milliseconds((INT32) (t->LoopDelay.GetValue() * 1000)),
|
||||||
},
|
[t]() { return !t->IsActive; });
|
||||||
callbackData);
|
MIX_PlayTrack(t->Track, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
MIX_PlayTrack(t->Track, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID Audio::ClearTrack(IN INT64 trackHandle)
|
VOID Audio::ClearTrack(IN INT64 trackHandle)
|
||||||
{
|
{
|
||||||
MIX_StopTrack(g_tracks[trackHandle], 0);
|
MIX_StopTrack(g_tracks[trackHandle]->Track, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID Audio::PauseTrack(IN INT64 trackHandle)
|
VOID Audio::PauseTrack(IN INT64 trackHandle)
|
||||||
{
|
{
|
||||||
MIX_PauseTrack(g_tracks[trackHandle]);
|
MIX_PauseTrack(g_tracks[trackHandle]->Track);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID Audio::ResumeTrack(IN INT64 trackHandle)
|
VOID Audio::ResumeTrack(IN INT64 trackHandle)
|
||||||
{
|
{
|
||||||
MIX_ResumeTrack(g_tracks[trackHandle]);
|
MIX_ResumeTrack(g_tracks[trackHandle]->Track);
|
||||||
}
|
}
|
||||||
} // namespace ia::iae
|
} // namespace ia::iae
|
||||||
@ -59,8 +59,8 @@ namespace ia::iae
|
|||||||
handles[i] = m_tileGrid.m_tileTextures[i].GetHandle();
|
handles[i] = m_tileGrid.m_tileTextures[i].GetHandle();
|
||||||
m_bakedGPUTexture = GPUTexture::GridCombine(handles.data(), m_tileGrid.TileCountX, m_tileGrid.TileCountY,
|
m_bakedGPUTexture = GPUTexture::GridCombine(handles.data(), m_tileGrid.TileCountX, m_tileGrid.TileCountY,
|
||||||
m_tileGrid.TileWidth, m_tileGrid.TileHeight);
|
m_tileGrid.TileWidth, m_tileGrid.TileHeight);
|
||||||
|
m_node->DrawnSize() = {w, h};
|
||||||
CurrentTexture() = Texture(m_bakedGPUTexture->GetHandle(), w, h);
|
CurrentTexture() = Texture(m_bakedGPUTexture->GetHandle(), w, h);
|
||||||
PositionOffset() = m_tileGrid.Position;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID AtlasRendererComponent::Update()
|
VOID AtlasRendererComponent::Update()
|
||||||
@ -69,6 +69,9 @@ namespace ia::iae
|
|||||||
|
|
||||||
VOID AtlasRendererComponent::Draw()
|
VOID AtlasRendererComponent::Draw()
|
||||||
{
|
{
|
||||||
|
PositionOffset() = m_tileGrid.Position;
|
||||||
|
ScaleOffset() = {1.0f, 1.0f};
|
||||||
|
IsCameraRelative() = true;
|
||||||
TextureRendererComponent::Draw();
|
TextureRendererComponent::Draw();
|
||||||
}
|
}
|
||||||
} // namespace ia::iae
|
} // namespace ia::iae
|
||||||
|
|||||||
@ -1,58 +0,0 @@
|
|||||||
// 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/Components/BoxCollider2D.hpp>
|
|
||||||
#include <IAEngine/Components/PhysicsBody2D.hpp>
|
|
||||||
#include <IAEngine/Components/TextureRenderer.hpp>
|
|
||||||
#include <IAEngine/Rendering/Renderer.hpp>
|
|
||||||
#include <IAEngine/Physics/Physics.hpp>
|
|
||||||
#include <IAEngine/Nodes/Node.hpp>
|
|
||||||
|
|
||||||
namespace ia::iae
|
|
||||||
{
|
|
||||||
EXTERN Texture g_whiteStrokeTexture;
|
|
||||||
|
|
||||||
BoxCollider2DComponent::BoxCollider2DComponent(IN Node *node) : IComponent(node)
|
|
||||||
{
|
|
||||||
IA_RELEASE_ASSERT(m_body = node->GetComponent<PhysicsBody2DComponent>());
|
|
||||||
m_physicsHandle = Physics::AddColliderToBody(m_body->PhysicsHandle(), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID BoxCollider2DComponent::Draw()
|
|
||||||
{
|
|
||||||
if (!m_isDebugDrawEnabled)
|
|
||||||
return;
|
|
||||||
Renderer::Draw(Renderer::GetMesh_Quad(), g_whiteStrokeTexture.GetHandle(), m_node->GetPosition() + glm::vec2{m_rect.x, m_rect.y},
|
|
||||||
glm::vec2{m_rect.z, m_rect.w}, 0, Renderer::MAX_LAYER_INDEX,
|
|
||||||
0, {1.0f, 1.0f, 1.0f, 1.0f});
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID BoxCollider2DComponent::Update()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID BoxCollider2DComponent::OnCollisionEnter(IN Node *other)
|
|
||||||
{
|
|
||||||
if (other->HasTag(NODE_TAG_GROUND))
|
|
||||||
m_body->IsGrounded() = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID BoxCollider2DComponent::OnCollisionExit(IN Node *other)
|
|
||||||
{
|
|
||||||
if (other->HasTag(NODE_TAG_GROUND))
|
|
||||||
m_body->IsGrounded() = false;
|
|
||||||
}
|
|
||||||
} // namespace ia::iae
|
|
||||||
78
Src/IAEngine/imp/cpp/Components/Physics.cpp
Normal file
78
Src/IAEngine/imp/cpp/Components/Physics.cpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// 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/Components/Physics.hpp>
|
||||||
|
#include <IAEngine/Physics/Physics.hpp>
|
||||||
|
#include <IAEngine/Nodes/Node.hpp>
|
||||||
|
|
||||||
|
namespace ia::iae
|
||||||
|
{
|
||||||
|
PhysicsComponent::PhysicsComponent(IN Node *node) : IComponent(node)
|
||||||
|
{
|
||||||
|
m_physicsHandle = Physics::RegisterComponent(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsComponent::~PhysicsComponent()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID PhysicsComponent::Draw()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID PhysicsComponent::Update()
|
||||||
|
{
|
||||||
|
m_velocity = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle PhysicsComponent::CreateCollider()
|
||||||
|
{
|
||||||
|
m_colliders.pushBack({});
|
||||||
|
return m_colliders.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle PhysicsComponent::AddCollider(IN Collider collider)
|
||||||
|
{
|
||||||
|
m_colliders.pushBack(collider);
|
||||||
|
return m_colliders.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsComponent::Collider &PhysicsComponent::GetCollider(IN Handle handle)
|
||||||
|
{
|
||||||
|
return m_colliders[handle];
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID PhysicsComponent::Move(IN glm::vec2 direction)
|
||||||
|
{
|
||||||
|
IA_ASSERT(m_isDynamic);
|
||||||
|
const auto v = direction * m_movementSpeed;
|
||||||
|
m_velocity += v;
|
||||||
|
for(const auto& t: m_colliders)
|
||||||
|
{
|
||||||
|
if(!Physics::CanMove(m_physicsHandle, t, v))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_node->SetLocalPosition(m_node->GetLocalPosition() + v);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID PhysicsComponent::Jump(IN FLOAT32 force)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID PhysicsComponent::OnCollision(IN PhysicsComponent *other)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
} // namespace ia::iae
|
||||||
@ -1,66 +0,0 @@
|
|||||||
// 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/Components/BoxCollider2D.hpp>
|
|
||||||
#include <IAEngine/Components/PhysicsBody2D.hpp>
|
|
||||||
#include <IAEngine/Nodes/Node.hpp>
|
|
||||||
#include <IAEngine/Physics/Physics.hpp>
|
|
||||||
|
|
||||||
namespace ia::iae
|
|
||||||
{
|
|
||||||
PhysicsBody2DComponent::PhysicsBody2DComponent(IN Node *node) : IComponent(node)
|
|
||||||
{
|
|
||||||
m_physicsHandle = Physics::AddBody(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID PhysicsBody2DComponent::Draw()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID PhysicsBody2DComponent::Update()
|
|
||||||
{
|
|
||||||
if (m_isDynamic)
|
|
||||||
m_node->SetLocalPosition(Physics::GetBodyPosition(m_physicsHandle));
|
|
||||||
if (!m_isRotationLocked)
|
|
||||||
m_node->SetLocalRotation(Physics::GetBodyRotation(m_physicsHandle));
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID PhysicsBody2DComponent::SetVelocity(IN glm::vec2 v)
|
|
||||||
{
|
|
||||||
Physics::SetBodyVelocity(m_physicsHandle, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID PhysicsBody2DComponent::SetVelocityX(IN FLOAT32 v)
|
|
||||||
{
|
|
||||||
Physics::SetBodyVelocityX(m_physicsHandle, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID PhysicsBody2DComponent::SetVelocityY(IN FLOAT32 v)
|
|
||||||
{
|
|
||||||
Physics::SetBodyVelocityY(m_physicsHandle, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID PhysicsBody2DComponent::ApplyForce(IN glm::vec2 force)
|
|
||||||
{
|
|
||||||
Physics::ApplyBodyForce(m_physicsHandle, force);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID PhysicsBody2DComponent::Jump(IN FLOAT32 velocity)
|
|
||||||
{
|
|
||||||
if(m_isGrounded)
|
|
||||||
Physics::SetBodyVelocityY(m_physicsHandle, -velocity);
|
|
||||||
}
|
|
||||||
} // namespace ia::iae
|
|
||||||
@ -26,7 +26,8 @@ namespace ia::iae
|
|||||||
SpriteRendererComponent::AnimationKeyFrame SpriteRendererComponent::GetKeyFrame(IN INT32 index)
|
SpriteRendererComponent::AnimationKeyFrame SpriteRendererComponent::GetKeyFrame(IN INT32 index)
|
||||||
{
|
{
|
||||||
index %= m_activeAnimation.Keys.size();
|
index %= m_activeAnimation.Keys.size();
|
||||||
return m_reverseAnimation ? m_activeAnimation.Keys[m_activeAnimation.Keys.size() - 1 - index] : m_activeAnimation.Keys[index];
|
return m_reverseAnimation ? m_activeAnimation.Keys[m_activeAnimation.Keys.size() - 1 - index]
|
||||||
|
: m_activeAnimation.Keys[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
SpriteRendererComponent::SpriteRendererComponent(IN Node *node) : TextureRendererComponent(node)
|
SpriteRendererComponent::SpriteRendererComponent(IN Node *node) : TextureRendererComponent(node)
|
||||||
@ -44,13 +45,24 @@ namespace ia::iae
|
|||||||
VOID SpriteRendererComponent::BakeAnimations()
|
VOID SpriteRendererComponent::BakeAnimations()
|
||||||
{
|
{
|
||||||
if (m_animations.size())
|
if (m_animations.size())
|
||||||
SetActiveAnimation(0);
|
ForceSetActiveAnimation(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID SpriteRendererComponent::SetAnimationFrame(IN INT32 animation, IN INT32 frame)
|
||||||
|
{
|
||||||
|
m_activeAnimation = {};
|
||||||
|
m_currentAnimationState = m_animations[animation].Keys[frame];
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID SpriteRendererComponent::SetActiveAnimation(IN Handle animation)
|
VOID SpriteRendererComponent::SetActiveAnimation(IN Handle animation)
|
||||||
{
|
{
|
||||||
if (animation == m_activeAnimationHandle)
|
if (animation == m_activeAnimationHandle)
|
||||||
return;
|
return;
|
||||||
|
ForceSetActiveAnimation(animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID SpriteRendererComponent::ForceSetActiveAnimation(IN Handle animation)
|
||||||
|
{
|
||||||
IA_RELEASE_ASSERT((animation != INVALID_HANDLE) && (animation < m_animations.size()));
|
IA_RELEASE_ASSERT((animation != INVALID_HANDLE) && (animation < m_animations.size()));
|
||||||
m_prevAnimationKeyFrameIndex = 0;
|
m_prevAnimationKeyFrameIndex = 0;
|
||||||
m_activeAnimation = m_animations[animation];
|
m_activeAnimation = m_animations[animation];
|
||||||
@ -62,7 +74,8 @@ namespace ia::iae
|
|||||||
m_activeAnimationHandle = animation;
|
m_activeAnimationHandle = animation;
|
||||||
|
|
||||||
CurrentTexture() = m_currentAnimationState.Texture;
|
CurrentTexture() = m_currentAnimationState.Texture;
|
||||||
m_node->DrawnSize() = m_node->GetScale() * m_currentAnimationState.Texture.GetExtent() * m_currentAnimationState.Scale;
|
m_node->DrawnSize() =
|
||||||
|
m_node->GetScale() * m_currentAnimationState.Texture.GetExtent() * m_currentAnimationState.Scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID SpriteRendererComponent::Update()
|
VOID SpriteRendererComponent::Update()
|
||||||
@ -84,7 +97,7 @@ namespace ia::iae
|
|||||||
VOID SpriteRendererComponent::UpdateAnimation()
|
VOID SpriteRendererComponent::UpdateAnimation()
|
||||||
{
|
{
|
||||||
const auto keyCount = m_activeAnimation.Keys.size();
|
const auto keyCount = m_activeAnimation.Keys.size();
|
||||||
if (!keyCount)
|
if (keyCount <= 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_currentAnimationState.ShouldInterpolate)
|
if (m_currentAnimationState.ShouldInterpolate)
|
||||||
|
|||||||
@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
namespace ia::iae
|
namespace ia::iae
|
||||||
{
|
{
|
||||||
|
EXTERN Texture g_whiteStrokeTexture;
|
||||||
|
|
||||||
TextureRendererComponent::TextureRendererComponent(IN Node *node) : IComponent(node)
|
TextureRendererComponent::TextureRendererComponent(IN Node *node) : IComponent(node)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -38,20 +40,15 @@ namespace ia::iae
|
|||||||
Renderer::SetState_CameraRelative(m_isCameraRelative);
|
Renderer::SetState_CameraRelative(m_isCameraRelative);
|
||||||
Renderer::SetState_TextureOffset(m_textureOffset.x, m_textureOffset.y);
|
Renderer::SetState_TextureOffset(m_textureOffset.x, m_textureOffset.y);
|
||||||
|
|
||||||
if (m_shouldDrawOutline)
|
|
||||||
{
|
|
||||||
const auto outlineFactor = 1.2f;
|
|
||||||
Renderer::Draw(Renderer::GetMesh_Quad(), m_texture.GetHandle(),
|
|
||||||
m_node->GetPosition() + m_positionOffset -
|
|
||||||
glm::vec2{m_node->DrawnSize().x * (outlineFactor - 1.0f) / 2.0f,
|
|
||||||
m_node->DrawnSize().y * (outlineFactor - 1.0f) / 2.0f},
|
|
||||||
m_node->DrawnSize() * glm::vec2{outlineFactor, outlineFactor},
|
|
||||||
m_node->GetRotation() + m_rotationOffset, m_node->LayerIndex(), m_node->GetSortIndex(),
|
|
||||||
m_outlineColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
Renderer::Draw(Renderer::GetMesh_Quad(), m_texture.GetHandle(), m_node->GetPosition() + m_positionOffset,
|
Renderer::Draw(Renderer::GetMesh_Quad(), m_texture.GetHandle(), m_node->GetPosition() + m_positionOffset,
|
||||||
m_node->DrawnSize(), m_node->GetRotation() + m_rotationOffset, m_node->LayerIndex(),
|
m_node->DrawnSize(), m_node->GetRotation() + m_rotationOffset, m_node->LayerIndex(),
|
||||||
m_node->GetSortIndex(), m_colorOverlay);
|
m_node->GetSortIndex(), m_colorOverlay);
|
||||||
|
|
||||||
|
//if (m_shouldDrawOutline)
|
||||||
|
//{
|
||||||
|
// Renderer::Draw(Renderer::GetMesh_Quad(), g_whiteStrokeTexture.GetHandle(), m_node->GetPosition() + m_positionOffset,
|
||||||
|
// m_node->DrawnSize(), m_node->GetRotation() + m_rotationOffset, Renderer::MAX_LAYER_INDEX,
|
||||||
|
// m_node->GetSortIndex(), m_outlineColor);
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
} // namespace ia::iae
|
} // namespace ia::iae
|
||||||
@ -36,6 +36,8 @@ namespace ia::iae
|
|||||||
{
|
{
|
||||||
CONSTEXPR FLOAT32 GAME_UPDATE_INTERVAL = 1000.0f / 60.0f;
|
CONSTEXPR FLOAT32 GAME_UPDATE_INTERVAL = 1000.0f / 60.0f;
|
||||||
|
|
||||||
|
EXTERN BOOL g_physicsDebugDrawEnabled;
|
||||||
|
|
||||||
SDL_Event g_event{};
|
SDL_Event g_event{};
|
||||||
FLOAT32 g_updateTimer{};
|
FLOAT32 g_updateTimer{};
|
||||||
BOOL g_shouldClose{false};
|
BOOL g_shouldClose{false};
|
||||||
@ -132,11 +134,16 @@ namespace ia::iae
|
|||||||
|
|
||||||
VOID Engine::UpdateGame()
|
VOID Engine::UpdateGame()
|
||||||
{
|
{
|
||||||
UI::Update();
|
if(Input::WasKeyPressed(Input::KEY_F6))
|
||||||
|
g_physicsDebugDrawEnabled = !g_physicsDebugDrawEnabled;
|
||||||
|
|
||||||
Physics::Update();
|
Physics::Update();
|
||||||
|
Audio::Update();
|
||||||
|
|
||||||
if B_LIKELY (g_activeScene)
|
if B_LIKELY (g_activeScene)
|
||||||
g_activeScene->Update();
|
g_activeScene->Update();
|
||||||
|
|
||||||
|
UI::Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID Engine::RenderGame()
|
VOID Engine::RenderGame()
|
||||||
|
|||||||
@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
namespace ia::iae
|
namespace ia::iae
|
||||||
{
|
{
|
||||||
|
EXTERN SDL_Window *g_windowHandle;
|
||||||
|
|
||||||
struct InputDirection
|
struct InputDirection
|
||||||
{
|
{
|
||||||
glm::vec2 Velocity{};
|
glm::vec2 Velocity{};
|
||||||
@ -82,4 +84,14 @@ namespace ia::iae
|
|||||||
direction = dir.Direction;
|
direction = dir.Direction;
|
||||||
return dir.Velocity;
|
return dir.Velocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID Input::StartTextInput()
|
||||||
|
{
|
||||||
|
SDL_StartTextInput(g_windowHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID Input::StopTextInput()
|
||||||
|
{
|
||||||
|
SDL_StopTextInput(g_windowHandle);
|
||||||
|
}
|
||||||
} // namespace ia::iae
|
} // namespace ia::iae
|
||||||
@ -72,9 +72,10 @@ namespace ia::iae
|
|||||||
c->Disable();
|
c->Disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID Node::AddChild(IN RefPtr<Node> node)
|
Node* Node::AddChild(IN RefPtr<Node> node)
|
||||||
{
|
{
|
||||||
m_children.pushBack(node);
|
m_children.pushBack(node);
|
||||||
|
return node.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID Node::AddComponent(IN RefPtr<IComponent> component)
|
VOID Node::AddComponent(IN RefPtr<IComponent> component)
|
||||||
|
|||||||
@ -16,172 +16,81 @@
|
|||||||
|
|
||||||
#include <IAEngine/IAEngine.hpp>
|
#include <IAEngine/IAEngine.hpp>
|
||||||
#include <IAEngine/Physics/Physics.hpp>
|
#include <IAEngine/Physics/Physics.hpp>
|
||||||
|
#include <IAEngine/Rendering/DebugDraw.hpp>
|
||||||
|
#include <IAEngine/Rendering/Camera.hpp>
|
||||||
|
#include <IAEngine/Rendering/Renderer.hpp>
|
||||||
|
|
||||||
#include <IAEngine/Nodes/Node.hpp>
|
#include <IAEngine/Nodes/Node.hpp>
|
||||||
|
|
||||||
#include <box2d/box2d.h>
|
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
namespace ia::iae
|
namespace ia::iae
|
||||||
{
|
{
|
||||||
struct Body
|
BOOL g_physicsDebugDrawEnabled = false;
|
||||||
{
|
|
||||||
struct Collider
|
|
||||||
{
|
|
||||||
b2ShapeId ShapeId{};
|
|
||||||
BoxCollider2DComponent *ColliderComponent{};
|
|
||||||
};
|
|
||||||
|
|
||||||
b2BodyId BodyId{.world0 = 0xFFFF};
|
Vector<PhysicsComponent *> g_physicsComponents;
|
||||||
PhysicsBody2DComponent *BodyComponent;
|
|
||||||
Vector<Collider> Colliders;
|
|
||||||
};
|
|
||||||
|
|
||||||
b2WorldId g_worldId{};
|
|
||||||
Vector<Body> g_bodies;
|
|
||||||
std::map<Handle, BoxCollider2DComponent*> g_shapeColliders;
|
|
||||||
|
|
||||||
INLINE Handle ShapeIdToHandle(IN b2ShapeId id)
|
|
||||||
{
|
|
||||||
return *reinterpret_cast<Handle*>(&id.index1);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID Physics::Initialize()
|
VOID Physics::Initialize()
|
||||||
{
|
{
|
||||||
auto worldDef = b2DefaultWorldDef();
|
|
||||||
worldDef.gravity = b2Vec2{0.0f, 1000.0f};
|
|
||||||
g_worldId = b2CreateWorld(&worldDef);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID Physics::Terminate()
|
VOID Physics::Terminate()
|
||||||
{
|
{
|
||||||
b2DestroyWorld(g_worldId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID Physics::Update()
|
VOID Physics::Update()
|
||||||
{
|
{
|
||||||
CONSTEXPR FLOAT32 TIME_STEP = 1.0f / 60.0f;
|
|
||||||
CONSTEXPR INT32 SUB_STEP_COUNT = 4;
|
|
||||||
b2World_Step(g_worldId, TIME_STEP, SUB_STEP_COUNT);
|
|
||||||
|
|
||||||
// Process contact events
|
|
||||||
const auto contactEvents = b2World_GetContactEvents(g_worldId);
|
|
||||||
for(INT32 i = 0; i < contactEvents.beginCount; i++)
|
|
||||||
{
|
|
||||||
const auto& shapeA = g_shapeColliders[ShapeIdToHandle(contactEvents.beginEvents[i].shapeIdA)];
|
|
||||||
const auto& shapeB = g_shapeColliders[ShapeIdToHandle(contactEvents.beginEvents[i].shapeIdB)];
|
|
||||||
shapeA->OnCollisionEnter(shapeB->GetNode());
|
|
||||||
shapeB->OnCollisionEnter(shapeA->GetNode());
|
|
||||||
}
|
|
||||||
for(INT32 i = 0; i < contactEvents.endCount; i++)
|
|
||||||
{
|
|
||||||
const auto& shapeA = g_shapeColliders[ShapeIdToHandle(contactEvents.endEvents[i].shapeIdA)];
|
|
||||||
const auto& shapeB = g_shapeColliders[ShapeIdToHandle(contactEvents.endEvents[i].shapeIdB)];
|
|
||||||
shapeA->OnCollisionExit(shapeB->GetNode());
|
|
||||||
shapeB->OnCollisionExit(shapeA->GetNode());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process sensor events
|
VOID Physics::DebugDraw()
|
||||||
const auto sensorEvents = b2World_GetSensorEvents(g_worldId);
|
|
||||||
for(INT32 i = 0; i < sensorEvents.beginCount; i++)
|
|
||||||
{
|
{
|
||||||
const auto& shapeA = g_shapeColliders[ShapeIdToHandle(sensorEvents.beginEvents[i].sensorShapeId)];
|
if(!g_physicsDebugDrawEnabled)
|
||||||
const auto& shapeB = g_shapeColliders[ShapeIdToHandle(sensorEvents.beginEvents[i].visitorShapeId)];
|
return;
|
||||||
shapeA->OnCollisionEnter(shapeB->GetNode());
|
|
||||||
shapeB->OnCollisionEnter(shapeA->GetNode());
|
|
||||||
}
|
|
||||||
for(INT32 i = 0; i < sensorEvents.endCount; i++)
|
|
||||||
{
|
|
||||||
const auto& shapeA = g_shapeColliders[ShapeIdToHandle(sensorEvents.endEvents[i].sensorShapeId)];
|
|
||||||
const auto& shapeB = g_shapeColliders[ShapeIdToHandle(sensorEvents.endEvents[i].visitorShapeId)];
|
|
||||||
shapeA->OnCollisionExit(shapeB->GetNode());
|
|
||||||
shapeB->OnCollisionExit(shapeA->GetNode());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID Physics::Bake()
|
for(const auto& t: g_physicsComponents)
|
||||||
{
|
{
|
||||||
for (auto &b : g_bodies)
|
for(const auto& c: t->Colliders())
|
||||||
{
|
{
|
||||||
const auto pos = b.BodyComponent->GetNode()->GetPosition();
|
auto color = glm::vec4{0.75f, 0.0f, 0.0f, 1.0f};
|
||||||
|
if(c.IsTrigger)
|
||||||
auto bodyDef = b2DefaultBodyDef();
|
color = {0.25f, 0.45f, 0.75f, 0.75f};
|
||||||
if (b.BodyComponent->IsDynamic())
|
DebugDraw::DrawRect(t->GetNode()->GetPosition() + c.Position - Renderer::GetCamera()->Position(), c.Size, color, 2.0f);
|
||||||
bodyDef.type = b2_dynamicBody;
|
|
||||||
bodyDef.position = b2Vec2{pos.x, pos.y};
|
|
||||||
if (b.BodyId.world0 != 0xFFFF)
|
|
||||||
b2DestroyBody(b.BodyId);
|
|
||||||
b.BodyId = b2CreateBody(g_worldId, &bodyDef);
|
|
||||||
|
|
||||||
for (auto &c : b.Colliders)
|
|
||||||
{
|
|
||||||
const auto rect = c.ColliderComponent->Rect();
|
|
||||||
const auto halfW = rect.z/2.0f;
|
|
||||||
const auto halfH = rect.w/2.0f;
|
|
||||||
const auto box = b2MakeOffsetBox(halfW, halfH, {rect.x, rect.y - halfH/2.0f}, b2MakeRot(0));
|
|
||||||
auto boxShapeDef = b2DefaultShapeDef();
|
|
||||||
boxShapeDef.density = 1.0f;
|
|
||||||
boxShapeDef.isSensor = c.ColliderComponent->IsTrigger();
|
|
||||||
boxShapeDef.enableContactEvents = c.ColliderComponent->CollisionsEnabled();
|
|
||||||
boxShapeDef.enableSensorEvents = boxShapeDef.enableContactEvents;
|
|
||||||
c.ShapeId = b2CreatePolygonShape(b.BodyId, &boxShapeDef, &box);
|
|
||||||
g_shapeColliders[ShapeIdToHandle(c.ShapeId)] = c.ColliderComponent;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle Physics::AddBody(IN PhysicsBody2DComponent *body)
|
Handle Physics::RegisterComponent(IN PhysicsComponent *component)
|
||||||
{
|
{
|
||||||
g_bodies.pushBack(Body{
|
g_physicsComponents.pushBack(component);
|
||||||
.BodyComponent = body,
|
return g_physicsComponents.size() - 1;
|
||||||
});
|
|
||||||
return g_bodies.size() - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle Physics::AddColliderToBody(IN Handle bodyHandle, IN BoxCollider2DComponent *collider)
|
BOOL Physics::CanMove(IN Handle handle, IN CONST PhysicsComponent::Collider &collider, IN glm::vec2 movement)
|
||||||
{
|
{
|
||||||
auto &b = g_bodies[bodyHandle];
|
const auto comp = g_physicsComponents[handle];
|
||||||
b.Colliders.pushBack(Body::Collider{
|
const auto pos = comp->GetNode()->GetPosition() + movement + collider.Position;
|
||||||
.ColliderComponent = collider,
|
for (const auto &t : g_physicsComponents)
|
||||||
});
|
{
|
||||||
return b.Colliders.size() - 1;
|
if (t == comp)
|
||||||
}
|
continue;
|
||||||
|
for (const auto &tc : t->Colliders())
|
||||||
|
{
|
||||||
|
const auto tPos = t->GetNode()->GetPosition() + tc.Position;
|
||||||
|
const auto xColliding = ((pos.x + collider.Size.x) >= tPos.x) && ((tPos.x + tc.Size.x) >= pos.x);
|
||||||
|
const auto yColliding = ((pos.y + collider.Size.y) >= tPos.y) && ((tPos.y + tc.Size.y) >= pos.y);
|
||||||
|
if (xColliding && yColliding)
|
||||||
|
{
|
||||||
|
// Collision callback
|
||||||
|
comp->OnCollision(t);
|
||||||
|
t->OnCollision(comp);
|
||||||
|
|
||||||
FLOAT32 Physics::GetBodyRotation(IN Handle handle)
|
// Overlap block
|
||||||
{
|
if (tc.IsTrigger)
|
||||||
const auto &b = g_bodies[handle];
|
continue;
|
||||||
return acosf(b2Body_GetRotation(b.BodyId).c);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec2 Physics::GetBodyPosition(IN Handle handle)
|
|
||||||
{
|
|
||||||
const auto &b = g_bodies[handle];
|
|
||||||
const auto v = b2Body_GetPosition(b.BodyId);
|
|
||||||
return {v.x, v.y};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID Physics::ApplyBodyForce(IN Handle handle, IN glm::vec2 force)
|
|
||||||
{
|
|
||||||
const auto &b = g_bodies[handle];
|
|
||||||
b2Body_ApplyForce(b.BodyId, {force.x, force.y}, b2Body_GetLocalCenterOfMass(b.BodyId), true);
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
VOID Physics::SetBodyVelocity(IN Handle handle, IN glm::vec2 v)
|
|
||||||
{
|
|
||||||
const auto &b = g_bodies[handle];
|
|
||||||
b2Body_SetLinearVelocity(b.BodyId, {v.x, v.y});
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID Physics::SetBodyVelocityX(IN Handle handle, IN FLOAT32 v)
|
|
||||||
{
|
|
||||||
const auto &b = g_bodies[handle];
|
|
||||||
b2Body_SetLinearVelocity(b.BodyId, {v, b2Body_GetLinearVelocity(b.BodyId).y});
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID Physics::SetBodyVelocityY(IN Handle handle, IN FLOAT32 v)
|
|
||||||
{
|
|
||||||
const auto &b = g_bodies[handle];
|
|
||||||
b2Body_SetLinearVelocity(b.BodyId, {b2Body_GetLinearVelocity(b.BodyId).x, v});
|
|
||||||
}
|
}
|
||||||
} // namespace ia::iae
|
} // namespace ia::iae
|
||||||
130
Src/IAEngine/imp/cpp/Rendering/DebugDraw.cpp
Normal file
130
Src/IAEngine/imp/cpp/Rendering/DebugDraw.cpp
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
// 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/IAEngine.hpp>
|
||||||
|
#include <IAEngine/Rendering/Camera.hpp>
|
||||||
|
#include <IAEngine/Rendering/DebugDraw.hpp>
|
||||||
|
#include <IAEngine/Rendering/GPUBuffer.hpp>
|
||||||
|
#include <IAEngine/Rendering/GPUTexture.hpp>
|
||||||
|
#include <IAEngine/Rendering/Pipeline/UnlitMesh.hpp>
|
||||||
|
#include <IAEngine/Rendering/Renderer.hpp>
|
||||||
|
#include <IAEngine/Physics/Physics.hpp>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_gpu.h>
|
||||||
|
|
||||||
|
#include <backends/imgui_impl_sdl3.h>
|
||||||
|
#include <backends/imgui_impl_sdlgpu3.h>
|
||||||
|
|
||||||
|
namespace ia::iae
|
||||||
|
{
|
||||||
|
EXTERN SDL_Window *g_windowHandle;
|
||||||
|
EXTERN SDL_GPUDevice *g_gpuDevice;
|
||||||
|
|
||||||
|
ImGuiIO g_imGUIIO{};
|
||||||
|
|
||||||
|
struct UIWindow
|
||||||
|
{
|
||||||
|
PCCHAR Title{""};
|
||||||
|
glm::vec2 Position{};
|
||||||
|
glm::vec2 Size{};
|
||||||
|
std::function<VOID()> ContentDrawCallback{};
|
||||||
|
BOOL Visibility{true};
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector<UIWindow> g_debugUIWindows;
|
||||||
|
|
||||||
|
VOID DebugDraw::Initailize()
|
||||||
|
{
|
||||||
|
const auto mainScale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay());
|
||||||
|
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
ImGui::CreateContext();
|
||||||
|
g_imGUIIO = ImGui::GetIO();
|
||||||
|
g_imGUIIO.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||||
|
g_imGUIIO.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
|
||||||
|
|
||||||
|
ImGui::StyleColorsClassic();
|
||||||
|
|
||||||
|
ImGuiStyle &style = ImGui::GetStyle();
|
||||||
|
style.ScaleAllSizes(mainScale);
|
||||||
|
style.FontScaleDpi = mainScale;
|
||||||
|
|
||||||
|
ImGui_ImplSDLGPU3_InitInfo initInfo{.Device = g_gpuDevice,
|
||||||
|
.ColorTargetFormat =
|
||||||
|
SDL_GetGPUSwapchainTextureFormat(g_gpuDevice, g_windowHandle),
|
||||||
|
.PresentMode = SDL_GPU_PRESENTMODE_VSYNC};
|
||||||
|
ImGui_ImplSDL3_InitForSDLGPU(g_windowHandle);
|
||||||
|
ImGui_ImplSDLGPU3_Init(&initInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID DebugDraw::Terminate()
|
||||||
|
{
|
||||||
|
ImGui_ImplSDL3_Shutdown();
|
||||||
|
ImGui_ImplSDLGPU3_Shutdown();
|
||||||
|
ImGui::DestroyContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID DebugDraw::Draw()
|
||||||
|
{
|
||||||
|
for (const auto &w : g_debugUIWindows)
|
||||||
|
{
|
||||||
|
if (!w.Visibility)
|
||||||
|
continue;
|
||||||
|
ImGui::Begin(w.Title);
|
||||||
|
ImGui::SetWindowPos({w.Position.x, w.Position.y});
|
||||||
|
ImGui::SetWindowSize({w.Size.x, w.Size.y});
|
||||||
|
w.ContentDrawCallback();
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
Physics::DebugDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID DebugDraw::DrawLine(IN CONST glm::vec2 &from, IN CONST glm::vec2 &to, IN CONST glm::vec4 &color,
|
||||||
|
IN FLOAT32 thickness)
|
||||||
|
{
|
||||||
|
const auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
drawList->AddLine(ImVec2(from.x, from.y), ImVec2(to.x, to.y), IM_COL32(color.x * 255, color.y * 255, color.z * 255, color.w * 255), thickness);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID DebugDraw::DrawRect(IN CONST glm::vec2 &position, IN CONST glm::vec2 &size, IN CONST glm::vec4 &color, IN FLOAT32 thickness)
|
||||||
|
{
|
||||||
|
const auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
drawList->AddRect(ImVec2(position.x, position.y), ImVec2(position.x + size.x, position.y + size.y), IM_COL32(color.x * 255, color.y * 255, color.z * 255, color.w * 255), 0.0f, 0, thickness);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID DebugDraw::DrawRectFilled(IN CONST glm::vec2 &position, IN CONST glm::vec2 &size, IN CONST glm::vec4 &color)
|
||||||
|
{
|
||||||
|
const auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
drawList->AddRectFilled(ImVec2(position.x, position.y), ImVec2(position.x + size.x, position.y + size.y), IM_COL32(color.x * 255, color.y * 255, color.z * 255, color.w * 255));
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle DebugDraw::AddUIWindow(IN PCCHAR title, IN CONST glm::vec2 &position, IN CONST glm::vec2 &size,
|
||||||
|
IN std::function<VOID()> contentDrawCallback)
|
||||||
|
{
|
||||||
|
g_debugUIWindows.pushBack(UIWindow{title, position, size, contentDrawCallback});
|
||||||
|
return g_debugUIWindows.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID DebugDraw::SetUIWindowVisibility(IN Handle handle, IN BOOL visible)
|
||||||
|
{
|
||||||
|
g_debugUIWindows[handle].Visibility = visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID DebugDraw::ToggleUIWindowVisibility(IN Handle handle)
|
||||||
|
{
|
||||||
|
g_debugUIWindows[handle].Visibility = !g_debugUIWindows[handle].Visibility;
|
||||||
|
}
|
||||||
|
} // namespace ia::iae
|
||||||
@ -34,8 +34,7 @@ namespace ia::iae
|
|||||||
.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_REPEAT,
|
.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_REPEAT,
|
||||||
.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_REPEAT,
|
.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_REPEAT,
|
||||||
.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_REPEAT,
|
.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_REPEAT,
|
||||||
.max_anisotropy = 1.0f,
|
.enable_anisotropy = false};
|
||||||
.enable_anisotropy = true};
|
|
||||||
g_defaultSampler = SDL_CreateGPUSampler(g_gpuDevice, &createInfo);
|
g_defaultSampler = SDL_CreateGPUSampler(g_gpuDevice, &createInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
81
Src/IAEngine/imp/cpp/Rendering/Pipeline/PostProcess.cpp
Normal file
81
Src/IAEngine/imp/cpp/Rendering/Pipeline/PostProcess.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// 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/Rendering/Pipeline/PostProcess.hpp>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_gpu.h>
|
||||||
|
|
||||||
|
#include <EmbeddedShaders.hpp>
|
||||||
|
|
||||||
|
namespace ia::iae
|
||||||
|
{
|
||||||
|
EXTERN SDL_GPUDevice *g_gpuDevice;
|
||||||
|
EXTERN SDL_Window *g_windowHandle;
|
||||||
|
|
||||||
|
Pipeline_PostProcess::~Pipeline_PostProcess()
|
||||||
|
{
|
||||||
|
if (m_handle)
|
||||||
|
SDL_ReleaseGPUGraphicsPipeline(g_gpuDevice, (SDL_GPUGraphicsPipeline *) m_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<Pipeline_PostProcess> Pipeline_PostProcess::Create()
|
||||||
|
{
|
||||||
|
const auto res = MakeRefPtr<Pipeline_PostProcess>();
|
||||||
|
|
||||||
|
const auto vertexShader = LoadShaderFromMemory(ShaderStage::VERTEX, SHADER_SOURCE_POSTPROCESS_VERT,
|
||||||
|
sizeof(SHADER_SOURCE_POSTPROCESS_VERT), 0, 0, 0, 0);
|
||||||
|
const auto pixelShader = LoadShaderFromMemory(ShaderStage::PIXEL, SHADER_SOURCE_POSTPROCESS_FRAG,
|
||||||
|
sizeof(SHADER_SOURCE_POSTPROCESS_FRAG), 2, 0, 0, 0);
|
||||||
|
|
||||||
|
SDL_GPUColorTargetDescription colorTargets[] = {{
|
||||||
|
.format = SDL_GetGPUSwapchainTextureFormat(g_gpuDevice, g_windowHandle),
|
||||||
|
}};
|
||||||
|
SDL_GPUGraphicsPipelineCreateInfo createInfo = {
|
||||||
|
.vertex_shader = (SDL_GPUShader *) vertexShader,
|
||||||
|
.fragment_shader = (SDL_GPUShader *) pixelShader,
|
||||||
|
.vertex_input_state = SDL_GPUVertexInputState{.vertex_buffer_descriptions = nullptr,
|
||||||
|
.num_vertex_buffers = 0,
|
||||||
|
.vertex_attributes = nullptr,
|
||||||
|
.num_vertex_attributes = 0},
|
||||||
|
.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST,
|
||||||
|
.rasterizer_state = SDL_GPURasterizerState{.fill_mode = SDL_GPU_FILLMODE_FILL,
|
||||||
|
.cull_mode = SDL_GPU_CULLMODE_NONE,
|
||||||
|
.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE},
|
||||||
|
.target_info = {.color_target_descriptions = colorTargets,
|
||||||
|
.num_color_targets = sizeof(colorTargets) / sizeof(colorTargets[0]),
|
||||||
|
.has_depth_stencil_target = false},
|
||||||
|
};
|
||||||
|
|
||||||
|
SDL_GPUGraphicsPipeline *handle{};
|
||||||
|
if (!(handle = SDL_CreateGPUGraphicsPipeline(g_gpuDevice, &createInfo)))
|
||||||
|
{
|
||||||
|
IAE_LOG_ERROR("Failed to create a SDL graphics pipeline: ", SDL_GetError());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnloadShader(pixelShader);
|
||||||
|
UnloadShader(vertexShader);
|
||||||
|
|
||||||
|
res->m_handle = (Handle) handle;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID Pipeline_PostProcess::Bind(IN Handle renderPassHandle)
|
||||||
|
{
|
||||||
|
SDL_BindGPUGraphicsPipeline((SDL_GPURenderPass *) renderPassHandle, (SDL_GPUGraphicsPipeline *) m_handle);
|
||||||
|
}
|
||||||
|
} // namespace ia::iae
|
||||||
@ -16,8 +16,10 @@
|
|||||||
|
|
||||||
#include <IAEngine/IAEngine.hpp>
|
#include <IAEngine/IAEngine.hpp>
|
||||||
#include <IAEngine/Rendering/Camera.hpp>
|
#include <IAEngine/Rendering/Camera.hpp>
|
||||||
|
#include <IAEngine/Rendering/DebugDraw.hpp>
|
||||||
#include <IAEngine/Rendering/GPUBuffer.hpp>
|
#include <IAEngine/Rendering/GPUBuffer.hpp>
|
||||||
#include <IAEngine/Rendering/GPUTexture.hpp>
|
#include <IAEngine/Rendering/GPUTexture.hpp>
|
||||||
|
#include <IAEngine/Rendering/Pipeline/PostProcess.hpp>
|
||||||
#include <IAEngine/Rendering/Pipeline/UnlitMesh.hpp>
|
#include <IAEngine/Rendering/Pipeline/UnlitMesh.hpp>
|
||||||
#include <IAEngine/Rendering/Renderer.hpp>
|
#include <IAEngine/Rendering/Renderer.hpp>
|
||||||
|
|
||||||
@ -45,7 +47,7 @@ namespace ia::iae
|
|||||||
SDL_Rect Scissor{0, 0, 0, 0};
|
SDL_Rect Scissor{0, 0, 0, 0};
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector<Mesh*> g_meshes{};
|
Vector<Mesh *> g_meshes{};
|
||||||
RenderState g_renderState{};
|
RenderState g_renderState{};
|
||||||
} // namespace ia::iae
|
} // namespace ia::iae
|
||||||
|
|
||||||
@ -55,21 +57,21 @@ namespace ia::iae
|
|||||||
|
|
||||||
INT32 Renderer::s_width{};
|
INT32 Renderer::s_width{};
|
||||||
INT32 Renderer::s_height{};
|
INT32 Renderer::s_height{};
|
||||||
Vector<Renderer::DebugUIWindow> Renderer::s_debugUIWindows;
|
|
||||||
|
|
||||||
SDL_GPUDevice *g_gpuDevice{};
|
SDL_GPUDevice *g_gpuDevice{};
|
||||||
|
|
||||||
|
ImDrawData *g_imDrawData{};
|
||||||
|
|
||||||
// Render State
|
// Render State
|
||||||
SDL_GPUCommandBuffer *g_cmdBuffer{};
|
SDL_GPUCommandBuffer *g_cmdBuffer{};
|
||||||
SDL_GPURenderPass *g_renderPass{};
|
SDL_GPURenderPass *g_renderPass{};
|
||||||
SDL_GPUTexture *g_swpChainTexture{};
|
SDL_GPUTexture *g_swpChainTexture{};
|
||||||
SDL_GPUTexture *g_depthBufferTexture{};
|
SDL_GPUTexture *g_depthBufferTexture{};
|
||||||
|
SDL_GPUTexture *g_sceneDrawBufferTexture{};
|
||||||
// ImGUI State
|
SDL_GPUTexture *g_debugDrawBufferTexture{};
|
||||||
ImGuiIO g_imGUIIO{};
|
|
||||||
ImDrawData *g_imDrawData{};
|
|
||||||
|
|
||||||
RefPtr<Pipeline_UnlitMesh> g_pipelineUnlitMesh;
|
RefPtr<Pipeline_UnlitMesh> g_pipelineUnlitMesh;
|
||||||
|
RefPtr<Pipeline_PostProcess> g_pipelinePostProcess;
|
||||||
|
|
||||||
Camera2D g_camera{};
|
Camera2D g_camera{};
|
||||||
|
|
||||||
@ -86,6 +88,9 @@ namespace ia::iae
|
|||||||
Texture g_whiteFillTexture{};
|
Texture g_whiteFillTexture{};
|
||||||
Texture g_whiteStrokeTexture{};
|
Texture g_whiteStrokeTexture{};
|
||||||
|
|
||||||
|
SDL_GPUColorTargetInfo colorTargetInfo = {0};
|
||||||
|
SDL_GPUDepthStencilTargetInfo depthStencilTargetInfo = {0};
|
||||||
|
|
||||||
BOOL Renderer::Initialize()
|
BOOL Renderer::Initialize()
|
||||||
{
|
{
|
||||||
SDL_GetWindowSizeInPixels(g_windowHandle, &s_width, &s_height);
|
SDL_GetWindowSizeInPixels(g_windowHandle, &s_width, &s_height);
|
||||||
@ -104,30 +109,24 @@ namespace ia::iae
|
|||||||
SDL_SetGPUSwapchainParameters(g_gpuDevice, g_windowHandle, SDL_GPU_SWAPCHAINCOMPOSITION_SDR,
|
SDL_SetGPUSwapchainParameters(g_gpuDevice, g_windowHandle, SDL_GPU_SWAPCHAINCOMPOSITION_SDR,
|
||||||
SDL_GPU_PRESENTMODE_VSYNC);
|
SDL_GPU_PRESENTMODE_VSYNC);
|
||||||
|
|
||||||
const auto mainScale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay());
|
DebugDraw::Initailize();
|
||||||
|
|
||||||
IMGUI_CHECKVERSION();
|
|
||||||
ImGui::CreateContext();
|
|
||||||
g_imGUIIO = ImGui::GetIO();
|
|
||||||
g_imGUIIO.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
|
||||||
g_imGUIIO.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
|
|
||||||
|
|
||||||
ImGui::StyleColorsClassic();
|
|
||||||
|
|
||||||
ImGuiStyle &style = ImGui::GetStyle();
|
|
||||||
style.ScaleAllSizes(mainScale);
|
|
||||||
style.FontScaleDpi = mainScale;
|
|
||||||
|
|
||||||
ImGui_ImplSDLGPU3_InitInfo initInfo{.Device = g_gpuDevice,
|
|
||||||
.ColorTargetFormat =
|
|
||||||
SDL_GetGPUSwapchainTextureFormat(g_gpuDevice, g_windowHandle),
|
|
||||||
.PresentMode = SDL_GPU_PRESENTMODE_VSYNC};
|
|
||||||
ImGui_ImplSDL3_InitForSDLGPU(g_windowHandle);
|
|
||||||
ImGui_ImplSDLGPU3_Init(&initInfo);
|
|
||||||
|
|
||||||
if (!GPUBuffer::InitializeStagingBuffer())
|
if (!GPUBuffer::InitializeStagingBuffer())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
{
|
||||||
|
SDL_GPUTextureCreateInfo createInfo{.type = SDL_GPU_TEXTURETYPE_2D,
|
||||||
|
.format = SDL_GetGPUSwapchainTextureFormat(g_gpuDevice, g_windowHandle),
|
||||||
|
.usage =
|
||||||
|
SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER,
|
||||||
|
.width = (UINT32) s_width,
|
||||||
|
.height = (UINT32) s_height,
|
||||||
|
.layer_count_or_depth = 1,
|
||||||
|
.num_levels = 1,
|
||||||
|
.sample_count = SDL_GPU_SAMPLECOUNT_1};
|
||||||
|
g_sceneDrawBufferTexture = SDL_CreateGPUTexture(g_gpuDevice, &createInfo);
|
||||||
|
g_debugDrawBufferTexture = SDL_CreateGPUTexture(g_gpuDevice, &createInfo);
|
||||||
|
}
|
||||||
{
|
{
|
||||||
SDL_GPUTextureCreateInfo createInfo{.type = SDL_GPU_TEXTURETYPE_2D,
|
SDL_GPUTextureCreateInfo createInfo{.type = SDL_GPU_TEXTURETYPE_2D,
|
||||||
.format = SDL_GPU_TEXTUREFORMAT_D16_UNORM,
|
.format = SDL_GPU_TEXTUREFORMAT_D16_UNORM,
|
||||||
@ -143,8 +142,9 @@ namespace ia::iae
|
|||||||
GPUTexture::Initialize();
|
GPUTexture::Initialize();
|
||||||
|
|
||||||
g_pipelineUnlitMesh = Pipeline_UnlitMesh::Create();
|
g_pipelineUnlitMesh = Pipeline_UnlitMesh::Create();
|
||||||
|
g_pipelinePostProcess = Pipeline_PostProcess::Create();
|
||||||
|
|
||||||
matProjection = glm::orthoLH(0.0f, (FLOAT32) s_width, (FLOAT32) s_height, 0.0f, -1000.0f, 1000.0f);
|
matProjection = glm::orthoLH(0.0f, (FLOAT32) s_width, (FLOAT32) s_height, 0.0f, -2097152.0f, 2097152.0f);
|
||||||
|
|
||||||
g_defaultScissor.x = 0;
|
g_defaultScissor.x = 0;
|
||||||
g_defaultScissor.y = 0;
|
g_defaultScissor.y = 0;
|
||||||
@ -153,7 +153,7 @@ namespace ia::iae
|
|||||||
|
|
||||||
{ // Generate default textures
|
{ // Generate default textures
|
||||||
constexpr auto size = 100;
|
constexpr auto size = 100;
|
||||||
constexpr auto strokeWeight = 5;
|
constexpr auto strokeWeight = 2;
|
||||||
const auto data = new UINT32[size * size];
|
const auto data = new UINT32[size * size];
|
||||||
memset(data, 0, size * size * 4);
|
memset(data, 0, size * size * 4);
|
||||||
for (SIZE_T i = 0; i < size; i++)
|
for (SIZE_T i = 0; i < size; i++)
|
||||||
@ -175,13 +175,25 @@ namespace ia::iae
|
|||||||
|
|
||||||
g_meshHandleQuad = CreateMesh(
|
g_meshHandleQuad = CreateMesh(
|
||||||
{
|
{
|
||||||
{glm::vec3{-0.5, 0.5, 0}, glm::vec2{0, 1}, glm::vec4{1.0f, 1.0f, 1.0f, 1.0f}},
|
{glm::vec3{0, 1, 0}, glm::vec2{0, 1}, glm::vec4{1.0f, 1.0f, 1.0f, 1.0f}},
|
||||||
{glm::vec3{0.5, 0.5, 0}, glm::vec2{1, 1}, glm::vec4{1.0f, 1.0f, 1.0f, 1.0f}},
|
{glm::vec3{1, 1, 0}, glm::vec2{1, 1}, glm::vec4{1.0f, 1.0f, 1.0f, 1.0f}},
|
||||||
{glm::vec3{0.5, -0.5, 0}, glm::vec2{1, 0}, glm::vec4{1.0f, 1.0f, 1.0f, 1.0f}},
|
{glm::vec3{1, 0, 0}, glm::vec2{1, 0}, glm::vec4{1.0f, 1.0f, 1.0f, 1.0f}},
|
||||||
{glm::vec3{-0.5, -0.5, 0}, glm::vec2{0, 0}, glm::vec4{1.0f, 1.0f, 1.0f, 1.0f}},
|
{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});
|
{0, 1, 2, 2, 3, 0});
|
||||||
|
|
||||||
|
colorTargetInfo.clear_color = SDL_FColor{0.33f, 0.33f, 0.33f, 1.0f};
|
||||||
|
colorTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR;
|
||||||
|
colorTargetInfo.store_op = SDL_GPU_STOREOP_STORE;
|
||||||
|
|
||||||
|
depthStencilTargetInfo.cycle = true;
|
||||||
|
depthStencilTargetInfo.clear_depth = 0;
|
||||||
|
depthStencilTargetInfo.clear_stencil = 0;
|
||||||
|
depthStencilTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR;
|
||||||
|
depthStencilTargetInfo.store_op = SDL_GPU_STOREOP_STORE;
|
||||||
|
depthStencilTargetInfo.stencil_load_op = SDL_GPU_LOADOP_CLEAR;
|
||||||
|
depthStencilTargetInfo.stencil_store_op = SDL_GPU_STOREOP_STORE;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,77 +209,32 @@ namespace ia::iae
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_pipelineUnlitMesh.reset();
|
g_pipelineUnlitMesh.reset();
|
||||||
|
g_pipelinePostProcess.reset();
|
||||||
|
|
||||||
GPUTexture::Terminate();
|
GPUTexture::Terminate();
|
||||||
|
|
||||||
GPUBuffer::TerminateStagingBuffer();
|
GPUBuffer::TerminateStagingBuffer();
|
||||||
|
|
||||||
SDL_ReleaseGPUTexture(g_gpuDevice, g_depthBufferTexture);
|
SDL_ReleaseGPUTexture(g_gpuDevice, g_depthBufferTexture);
|
||||||
|
SDL_ReleaseGPUTexture(g_gpuDevice, g_sceneDrawBufferTexture);
|
||||||
|
SDL_ReleaseGPUTexture(g_gpuDevice, g_debugDrawBufferTexture);
|
||||||
|
|
||||||
ImGui_ImplSDL3_Shutdown();
|
DebugDraw::Terminate();
|
||||||
ImGui_ImplSDLGPU3_Shutdown();
|
|
||||||
ImGui::DestroyContext();
|
|
||||||
|
|
||||||
SDL_ReleaseWindowFromGPUDevice(g_gpuDevice, g_windowHandle);
|
SDL_ReleaseWindowFromGPUDevice(g_gpuDevice, g_windowHandle);
|
||||||
SDL_DestroyGPUDevice(g_gpuDevice);
|
SDL_DestroyGPUDevice(g_gpuDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID Renderer::AddDebugUIWindow(IN PCCHAR title, IN CONST glm::vec2 &position, IN CONST glm::vec2 &size,
|
|
||||||
IN std::function<VOID()> contentDrawCallback)
|
|
||||||
{
|
|
||||||
s_debugUIWindows.pushBack(DebugUIWindow{title, position, size, contentDrawCallback});
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID Renderer::BeginFrame()
|
VOID Renderer::BeginFrame()
|
||||||
{
|
{
|
||||||
ImGui_ImplSDLGPU3_NewFrame();
|
|
||||||
ImGui_ImplSDL3_NewFrame();
|
|
||||||
ImGui::NewFrame();
|
|
||||||
for (const auto &w : s_debugUIWindows)
|
|
||||||
{
|
|
||||||
ImGui::Begin(w.Title);
|
|
||||||
ImGui::SetWindowPos({w.Position.x, w.Position.y});
|
|
||||||
ImGui::SetWindowSize({w.Size.x, w.Size.y});
|
|
||||||
w.ContentDrawCallback();
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
ImGui::Render();
|
|
||||||
|
|
||||||
if (!(g_cmdBuffer = SDL_AcquireGPUCommandBuffer(g_gpuDevice)))
|
if (!(g_cmdBuffer = SDL_AcquireGPUCommandBuffer(g_gpuDevice)))
|
||||||
{
|
{
|
||||||
IAE_LOG_ERROR("Couldn't acquire SDL3 GPU command buffer: ", SDL_GetError());
|
IAE_LOG_ERROR("Couldn't acquire SDL3 GPU command buffer: ", SDL_GetError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SDL_WaitAndAcquireGPUSwapchainTexture(g_cmdBuffer, g_windowHandle, &g_swpChainTexture, (PUINT32) &s_width,
|
colorTargetInfo.texture = g_sceneDrawBufferTexture;
|
||||||
(PUINT32) &s_height))
|
|
||||||
{
|
|
||||||
IAE_LOG_ERROR("Couldn't acquire SDL3 GPU Swapchain texture: ", SDL_GetError());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!g_swpChainTexture)
|
|
||||||
return;
|
|
||||||
|
|
||||||
g_imDrawData = ImGui::GetDrawData();
|
|
||||||
|
|
||||||
ImGui_ImplSDLGPU3_PrepareDrawData(g_imDrawData, g_cmdBuffer);
|
|
||||||
|
|
||||||
SDL_GPUColorTargetInfo colorTargetInfo = {0};
|
|
||||||
colorTargetInfo.texture = g_swpChainTexture;
|
|
||||||
colorTargetInfo.clear_color = SDL_FColor{0.33f, 0.33f, 0.33f, 1.0f};
|
|
||||||
colorTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR;
|
|
||||||
colorTargetInfo.store_op = SDL_GPU_STOREOP_STORE;
|
|
||||||
|
|
||||||
SDL_GPUDepthStencilTargetInfo depthStencilTargetInfo = {0};
|
|
||||||
depthStencilTargetInfo.texture = g_depthBufferTexture;
|
depthStencilTargetInfo.texture = g_depthBufferTexture;
|
||||||
depthStencilTargetInfo.cycle = true;
|
|
||||||
depthStencilTargetInfo.clear_depth = 0;
|
|
||||||
depthStencilTargetInfo.clear_stencil = 0;
|
|
||||||
depthStencilTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR;
|
|
||||||
depthStencilTargetInfo.store_op = SDL_GPU_STOREOP_STORE;
|
|
||||||
depthStencilTargetInfo.stencil_load_op = SDL_GPU_LOADOP_CLEAR;
|
|
||||||
depthStencilTargetInfo.stencil_store_op = SDL_GPU_STOREOP_STORE;
|
|
||||||
|
|
||||||
g_renderPass = SDL_BeginGPURenderPass(g_cmdBuffer, &colorTargetInfo, 1, &depthStencilTargetInfo);
|
g_renderPass = SDL_BeginGPURenderPass(g_cmdBuffer, &colorTargetInfo, 1, &depthStencilTargetInfo);
|
||||||
|
|
||||||
@ -279,11 +246,48 @@ namespace ia::iae
|
|||||||
|
|
||||||
VOID Renderer::EndFrame()
|
VOID Renderer::EndFrame()
|
||||||
{
|
{
|
||||||
|
SDL_EndGPURenderPass(g_renderPass);
|
||||||
|
|
||||||
|
ImGui_ImplSDLGPU3_NewFrame();
|
||||||
|
ImGui_ImplSDL3_NewFrame();
|
||||||
|
ImGui::NewFrame();
|
||||||
|
DebugDraw::Draw();
|
||||||
|
ImGui::Render();
|
||||||
|
g_imDrawData = ImGui::GetDrawData();
|
||||||
|
ImGui_ImplSDLGPU3_PrepareDrawData(g_imDrawData, g_cmdBuffer);
|
||||||
|
colorTargetInfo.texture = g_debugDrawBufferTexture;
|
||||||
|
g_renderPass = SDL_BeginGPURenderPass(g_cmdBuffer, &colorTargetInfo, 1, nullptr);
|
||||||
|
ImGui_ImplSDLGPU3_RenderDrawData(g_imDrawData, g_cmdBuffer, g_renderPass);
|
||||||
|
SDL_EndGPURenderPass(g_renderPass);
|
||||||
|
|
||||||
|
if (!SDL_WaitAndAcquireGPUSwapchainTexture(g_cmdBuffer, g_windowHandle, &g_swpChainTexture, (PUINT32) &s_width,
|
||||||
|
(PUINT32) &s_height))
|
||||||
|
{
|
||||||
|
IAE_LOG_ERROR("Couldn't acquire SDL3 GPU Swapchain texture: ", SDL_GetError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!g_swpChainTexture)
|
if (!g_swpChainTexture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ImGui_ImplSDLGPU3_RenderDrawData(g_imDrawData, g_cmdBuffer, g_renderPass);
|
colorTargetInfo.texture = g_swpChainTexture;
|
||||||
|
|
||||||
|
g_renderPass = SDL_BeginGPURenderPass(g_cmdBuffer, &colorTargetInfo, 1, nullptr);
|
||||||
|
g_pipelinePostProcess->Bind((Handle) g_renderPass);
|
||||||
|
SDL_GPUTextureSamplerBinding textureBindings[2] = {
|
||||||
|
{
|
||||||
|
.texture = g_sceneDrawBufferTexture,
|
||||||
|
.sampler = (SDL_GPUSampler*)GPUTexture::GetDefaultSampler()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.texture = g_debugDrawBufferTexture,
|
||||||
|
.sampler = (SDL_GPUSampler*)GPUTexture::GetDefaultSampler()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
SDL_BindGPUFragmentSamplers(g_renderPass, 0, textureBindings, 2);
|
||||||
|
SDL_DrawGPUPrimitives(g_renderPass, 6, 1, 0, 0);
|
||||||
SDL_EndGPURenderPass(g_renderPass);
|
SDL_EndGPURenderPass(g_renderPass);
|
||||||
|
|
||||||
SDL_SubmitGPUCommandBuffer(g_cmdBuffer);
|
SDL_SubmitGPUCommandBuffer(g_cmdBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,7 +340,7 @@ namespace ia::iae
|
|||||||
Handle Renderer::CreateMesh(IN CONST Vector<MeshVertex> &vertices, IN CONST Vector<INT32> &indices)
|
Handle Renderer::CreateMesh(IN CONST Vector<MeshVertex> &vertices, IN CONST Vector<INT32> &indices)
|
||||||
{
|
{
|
||||||
const auto mesh = CreateUnmanagedMesh(vertices, indices);
|
const auto mesh = CreateUnmanagedMesh(vertices, indices);
|
||||||
g_meshes.pushBack((Mesh*)mesh);
|
g_meshes.pushBack((Mesh *) mesh);
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,12 +352,12 @@ namespace ia::iae
|
|||||||
mesh->IndexBuffer = GPUBuffer::Create(GPUBuffer::Usage::INDEX, indices.data(),
|
mesh->IndexBuffer = GPUBuffer::Create(GPUBuffer::Usage::INDEX, indices.data(),
|
||||||
static_cast<UINT32>(indices.size() * sizeof(indices[0])));
|
static_cast<UINT32>(indices.size() * sizeof(indices[0])));
|
||||||
mesh->IndexCount = static_cast<UINT32>(indices.size());
|
mesh->IndexCount = static_cast<UINT32>(indices.size());
|
||||||
return (Handle)mesh;
|
return (Handle) mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID Renderer::DestroyUnmanagedMesh(IN Handle handle)
|
VOID Renderer::DestroyUnmanagedMesh(IN Handle handle)
|
||||||
{
|
{
|
||||||
delete ((Mesh*)handle);
|
delete ((Mesh *) handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID Renderer::Draw(IN Handle meshHandle, IN Handle textureHandle, IN CONST glm::vec2 &position,
|
VOID Renderer::Draw(IN Handle meshHandle, IN Handle textureHandle, IN CONST glm::vec2 &position,
|
||||||
@ -402,7 +406,7 @@ namespace ia::iae
|
|||||||
else
|
else
|
||||||
SDL_SetGPUScissor(g_renderPass, &g_defaultScissor);
|
SDL_SetGPUScissor(g_renderPass, &g_defaultScissor);
|
||||||
|
|
||||||
const auto mesh = (Mesh*)meshHandle;
|
const auto mesh = (Mesh *) meshHandle;
|
||||||
SDL_GPUBufferBinding bufferBindings[] = {
|
SDL_GPUBufferBinding bufferBindings[] = {
|
||||||
{.buffer = (SDL_GPUBuffer *) mesh->VertexBuffer->GetHandle(), .offset = 0},
|
{.buffer = (SDL_GPUBuffer *) mesh->VertexBuffer->GetHandle(), .offset = 0},
|
||||||
{.buffer = (SDL_GPUBuffer *) mesh->IndexBuffer->GetHandle(), .offset = 0}};
|
{.buffer = (SDL_GPUBuffer *) mesh->IndexBuffer->GetHandle(), .offset = 0}};
|
||||||
|
|||||||
@ -27,7 +27,6 @@ namespace ia::iae
|
|||||||
|
|
||||||
VOID Scene::OnActivate()
|
VOID Scene::OnActivate()
|
||||||
{
|
{
|
||||||
Physics::Bake();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID Scene::OnDeactivate()
|
VOID Scene::OnDeactivate()
|
||||||
|
|||||||
@ -26,6 +26,9 @@
|
|||||||
|
|
||||||
#include <IACore/File.hpp>
|
#include <IACore/File.hpp>
|
||||||
|
|
||||||
|
#include <IACore/Map.hpp>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
namespace ia::iae
|
namespace ia::iae
|
||||||
{
|
{
|
||||||
class RmlUIRenderInterface : public Rml::RenderInterface
|
class RmlUIRenderInterface : public Rml::RenderInterface
|
||||||
@ -311,18 +314,109 @@ namespace ia::iae
|
|||||||
}
|
}
|
||||||
} // namespace ia::iae
|
} // namespace ia::iae
|
||||||
|
|
||||||
|
namespace ia::iae
|
||||||
|
{
|
||||||
|
class EventListener : public Rml::EventListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EventListener(IN Rml::ElementDocument *document) : m_document(document)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID AddClickListener(IN PCCHAR elementId, IN std::function<VOID()> callback)
|
||||||
|
{
|
||||||
|
m_document->GetElementById(elementId)->AddEventListener("click", this);
|
||||||
|
m_clickCallbacks[elementId] = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID AddHoverEnterListener(IN PCCHAR elementId, IN std::function<VOID()> callback)
|
||||||
|
{
|
||||||
|
m_document->GetElementById(elementId)->AddEventListener("mouseover", this);
|
||||||
|
m_hoverEnterCallbacks[elementId] = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID AddHoverExitListener(IN PCCHAR elementId, IN std::function<VOID()> callback)
|
||||||
|
{
|
||||||
|
m_document->GetElementById(elementId)->AddEventListener("mouseout", this);
|
||||||
|
m_hoverExitCallbacks[elementId] = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID AddPointerDownListener(IN PCCHAR elementId, IN std::function<VOID()> callback)
|
||||||
|
{
|
||||||
|
m_document->GetElementById(elementId)->AddEventListener("mousedown", this);
|
||||||
|
m_pointerDownCallbacks[elementId] = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID AddPointerUpListener(IN PCCHAR elementId, IN std::function<VOID()> callback)
|
||||||
|
{
|
||||||
|
m_document->GetElementById(elementId)->AddEventListener("mouseup", this);
|
||||||
|
m_pointerUpCallbacks[elementId] = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID ProcessEvent(IN Rml::Event &event)
|
||||||
|
{
|
||||||
|
switch (event.GetId())
|
||||||
|
{
|
||||||
|
case Rml::EventId::Click:
|
||||||
|
m_clickCallbacks[event.GetTargetElement()->GetId().c_str()]();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rml::EventId::Mouseover:
|
||||||
|
m_hoverEnterCallbacks[event.GetTargetElement()->GetId().c_str()]();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rml::EventId::Mouseout:
|
||||||
|
m_hoverExitCallbacks[event.GetTargetElement()->GetId().c_str()]();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rml::EventId::Mousedown:
|
||||||
|
m_pointerDownCallbacks[event.GetTargetElement()->GetId().c_str()]();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rml::EventId::Mouseup:
|
||||||
|
m_pointerUpCallbacks[event.GetTargetElement()->GetId().c_str()]();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Rml::ElementDocument *CONST m_document;
|
||||||
|
Map<String, std::function<VOID()>> m_clickCallbacks;
|
||||||
|
Map<String, std::function<VOID()>> m_hoverEnterCallbacks;
|
||||||
|
Map<String, std::function<VOID()>> m_hoverExitCallbacks;
|
||||||
|
Map<String, std::function<VOID()>> m_pointerDownCallbacks;
|
||||||
|
Map<String, std::function<VOID()>> m_pointerUpCallbacks;
|
||||||
|
};
|
||||||
|
} // namespace ia::iae
|
||||||
|
|
||||||
namespace ia::iae
|
namespace ia::iae
|
||||||
{
|
{
|
||||||
Rml::Context *g_context{};
|
Rml::Context *g_context{};
|
||||||
|
BOOL g_debuggerEnabled{false};
|
||||||
|
|
||||||
|
std::map<Handle, EventListener *> g_eventListeners;
|
||||||
|
|
||||||
|
struct MainDataModel
|
||||||
|
{
|
||||||
|
Rml::String InputValues[10];
|
||||||
|
} g_mainDataModel;
|
||||||
|
|
||||||
VOID UI::Initialize(IN INT32 width, IN INT32 height)
|
VOID UI::Initialize(IN INT32 width, IN INT32 height)
|
||||||
{
|
{
|
||||||
Rml::SetRenderInterface(&g_rmlUIRenderInterface);
|
Rml::SetRenderInterface(&g_rmlUIRenderInterface);
|
||||||
Rml::Initialise();
|
Rml::Initialise();
|
||||||
g_context = Rml::CreateContext("main", Rml::Vector2i(width, height));
|
g_context = Rml::CreateContext("main", Rml::Vector2i(width, height));
|
||||||
//Rml::Debugger::Initialise(g_context);
|
Rml::Debugger::Initialise(g_context);
|
||||||
//Rml::Debugger::SetVisible(true);
|
DisableDebugger();
|
||||||
//Rml::LoadFontFace("Roboto-Black.ttf");
|
|
||||||
|
if (auto dataModel = g_context->CreateDataModel("main"))
|
||||||
|
{
|
||||||
|
for (INT32 i = 0; i < ((sizeof(MainDataModel::InputValues) / sizeof(MainDataModel::InputValues[0]))); i++)
|
||||||
|
dataModel.Bind(BuildString("InputValue", i).c_str(), &g_mainDataModel.InputValues[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID UI::Terminate()
|
VOID UI::Terminate()
|
||||||
@ -356,11 +450,21 @@ namespace ia::iae
|
|||||||
g_context->ProcessMouseButtonDown(SDLMouseButtonToRml(event->button.button), keymods);
|
g_context->ProcessMouseButtonDown(SDLMouseButtonToRml(event->button.button), keymods);
|
||||||
break;
|
break;
|
||||||
case SDL_EventType::SDL_EVENT_KEY_DOWN:
|
case SDL_EventType::SDL_EVENT_KEY_DOWN:
|
||||||
|
if (event->key.key == SDLK_F8)
|
||||||
|
{
|
||||||
|
if (g_debuggerEnabled)
|
||||||
|
DisableDebugger();
|
||||||
|
else
|
||||||
|
EnableDebugger();
|
||||||
|
}
|
||||||
g_context->ProcessKeyDown(SDLKeyToRml(event->key.key), keymods);
|
g_context->ProcessKeyDown(SDLKeyToRml(event->key.key), keymods);
|
||||||
break;
|
break;
|
||||||
case SDL_EventType::SDL_EVENT_KEY_UP:
|
case SDL_EventType::SDL_EVENT_KEY_UP:
|
||||||
g_context->ProcessKeyUp(SDLKeyToRml(event->key.key), keymods);
|
g_context->ProcessKeyUp(SDLKeyToRml(event->key.key), keymods);
|
||||||
break;
|
break;
|
||||||
|
case SDL_EventType::SDL_EVENT_TEXT_INPUT:
|
||||||
|
g_context->ProcessTextInput(Rml::String(&event->text.text[0]));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,6 +473,84 @@ namespace ia::iae
|
|||||||
}
|
}
|
||||||
} // namespace ia::iae
|
} // namespace ia::iae
|
||||||
|
|
||||||
|
namespace ia::iae
|
||||||
|
{
|
||||||
|
VOID UI::AddFontFromFile(IN CONST String &path)
|
||||||
|
{
|
||||||
|
Rml::LoadFontFace(path.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID UI::EnableDebugger()
|
||||||
|
{
|
||||||
|
Rml::Debugger::SetVisible(g_debuggerEnabled = true);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID UI::DisableDebugger()
|
||||||
|
{
|
||||||
|
Rml::Debugger::SetVisible(g_debuggerEnabled = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle UI::AddWindowFromFile(IN CONST String &path)
|
||||||
|
{
|
||||||
|
const auto w = g_context->LoadDocument(path.c_str());
|
||||||
|
const auto handle = (Handle) w;
|
||||||
|
g_eventListeners[handle] = new EventListener(w);
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID UI::ShowWindow(IN Handle handle)
|
||||||
|
{
|
||||||
|
reinterpret_cast<Rml::ElementDocument *>(handle)->Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID UI::HideWindow(IN Handle handle)
|
||||||
|
{
|
||||||
|
reinterpret_cast<Rml::ElementDocument *>(handle)->Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID UI::AddClickEvent(IN Handle handle, IN PCCHAR elementId, IN std::function<VOID()> callback)
|
||||||
|
{
|
||||||
|
g_eventListeners[handle]->AddClickListener(elementId, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID UI::AddHoverEnterEvent(IN Handle handle, IN PCCHAR elementId, IN std::function<VOID()> callback)
|
||||||
|
{
|
||||||
|
g_eventListeners[handle]->AddHoverEnterListener(elementId, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID UI::AddHoverExitEvent(IN Handle handle, IN PCCHAR elementId, IN std::function<VOID()> callback)
|
||||||
|
{
|
||||||
|
g_eventListeners[handle]->AddHoverExitListener(elementId, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID UI::AddPointerDownEvent(IN Handle handle, IN PCCHAR elementId, IN std::function<VOID()> callback)
|
||||||
|
{
|
||||||
|
g_eventListeners[handle]->AddPointerDownListener(elementId, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID UI::AddPointerUpEvent(IN Handle handle, IN PCCHAR elementId, IN std::function<VOID()> callback)
|
||||||
|
{
|
||||||
|
g_eventListeners[handle]->AddPointerUpListener(elementId, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
String UI::GetInputValue(IN INT32 index)
|
||||||
|
{
|
||||||
|
return g_mainDataModel.InputValues[index].c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID UI::SetInputValue(IN INT32 index, IN CONST String &value)
|
||||||
|
{
|
||||||
|
g_mainDataModel.InputValues[index] = Rml::String(value.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID UI::DestroyWindow(IN Handle handle)
|
||||||
|
{
|
||||||
|
const auto w = reinterpret_cast<Rml::ElementDocument *>(handle);
|
||||||
|
w->Hide();
|
||||||
|
w->Close();
|
||||||
|
}
|
||||||
|
} // namespace ia::iae
|
||||||
|
|
||||||
namespace ia::iae
|
namespace ia::iae
|
||||||
{
|
{
|
||||||
Rml::CompiledGeometryHandle RmlUIRenderInterface::CompileGeometry(Rml::Span<const Rml::Vertex> vertices,
|
Rml::CompiledGeometryHandle RmlUIRenderInterface::CompileGeometry(Rml::Span<const Rml::Vertex> vertices,
|
||||||
@ -393,9 +575,10 @@ namespace ia::iae
|
|||||||
Renderer::SetState_CameraRelative(false);
|
Renderer::SetState_CameraRelative(false);
|
||||||
Renderer::SetState_TextureOffset(0, 0);
|
Renderer::SetState_TextureOffset(0, 0);
|
||||||
if (texture)
|
if (texture)
|
||||||
Renderer::Draw(geometry, g_textures[texture - 1].GetHandle(), {translation.x, translation.y}, {1.0f, 1.0f});
|
Renderer::Draw(geometry, g_textures[texture - 1].GetHandle(), {translation.x, translation.y}, {1.0f, 1.0f},
|
||||||
|
0.0f, Renderer::MAX_LAYER_INDEX);
|
||||||
else
|
else
|
||||||
Renderer::Draw(geometry, 0, {translation.x, translation.y}, {1.0f, 1.0f});
|
Renderer::Draw(geometry, 0, {translation.x, translation.y}, {1.0f, 1.0f}, 0.0f, Renderer::MAX_LAYER_INDEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RmlUIRenderInterface::ReleaseGeometry(Rml::CompiledGeometryHandle geometry)
|
void RmlUIRenderInterface::ReleaseGeometry(Rml::CompiledGeometryHandle geometry)
|
||||||
@ -404,7 +587,8 @@ namespace ia::iae
|
|||||||
|
|
||||||
Rml::TextureHandle RmlUIRenderInterface::LoadTexture(Rml::Vector2i &texture_dimensions, const Rml::String &source)
|
Rml::TextureHandle RmlUIRenderInterface::LoadTexture(Rml::Vector2i &texture_dimensions, const Rml::String &source)
|
||||||
{
|
{
|
||||||
return 0;
|
g_textures.pushBack(Engine::CreateTexture(File::ReadToVector(source.c_str())));
|
||||||
|
return g_textures.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
Rml::TextureHandle RmlUIRenderInterface::GenerateTexture(Rml::Span<const Rml::byte> source,
|
Rml::TextureHandle RmlUIRenderInterface::GenerateTexture(Rml::Span<const Rml::byte> source,
|
||||||
|
|||||||
23
Src/IAEngine/imp/glsl/PostProcessing/PostProcess.frag
Normal file
23
Src/IAEngine/imp/glsl/PostProcessing/PostProcess.frag
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#version 450
|
||||||
|
#extension GL_ARB_separate_shader_objects : enable
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 inTexCoord;
|
||||||
|
|
||||||
|
layout(set = 2, binding = 0) uniform sampler2D sceneDrawTexture;
|
||||||
|
layout(set = 2, binding = 1) uniform sampler2D debugDrawTexture;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
vec4 overlay(vec4 background, vec4 foreground) {
|
||||||
|
return mix(
|
||||||
|
2.0 * background * foreground,
|
||||||
|
1.0 - 2.0 * (1.0 - background) * (1.0 - foreground),
|
||||||
|
step(0.5, background)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec2 uv = vec2(inTexCoord.x, 1.0 - inTexCoord.y);
|
||||||
|
outColor = overlay(texture(debugDrawTexture, uv), texture(sceneDrawTexture, uv));
|
||||||
|
}
|
||||||
10
Src/IAEngine/imp/glsl/PostProcessing/PostProcess.vert
Normal file
10
Src/IAEngine/imp/glsl/PostProcessing/PostProcess.vert
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#version 450
|
||||||
|
#extension GL_ARB_separate_shader_objects : enable
|
||||||
|
|
||||||
|
layout(location = 0) out vec2 outTexCoord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
outTexCoord = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
||||||
|
gl_Position = vec4(outTexCoord * 2.0f - 1.0f, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@ -64,11 +64,13 @@ namespace ia::iae
|
|||||||
STATIC VOID Initialize();
|
STATIC VOID Initialize();
|
||||||
STATIC VOID Terminate();
|
STATIC VOID Terminate();
|
||||||
|
|
||||||
STATIC Sound CreateSound(IN PCUINT8 audioData, IN SIZE_T audioDataSize);
|
STATIC VOID Update();
|
||||||
|
|
||||||
STATIC INT64 CreateTrack();
|
STATIC INT64 CreateTrack();
|
||||||
STATIC VOID DestroyTrack(IN INT64 trackHandle);
|
STATIC VOID DestroyTrack(IN INT64 trackHandle);
|
||||||
|
|
||||||
|
STATIC Sound CreateSound(IN PCUINT8 audioData, IN SIZE_T audioDataSize);
|
||||||
|
|
||||||
STATIC VOID QueueTrackData(IN INT64 trackHandle, IN INT64 dataHandle);
|
STATIC VOID QueueTrackData(IN INT64 trackHandle, IN INT64 dataHandle);
|
||||||
STATIC VOID PlayTrack(IN INT64 trackHandle, IN INT32 loopTimes, IN TimePeriod loopDelay);
|
STATIC VOID PlayTrack(IN INT64 trackHandle, IN INT32 loopTimes, IN TimePeriod loopDelay);
|
||||||
STATIC VOID ClearTrack(IN INT64 trackHandle);
|
STATIC VOID ClearTrack(IN INT64 trackHandle);
|
||||||
|
|||||||
@ -1,72 +0,0 @@
|
|||||||
// 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 Physics;
|
|
||||||
class PhysicsBody2DComponent;
|
|
||||||
|
|
||||||
class BoxCollider2DComponent : public IComponent
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BoxCollider2DComponent(IN Node *node);
|
|
||||||
|
|
||||||
VOID OnCollisionEnter(IN Node *other);
|
|
||||||
VOID OnCollisionExit(IN Node *other);
|
|
||||||
|
|
||||||
public:
|
|
||||||
BOOL &IsDebugDrawEnabled()
|
|
||||||
{
|
|
||||||
return m_isDebugDrawEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL &CollisionsEnabled()
|
|
||||||
{
|
|
||||||
return m_collisionsEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL &IsTrigger()
|
|
||||||
{
|
|
||||||
return m_isTrigger;
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec4 &Rect()
|
|
||||||
{
|
|
||||||
return m_rect;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle PhysicsHandle() CONST
|
|
||||||
{
|
|
||||||
return m_physicsHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
VOID Draw();
|
|
||||||
VOID Update();
|
|
||||||
|
|
||||||
private:
|
|
||||||
glm::vec4 m_rect{};
|
|
||||||
BOOL m_isTrigger{false};
|
|
||||||
BOOL m_isDebugDrawEnabled{false};
|
|
||||||
BOOL m_collisionsEnabled{true};
|
|
||||||
Handle m_physicsHandle{INVALID_HANDLE};
|
|
||||||
PhysicsBody2DComponent *m_body{};
|
|
||||||
};
|
|
||||||
} // namespace ia::iae
|
|
||||||
@ -20,37 +20,47 @@
|
|||||||
|
|
||||||
namespace ia::iae
|
namespace ia::iae
|
||||||
{
|
{
|
||||||
class PhysicsBody2DComponent : public IComponent
|
class PhysicsComponent : public IComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PhysicsBody2DComponent(IN Node *node);
|
struct Collider
|
||||||
|
{
|
||||||
VOID SetVelocity(IN glm::vec2 v);
|
BOOL IsTrigger{false};
|
||||||
VOID SetVelocityX(IN FLOAT32 v);
|
glm::vec2 Position{};
|
||||||
VOID SetVelocityY(IN FLOAT32 v);
|
glm::vec2 Size{};
|
||||||
VOID ApplyForce(IN glm::vec2 force);
|
};
|
||||||
|
|
||||||
VOID Jump(IN FLOAT32 velocity);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BOOL &IsGrounded()
|
PhysicsComponent(IN Node *node);
|
||||||
{
|
~PhysicsComponent();
|
||||||
return m_isGrounded;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Handle CreateCollider();
|
||||||
|
Handle AddCollider(IN Collider collider);
|
||||||
|
Collider &GetCollider(IN Handle handle);
|
||||||
|
|
||||||
|
VOID Move(IN glm::vec2 direction);
|
||||||
|
|
||||||
|
VOID Jump(IN FLOAT32 force);
|
||||||
|
|
||||||
|
public:
|
||||||
BOOL &IsDynamic()
|
BOOL &IsDynamic()
|
||||||
{
|
{
|
||||||
return m_isDynamic;
|
return m_isDynamic;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL &IsRotationLocked()
|
FLOAT32 &MovementSpeed()
|
||||||
{
|
{
|
||||||
return m_isRotationLocked;
|
return m_movementSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle PhysicsHandle() CONST
|
Vector<Collider> &Colliders()
|
||||||
{
|
{
|
||||||
return m_physicsHandle;
|
return m_colliders;
|
||||||
|
}
|
||||||
|
|
||||||
|
CONST glm::vec2& GetVelocity() CONST
|
||||||
|
{
|
||||||
|
return m_velocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -58,9 +68,14 @@ namespace ia::iae
|
|||||||
VOID Update();
|
VOID Update();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BOOL m_isDynamic{};
|
glm::vec2 m_velocity{};
|
||||||
BOOL m_isGrounded{};
|
BOOL m_isDynamic{false};
|
||||||
BOOL m_isRotationLocked{};
|
Vector<Collider> m_colliders;
|
||||||
|
FLOAT32 m_movementSpeed{1.0f};
|
||||||
Handle m_physicsHandle{INVALID_HANDLE};
|
Handle m_physicsHandle{INVALID_HANDLE};
|
||||||
|
|
||||||
|
VOID OnCollision(IN PhysicsComponent *other);
|
||||||
|
|
||||||
|
friend class Physics;
|
||||||
};
|
};
|
||||||
} // namespace ia::iae
|
} // namespace ia::iae
|
||||||
@ -50,6 +50,9 @@ namespace ia::iae
|
|||||||
VOID BakeAnimations();
|
VOID BakeAnimations();
|
||||||
|
|
||||||
VOID SetActiveAnimation(IN Handle animation);
|
VOID SetActiveAnimation(IN Handle animation);
|
||||||
|
VOID ForceSetActiveAnimation(IN Handle animation);
|
||||||
|
|
||||||
|
VOID SetAnimationFrame(IN INT32 animation, IN INT32 frame);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Vector<Animation> &Animations()
|
Vector<Animation> &Animations()
|
||||||
|
|||||||
@ -90,9 +90,9 @@ namespace ia::iae
|
|||||||
BOOL m_isFlippedV{};
|
BOOL m_isFlippedV{};
|
||||||
BOOL m_shouldDrawOutline{};
|
BOOL m_shouldDrawOutline{};
|
||||||
glm::vec4 m_outlineColor{0.25f, 0.25f, 0.25f, 0.75f};
|
glm::vec4 m_outlineColor{0.25f, 0.25f, 0.25f, 0.75f};
|
||||||
BOOL m_isCameraRelative{};
|
BOOL m_isCameraRelative{true};
|
||||||
glm::vec2 m_positionOffset{};
|
glm::vec2 m_positionOffset{};
|
||||||
glm::vec2 m_scaleOffset{};
|
glm::vec2 m_scaleOffset{1.0f, 1.0f};
|
||||||
FLOAT32 m_rotationOffset{};
|
FLOAT32 m_rotationOffset{};
|
||||||
glm::vec2 m_textureOffset{};
|
glm::vec2 m_textureOffset{};
|
||||||
glm::vec4 m_colorOverlay{1.0f, 1.0f, 1.0f, 1.0f};
|
glm::vec4 m_colorOverlay{1.0f, 1.0f, 1.0f, 1.0f};
|
||||||
|
|||||||
@ -255,8 +255,8 @@ namespace ia::iae
|
|||||||
|
|
||||||
enum class DirectionalInput: UINT8
|
enum class DirectionalInput: UINT8
|
||||||
{
|
{
|
||||||
NONE = 0,
|
NONE = 255,
|
||||||
DOWN,
|
DOWN = 0,
|
||||||
DOWN_LEFT,
|
DOWN_LEFT,
|
||||||
LEFT,
|
LEFT,
|
||||||
UP_LEFT,
|
UP_LEFT,
|
||||||
@ -270,6 +270,9 @@ namespace ia::iae
|
|||||||
STATIC VOID Initialize();
|
STATIC VOID Initialize();
|
||||||
STATIC VOID OnEvent(IN PVOID event);
|
STATIC VOID OnEvent(IN PVOID event);
|
||||||
|
|
||||||
|
STATIC VOID StartTextInput();
|
||||||
|
STATIC VOID StopTextInput();
|
||||||
|
|
||||||
STATIC BOOL IsKeyDown(IN Key key)
|
STATIC BOOL IsKeyDown(IN Key key)
|
||||||
{
|
{
|
||||||
return s_keys[(UINT8)key];
|
return s_keys[(UINT8)key];
|
||||||
|
|||||||
@ -39,7 +39,7 @@ namespace ia::iae
|
|||||||
VIRTUAL VOID Disable();
|
VIRTUAL VOID Disable();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VOID AddChild(IN RefPtr<Node> node);
|
Node* AddChild(IN RefPtr<Node> node);
|
||||||
|
|
||||||
template<typename _component_type> _component_type *AddComponent();
|
template<typename _component_type> _component_type *AddComponent();
|
||||||
|
|
||||||
|
|||||||
@ -23,6 +23,30 @@ namespace ia::iae
|
|||||||
template<typename _node_type> class Transform
|
template<typename _node_type> class Transform
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
VOID Translate(IN glm::vec2 v)
|
||||||
|
{
|
||||||
|
m_local.Position += v;
|
||||||
|
RecalculatePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID Scale(IN FLOAT32 v)
|
||||||
|
{
|
||||||
|
m_local.Scale *= v;
|
||||||
|
RecalculateScale();
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID Scale(IN glm::vec2 v)
|
||||||
|
{
|
||||||
|
m_local.Scale *= v;
|
||||||
|
RecalculateScale();
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID Rotate(IN FLOAT32 v)
|
||||||
|
{
|
||||||
|
m_local.Rotation += v;
|
||||||
|
RecalculateRotation();
|
||||||
|
}
|
||||||
|
|
||||||
VOID SetLocalSortIndex(IN INT16 index)
|
VOID SetLocalSortIndex(IN INT16 index)
|
||||||
{
|
{
|
||||||
m_local.SortIndex = index;
|
m_local.SortIndex = index;
|
||||||
|
|||||||
@ -16,29 +16,26 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <IAEngine/Components/BoxCollider2D.hpp>
|
#include <IAEngine/Physics/Physics.hpp>
|
||||||
#include <IAEngine/Components/PhysicsBody2D.hpp>
|
#include <IAEngine/Components/Physics.hpp>
|
||||||
|
|
||||||
namespace ia::iae
|
namespace ia::iae
|
||||||
{
|
{
|
||||||
class Physics
|
class Physics
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
STATIC Handle RegisterComponent(IN PhysicsComponent* component);
|
||||||
|
|
||||||
|
STATIC BOOL CanMove(IN Handle handle, IN CONST PhysicsComponent::Collider& collider, IN glm::vec2 movement);
|
||||||
|
|
||||||
|
private:
|
||||||
STATIC VOID Initialize();
|
STATIC VOID Initialize();
|
||||||
STATIC VOID Terminate();
|
STATIC VOID Terminate();
|
||||||
|
|
||||||
STATIC VOID Bake();
|
|
||||||
|
|
||||||
STATIC VOID Update();
|
STATIC VOID Update();
|
||||||
|
STATIC VOID DebugDraw();
|
||||||
|
|
||||||
STATIC Handle AddBody(IN PhysicsBody2DComponent* body);
|
friend class Engine;
|
||||||
STATIC Handle AddColliderToBody(IN Handle bodyHandle, IN BoxCollider2DComponent* collider);
|
friend class DebugDraw;
|
||||||
|
|
||||||
STATIC FLOAT32 GetBodyRotation(IN Handle handle);
|
|
||||||
STATIC glm::vec2 GetBodyPosition(IN Handle handle);
|
|
||||||
STATIC VOID SetBodyVelocity(IN Handle handle, IN glm::vec2 v);
|
|
||||||
STATIC VOID SetBodyVelocityX(IN Handle handle, IN FLOAT32 v);
|
|
||||||
STATIC VOID SetBodyVelocityY(IN Handle handle, IN FLOAT32 v);
|
|
||||||
STATIC VOID ApplyBodyForce(IN Handle handle, IN glm::vec2 force);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
46
Src/IAEngine/inc/IAEngine/Rendering/DebugDraw.hpp
Normal file
46
Src/IAEngine/inc/IAEngine/Rendering/DebugDraw.hpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// 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/Rendering/Types.hpp>
|
||||||
|
|
||||||
|
namespace ia::iae
|
||||||
|
{
|
||||||
|
class DebugDraw
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
STATIC Handle AddUIWindow(IN PCCHAR title, IN CONST glm::vec2 &position, IN CONST glm::vec2 &size,
|
||||||
|
IN std::function<VOID()> contentDrawCallback);
|
||||||
|
|
||||||
|
STATIC VOID ToggleUIWindowVisibility(IN Handle handle);
|
||||||
|
STATIC VOID SetUIWindowVisibility(IN Handle handle, IN BOOL visible);
|
||||||
|
|
||||||
|
public:
|
||||||
|
STATIC VOID DrawLine(IN CONST glm::vec2 &from, IN CONST glm::vec2 &to, IN CONST glm::vec4 &color,
|
||||||
|
IN FLOAT32 thickness = 1.0f);
|
||||||
|
STATIC VOID DrawRect(IN CONST glm::vec2 &position, IN CONST glm::vec2 &size, IN CONST glm::vec4 &color, IN FLOAT32 thickness = 1.0f);
|
||||||
|
STATIC VOID DrawRectFilled(IN CONST glm::vec2 &position, IN CONST glm::vec2 &size, IN CONST glm::vec4 &color);
|
||||||
|
|
||||||
|
private:
|
||||||
|
STATIC VOID Initailize();
|
||||||
|
STATIC VOID Terminate();
|
||||||
|
|
||||||
|
STATIC VOID Draw();
|
||||||
|
|
||||||
|
friend class Renderer;
|
||||||
|
};
|
||||||
|
} // namespace ia::iae
|
||||||
35
Src/IAEngine/inc/IAEngine/Rendering/Pipeline/PostProcess.hpp
Normal file
35
Src/IAEngine/inc/IAEngine/Rendering/Pipeline/PostProcess.hpp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// 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/Rendering/Pipeline/Pipeline.hpp>
|
||||||
|
|
||||||
|
namespace ia::iae
|
||||||
|
{
|
||||||
|
class Pipeline_PostProcess: public IPipeline
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~Pipeline_PostProcess();
|
||||||
|
|
||||||
|
STATIC RefPtr<Pipeline_PostProcess> Create();
|
||||||
|
|
||||||
|
VOID Bind(IN Handle renderPassHandle);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Handle m_handle{INVALID_HANDLE};
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -24,14 +24,6 @@ namespace ia::iae
|
|||||||
|
|
||||||
class Renderer
|
class Renderer
|
||||||
{
|
{
|
||||||
struct DebugUIWindow
|
|
||||||
{
|
|
||||||
PCCHAR Title{""};
|
|
||||||
glm::vec2 Position{};
|
|
||||||
glm::vec2 Size{};
|
|
||||||
std::function<VOID()> ContentDrawCallback{};
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
STATIC CONSTEXPR UINT8 MAX_LAYER_INDEX = 255;
|
STATIC CONSTEXPR UINT8 MAX_LAYER_INDEX = 255;
|
||||||
|
|
||||||
@ -39,10 +31,6 @@ namespace ia::iae
|
|||||||
STATIC BOOL Initialize();
|
STATIC BOOL Initialize();
|
||||||
STATIC VOID Terminate();
|
STATIC VOID Terminate();
|
||||||
|
|
||||||
public:
|
|
||||||
STATIC VOID AddDebugUIWindow(IN PCCHAR title, IN CONST glm::vec2 &position, IN CONST glm::vec2 &size,
|
|
||||||
IN std::function<VOID()> contentDrawCallback);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
STATIC VOID BeginFrame();
|
STATIC VOID BeginFrame();
|
||||||
STATIC VOID EndFrame();
|
STATIC VOID EndFrame();
|
||||||
@ -82,6 +70,5 @@ namespace ia::iae
|
|||||||
private:
|
private:
|
||||||
STATIC INT32 s_width;
|
STATIC INT32 s_width;
|
||||||
STATIC INT32 s_height;
|
STATIC INT32 s_height;
|
||||||
STATIC Vector<DebugUIWindow> s_debugUIWindows;
|
|
||||||
};
|
};
|
||||||
} // namespace ia::iae
|
} // namespace ia::iae
|
||||||
@ -25,11 +25,11 @@ namespace ia::iae
|
|||||||
public:
|
public:
|
||||||
~Scene();
|
~Scene();
|
||||||
|
|
||||||
VOID OnActivate();
|
VIRTUAL VOID OnActivate();
|
||||||
VOID OnDeactivate();
|
VIRTUAL VOID OnDeactivate();
|
||||||
|
|
||||||
VOID Draw();
|
VIRTUAL VOID Draw();
|
||||||
VOID Update();
|
VIRTUAL VOID Update();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VOID AddNode(IN RefPtr<Node> node);
|
VOID AddNode(IN RefPtr<Node> node);
|
||||||
@ -46,8 +46,14 @@ namespace ia::iae
|
|||||||
return m_ySortingEnabled;
|
return m_ySortingEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec4 &Bounds()
|
||||||
|
{
|
||||||
|
return m_bounds;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BOOL m_ySortingEnabled{false};
|
BOOL m_ySortingEnabled{false};
|
||||||
Vector<RefPtr<Node>> m_nodes;
|
Vector<RefPtr<Node>> m_nodes;
|
||||||
|
glm::vec4 m_bounds;
|
||||||
};
|
};
|
||||||
} // namespace ia::iae
|
} // namespace ia::iae
|
||||||
@ -23,6 +23,28 @@ namespace ia::iae
|
|||||||
class UI
|
class UI
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
STATIC VOID AddFontFromFile(IN CONST String &path);
|
||||||
|
|
||||||
|
STATIC Handle AddWindowFromFile(IN CONST String &path);
|
||||||
|
|
||||||
|
STATIC VOID DestroyWindow(IN Handle handle);
|
||||||
|
|
||||||
|
STATIC VOID ShowWindow(IN Handle handle);
|
||||||
|
STATIC VOID HideWindow(IN Handle handle);
|
||||||
|
|
||||||
|
STATIC String GetInputValue(IN INT32 index);
|
||||||
|
STATIC VOID SetInputValue(IN INT32 index, IN CONST String& value);
|
||||||
|
|
||||||
|
STATIC VOID AddClickEvent(IN Handle handle, IN PCCHAR elementId, IN std::function<VOID()> callback);
|
||||||
|
STATIC VOID AddHoverEnterEvent(IN Handle handle, IN PCCHAR elementId, IN std::function<VOID()> callback);
|
||||||
|
STATIC VOID AddHoverExitEvent(IN Handle handle, IN PCCHAR elementId, IN std::function<VOID()> callback);
|
||||||
|
STATIC VOID AddPointerDownEvent(IN Handle handle, IN PCCHAR elementId, IN std::function<VOID()> callback);
|
||||||
|
STATIC VOID AddPointerUpEvent(IN Handle handle, IN PCCHAR elementId, IN std::function<VOID()> callback);
|
||||||
|
|
||||||
|
STATIC VOID EnableDebugger();
|
||||||
|
STATIC VOID DisableDebugger();
|
||||||
|
|
||||||
|
private:
|
||||||
STATIC VOID Initialize(IN INT32 width, IN INT32 height);
|
STATIC VOID Initialize(IN INT32 width, IN INT32 height);
|
||||||
STATIC VOID Terminate();
|
STATIC VOID Terminate();
|
||||||
|
|
||||||
@ -31,5 +53,7 @@ namespace ia::iae
|
|||||||
|
|
||||||
STATIC VOID OnEvent(IN PVOID event);
|
STATIC VOID OnEvent(IN PVOID event);
|
||||||
STATIC VOID OnResize(IN INT32 width, IN INT32 height);
|
STATIC VOID OnResize(IN INT32 width, IN INT32 height);
|
||||||
|
|
||||||
|
friend class Engine;
|
||||||
};
|
};
|
||||||
}
|
} // namespace ia::iae
|
||||||
@ -34,7 +34,9 @@ SHADER_SOURCE_PATH = "Src/IAEngine/imp/glsl"
|
|||||||
|
|
||||||
SHADER_SOURCE_FILES = [
|
SHADER_SOURCE_FILES = [
|
||||||
"UnlitMesh/UnlitMesh.vert",
|
"UnlitMesh/UnlitMesh.vert",
|
||||||
"UnlitMesh/UnlitMesh.frag"
|
"UnlitMesh/UnlitMesh.frag",
|
||||||
|
"PostProcessing/PostProcess.vert",
|
||||||
|
"PostProcessing/PostProcess.frag"
|
||||||
]
|
]
|
||||||
|
|
||||||
def file_to_source_array(arrayName, filePath):
|
def file_to_source_array(arrayName, filePath):
|
||||||
|
|||||||
4
Vendor/CMakeLists.txt
vendored
4
Vendor/CMakeLists.txt
vendored
@ -54,7 +54,3 @@ add_library(Freetype::Freetype ALIAS freetype)
|
|||||||
# -----------------------------------------------
|
# -----------------------------------------------
|
||||||
add_subdirectory(RmlUI/)
|
add_subdirectory(RmlUI/)
|
||||||
|
|
||||||
# -----------------------------------------------
|
|
||||||
# Box2D
|
|
||||||
# -----------------------------------------------
|
|
||||||
add_subdirectory(box2d/)
|
|
||||||
|
|||||||
1
Vendor/box2d
vendored
1
Vendor/box2d
vendored
Submodule Vendor/box2d deleted from f86d1827eb
Reference in New Issue
Block a user