fixes for mac music
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,14 +1,14 @@
|
||||
@echo off
|
||||
echo Converting MP3 files to WAV using Windows Media Player...
|
||||
echo Convert MP3 files to OGG (preferred) for cross-platform playback...
|
||||
echo.
|
||||
|
||||
REM Check if we have access to Windows Media Format SDK
|
||||
set MUSIC_DIR=assets\music
|
||||
|
||||
REM List of MP3 files to convert
|
||||
set FILES=amazing.mp3 boom_tetris.mp3 great_move.mp3 impressive.mp3 keep_that_ryhtm.mp3 lets_go.mp3 nice_combo.mp3 smooth_clear.mp3 triple_strike.mp3 well_played.mp3 wonderful.mp3 you_fire.mp3 you_re_unstoppable.mp3
|
||||
set FILES=amazing.mp3 boom_tetris.mp3 great_move.mp3 impressive.mp3 keep_that_ryhtm.mp3 lets_go.mp3 nice_combo.mp3 smooth_clear.mp3 triple_strike.mp3 well_played.mp3 wonderful.mp3 you_fire.mp3 you_re_unstoppable.mp3 hard_drop_001.mp3 new_level.mp3
|
||||
|
||||
echo Please convert these MP3 files to WAV format manually:
|
||||
echo Please convert these MP3 files to OGG Vorbis manually (or run convert_to_ogg.ps1 on Windows):
|
||||
echo.
|
||||
for %%f in (%FILES%) do (
|
||||
echo - %MUSIC_DIR%\%%f
|
||||
@@ -17,13 +17,12 @@ for %%f in (%FILES%) do (
|
||||
echo.
|
||||
echo Recommended settings for conversion:
|
||||
echo - Sample Rate: 44100 Hz
|
||||
echo - Bit Depth: 16-bit
|
||||
echo - Channels: Stereo (2)
|
||||
echo - Format: PCM WAV
|
||||
echo - Use OGG Vorbis quality ~4 (or convert to FLAC if you prefer lossless)
|
||||
echo.
|
||||
echo You can use:
|
||||
echo - Audacity (free): https://www.audacityteam.org/
|
||||
echo - VLC Media Player (free): Media ^> Convert/Save
|
||||
echo - Any audio converter software
|
||||
echo - ffmpeg (CLI): ffmpeg -i input.mp3 -c:a libvorbis -qscale:a 4 output.ogg
|
||||
echo.
|
||||
pause
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# Convert MP3 sound effects to OGG Vorbis format for cross-platform playback
|
||||
# Requires ffmpeg (https://ffmpeg.org/). OGG keeps files small while SDL's decoders
|
||||
# work everywhere the game ships.
|
||||
|
||||
$musicDir = "assets\music"
|
||||
$sourceFiles = @(
|
||||
"amazing.mp3",
|
||||
"boom_tetris.mp3",
|
||||
"great_move.mp3",
|
||||
"impressive.mp3",
|
||||
"keep_that_ryhtm.mp3",
|
||||
"lets_go.mp3",
|
||||
"nice_combo.mp3",
|
||||
"smooth_clear.mp3",
|
||||
"triple_strike.mp3",
|
||||
"well_played.mp3",
|
||||
"wonderful.mp3",
|
||||
"you_fire.mp3",
|
||||
"you_re_unstoppable.mp3",
|
||||
"hard_drop_001.mp3",
|
||||
"new_level.mp3",
|
||||
"Every Block You Take.mp3"
|
||||
)
|
||||
|
||||
if (!(Get-Command ffmpeg -ErrorAction SilentlyContinue)) {
|
||||
Write-Host "ffmpeg is required. Install via https://ffmpeg.org/ or winget install Gyan.FFmpeg" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "Converting MP3 sound effects to OGG..." -ForegroundColor Cyan
|
||||
foreach ($file in $sourceFiles) {
|
||||
$src = Join-Path $musicDir $file
|
||||
if (!(Test-Path $src)) {
|
||||
Write-Host "Skipping (missing): $src" -ForegroundColor Yellow
|
||||
continue
|
||||
}
|
||||
$ogg = ($file -replace ".mp3$", ".ogg")
|
||||
$dest = Join-Path $musicDir $ogg
|
||||
Write-Host "-> $ogg" -ForegroundColor Green
|
||||
& ffmpeg -y -i $src -c:a libvorbis -qscale:a 4 $dest > $null 2>&1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "Failed to convert $file" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
Write-Host "Conversion complete." -ForegroundColor Green
|
||||
+9
-61
@@ -1,63 +1,11 @@
|
||||
# Convert MP3 sound effects to WAV format
|
||||
# This script converts all MP3 sound effect files to WAV for better compatibility
|
||||
# Deprecated shim: point developers to the OGG conversion workflow
|
||||
Write-Host "convert_to_wav.ps1 is deprecated." -ForegroundColor Yellow
|
||||
Write-Host "Use convert_to_ogg.ps1 for generating assets with OGG Vorbis." -ForegroundColor Yellow
|
||||
|
||||
$musicDir = "assets\music"
|
||||
$mp3Files = @(
|
||||
"amazing.mp3",
|
||||
"boom_tetris.mp3",
|
||||
"great_move.mp3",
|
||||
"impressive.mp3",
|
||||
"keep_that_ryhtm.mp3",
|
||||
"lets_go.mp3",
|
||||
"nice_combo.mp3",
|
||||
"smooth_clear.mp3",
|
||||
"triple_strike.mp3",
|
||||
"well_played.mp3",
|
||||
"wonderful.mp3",
|
||||
"you_fire.mp3",
|
||||
"you_re_unstoppable.mp3"
|
||||
)
|
||||
|
||||
Write-Host "Converting MP3 sound effects to WAV format..." -ForegroundColor Green
|
||||
|
||||
foreach ($mp3File in $mp3Files) {
|
||||
$mp3Path = Join-Path $musicDir $mp3File
|
||||
$wavFile = $mp3File -replace "\.mp3$", ".wav"
|
||||
$wavPath = Join-Path $musicDir $wavFile
|
||||
|
||||
if (Test-Path $mp3Path) {
|
||||
Write-Host "Converting $mp3File to $wavFile..." -ForegroundColor Yellow
|
||||
|
||||
# Try ffmpeg first (most common)
|
||||
$ffmpegResult = $null
|
||||
try {
|
||||
$ffmpegResult = & ffmpeg -i $mp3Path -acodec pcm_s16le -ar 44100 -ac 2 $wavPath -y 2>&1
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Host "✓ Successfully converted $mp3File" -ForegroundColor Green
|
||||
continue
|
||||
}
|
||||
} catch {
|
||||
# FFmpeg not available, try other methods
|
||||
}
|
||||
|
||||
# Try Windows Media Format SDK (if available)
|
||||
try {
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
Add-Type -AssemblyName Microsoft.VisualBasic
|
||||
|
||||
# Use Windows built-in audio conversion
|
||||
$shell = New-Object -ComObject Shell.Application
|
||||
# This is a fallback method - may not work on all systems
|
||||
Write-Host "⚠ FFmpeg not found. Please install FFmpeg or convert manually." -ForegroundColor Red
|
||||
} catch {
|
||||
Write-Host "⚠ Could not convert $mp3File automatically." -ForegroundColor Red
|
||||
}
|
||||
} else {
|
||||
Write-Host "⚠ File not found: $mp3Path" -ForegroundColor Red
|
||||
}
|
||||
$oggScript = Join-Path $PSScriptRoot "convert_to_ogg.ps1"
|
||||
if (Test-Path $oggScript) {
|
||||
& $oggScript
|
||||
} else {
|
||||
Write-Host "Missing convert_to_ogg.ps1" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "`nConversion complete! If FFmpeg was not found, please:" -ForegroundColor Cyan
|
||||
Write-Host "1. Install FFmpeg: https://ffmpeg.org/download.html" -ForegroundColor White
|
||||
Write-Host "2. Or use an audio converter like Audacity" -ForegroundColor White
|
||||
Write-Host "3. Convert to: 44.1kHz, 16-bit, Stereo WAV" -ForegroundColor White
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ Sound=1
|
||||
SmoothScroll=1
|
||||
|
||||
[Player]
|
||||
Name=GREGOR
|
||||
Name=PLAYER
|
||||
|
||||
[Debug]
|
||||
Enabled=1
|
||||
|
||||
@@ -558,16 +558,20 @@ bool ApplicationManager::initializeGame() {
|
||||
Audio::instance().init();
|
||||
// Discover available tracks (up to 100) and queue for background loading
|
||||
m_totalTracks = 0;
|
||||
std::vector<std::string> trackPaths;
|
||||
trackPaths.reserve(100);
|
||||
for (int i = 1; i <= 100; ++i) {
|
||||
char buf[128];
|
||||
std::snprintf(buf, sizeof(buf), "assets/music/music%03d.mp3", i);
|
||||
// Use simple file existence check via std::filesystem
|
||||
if (std::filesystem::exists(buf)) {
|
||||
Audio::instance().addTrackAsync(buf);
|
||||
++m_totalTracks;
|
||||
} else {
|
||||
char base[128];
|
||||
std::snprintf(base, sizeof(base), "assets/music/music%03d", i);
|
||||
std::string path = AssetPath::resolveWithExtensions(base, { ".mp3" });
|
||||
if (path.empty()) {
|
||||
break;
|
||||
}
|
||||
trackPaths.push_back(path);
|
||||
}
|
||||
m_totalTracks = static_cast<int>(trackPaths.size());
|
||||
for (const auto& path : trackPaths) {
|
||||
Audio::instance().addTrackAsync(path);
|
||||
}
|
||||
if (m_totalTracks > 0) {
|
||||
Audio::instance().startBackgroundLoading();
|
||||
|
||||
@@ -208,27 +208,14 @@ bool AssetManager::loadSoundEffectWithFallback(const std::string& id, const std:
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try WAV first, then MP3 fallback (matching main.cpp pattern)
|
||||
std::string wavPath = "assets/music/" + baseName + ".wav";
|
||||
std::string mp3Path = "assets/music/" + baseName + ".mp3";
|
||||
|
||||
// Check WAV first
|
||||
if (fileExists(wavPath)) {
|
||||
if (m_soundSystem->loadSound(id, wavPath)) {
|
||||
logInfo("Loaded sound effect: " + id + " from " + wavPath + " (WAV)");
|
||||
return true;
|
||||
}
|
||||
const std::string basePath = "assets/music/" + baseName;
|
||||
std::string resolved = AssetPath::resolveWithExtensions(basePath, { ".wav", ".mp3" });
|
||||
if (!resolved.empty() && m_soundSystem->loadSound(id, resolved)) {
|
||||
logInfo("Loaded sound effect: " + id + " from " + resolved);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fallback to MP3
|
||||
if (fileExists(mp3Path)) {
|
||||
if (m_soundSystem->loadSound(id, mp3Path)) {
|
||||
logInfo("Loaded sound effect: " + id + " from " + mp3Path + " (MP3 fallback)");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
setError("Failed to load sound effect: " + id + " (tried both WAV and MP3)");
|
||||
setError("Failed to load sound effect: " + id + " (no supported audio extension found)");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+67
-70
@@ -15,6 +15,7 @@
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <filesystem>
|
||||
#include <thread>
|
||||
|
||||
#include "audio/Audio.h"
|
||||
#include "audio/SoundEffect.h"
|
||||
@@ -682,11 +683,11 @@ int main(int, char **)
|
||||
}
|
||||
SDL_SetRenderVSync(renderer, 1);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
// On macOS bundles launched from Finder start in /, so re-root relative paths.
|
||||
if (const char* basePathRaw = SDL_GetBasePath()) {
|
||||
std::filesystem::path exeDir(basePathRaw);
|
||||
SDL_free(const_cast<char*>(basePathRaw));
|
||||
AssetPath::setBasePath(exeDir.string());
|
||||
#if defined(__APPLE__)
|
||||
// On macOS bundles launched from Finder start in /, so re-root relative paths.
|
||||
std::error_code ec;
|
||||
std::filesystem::current_path(exeDir, ec);
|
||||
if (ec) {
|
||||
@@ -694,12 +695,13 @@ int main(int, char **)
|
||||
"Failed to set working directory to %s: %s",
|
||||
exeDir.string().c_str(), ec.message().c_str());
|
||||
}
|
||||
#endif
|
||||
SDL_free(const_cast<char*>(basePathRaw));
|
||||
} else {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_GetBasePath() failed; asset lookups rely on current directory: %s",
|
||||
SDL_GetError());
|
||||
}
|
||||
#endif
|
||||
|
||||
FontAtlas font;
|
||||
font.init("FreeSans.ttf", 24);
|
||||
@@ -709,10 +711,15 @@ int main(int, char **)
|
||||
pixelFont.init("assets/fonts/PressStart2P-Regular.ttf", 16);
|
||||
|
||||
ScoreManager scores;
|
||||
// Load scores asynchronously to prevent startup hang due to network request
|
||||
std::thread([&scores]() {
|
||||
// Load scores asynchronously but keep the worker alive until shutdown to avoid lifetime issues
|
||||
std::jthread scoreLoader([&scores]() {
|
||||
scores.load();
|
||||
}).detach();
|
||||
});
|
||||
const auto ensureScoresLoaded = [&]() {
|
||||
if (scoreLoader.joinable()) {
|
||||
scoreLoader.join();
|
||||
}
|
||||
};
|
||||
Starfield starfield;
|
||||
starfield.init(200, LOGICAL_W, LOGICAL_H);
|
||||
Starfield3D starfield3D;
|
||||
@@ -771,9 +778,19 @@ int main(int, char **)
|
||||
|
||||
// Initialize sound effects system
|
||||
SoundEffectManager::instance().init();
|
||||
|
||||
// Load sound effects
|
||||
SoundEffectManager::instance().loadSound("clear_line", "assets/music/clear_line.wav");
|
||||
|
||||
auto loadAudioAsset = [](const std::string& basePath, const std::string& id) {
|
||||
std::string resolved = AssetPath::resolveWithExtensions(basePath, { ".wav", ".mp3" });
|
||||
if (resolved.empty()) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Missing audio asset for %s (base %s)", id.c_str(), basePath.c_str());
|
||||
return;
|
||||
}
|
||||
if (!SoundEffectManager::instance().loadSound(id, resolved)) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load %s from %s", id.c_str(), resolved.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
loadAudioAsset("assets/music/clear_line", "clear_line");
|
||||
|
||||
// Load voice lines for line clears using WAV files (with MP3 fallback)
|
||||
std::vector<std::string> singleSounds = {"well_played", "smooth_clear", "great_move"};
|
||||
@@ -789,49 +806,25 @@ int main(int, char **)
|
||||
appendVoices(tripleSounds);
|
||||
appendVoices(tetrisSounds);
|
||||
|
||||
// Helper function to load sound with WAV/MP3 fallback and file existence check
|
||||
auto loadSoundWithFallback = [&](const std::string& id, const std::string& baseName) {
|
||||
std::string wavPath = "assets/music/" + baseName + ".wav";
|
||||
std::string mp3Path = "assets/music/" + baseName + ".mp3";
|
||||
|
||||
// Check if WAV file exists first
|
||||
SDL_IOStream* wavFile = SDL_IOFromFile(wavPath.c_str(), "rb");
|
||||
if (wavFile) {
|
||||
SDL_CloseIO(wavFile);
|
||||
if (SoundEffectManager::instance().loadSound(id, wavPath)) {
|
||||
(void)0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to MP3 if WAV doesn't exist or fails to load
|
||||
SDL_IOStream* mp3File = SDL_IOFromFile(mp3Path.c_str(), "rb");
|
||||
if (mp3File) {
|
||||
SDL_CloseIO(mp3File);
|
||||
if (SoundEffectManager::instance().loadSound(id, mp3Path)) {
|
||||
(void)0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load sound: %s (tried both WAV and MP3)", id.c_str());
|
||||
auto loadVoice = [&](const std::string& id, const std::string& baseName) {
|
||||
loadAudioAsset("assets/music/" + baseName, id);
|
||||
};
|
||||
|
||||
loadSoundWithFallback("nice_combo", "nice_combo");
|
||||
loadSoundWithFallback("you_fire", "you_fire");
|
||||
loadSoundWithFallback("well_played", "well_played");
|
||||
loadSoundWithFallback("keep_that_ryhtm", "keep_that_ryhtm");
|
||||
loadSoundWithFallback("great_move", "great_move");
|
||||
loadSoundWithFallback("smooth_clear", "smooth_clear");
|
||||
loadSoundWithFallback("impressive", "impressive");
|
||||
loadSoundWithFallback("triple_strike", "triple_strike");
|
||||
loadSoundWithFallback("amazing", "amazing");
|
||||
loadSoundWithFallback("you_re_unstoppable", "you_re_unstoppable");
|
||||
loadSoundWithFallback("boom_tetris", "boom_tetris");
|
||||
loadSoundWithFallback("wonderful", "wonderful");
|
||||
loadSoundWithFallback("lets_go", "lets_go"); // For level up
|
||||
loadSoundWithFallback("hard_drop", "hard_drop_001");
|
||||
loadSoundWithFallback("new_level", "new_level");
|
||||
|
||||
loadVoice("nice_combo", "nice_combo");
|
||||
loadVoice("you_fire", "you_fire");
|
||||
loadVoice("well_played", "well_played");
|
||||
loadVoice("keep_that_ryhtm", "keep_that_ryhtm");
|
||||
loadVoice("great_move", "great_move");
|
||||
loadVoice("smooth_clear", "smooth_clear");
|
||||
loadVoice("impressive", "impressive");
|
||||
loadVoice("triple_strike", "triple_strike");
|
||||
loadVoice("amazing", "amazing");
|
||||
loadVoice("you_re_unstoppable", "you_re_unstoppable");
|
||||
loadVoice("boom_tetris", "boom_tetris");
|
||||
loadVoice("wonderful", "wonderful");
|
||||
loadVoice("lets_go", "lets_go");
|
||||
loadVoice("hard_drop", "hard_drop_001");
|
||||
loadVoice("new_level", "new_level");
|
||||
|
||||
bool suppressLineVoiceForLevelUp = false;
|
||||
|
||||
@@ -1122,6 +1115,7 @@ int main(int, char **)
|
||||
playerName.pop_back();
|
||||
} else if (e.key.scancode == SDL_SCANCODE_RETURN || e.key.scancode == SDL_SCANCODE_KP_ENTER) {
|
||||
if (playerName.empty()) playerName = "PLAYER";
|
||||
ensureScoresLoaded();
|
||||
scores.submit(game.score(), game.lines(), game.level(), game.elapsed(), playerName);
|
||||
Settings::instance().setPlayerName(playerName);
|
||||
isNewHighScore = false;
|
||||
@@ -1379,6 +1373,7 @@ int main(int, char **)
|
||||
SDL_StartTextInput(window);
|
||||
} else {
|
||||
isNewHighScore = false;
|
||||
ensureScoresLoaded();
|
||||
scores.submit(game.score(), game.lines(), game.level(), game.elapsed());
|
||||
}
|
||||
state = AppState::GameOver;
|
||||
@@ -1396,25 +1391,21 @@ int main(int, char **)
|
||||
|
||||
// Count actual music files first
|
||||
totalTracks = 0;
|
||||
for (int i = 1; i <= 100; ++i) { // Check up to 100 files
|
||||
char buf[64];
|
||||
std::snprintf(buf, sizeof(buf), "assets/music/music%03d.mp3", i);
|
||||
|
||||
// Check if file exists
|
||||
SDL_IOStream* file = SDL_IOFromFile(buf, "rb");
|
||||
if (file) {
|
||||
SDL_CloseIO(file);
|
||||
totalTracks++;
|
||||
} else {
|
||||
break; // No more consecutive files
|
||||
std::vector<std::string> trackPaths;
|
||||
trackPaths.reserve(100);
|
||||
for (int i = 1; i <= 100; ++i) {
|
||||
char base[64];
|
||||
std::snprintf(base, sizeof(base), "assets/music/music%03d", i);
|
||||
std::string path = AssetPath::resolveWithExtensions(base, { ".mp3" });
|
||||
if (path.empty()) {
|
||||
break;
|
||||
}
|
||||
trackPaths.push_back(path);
|
||||
}
|
||||
|
||||
// Add all found tracks to the background loading queue
|
||||
for (int i = 1; i <= totalTracks; ++i) {
|
||||
char buf[64];
|
||||
std::snprintf(buf, sizeof(buf), "assets/music/music%03d.mp3", i);
|
||||
Audio::instance().addTrackAsync(buf);
|
||||
totalTracks = static_cast<int>(trackPaths.size());
|
||||
|
||||
for (const auto& track : trackPaths) {
|
||||
Audio::instance().addTrackAsync(track);
|
||||
}
|
||||
|
||||
// Start background loading thread
|
||||
@@ -1470,7 +1461,12 @@ int main(int, char **)
|
||||
static bool menuTrackLoaded = false;
|
||||
if (!menuTrackLoaded) {
|
||||
std::thread([]() {
|
||||
Audio::instance().setMenuTrack("assets/music/Every Block You Take.mp3");
|
||||
std::string menuTrack = AssetPath::resolveWithExtensions("assets/music/Every Block You Take", { ".mp3" });
|
||||
if (!menuTrack.empty()) {
|
||||
Audio::instance().setMenuTrack(menuTrack);
|
||||
} else {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Menu track not found (Every Block You Take)");
|
||||
}
|
||||
}).detach();
|
||||
menuTrackLoaded = true;
|
||||
}
|
||||
@@ -1804,6 +1800,7 @@ int main(int, char **)
|
||||
// 4. Draw Text
|
||||
// 4. Draw Text
|
||||
// Title
|
||||
ensureScoresLoaded();
|
||||
bool realHighScore = scores.isHighScore(game.score());
|
||||
const char* title = realHighScore ? "NEW HIGH SCORE!" : "GAME OVER";
|
||||
int tW=0, tH=0; pixelFont.measure(title, 2.0f, tW, tH);
|
||||
|
||||
@@ -2,17 +2,27 @@
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#include <initializer_list>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
namespace AssetPath {
|
||||
|
||||
inline bool fileExists(const std::string& path) {
|
||||
if (path.empty()) {
|
||||
inline std::string& baseDirectory() {
|
||||
static std::string base;
|
||||
return base;
|
||||
}
|
||||
|
||||
inline void setBasePath(std::string path) {
|
||||
baseDirectory() = std::move(path);
|
||||
}
|
||||
|
||||
inline bool tryOpenFile(const std::string& candidate) {
|
||||
if (candidate.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_IOStream* file = SDL_IOFromFile(path.c_str(), "rb");
|
||||
SDL_IOStream* file = SDL_IOFromFile(candidate.c_str(), "rb");
|
||||
if (file) {
|
||||
SDL_CloseIO(file);
|
||||
return true;
|
||||
@@ -20,13 +30,58 @@ inline bool fileExists(const std::string& path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool fileExists(const std::string& path) {
|
||||
if (path.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tryOpenFile(path)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::filesystem::path p(path);
|
||||
if (!p.is_absolute()) {
|
||||
const std::string& base = baseDirectory();
|
||||
if (!base.empty()) {
|
||||
std::filesystem::path combined = std::filesystem::path(base) / p;
|
||||
if (tryOpenFile(combined.string())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline std::string resolveWithBase(const std::string& path) {
|
||||
if (path.empty()) {
|
||||
return path;
|
||||
}
|
||||
|
||||
if (tryOpenFile(path)) {
|
||||
return path;
|
||||
}
|
||||
|
||||
std::filesystem::path p(path);
|
||||
if (!p.is_absolute()) {
|
||||
const std::string& base = baseDirectory();
|
||||
if (!base.empty()) {
|
||||
std::filesystem::path combined = std::filesystem::path(base) / p;
|
||||
std::string combinedStr = combined.string();
|
||||
if (tryOpenFile(combinedStr)) {
|
||||
return combinedStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
inline std::string resolveImagePath(const std::string& originalPath) {
|
||||
if (originalPath.empty()) {
|
||||
return originalPath;
|
||||
}
|
||||
|
||||
if (fileExists(originalPath)) {
|
||||
return originalPath;
|
||||
if (auto resolved = resolveWithBase(originalPath); resolved != originalPath || fileExists(resolved)) {
|
||||
return resolved;
|
||||
}
|
||||
|
||||
const std::size_t dot = originalPath.find_last_of('.');
|
||||
@@ -45,12 +100,41 @@ inline std::string resolveImagePath(const std::string& originalPath) {
|
||||
if (candidate == originalPath) {
|
||||
continue;
|
||||
}
|
||||
if (fileExists(candidate)) {
|
||||
return candidate;
|
||||
std::string resolvedCandidate = resolveWithBase(candidate);
|
||||
if (resolvedCandidate != candidate || fileExists(resolvedCandidate)) {
|
||||
return resolvedCandidate;
|
||||
}
|
||||
}
|
||||
|
||||
return originalPath;
|
||||
}
|
||||
|
||||
inline std::string resolveWithExtensions(const std::string& basePathWithoutExt, std::initializer_list<const char*> extensions) {
|
||||
for (const char* ext : extensions) {
|
||||
std::string candidate = basePathWithoutExt + ext;
|
||||
std::string resolved = resolveWithBase(candidate);
|
||||
if (resolved != candidate || fileExists(resolved)) {
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
inline std::string resolveAudioPath(const std::string& basePathWithoutExt) {
|
||||
static constexpr std::array<const char*, 4> AUDIO_EXTENSIONS = {
|
||||
".ogg",
|
||||
".flac",
|
||||
".wav",
|
||||
".mp3"
|
||||
};
|
||||
for (const char* ext : AUDIO_EXTENSIONS) {
|
||||
std::string candidate = basePathWithoutExt + ext;
|
||||
std::string resolved = resolveWithBase(candidate);
|
||||
if (resolved != candidate || fileExists(resolved)) {
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace AssetPath
|
||||
|
||||
Reference in New Issue
Block a user