diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c5c897..f1383b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,11 +108,6 @@ set(APP_SOURCES source/main.cpp ) -# Fuentes de librerías de terceros -set(EXTERNAL_SOURCES - source/external/jail_audio.cpp -) - # Fuentes del sistema de renderizado set(RENDERING_SOURCES source/core/rendering/opengl/opengl_shader.cpp @@ -128,7 +123,7 @@ find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3) message(STATUS "SDL3 encontrado: ${SDL3_INCLUDE_DIRS}") # --- 2. AÑADIR EJECUTABLE --- -add_executable(${PROJECT_NAME} ${APP_SOURCES} ${EXTERNAL_SOURCES} ${RENDERING_SOURCES}) +add_executable(${PROJECT_NAME} ${APP_SOURCES} ${RENDERING_SOURCES}) # Añadir fuentes de debug solo en modo Debug target_sources(${PROJECT_NAME} PRIVATE $<$:${DEBUG_SOURCES}>) diff --git a/CMakeLists.txt.backup b/CMakeLists.txt.backup deleted file mode 100644 index cc6669f..0000000 --- a/CMakeLists.txt.backup +++ /dev/null @@ -1,187 +0,0 @@ -# CMakeLists.txt - -cmake_minimum_required(VERSION 3.10) -project(jaildoctors_dilemma VERSION 1.00) - -# Establecer estándar de C++ -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED True) - -# Exportar comandos de compilación para herramientas de análisis -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) - -# Establece la política CMP0072 para indicar cómo se debe seleccionar la implementación de OpenGL. -# En este caso, se elige la opción "GLVND", que utiliza bibliotecas modernas y modulares (libOpenGL, libGLX), -# en lugar de la biblioteca OpenGL clásica (libGL). Esto mejora la compatibilidad con drivers recientes -# y evita ambigüedades cuando se encuentran múltiples implementaciones de OpenGL en el sistema. -cmake_policy(SET CMP0072 NEW) -set(OpenGL_GL_PREFERENCE GLVND) - -# --- GENERACIÓN DE VERSIÓN AUTOMÁTICA --- -find_package(Git QUIET) -if(GIT_FOUND) - execute_process( - COMMAND ${GIT_EXECUTABLE} rev-parse --short=7 HEAD - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE GIT_HASH - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_QUIET - ) -else() - set(GIT_HASH "unknown") -endif() - -# Configurar archivo de versión -configure_file(${CMAKE_SOURCE_DIR}/source/version.h.in ${CMAKE_BINARY_DIR}/version.h @ONLY) - -# --- 1. LISTA EXPLÍCITA DE FUENTES --- -set(APP_SOURCES - # Core - Audio - source/core/audio/audio.cpp - - # Core - Input - source/core/input/global_inputs.cpp - source/core/input/input.cpp - source/core/input/input_types.cpp - source/core/input/mouse.cpp - - # Core - Rendering - source/core/rendering/gif.cpp - source/core/rendering/screen.cpp - source/core/rendering/surface.cpp - source/core/rendering/surface_animated_sprite.cpp - source/core/rendering/surface_moving_sprite.cpp - source/core/rendering/surface_sprite.cpp - source/core/rendering/text.cpp - source/core/rendering/texture.cpp - - # Core - Resources - source/core/resources/resource_list.cpp - source/core/resources/resource_cache.cpp - source/core/resources/resource_pack.cpp - source/core/resources/resource_loader.cpp - source/core/resources/resource_helper.cpp - - # Core - System - source/core/system/director.cpp - source/core/system/global_events.cpp - - # Game - Entities - source/game/entities/enemy.cpp - source/game/entities/item.cpp - source/game/entities/player.cpp - - # Game - Configuration - source/game/options.cpp - - # Game - Gameplay - source/game/gameplay/cheevos.cpp - source/game/gameplay/collision_map.cpp - source/game/gameplay/enemy_manager.cpp - source/game/gameplay/item_manager.cpp - source/game/gameplay/item_tracker.cpp - source/game/gameplay/room.cpp - source/game/gameplay/room_loader.cpp - source/game/gameplay/room_tracker.cpp - source/game/gameplay/scoreboard.cpp - source/game/gameplay/stats.cpp - source/game/gameplay/tilemap_renderer.cpp - - # Game - Scenes - source/game/scenes/credits.cpp - source/game/scenes/ending.cpp - source/game/scenes/ending2.cpp - source/game/scenes/game.cpp - source/game/scenes/game_over.cpp - source/game/scenes/loading_screen.cpp - source/game/scenes/logo.cpp - source/game/scenes/title.cpp - - # Game - UI - source/game/ui/notifier.cpp - - # Utils - source/utils/delta_timer.cpp - source/utils/utils.cpp - - # Main - source/main.cpp -) - -# Fuentes de librerías de terceros -set(EXTERNAL_SOURCES - source/external/jail_audio.cpp -) - -# Fuentes del sistema de renderizado -set(RENDERING_SOURCES - source/core/rendering/opengl/opengl_shader.cpp -) - -# Fuentes de debug (solo en modo Debug) -set(DEBUG_SOURCES - source/core/system/debug.cpp -) - -# Configuración de SDL3 -find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3) -message(STATUS "SDL3 encontrado: ${SDL3_INCLUDE_DIRS}") - -# Configuración de yaml-cpp (desde source/external/) -# Deshabilitar tests y herramientas de yaml-cpp -set(YAML_CPP_BUILD_TESTS OFF CACHE INTERNAL "") -set(YAML_CPP_BUILD_TOOLS OFF CACHE INTERNAL "") -set(YAML_CPP_BUILD_CONTRIB OFF CACHE INTERNAL "") -set(YAML_CPP_INSTALL OFF CACHE INTERNAL "") -add_subdirectory(source/external/yaml-cpp) -message(STATUS "yaml-cpp configurado desde source/external/") - -# --- 2. AÑADIR EJECUTABLE --- -add_executable(${PROJECT_NAME} ${APP_SOURCES} ${EXTERNAL_SOURCES} ${RENDERING_SOURCES}) - -# Añadir fuentes de debug solo en modo Debug -target_sources(${PROJECT_NAME} PRIVATE $<$:${DEBUG_SOURCES}>) - -# --- 3. DIRECTORIOS DE INCLUSIÓN --- -target_include_directories(${PROJECT_NAME} PUBLIC - "${CMAKE_SOURCE_DIR}/source" - "${CMAKE_BINARY_DIR}" -) - -# Enlazar las librerías SDL3 y yaml-cpp -target_link_libraries(${PROJECT_NAME} PRIVATE SDL3::SDL3 yaml-cpp::yaml-cpp) - - -# --- 4. CONFIGURACIÓN PLATAFORMAS Y COMPILADOR --- -# Configuración de flags de compilación -target_compile_options(${PROJECT_NAME} PRIVATE -Wall) -target_compile_options(${PROJECT_NAME} PRIVATE $<$:-Os -ffunction-sections -fdata-sections>) - -# Definir _DEBUG en modo Debug -target_compile_definitions(${PROJECT_NAME} PRIVATE $<$:_DEBUG>) - -# Configuración específica para cada plataforma -if(WIN32) - target_compile_definitions(${PROJECT_NAME} PRIVATE WINDOWS_BUILD) - target_link_libraries(${PROJECT_NAME} PRIVATE ws2_32 mingw32 opengl32) -elseif(APPLE) - target_compile_definitions(${PROJECT_NAME} PRIVATE MACOS_BUILD) - target_compile_options(${PROJECT_NAME} PRIVATE -Wno-deprecated) - set(CMAKE_OSX_ARCHITECTURES "arm64") -elseif(UNIX AND NOT APPLE) - target_compile_definitions(${PROJECT_NAME} PRIVATE LINUX_BUILD) -endif() - -# Configuración común para OpenGL -if(NOT WIN32) - find_package(OpenGL REQUIRED) - if(OPENGL_FOUND) - message(STATUS "OpenGL encontrado: ${OPENGL_LIBRARIES}") - target_link_libraries(${PROJECT_NAME} PRIVATE ${OPENGL_LIBRARIES}) - else() - message(FATAL_ERROR "OpenGL no encontrado") - endif() -endif() - -# Especificar la ubicación del ejecutable -set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}) \ No newline at end of file diff --git a/Makefile b/Makefile index b6569e3..18b9be0 100644 --- a/Makefile +++ b/Makefile @@ -109,19 +109,15 @@ APP_SOURCES := \ source/game/scenes/credits.cpp \ source/game/ui/notifier.cpp \ source/utils/utils.cpp \ - source/utils/delta_timer.cpp \ - source/external/jail_audio.cpp - -# yaml-cpp library sources -YAML_CPP_SOURCES := $(wildcard source/external/yaml-cpp/src/*.cpp) + source/utils/delta_timer.cpp # All sources combined -ALL_SOURCES := $(APP_SOURCES) $(YAML_CPP_SOURCES) +ALL_SOURCES := $(APP_SOURCES) # ============================================================================== # INCLUDES # ============================================================================== -INCLUDES := -Isource -Isource/external/yaml-cpp/include +INCLUDES := -Isource # ============================================================================== # COMPILER FLAGS (OS-specific) diff --git a/source/core/audio/audio.cpp b/source/core/audio/audio.cpp index c1dfac0..7312fab 100644 --- a/source/core/audio/audio.cpp +++ b/source/core/audio/audio.cpp @@ -5,8 +5,14 @@ #include // Para clamp #include // Para std::cout +// Implementación de stb_vorbis (debe estar ANTES de incluir jail_audio.hpp) +// clang-format off +#undef STB_VORBIS_HEADER_ONLY +#include "external/stb_vorbis.h" +// clang-format on + +#include "core/audio/jail_audio.hpp" // Para JA_FadeOutMusic, JA_Init, JA_PauseM... #include "core/resources/resource_cache.hpp" // Para Resource -#include "external/jail_audio.h" // Para JA_FadeOutMusic, JA_Init, JA_PauseM... #include "game/options.hpp" // Para AudioOptions, audio, MusicOptions // Singleton diff --git a/source/core/audio/jail_audio.hpp b/source/core/audio/jail_audio.hpp new file mode 100644 index 0000000..d538cb4 --- /dev/null +++ b/source/core/audio/jail_audio.hpp @@ -0,0 +1,529 @@ +#pragma once + +// --- Includes --- +#include +#include // Para uint32_t, uint8_t +#include // Para NULL, fseek, printf, fclose, fopen, fread, ftell, FILE, SEEK_END, SEEK_SET +#include // Para free, malloc +#include // Para strcpy, strlen + +#define STB_VORBIS_HEADER_ONLY +#include "external/stb_vorbis.h" // Para stb_vorbis_decode_memory + +// --- Public Enums --- +enum JA_Channel_state { JA_CHANNEL_INVALID, JA_CHANNEL_FREE, JA_CHANNEL_PLAYING, JA_CHANNEL_PAUSED, JA_SOUND_DISABLED }; +enum JA_Music_state { JA_MUSIC_INVALID, JA_MUSIC_PLAYING, JA_MUSIC_PAUSED, JA_MUSIC_STOPPED, JA_MUSIC_DISABLED }; + +// --- Struct Definitions --- +#define JA_MAX_SIMULTANEOUS_CHANNELS 20 +#define JA_MAX_GROUPS 2 + +struct JA_Sound_t +{ + SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 }; + Uint32 length { 0 }; + Uint8 *buffer { NULL }; +}; + +struct JA_Channel_t +{ + JA_Sound_t *sound { nullptr }; + int pos { 0 }; + int times { 0 }; + int group { 0 }; + SDL_AudioStream *stream { nullptr }; + JA_Channel_state state { JA_CHANNEL_FREE }; +}; + +struct JA_Music_t +{ + SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 }; + Uint32 length { 0 }; + Uint8 *buffer { nullptr }; + char *filename { nullptr }; + + int pos { 0 }; + int times { 0 }; + SDL_AudioStream *stream { nullptr }; + JA_Music_state state { JA_MUSIC_INVALID }; +}; + +// --- Internal Global State --- +// Marcado 'inline' (C++17) para asegurar una única instancia. + +inline JA_Music_t* current_music { nullptr }; +inline JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS]; + +inline SDL_AudioSpec JA_audioSpec { SDL_AUDIO_S16, 2, 48000 }; +inline float JA_musicVolume { 1.0f }; +inline float JA_soundVolume[JA_MAX_GROUPS]; +inline bool JA_musicEnabled { true }; +inline bool JA_soundEnabled { true }; +inline SDL_AudioDeviceID sdlAudioDevice { 0 }; + +inline bool fading { false }; +inline int fade_start_time { 0 }; +inline int fade_duration { 0 }; +inline float fade_initial_volume { 0.0f }; // Corregido de 'int' a 'float' + +// --- Forward Declarations --- +inline void JA_StopMusic(); +inline void JA_StopChannel(const int channel); +inline int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop = 0, const int group = 0); + +// --- Core Functions --- + +inline void JA_Update() +{ + if (JA_musicEnabled && current_music && current_music->state == JA_MUSIC_PLAYING) + { + if (fading) { + int time = SDL_GetTicks(); + if (time > (fade_start_time + fade_duration)) { + fading = false; + JA_StopMusic(); + return; + } else { + const int time_passed = time - fade_start_time; + const float percent = (float)time_passed / (float)fade_duration; + SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume * (1.0 - percent)); + } + } + + if (current_music->times != 0) + { + if ((Uint32)SDL_GetAudioStreamAvailable(current_music->stream) < (current_music->length / 2)) { + SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length); + } + if (current_music->times > 0) current_music->times--; + } + else + { + if (SDL_GetAudioStreamAvailable(current_music->stream) == 0) JA_StopMusic(); + } + } + + if (JA_soundEnabled) + { + for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i) + if (channels[i].state == JA_CHANNEL_PLAYING) + { + if (channels[i].times != 0) + { + if ((Uint32)SDL_GetAudioStreamAvailable(channels[i].stream) < (channels[i].sound->length / 2)) { + SDL_PutAudioStreamData(channels[i].stream, channels[i].sound->buffer, channels[i].sound->length); + if (channels[i].times > 0) channels[i].times--; + } + } + else + { + if (SDL_GetAudioStreamAvailable(channels[i].stream) == 0) JA_StopChannel(i); + } + } + } +} + +inline void JA_Init(const int freq, const SDL_AudioFormat format, const int num_channels) +{ + #ifdef _DEBUG + SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG); + #endif + + JA_audioSpec = { format, num_channels, freq }; + if (sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice); // Corregido: !sdlAudioDevice -> sdlAudioDevice + sdlAudioDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &JA_audioSpec); + if (sdlAudioDevice == 0) SDL_Log("Failed to initialize SDL audio!"); + for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i) channels[i].state = JA_CHANNEL_FREE; + for (int i = 0; i < JA_MAX_GROUPS; ++i) JA_soundVolume[i] = 0.5f; +} + +inline void JA_Quit() +{ + if (sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice); // Corregido: !sdlAudioDevice -> sdlAudioDevice + sdlAudioDevice = 0; +} + +// --- Music Functions --- + +inline JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length) +{ + JA_Music_t *music = new JA_Music_t(); + + int chan, samplerate; + short *output; + music->length = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &output) * chan * 2; + + music->spec.channels = chan; + music->spec.freq = samplerate; + music->spec.format = SDL_AUDIO_S16; + music->buffer = (Uint8*)SDL_malloc(music->length); + SDL_memcpy(music->buffer, output, music->length); + free(output); + music->pos = 0; + music->state = JA_MUSIC_STOPPED; + + return music; +} + +inline JA_Music_t *JA_LoadMusic(const char* filename) +{ + // [RZC 28/08/22] Carreguem primer el arxiu en memòria i després el descomprimim. Es algo més rapid. + FILE *f = fopen(filename, "rb"); + if (!f) return NULL; // Añadida comprobación de apertura + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + Uint8 *buffer = (Uint8*)malloc(fsize + 1); + if (!buffer) { // Añadida comprobación de malloc + fclose(f); + return NULL; + } + if (fread(buffer, fsize, 1, f) != 1) { + fclose(f); + free(buffer); + return NULL; + } + fclose(f); + + JA_Music_t *music = JA_LoadMusic(buffer, fsize); + if (music) { // Comprobar que JA_LoadMusic tuvo éxito + music->filename = (char*)malloc(strlen(filename) + 1); + if (music->filename) { + strcpy(music->filename, filename); + } + } + + free(buffer); + + return music; +} + +inline void JA_PlayMusic(JA_Music_t *music, const int loop = -1) +{ + if (!JA_musicEnabled || !music) return; // Añadida comprobación de music + + JA_StopMusic(); + + current_music = music; + current_music->pos = 0; + current_music->state = JA_MUSIC_PLAYING; + current_music->times = loop; + + current_music->stream = SDL_CreateAudioStream(¤t_music->spec, &JA_audioSpec); + if (!current_music->stream) { // Comprobar creación de stream + SDL_Log("Failed to create audio stream!"); + current_music->state = JA_MUSIC_STOPPED; + return; + } + if (!SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length)) printf("[ERROR] SDL_PutAudioStreamData failed!\n"); + SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume); + if (!SDL_BindAudioStream(sdlAudioDevice, current_music->stream)) printf("[ERROR] SDL_BindAudioStream failed!\n"); +} + +inline char *JA_GetMusicFilename(JA_Music_t *music = nullptr) +{ + if (!music) music = current_music; + if (!music) return nullptr; // Añadida comprobación + return music->filename; +} + +inline void JA_PauseMusic() +{ + if (!JA_musicEnabled) return; + if (!current_music || current_music->state != JA_MUSIC_PLAYING) return; // Comprobación mejorada + + current_music->state = JA_MUSIC_PAUSED; + SDL_UnbindAudioStream(current_music->stream); +} + +inline void JA_ResumeMusic() +{ + if (!JA_musicEnabled) return; + if (!current_music || current_music->state != JA_MUSIC_PAUSED) return; // Comprobación mejorada + + current_music->state = JA_MUSIC_PLAYING; + SDL_BindAudioStream(sdlAudioDevice, current_music->stream); +} + +inline void JA_StopMusic() +{ + if (!current_music || current_music->state == JA_MUSIC_INVALID || current_music->state == JA_MUSIC_STOPPED) return; + + current_music->pos = 0; + current_music->state = JA_MUSIC_STOPPED; + if (current_music->stream) { + SDL_DestroyAudioStream(current_music->stream); + current_music->stream = nullptr; + } + // No liberamos filename aquí, se debería liberar en JA_DeleteMusic +} + +inline void JA_FadeOutMusic(const int milliseconds) +{ + if (!JA_musicEnabled) return; + if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return; + + fading = true; + fade_start_time = SDL_GetTicks(); + fade_duration = milliseconds; + fade_initial_volume = JA_musicVolume; +} + +inline JA_Music_state JA_GetMusicState() +{ + if (!JA_musicEnabled) return JA_MUSIC_DISABLED; + if (!current_music) return JA_MUSIC_INVALID; + + return current_music->state; +} + +inline void JA_DeleteMusic(JA_Music_t *music) +{ + if (!music) return; + if (current_music == music) { + JA_StopMusic(); + current_music = nullptr; + } + SDL_free(music->buffer); + if (music->stream) SDL_DestroyAudioStream(music->stream); + free(music->filename); // filename se libera aquí + delete music; +} + +inline float JA_SetMusicVolume(float volume) +{ + JA_musicVolume = SDL_clamp(volume, 0.0f, 1.0f); + if (current_music && current_music->stream) { + SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume); + } + return JA_musicVolume; +} + +inline void JA_SetMusicPosition(float value) +{ + if (!current_music) return; + current_music->pos = value * current_music->spec.freq; + // Nota: Esta implementación de 'pos' no parece usarse en JA_Update para + // el streaming. El streaming siempre parece empezar desde el principio. +} + +inline float JA_GetMusicPosition() +{ + if (!current_music) return 0; + return float(current_music->pos) / float(current_music->spec.freq); + // Nota: Ver `JA_SetMusicPosition` +} + +inline void JA_EnableMusic(const bool value) +{ + if (!value && current_music && (current_music->state == JA_MUSIC_PLAYING)) JA_StopMusic(); + + JA_musicEnabled = value; +} + + +// --- Sound Functions --- + +inline JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length) +{ + JA_Sound_t *sound = new JA_Sound_t(); + sound->buffer = buffer; + sound->length = length; + // Nota: spec se queda con los valores por defecto. + return sound; +} + +inline JA_Sound_t *JA_LoadSound(uint8_t* buffer, uint32_t size) +{ + JA_Sound_t *sound = new JA_Sound_t(); + if (!SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size), 1, &sound->spec, &sound->buffer, &sound->length)) { + SDL_Log("Failed to load WAV from memory: %s", SDL_GetError()); + delete sound; + return nullptr; + } + return sound; +} + +inline JA_Sound_t *JA_LoadSound(const char* filename) +{ + JA_Sound_t *sound = new JA_Sound_t(); + if (!SDL_LoadWAV(filename, &sound->spec, &sound->buffer, &sound->length)) { + SDL_Log("Failed to load WAV file: %s", SDL_GetError()); + delete sound; + return nullptr; + } + return sound; +} + +inline int JA_PlaySound(JA_Sound_t *sound, const int loop = 0, const int group = 0) +{ + if (!JA_soundEnabled || !sound) return -1; + + int channel = 0; + while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) { channel++; } + if (channel == JA_MAX_SIMULTANEOUS_CHANNELS) { + // No hay canal libre, reemplazamos el primero + channel = 0; + } + + return JA_PlaySoundOnChannel(sound, channel, loop, group); +} + +inline int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop, const int group) +{ + if (!JA_soundEnabled || !sound) return -1; + if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return -1; + + JA_StopChannel(channel); // Detiene y limpia el canal si estaba en uso + + channels[channel].sound = sound; + channels[channel].times = loop; + channels[channel].pos = 0; + channels[channel].group = group; // Asignar grupo + channels[channel].state = JA_CHANNEL_PLAYING; + channels[channel].stream = SDL_CreateAudioStream(&channels[channel].sound->spec, &JA_audioSpec); + + if (!channels[channel].stream) { + SDL_Log("Failed to create audio stream for sound!"); + channels[channel].state = JA_CHANNEL_FREE; + return -1; + } + + SDL_PutAudioStreamData(channels[channel].stream, channels[channel].sound->buffer, channels[channel].sound->length); + SDL_SetAudioStreamGain(channels[channel].stream, JA_soundVolume[group]); + SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream); + + return channel; +} + +inline void JA_DeleteSound(JA_Sound_t *sound) +{ + if (!sound) return; + for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { + if (channels[i].sound == sound) JA_StopChannel(i); + } + SDL_free(sound->buffer); + delete sound; +} + +inline void JA_PauseChannel(const int channel) +{ + if (!JA_soundEnabled) return; + + if (channel == -1) + { + for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) + if (channels[i].state == JA_CHANNEL_PLAYING) + { + channels[i].state = JA_CHANNEL_PAUSED; + SDL_UnbindAudioStream(channels[i].stream); + } + } + else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) + { + if (channels[channel].state == JA_CHANNEL_PLAYING) + { + channels[channel].state = JA_CHANNEL_PAUSED; + SDL_UnbindAudioStream(channels[channel].stream); + } + } +} + +inline void JA_ResumeChannel(const int channel) +{ + if (!JA_soundEnabled) return; + + if (channel == -1) + { + for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) + if (channels[i].state == JA_CHANNEL_PAUSED) + { + channels[i].state = JA_CHANNEL_PLAYING; + SDL_BindAudioStream(sdlAudioDevice, channels[i].stream); + } + } + else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) + { + if (channels[channel].state == JA_CHANNEL_PAUSED) + { + channels[channel].state = JA_CHANNEL_PLAYING; + SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream); + } + } +} + +inline void JA_StopChannel(const int channel) +{ + if (channel == -1) + { + for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { + if (channels[i].state != JA_CHANNEL_FREE) { + if (channels[i].stream) SDL_DestroyAudioStream(channels[i].stream); + channels[i].stream = nullptr; + channels[i].state = JA_CHANNEL_FREE; + channels[i].pos = 0; + channels[i].sound = NULL; + } + } + } + else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) + { + if (channels[channel].state != JA_CHANNEL_FREE) { + if (channels[channel].stream) SDL_DestroyAudioStream(channels[channel].stream); + channels[channel].stream = nullptr; + channels[channel].state = JA_CHANNEL_FREE; + channels[channel].pos = 0; + channels[channel].sound = NULL; + } + } +} + +inline JA_Channel_state JA_GetChannelState(const int channel) +{ + if (!JA_soundEnabled) return JA_SOUND_DISABLED; + if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return JA_CHANNEL_INVALID; + + return channels[channel].state; +} + +inline float JA_SetSoundVolume(float volume, const int group = -1) // -1 para todos los grupos +{ + const float v = SDL_clamp(volume, 0.0f, 1.0f); + + if (group == -1) { + for (int i = 0; i < JA_MAX_GROUPS; ++i) { + JA_soundVolume[i] = v; + } + } else if (group >= 0 && group < JA_MAX_GROUPS) { + JA_soundVolume[group] = v; + } else { + return v; // Grupo inválido + } + + // Aplicar volumen a canales activos + for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { + if ((channels[i].state == JA_CHANNEL_PLAYING) || (channels[i].state == JA_CHANNEL_PAUSED)) { + if (group == -1 || channels[i].group == group) { + if (channels[i].stream) { + SDL_SetAudioStreamGain(channels[i].stream, JA_soundVolume[channels[i].group]); + } + } + } + } + return v; +} + +inline void JA_EnableSound(const bool value) +{ + if (!value) { + JA_StopChannel(-1); // Detener todos los canales + } + JA_soundEnabled = value; +} + +inline float JA_SetVolume(float volume) +{ + float v = JA_SetMusicVolume(volume); + JA_SetSoundVolume(v, -1); // Aplicar a todos los grupos de sonido + return v; +} \ No newline at end of file diff --git a/source/core/resources/resource_cache.cpp b/source/core/resources/resource_cache.cpp index 1bbbd42..4f25122 100644 --- a/source/core/resources/resource_cache.cpp +++ b/source/core/resources/resource_cache.cpp @@ -8,19 +8,19 @@ #include // Para runtime_error #include -#include "core/rendering/screen.hpp" // Para Screen -#include "core/rendering/text.hpp" // Para Text, loadTextFile -#include "core/resources/resource_list.hpp" // Para List, List::Type -#include "core/resources/resource_helper.hpp" // Para Helper -#include "external/jail_audio.h" // Para JA_DeleteMusic, JA_DeleteSound, JA_Loa... -#include "game/defaults.hpp" // Para GameDefaults::VERSION -#include "game/gameplay/room.hpp" // Para RoomData, loadRoomFile, loadRoomTileFile -#include "game/options.hpp" // Para Options, OptionsGame, options -#include "utils/defines.hpp" // Para WINDOW_CAPTION -#include "utils/utils.hpp" // Para getFileName, printWithDots, PaletteColor -#include "version.h" // Para Version::GIT_HASH -struct JA_Music_t; // lines 17-17 -struct JA_Sound_t; // lines 18-18 +#include "core/audio/jail_audio.hpp" // Para JA_DeleteMusic, JA_DeleteSound, JA_Loa... +#include "core/rendering/screen.hpp" // Para Screen +#include "core/rendering/text.hpp" // Para Text, loadTextFile +#include "core/resources/resource_helper.hpp" // Para Helper +#include "core/resources/resource_list.hpp" // Para List, List::Type +#include "game/defaults.hpp" // Para GameDefaults::VERSION +#include "game/gameplay/room.hpp" // Para RoomData, loadRoomFile, loadRoomTileFile +#include "game/options.hpp" // Para Options, OptionsGame, options +#include "utils/defines.hpp" // Para WINDOW_CAPTION +#include "utils/utils.hpp" // Para getFileName, printWithDots, PaletteColor +#include "version.h" // Para Version::GIT_HASH +struct JA_Music_t; // lines 17-17 +struct JA_Sound_t; // lines 18-18 namespace Resource { diff --git a/source/external/README.md b/source/external/README.md index 5105181..e5172ef 100644 --- a/source/external/README.md +++ b/source/external/README.md @@ -10,7 +10,7 @@ This directory contains third-party libraries used by JailDoctor's Dilemma. | **stb_image** | v2.x | Header-only | Image loading (PNG, GIF) | | **stb_vorbis** | v1.x | Header-only | OGG Vorbis audio decoding | | **json** | nlohmann/json | Header-only | JSON parsing (if needed) | -| **yaml-cpp** | v0.8.0 | Source library | YAML parsing for room files | +| **fkYAML** | v3.x | Header-only | YAML parsing for room files | ## Structure @@ -21,11 +21,7 @@ external/ ├── stb_image.h # STB image loader (header-only) ├── stb_vorbis.h # STB Vorbis decoder (header-only) ├── json.hpp # nlohmann JSON library (header-only) -└── yaml-cpp/ # YAML parser library - ├── include/ # Public headers - │ └── yaml-cpp/ - ├── src/ # Source files (.cpp) - └── CMakeLists.txt # Build configuration +└── fkyaml_node.hpp # fkYAML parser library (header-only) ``` ## Why Dependencies Are Here @@ -42,28 +38,30 @@ All dependencies are kept in `source/external/` for several reasons: ### CMake (Recommended) ```cmake -# yaml-cpp -add_subdirectory(source/external/yaml-cpp) -target_link_libraries(${PROJECT_NAME} PRIVATE yaml-cpp::yaml-cpp) - -# Include path +# Include path for header-only libraries (fkYAML, json, stb) target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_SOURCE_DIR}/source") + +# All external dependencies are header-only except jail_audio +# jail_audio.cpp is compiled as part of the main build ``` ### Makefile See `Makefile.example` in the project root for a complete example. ```makefile -CXXFLAGS = -I./source -I./source/external/yaml-cpp/include -# Compile yaml-cpp sources and link +CXXFLAGS = -I./source +# Compile jail_audio.cpp and link with your sources ``` ### Manual Compilation ```bash -# Compile yaml-cpp sources -g++ -c source/external/yaml-cpp/src/*.cpp -I./source/external/yaml-cpp/include +# Compile jail_audio (only non-header-only library) +g++ -c source/external/jail_audio.cpp -I./source -# Link with your project +# Compile your project sources +g++ -c source/game/*.cpp -I./source + +# Link everything together g++ *.o -o game -lSDL3 ``` @@ -75,35 +73,34 @@ g++ *.o -o game -lSDL3 3. Include in code: `#include "external/library.h"` ### Source Libraries -1. Create subdirectory: `source/external/library-name/` -2. Place headers in `library-name/include/` -3. Place sources in `library-name/src/` -4. Update CMakeLists.txt: +1. Place source files (.cpp) directly in `source/external/` +2. Place header files (.h/.hpp) in `source/external/` +3. Add to CMakeLists.txt if needed: ```cmake - add_subdirectory(source/external/library-name) + # Most dependencies are header-only + # For source libraries, add to SOURCES list ``` ## Updating Dependencies -### yaml-cpp -To update yaml-cpp to a newer version: +### fkYAML +To update fkYAML to a newer version: ```bash cd source/external -rm -rf yaml-cpp -git clone https://github.com/jbeder/yaml-cpp.git -cd yaml-cpp -git checkout # e.g., 0.8.0 -rm -rf .git # Remove git history to reduce size +# Download the single-header version from the releases page +curl -L -O https://github.com/fktn-k/fkYAML/releases/download/v3.x.x/fkyaml_node.hpp ``` +Or download from: https://github.com/fktn-k/fkYAML/releases + ### STB Libraries Download latest from: https://github.com/nothings/stb ```bash cd source/external curl -O https://raw.githubusercontent.com/nothings/stb/master/stb_image.h -curl -O https://raw.githubusercontent.com/nothings/stb/master/stb_vorbis.c +curl -O https://raw.githubusercontent.com/nothings/stb/master/stb_vorbis.h ``` ## License Information @@ -113,13 +110,13 @@ Each library has its own license: - **jail_audio** - Custom (see source files) - **stb libraries** - Public Domain / MIT - **nlohmann/json** - MIT License -- **yaml-cpp** - MIT License +- **fkYAML** - MIT License -See individual library directories/files for full license texts. +See individual library files for full license texts. ## Notes - All dependencies are compatible with C++20 -- Header-only libraries require no compilation -- Source libraries (yaml-cpp, jail_audio) are compiled as part of the main build +- Most libraries are header-only and require no compilation +- Only jail_audio (source library) is compiled as part of the main build - Keep dependencies minimal to reduce build times and binary size diff --git a/source/external/jail_audio.cpp b/source/external/jail_audio.cpp deleted file mode 100644 index 72ea435..0000000 --- a/source/external/jail_audio.cpp +++ /dev/null @@ -1,477 +0,0 @@ -#ifndef JA_USESDLMIXER -#include "jail_audio.h" - -#include // Para SDL_AudioFormat, SDL_BindAudioStream, SDL_SetAudioStreamGain, SDL_PutAudioStreamData, SDL_DestroyAudioStream, SDL_GetAudioStreamAvailable, Uint8, SDL_CreateAudioStream, SDL_UnbindAudioStream, Uint32, SDL_CloseAudioDevice, SDL_GetTicks, SDL_Log, SDL_free, SDL_AudioSpec, SDL_AudioStream, SDL_IOFromMem, SDL_LoadWAV, SDL_LoadWAV_IO, SDL_OpenAudioDevice, SDL_clamp, SDL_malloc, SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, SDL_AudioDeviceID, SDL_memcpy -#include // Para uint32_t, uint8_t -#include // Para NULL, fseek, printf, fclose, fopen, fread, ftell, FILE, SEEK_END, SEEK_SET -#include // Para free, malloc -#include // Para strcpy, strlen - -#include "stb_vorbis.h" // Para stb_vorbis_decode_memory - -#define JA_MAX_SIMULTANEOUS_CHANNELS 20 -#define JA_MAX_GROUPS 2 - -struct JA_Sound_t -{ - SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 }; - Uint32 length { 0 }; - Uint8 *buffer { NULL }; -}; - -struct JA_Channel_t -{ - JA_Sound_t *sound { nullptr }; - int pos { 0 }; - int times { 0 }; - int group { 0 }; - SDL_AudioStream *stream { nullptr }; - JA_Channel_state state { JA_CHANNEL_FREE }; -}; - -struct JA_Music_t -{ - SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 }; - Uint32 length { 0 }; - Uint8 *buffer { nullptr }; - char *filename { nullptr }; - - int pos { 0 }; - int times { 0 }; - SDL_AudioStream *stream { nullptr }; - JA_Music_state state { JA_MUSIC_INVALID }; -}; - -JA_Music_t *current_music { nullptr }; -JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS]; - -SDL_AudioSpec JA_audioSpec { SDL_AUDIO_S16, 2, 48000 }; -float JA_musicVolume { 1.0f }; -float JA_soundVolume[JA_MAX_GROUPS]; -bool JA_musicEnabled { true }; -bool JA_soundEnabled { true }; -SDL_AudioDeviceID sdlAudioDevice { 0 }; -//SDL_TimerID JA_timerID { 0 }; - -bool fading = false; -int fade_start_time; -int fade_duration; -int fade_initial_volume; - - -void JA_Update() -{ - if (JA_musicEnabled && current_music && current_music->state == JA_MUSIC_PLAYING) - { - if (fading) { - int time = SDL_GetTicks(); - if (time > (fade_start_time+fade_duration)) { - fading = false; - JA_StopMusic(); - return; - } else { - const int time_passed = time - fade_start_time; - const float percent = (float)time_passed / (float)fade_duration; - SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume*(1.0 - percent)); - } - } - - if (current_music->times != 0) - { - if ((Uint32)SDL_GetAudioStreamAvailable(current_music->stream) < (current_music->length/2)) { - SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length); - } - if (current_music->times>0) current_music->times--; - } - else - { - if (SDL_GetAudioStreamAvailable(current_music->stream) == 0) JA_StopMusic(); - } - } - - if (JA_soundEnabled) - { - for (int i=0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i) - if (channels[i].state == JA_CHANNEL_PLAYING) - { - if (channels[i].times != 0) - { - if ((Uint32)SDL_GetAudioStreamAvailable(channels[i].stream) < (channels[i].sound->length/2)) { - SDL_PutAudioStreamData(channels[i].stream, channels[i].sound->buffer, channels[i].sound->length); - if (channels[i].times>0) channels[i].times--; - } - } - else - { - if (SDL_GetAudioStreamAvailable(channels[i].stream) == 0) JA_StopChannel(i); - } - } - - } - - return; -} - -void JA_Init(const int freq, const SDL_AudioFormat format, const int num_channels) -{ - #ifdef _DEBUG - SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG); - #endif - - JA_audioSpec = {format, num_channels, freq }; - if (!sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice); - sdlAudioDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &JA_audioSpec); - if (sdlAudioDevice==0) SDL_Log("Failed to initialize SDL audio!"); - for (int i=0; ilength = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &output) * chan * 2; - - music->spec.channels = chan; - music->spec.freq = samplerate; - music->spec.format = SDL_AUDIO_S16; - music->buffer = (Uint8*)SDL_malloc(music->length); - SDL_memcpy(music->buffer, output, music->length); - free(output); - music->pos = 0; - music->state = JA_MUSIC_STOPPED; - - return music; -} - -JA_Music_t *JA_LoadMusic(const char* filename) -{ - // [RZC 28/08/22] Carreguem primer el arxiu en memòria i després el descomprimim. Es algo més rapid. - FILE *f = fopen(filename, "rb"); - fseek(f, 0, SEEK_END); - long fsize = ftell(f); - fseek(f, 0, SEEK_SET); - Uint8 *buffer = (Uint8*)malloc(fsize + 1); - if (fread(buffer, fsize, 1, f)!=1) return NULL; - fclose(f); - - JA_Music_t *music = JA_LoadMusic(buffer, fsize); - music->filename = (char*)malloc(strlen(filename)+1); - strcpy(music->filename, filename); - - free(buffer); - - return music; -} - -void JA_PlayMusic(JA_Music_t *music, const int loop) -{ - if (!JA_musicEnabled) return; - - JA_StopMusic(); - - current_music = music; - current_music->pos = 0; - current_music->state = JA_MUSIC_PLAYING; - current_music->times = loop; - - current_music->stream = SDL_CreateAudioStream(¤t_music->spec, &JA_audioSpec); - if (!SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length)) printf("[ERROR] SDL_PutAudioStreamData failed!\n"); - SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume); - if (!SDL_BindAudioStream(sdlAudioDevice, current_music->stream)) printf("[ERROR] SDL_BindAudioStream failed!\n"); - //SDL_ResumeAudioStreamDevice(current_music->stream); -} - -char *JA_GetMusicFilename(JA_Music_t *music) -{ - if (!music) music = current_music; - return music->filename; -} - -void JA_PauseMusic() -{ - if (!JA_musicEnabled) return; - if (!current_music || current_music->state == JA_MUSIC_INVALID) return; - - current_music->state = JA_MUSIC_PAUSED; - //SDL_PauseAudioStreamDevice(current_music->stream); - SDL_UnbindAudioStream(current_music->stream); -} - -void JA_ResumeMusic() -{ - if (!JA_musicEnabled) return; - if (!current_music || current_music->state == JA_MUSIC_INVALID) return; - - current_music->state = JA_MUSIC_PLAYING; - //SDL_ResumeAudioStreamDevice(current_music->stream); - SDL_BindAudioStream(sdlAudioDevice, current_music->stream); -} - -void JA_StopMusic() -{ - if (!JA_musicEnabled) return; - if (!current_music || current_music->state == JA_MUSIC_INVALID) return; - - current_music->pos = 0; - current_music->state = JA_MUSIC_STOPPED; - //SDL_PauseAudioStreamDevice(current_music->stream); - SDL_DestroyAudioStream(current_music->stream); - current_music->stream = nullptr; - free(current_music->filename); - current_music->filename = nullptr; -} - -void JA_FadeOutMusic(const int milliseconds) -{ - if (!JA_musicEnabled) return; - if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return; - - fading = true; - fade_start_time = SDL_GetTicks(); - fade_duration = milliseconds; - fade_initial_volume = JA_musicVolume; -} - -JA_Music_state JA_GetMusicState() -{ - if (!JA_musicEnabled) return JA_MUSIC_DISABLED; - if (!current_music) return JA_MUSIC_INVALID; - - return current_music->state; -} - -void JA_DeleteMusic(JA_Music_t *music) -{ - if (current_music == music) current_music = nullptr; - SDL_free(music->buffer); - if (music->stream) SDL_DestroyAudioStream(music->stream); - delete music; -} - -float JA_SetMusicVolume(float volume) -{ - JA_musicVolume = SDL_clamp( volume, 0.0f, 1.0f ); - if (current_music) SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume); - return JA_musicVolume; -} - -void JA_SetMusicPosition(float value) -{ - if (!current_music) return; - current_music->pos = value * current_music->spec.freq; -} - -float JA_GetMusicPosition() -{ - if (!current_music) return 0; - return float(current_music->pos)/float(current_music->spec.freq); -} - -void JA_EnableMusic(const bool value) -{ - if ( !value && current_music && (current_music->state==JA_MUSIC_PLAYING) ) JA_StopMusic(); - - JA_musicEnabled = value; -} - - - - - -JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length) -{ - JA_Sound_t *sound = new JA_Sound_t(); - sound->buffer = buffer; - sound->length = length; - return sound; -} - -JA_Sound_t *JA_LoadSound(uint8_t* buffer, uint32_t size) -{ - JA_Sound_t *sound = new JA_Sound_t(); - SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size),1, &sound->spec, &sound->buffer, &sound->length); - - return sound; -} - -JA_Sound_t *JA_LoadSound(const char* filename) -{ - JA_Sound_t *sound = new JA_Sound_t(); - SDL_LoadWAV(filename, &sound->spec, &sound->buffer, &sound->length); - - return sound; -} - -int JA_PlaySound(JA_Sound_t *sound, const int loop, const int group) -{ - if (!JA_soundEnabled) return -1; - - int channel = 0; - while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) { channel++; } - if (channel == JA_MAX_SIMULTANEOUS_CHANNELS) channel = 0; - JA_StopChannel(channel); - - channels[channel].sound = sound; - channels[channel].times = loop; - channels[channel].pos = 0; - channels[channel].state = JA_CHANNEL_PLAYING; - channels[channel].stream = SDL_CreateAudioStream(&channels[channel].sound->spec, &JA_audioSpec); - SDL_PutAudioStreamData(channels[channel].stream, channels[channel].sound->buffer, channels[channel].sound->length); - SDL_SetAudioStreamGain(channels[channel].stream, JA_soundVolume[group]); - SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream); - - return channel; -} - -int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop, const int group) -{ - if (!JA_soundEnabled) return -1; - - if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return -1; - JA_StopChannel(channel); - - channels[channel].sound = sound; - channels[channel].times = loop; - channels[channel].pos = 0; - channels[channel].state = JA_CHANNEL_PLAYING; - channels[channel].stream = SDL_CreateAudioStream(&channels[channel].sound->spec, &JA_audioSpec); - SDL_PutAudioStreamData(channels[channel].stream, channels[channel].sound->buffer, channels[channel].sound->length); - SDL_SetAudioStreamGain(channels[channel].stream, JA_soundVolume[group]); - SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream); - - return channel; -} - -void JA_DeleteSound(JA_Sound_t *sound) -{ - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { - if (channels[i].sound == sound) JA_StopChannel(i); - } - SDL_free(sound->buffer); - delete sound; -} - -void JA_PauseChannel(const int channel) -{ - if (!JA_soundEnabled) return; - - if (channel == -1) - { - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) - if (channels[i].state == JA_CHANNEL_PLAYING) - { - channels[i].state = JA_CHANNEL_PAUSED; - //SDL_PauseAudioStreamDevice(channels[i].stream); - SDL_UnbindAudioStream(channels[i].stream); - } - } - else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) - { - if (channels[channel].state == JA_CHANNEL_PLAYING) - { - channels[channel].state = JA_CHANNEL_PAUSED; - //SDL_PauseAudioStreamDevice(channels[channel].stream); - SDL_UnbindAudioStream(channels[channel].stream); - } - } -} - -void JA_ResumeChannel(const int channel) -{ - if (!JA_soundEnabled) return; - - if (channel == -1) - { - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) - if (channels[i].state == JA_CHANNEL_PAUSED) - { - channels[i].state = JA_CHANNEL_PLAYING; - //SDL_ResumeAudioStreamDevice(channels[i].stream); - SDL_BindAudioStream(sdlAudioDevice, channels[i].stream); - } - } - else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) - { - if (channels[channel].state == JA_CHANNEL_PAUSED) - { - channels[channel].state = JA_CHANNEL_PLAYING; - //SDL_ResumeAudioStreamDevice(channels[channel].stream); - SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream); - } - } -} - -void JA_StopChannel(const int channel) -{ - if (!JA_soundEnabled) return; - - if (channel == -1) - { - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { - if (channels[i].state != JA_CHANNEL_FREE) SDL_DestroyAudioStream(channels[i].stream); - channels[i].stream = nullptr; - channels[i].state = JA_CHANNEL_FREE; - channels[i].pos = 0; - channels[i].sound = NULL; - } - } - else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) - { - if (channels[channel].state != JA_CHANNEL_FREE) SDL_DestroyAudioStream(channels[channel].stream); - channels[channel].stream = nullptr; - channels[channel].state = JA_CHANNEL_FREE; - channels[channel].pos = 0; - channels[channel].sound = NULL; - } -} - -JA_Channel_state JA_GetChannelState(const int channel) -{ - if (!JA_soundEnabled) return JA_SOUND_DISABLED; - - if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return JA_CHANNEL_INVALID; - - return channels[channel].state; -} - -float JA_SetSoundVolume(float volume, const int group) -{ - const float v = SDL_clamp( volume, 0.0f, 1.0f ); - for (int i = 0; i < JA_MAX_GROUPS; ++i) { - if (group==-1 || group==i) JA_soundVolume[i]=v; - } - - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) - if ( ((channels[i].state == JA_CHANNEL_PLAYING) || (channels[i].state == JA_CHANNEL_PAUSED)) && - ((group==-1) || (channels[i].group==group)) ) - SDL_SetAudioStreamGain(channels[i].stream, JA_soundVolume[i]); - - return v; -} - -void JA_EnableSound(const bool value) -{ - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) - { - if (channels[i].state == JA_CHANNEL_PLAYING) JA_StopChannel(i); - } - JA_soundEnabled = value; -} - -float JA_SetVolume(float volume) -{ - JA_SetSoundVolume(JA_SetMusicVolume(volume) / 2.0f); - - return JA_musicVolume; -} - -#endif \ No newline at end of file diff --git a/source/external/jail_audio.h b/source/external/jail_audio.h deleted file mode 100644 index 716b7f9..0000000 --- a/source/external/jail_audio.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once -#include - -enum JA_Channel_state { JA_CHANNEL_INVALID, JA_CHANNEL_FREE, JA_CHANNEL_PLAYING, JA_CHANNEL_PAUSED, JA_SOUND_DISABLED }; -enum JA_Music_state { JA_MUSIC_INVALID, JA_MUSIC_PLAYING, JA_MUSIC_PAUSED, JA_MUSIC_STOPPED, JA_MUSIC_DISABLED }; - -struct JA_Sound_t; -struct JA_Music_t; - -void JA_Update(); - -void JA_Init(const int freq, const SDL_AudioFormat format, const int num_channels); -void JA_Quit(); - -JA_Music_t *JA_LoadMusic(const char* filename); -JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length); -void JA_PlayMusic(JA_Music_t *music, const int loop = -1); -char *JA_GetMusicFilename(JA_Music_t *music = nullptr); -void JA_PauseMusic(); -void JA_ResumeMusic(); -void JA_StopMusic(); -void JA_FadeOutMusic(const int milliseconds); -JA_Music_state JA_GetMusicState(); -void JA_DeleteMusic(JA_Music_t *music); -float JA_SetMusicVolume(float volume); -void JA_SetMusicPosition(float value); -float JA_GetMusicPosition(); -void JA_EnableMusic(const bool value); - -JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length); -JA_Sound_t *JA_LoadSound(Uint8* buffer, Uint32 length); -JA_Sound_t *JA_LoadSound(const char* filename); -int JA_PlaySound(JA_Sound_t *sound, const int loop = 0, const int group=0); -int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop = 0, const int group=0); -void JA_PauseChannel(const int channel); -void JA_ResumeChannel(const int channel); -void JA_StopChannel(const int channel); -JA_Channel_state JA_GetChannelState(const int channel); -void JA_DeleteSound(JA_Sound_t *sound); -float JA_SetSoundVolume(float volume, const int group=0); -void JA_EnableSound(const bool value); - -float JA_SetVolume(float volume); diff --git a/source/game/gameplay/room_loader.cpp.yaml-cpp-backup b/source/game/gameplay/room_loader.cpp.yaml-cpp-backup deleted file mode 100644 index 3529496..0000000 --- a/source/game/gameplay/room_loader.cpp.yaml-cpp-backup +++ /dev/null @@ -1,297 +0,0 @@ -#include "room_loader.hpp" - -#include // Para exception -#include // Para cout, cerr -#include // Para YAML::Node, YAML::LoadFile - -#include "core/resources/resource_helper.hpp" // Para Resource::Helper -#include "utils/defines.hpp" // Para TILE_SIZE -#include "utils/utils.hpp" // Para stringToColor - -// Convierte room connection de YAML a formato con extensión -auto RoomLoader::convertRoomConnection(const std::string& value) -> std::string { - if (value == "null" || value.empty()) { - return "0"; - } - // "02" → "02.yaml" - return value + ".yaml"; -} - -// Convierte un tilemap 2D a vector 1D flat -auto RoomLoader::flattenTilemap(const std::vector>& tilemap_2d) -> std::vector { - std::vector tilemap_flat; - tilemap_flat.reserve(512); // 16 rows × 32 cols - - for (const auto& row : tilemap_2d) { - for (int tile : row) { - tilemap_flat.push_back(tile); - } - } - - return tilemap_flat; -} - -// Carga un archivo de room en formato YAML -auto RoomLoader::loadYAML(const std::string& file_path, bool verbose) -> Room::Data { - Room::Data room; - - // Extract filename for logging - const std::string FILE_NAME = file_path.substr(file_path.find_last_of("\\/") + 1); - - try { - // Load YAML file using ResourceHelper (supports both filesystem and pack) - auto file_data = Resource::Helper::loadFile(file_path); - - if (file_data.empty()) { - std::cerr << "Error: Unable to load file " << FILE_NAME << '\n'; - return room; - } - - // Parse YAML from string - std::string yaml_content(file_data.begin(), file_data.end()); - YAML::Node yaml = YAML::Load(yaml_content); - - // --- Parse room configuration --- - if (yaml["room"]) { - const YAML::Node& room_node = yaml["room"]; - - // Extract room number from filename (e.g., "01.yaml" → "01") - room.number = FILE_NAME.substr(0, FILE_NAME.find_last_of('.')); - - // Basic properties - if (room_node["name"]) { - room.name = room_node["name"].as(); - } - if (room_node["bgColor"]) { - room.bg_color = room_node["bgColor"].as(); - } - if (room_node["border"]) { - room.border_color = room_node["border"].as(); - } - if (room_node["tileSetFile"]) { - room.tile_set_file = room_node["tileSetFile"].as(); - } - - // Room connections - if (room_node["connections"]) { - const YAML::Node& conn = room_node["connections"]; - - if (conn["up"]) { - room.upper_room = convertRoomConnection(conn["up"].as("null")); - } else { - room.upper_room = "0"; - } - - if (conn["down"]) { - room.lower_room = convertRoomConnection(conn["down"].as("null")); - } else { - room.lower_room = "0"; - } - - if (conn["left"]) { - room.left_room = convertRoomConnection(conn["left"].as("null")); - } else { - room.left_room = "0"; - } - - if (conn["right"]) { - room.right_room = convertRoomConnection(conn["right"].as("null")); - } else { - room.right_room = "0"; - } - } - - // Item colors - if (room_node["itemColor1"]) { - room.item_color1 = room_node["itemColor1"].as("yellow"); - } else { - room.item_color1 = "yellow"; - } - - if (room_node["itemColor2"]) { - room.item_color2 = room_node["itemColor2"].as("magenta"); - } else { - room.item_color2 = "magenta"; - } - - // Conveyor belt direction - if (room_node["autoSurface"]) { - room.conveyor_belt_direction = room_node["autoSurface"].as(0); - } else { - room.conveyor_belt_direction = 0; - } - } - - // --- Parse tilemap --- - if (yaml["tilemap"]) { - const YAML::Node& tilemap_node = yaml["tilemap"]; - - // Read 2D array - std::vector> tilemap_2d; - tilemap_2d.reserve(16); - - for (const auto& row_node : tilemap_node) { - std::vector row; - row.reserve(32); - - for (const auto& tile_node : row_node) { - row.push_back(tile_node.as()); - } - - tilemap_2d.push_back(row); - } - - // Convert to 1D flat array - room.tile_map = flattenTilemap(tilemap_2d); - - if (verbose) { - std::cout << "Loaded tilemap: " << room.tile_map.size() << " tiles\n"; - } - } else { - std::cerr << "Warning: No tilemap found in " << FILE_NAME << '\n'; - } - - // --- Parse enemies --- - if (yaml["enemies"] && !yaml["enemies"].IsNull()) { - const YAML::Node& enemies_node = yaml["enemies"]; - - for (const auto& enemy_node : enemies_node) { - Enemy::Data enemy; - - // Animation path - if (enemy_node["animation"]) { - enemy.animation_path = enemy_node["animation"].as(); - } - - // Position (in tiles, convert to pixels) - if (enemy_node["position"]) { - const YAML::Node& pos = enemy_node["position"]; - if (pos["x"]) { - enemy.x = pos["x"].as() * TILE_SIZE; - } - if (pos["y"]) { - enemy.y = pos["y"].as() * TILE_SIZE; - } - } - - // Velocity (already in pixels/second) - if (enemy_node["velocity"]) { - const YAML::Node& vel = enemy_node["velocity"]; - if (vel["x"]) { - enemy.vx = vel["x"].as(); - } - if (vel["y"]) { - enemy.vy = vel["y"].as(); - } - } - - // Boundaries (in tiles, convert to pixels) - if (enemy_node["boundaries"]) { - const YAML::Node& bounds = enemy_node["boundaries"]; - if (bounds["x1"]) { - enemy.x1 = bounds["x1"].as() * TILE_SIZE; - } - if (bounds["y1"]) { - enemy.y1 = bounds["y1"].as() * TILE_SIZE; - } - if (bounds["x2"]) { - enemy.x2 = bounds["x2"].as() * TILE_SIZE; - } - if (bounds["y2"]) { - enemy.y2 = bounds["y2"].as() * TILE_SIZE; - } - } - - // Color - if (enemy_node["color"]) { - enemy.color = enemy_node["color"].as("white"); - } else { - enemy.color = "white"; - } - - // Optional fields - if (enemy_node["flip"]) { - enemy.flip = enemy_node["flip"].as(false); - } else { - enemy.flip = false; - } - - if (enemy_node["mirror"]) { - enemy.mirror = enemy_node["mirror"].as(false); - } else { - enemy.mirror = false; - } - - if (enemy_node["frame"]) { - enemy.frame = enemy_node["frame"].as(-1); - } else { - enemy.frame = -1; - } - - room.enemies.push_back(enemy); - } - - if (verbose) { - std::cout << "Loaded " << room.enemies.size() << " enemies\n"; - } - } - - // --- Parse items --- - if (yaml["items"] && !yaml["items"].IsNull()) { - const YAML::Node& items_node = yaml["items"]; - - for (const auto& item_node : items_node) { - Item::Data item; - - // Tileset file - if (item_node["tileSetFile"]) { - item.tile_set_file = item_node["tileSetFile"].as(); - } - - // Tile index - if (item_node["tile"]) { - item.tile = item_node["tile"].as(); - } - - // Position (in tiles, convert to pixels) - if (item_node["position"]) { - const YAML::Node& pos = item_node["position"]; - if (pos["x"]) { - item.x = pos["x"].as() * TILE_SIZE; - } - if (pos["y"]) { - item.y = pos["y"].as() * TILE_SIZE; - } - } - - // Counter - if (item_node["counter"]) { - item.counter = item_node["counter"].as(0); - } else { - item.counter = 0; - } - - // Colors (assigned from room defaults) - item.color1 = stringToColor(room.item_color1); - item.color2 = stringToColor(room.item_color2); - - room.items.push_back(item); - } - - if (verbose) { - std::cout << "Loaded " << room.items.size() << " items\n"; - } - } - - if (verbose) { - std::cout << "Room loaded successfully: " << FILE_NAME << '\n'; - } - - } catch (const YAML::Exception& e) { - std::cerr << "YAML parsing error in " << FILE_NAME << ": " << e.what() << '\n'; - } catch (const std::exception& e) { - std::cerr << "Error loading room " << FILE_NAME << ": " << e.what() << '\n'; - } - - return room; -} diff --git a/source/utils/utils.cpp b/source/utils/utils.cpp index dd3ae32..c6861a8 100644 --- a/source/utils/utils.cpp +++ b/source/utils/utils.cpp @@ -12,7 +12,6 @@ #include // Para pair #include "core/resources/resource_cache.hpp" // Para Resource -#include "external/jail_audio.h" // Para JA_GetMusicState, JA_Music_state, JA_PlayMusic // Calcula el cuadrado de la distancia entre dos puntos auto distanceSquared(int x1, int y1, int x2, int y2) -> double {