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
|
source/main.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# Fuentes de librerías de terceros
|
|
||||||
set(EXTERNAL_SOURCES
|
|
||||||
source/external/jail_audio.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
# Fuentes del sistema de renderizado
|
# Fuentes del sistema de renderizado
|
||||||
set(RENDERING_SOURCES
|
set(RENDERING_SOURCES
|
||||||
source/core/rendering/opengl/opengl_shader.cpp
|
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}")
|
message(STATUS "SDL3 encontrado: ${SDL3_INCLUDE_DIRS}")
|
||||||
|
|
||||||
# --- 2. AÑADIR EJECUTABLE ---
|
# --- 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
|
# Añadir fuentes de debug solo en modo Debug
|
||||||
target_sources(${PROJECT_NAME} PRIVATE $<$<CONFIG:Debug>:${DEBUG_SOURCES}>)
|
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/scenes/credits.cpp \
|
||||||
source/game/ui/notifier.cpp \
|
source/game/ui/notifier.cpp \
|
||||||
source/utils/utils.cpp \
|
source/utils/utils.cpp \
|
||||||
source/utils/delta_timer.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)
|
|
||||||
|
|
||||||
# All sources combined
|
# All sources combined
|
||||||
ALL_SOURCES := $(APP_SOURCES) $(YAML_CPP_SOURCES)
|
ALL_SOURCES := $(APP_SOURCES)
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# INCLUDES
|
# INCLUDES
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
INCLUDES := -Isource -Isource/external/yaml-cpp/include
|
INCLUDES := -Isource
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# COMPILER FLAGS (OS-specific)
|
# COMPILER FLAGS (OS-specific)
|
||||||
|
|||||||
@@ -5,8 +5,14 @@
|
|||||||
#include <algorithm> // Para clamp
|
#include <algorithm> // Para clamp
|
||||||
#include <iostream> // Para std::cout
|
#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 "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
|
#include "game/options.hpp" // Para AudioOptions, audio, MusicOptions
|
||||||
|
|
||||||
// Singleton
|
// 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,11 +8,11 @@
|
|||||||
#include <stdexcept> // Para runtime_error
|
#include <stdexcept> // Para runtime_error
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "core/audio/jail_audio.hpp" // Para JA_DeleteMusic, JA_DeleteSound, JA_Loa...
|
||||||
#include "core/rendering/screen.hpp" // Para Screen
|
#include "core/rendering/screen.hpp" // Para Screen
|
||||||
#include "core/rendering/text.hpp" // Para Text, loadTextFile
|
#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 "core/resources/resource_helper.hpp" // Para Helper
|
||||||
#include "external/jail_audio.h" // Para JA_DeleteMusic, JA_DeleteSound, JA_Loa...
|
#include "core/resources/resource_list.hpp" // Para List, List::Type
|
||||||
#include "game/defaults.hpp" // Para GameDefaults::VERSION
|
#include "game/defaults.hpp" // Para GameDefaults::VERSION
|
||||||
#include "game/gameplay/room.hpp" // Para RoomData, loadRoomFile, loadRoomTileFile
|
#include "game/gameplay/room.hpp" // Para RoomData, loadRoomFile, loadRoomTileFile
|
||||||
#include "game/options.hpp" // Para Options, OptionsGame, options
|
#include "game/options.hpp" // Para Options, OptionsGame, options
|
||||||
|
|||||||
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_image** | v2.x | Header-only | Image loading (PNG, GIF) |
|
||||||
| **stb_vorbis** | v1.x | Header-only | OGG Vorbis audio decoding |
|
| **stb_vorbis** | v1.x | Header-only | OGG Vorbis audio decoding |
|
||||||
| **json** | nlohmann/json | Header-only | JSON parsing (if needed) |
|
| **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
|
## Structure
|
||||||
|
|
||||||
@@ -21,11 +21,7 @@ external/
|
|||||||
├── stb_image.h # STB image loader (header-only)
|
├── stb_image.h # STB image loader (header-only)
|
||||||
├── stb_vorbis.h # STB Vorbis decoder (header-only)
|
├── stb_vorbis.h # STB Vorbis decoder (header-only)
|
||||||
├── json.hpp # nlohmann JSON library (header-only)
|
├── json.hpp # nlohmann JSON library (header-only)
|
||||||
└── yaml-cpp/ # YAML parser library
|
└── fkyaml_node.hpp # fkYAML parser library (header-only)
|
||||||
├── include/ # Public headers
|
|
||||||
│ └── yaml-cpp/
|
|
||||||
├── src/ # Source files (.cpp)
|
|
||||||
└── CMakeLists.txt # Build configuration
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Why Dependencies Are Here
|
## Why Dependencies Are Here
|
||||||
@@ -42,28 +38,30 @@ All dependencies are kept in `source/external/` for several reasons:
|
|||||||
|
|
||||||
### CMake (Recommended)
|
### CMake (Recommended)
|
||||||
```cmake
|
```cmake
|
||||||
# yaml-cpp
|
# Include path for header-only libraries (fkYAML, json, stb)
|
||||||
add_subdirectory(source/external/yaml-cpp)
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE yaml-cpp::yaml-cpp)
|
|
||||||
|
|
||||||
# Include path
|
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_SOURCE_DIR}/source")
|
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
|
### Makefile
|
||||||
See `Makefile.example` in the project root for a complete example.
|
See `Makefile.example` in the project root for a complete example.
|
||||||
|
|
||||||
```makefile
|
```makefile
|
||||||
CXXFLAGS = -I./source -I./source/external/yaml-cpp/include
|
CXXFLAGS = -I./source
|
||||||
# Compile yaml-cpp sources and link
|
# Compile jail_audio.cpp and link with your sources
|
||||||
```
|
```
|
||||||
|
|
||||||
### Manual Compilation
|
### Manual Compilation
|
||||||
```bash
|
```bash
|
||||||
# Compile yaml-cpp sources
|
# Compile jail_audio (only non-header-only library)
|
||||||
g++ -c source/external/yaml-cpp/src/*.cpp -I./source/external/yaml-cpp/include
|
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
|
g++ *.o -o game -lSDL3
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -75,35 +73,34 @@ g++ *.o -o game -lSDL3
|
|||||||
3. Include in code: `#include "external/library.h"`
|
3. Include in code: `#include "external/library.h"`
|
||||||
|
|
||||||
### Source Libraries
|
### Source Libraries
|
||||||
1. Create subdirectory: `source/external/library-name/`
|
1. Place source files (.cpp) directly in `source/external/`
|
||||||
2. Place headers in `library-name/include/`
|
2. Place header files (.h/.hpp) in `source/external/`
|
||||||
3. Place sources in `library-name/src/`
|
3. Add to CMakeLists.txt if needed:
|
||||||
4. Update CMakeLists.txt:
|
|
||||||
```cmake
|
```cmake
|
||||||
add_subdirectory(source/external/library-name)
|
# Most dependencies are header-only
|
||||||
|
# For source libraries, add to SOURCES list
|
||||||
```
|
```
|
||||||
|
|
||||||
## Updating Dependencies
|
## Updating Dependencies
|
||||||
|
|
||||||
### yaml-cpp
|
### fkYAML
|
||||||
To update yaml-cpp to a newer version:
|
To update fkYAML to a newer version:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd source/external
|
cd source/external
|
||||||
rm -rf yaml-cpp
|
# Download the single-header version from the releases page
|
||||||
git clone https://github.com/jbeder/yaml-cpp.git
|
curl -L -O https://github.com/fktn-k/fkYAML/releases/download/v3.x.x/fkyaml_node.hpp
|
||||||
cd yaml-cpp
|
|
||||||
git checkout <version-tag> # e.g., 0.8.0
|
|
||||||
rm -rf .git # Remove git history to reduce size
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Or download from: https://github.com/fktn-k/fkYAML/releases
|
||||||
|
|
||||||
### STB Libraries
|
### STB Libraries
|
||||||
Download latest from: https://github.com/nothings/stb
|
Download latest from: https://github.com/nothings/stb
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd source/external
|
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_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
|
## License Information
|
||||||
@@ -113,13 +110,13 @@ Each library has its own license:
|
|||||||
- **jail_audio** - Custom (see source files)
|
- **jail_audio** - Custom (see source files)
|
||||||
- **stb libraries** - Public Domain / MIT
|
- **stb libraries** - Public Domain / MIT
|
||||||
- **nlohmann/json** - MIT License
|
- **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
|
## Notes
|
||||||
|
|
||||||
- All dependencies are compatible with C++20
|
- All dependencies are compatible with C++20
|
||||||
- Header-only libraries require no compilation
|
- Most libraries are header-only and require no compilation
|
||||||
- Source libraries (yaml-cpp, jail_audio) are compiled as part of the main build
|
- Only jail_audio (source library) is compiled as part of the main build
|
||||||
- Keep dependencies minimal to reduce build times and binary size
|
- 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 <utility> // Para pair
|
||||||
|
|
||||||
#include "core/resources/resource_cache.hpp" // Para Resource
|
#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
|
// Calcula el cuadrado de la distancia entre dos puntos
|
||||||
auto distanceSquared(int x1, int y1, int x2, int y2) -> double {
|
auto distanceSquared(int x1, int y1, int x2, int y2) -> double {
|
||||||
|
|||||||
Reference in New Issue
Block a user