Files
IAEngine/Engine/Src/Imp/CPP/ResourceManager.cpp
Isuru Samarathunga dfce12ee10 mipmaps
2025-10-16 22:59:33 +05:30

256 lines
9.2 KiB
C++

// IAEngine: 2D Game Engine by IA
// Copyright (C) 2025 IASoft (PVT) LTD (oss@iasoft.dev)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <IAEngine/Engine.hpp>
#include <ResourceManager.hpp>
#include <AudioManager.hpp>
#include <Renderer/GPUResourceManager.hpp>
#include <Renderer/Renderer.hpp>
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include <stb_image.h>
#include <stb_image_resize2.h>
namespace ia::iae
{
Map<String, Handle> ResourceManager::s_images;
Map<String, Handle> ResourceManager::s_sounds;
Vector<ResourceManager::ImageResource> ResourceManager::s_imageHandles;
VOID ResourceManager::Initialize()
{
{ // Set Texture Handle 0 to a pure white image
const auto data = new UINT8[100 * 100 * 4];
ia_memset(data, 0xFF, 100 * 100 * 4);
CreateImage(Engine::GetUniqueResourceName(), data, 100, 100);
delete[] data;
}
}
VOID ResourceManager::Terminate()
{
for (const auto &t : s_images)
GPUResourceManager::DestroyTexture(s_imageHandles[t->Value].Handle);
for (const auto &t : s_sounds)
AudioManager::DestoryAudio(t->Value);
}
Handle ResourceManager::CreateImage(IN CONST String &name, IN PCUINT8 encodedData, IN SIZE_T encodedDataSize)
{
INT32 w, h, n;
const auto rgbaData = stbi_load_from_memory(encodedData, encodedDataSize, &w, &h, &n, STBI_rgb_alpha);
const auto result = CreateImage(name, rgbaData, w, h);
STBI_FREE(rgbaData);
return result;
}
Handle ResourceManager::CreateImage(IN CONST String &name, IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height)
{
const auto texture = GPUResourceManager::CreateTexture(SDL_GPU_TEXTUREUSAGE_SAMPLER | SDL_GPU_TEXTUREUSAGE_COLOR_TARGET, width, height, rgbaData,
SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM, true);
s_imageHandles.pushBack(ImageResource{.OriginalWidth = width,
.OriginalHeight = height,
.OriginalPixelData = new UINT8[width * height * 4],
.Width = width,
.Height = height,
.Handle = texture});
ia_memcpy(s_imageHandles.back().OriginalPixelData, rgbaData, width * height * 4);
Handle handle = s_imageHandles.size() - 1;
s_images[name] = handle;
return handle;
}
Handle ResourceManager::CreateSound(IN CONST String &name, IN PCUINT8 encodedData, IN SIZE_T encodedDataSize)
{
const auto handle = AudioManager::CreateAudio(encodedData, encodedDataSize);
s_sounds[name] = handle;
return handle;
}
Handle ResourceManager::GetImage(IN CONST String &name)
{
return s_images[name];
}
Handle ResourceManager::GetSound(IN CONST String &name)
{
return s_sounds[name];
}
String ResourceManager::GetImageName(IN Handle handle)
{
for (const auto &t : s_images)
{
if (handle == t->Value)
return t->Key;
}
THROW_NO_SUCH_KEY();
return "";
}
String ResourceManager::GetSoundName(IN Handle handle)
{
for (const auto &t : s_sounds)
{
if (handle == t->Value)
return t->Key;
}
THROW_NO_SUCH_KEY();
return "";
}
VOID ResourceManager::DestroyImage(IN Handle image)
{
GPUResourceManager::DestroyTexture(s_imageHandles[image].Handle);
s_imageHandles[image] = {};
}
VOID ResourceManager::DestroySound(IN Handle sound)
{
AudioManager::DestoryAudio(sound);
}
IVec2 ResourceManager::GetImageExtent(IN Handle image)
{
const auto t = s_imageHandles[image];
return {t.Width, t.Height};
}
IVec2 ResourceManager::GetImageOriginalExtent(IN Handle image)
{
const auto t = s_imageHandles[image];
return {t.OriginalWidth, t.OriginalHeight};
}
Handle ResourceManager::RescaleImage(IN Handle image, IN Vec2 factor)
{
if (!s_imageHandles[image].OriginalPixelData)
return image;
const auto newWidth = (INT32) (s_imageHandles[image].OriginalWidth * factor.x);
const auto newHeight = (INT32) (s_imageHandles[image].OriginalHeight * factor.y);
if (!newWidth || !newHeight ||
((newWidth <= s_imageHandles[image].OriginalWidth) && (newHeight <= s_imageHandles[image].OriginalHeight)))
return image;
const auto newPixelData =
stbir_resize_uint8_linear(s_imageHandles[image].OriginalPixelData, s_imageHandles[image].OriginalWidth,
s_imageHandles[image].OriginalHeight, s_imageHandles[image].OriginalWidth * 4,
nullptr, newWidth, newHeight, newWidth * 4, stbir_pixel_layout::STBIR_RGBA);
const auto texture = GPUResourceManager::CreateTexture(SDL_GPU_TEXTUREUSAGE_SAMPLER | SDL_GPU_TEXTUREUSAGE_COLOR_TARGET, newWidth, newHeight,
newPixelData, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM, true);
GPUResourceManager::DestroyTexture(s_imageHandles[image].Handle);
s_imageHandles[image].Handle = texture;
s_imageHandles[image].Width = newWidth;
s_imageHandles[image].Height = newHeight;
free(newPixelData);
return image;
}
Handle ResourceManager::CombineImages(IN CONST Vector<Handle> &images, IN INT32 unitWidth, IN INT32 unitHeight,
IN INT32 unitCountX, IN INT32 unitCountY)
{
const auto w = unitWidth * unitCountX;
const auto h = unitHeight * unitCountY;
Vector<SDL_GPUTexture *> textures;
for (const auto &t : images)
textures.pushBack(s_imageHandles[t].Handle);
const auto texture =
GPUResourceManager::CombineTextures(textures.data(), unitWidth, unitHeight, unitCountX, unitCountY);
s_imageHandles.pushBack(ImageResource{.OriginalWidth = w,
.OriginalHeight = h,
.OriginalPixelData = nullptr,
.Width = w,
.Height = h,
.Handle = texture});
Handle handle = s_imageHandles.size() - 1;
s_images[Engine::GetUniqueResourceName()] = handle;
return handle;
}
VOID ResourceManager::RescaleAllImages(IN Vec2 factor)
{
for (auto &t : s_images)
t->Value = RescaleImage(t->Value, factor);
}
} // namespace ia::iae
namespace ia::iae
{
Handle Engine::CreateImage(IN CONST String &name, IN PCUINT8 encodedData, IN SIZE_T encodedDataSize)
{
return ResourceManager::CreateImage(name, encodedData, encodedDataSize);
}
Handle Engine::CreateImage(IN CONST String &name, IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height)
{
return ResourceManager::CreateImage(name, rgbaData, width, height);
}
Handle Engine::CreateSound(IN CONST String &name, IN PCUINT8 encodedData, IN SIZE_T encodedDataSize)
{
return ResourceManager::CreateSound(name, encodedData, encodedDataSize);
}
Handle Engine::GetImage(IN CONST String &name)
{
return ResourceManager::GetImage(name);
}
Handle Engine::GetSound(IN CONST String &name)
{
return ResourceManager::GetSound(name);
}
VOID Engine::DestroyImage(IN Handle image)
{
ResourceManager::DestroyImage(image);
}
VOID Engine::DestroySound(IN Handle sound)
{
ResourceManager::DestroySound(sound);
}
IVec2 Engine::GetImageExtent(IN Handle image)
{
return ResourceManager::GetImageExtent(image);
}
IVec2 Engine::GetImageOriginalExtent(IN Handle image)
{
return ResourceManager::GetImageOriginalExtent(image);
}
Handle Engine::RescaleImage(IN Handle image, IN Vec2 factor)
{
return ResourceManager::RescaleImage(image, factor);
}
VOID Engine::RescaleAllImages(IN Vec2 factor)
{
ResourceManager::RescaleAllImages(factor);
}
Handle Engine::CombineImages(IN CONST Vector<Handle> &images, IN INT32 unitWidth, IN INT32 unitHeight,
IN INT32 unitCountX, IN INT32 unitCountY)
{
return ResourceManager::CombineImages(images, unitWidth, unitHeight, unitCountX, unitCountY);
}
} // namespace ia::iae