diff --git a/CMakeLists.txt b/CMakeLists.txt index 000fcb5..c6b1dc9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) # Homebrew: brew install sdl3 find_package(SDL3 CONFIG REQUIRED) find_package(SDL3_ttf CONFIG REQUIRED) +find_package(SDL3_image CONFIG REQUIRED) find_package(cpr CONFIG REQUIRED) find_package(nlohmann_json CONFIG REQUIRED) @@ -85,7 +86,7 @@ if (WIN32) ) endif() -target_link_libraries(tetris PRIVATE SDL3::SDL3 SDL3_ttf::SDL3_ttf cpr::cpr nlohmann_json::nlohmann_json) +target_link_libraries(tetris PRIVATE SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image cpr::cpr nlohmann_json::nlohmann_json) if (WIN32) target_link_libraries(tetris PRIVATE mfplat mfreadwrite mfuuid) @@ -160,7 +161,7 @@ if (WIN32) ) endif() -target_link_libraries(tetris_refactored PRIVATE SDL3::SDL3 SDL3_ttf::SDL3_ttf cpr::cpr nlohmann_json::nlohmann_json) +target_link_libraries(tetris_refactored PRIVATE SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image cpr::cpr nlohmann_json::nlohmann_json) if (WIN32) target_link_libraries(tetris_refactored PRIVATE mfplat mfreadwrite mfuuid) diff --git a/assets/images/background.bmp b/assets/images/background.bmp deleted file mode 100644 index 0274add..0000000 Binary files a/assets/images/background.bmp and /dev/null differ diff --git a/assets/images/gameplay1.bmp b/assets/images/gameplay1.bmp deleted file mode 100644 index 85162a1..0000000 Binary files a/assets/images/gameplay1.bmp and /dev/null differ diff --git a/assets/images/gameplay2.bmp b/assets/images/gameplay2.bmp deleted file mode 100644 index ed52e99..0000000 Binary files a/assets/images/gameplay2.bmp and /dev/null differ diff --git a/assets/images/gameplay3.bmp b/assets/images/gameplay3.bmp deleted file mode 100644 index 10ad47c..0000000 Binary files a/assets/images/gameplay3.bmp and /dev/null differ diff --git a/assets/images/main_background.bmp b/assets/images/main_background.bmp deleted file mode 100644 index 72ef709..0000000 Binary files a/assets/images/main_background.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level0.bmp b/assets/images/tetris_main_back_level0.bmp deleted file mode 100644 index 0274add..0000000 Binary files a/assets/images/tetris_main_back_level0.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level0x.bmp b/assets/images/tetris_main_back_level0x.bmp deleted file mode 100644 index 58ae7f9..0000000 Binary files a/assets/images/tetris_main_back_level0x.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level1.bmp b/assets/images/tetris_main_back_level1.bmp deleted file mode 100644 index 4f68b82..0000000 Binary files a/assets/images/tetris_main_back_level1.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level10.bmp b/assets/images/tetris_main_back_level10.bmp deleted file mode 100644 index 0ef0916..0000000 Binary files a/assets/images/tetris_main_back_level10.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level11.bmp b/assets/images/tetris_main_back_level11.bmp deleted file mode 100644 index 5edc3c9..0000000 Binary files a/assets/images/tetris_main_back_level11.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level12.bmp b/assets/images/tetris_main_back_level12.bmp deleted file mode 100644 index 610aff7..0000000 Binary files a/assets/images/tetris_main_back_level12.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level13.bmp b/assets/images/tetris_main_back_level13.bmp deleted file mode 100644 index 42c52f8..0000000 Binary files a/assets/images/tetris_main_back_level13.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level14.bmp b/assets/images/tetris_main_back_level14.bmp deleted file mode 100644 index 6a26df4..0000000 Binary files a/assets/images/tetris_main_back_level14.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level15.bmp b/assets/images/tetris_main_back_level15.bmp deleted file mode 100644 index d4759a3..0000000 Binary files a/assets/images/tetris_main_back_level15.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level16.bmp b/assets/images/tetris_main_back_level16.bmp deleted file mode 100644 index 68e6540..0000000 Binary files a/assets/images/tetris_main_back_level16.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level17.bmp b/assets/images/tetris_main_back_level17.bmp deleted file mode 100644 index 2e3aa72..0000000 Binary files a/assets/images/tetris_main_back_level17.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level18.bmp b/assets/images/tetris_main_back_level18.bmp deleted file mode 100644 index ac921ec..0000000 Binary files a/assets/images/tetris_main_back_level18.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level19.bmp b/assets/images/tetris_main_back_level19.bmp deleted file mode 100644 index 6d5f762..0000000 Binary files a/assets/images/tetris_main_back_level19.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level2.bmp b/assets/images/tetris_main_back_level2.bmp deleted file mode 100644 index 3632a65..0000000 Binary files a/assets/images/tetris_main_back_level2.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level20.bmp b/assets/images/tetris_main_back_level20.bmp deleted file mode 100644 index 26c88ff..0000000 Binary files a/assets/images/tetris_main_back_level20.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level21.bmp b/assets/images/tetris_main_back_level21.bmp deleted file mode 100644 index 8426613..0000000 Binary files a/assets/images/tetris_main_back_level21.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level22.bmp b/assets/images/tetris_main_back_level22.bmp deleted file mode 100644 index d835bbf..0000000 Binary files a/assets/images/tetris_main_back_level22.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level23.bmp b/assets/images/tetris_main_back_level23.bmp deleted file mode 100644 index 74fc4e5..0000000 Binary files a/assets/images/tetris_main_back_level23.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level24.bmp b/assets/images/tetris_main_back_level24.bmp deleted file mode 100644 index 9157494..0000000 Binary files a/assets/images/tetris_main_back_level24.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level25.bmp b/assets/images/tetris_main_back_level25.bmp deleted file mode 100644 index e30380b..0000000 Binary files a/assets/images/tetris_main_back_level25.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level26.bmp b/assets/images/tetris_main_back_level26.bmp deleted file mode 100644 index 7785436..0000000 Binary files a/assets/images/tetris_main_back_level26.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level27.bmp b/assets/images/tetris_main_back_level27.bmp deleted file mode 100644 index fda9b7e..0000000 Binary files a/assets/images/tetris_main_back_level27.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level28.bmp b/assets/images/tetris_main_back_level28.bmp deleted file mode 100644 index 5fa0311..0000000 Binary files a/assets/images/tetris_main_back_level28.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level29.bmp b/assets/images/tetris_main_back_level29.bmp deleted file mode 100644 index 1d114c3..0000000 Binary files a/assets/images/tetris_main_back_level29.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level3.bmp b/assets/images/tetris_main_back_level3.bmp deleted file mode 100644 index c1f4530..0000000 Binary files a/assets/images/tetris_main_back_level3.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level30.bmp b/assets/images/tetris_main_back_level30.bmp deleted file mode 100644 index b55b99c..0000000 Binary files a/assets/images/tetris_main_back_level30.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level31.bmp b/assets/images/tetris_main_back_level31.bmp deleted file mode 100644 index 796c424..0000000 Binary files a/assets/images/tetris_main_back_level31.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level32.bmp b/assets/images/tetris_main_back_level32.bmp deleted file mode 100644 index 65edfec..0000000 Binary files a/assets/images/tetris_main_back_level32.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level4.bmp b/assets/images/tetris_main_back_level4.bmp deleted file mode 100644 index a68f9ff..0000000 Binary files a/assets/images/tetris_main_back_level4.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level5.bmp b/assets/images/tetris_main_back_level5.bmp deleted file mode 100644 index d27d2d8..0000000 Binary files a/assets/images/tetris_main_back_level5.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level6.bmp b/assets/images/tetris_main_back_level6.bmp deleted file mode 100644 index ebaeca9..0000000 Binary files a/assets/images/tetris_main_back_level6.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level7.bmp b/assets/images/tetris_main_back_level7.bmp deleted file mode 100644 index f92d223..0000000 Binary files a/assets/images/tetris_main_back_level7.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level8.bmp b/assets/images/tetris_main_back_level8.bmp deleted file mode 100644 index 8f392c1..0000000 Binary files a/assets/images/tetris_main_back_level8.bmp and /dev/null differ diff --git a/assets/images/tetris_main_back_level9.bmp b/assets/images/tetris_main_back_level9.bmp deleted file mode 100644 index 2962513..0000000 Binary files a/assets/images/tetris_main_back_level9.bmp and /dev/null differ diff --git a/build-production.ps1 b/build-production.ps1 index 01d3f9b..25fc457 100644 --- a/build-production.ps1 +++ b/build-production.ps1 @@ -212,7 +212,7 @@ Tetris SDL3 Game - Release $Version ## Files Included - tetris.exe - Main game executable -- SDL3.dll, SDL3_ttf.dll - Required libraries +- SDL3.dll, SDL3_ttf.dll, SDL3_image.dll - Required libraries - assets/ - Game assets (images, music, fonts) - FreeSans.ttf - Main font file diff --git a/src/core/application/ApplicationManager.cpp b/src/core/application/ApplicationManager.cpp index d4a3120..d509779 100644 --- a/src/core/application/ApplicationManager.cpp +++ b/src/core/application/ApplicationManager.cpp @@ -26,7 +26,9 @@ #include "../../gameplay/core/Game.h" #include "../../gameplay/effects/LineEffect.h" #include +#include #include +#include "../../utils/ImagePathResolver.h" #include #include #include @@ -1044,17 +1046,20 @@ void ApplicationManager::setupStateHandlers() { if (m_cachedBgLevel != bgLevel) { if (m_nextLevelBackgroundTex) { SDL_DestroyTexture(m_nextLevelBackgroundTex); m_nextLevelBackgroundTex = nullptr; } char bgPath[256]; - std::snprintf(bgPath, sizeof(bgPath), "assets/images/tetris_main_back_level%d.bmp", bgLevel); - SDL_Surface* s = SDL_LoadBMP(bgPath); + std::snprintf(bgPath, sizeof(bgPath), "assets/images/tetris_main_back_level%d.jpg", bgLevel); + const std::string resolvedBgPath = AssetPath::resolveImagePath(bgPath); + SDL_Surface* s = IMG_Load(resolvedBgPath.c_str()); if (s && renderer.getSDLRenderer()) { m_nextLevelBackgroundTex = SDL_CreateTextureFromSurface(renderer.getSDLRenderer(), s); SDL_DestroySurface(s); m_levelFadeAlpha = 0.0f; m_levelFadeElapsed = 0.0f; m_cachedBgLevel = bgLevel; + if (resolvedBgPath != bgPath) { + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Loaded level %d background via %s", bgLevel, resolvedBgPath.c_str()); + } } else { - m_cachedBgLevel = -1; // don’t change if missing - m_cachedBgLevel = -1; // don't change if missing + m_cachedBgLevel = -1; // don't change if missing if (s) SDL_DestroySurface(s); } } diff --git a/src/core/assets/AssetManager.cpp b/src/core/assets/AssetManager.cpp index a5983c1..be7b210 100644 --- a/src/core/assets/AssetManager.cpp +++ b/src/core/assets/AssetManager.cpp @@ -3,8 +3,10 @@ #include "../../audio/Audio.h" #include "../../audio/SoundEffect.h" #include +#include #include #include +#include "../../utils/ImagePathResolver.h" AssetManager::AssetManager() : m_renderer(nullptr) @@ -379,19 +381,25 @@ SDL_Texture* AssetManager::loadTextureFromFile(const std::string& filepath) { return nullptr; } - // Load using SDL_LoadBMP (matching main.cpp pattern) - SDL_Surface* surface = SDL_LoadBMP(filepath.c_str()); - if (!surface) { - setError("Failed to load surface from: " + filepath + " - " + SDL_GetError()); + const std::string resolvedPath = AssetPath::resolveImagePath(filepath); + SDL_Texture* texture = IMG_LoadTexture(m_renderer, resolvedPath.c_str()); + if (!texture) { + std::string message = "Failed to load texture from: "; + message += filepath; + message += " (resolved: "; + message += resolvedPath; + message += ") - "; + message += SDL_GetError(); + setError(message); return nullptr; } - SDL_Texture* texture = SDL_CreateTextureFromSurface(m_renderer, surface); - SDL_DestroySurface(surface); - - if (!texture) { - setError("Failed to create texture from surface: " + filepath + " - " + SDL_GetError()); - return nullptr; + if (resolvedPath != filepath) { + std::string message = "Loaded alternative image path for "; + message += filepath; + message += ": "; + message += resolvedPath; + logInfo(message); } return texture; diff --git a/src/main.cpp b/src/main.cpp index ebb3069..3b20749 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -30,6 +31,7 @@ #include "states/LevelSelectorState.h" #include "states/PlayingState.h" #include "audio/MenuWrappers.h" +#include "utils/ImagePathResolver.h" #include "graphics/renderers/GameRenderer.h" // Debug logging removed: no-op in this build (previously LOG_DEBUG) @@ -74,6 +76,36 @@ static void drawRect(SDL_Renderer *r, float x, float y, float w, float h, SDL_Co SDL_RenderFillRect(r, &fr); } +static SDL_Texture* loadTextureFromImage(SDL_Renderer* renderer, const std::string& path, int* outW = nullptr, int* outH = nullptr) { + if (!renderer) { + return nullptr; + } + + const std::string resolvedPath = AssetPath::resolveImagePath(path); + SDL_Surface* surface = IMG_Load(resolvedPath.c_str()); + if (!surface) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load image %s (resolved: %s): %s", path.c_str(), resolvedPath.c_str(), SDL_GetError()); + return nullptr; + } + + if (outW) { *outW = surface->w; } + if (outH) { *outH = surface->h; } + + SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface); + SDL_DestroySurface(surface); + + if (!texture) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create texture from %s: %s", resolvedPath.c_str(), SDL_GetError()); + return nullptr; + } + + if (resolvedPath != path) { + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Loaded %s via %s", path.c_str(), resolvedPath.c_str()); + } + + return texture; +} + // Hover state for level popup ( -1 = none, 0..19 = hovered level ) // Now managed by LevelSelectorState @@ -455,41 +487,15 @@ int main(int, char **) LineEffect lineEffect; lineEffect.init(renderer); - // Load logo using native SDL BMP loading - SDL_Texture *logoTex = nullptr; - SDL_Surface* logoSurface = SDL_LoadBMP("assets/images/logo.bmp"); - if (logoSurface) { - (void)0; - logoTex = SDL_CreateTextureFromSurface(renderer, logoSurface); - SDL_DestroySurface(logoSurface); - } else { - (void)0; - } + // Load logo assets via SDL_image so we can use compressed formats + SDL_Texture* logoTex = loadTextureFromImage(renderer, "assets/images/logo.bmp"); + // Load small logo (used by Menu to show whole logo) - SDL_Texture *logoSmallTex = nullptr; - SDL_Surface* logoSmallSurface = SDL_LoadBMP("assets/images/logo_small.bmp"); int logoSmallW = 0, logoSmallH = 0; - if (logoSmallSurface) { - // capture surface size before creating the texture (avoids SDL_QueryTexture) - logoSmallW = logoSmallSurface->w; - logoSmallH = logoSmallSurface->h; - logoSmallTex = SDL_CreateTextureFromSurface(renderer, logoSmallSurface); - SDL_DestroySurface(logoSmallSurface); - } else { - // fallback: leave logoSmallTex null so MenuState will use large logo - (void)0; - } + SDL_Texture* logoSmallTex = loadTextureFromImage(renderer, "assets/images/logo_small.bmp", &logoSmallW, &logoSmallH); - // Load background using native SDL BMP loading - SDL_Texture *backgroundTex = nullptr; - SDL_Surface* backgroundSurface = SDL_LoadBMP("assets/images/main_background.bmp"); - if (backgroundSurface) { - (void)0; - backgroundTex = SDL_CreateTextureFromSurface(renderer, backgroundSurface); - SDL_DestroySurface(backgroundSurface); - } else { - (void)0; - } + // Load menu background using SDL_image (prefers JPEG) + SDL_Texture* backgroundTex = loadTextureFromImage(renderer, "assets/images/main_background.bmp"); // Note: `backgroundTex` is owned by main and passed into `StateContext::backgroundTex` below. // States should render using `ctx.backgroundTex` rather than accessing globals. @@ -505,16 +511,8 @@ int main(int, char **) // Default start level selection: 0 (declare here so it's in scope for all handlers) int startLevelSelection = 0; - // Load blocks texture using native SDL BMP loading - SDL_Texture *blocksTex = nullptr; - SDL_Surface* blocksSurface = SDL_LoadBMP("assets/images/blocks90px_001.bmp"); - if (blocksSurface) { - (void)0; - blocksTex = SDL_CreateTextureFromSurface(renderer, blocksSurface); - SDL_DestroySurface(blocksSurface); - } else { - (void)0; - } + // Load blocks texture via SDL_image (falls back to procedural blocks if missing) + SDL_Texture* blocksTex = loadTextureFromImage(renderer, "assets/images/blocks90px_001.bmp"); // No global exposure of blocksTex; states receive textures via StateContext. if (!blocksTex) { @@ -1287,18 +1285,17 @@ int main(int, char **) // Load new level background into nextLevelBackgroundTex if (nextLevelBackgroundTex) { SDL_DestroyTexture(nextLevelBackgroundTex); nextLevelBackgroundTex = nullptr; } char bgPath[256]; - snprintf(bgPath, sizeof(bgPath), "assets/images/tetris_main_back_level%d.bmp", bgLevel); - SDL_Surface* levelBgSurface = SDL_LoadBMP(bgPath); - if (levelBgSurface) { + snprintf(bgPath, sizeof(bgPath), "assets/images/tetris_main_back_level%d.jpg", bgLevel); + SDL_Texture* newLevelTex = loadTextureFromImage(renderer, bgPath); + if (newLevelTex) { SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Loaded background for level %d: %s", bgLevel, bgPath); - nextLevelBackgroundTex = SDL_CreateTextureFromSurface(renderer, levelBgSurface); - SDL_DestroySurface(levelBgSurface); + nextLevelBackgroundTex = newLevelTex; // start fade transition levelFadeAlpha = 0.0f; levelFadeElapsed = 0.0f; cachedLevel = bgLevel; } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load background for level %d: %s (Error: %s)", bgLevel, bgPath, SDL_GetError()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load background for level %d: %s", bgLevel, bgPath); // don't change textures if file missing cachedLevel = -1; } @@ -1651,10 +1648,14 @@ int main(int, char **) SDL_DestroyTexture(logoTex); if (backgroundTex) SDL_DestroyTexture(backgroundTex); + if (nextLevelBackgroundTex) + SDL_DestroyTexture(nextLevelBackgroundTex); if (levelBackgroundTex) SDL_DestroyTexture(levelBackgroundTex); if (blocksTex) SDL_DestroyTexture(blocksTex); + if (logoSmallTex) + SDL_DestroyTexture(logoSmallTex); lineEffect.shutdown(); Audio::instance().shutdown(); SoundEffectManager::instance().shutdown(); diff --git a/src/main_dist.cpp b/src/main_dist.cpp index 7cfebfc..8391149 100644 --- a/src/main_dist.cpp +++ b/src/main_dist.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -30,6 +31,7 @@ #include "states/LevelSelectorState.h" #include "states/PlayingState.h" #include "audio/MenuWrappers.h" +#include "utils/ImagePathResolver.h" // Debug logging removed: no-op in this build (previously LOG_DEBUG) @@ -73,6 +75,36 @@ static void drawRect(SDL_Renderer *r, float x, float y, float w, float h, SDL_Co SDL_RenderFillRect(r, &fr); } +static SDL_Texture* loadTextureFromImage(SDL_Renderer* renderer, const std::string& path, int* outW = nullptr, int* outH = nullptr) { + if (!renderer) { + return nullptr; + } + + const std::string resolvedPath = AssetPath::resolveImagePath(path); + SDL_Surface* surface = IMG_Load(resolvedPath.c_str()); + if (!surface) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load image %s (resolved: %s): %s", path.c_str(), resolvedPath.c_str(), SDL_GetError()); + return nullptr; + } + + if (outW) { *outW = surface->w; } + if (outH) { *outH = surface->h; } + + SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface); + SDL_DestroySurface(surface); + + if (!texture) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create texture from %s: %s", resolvedPath.c_str(), SDL_GetError()); + return nullptr; + } + + if (resolvedPath != path) { + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Loaded %s via %s", path.c_str(), resolvedPath.c_str()); + } + + return texture; +} + // Hover state for level popup ( -1 = none, 0..19 = hovered level ) // Now managed by LevelSelectorState @@ -450,41 +482,14 @@ int main(int, char **) LineEffect lineEffect; lineEffect.init(renderer); - // Load logo using native SDL BMP loading - SDL_Texture *logoTex = nullptr; - SDL_Surface* logoSurface = SDL_LoadBMP("assets/images/logo.bmp"); - if (logoSurface) { - (void)0; - logoTex = SDL_CreateTextureFromSurface(renderer, logoSurface); - SDL_DestroySurface(logoSurface); - } else { - (void)0; - } + // Load logo assets via SDL_image so we can use compressed formats + SDL_Texture* logoTex = loadTextureFromImage(renderer, "assets/images/logo.bmp"); // Load small logo (used by Menu to show whole logo) - SDL_Texture *logoSmallTex = nullptr; - SDL_Surface* logoSmallSurface = SDL_LoadBMP("assets/images/logo_small.bmp"); int logoSmallW = 0, logoSmallH = 0; - if (logoSmallSurface) { - // capture surface size before creating the texture (avoids SDL_QueryTexture) - logoSmallW = logoSmallSurface->w; - logoSmallH = logoSmallSurface->h; - logoSmallTex = SDL_CreateTextureFromSurface(renderer, logoSmallSurface); - SDL_DestroySurface(logoSmallSurface); - } else { - // fallback: leave logoSmallTex null so MenuState will use large logo - (void)0; - } + SDL_Texture* logoSmallTex = loadTextureFromImage(renderer, "assets/images/logo_small.bmp", &logoSmallW, &logoSmallH); - // Load background using native SDL BMP loading - SDL_Texture *backgroundTex = nullptr; - SDL_Surface* backgroundSurface = SDL_LoadBMP("assets/images/main_background.bmp"); - if (backgroundSurface) { - (void)0; - backgroundTex = SDL_CreateTextureFromSurface(renderer, backgroundSurface); - SDL_DestroySurface(backgroundSurface); - } else { - (void)0; - } + // Load background using SDL_image (prefers JPEG) + SDL_Texture* backgroundTex = loadTextureFromImage(renderer, "assets/images/main_background.bmp"); // Note: `backgroundTex` is owned by main and passed into `StateContext::backgroundTex` below. // States should render using `ctx.backgroundTex` rather than accessing globals. @@ -500,16 +505,8 @@ int main(int, char **) // Default start level selection: 0 (declare here so it's in scope for all handlers) int startLevelSelection = 0; - // Load blocks texture using native SDL BMP loading - SDL_Texture *blocksTex = nullptr; - SDL_Surface* blocksSurface = SDL_LoadBMP("assets/images/blocks90px_001.bmp"); - if (blocksSurface) { - (void)0; - blocksTex = SDL_CreateTextureFromSurface(renderer, blocksSurface); - SDL_DestroySurface(blocksSurface); - } else { - (void)0; - } + // Load blocks texture using SDL_image (falls back to procedural blocks if necessary) + SDL_Texture* blocksTex = loadTextureFromImage(renderer, "assets/images/blocks90px_001.bmp"); // No global exposure of blocksTex; states receive textures via StateContext. if (!blocksTex) { @@ -1136,11 +1133,10 @@ int main(int, char **) // Load new level background into nextLevelBackgroundTex if (nextLevelBackgroundTex) { SDL_DestroyTexture(nextLevelBackgroundTex); nextLevelBackgroundTex = nullptr; } char bgPath[256]; - snprintf(bgPath, sizeof(bgPath), "assets/images/tetris_main_back_level%d.bmp", bgLevel); - SDL_Surface* levelBgSurface = SDL_LoadBMP(bgPath); - if (levelBgSurface) { - nextLevelBackgroundTex = SDL_CreateTextureFromSurface(renderer, levelBgSurface); - SDL_DestroySurface(levelBgSurface); + snprintf(bgPath, sizeof(bgPath), "assets/images/tetris_main_back_level%d.jpg", bgLevel); + SDL_Texture* newLevelTex = loadTextureFromImage(renderer, bgPath); + if (newLevelTex) { + nextLevelBackgroundTex = newLevelTex; // start fade transition levelFadeAlpha = 0.0f; levelFadeElapsed = 0.0f; @@ -1718,10 +1714,14 @@ int main(int, char **) SDL_DestroyTexture(logoTex); if (backgroundTex) SDL_DestroyTexture(backgroundTex); + if (nextLevelBackgroundTex) + SDL_DestroyTexture(nextLevelBackgroundTex); if (levelBackgroundTex) SDL_DestroyTexture(levelBackgroundTex); if (blocksTex) SDL_DestroyTexture(blocksTex); + if (logoSmallTex) + SDL_DestroyTexture(logoSmallTex); lineEffect.shutdown(); Audio::instance().shutdown(); SoundEffectManager::instance().shutdown(); diff --git a/src/utils/ImagePathResolver.h b/src/utils/ImagePathResolver.h new file mode 100644 index 0000000..5fc442b --- /dev/null +++ b/src/utils/ImagePathResolver.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include + +#include + +namespace AssetPath { + +inline bool fileExists(const std::string& path) { + if (path.empty()) { + return false; + } + + SDL_IOStream* file = SDL_IOFromFile(path.c_str(), "rb"); + if (file) { + SDL_CloseIO(file); + return true; + } + return false; +} + +inline std::string resolveImagePath(const std::string& originalPath) { + if (originalPath.empty()) { + return originalPath; + } + + if (fileExists(originalPath)) { + return originalPath; + } + + const std::size_t dot = originalPath.find_last_of('.'); + const std::string base = (dot == std::string::npos) ? originalPath : originalPath.substr(0, dot); + + static constexpr std::array preferredExtensions{ + ".jpg", + ".jpeg", + ".png", + ".webp", + ".bmp" + }; + + for (const char* ext : preferredExtensions) { + std::string candidate = base + ext; + if (candidate == originalPath) { + continue; + } + if (fileExists(candidate)) { + return candidate; + } + } + + return originalPath; +} + +} // namespace AssetPath diff --git a/vcpkg.json b/vcpkg.json index 255341f..7116b91 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -2,6 +2,10 @@ "dependencies": [ "sdl3", "sdl3-ttf", + { + "name": "sdl3-image", + "features": ["jpeg", "png", "webp"] + }, "catch2", "cpr", "nlohmann-json"