221 lines
6.2 KiB
C++
221 lines
6.2 KiB
C++
// 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/GPUTexture.hpp>
|
|
|
|
#include <IAEngine/Audio.hpp>
|
|
#include <IAEngine/IAEngine.hpp>
|
|
#include <IAEngine/Input.hpp>
|
|
#include <IAEngine/Physics/Physics.hpp>
|
|
#include <IAEngine/Random.hpp>
|
|
#include <IAEngine/Time.hpp>
|
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
#include <backends/imgui_impl_sdl3.h>
|
|
#include <imgui.h>
|
|
|
|
#define STB_IMAGE_IMPLEMENTATION
|
|
#include <stb_image.h>
|
|
|
|
namespace ia::iae
|
|
{
|
|
CONSTEXPR FLOAT32 GAME_UPDATE_INTERVAL = 1000.0f / 60.0f;
|
|
|
|
SDL_Event g_event{};
|
|
FLOAT32 g_updateTimer{};
|
|
BOOL g_shouldClose{false};
|
|
SDL_Window *g_windowHandle{};
|
|
Vector<RefPtr<GPUTexture>> g_gpuTextureRefs;
|
|
|
|
Scene* g_activeScene;
|
|
|
|
BOOL Engine::Initialize(IN CONST InitConfig &config)
|
|
{
|
|
IAE_LOG_INFO("Booting IAEngine for \"", config.GameName, "\"");
|
|
|
|
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD))
|
|
{
|
|
IAE_LOG_ERROR("Couldn't intialize SDL3: ", SDL_GetError());
|
|
return false;
|
|
}
|
|
|
|
if (!(g_windowHandle = SDL_CreateWindow(config.GameName.c_str(), config.WindowWidth, config.WindowHeight,
|
|
SDL_WINDOW_RESIZABLE)))
|
|
{
|
|
IAE_LOG_ERROR("Couldn't create SDL3 window: ", SDL_GetError());
|
|
return false;
|
|
}
|
|
SDL_SetWindowResizable(g_windowHandle, false);
|
|
|
|
Time::Initialize();
|
|
|
|
if (!Renderer::Initialize())
|
|
return false;
|
|
|
|
Random::Initialize();
|
|
|
|
Input::Initialize();
|
|
Audio::Initialize();
|
|
Physics::Initialize();
|
|
|
|
return true;
|
|
}
|
|
|
|
VOID Engine::Terminate()
|
|
{
|
|
IAE_LOG_INFO("Shutting down IAEngine");
|
|
|
|
for (auto &t : g_gpuTextureRefs)
|
|
t.reset();
|
|
|
|
Renderer::Terminate();
|
|
Audio::Terminate();
|
|
Physics::Terminate();
|
|
|
|
SDL_DestroyWindow(g_windowHandle);
|
|
|
|
SDL_Quit();
|
|
}
|
|
|
|
VOID Engine::BeginFrame()
|
|
{
|
|
SDL_PollEvent(&g_event);
|
|
if (g_event.type == SDL_EVENT_QUIT)
|
|
g_shouldClose = true;
|
|
ProcessEvents();
|
|
g_updateTimer += Time::GetFrameDeltaTime();
|
|
if (g_updateTimer >= GAME_UPDATE_INTERVAL)
|
|
{
|
|
UpdateGame();
|
|
while (g_updateTimer >= GAME_UPDATE_INTERVAL)
|
|
g_updateTimer -= GAME_UPDATE_INTERVAL;
|
|
}
|
|
Renderer::BeginFrame();
|
|
RenderGame();
|
|
}
|
|
|
|
VOID Engine::EndFrame()
|
|
{
|
|
Renderer::EndFrame();
|
|
Time::NextFrame();
|
|
}
|
|
|
|
BOOL Engine::ShouldClose()
|
|
{
|
|
return g_shouldClose;
|
|
}
|
|
|
|
VOID Engine::ProcessEvents()
|
|
{
|
|
ImGui_ImplSDL3_ProcessEvent(&g_event);
|
|
Input::OnEvent(&g_event);
|
|
}
|
|
|
|
VOID Engine::UpdateGame()
|
|
{
|
|
Physics::Update();
|
|
|
|
if B_LIKELY (g_activeScene)
|
|
g_activeScene->Update();
|
|
}
|
|
|
|
VOID Engine::RenderGame()
|
|
{
|
|
if B_LIKELY (g_activeScene)
|
|
g_activeScene->Draw();
|
|
}
|
|
|
|
VOID Engine::ChangeScene(IN Scene* scene)
|
|
{
|
|
g_activeScene = scene;
|
|
}
|
|
|
|
Scene *Engine::GetActiveScene()
|
|
{
|
|
return g_activeScene;
|
|
}
|
|
} // namespace ia::iae
|
|
|
|
namespace ia::iae
|
|
{
|
|
RefPtr<Scene> Engine::CreateScene()
|
|
{
|
|
return MakeRefPtr<Scene>();
|
|
}
|
|
|
|
Texture Engine::CreateTexture(IN CONST Vector<UINT8> &encodedData)
|
|
{
|
|
return CreateTexture(encodedData.data(), encodedData.size());
|
|
}
|
|
|
|
Texture Engine::CreateTexture(IN PCUINT8 encodedData, IN SIZE_T encodedDataSize)
|
|
{
|
|
INT32 w, h, nrChannels;
|
|
const auto pixels = stbi_load_from_memory(encodedData, encodedDataSize, &w, &h, &nrChannels, STBI_rgb_alpha);
|
|
if (!pixels)
|
|
THROW_INVALID_DATA("Failed to decode the provided image data");
|
|
const auto result = CreateTexture((PCUINT8) pixels, w, h);
|
|
STBI_FREE(pixels);
|
|
return result;
|
|
}
|
|
|
|
Texture Engine::CreateTexture(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height)
|
|
{
|
|
const auto t = GPUTexture::Create(rgbaData, width, height);
|
|
g_gpuTextureRefs.pushBack(t);
|
|
return Texture(t->GetHandle(), width, height);
|
|
}
|
|
|
|
Vector<Texture> Engine::CreateTextures(IN CONST Vector<UINT8> &encodedData, IN INT32 textureCount)
|
|
{
|
|
return CreateTextures(encodedData.data(), encodedData.size(), textureCount);
|
|
}
|
|
|
|
Vector<Texture> Engine::CreateTextures(IN PCUINT8 encodedData, IN SIZE_T encodedDataSize, IN INT32 textureCount)
|
|
{
|
|
SIZE_T offset{0};
|
|
Vector<Texture> result;
|
|
INT32 w, h, nrChannels;
|
|
for (INT32 i = 0; i < textureCount; i++)
|
|
{
|
|
SIZE_T readSize{};
|
|
const auto pixels = stbi_load_from_memory(&encodedData[offset], encodedDataSize - offset, &w, &h,
|
|
&nrChannels, STBI_rgb_alpha, readSize);
|
|
if (!pixels)
|
|
THROW_INVALID_DATA("Failed to decode the provided image data");
|
|
result.pushBack(CreateTexture((PCUINT8) pixels, w, h));
|
|
STBI_FREE(pixels);
|
|
offset += readSize;
|
|
if (offset >= encodedDataSize)
|
|
{
|
|
IA_RELEASE_ASSERT(i == (textureCount - 1));
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Sound Engine::CreateSound(IN PCUINT8 audioData, IN SIZE_T audioDataSize)
|
|
{
|
|
return Audio::CreateSound(audioData, audioDataSize);
|
|
}
|
|
|
|
Sound Engine::CreateSound(IN CONST Vector<UINT8> &audioData)
|
|
{
|
|
return CreateSound(audioData.data(), audioData.size());
|
|
}
|
|
} // namespace ia::iae
|