// IAEngine: 2D Game Engine by IA // Copyright (C) 2025 IASoft (PVT) LTD (oss@iasoft.dev) // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include #include #include #include #include #define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_RESIZE_IMPLEMENTATION #include #include namespace ia::iae { Vector ResourceManager::s_imageHandles; Map ResourceManager::s_images; Map ResourceManager::s_sounds; Map ResourceManager::s_imageExtents; Map ResourceManager::s_nonScaledImageExtents; 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]); 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, width, height, rgbaData, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM); s_imageHandles.pushBack(texture); Handle handle = s_imageHandles.size() - 1; s_images[name] = handle; s_imageExtents[handle] = (((UINT64) width) << 32) | height; s_nonScaledImageExtents[handle] = s_imageExtents[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]); s_imageHandles[image] = nullptr; } VOID ResourceManager::DestroySound(IN Handle sound) { AudioManager::DestoryAudio(sound); } IVec2 ResourceManager::GetImageExtent(IN Handle image) { const auto t = s_imageExtents[image]; return {(INT32) (t >> 32), (INT32) t}; } Handle ResourceManager::ResizeImage(IN Handle image, IN INT32 newWidth, IN INT32 newHeight) { const auto currentExtent = GetImageExtent(image); const auto pixelData = GPUResourceManager::GetTexturePixelData(s_imageHandles[image], currentExtent.x, currentExtent.y); const auto newPixelData = stbir_resize_uint8_linear(pixelData.data(), currentExtent.x, currentExtent.y, currentExtent.x * 4, nullptr, newWidth, newHeight, newWidth * 4, stbir_pixel_layout::STBIR_RGBA); const auto texture = GPUResourceManager::CreateTexture(SDL_GPU_TEXTUREUSAGE_SAMPLER, newWidth, newHeight, newPixelData, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM); s_imageExtents[image] = (((UINT64) newWidth) << 32) | newHeight; GPUResourceManager::DestroyTexture(s_imageHandles[image]); s_imageHandles[image] = texture; free(newPixelData); return image; } Handle ResourceManager::CombineImages(IN CONST Vector &images, IN INT32 unitWidth, IN INT32 unitHeight, IN INT32 unitCountX, IN INT32 unitCountY) { const auto w = unitWidth * unitCountX; const auto h = unitHeight * unitCountY; Vector textures; for (const auto &t : images) textures.pushBack(s_imageHandles[t]); const auto texture = GPUResourceManager::CombineTextures(textures.data(), unitWidth, unitHeight, unitCountX, unitCountY); s_imageHandles.pushBack(texture); Handle handle = s_imageHandles.size() - 1; s_images[Engine::GetUniqueResourceName()] = handle; s_imageExtents[handle] = (((UINT64) w) << 32) | h; s_nonScaledImageExtents[handle] = s_imageExtents[handle]; return handle; } VOID ResourceManager::RescaleAllImages(IN FLOAT32 factorX, IN FLOAT32 factorY) { for (auto &t : s_images) { const auto p = s_nonScaledImageExtents[t->Value]; t->Value = ResizeImage(t->Value, ((INT32) (p >> 32)) * factorX, ((INT32) p) * factorY); } } } // 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); } Handle Engine::ResizeImage(IN Handle image, IN INT32 newWidth, IN INT32 newHeight) { return ResourceManager::ResizeImage(image, newWidth, newHeight); } VOID Engine::RescaleAllImages(IN FLOAT32 factorX, IN FLOAT32 factorY) { ResourceManager::RescaleAllImages(factorX, factorY); } Handle Engine::CombineImages(IN CONST Vector &images, IN INT32 unitWidth, IN INT32 unitHeight, IN INT32 unitCountX, IN INT32 unitCountY) { return ResourceManager::CombineImages(images, unitWidth, unitHeight, unitCountX, unitCountY); } } // namespace ia::iae