refactored some functions from main.cpp
This commit is contained in:
@ -57,6 +57,7 @@ set(TETRIS_SOURCES
|
|||||||
src/app/BackgroundManager.cpp
|
src/app/BackgroundManager.cpp
|
||||||
src/app/Fireworks.cpp
|
src/app/Fireworks.cpp
|
||||||
src/app/AssetLoader.cpp
|
src/app/AssetLoader.cpp
|
||||||
|
src/app/TextureLoader.cpp
|
||||||
src/states/LoadingManager.cpp
|
src/states/LoadingManager.cpp
|
||||||
# State implementations (new)
|
# State implementations (new)
|
||||||
src/states/LoadingState.cpp
|
src/states/LoadingState.cpp
|
||||||
|
|||||||
91
src/app/TextureLoader.cpp
Normal file
91
src/app/TextureLoader.cpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#include "app/TextureLoader.h"
|
||||||
|
|
||||||
|
#include <SDL3_image/SDL_image.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <mutex>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "utils/ImagePathResolver.h"
|
||||||
|
|
||||||
|
TextureLoader::TextureLoader(
|
||||||
|
std::atomic<int>& loadedTasks,
|
||||||
|
std::string& currentLoadingFile,
|
||||||
|
std::mutex& currentLoadingMutex,
|
||||||
|
std::vector<std::string>& assetLoadErrors,
|
||||||
|
std::mutex& assetLoadErrorsMutex)
|
||||||
|
: loadedTasks_(loadedTasks)
|
||||||
|
, currentLoadingFile_(currentLoadingFile)
|
||||||
|
, currentLoadingMutex_(currentLoadingMutex)
|
||||||
|
, assetLoadErrors_(assetLoadErrors)
|
||||||
|
, assetLoadErrorsMutex_(assetLoadErrorsMutex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextureLoader::setCurrentLoadingFile(const std::string& filename) {
|
||||||
|
std::lock_guard<std::mutex> lk(currentLoadingMutex_);
|
||||||
|
currentLoadingFile_ = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextureLoader::clearCurrentLoadingFile() {
|
||||||
|
std::lock_guard<std::mutex> lk(currentLoadingMutex_);
|
||||||
|
currentLoadingFile_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextureLoader::recordAssetLoadError(const std::string& message) {
|
||||||
|
std::lock_guard<std::mutex> lk(assetLoadErrorsMutex_);
|
||||||
|
assetLoadErrors_.emplace_back(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Texture* TextureLoader::loadFromImage(SDL_Renderer* renderer, const std::string& path, int* outW, int* outH) {
|
||||||
|
if (!renderer) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string resolvedPath = AssetPath::resolveImagePath(path);
|
||||||
|
setCurrentLoadingFile(resolvedPath.empty() ? path : resolvedPath);
|
||||||
|
|
||||||
|
SDL_Surface* surface = IMG_Load(resolvedPath.c_str());
|
||||||
|
if (!surface) {
|
||||||
|
{
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << "Image load failed: " << path << " (" << resolvedPath << "): " << SDL_GetError();
|
||||||
|
recordAssetLoadError(ss.str());
|
||||||
|
}
|
||||||
|
loadedTasks_.fetch_add(1);
|
||||||
|
clearCurrentLoadingFile();
|
||||||
|
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) {
|
||||||
|
{
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << "Texture create failed: " << resolvedPath << ": " << SDL_GetError();
|
||||||
|
recordAssetLoadError(ss.str());
|
||||||
|
}
|
||||||
|
loadedTasks_.fetch_add(1);
|
||||||
|
clearCurrentLoadingFile();
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create texture from %s: %s", resolvedPath.c_str(), SDL_GetError());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadedTasks_.fetch_add(1);
|
||||||
|
clearCurrentLoadingFile();
|
||||||
|
|
||||||
|
if (resolvedPath != path) {
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Loaded %s via %s", path.c_str(), resolvedPath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
31
src/app/TextureLoader.h
Normal file
31
src/app/TextureLoader.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class TextureLoader {
|
||||||
|
public:
|
||||||
|
TextureLoader(
|
||||||
|
std::atomic<int>& loadedTasks,
|
||||||
|
std::string& currentLoadingFile,
|
||||||
|
std::mutex& currentLoadingMutex,
|
||||||
|
std::vector<std::string>& assetLoadErrors,
|
||||||
|
std::mutex& assetLoadErrorsMutex);
|
||||||
|
|
||||||
|
SDL_Texture* loadFromImage(SDL_Renderer* renderer, const std::string& path, int* outW = nullptr, int* outH = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::atomic<int>& loadedTasks_;
|
||||||
|
std::string& currentLoadingFile_;
|
||||||
|
std::mutex& currentLoadingMutex_;
|
||||||
|
std::vector<std::string>& assetLoadErrors_;
|
||||||
|
std::mutex& assetLoadErrorsMutex_;
|
||||||
|
|
||||||
|
void setCurrentLoadingFile(const std::string& filename);
|
||||||
|
void clearCurrentLoadingFile();
|
||||||
|
void recordAssetLoadError(const std::string& message);
|
||||||
|
};
|
||||||
294
src/main.cpp
294
src/main.cpp
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
#include <SDL3/SDL_main.h>
|
#include <SDL3/SDL_main.h>
|
||||||
#include <SDL3_image/SDL_image.h>
|
|
||||||
#include <SDL3_ttf/SDL_ttf.h>
|
#include <SDL3_ttf/SDL_ttf.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@ -39,6 +38,7 @@
|
|||||||
#include "states/PlayingState.h"
|
#include "states/PlayingState.h"
|
||||||
#include "audio/MenuWrappers.h"
|
#include "audio/MenuWrappers.h"
|
||||||
#include "app/AssetLoader.h"
|
#include "app/AssetLoader.h"
|
||||||
|
#include "app/TextureLoader.h"
|
||||||
#include "states/LoadingManager.h"
|
#include "states/LoadingManager.h"
|
||||||
#include "utils/ImagePathResolver.h"
|
#include "utils/ImagePathResolver.h"
|
||||||
#include "graphics/renderers/GameRenderer.h"
|
#include "graphics/renderers/GameRenderer.h"
|
||||||
@ -47,8 +47,6 @@
|
|||||||
#include "ui/MenuLayout.h"
|
#include "ui/MenuLayout.h"
|
||||||
#include "ui/BottomMenu.h"
|
#include "ui/BottomMenu.h"
|
||||||
|
|
||||||
// Debug logging removed: no-op in this build (previously LOG_DEBUG)
|
|
||||||
|
|
||||||
// Font rendering now handled by FontAtlas
|
// Font rendering now handled by FontAtlas
|
||||||
|
|
||||||
// ---------- Game config ----------
|
// ---------- Game config ----------
|
||||||
@ -99,289 +97,6 @@ static void drawRect(SDL_Renderer *r, float x, float y, float w, float h, SDL_Co
|
|||||||
SDL_RenderFillRect(r, &fr);
|
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);
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lk(g_currentLoadingMutex);
|
|
||||||
g_currentLoadingFile = resolvedPath.empty() ? path : resolvedPath;
|
|
||||||
}
|
|
||||||
SDL_Surface* surface = IMG_Load(resolvedPath.c_str());
|
|
||||||
if (!surface) {
|
|
||||||
// Record the error for display on the loading screen
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lk(g_assetLoadErrorsMutex);
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << "Image load failed: " << path << " (" << resolvedPath << "): " << SDL_GetError();
|
|
||||||
g_assetLoadErrors.emplace_back(ss.str());
|
|
||||||
}
|
|
||||||
g_loadedTasks.fetch_add(1);
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lk(g_currentLoadingMutex);
|
|
||||||
g_currentLoadingFile.clear();
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lk(g_assetLoadErrorsMutex);
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << "Texture create failed: " << resolvedPath << ": " << SDL_GetError();
|
|
||||||
g_assetLoadErrors.emplace_back(ss.str());
|
|
||||||
}
|
|
||||||
g_loadedTasks.fetch_add(1);
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lk(g_currentLoadingMutex);
|
|
||||||
g_currentLoadingFile.clear();
|
|
||||||
}
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create texture from %s: %s", resolvedPath.c_str(), SDL_GetError());
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
// Mark this task as completed
|
|
||||||
g_loadedTasks.fetch_add(1);
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lk(g_currentLoadingMutex);
|
|
||||||
g_currentLoadingFile.clear();
|
|
||||||
}
|
|
||||||
if (resolvedPath != path) {
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Loaded %s via %s", path.c_str(), resolvedPath.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class LevelBackgroundPhase { Idle, ZoomOut, ZoomIn };
|
|
||||||
|
|
||||||
struct LevelBackgroundFader {
|
|
||||||
SDL_Texture* currentTex = nullptr;
|
|
||||||
SDL_Texture* nextTex = nullptr;
|
|
||||||
int currentLevel = -1;
|
|
||||||
int queuedLevel = -1;
|
|
||||||
float phaseElapsedMs = 0.0f;
|
|
||||||
float phaseDurationMs = 0.0f;
|
|
||||||
float fadeDurationMs = Config::Gameplay::LEVEL_FADE_DURATION;
|
|
||||||
LevelBackgroundPhase phase = LevelBackgroundPhase::Idle;
|
|
||||||
};
|
|
||||||
|
|
||||||
static float getPhaseDurationMs(const LevelBackgroundFader& fader, LevelBackgroundPhase phase) {
|
|
||||||
const float total = std::max(1200.0f, fader.fadeDurationMs);
|
|
||||||
switch (phase) {
|
|
||||||
case LevelBackgroundPhase::ZoomOut: return total * 0.45f;
|
|
||||||
case LevelBackgroundPhase::ZoomIn: return total * 0.45f;
|
|
||||||
case LevelBackgroundPhase::Idle:
|
|
||||||
default: return 0.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setPhase(LevelBackgroundFader& fader, LevelBackgroundPhase nextPhase) {
|
|
||||||
fader.phase = nextPhase;
|
|
||||||
fader.phaseDurationMs = getPhaseDurationMs(fader, nextPhase);
|
|
||||||
fader.phaseElapsedMs = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void destroyTexture(SDL_Texture*& tex) {
|
|
||||||
if (tex) {
|
|
||||||
SDL_DestroyTexture(tex);
|
|
||||||
tex = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool queueLevelBackground(LevelBackgroundFader& fader, SDL_Renderer* renderer, int level) {
|
|
||||||
if (!renderer) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
level = std::clamp(level, 0, 32);
|
|
||||||
if (fader.currentLevel == level || fader.queuedLevel == level) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
char bgPath[256];
|
|
||||||
std::snprintf(bgPath, sizeof(bgPath), "assets/images/levels/level%d.jpg", level);
|
|
||||||
|
|
||||||
SDL_Texture* newTexture = loadTextureFromImage(renderer, bgPath);
|
|
||||||
if (!newTexture) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to queue background for level %d: %s", level, bgPath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
destroyTexture(fader.nextTex);
|
|
||||||
fader.nextTex = newTexture;
|
|
||||||
fader.queuedLevel = level;
|
|
||||||
|
|
||||||
if (!fader.currentTex) {
|
|
||||||
// First background load happens instantly.
|
|
||||||
fader.currentTex = fader.nextTex;
|
|
||||||
fader.currentLevel = fader.queuedLevel;
|
|
||||||
fader.nextTex = nullptr;
|
|
||||||
fader.queuedLevel = -1;
|
|
||||||
fader.phase = LevelBackgroundPhase::Idle;
|
|
||||||
fader.phaseElapsedMs = 0.0f;
|
|
||||||
fader.phaseDurationMs = 0.0f;
|
|
||||||
} else if (fader.phase == LevelBackgroundPhase::Idle) {
|
|
||||||
// Kick off fancy transition.
|
|
||||||
setPhase(fader, LevelBackgroundPhase::ZoomOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void updateLevelBackgroundFade(LevelBackgroundFader& fader, float frameMs) {
|
|
||||||
if (fader.phase == LevelBackgroundPhase::Idle) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Guard against missing textures
|
|
||||||
if (!fader.currentTex && !fader.nextTex) {
|
|
||||||
fader.phase = LevelBackgroundPhase::Idle;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fader.phaseElapsedMs += frameMs;
|
|
||||||
if (fader.phaseElapsedMs < std::max(1.0f, fader.phaseDurationMs)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (fader.phase) {
|
|
||||||
case LevelBackgroundPhase::ZoomOut:
|
|
||||||
// After zoom-out, swap textures then start zoom-in.
|
|
||||||
if (fader.nextTex) {
|
|
||||||
destroyTexture(fader.currentTex);
|
|
||||||
fader.currentTex = fader.nextTex;
|
|
||||||
fader.currentLevel = fader.queuedLevel;
|
|
||||||
fader.nextTex = nullptr;
|
|
||||||
fader.queuedLevel = -1;
|
|
||||||
}
|
|
||||||
setPhase(fader, LevelBackgroundPhase::ZoomIn);
|
|
||||||
break;
|
|
||||||
case LevelBackgroundPhase::ZoomIn:
|
|
||||||
fader.phase = LevelBackgroundPhase::Idle;
|
|
||||||
fader.phaseElapsedMs = 0.0f;
|
|
||||||
fader.phaseDurationMs = 0.0f;
|
|
||||||
break;
|
|
||||||
case LevelBackgroundPhase::Idle:
|
|
||||||
default:
|
|
||||||
fader.phase = LevelBackgroundPhase::Idle;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void renderScaledBackground(SDL_Renderer* renderer, SDL_Texture* tex, int winW, int winH, float scale, Uint8 alpha = 255) {
|
|
||||||
if (!renderer || !tex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
scale = std::max(0.5f, scale);
|
|
||||||
SDL_FRect dest{
|
|
||||||
(winW - winW * scale) * 0.5f,
|
|
||||||
(winH - winH * scale) * 0.5f,
|
|
||||||
winW * scale,
|
|
||||||
winH * scale
|
|
||||||
};
|
|
||||||
|
|
||||||
SDL_SetTextureAlphaMod(tex, alpha);
|
|
||||||
SDL_RenderTexture(renderer, tex, nullptr, &dest);
|
|
||||||
SDL_SetTextureAlphaMod(tex, 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void renderDynamicBackground(SDL_Renderer* renderer, SDL_Texture* tex, int winW, int winH, float baseScale, float motionClockMs, float alphaMul = 1.0f) {
|
|
||||||
if (!renderer || !tex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float seconds = motionClockMs * 0.001f;
|
|
||||||
const float wobble = std::max(0.4f, baseScale + std::sin(seconds * 0.07f) * 0.02f + std::sin(seconds * 0.23f) * 0.01f);
|
|
||||||
const float rotation = std::sin(seconds * 0.035f) * 1.25f;
|
|
||||||
const float panX = std::sin(seconds * 0.11f) * winW * 0.02f;
|
|
||||||
const float panY = std::cos(seconds * 0.09f) * winH * 0.015f;
|
|
||||||
|
|
||||||
SDL_FRect dest{
|
|
||||||
(winW - winW * wobble) * 0.5f + panX,
|
|
||||||
(winH - winH * wobble) * 0.5f + panY,
|
|
||||||
winW * wobble,
|
|
||||||
winH * wobble
|
|
||||||
};
|
|
||||||
SDL_FPoint center{dest.w * 0.5f, dest.h * 0.5f};
|
|
||||||
|
|
||||||
Uint8 alpha = static_cast<Uint8>(std::clamp(alphaMul, 0.0f, 1.0f) * 255.0f);
|
|
||||||
SDL_SetTextureAlphaMod(tex, alpha);
|
|
||||||
SDL_RenderTextureRotated(renderer, tex, nullptr, &dest, rotation, ¢er, SDL_FLIP_NONE);
|
|
||||||
SDL_SetTextureAlphaMod(tex, 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void drawOverlay(SDL_Renderer* renderer, const SDL_FRect& rect, SDL_Color color, Uint8 alpha) {
|
|
||||||
if (!renderer || alpha == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
|
||||||
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, alpha);
|
|
||||||
SDL_RenderFillRect(renderer, &rect);
|
|
||||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void renderLevelBackgrounds(const LevelBackgroundFader& fader, SDL_Renderer* renderer, int winW, int winH, float motionClockMs) {
|
|
||||||
if (!renderer) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_FRect fullRect{0.f, 0.f, static_cast<float>(winW), static_cast<float>(winH)};
|
|
||||||
const float duration = std::max(1.0f, fader.phaseDurationMs);
|
|
||||||
const float progress = (fader.phase == LevelBackgroundPhase::Idle) ? 0.0f : std::clamp(fader.phaseElapsedMs / duration, 0.0f, 1.0f);
|
|
||||||
const float seconds = motionClockMs * 0.001f;
|
|
||||||
|
|
||||||
switch (fader.phase) {
|
|
||||||
case LevelBackgroundPhase::ZoomOut: {
|
|
||||||
const float scale = 1.0f + progress * 0.15f;
|
|
||||||
if (fader.currentTex) {
|
|
||||||
renderDynamicBackground(renderer, fader.currentTex, winW, winH, scale, motionClockMs, (1.0f - progress * 0.4f));
|
|
||||||
drawOverlay(renderer, fullRect, SDL_Color{0, 0, 0, 255}, Uint8(progress * 200.0f));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case LevelBackgroundPhase::ZoomIn: {
|
|
||||||
const float scale = 1.10f - progress * 0.10f;
|
|
||||||
const Uint8 alpha = Uint8((0.4f + progress * 0.6f) * 255.0f);
|
|
||||||
if (fader.currentTex) {
|
|
||||||
renderDynamicBackground(renderer, fader.currentTex, winW, winH, scale, motionClockMs, alpha / 255.0f);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case LevelBackgroundPhase::Idle:
|
|
||||||
default:
|
|
||||||
if (fader.currentTex) {
|
|
||||||
renderDynamicBackground(renderer, fader.currentTex, winW, winH, 1.02f, motionClockMs, 1.0f);
|
|
||||||
float pulse = 0.35f + 0.25f * (0.5f + 0.5f * std::sin(seconds * 0.5f));
|
|
||||||
drawOverlay(renderer, fullRect, SDL_Color{5, 12, 28, 255}, Uint8(pulse * 90.0f));
|
|
||||||
} else if (fader.nextTex) {
|
|
||||||
renderDynamicBackground(renderer, fader.nextTex, winW, winH, 1.02f, motionClockMs, 1.0f);
|
|
||||||
} else {
|
|
||||||
drawOverlay(renderer, fullRect, SDL_Color{0, 0, 0, 255}, 255);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void resetLevelBackgrounds(LevelBackgroundFader& fader) {
|
|
||||||
destroyTexture(fader.currentTex);
|
|
||||||
destroyTexture(fader.nextTex);
|
|
||||||
fader.currentLevel = -1;
|
|
||||||
fader.queuedLevel = -1;
|
|
||||||
fader.phaseElapsedMs = 0.0f;
|
|
||||||
fader.phaseDurationMs = 0.0f;
|
|
||||||
fader.phase = LevelBackgroundPhase::Idle;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hover state for level popup ( -1 = none, 0..19 = hovered level )
|
// Hover state for level popup ( -1 = none, 0..19 = hovered level )
|
||||||
// Now managed by LevelSelectorState
|
// Now managed by LevelSelectorState
|
||||||
|
|
||||||
@ -494,6 +209,9 @@ int main(int, char **)
|
|||||||
assetLoader.init(renderer);
|
assetLoader.init(renderer);
|
||||||
LoadingManager loadingManager(&assetLoader);
|
LoadingManager loadingManager(&assetLoader);
|
||||||
|
|
||||||
|
// Legacy image loader (used only as a fallback when AssetLoader misses)
|
||||||
|
TextureLoader textureLoader(g_loadedTasks, g_currentLoadingFile, g_currentLoadingMutex, g_assetLoadErrors, g_assetLoadErrorsMutex);
|
||||||
|
|
||||||
// Font and UI asset handles (actual loading deferred until Loading state)
|
// Font and UI asset handles (actual loading deferred until Loading state)
|
||||||
FontAtlas pixelFont;
|
FontAtlas pixelFont;
|
||||||
FontAtlas font;
|
FontAtlas font;
|
||||||
@ -1319,7 +1037,7 @@ int main(int, char **)
|
|||||||
// load synchronously using the legacy helper so the Menu can render.
|
// load synchronously using the legacy helper so the Menu can render.
|
||||||
auto legacyLoad = [&](const std::string& p, SDL_Texture*& outTex, int* outW = nullptr, int* outH = nullptr) {
|
auto legacyLoad = [&](const std::string& p, SDL_Texture*& outTex, int* outW = nullptr, int* outH = nullptr) {
|
||||||
if (!outTex) {
|
if (!outTex) {
|
||||||
outTex = loadTextureFromImage(renderer, p, outW, outH);
|
outTex = textureLoader.loadFromImage(renderer, p, outW, outH);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1753,7 +1471,7 @@ int main(int, char **)
|
|||||||
case AppState::Menu:
|
case AppState::Menu:
|
||||||
// Ensure overlay is loaded (drawn after highscores so it sits above that layer)
|
// Ensure overlay is loaded (drawn after highscores so it sits above that layer)
|
||||||
if (!mainScreenTex) {
|
if (!mainScreenTex) {
|
||||||
mainScreenTex = loadTextureFromImage(renderer, "assets/images/main_screen.png", &mainScreenW, &mainScreenH);
|
mainScreenTex = textureLoader.loadFromImage(renderer, "assets/images/main_screen.png", &mainScreenW, &mainScreenH);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render menu content that should appear *behind* the overlay (highscores/logo).
|
// Render menu content that should appear *behind* the overlay (highscores/logo).
|
||||||
|
|||||||
Reference in New Issue
Block a user