migrat jail_audio a un .hpp (segur que ja no funciona res)
This commit is contained in:
@@ -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 $<$<CONFIG:Debug>:${DEBUG_SOURCES}>)
|
||||
|
||||
@@ -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 $<$<CONFIG:Debug>:${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 $<$<CONFIG:RELEASE>:-Os -ffunction-sections -fdata-sections>)
|
||||
|
||||
# Definir _DEBUG en modo Debug
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE $<$<CONFIG:DEBUG>:_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})
|
||||
10
Makefile
10
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)
|
||||
|
||||
@@ -5,8 +5,14 @@
|
||||
#include <algorithm> // Para clamp
|
||||
#include <iostream> // 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
|
||||
|
||||
529
source/core/audio/jail_audio.hpp
Normal file
529
source/core/audio/jail_audio.hpp
Normal file
@@ -0,0 +1,529 @@
|
||||
#pragma once
|
||||
|
||||
// --- Includes ---
|
||||
#include <SDL3/SDL.h>
|
||||
#include <stdint.h> // Para uint32_t, uint8_t
|
||||
#include <stdio.h> // Para NULL, fseek, printf, fclose, fopen, fread, ftell, FILE, SEEK_END, SEEK_SET
|
||||
#include <stdlib.h> // Para free, malloc
|
||||
#include <string.h> // 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;
|
||||
}
|
||||
@@ -8,19 +8,19 @@
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <utility>
|
||||
|
||||
#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 {
|
||||
|
||||
|
||||
63
source/external/README.md
vendored
63
source/external/README.md
vendored
@@ -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 <version-tag> # 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
|
||||
|
||||
477
source/external/jail_audio.cpp
vendored
477
source/external/jail_audio.cpp
vendored
@@ -1,477 +0,0 @@
|
||||
#ifndef JA_USESDLMIXER
|
||||
#include "jail_audio.h"
|
||||
|
||||
#include <SDL3/SDL.h> // 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 <stdint.h> // Para uint32_t, uint8_t
|
||||
#include <stdio.h> // Para NULL, fseek, printf, fclose, fopen, fread, ftell, FILE, SEEK_END, SEEK_SET
|
||||
#include <stdlib.h> // Para free, malloc
|
||||
#include <string.h> // 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; 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;
|
||||
}
|
||||
|
||||
void JA_Quit()
|
||||
{
|
||||
if (!sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice);
|
||||
sdlAudioDevice = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
43
source/external/jail_audio.h
vendored
43
source/external/jail_audio.h
vendored
@@ -1,43 +0,0 @@
|
||||
#pragma once
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
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);
|
||||
@@ -1,297 +0,0 @@
|
||||
#include "room_loader.hpp"
|
||||
|
||||
#include <exception> // Para exception
|
||||
#include <iostream> // Para cout, cerr
|
||||
#include <yaml-cpp/yaml.h> // 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<std::vector<int>>& tilemap_2d) -> std::vector<int> {
|
||||
std::vector<int> 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<std::string>();
|
||||
}
|
||||
if (room_node["bgColor"]) {
|
||||
room.bg_color = room_node["bgColor"].as<std::string>();
|
||||
}
|
||||
if (room_node["border"]) {
|
||||
room.border_color = room_node["border"].as<std::string>();
|
||||
}
|
||||
if (room_node["tileSetFile"]) {
|
||||
room.tile_set_file = room_node["tileSetFile"].as<std::string>();
|
||||
}
|
||||
|
||||
// Room connections
|
||||
if (room_node["connections"]) {
|
||||
const YAML::Node& conn = room_node["connections"];
|
||||
|
||||
if (conn["up"]) {
|
||||
room.upper_room = convertRoomConnection(conn["up"].as<std::string>("null"));
|
||||
} else {
|
||||
room.upper_room = "0";
|
||||
}
|
||||
|
||||
if (conn["down"]) {
|
||||
room.lower_room = convertRoomConnection(conn["down"].as<std::string>("null"));
|
||||
} else {
|
||||
room.lower_room = "0";
|
||||
}
|
||||
|
||||
if (conn["left"]) {
|
||||
room.left_room = convertRoomConnection(conn["left"].as<std::string>("null"));
|
||||
} else {
|
||||
room.left_room = "0";
|
||||
}
|
||||
|
||||
if (conn["right"]) {
|
||||
room.right_room = convertRoomConnection(conn["right"].as<std::string>("null"));
|
||||
} else {
|
||||
room.right_room = "0";
|
||||
}
|
||||
}
|
||||
|
||||
// Item colors
|
||||
if (room_node["itemColor1"]) {
|
||||
room.item_color1 = room_node["itemColor1"].as<std::string>("yellow");
|
||||
} else {
|
||||
room.item_color1 = "yellow";
|
||||
}
|
||||
|
||||
if (room_node["itemColor2"]) {
|
||||
room.item_color2 = room_node["itemColor2"].as<std::string>("magenta");
|
||||
} else {
|
||||
room.item_color2 = "magenta";
|
||||
}
|
||||
|
||||
// Conveyor belt direction
|
||||
if (room_node["autoSurface"]) {
|
||||
room.conveyor_belt_direction = room_node["autoSurface"].as<int>(0);
|
||||
} else {
|
||||
room.conveyor_belt_direction = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Parse tilemap ---
|
||||
if (yaml["tilemap"]) {
|
||||
const YAML::Node& tilemap_node = yaml["tilemap"];
|
||||
|
||||
// Read 2D array
|
||||
std::vector<std::vector<int>> tilemap_2d;
|
||||
tilemap_2d.reserve(16);
|
||||
|
||||
for (const auto& row_node : tilemap_node) {
|
||||
std::vector<int> row;
|
||||
row.reserve(32);
|
||||
|
||||
for (const auto& tile_node : row_node) {
|
||||
row.push_back(tile_node.as<int>());
|
||||
}
|
||||
|
||||
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<std::string>();
|
||||
}
|
||||
|
||||
// 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<float>() * TILE_SIZE;
|
||||
}
|
||||
if (pos["y"]) {
|
||||
enemy.y = pos["y"].as<float>() * 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<float>();
|
||||
}
|
||||
if (vel["y"]) {
|
||||
enemy.vy = vel["y"].as<float>();
|
||||
}
|
||||
}
|
||||
|
||||
// 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<int>() * TILE_SIZE;
|
||||
}
|
||||
if (bounds["y1"]) {
|
||||
enemy.y1 = bounds["y1"].as<int>() * TILE_SIZE;
|
||||
}
|
||||
if (bounds["x2"]) {
|
||||
enemy.x2 = bounds["x2"].as<int>() * TILE_SIZE;
|
||||
}
|
||||
if (bounds["y2"]) {
|
||||
enemy.y2 = bounds["y2"].as<int>() * TILE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
// Color
|
||||
if (enemy_node["color"]) {
|
||||
enemy.color = enemy_node["color"].as<std::string>("white");
|
||||
} else {
|
||||
enemy.color = "white";
|
||||
}
|
||||
|
||||
// Optional fields
|
||||
if (enemy_node["flip"]) {
|
||||
enemy.flip = enemy_node["flip"].as<bool>(false);
|
||||
} else {
|
||||
enemy.flip = false;
|
||||
}
|
||||
|
||||
if (enemy_node["mirror"]) {
|
||||
enemy.mirror = enemy_node["mirror"].as<bool>(false);
|
||||
} else {
|
||||
enemy.mirror = false;
|
||||
}
|
||||
|
||||
if (enemy_node["frame"]) {
|
||||
enemy.frame = enemy_node["frame"].as<int>(-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<std::string>();
|
||||
}
|
||||
|
||||
// Tile index
|
||||
if (item_node["tile"]) {
|
||||
item.tile = item_node["tile"].as<int>();
|
||||
}
|
||||
|
||||
// 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<float>() * TILE_SIZE;
|
||||
}
|
||||
if (pos["y"]) {
|
||||
item.y = pos["y"].as<float>() * TILE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
// Counter
|
||||
if (item_node["counter"]) {
|
||||
item.counter = item_node["counter"].as<int>(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;
|
||||
}
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <utility> // 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 {
|
||||
|
||||
Reference in New Issue
Block a user