diff --git a/Samples/RPG/Src/imp/cpp/Game.cpp b/Samples/RPG/Src/imp/cpp/Game.cpp index 99ff8de..09312a4 100644 --- a/Samples/RPG/Src/imp/cpp/Game.cpp +++ b/Samples/RPG/Src/imp/cpp/Game.cpp @@ -29,12 +29,20 @@ namespace ia::iae::rpg return &EngineConfig; } + Handle g_playerSpriteSheet; + VOID OnInitialize() { + g_playerSpriteSheet = IAEngine::CreateSpriteSheet("Resources/Cute_Fantasy_Free/Player/Player.png", 32, 32, + {6, 6, 6, 6, 6, 6, 4, 4, 4, 4}); + + IAEngine::LoadResources({g_playerSpriteSheet}); } VOID OnTerminate() { + + IAEngine::DestroyResource(g_playerSpriteSheet); } VOID OnDebugDraw() @@ -47,6 +55,7 @@ namespace ia::iae::rpg VOID OnUpdate(IN FLOAT32 deltaTime) { + IAEngine::DrawSprite(g_playerSpriteSheet, 0, 0, {100.0f, 100.0f}); } VOID OnResize(IN INT32 newWidth, IN INT32 newHeight) diff --git a/Src/IAEngine/imp/cpp/IAEngine.cpp b/Src/IAEngine/imp/cpp/IAEngine.cpp index 120f113..30dc5a3 100644 --- a/Src/IAEngine/imp/cpp/IAEngine.cpp +++ b/Src/IAEngine/imp/cpp/IAEngine.cpp @@ -21,6 +21,35 @@ #define STB_IMAGE_IMPLEMENTATION #include +namespace ia::iae +{ + struct Resource + { + enum class EType + { + INVALID, + + TEXTURE, + SPRITE_SHEET, + SOUND + }; + + EType Type{EType::INVALID}; + }; + + struct Resource_Texture : public Resource + { + Handle Texture; + }; + + struct Resource_SpriteSheet : public Resource_Texture + { + Vector FrameCounts; + }; + + Vector g_resources; +} // namespace ia::iae + namespace ia::iae { String g_gameName; @@ -98,38 +127,26 @@ namespace ia::iae namespace ia::iae { - Handle CreateTexture(IN PCCHAR path, IN INT32 tileWidth = -1, IN INT32 tileHeight = -1) - { - INT32 w, h, n; - auto pixels = stbi_load(path, &w, &h, &n, STBI_rgb_alpha); - const auto t = Renderer::CreateTexture(pixels, w, h, tileWidth == -1 ? 1 : w/tileWidth, tileHeight == -1 ? 1 : h/tileHeight); - stbi_image_free(pixels); - return t; - } - - Handle textures[5]; - VOID IAEngine::Initialize() { Renderer::Initialize(IVec2{g_designViewport.x, g_designViewport.y}); - textures[0] = CreateTexture("Resources/Cute_Fantasy_Free/Tiles/Beach_Tile.png", 16, 16); - textures[1] = CreateTexture("Resources/Cute_Fantasy_Free/Tiles/Cliff_Tile.png", 16, 16); - - Renderer::SetTextureAtlas({textures[0], textures[1]}); + Game_OnInitialize(); } VOID IAEngine::Terminate() { + Game_OnTerminate(); + Renderer::Terminate(); + + for (SIZE_T i = 0; i < g_resources.size(); i++) + DestroyResource(i); } VOID IAEngine::Update() { - Renderer::DrawStaticSpriteTopLeft(textures[1], 0, {0.0f, 0.0f}, {1.0f, 1.0f}, 0.0f); - Renderer::DrawStaticSpriteTopLeft(textures[1], 1, {16.0f, 0.0f}, {1.0f, 1.0f}, 0.0f); - Renderer::DrawStaticSpriteTopLeft(textures[1], 2, {32.0f, 0.0f}, {1.0f, 1.0f}, 0.0f); - + Game_OnUpdate(0.0f); Renderer::Update(); } @@ -138,3 +155,139 @@ namespace ia::iae const auto event = (SDL_Event *) _event; } } // namespace ia::iae + +namespace ia::iae +{ + Handle CreateTextureFromFile(IN PCCHAR path, IN INT32 tileWidth = -1, IN INT32 tileHeight = -1) + { + INT32 w, h, n; + auto pixels = stbi_load(path, &w, &h, &n, STBI_rgb_alpha); + const auto t = Renderer::CreateTexture(pixels, w, h, tileWidth == -1 ? 1 : w / tileWidth, + tileHeight == -1 ? 1 : h / tileHeight); + stbi_image_free(pixels); + return t; + } + + Handle IAEngine::CreateSprite(IN CONST String &path) + { + const auto t = new Resource_Texture(); + t->Type = Resource::EType::TEXTURE; + t->Texture = CreateTextureFromFile(path.c_str()); + g_resources.pushBack(t); + return (Handle)g_resources.size() - 1; + } + + Handle IAEngine::CreateSprite(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height) + { + const auto t = new Resource_Texture(); + t->Type = Resource::EType::TEXTURE; + t->Texture = Renderer::CreateTexture(rgbaData, width, height); + g_resources.pushBack(t); + return (Handle)g_resources.size() - 1; + } + + Handle IAEngine::CreateSpriteSheet(IN CONST Vector> &animations) + { + THROW_NOT_IMPLEMENTED(); + return INVALID_HANDLE; + } + + Handle IAEngine::CreateSpriteSheet(IN CONST String &path, IN INT32 spriteWidth, IN INT32 spriteHeight, + IN CONST Vector &frameCounts) + { + const auto t = new Resource_SpriteSheet(); + t->Type = Resource::EType::SPRITE_SHEET; + t->FrameCounts = frameCounts; + t->Texture = CreateTextureFromFile(path.c_str(), spriteWidth, spriteHeight); + g_resources.pushBack(t); + return (Handle)g_resources.size() - 1; + } + + Handle IAEngine::CreateTileSheet(IN CONST String &path, IN INT32 tileWidth, IN INT32 tileHeight) + { + const auto t = new Resource_Texture(); + t->Type = Resource::EType::TEXTURE; + t->Texture = CreateTextureFromFile(path.c_str(), tileWidth, tileHeight); + g_resources.pushBack(t); + return (Handle)g_resources.size() - 1; + } + + Handle IAEngine::CreateTileSheet(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height, IN INT32 tileWidth, + IN INT32 tileHeight) + { + const auto t = new Resource_Texture(); + t->Type = Resource::EType::TEXTURE; + t->Texture = Renderer::CreateTexture(rgbaData, width, height, width / tileWidth, height / tileHeight); + g_resources.pushBack(t); + return (Handle)g_resources.size() - 1; + } + + VOID IAEngine::DestroyResource(IN Handle resource) + { + if(!g_resources[resource]) return; + + switch (g_resources[resource]->Type) + { + case Resource::EType::INVALID: + break; + + case Resource::EType::TEXTURE: + case Resource::EType::SPRITE_SHEET: + Renderer::DestroyTexture(static_cast(g_resources[resource])->Texture); + break; + + case Resource::EType::SOUND: + break; + } + delete g_resources[resource]; + g_resources[resource] = nullptr; + } + + VOID IAEngine::LoadResources(IN CONST Vector &resources) + { + Vector atlasTextures; + + for (const auto &handle : resources) + { + switch (g_resources[handle]->Type) + { + case Resource::EType::INVALID: + break; + + case Resource::EType::TEXTURE: + case Resource::EType::SPRITE_SHEET: + atlasTextures.pushBack(static_cast(g_resources[handle])->Texture); + break; + + case Resource::EType::SOUND: + break; + } + } + + Renderer::BakeTextureAtlas(atlasTextures); + } +} // namespace ia::iae + +namespace ia::iae +{ + VOID IAEngine::DrawTile(IN Handle tileSheet, IN INT32 tileIndexX, IN INT32 tileIndexY, IN Vec2 position, + IN Vec2 scale, IN FLOAT32 rotation, IN BOOL flipH, IN BOOL flipV, IN Vec2 uvOffset) + { + const auto t = static_cast(g_resources[tileSheet]); + Renderer::DrawStaticSpriteTopLeft(t->Texture, tileIndexX, tileIndexY, position, scale, rotation, flipH, flipV, uvOffset); + } + + VOID IAEngine::DrawSprite(IN Handle sprite, IN Vec2 position, IN Vec2 scale, IN FLOAT32 rotation, IN BOOL flipH, + IN BOOL flipV, IN Vec2 uvOffset) + { + const auto t = static_cast(g_resources[sprite]); + Renderer::DrawDynamicSpriteTopLeft(t->Texture, 0, 0, position, scale, rotation, flipH, flipV, uvOffset); + } + + VOID IAEngine::DrawSprite(IN Handle spriteSheet, IN INT32 animationIndex, IN INT32 frameIndex, IN Vec2 position, + IN Vec2 scale, IN FLOAT32 rotation, IN BOOL flipH, IN BOOL flipV, IN Vec2 uvOffset) + { + const auto t = static_cast(g_resources[spriteSheet]); + Renderer::DrawDynamicSpriteTopLeft(t->Texture, animationIndex, frameIndex, position, scale, rotation, flipH, flipV, uvOffset); + } +} // namespace ia::iae \ No newline at end of file diff --git a/Src/IAEngine/imp/cpp/Renderer.cpp b/Src/IAEngine/imp/cpp/Renderer.cpp index 8db7f16..153f88c 100644 --- a/Src/IAEngine/imp/cpp/Renderer.cpp +++ b/Src/IAEngine/imp/cpp/Renderer.cpp @@ -204,26 +204,58 @@ namespace ia::iae namespace ia::iae { - VOID Renderer::DrawStaticSpriteTopLeft(IN Handle texture, IN INT32 tileIndex, IN Vec2 position, IN Vec2 scale, - IN FLOAT32 rotation) + Vec2 Renderer::DrawStaticSpriteTopLeft(IN Handle texture, IN INT32 tileIndexX, IN INT32 tileIndexY, + IN Vec2 position, IN Vec2 scale, IN FLOAT32 rotation, IN BOOL flipH, IN BOOL flipV, IN Vec2 uvOffset) { + const auto _s = Vec2{scale.x * g_texureData[texture].TileWidth, scale.y * g_texureData[texture].TileHeight}; Mat4 transform = glm::translate(glm::mat4(1.0f), glm::vec3{position.x, position.y, 0}); transform = glm::rotate(transform, rotation, glm::vec3(0.0f, 0.0f, 1.0f)); - transform = glm::scale(transform, glm::vec3{scale.x * g_texureData[texture].TileWidth, scale.y * g_texureData[texture].TileHeight, 1.0f}); + transform = glm::scale(transform, glm::vec3(_s, 1.0f)); g_staticSprites.pushBack({.Transform = transform, - .TexCoords = GetTextureAtlasCoordinates(texture, tileIndex), + .TexCoords = GetTextureAtlasCoordinates(texture, tileIndexX, tileIndexY, flipH, flipV, uvOffset), .Color = {1.0f, 1.0f, 1.0f, 1.0f}}); + return _s; } - VOID Renderer::DrawDynamicSpriteTopLeft(IN Handle texture, IN INT32 tileIndex, IN Vec2 position, IN Vec2 scale, - IN FLOAT32 rotation) + Vec2 Renderer::DrawStaticSpriteCentered(IN Handle texture, IN INT32 tileIndexX, IN INT32 tileIndexY, + IN Vec2 position, IN Vec2 scale, IN FLOAT32 rotation, IN BOOL flipH, IN BOOL flipV, IN Vec2 uvOffset) { + const auto _s = Vec2{scale.x * g_texureData[texture].TileWidth, scale.y * g_texureData[texture].TileHeight}; + Mat4 transform = + glm::translate(glm::mat4(1.0f), glm::vec3{position.x - _s.x / 2.0f, position.y - _s.y / 2.0f, 0}); + transform = glm::rotate(transform, rotation, glm::vec3(0.0f, 0.0f, 1.0f)); + transform = glm::scale(transform, glm::vec3(_s, 1.0f)); + g_staticSprites.pushBack({.Transform = transform, + .TexCoords = GetTextureAtlasCoordinates(texture, tileIndexX, tileIndexY, flipH, flipV, uvOffset), + .Color = {1.0f, 1.0f, 1.0f, 1.0f}}); + return _s; + } + + Vec2 Renderer::DrawDynamicSpriteTopLeft(IN Handle texture, IN INT32 tileIndexX, IN INT32 tileIndexY, + IN Vec2 position, IN Vec2 scale, IN FLOAT32 rotation, IN BOOL flipH, IN BOOL flipV, IN Vec2 uvOffset) + { + const auto _s = Vec2{scale.x * g_texureData[texture].TileWidth, scale.y * g_texureData[texture].TileHeight}; Mat4 transform = glm::translate(glm::mat4(1.0f), glm::vec3{position.x, position.y, 0}); transform = glm::rotate(transform, rotation, glm::vec3(0.0f, 0.0f, 1.0f)); - transform = glm::scale(transform, glm::vec3{scale.x * g_texureData[texture].TileWidth, scale.y * g_texureData[texture].TileHeight, 1.0f}); + transform = glm::scale(transform, glm::vec3{_s, 1.0f}); g_dynamicSprites.pushBack({.Transform = transform, - .TexCoords = GetTextureAtlasCoordinates(texture, tileIndex), + .TexCoords = GetTextureAtlasCoordinates(texture, tileIndexX, tileIndexY, flipH, flipV, uvOffset), .Color = {1.0f, 1.0f, 1.0f, 1.0f}}); + return _s; + } + + Vec2 Renderer::DrawDynamicSpriteCentered(IN Handle texture, IN INT32 tileIndexX, IN INT32 tileIndexY, + IN Vec2 position, IN Vec2 scale, IN FLOAT32 rotation, IN BOOL flipH, IN BOOL flipV, IN Vec2 uvOffset) + { + const auto _s = Vec2{scale.x * g_texureData[texture].TileWidth, scale.y * g_texureData[texture].TileHeight}; + Mat4 transform = + glm::translate(glm::mat4(1.0f), glm::vec3{position.x - _s.x / 2.0f, position.y - _s.y / 2.0f, 0}); + transform = glm::rotate(transform, rotation, glm::vec3(0.0f, 0.0f, 1.0f)); + transform = glm::scale(transform, glm::vec3{_s, 1.0f}); + g_dynamicSprites.pushBack({.Transform = transform, + .TexCoords = GetTextureAtlasCoordinates(texture, tileIndexX, tileIndexY, flipH, flipV, uvOffset), + .Color = {1.0f, 1.0f, 1.0f, 1.0f}}); + return _s; } Geometry *Renderer::CreateGeometry(IN CONST Vector &vertices, IN CONST Vector &indices) @@ -284,7 +316,7 @@ namespace ia::iae t.Height, t.Width, t.Pixels); } - VOID Renderer::SetTextureAtlas(IN CONST Vector textures) + VOID Renderer::BakeTextureAtlas(IN CONST Vector textures) { if (g_activeTextureAtlas && (g_activeTextureAtlas != g_defaultTexture)) DestroyTexture(g_activeTextureAtlas); @@ -320,14 +352,12 @@ namespace ia::iae delete[] pixels; } - Vec4 Renderer::GetTextureAtlasCoordinates(IN Handle texture, IN INT32 tileIndex) + Vec4 Renderer::GetTextureAtlasCoordinates(IN Handle texture, IN INT32 tileIndexX, IN INT32 tileIndexY, IN BOOL flipH, IN BOOL flipV, IN Vec2 uvOffset) { const auto &d = g_texureData[texture]; const auto &t = g_activeTextureAtlasUVMap[texture]; - const auto pX = - ((INT32) (tileIndex % d.TileCountX) * ((FLOAT32) d.TileWidth)) * g_activeTextureAtlasInverseSize.x; - const auto pY = - ((INT32) (tileIndex / d.TileCountX) * ((FLOAT32) d.TileHeight)) * g_activeTextureAtlasInverseSize.y; + const auto pX = (tileIndexX * ((FLOAT32) d.TileWidth)) * g_activeTextureAtlasInverseSize.x; + const auto pY = (tileIndexY * ((FLOAT32) d.TileHeight)) * g_activeTextureAtlasInverseSize.y; return Vec4(t.x + pX, t.y + pY, d.TileWidth * g_activeTextureAtlasInverseSize.x, d.TileHeight * g_activeTextureAtlasInverseSize.y); } diff --git a/Src/IAEngine/imp/hpp/Renderer.hpp b/Src/IAEngine/imp/hpp/Renderer.hpp index a21e334..41854cd 100644 --- a/Src/IAEngine/imp/hpp/Renderer.hpp +++ b/Src/IAEngine/imp/hpp/Renderer.hpp @@ -66,23 +66,26 @@ namespace ia::iae STATIC VOID SetCameraPosition(IN Vec2 position); public: - STATIC VOID DrawStaticSpriteTopLeft(IN Handle texture, IN INT32 tileIndex, IN Vec2 position, IN Vec2 scale, IN FLOAT32 rotation); - STATIC INLINE VOID DrawStaticSpriteCentered(IN Handle texture, IN INT32 tileIndex, IN Vec2 position, IN Vec2 scale, - IN FLOAT32 rotation); + STATIC Vec2 DrawStaticSpriteTopLeft(IN Handle texture, IN INT32 tileIndexX, IN INT32 tileIndexY, + IN Vec2 position, IN Vec2 scale, IN FLOAT32 rotation, IN BOOL flipH = false, IN BOOL flipV = false, IN Vec2 uvOffset = {}); + STATIC Vec2 DrawStaticSpriteCentered(IN Handle texture, IN INT32 tileIndexX, IN INT32 tileIndexY, + IN Vec2 position, IN Vec2 scale, IN FLOAT32 rotation, IN BOOL flipH = false, IN BOOL flipV = false, IN Vec2 uvOffset = {}); - STATIC VOID DrawDynamicSpriteTopLeft(IN Handle texture, IN INT32 tileIndex, IN Vec2 position, IN Vec2 scale, IN FLOAT32 rotation); - STATIC INLINE VOID DrawDynamicSpriteCentered(IN Handle texture, IN INT32 tileIndex, IN Vec2 position, IN Vec2 scale, - IN FLOAT32 rotation); + STATIC Vec2 DrawDynamicSpriteTopLeft(IN Handle texture, IN INT32 tileIndexX, IN INT32 tileIndexY, + IN Vec2 position, IN Vec2 scale, IN FLOAT32 rotation, IN BOOL flipH = false, IN BOOL flipV = false, IN Vec2 uvOffset = {}); + STATIC Vec2 DrawDynamicSpriteCentered(IN Handle texture, IN INT32 tileIndexX, IN INT32 tileIndexY, + IN Vec2 position, IN Vec2 scale, IN FLOAT32 rotation, IN BOOL flipH = false, IN BOOL flipV = false, IN Vec2 uvOffset = {}); STATIC VOID ResizeScreen(IN IVec2 newSize); public: - STATIC Handle CreateTexture(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height, IN INT32 tileCountX = 1, IN INT32 tileCountY = 1); + STATIC Handle CreateTexture(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height, IN INT32 tileCountX = 1, + IN INT32 tileCountY = 1); STATIC VOID DestroyTexture(IN Handle texture); STATIC VOID BakeTexture(IN Handle texture); - STATIC VOID SetTextureAtlas(IN CONST Vector textures); + STATIC VOID BakeTextureAtlas(IN CONST Vector textures); private: STATIC SDL_GPUTexture *CreateTexture(IN SDL_GPUTextureUsageFlags usage, IN INT32 width, IN INT32 height, @@ -115,7 +118,7 @@ namespace ia::iae STATIC VOID Render(); - STATIC Vec4 GetTextureAtlasCoordinates(IN Handle texture, IN INT32 tileIndex); + STATIC Vec4 GetTextureAtlasCoordinates(IN Handle texture, IN INT32 tileIndexX, IN INT32 tileIndexY, IN BOOL flipH, IN BOOL flipV, IN Vec2 uvOffset); private: STATIC VOID Initialize(IN IVec2 screenExtent); @@ -124,14 +127,4 @@ namespace ia::iae friend class IAEngine; }; - - VOID Renderer::DrawStaticSpriteCentered(IN Handle texture,IN INT32 tileIndex, IN Vec2 position, IN Vec2 scale, IN FLOAT32 rotation) - { - DrawStaticSpriteTopLeft(texture, tileIndex, position - scale / 2.0f, scale, rotation); - } - - VOID Renderer::DrawDynamicSpriteCentered(IN Handle texture,IN INT32 tileIndex, IN Vec2 position, IN Vec2 scale, IN FLOAT32 rotation) - { - DrawDynamicSpriteTopLeft(texture, tileIndex, position - scale / 2.0f, scale, rotation); - } } // namespace ia::iae diff --git a/Src/IAEngine/inc/IAEngine/IAEngine.hpp b/Src/IAEngine/inc/IAEngine/IAEngine.hpp index e6aa8bc..a512f72 100644 --- a/Src/IAEngine/inc/IAEngine/IAEngine.hpp +++ b/Src/IAEngine/inc/IAEngine/IAEngine.hpp @@ -22,15 +22,40 @@ namespace ia::iae { class IAEngine { - public: + public: + STATIC Handle CreateSprite(IN CONST String &path); + STATIC Handle CreateSprite(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height); - private: + STATIC Handle CreateSpriteSheet(IN CONST Vector> &animations); + STATIC Handle CreateSpriteSheet(IN CONST String &path, IN INT32 spriteWidth, IN INT32 spriteHeight, + IN CONST Vector &frameCounts); + + STATIC Handle CreateTileSheet(IN CONST String &path, IN INT32 tileWidth, IN INT32 tileHeight); + STATIC Handle CreateTileSheet(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height, IN INT32 tileWidth, + IN INT32 tileHeight); + + STATIC VOID DestroyResource(IN Handle resource); + + STATIC VOID LoadResources(IN CONST Vector &resources); + + public: + STATIC VOID DrawTile(IN Handle tileSheet, IN INT32 tileIndexX, IN INT32 tileIndexY, IN Vec2 position, + IN Vec2 scale = {1.0f, 1.0f}, IN FLOAT32 rotation = 0.0f, IN BOOL flipH = false, + IN BOOL flipV = false, IN Vec2 uvOffset = {}); + + STATIC VOID DrawSprite(IN Handle sprite, IN Vec2 position, IN Vec2 scale = {1.0f, 1.0f}, + IN FLOAT32 rotation = 0.0f, IN BOOL flipH = false, IN BOOL flipV = false, IN Vec2 uvOffset = {}); + STATIC VOID DrawSprite(IN Handle spriteSheet, IN INT32 animationIndex, IN INT32 frameIndex, IN Vec2 position, + IN Vec2 scale = {1.0f, 1.0f}, IN FLOAT32 rotation = 0.0f, IN BOOL flipH = false, + IN BOOL flipV = false, IN Vec2 uvOffset = {}); + + private: STATIC VOID Initialize(); STATIC VOID Terminate(); STATIC VOID Update(); STATIC VOID ProcessEvent(IN PVOID event); friend INT32 Run(IN CONST String &name, IN CONST String &packageName, IN CONST String &developerName, - IN CONST String &publisherName, IN IA_VERSION_TYPE version); + IN CONST String &publisherName, IN IA_VERSION_TYPE version); }; -} +} // namespace ia::iae