diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..d5307d1 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,80 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Coffee Crisis is a C++20 arcade game built with SDL2. The player controls a character defending the UPV (university) from bouncing coffee-ball enemies across 10 stages. Supports 1-2 players, keyboard and gamepad input, and multiple languages (Spanish, Basque, English). + +## Build Commands + +Dependencies: `libsdl2-dev` and `g++` (Linux) or `clang++` (macOS). + +```bash +# Linux +make linux # Release build → ./coffee_crisis +make linux_debug # Debug build (defines DEBUG and PAUSE) → ./coffee_crisis_debug + +# macOS +make macos # Release build with clang++ +make macos_debug # Debug build + +# Windows (MinGW) +make windows # Release build → coffee_crisis.exe +make windows_debug # Debug build + +# Release packaging +make linux_release # Builds and creates .tar.gz +make macos_release # Builds Intel + Apple Silicon .dmg files +make windows_release # Builds and creates .zip +``` + +There is also a CMakeLists.txt available as an alternative build system. + +There are no tests or linter configured. + +## Architecture + +All source code is in `source/`. The game uses a section-based architecture controlled by the **Director** class: + +- **Director** (`director.h/cpp`): Top-level controller. Initializes SDL, manages the window/renderer, and runs sections in sequence: Logo → Intro → Title → Game → Quit. Owns all shared objects (Screen, Input, Lang, Asset). +- **Game** (`game.h/cpp`): Core gameplay logic. Manages players, balloons (enemies), bullets, items, stages, menace level, and collision detection. Contains its own update/render loop plus sub-loops for pause and game over screens. +- **Screen** (`screen.h/cpp`): Rendering abstraction. Manages a virtual canvas (256×192) that gets scaled to the actual window. Handles fullscreen/windowed modes, border rendering, and fade effects. +- **Input** (`input.h/cpp`): Abstracts keyboard and gamepad input. +- **Asset** (`asset.h/cpp`): Resource file index. Files are registered with `add()` and retrieved by name with `get()`. All paths are relative to the executable. +- **Lang** (`lang.h/cpp`): i18n system loading text strings from files in `data/lang/`. + +### Sprite hierarchy + +- **Sprite** → base class for drawing from a PNG spritesheet +- **AnimatedSprite** → extends Sprite with frame-based animation (loaded from `.ani` files) +- **MovingSprite** → sprite with movement +- **SmartSprite** → sprite with autonomous behavior (score popups, thrown items) + +### Game entities + +- **Player** (`player.h/cpp`): Player character state and rendering +- **Balloon** (`balloon.h/cpp`): Enemy entities with multiple types and split-on-pop behavior +- **Bullet** (`bullet.h/cpp`): Projectiles fired by the player (left/center/right) +- **Item** (`item.h/cpp`): Collectible items (points, clock, coffee, power-ups) + +### Audio + +**jail_audio** (`jail_audio.h/cpp`): Custom audio library wrapping SDL2 audio. Uses stb_vorbis for OGG decoding. Provides `JA_*` functions for music and sound effects with channel-based mixing. + +### Key constants + +Defined in `const.h`: block size (8px), virtual canvas (256×192), play area bounds, section/subsection IDs, and color definitions. + +## Data Directory + +- `data/gfx/` — PNG spritesheets and `.ani` animation definition files +- `data/font/` — bitmap font files +- `data/music/` and `data/sound/` — audio assets +- `data/lang/` — language files (es_ES, ba_BA, en_UK) +- `data/config/` — gamecontroller DB, demo recording data +- `data/menu/` — menu definition files + +## Language + +Code comments and variable names are primarily in Spanish/Catalan-Valencian. README is in Catalan-Valencian. diff --git a/CMakeLists.txt b/CMakeLists.txt index bc007ef..8eb7f10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,22 +28,9 @@ if(NOT SOURCES) message(FATAL_ERROR "No se encontraron archivos fuente en ${DIR_SOURCES}. Verifica que el directorio existe y contiene archivos .cpp.") endif() -# Configuración de SDL2 -find_package(SDL2 REQUIRED) -if(SDL2_FOUND) - message(STATUS "SDL2 encontrado: ${SDL2_INCLUDE_DIRS}") - include_directories(${SDL2_INCLUDE_DIRS}) - link_directories(${SDL2_LIBDIR}) -else() - message(FATAL_ERROR "SDL2 no encontrado") -endif() - -# Incluye rutas de SDL2 obtenidas con pkg-config -include_directories(/usr/local/include /usr/local/include/SDL2) -link_directories(/usr/local/lib) - -# Definir las bibliotecas comunes -set(LIBS SDL2) +# Configuración de SDL3 +find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3) +message(STATUS "SDL3 encontrado: ${SDL3_INCLUDE_DIRS}") # Configuración común de salida de ejecutables en el directorio raíz set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}) @@ -55,17 +42,16 @@ add_executable(${PROJECT_NAME} ${SOURCES}) target_compile_definitions(${PROJECT_NAME} PRIVATE $<$:DEBUG VERBOSE>) # Enlazar bibliotecas -target_link_libraries(${PROJECT_NAME} ${LIBS}) +target_link_libraries(${PROJECT_NAME} PRIVATE SDL3::SDL3) # Configuración específica para cada plataforma if(WIN32) target_compile_definitions(${PROJECT_NAME} PRIVATE WINDOWS_BUILD) - target_link_libraries(${PROJECT_NAME} mingw32 gdi32 winmm imm32 ole32 version) + target_link_libraries(${PROJECT_NAME} PRIVATE mingw32 gdi32 winmm imm32 ole32 version) elseif(APPLE) target_compile_definitions(${PROJECT_NAME} PRIVATE MACOS_BUILD) # Configurar compilación para Apple Silicon set(CMAKE_OSX_ARCHITECTURES "arm64") elseif(UNIX AND NOT APPLE) target_compile_definitions(${PROJECT_NAME} PRIVATE LINUX_BUILD) - target_link_libraries(${PROJECT_NAME} ${LIBS}) endif() \ No newline at end of file diff --git a/Makefile b/Makefile index bbeaaa8..3f0bcc5 100644 --- a/Makefile +++ b/Makefile @@ -17,12 +17,12 @@ cpp_standard = c++20 windows: @echo off windres release/coffee.rc -O coff -o $(resource_file) - g++ $(source) $(resource_file) -std=$(cpp_standard) -Wall -Os -lmingw32 -lws2_32 -lSDL2main -lSDL2 -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows -o "$(executable).exe" + g++ $(source) $(resource_file) -std=$(cpp_standard) -Wall -Os -lmingw32 -lws2_32 -lSDL3 -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows -o "$(executable).exe" strip -s -R .comment -R .gnu.version "$(executable).exe" --strip-unneeded windows_debug: @echo off - g++ $(source) -D DEBUG -D PAUSE -std=$(cpp_standard) -Wall -Os -lmingw32 -lws2_32 -lSDL2main -lSDL2 -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows -o "$(executable)_debug.exe" + g++ $(source) -D DEBUG -D PAUSE -std=$(cpp_standard) -Wall -Os -lmingw32 -lws2_32 -lSDL3 -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows -o "$(executable)_debug.exe" strip -s -R .comment -R .gnu.version "$(executable)_debug.exe" --strip-unneeded windows_release: @@ -52,10 +52,10 @@ windows_release: powershell if (Test-Path "$(releaseFolder)") {Remove-Item "$(releaseFolder)" -Recurse -Force} macos: - clang++ $(source) -std=$(cpp_standard) -Wall -Os -lSDL2 -ffunction-sections -fdata-sections -o "$(executable)" + clang++ $(source) -std=$(cpp_standard) -Wall -Os -lSDL3 -ffunction-sections -fdata-sections -o "$(executable)" macos_debug: - clang++ $(source) -D DEBUG -D PAUSE -std=$(cpp_standard) -Wall -Os -lSDL2 -ffunction-sections -fdata-sections -o "$(executable)_debug" + clang++ $(source) -D DEBUG -D PAUSE -std=$(cpp_standard) -Wall -Os -lSDL3 -ffunction-sections -fdata-sections -o "$(executable)_debug" macos_release: # Remove data and possible data from previous builds @@ -106,11 +106,11 @@ macos_release: rm -rdf "$(releaseFolder)" linux: - g++ $(source) -std=$(cpp_standard) -Wall -Os -lSDL2 -ffunction-sections -fdata-sections -Wl,--gc-sections -o "$(executable)" + g++ $(source) -std=$(cpp_standard) -Wall -Os -lSDL3 -ffunction-sections -fdata-sections -Wl,--gc-sections -o "$(executable)" strip -s -R .comment -R .gnu.version "$(executable)" --strip-unneeded linux_debug: - g++ $(source) -D DEBUG -D PAUSE -std=$(cpp_standard) -Wall -Os -lSDL2 -ffunction-sections -fdata-sections -Wl,--gc-sections -o "$(executable)_debug" + g++ $(source) -D DEBUG -D PAUSE -std=$(cpp_standard) -Wall -Os -lSDL3 -ffunction-sections -fdata-sections -Wl,--gc-sections -o "$(executable)_debug" strip -s -R .comment -R .gnu.version "$(executable)_debug" --strip-unneeded linux_release: diff --git a/source/animatedsprite.h b/source/animatedsprite.h index f0d5c74..f66ccab 100644 --- a/source/animatedsprite.h +++ b/source/animatedsprite.h @@ -1,8 +1,6 @@ #pragma once -#include // for SDL_Rect -#include // for SDL_Renderer -#include // for Uint8 +#include #include // for string, basic_string #include // for vector #include "movingsprite.h" // for MovingSprite diff --git a/source/asset.cpp b/source/asset.cpp index d3a4823..e32a8d2 100644 --- a/source/asset.cpp +++ b/source/asset.cpp @@ -1,6 +1,5 @@ #include "asset.h" -#include // for SDL_RWFromFile, SDL_RWclose, SDL_RWops -#include // for SDL_max +#include #include // for size_t #include // for basic_ostream, operator<<, cout, endl @@ -117,13 +116,13 @@ bool Asset::checkFile(std::string path) // Comprueba si existe el fichero const std::string filename = path.substr(path.find_last_of("\\/") + 1); - SDL_RWops *file = SDL_RWFromFile(path.c_str(), "rb"); + SDL_IOStream *file = SDL_IOFromFile(path.c_str(), "rb"); if (file != nullptr) { result = "OK"; success = true; - SDL_RWclose(file); + SDL_CloseIO(file); } if (verbose) diff --git a/source/balloon.h b/source/balloon.h index 3264ab2..35c6c44 100644 --- a/source/balloon.h +++ b/source/balloon.h @@ -1,7 +1,6 @@ #pragma once -#include // for SDL_Renderer -#include // for Uint8, Uint16, Uint32 +#include #include // for string #include // for vector #include "utils.h" // for circle_t diff --git a/source/bullet.h b/source/bullet.h index 0956948..1f7f7d3 100644 --- a/source/bullet.h +++ b/source/bullet.h @@ -1,7 +1,6 @@ #pragma once -#include // for SDL_Renderer -#include // for Uint8 +#include #include "utils.h" // for circle_t class Sprite; class Texture; diff --git a/source/const.h b/source/const.h index 3ebc977..6fef82e 100644 --- a/source/const.h +++ b/source/const.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "utils.h" #include "lang.h" diff --git a/source/director.cpp b/source/director.cpp index 76102da..efdc1a1 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -1,13 +1,5 @@ #include "director.h" -#include // for SDL_Init, SDL_Quit, SDL_INIT_EV... -#include // for AUDIO_S16 -#include // for SDL_BLENDMODE_BLEND -#include // for SDL_GetError -#include // for SDL_CONTROLLER_BUTTON_B, SDL_CO... -#include // for SDL_SetHint, SDL_HINT_RENDER_SC... -#include // for SDL_SCANCODE_ESCAPE, SDL_SCANCO... -#include // for Uint32 -#include // for SDL_GetTicks +#include #include // for errno, EEXIST, EACCES, ENAMETOO... #include // for printf, perror #include // for strcmp @@ -24,7 +16,7 @@ #include "game.h" // for Game #include "input.h" // for Input, inputs_e, INPUT_USE_GAME... #include "intro.h" // for Intro -#include "jail_audio.h" // for JA_Init +#include "jail_audio.hpp" // for JA_Init #include "lang.h" // for Lang, MAX_LANGUAGES, ba_BA, en_UK #include "logo.h" // for Logo #include "screen.h" // for FILTER_NEAREST, Screen, FILTER_... @@ -133,30 +125,30 @@ void Director::initInput() input->bindKey(input_window_fullscreen, SDL_SCANCODE_F3); // Mando - Movimiento del jugador - input->bindGameControllerButton(input_up, SDL_CONTROLLER_BUTTON_DPAD_UP); - input->bindGameControllerButton(input_down, SDL_CONTROLLER_BUTTON_DPAD_DOWN); - input->bindGameControllerButton(input_left, SDL_CONTROLLER_BUTTON_DPAD_LEFT); - input->bindGameControllerButton(input_right, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); - input->bindGameControllerButton(input_fire_left, SDL_CONTROLLER_BUTTON_X); - input->bindGameControllerButton(input_fire_center, SDL_CONTROLLER_BUTTON_Y); - input->bindGameControllerButton(input_fire_right, SDL_CONTROLLER_BUTTON_B); + input->bindGameControllerButton(input_up, SDL_GAMEPAD_BUTTON_DPAD_UP); + input->bindGameControllerButton(input_down, SDL_GAMEPAD_BUTTON_DPAD_DOWN); + input->bindGameControllerButton(input_left, SDL_GAMEPAD_BUTTON_DPAD_LEFT); + input->bindGameControllerButton(input_right, SDL_GAMEPAD_BUTTON_DPAD_RIGHT); + input->bindGameControllerButton(input_fire_left, SDL_GAMEPAD_BUTTON_WEST); + input->bindGameControllerButton(input_fire_center, SDL_GAMEPAD_BUTTON_NORTH); + input->bindGameControllerButton(input_fire_right, SDL_GAMEPAD_BUTTON_EAST); // Mando - Otros - input->bindGameControllerButton(input_accept, SDL_CONTROLLER_BUTTON_B); - input->bindGameControllerButton(input_cancel, SDL_CONTROLLER_BUTTON_A); + input->bindGameControllerButton(input_accept, SDL_GAMEPAD_BUTTON_EAST); + input->bindGameControllerButton(input_cancel, SDL_GAMEPAD_BUTTON_SOUTH); #ifdef GAME_CONSOLE - input->bindGameControllerButton(input_pause, SDL_CONTROLLER_BUTTON_BACK); - input->bindGameControllerButton(input_exit, SDL_CONTROLLER_BUTTON_START); + input->bindGameControllerButton(input_pause, SDL_GAMEPAD_BUTTON_BACK); + input->bindGameControllerButton(input_exit, SDL_GAMEPAD_BUTTON_START); #else - input->bindGameControllerButton(input_pause, SDL_CONTROLLER_BUTTON_START); - input->bindGameControllerButton(input_exit, SDL_CONTROLLER_BUTTON_BACK); + input->bindGameControllerButton(input_pause, SDL_GAMEPAD_BUTTON_START); + input->bindGameControllerButton(input_exit, SDL_GAMEPAD_BUTTON_BACK); #endif } // Inicializa JailAudio void Director::initJailAudio() { - JA_Init(48000, AUDIO_S16, 2); + JA_Init(48000, SDL_AUDIO_S16, 2); } // Arranca SDL y crea la ventana @@ -166,8 +158,7 @@ bool Director::initSDL() bool success = true; // Inicializa SDL - if (SDL_Init(SDL_INIT_EVERYTHING) < 0) - // if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER | SDL_INIT_AUDIO) < 0) + if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD)) { if (options->console) { @@ -180,15 +171,6 @@ bool Director::initSDL() // Inicia el generador de numeros aleatorios std::srand(static_cast(SDL_GetTicks())); - // Establece el filtro de la textura - if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, std::to_string(options->filter).c_str())) - { - if (options->console) - { - std::cout << "Warning: Nearest texture filtering not enabled!\n"; - } - } - // Crea la ventana int incW = 0; int incH = 0; @@ -197,7 +179,7 @@ bool Director::initSDL() incW = options->borderWidth * 2; incH = options->borderHeight * 2; } - window = SDL_CreateWindow(WINDOW_CAPTION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (options->gameWidth + incW) * options->windowSize, (options->gameHeight + incH) * options->windowSize, SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI); + window = SDL_CreateWindow(WINDOW_CAPTION, (options->gameWidth + incW) * options->windowSize, (options->gameHeight + incH) * options->windowSize, 0); if (window == nullptr) { if (options->console) @@ -208,16 +190,10 @@ bool Director::initSDL() } else { - // Crea un renderizador para la ventana. El vsync se activa en funcion de las opciones - // Crea un renderizador para la ventana. El vsync se activa en funcion de las opciones - // Uint32 flags = SDL_RENDERER_SOFTWARE; - // Uint32 flags = SDL_RENDERER_ACCELERATED; - Uint32 flags = 0; - if (options->vSync) - { - flags = flags | SDL_RENDERER_PRESENTVSYNC; - } - renderer = SDL_CreateRenderer(window, -1, flags); + SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); + + // Crea un renderizador para la ventana + renderer = SDL_CreateRenderer(window, NULL); if (renderer == nullptr) { @@ -229,11 +205,17 @@ bool Director::initSDL() } else { + // Activa vsync si es necesario + if (options->vSync) + { + SDL_SetRenderVSync(renderer, 1); + } + // Inicializa el color de renderizado SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF); // Establece el tamaño del buffer de renderizado - SDL_RenderSetLogicalSize(renderer, options->gameWidth, options->gameHeight); + SDL_SetRenderLogicalPresentation(renderer, options->gameWidth, options->gameHeight, SDL_LOGICAL_PRESENTATION_LETTERBOX); // Establece el modo de mezcla SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); @@ -549,10 +531,7 @@ bool Director::loadConfigFile() } // Normaliza los valores - const bool a = options->videoMode == 0; - const bool b = options->videoMode == SDL_WINDOW_FULLSCREEN; - const bool c = options->videoMode == SDL_WINDOW_FULLSCREEN_DESKTOP; - if (!(a || b || c)) + if (options->videoMode != 0 && options->videoMode != SDL_WINDOW_FULLSCREEN) { options->videoMode = 0; } @@ -605,11 +584,6 @@ bool Director::saveConfigFile() file << "videoMode=SDL_WINDOW_FULLSCREEN\n"; } - else if (options->videoMode == SDL_WINDOW_FULLSCREEN_DESKTOP) - { - file << "videoMode=SDL_WINDOW_FULLSCREEN_DESKTOP\n"; - } - file << "windowSize=" + std::to_string(options->windowSize) + "\n"; if (options->filter == FILTER_NEAREST) @@ -703,11 +677,7 @@ bool Director::setOptions(options_t *options, std::string var, std::string value // Opciones de video if (var == "videoMode") { - if (value == "SDL_WINDOW_FULLSCREEN_DESKTOP") - { - options->videoMode = SDL_WINDOW_FULLSCREEN_DESKTOP; - } - else if (value == "SDL_WINDOW_FULLSCREEN") + if (value == "SDL_WINDOW_FULLSCREEN" || value == "SDL_WINDOW_FULLSCREEN_DESKTOP") { options->videoMode = SDL_WINDOW_FULLSCREEN; } diff --git a/source/director.h b/source/director.h index 3a7926f..5ebf7fe 100644 --- a/source/director.h +++ b/source/director.h @@ -1,7 +1,6 @@ #pragma once -#include // for SDL_Renderer -#include // for SDL_Window +#include #include // for string, basic_string class Asset; class Game; diff --git a/source/fade.cpp b/source/fade.cpp index 6d46b52..afd8cb2 100644 --- a/source/fade.cpp +++ b/source/fade.cpp @@ -1,7 +1,5 @@ #include "fade.h" -#include // for SDL_GetError -#include // for SDL_PIXELFORMAT_RGBA8888 -#include // for SDL_Delay +#include #include // for rand #include // for char_traits, basic_ostream, operator<< #include "const.h" // for GAMECANVAS_HEIGHT, GAMECANVAS_WIDTH @@ -45,7 +43,8 @@ void Fade::render() switch (mFadeType) { case FADE_FULLSCREEN: - mRect1 = {0, 0, GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT}; + { + SDL_FRect fRect1 = {0, 0, (float)GAMECANVAS_WIDTH, (float)GAMECANVAS_HEIGHT}; for (int i = 0; i < 256; i += 4) { @@ -53,10 +52,10 @@ void Fade::render() SDL_SetRenderTarget(mRenderer, nullptr); // Copia el backbuffer con la imagen que había al renderizador - SDL_RenderCopy(mRenderer, mBackbuffer, nullptr, nullptr); + SDL_RenderTexture(mRenderer, mBackbuffer, nullptr, nullptr); SDL_SetRenderDrawColor(mRenderer, mR, mG, mB, i); - SDL_RenderFillRect(mRenderer, &mRect1); + SDL_RenderFillRect(mRenderer, &fRect1); // Vuelca el renderizador en pantalla SDL_RenderPresent(mRenderer); @@ -71,28 +70,32 @@ void Fade::render() SDL_SetRenderDrawColor(mRenderer, mR, mG, mB, 255); SDL_RenderClear(mRenderer); break; + } case FADE_CENTER: - mRect1 = {0, 0, GAMECANVAS_WIDTH, 0}; - mRect2 = {0, 0, GAMECANVAS_WIDTH, 0}; + { + SDL_FRect fR1 = {0, 0, (float)GAMECANVAS_WIDTH, 0}; + SDL_FRect fR2 = {0, 0, (float)GAMECANVAS_WIDTH, 0}; SDL_SetRenderDrawColor(mRenderer, mR, mG, mB, 64); for (int i = 0; i < mCounter; i++) { - mRect1.h = mRect2.h = i * 4; - mRect2.y = GAMECANVAS_HEIGHT - (i * 4); + fR1.h = fR2.h = (float)(i * 4); + fR2.y = (float)(GAMECANVAS_HEIGHT - (i * 4)); - SDL_RenderFillRect(mRenderer, &mRect1); - SDL_RenderFillRect(mRenderer, &mRect2); + SDL_RenderFillRect(mRenderer, &fR1); + SDL_RenderFillRect(mRenderer, &fR2); } if ((mCounter * 4) > GAMECANVAS_HEIGHT) mFinished = true; break; + } case FADE_RANDOM_SQUARE: - mRect1 = {0, 0, 32, 32}; + { + SDL_FRect fRs = {0, 0, 32, 32}; for (Uint16 i = 0; i < 50; i++) { @@ -105,21 +108,22 @@ void Fade::render() // Dibujamos sobre el backbuffer SDL_SetRenderTarget(mRenderer, mBackbuffer); - mRect1.x = rand() % (GAMECANVAS_WIDTH - mRect1.w); - mRect1.y = rand() % (GAMECANVAS_HEIGHT - mRect1.h); - SDL_RenderFillRect(mRenderer, &mRect1); + fRs.x = (float)(rand() % (GAMECANVAS_WIDTH - 32)); + fRs.y = (float)(rand() % (GAMECANVAS_HEIGHT - 32)); + SDL_RenderFillRect(mRenderer, &fRs); // Volvemos a usar el renderizador de forma normal SDL_SetRenderTarget(mRenderer, nullptr); // Copiamos el backbuffer al renderizador - SDL_RenderCopy(mRenderer, mBackbuffer, nullptr, nullptr); + SDL_RenderTexture(mRenderer, mBackbuffer, nullptr, nullptr); // Volcamos el renderizador en pantalla SDL_RenderPresent(mRenderer); SDL_Delay(100); } break; + } default: break; diff --git a/source/fade.h b/source/fade.h index aafb854..a6cb678 100644 --- a/source/fade.h +++ b/source/fade.h @@ -1,8 +1,6 @@ #pragma once -#include // for SDL_Rect -#include // for SDL_Renderer, SDL_Texture -#include // for Uint8, Uint16 +#include // Tipos de fundido constexpr int FADE_FULLSCREEN = 0; diff --git a/source/game.cpp b/source/game.cpp index 2b1257b..2d7976d 100644 --- a/source/game.cpp +++ b/source/game.cpp @@ -1,8 +1,5 @@ #include "game.h" -#include // for SDL_GetError -#include // for SDL_RWFromFile, SDL_RWclose, SDL_RWwrite -#include // for SDL_GetTicks, SDL_Delay -#include // for SDL_WINDOWEVENT_FOCUS_LOST +#include #include // for rand #include // for max, min #include // for basic_ifstream @@ -14,7 +11,7 @@ #include "fade.h" // for Fade, FADE_CENTER #include "input.h" // for inputs_e, Input, REPEAT_TRUE, REPEAT_FALSE #include "item.h" // for Item, ITEM_COFFEE_MACHINE, ITEM_CLOCK -#include "jail_audio.h" // for JA_PlaySound, JA_DeleteSound, JA_LoadSound +#include "jail_audio.hpp" // for JA_PlaySound, JA_DeleteSound, JA_LoadSound #include "lang.h" // for Lang #include "menu.h" // for Menu #include "movingsprite.h" // for MovingSprite @@ -624,7 +621,7 @@ bool Game::loadScoreFile() bool success = true; const std::string p = asset->get("score.bin"); const std::string filename = p.substr(p.find_last_of("\\/") + 1); - SDL_RWops *file = SDL_RWFromFile(p.c_str(), "r+b"); + SDL_IOStream *file = SDL_IOFromFile(p.c_str(), "r+b"); // El fichero no existe if (file == nullptr) @@ -635,7 +632,7 @@ bool Game::loadScoreFile() } // Creamos el fichero para escritura - file = SDL_RWFromFile(p.c_str(), "w+b"); + file = SDL_IOFromFile(p.c_str(), "w+b"); if (file != nullptr) { if (options->console) @@ -647,11 +644,11 @@ bool Game::loadScoreFile() for (int i = 0; i < TOTAL_SCORE_DATA; ++i) { scoreDataFile[i] = 0; - SDL_RWwrite(file, &scoreDataFile[i], sizeof(Uint32), 1); + SDL_WriteIO(file, &scoreDataFile[i], sizeof(Uint32)); } // Cerramos el fichero - SDL_RWclose(file); + SDL_CloseIO(file); } else { @@ -671,10 +668,10 @@ bool Game::loadScoreFile() std::cout << "Reading file " << filename.c_str() << std::endl; } for (int i = 0; i < TOTAL_SCORE_DATA; ++i) - SDL_RWread(file, &scoreDataFile[i], sizeof(Uint32), 1); + SDL_ReadIO(file, &scoreDataFile[i], sizeof(Uint32)); // Cierra el fichero - SDL_RWclose(file); + SDL_CloseIO(file); } // Establece el valor de la máxima puntuación a partir del vector con los datos @@ -702,7 +699,7 @@ bool Game::loadDemoFile() bool success = true; const std::string p = asset->get("demo.bin"); const std::string filename = p.substr(p.find_last_of("\\/") + 1); - SDL_RWops *file = SDL_RWFromFile(p.c_str(), "r+b"); + SDL_IOStream *file = SDL_IOFromFile(p.c_str(), "r+b"); // El fichero no existe if (file == nullptr) @@ -713,7 +710,7 @@ bool Game::loadDemoFile() } // Creamos el fichero para escritura - file = SDL_RWFromFile(p.c_str(), "w+b"); + file = SDL_IOFromFile(p.c_str(), "w+b"); if (file != nullptr) { if (options->console) @@ -731,11 +728,11 @@ bool Game::loadDemoFile() demo.keys.fireLeft = 0; demo.keys.fireRight = 0; demo.dataFile[i] = demo.keys; - SDL_RWwrite(file, &demo.dataFile[i], sizeof(demoKeys_t), 1); + SDL_WriteIO(file, &demo.dataFile[i], sizeof(demoKeys_t)); } // Cerramos el fichero - SDL_RWclose(file); + SDL_CloseIO(file); } else { @@ -755,10 +752,10 @@ bool Game::loadDemoFile() std::cout << "Reading file " << filename.c_str() << std::endl; } for (int i = 0; i < TOTAL_DEMO_DATA; ++i) - SDL_RWread(file, &demo.dataFile[i], sizeof(demoKeys_t), 1); + SDL_ReadIO(file, &demo.dataFile[i], sizeof(demoKeys_t)); // Cierra el fichero - SDL_RWclose(file); + SDL_CloseIO(file); } return success; @@ -770,13 +767,13 @@ bool Game::saveScoreFile() bool success = true; const std::string p = asset->get("score.bin"); const std::string filename = p.substr(p.find_last_of("\\/") + 1); - SDL_RWops *file = SDL_RWFromFile(p.c_str(), "w+b"); + SDL_IOStream *file = SDL_IOFromFile(p.c_str(), "w+b"); if (file != nullptr) { // Guardamos los datos for (int i = 0; i < TOTAL_SCORE_DATA; ++i) { - SDL_RWwrite(file, &scoreDataFile[i], sizeof(Uint32), 1); + SDL_WriteIO(file, &scoreDataFile[i], sizeof(Uint32)); } if (options->console) @@ -785,7 +782,7 @@ bool Game::saveScoreFile() } // Cerramos el fichero - SDL_RWclose(file); + SDL_CloseIO(file); } else { @@ -805,13 +802,13 @@ bool Game::saveDemoFile() const std::string filename = p.substr(p.find_last_of("\\/") + 1); if (demo.recording) { - SDL_RWops *file = SDL_RWFromFile(p.c_str(), "w+b"); + SDL_IOStream *file = SDL_IOFromFile(p.c_str(), "w+b"); if (file != nullptr) { // Guardamos los datos for (int i = 0; i < TOTAL_DEMO_DATA; ++i) { - SDL_RWwrite(file, &demo.dataFile[i], sizeof(demoKeys_t), 1); + SDL_WriteIO(file, &demo.dataFile[i], sizeof(demoKeys_t)); } if (options->console) @@ -820,7 +817,7 @@ bool Game::saveDemoFile() } // Cerramos el fichero - SDL_RWclose(file); + SDL_CloseIO(file); } else { @@ -1679,12 +1676,12 @@ void Game::renderScoreBoard() { // Pinta el fondo del marcador del color de la dificultad SDL_SetRenderDrawColor(renderer, difficultyColor.r, difficultyColor.g, difficultyColor.b, 255); } - SDL_Rect rect = {0, 160, 256, 32}; - SDL_RenderFillRect(renderer, &rect); + SDL_FRect fRect = {0, 160, 256, 32}; + SDL_RenderFillRect(renderer, &fRect); // Dibuja la linea que separa el marcador de la zona de juego SDL_SetRenderDrawColor(renderer, 13, 26, 43, 255); - SDL_RenderDrawLine(renderer, 0, 160, 255, 160); + SDL_RenderLine(renderer, 0, 160, 255, 160); // Anclas para los elementos const int offset1 = 162; @@ -1867,27 +1864,27 @@ void Game::renderDeathFade(int counter) if (counter < 150) { // 192 / 6 = 32, 6 cuadrados de 32 pixeles - SDL_Rect rect[12]; - Uint8 h = counter / 3; + SDL_FRect rect[12]; + float h = (float)(counter / 3); for (int i = 0; i < 12; ++i) { rect[i].x = 0; - rect[i].y = i * 16; - rect[i].w = GAMECANVAS_WIDTH; + rect[i].y = (float)(i * 16); + rect[i].w = (float)GAMECANVAS_WIDTH; if (i == 0) { rect[i].h = h; } else { - rect[i].h = std::max(rect[i - 1].h - 3, 0); + rect[i].h = std::max(rect[i - 1].h - 3.0f, 0.0f); } SDL_RenderFillRect(renderer, &rect[i]); } } else { - SDL_Rect rect = {0, 0, GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT}; + SDL_FRect rect = {0, 0, (float)GAMECANVAS_WIDTH, (float)GAMECANVAS_HEIGHT}; SDL_RenderFillRect(renderer, &rect); } } @@ -2773,6 +2770,9 @@ void Game::updateEnemyDeployCounter() // Actualiza el juego void Game::update() { + // Actualiza el audio + JA_Update(); + // Comprueba que la diferencia de ticks sea mayor a la velocidad del juego if (SDL_GetTicks() - ticks > ticksSpeed) { @@ -3581,12 +3581,12 @@ void Game::updateGameOverScreen() while (SDL_PollEvent(eventHandler) != 0) { // Evento de salida de la aplicación - if (eventHandler->type == SDL_QUIT) + if (eventHandler->type == SDL_EVENT_QUIT) { section->name = SECTION_PROG_QUIT; break; } - else if (eventHandler->type == SDL_KEYDOWN && eventHandler->key.repeat == 0) + else if (eventHandler->type == SDL_EVENT_KEY_DOWN && eventHandler->key.repeat == 0) { if (gameCompleted) { @@ -3842,24 +3842,21 @@ void Game::checkEvents() while (SDL_PollEvent(eventHandler) != 0) { // Evento de salida de la aplicación - if (eventHandler->type == SDL_QUIT) + if (eventHandler->type == SDL_EVENT_QUIT) { section->name = SECTION_PROG_QUIT; break; } - else if (eventHandler->type == SDL_WINDOWEVENT) + else if (eventHandler->type == SDL_EVENT_WINDOW_FOCUS_LOST) { - if (eventHandler->window.event == SDL_WINDOWEVENT_FOCUS_LOST) - { - section->subsection = SUBSECTION_GAME_PAUSE; - } + section->subsection = SUBSECTION_GAME_PAUSE; } #ifdef PAUSE - else if (eventHandler->type == SDL_KEYDOWN) + else if (eventHandler->type == SDL_EVENT_KEY_DOWN) { - if (eventHandler->key.keysym.scancode == SDL_SCANCODE_P) + if (eventHandler->key.scancode == SDL_SCANCODE_P) { pause = !pause; } diff --git a/source/game.h b/source/game.h index 6dc6751..d674678 100644 --- a/source/game.h +++ b/source/game.h @@ -1,9 +1,6 @@ #pragma once -#include // for SDL_Event -#include // for SDL_Rect -#include // for SDL_Renderer -#include // for Uint8, Uint16, Uint32 +#include #include // for string, basic_string #include // for vector #include "utils.h" // for demoKeys_t, color_t diff --git a/source/input.cpp b/source/input.cpp index 353d894..713a7e1 100644 --- a/source/input.cpp +++ b/source/input.cpp @@ -1,9 +1,5 @@ #include "input.h" -#include // for SDL_INIT_GAMECONTROLLER, SDL_InitSubS... -#include // for SDL_GetError -#include // for SDL_ENABLE -#include // for SDL_NumJoysticks -#include // for SDL_GetKeyboardState +#include #include // for basic_ostream, operator<<, cout, basi... // Constructor @@ -19,7 +15,7 @@ Input::Input(std::string file) keyBindings.resize(input_number_of_inputs, kb); GameControllerBindings_t gcb; - gcb.button = SDL_CONTROLLER_BUTTON_INVALID; + gcb.button = SDL_GAMEPAD_BUTTON_INVALID; gcb.active = false; gameControllerBindings.resize(input_number_of_inputs, gcb); @@ -43,7 +39,7 @@ void Input::bindKey(Uint8 input, SDL_Scancode code) } // Asigna inputs a botones del mando -void Input::bindGameControllerButton(Uint8 input, SDL_GameControllerButton button) +void Input::bindGameControllerButton(Uint8 input, SDL_GamepadButton button) { gameControllerBindings[input].button = button; } @@ -66,11 +62,11 @@ bool Input::checkInput(Uint8 input, bool repeat, int device, int index) if (device == INPUT_USE_KEYBOARD || device == INPUT_USE_ANY) { - const Uint8 *keyStates = SDL_GetKeyboardState(nullptr); + const bool *keyStates = SDL_GetKeyboardState(nullptr); if (repeat) { - if (keyStates[keyBindings[input].scancode] != 0) + if (keyStates[keyBindings[input].scancode]) { successKeyboard = true; } @@ -83,7 +79,7 @@ bool Input::checkInput(Uint8 input, bool repeat, int device, int index) { if (!keyBindings[input].active) { - if (keyStates[keyBindings[input].scancode] != 0) + if (keyStates[keyBindings[input].scancode]) { keyBindings[input].active = true; successKeyboard = true; @@ -95,7 +91,7 @@ bool Input::checkInput(Uint8 input, bool repeat, int device, int index) } else { - if (keyStates[keyBindings[input].scancode] == 0) + if (!keyStates[keyBindings[input].scancode]) { keyBindings[input].active = false; successKeyboard = false; @@ -113,7 +109,7 @@ bool Input::checkInput(Uint8 input, bool repeat, int device, int index) { if (repeat) { - if (SDL_GameControllerGetButton(connectedControllers[index], gameControllerBindings[input].button) != 0) + if (SDL_GetGamepadButton(connectedControllers[index], gameControllerBindings[input].button)) { successGameController = true; } @@ -126,7 +122,7 @@ bool Input::checkInput(Uint8 input, bool repeat, int device, int index) { if (!gameControllerBindings[input].active) { - if (SDL_GameControllerGetButton(connectedControllers[index], gameControllerBindings[input].button) != 0) + if (SDL_GetGamepadButton(connectedControllers[index], gameControllerBindings[input].button)) { gameControllerBindings[input].active = true; successGameController = true; @@ -138,7 +134,7 @@ bool Input::checkInput(Uint8 input, bool repeat, int device, int index) } else { - if (SDL_GameControllerGetButton(connectedControllers[index], gameControllerBindings[input].button) == 0) + if (!SDL_GetGamepadButton(connectedControllers[index], gameControllerBindings[input].button)) { gameControllerBindings[input].active = false; successGameController = false; @@ -164,11 +160,11 @@ bool Input::checkAnyInput(int device, int index) if (device == INPUT_USE_KEYBOARD || device == INPUT_USE_ANY) { - const Uint8 *mKeystates = SDL_GetKeyboardState(nullptr); + const bool *mKeystates = SDL_GetKeyboardState(nullptr); for (int i = 0; i < (int)keyBindings.size(); ++i) { - if (mKeystates[keyBindings[i].scancode] != 0) + if (mKeystates[keyBindings[i].scancode]) { return true; } @@ -181,7 +177,7 @@ bool Input::checkAnyInput(int device, int index) { for (int i = 0; i < (int)gameControllerBindings.size(); ++i) { - if (SDL_GameControllerGetButton(connectedControllers[index], gameControllerBindings[i].button) != 0) + if (SDL_GetGamepadButton(connectedControllers[index], gameControllerBindings[i].button)) { return true; } @@ -197,12 +193,12 @@ bool Input::discoverGameController() { bool found = false; - if (SDL_WasInit(SDL_INIT_GAMECONTROLLER) != 1) + if (SDL_WasInit(SDL_INIT_GAMEPAD) != SDL_INIT_GAMEPAD) { - SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER); + SDL_InitSubSystem(SDL_INIT_GAMEPAD); } - if (SDL_GameControllerAddMappingsFromFile(dbPath.c_str()) < 0) + if (SDL_AddGamepadMappingsFromFile(dbPath.c_str()) < 0) { if (verbose) { @@ -210,55 +206,66 @@ bool Input::discoverGameController() } } - const int nJoysticks = SDL_NumJoysticks(); + int nJoysticks = 0; + SDL_JoystickID *joysticks = SDL_GetJoysticks(&nJoysticks); numGamepads = 0; - // Cuenta el numero de mandos - for (int i = 0; i < nJoysticks; ++i) + if (joysticks) { - if (SDL_IsGameController(i)) + // Cuenta el numero de mandos + for (int i = 0; i < nJoysticks; ++i) { - numGamepads++; - } - } - - if (verbose) - { - std::cout << "\nChecking for game controllers...\n"; - std::cout << nJoysticks << " joysticks found, " << numGamepads << " are gamepads\n"; - } - - if (numGamepads > 0) - { - found = true; - - for (int i = 0; i < numGamepads; i++) - { - // Abre el mando y lo añade a la lista - SDL_GameController *pad = SDL_GameControllerOpen(i); - if (SDL_GameControllerGetAttached(pad) == 1) + if (SDL_IsGamepad(joysticks[i])) { - connectedControllers.push_back(pad); - const std::string separator(" #"); - std::string name = SDL_GameControllerNameForIndex(i); - name.resize(25); - name = name + separator + std::to_string(i); - if (verbose) - { - std::cout << name << std::endl; - } - controllerNames.push_back(name); - } - else - { - if (verbose) - { - std::cout << "SDL_GetError() = " << SDL_GetError() << std::endl; - } + numGamepads++; } } - SDL_GameControllerEventState(SDL_ENABLE); + if (verbose) + { + std::cout << "\nChecking for game controllers...\n"; + std::cout << nJoysticks << " joysticks found, " << numGamepads << " are gamepads\n"; + } + + if (numGamepads > 0) + { + found = true; + int padIndex = 0; + + for (int i = 0; i < nJoysticks; i++) + { + if (!SDL_IsGamepad(joysticks[i])) continue; + + // Abre el mando y lo añade a la lista + SDL_Gamepad *pad = SDL_OpenGamepad(joysticks[i]); + if (pad != nullptr) + { + connectedControllers.push_back(pad); + const std::string separator(" #"); + const char *padName = SDL_GetGamepadName(pad); + std::string name = padName ? padName : "Unknown"; + name.resize(25); + name = name + separator + std::to_string(padIndex); + if (verbose) + { + std::cout << name << std::endl; + } + controllerNames.push_back(name); + padIndex++; + } + else + { + if (verbose) + { + std::cout << "SDL_GetError() = " << SDL_GetError() << std::endl; + } + } + } + + SDL_SetGamepadEventsEnabled(true); + } + + SDL_free(joysticks); } return found; @@ -314,4 +321,4 @@ void Input::enable() { enabled = true; disabledUntil = d_notDisabled; -} \ No newline at end of file +} diff --git a/source/input.h b/source/input.h index f5255a4..1593a6f 100644 --- a/source/input.h +++ b/source/input.h @@ -1,8 +1,6 @@ #pragma once -#include // for SDL_GameControllerButton, SDL_G... -#include // for SDL_Scancode -#include // for Uint8 +#include #include // for string, basic_string #include // for vector @@ -58,12 +56,12 @@ private: struct GameControllerBindings_t { - SDL_GameControllerButton button; // GameControllerButton asociado + SDL_GamepadButton button; // GameControllerButton asociado bool active; // Indica si está activo }; // Objetos y punteros - std::vector connectedControllers; // Vector con todos los mandos conectados + std::vector connectedControllers; // Vector con todos los mandos conectados // Variables std::vector keyBindings; // Vector con las teclas asociadas a los inputs predefinidos @@ -86,7 +84,7 @@ public: void bindKey(Uint8 input, SDL_Scancode code); // Asigna inputs a botones del mando - void bindGameControllerButton(Uint8 input, SDL_GameControllerButton button); + void bindGameControllerButton(Uint8 input, SDL_GamepadButton button); // Comprueba si un input esta activo bool checkInput(Uint8 input, bool repeat = true, int device = INPUT_USE_ANY, int index = 0); diff --git a/source/instructions.cpp b/source/instructions.cpp index 3b08e93..3f46a42 100644 --- a/source/instructions.cpp +++ b/source/instructions.cpp @@ -1,15 +1,12 @@ #include "instructions.h" -#include // for SDL_GetError -#include // for SDL_PIXELFORMAT_RGBA8888 -#include // for SDL_Rect -#include // for SDL_GetTicks +#include #include // for max #include // for char_traits, basic_ostream, operator<< #include // for basic_string #include "asset.h" // for Asset #include "const.h" // for shdwTxtColor, GAMECANVAS_CENTER_X, GAME... #include "input.h" // for Input, REPEAT_FALSE, inputs_e -#include "jail_audio.h" // for JA_StopMusic +#include "jail_audio.hpp" // for JA_StopMusic #include "lang.h" // for Lang #include "screen.h" // for Screen #include "sprite.h" // for Sprite @@ -216,7 +213,8 @@ void Instructions::render() } // Copia el backbuffer al renderizador - SDL_RenderCopy(renderer, backbuffer, nullptr, &window); + SDL_FRect fWindow = {(float)window.x, (float)window.y, (float)window.w, (float)window.h}; + SDL_RenderTexture(renderer, backbuffer, nullptr, &fWindow); // Vuelca el contenido del renderizador en pantalla screen->blit(); @@ -229,7 +227,7 @@ void Instructions::checkEvents() while (SDL_PollEvent(eventHandler) != 0) { // Evento de salida de la aplicación - if (eventHandler->type == SDL_QUIT) + if (eventHandler->type == SDL_EVENT_QUIT) { section->name = SECTION_PROG_QUIT; break; diff --git a/source/instructions.h b/source/instructions.h index 385400a..b5089cf 100644 --- a/source/instructions.h +++ b/source/instructions.h @@ -1,8 +1,6 @@ #pragma once -#include // for SDL_Event -#include // for SDL_Renderer, SDL_Texture -#include // for Uint16, Uint32 +#include #include // for vector class Asset; class Input; diff --git a/source/intro.cpp b/source/intro.cpp index 361dfa1..b7f61a9 100644 --- a/source/intro.cpp +++ b/source/intro.cpp @@ -1,10 +1,10 @@ #include "intro.h" -#include // for SDL_GetTicks +#include #include // for basic_string #include "asset.h" // for Asset #include "const.h" // for GAMECANVAS_CENTER_X, GAMECANVAS_FIRST_QU... #include "input.h" // for Input, REPEAT_FALSE, inputs_e -#include "jail_audio.h" // for JA_StopMusic, JA_DeleteMusic, JA_LoadMusic +#include "jail_audio.hpp" // for JA_StopMusic, JA_DeleteMusic, JA_LoadMusic #include "lang.h" // for Lang #include "screen.h" // for Screen #include "smartsprite.h" // for SmartSprite @@ -193,7 +193,7 @@ void Intro::checkEvents() while (SDL_PollEvent(eventHandler) != 0) { // Evento de salida de la aplicación - if (eventHandler->type == SDL_QUIT) + if (eventHandler->type == SDL_EVENT_QUIT) { section->name = SECTION_PROG_QUIT; break; @@ -391,6 +391,7 @@ void Intro::updateScenes() // Actualiza las variables del objeto void Intro::update() { + JA_Update(); checkInput(); if (SDL_GetTicks() - ticks > ticksSpeed) diff --git a/source/intro.h b/source/intro.h index 4a4ddaf..edb3cff 100644 --- a/source/intro.h +++ b/source/intro.h @@ -1,8 +1,6 @@ #pragma once -#include // for SDL_Event -#include // for SDL_Renderer -#include // for Uint32, Uint8 +#include #include // for vector class Asset; class Input; diff --git a/source/item.h b/source/item.h index 2a3b467..aa7f831 100644 --- a/source/item.h +++ b/source/item.h @@ -1,7 +1,6 @@ #pragma once -#include // for SDL_Renderer -#include // for Uint8, Uint16 +#include #include // for string #include // for vector #include "utils.h" // for circle_t diff --git a/source/jail_audio.cpp b/source/jail_audio.cpp deleted file mode 100644 index 04a793d..0000000 --- a/source/jail_audio.cpp +++ /dev/null @@ -1,413 +0,0 @@ -#ifndef JA_USESDLMIXER -#include "jail_audio.h" -#include // for SDL_Log, SDL_LogSetPriority, SDL_LOG_CAT... -#include // for SDL_RWFromMem -#include // for SDL_GetTicks -#include // for uint8_t, uint32_t -#include // for NULL, fseek, fclose, fopen, fread, ftell -#include // for free, malloc -#include "stb_vorbis.c" // for stb_vorbis_decode_memory - -constexpr int JA_MAX_SIMULTANEOUS_CHANNELS = 20; - -struct JA_Sound_t { - Uint32 length {0}; - Uint8* buffer {NULL}; -}; - -struct JA_Channel_t { - JA_Sound_t *sound; - int pos {0}; - int times {0}; - JA_Channel_state state { JA_CHANNEL_FREE }; -}; - -struct JA_Music_t { - int samples {0}; - Uint32 length {0}; - int pos {0}; - int times {0}; - short* output {NULL}; - JA_Music_state state {JA_MUSIC_INVALID}; -}; - -JA_Music_t *current_music{NULL}; -JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS]; - -int JA_freq {48000}; -SDL_AudioFormat JA_format {AUDIO_S16}; -Uint8 JA_channels {2}; -int JA_musicVolume = 128; -int JA_soundVolume = 64; -bool JA_musicEnabled = true; -bool JA_soundEnabled = true; -SDL_AudioDeviceID sdlAudioDevice = 0; - -bool fading = false; -int fade_start_time; -int fade_duration; -int fade_initial_volume; - -void audioCallback(void * userdata, uint8_t * stream, int len) { - SDL_memset(stream, 0, len); - if (current_music != NULL && current_music->state == JA_MUSIC_PLAYING) { - int volume = JA_musicVolume; - if (fading) { - int time = SDL_GetTicks(); - if (time > (fade_start_time+fade_duration)) { - fading = false; - current_music->pos = 0; - current_music->state = JA_MUSIC_STOPPED; - volume = 0; - } else { - const int time_passed = time - fade_start_time; - const float percent = (float)time_passed / (float)fade_duration; - volume = JA_musicVolume * (1.0 - percent); - } - } - const int size = SDL_min(len, current_music->length - current_music->pos); - SDL_MixAudioFormat(stream, (Uint8*)(current_music->output)+current_music->pos, AUDIO_S16, size, volume); - current_music->pos += size; - if (size < len) { - if (current_music->times != 0) { - SDL_MixAudioFormat(stream+size, (Uint8*)current_music->output, AUDIO_S16, len-size, volume); - current_music->pos = len-size; - if (current_music->times > 0) current_music->times--; - } else { - current_music->pos = 0; - current_music->state = JA_MUSIC_STOPPED; - } - } - } - // Mixar els channels mi amol - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { - if (channels[i].state == JA_CHANNEL_PLAYING) { - const int size = SDL_min(len, channels[i].sound->length - channels[i].pos); - SDL_MixAudioFormat(stream, channels[i].sound->buffer + channels[i].pos, AUDIO_S16, size, JA_soundVolume); - channels[i].pos += size; - if (size < len) { - if (channels[i].times != 0) { - SDL_MixAudioFormat(stream + size, channels[i].sound->buffer, AUDIO_S16, len-size, JA_soundVolume); - channels[i].pos = len-size; - if (channels[i].times > 0) channels[i].times--; - } else { - JA_StopChannel(i); - } - } - } - } -} - -void JA_Init(const int freq, const SDL_AudioFormat format, const int channels) -{ - #ifdef DEBUG - SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG); - #endif - - JA_freq = freq; - JA_format = format; - JA_channels = channels; - SDL_AudioSpec audioSpec{JA_freq, JA_format, JA_channels, 0, 1024, 0, 0, audioCallback, NULL}; - if (sdlAudioDevice != 0) SDL_CloseAudioDevice(sdlAudioDevice); - sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0); - - SDL_PauseAudioDevice(sdlAudioDevice, 0); -} - -void JA_Quit() { - SDL_PauseAudioDevice(sdlAudioDevice, 1); - if (sdlAudioDevice != 0) SDL_CloseAudioDevice(sdlAudioDevice); - sdlAudioDevice = 0; -} - -JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length) -{ - int chan, samplerate; - JA_Music_t *music = new JA_Music_t(); - - music->samples = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &music->output); - // [RZC 28/08/22] Abans el descomprimiem mentre el teniem obert -// music->samples = stb_vorbis_decode_filename(filename, &chan, &samplerate, &music->output); - - SDL_AudioCVT cvt; - SDL_BuildAudioCVT(&cvt, AUDIO_S16, chan, samplerate, JA_format, JA_channels, JA_freq); - if (cvt.needed) { - cvt.len = music->samples * chan * 2; - music->length = cvt.len; - cvt.buf = (Uint8 *) SDL_malloc(cvt.len * cvt.len_mult); - SDL_memcpy(cvt.buf, music->output, cvt.len); - SDL_ConvertAudio(&cvt); - free(music->output); - music->output = (short*)cvt.buf; - } - music->length = music->samples * chan * 2; - 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); - - free(buffer); - - return music; -} - -void JA_PlayMusic(JA_Music_t *music, const int loop) -{ - if (!JA_musicEnabled) return; - - if (current_music != NULL) { - current_music->pos = 0; - current_music->state = JA_MUSIC_STOPPED; - } - current_music = music; - current_music->pos = 0; - current_music->state = JA_MUSIC_PLAYING; - current_music->times = loop; -} - -void JA_PauseMusic() -{ - if (!JA_musicEnabled) return; - - if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return; - current_music->state = JA_MUSIC_PAUSED; -} - -void JA_ResumeMusic() -{ - if (!JA_musicEnabled) return; - - if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return; - current_music->state = JA_MUSIC_PLAYING; -} - -void JA_StopMusic() -{ - if (!JA_musicEnabled) return; - - if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return; - current_music->pos = 0; - current_music->state = JA_MUSIC_STOPPED; -} - -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 == NULL) return JA_MUSIC_INVALID; - return current_music->state; -} - -void JA_DeleteMusic(JA_Music_t *music) { - if (current_music == music) current_music = NULL; - free(music->output); - delete music; -} - -int JA_SetMusicVolume(int volume) -{ - JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume; - return JA_musicVolume; -} - -void JA_SetMusicPosition(float value) -{ - if (!current_music) return; - current_music->pos = value * JA_freq; -} - -float JA_GetMusicPosition() -{ - if (!current_music) return 0; - return float(current_music->pos)/float(JA_freq); -} - -void JA_EnableMusic(const bool value) -{ - if (!value && current_music != NULL && 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_AudioSpec wavSpec; - SDL_LoadWAV_RW(SDL_RWFromMem(buffer, size),1, &wavSpec, &sound->buffer, &sound->length); - - SDL_AudioCVT cvt; - SDL_BuildAudioCVT(&cvt, wavSpec.format, wavSpec.channels, wavSpec.freq, JA_format, JA_channels, JA_freq); - cvt.len = sound->length; - cvt.buf = (Uint8 *) SDL_malloc(cvt.len * cvt.len_mult); - SDL_memcpy(cvt.buf, sound->buffer, sound->length); - SDL_ConvertAudio(&cvt); - SDL_FreeWAV(sound->buffer); - sound->buffer = cvt.buf; - sound->length = cvt.len_cvt; - - return sound; -} - -JA_Sound_t *JA_LoadSound(const char* filename) { - JA_Sound_t *sound = new JA_Sound_t(); - SDL_AudioSpec wavSpec; - SDL_LoadWAV(filename, &wavSpec, &sound->buffer, &sound->length); - - SDL_AudioCVT cvt; - SDL_BuildAudioCVT(&cvt, wavSpec.format, wavSpec.channels, wavSpec.freq, JA_format, JA_channels, JA_freq); - cvt.len = sound->length; - cvt.buf = (Uint8 *) SDL_malloc(cvt.len * cvt.len_mult); - SDL_memcpy(cvt.buf, sound->buffer, sound->length); - SDL_ConvertAudio(&cvt); - SDL_FreeWAV(sound->buffer); - sound->buffer = cvt.buf; - sound->length = cvt.len_cvt; - - return sound; -} - -int JA_PlaySound(JA_Sound_t *sound, const int loop) -{ - 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; - - channels[channel].sound = sound; - channels[channel].times = loop; - channels[channel].pos = 0; - channels[channel].state = JA_CHANNEL_PLAYING; - return channel; -} - -int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop) -{ - if (!JA_soundEnabled) return -1; - - if (channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return -1; - - channels[channel].sound = sound; - channels[channel].times = loop; - channels[channel].pos = 0; - channels[channel].state = JA_CHANNEL_PLAYING; - 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; - } - } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) { - if (channels[channel].state == JA_CHANNEL_PLAYING) channels[channel].state = JA_CHANNEL_PAUSED; - } -} - -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; - } - } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) { - if (channels[channel].state == JA_CHANNEL_PAUSED) channels[channel].state = JA_CHANNEL_PLAYING; - } -} - -void JA_StopChannel(const int channel) -{ - if (!JA_soundEnabled) return; - - if (channel == -1) { - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { - channels[i].state = JA_CHANNEL_FREE; - channels[i].pos = 0; - channels[i].sound = NULL; - } - } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) { - 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; -} - -int JA_SetSoundVolume(int volume) -{ - JA_soundVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume; - return JA_soundVolume; -} - -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; -} - -int JA_SetVolume(int volume) -{ - JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume; - JA_soundVolume = JA_musicVolume/2; - return JA_musicVolume; -} - -#endif \ No newline at end of file diff --git a/source/jail_audio.h b/source/jail_audio.h deleted file mode 100644 index f51135c..0000000 --- a/source/jail_audio.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include // for SDL_AudioFormat -#include // for Uint32, Uint8 -struct JA_Music_t; // lines 8-8 -struct JA_Sound_t; // lines 7-7 - -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_Init(const int freq, const SDL_AudioFormat format, const int 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); -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); -int JA_SetMusicVolume(int 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); -int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop = 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); -int JA_SetSoundVolume(int volume); -void JA_EnableSound(const bool value); - -int JA_SetVolume(int volume); diff --git a/source/jail_audio.hpp b/source/jail_audio.hpp new file mode 100644 index 0000000..35cac80 --- /dev/null +++ b/source/jail_audio.hpp @@ -0,0 +1,467 @@ +#pragma once + +// --- Includes --- +#include +#include // Para uint32_t, uint8_t +#include // Para NULL, fseek, printf, fclose, fopen, fread, ftell, FILE, SEEK_END, SEEK_SET +#include // Para free, malloc +#include // Para strcpy, strlen + +#define STB_VORBIS_HEADER_ONLY +#include "stb_vorbis.c" + +// --- 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 unica 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}; + +// --- 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); + 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); + sdlAudioDevice = 0; +} + +// --- Music Functions --- + +inline JA_Music_t* JA_LoadMusic(const 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 = static_cast(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) { + FILE* f = fopen(filename, "rb"); + if (!f) return NULL; + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + auto* buffer = static_cast(malloc(fsize + 1)); + if (!buffer) { + 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) { + music->filename = static_cast(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; + + 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) { + 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 void JA_PauseMusic() { + if (!JA_musicEnabled) return; + if (!current_music || current_music->state != JA_MUSIC_PLAYING) return; + + 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; + + 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; + } +} + +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); + 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; +} + +inline float JA_GetMusicPosition() { + if (!current_music) return 0; + return float(current_music->pos) / float(current_music->spec.freq); +} + +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; + 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) { + 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); + + channels[channel].sound = sound; + channels[channel].times = loop; + channels[channel].pos = 0; + channels[channel].group = group; + 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) { + 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; + } + + 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); + } + JA_soundEnabled = value; +} + +inline float JA_SetVolume(float volume) { + float v = JA_SetMusicVolume(volume); + JA_SetSoundVolume(v, -1); + return v; +} diff --git a/source/lang.h b/source/lang.h index e155914..f6f2a31 100644 --- a/source/lang.h +++ b/source/lang.h @@ -1,6 +1,6 @@ #pragma once -#include // for Uint8 +#include #include // for string, basic_string class Asset; diff --git a/source/logo.cpp b/source/logo.cpp index 5d415b8..55b7606 100644 --- a/source/logo.cpp +++ b/source/logo.cpp @@ -1,11 +1,11 @@ #include "logo.h" -#include // for SDL_GetTicks +#include #include // for min #include // for basic_string #include "asset.h" // for Asset #include "const.h" // for bgColor, SECTION_PROG_LOGO, SECTION_PROG... #include "input.h" // for Input, REPEAT_FALSE, inputs_e -#include "jail_audio.h" // for JA_StopMusic +#include "jail_audio.hpp" // for JA_StopMusic #include "screen.h" // for Screen #include "sprite.h" // for Sprite #include "texture.h" // for Texture @@ -65,7 +65,7 @@ void Logo::checkEvents() while (SDL_PollEvent(eventHandler) != 0) { // Evento de salida de la aplicación - if (eventHandler->type == SDL_QUIT) + if (eventHandler->type == SDL_EVENT_QUIT) { section->name = SECTION_PROG_QUIT; break; @@ -119,6 +119,7 @@ void Logo::renderFade() // Actualiza las variables del objeto void Logo::update() { + JA_Update(); checkInput(); if (SDL_GetTicks() - ticks > ticksSpeed) diff --git a/source/logo.h b/source/logo.h index 06939c5..42f64dc 100644 --- a/source/logo.h +++ b/source/logo.h @@ -1,8 +1,6 @@ #pragma once -#include // for SDL_Event -#include // for SDL_Renderer -#include // for Uint32 +#include class Asset; class Input; class Screen; diff --git a/source/main.cpp b/source/main.cpp index a3246a3..c85b3e8 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -40,6 +40,7 @@ Reescribiendo el código el 27/09/2022 */ #include +#include "stb_vorbis.c" #include "director.h" int main(int argc, char *argv[]) diff --git a/source/menu.cpp b/source/menu.cpp index 5545207..c0b2686 100644 --- a/source/menu.cpp +++ b/source/menu.cpp @@ -4,7 +4,7 @@ #include // for basic_stringstream #include "asset.h" // for Asset #include "input.h" // for Input, REPEAT_FALSE, inputs_e -#include "jail_audio.h" // for JA_LoadSound, JA_PlaySound, JA_DeleteSound +#include "jail_audio.hpp" // for JA_LoadSound, JA_PlaySound, JA_DeleteSound #include "text.h" // for Text // Constructor @@ -645,20 +645,22 @@ void Menu::render() // Rendereritza el fondo del menu if (backgroundType == MENU_BACKGROUND_SOLID) { + SDL_FRect fBG = {(float)rectBG.rect.x, (float)rectBG.rect.y, (float)rectBG.rect.w, (float)rectBG.rect.h}; SDL_SetRenderDrawColor(renderer, rectBG.color.r, rectBG.color.g, rectBG.color.b, rectBG.a); - SDL_RenderFillRect(renderer, &rectBG.rect); + SDL_RenderFillRect(renderer, &fBG); } // Renderiza el rectangulo del selector - const SDL_Rect temp = {selector.rect.x, selector.rect.y - 1, selector.rect.w, selector.rect.h + 1}; + const SDL_FRect fTemp = {(float)selector.rect.x, (float)(selector.rect.y - 1), (float)selector.rect.w, (float)(selector.rect.h + 1)}; SDL_SetRenderDrawColor(renderer, selector.color.r, selector.color.g, selector.color.b, selector.a); - SDL_RenderFillRect(renderer, &temp); + SDL_RenderFillRect(renderer, &fTemp); // Renderiza el borde del fondo if (backgroundType == MENU_BACKGROUND_SOLID) { + SDL_FRect fBGBorder = {(float)rectBG.rect.x, (float)rectBG.rect.y, (float)rectBG.rect.w, (float)rectBG.rect.h}; SDL_SetRenderDrawColor(renderer, rectBG.color.r, rectBG.color.g, rectBG.color.b, 255); - SDL_RenderDrawRect(renderer, &rectBG.rect); + SDL_RenderRect(renderer, &fBGBorder); } // Crea una linea por si hay que dibujarla entre los items @@ -676,7 +678,7 @@ void Menu::render() { line.y = item[i].rect.y + item[i].rect.h + (item[i].hPaddingDown / 2) - 1; SDL_SetRenderDrawColor(renderer, 255, 255, 255, 64); - SDL_RenderDrawLine(renderer, line.x1, line.y, line.x2, line.y); + SDL_RenderLine(renderer, line.x1, line.y, line.x2, line.y); } // Dibuja el elemento diff --git a/source/menu.h b/source/menu.h index 8f54ce7..0503032 100644 --- a/source/menu.h +++ b/source/menu.h @@ -1,7 +1,6 @@ #pragma once -#include // for SDL_Rect -#include // for SDL_Renderer +#include #include // for string, basic_string #include // for vector #include "utils.h" // for color_t diff --git a/source/movingsprite.cpp b/source/movingsprite.cpp index 360107c..2a63ee0 100644 --- a/source/movingsprite.cpp +++ b/source/movingsprite.cpp @@ -306,7 +306,7 @@ void MovingSprite::switchRotate() } // Establece el valor de la variable -void MovingSprite::setFlip(SDL_RendererFlip flip) +void MovingSprite::setFlip(SDL_FlipMode flip) { currentFlip = flip; } @@ -318,7 +318,7 @@ void MovingSprite::flip() } // Obtiene el valor de la variable -SDL_RendererFlip MovingSprite::getFlip() +SDL_FlipMode MovingSprite::getFlip() { return currentFlip; } diff --git a/source/movingsprite.h b/source/movingsprite.h index e8d73cc..81f8646 100644 --- a/source/movingsprite.h +++ b/source/movingsprite.h @@ -1,8 +1,6 @@ #pragma once -#include // for SDL_Rect, SDL_Point -#include // for SDL_RendererFlip, SDL_Renderer -#include // for Uint16 +#include #include "sprite.h" // for Sprite class Texture; @@ -31,7 +29,7 @@ protected: double rotateAmount; // Cantidad de grados a girar en cada iteración int counter; // Contador interno SDL_Point *center; // Centro de rotación - SDL_RendererFlip currentFlip; // Indica como se voltea el sprite + SDL_FlipMode currentFlip; // Indica como se voltea el sprite public: // Constructor @@ -137,13 +135,13 @@ public: void switchRotate(); // Establece el valor de la variable - void setFlip(SDL_RendererFlip flip); + void setFlip(SDL_FlipMode flip); // Gira el sprite horizontalmente void flip(); // Obtiene el valor de la variable - SDL_RendererFlip getFlip(); + SDL_FlipMode getFlip(); // Devuelve el rectangulo donde está el sprite SDL_Rect getRect(); diff --git a/source/player.cpp b/source/player.cpp index de7a497..0ec07b3 100644 --- a/source/player.cpp +++ b/source/player.cpp @@ -243,8 +243,8 @@ void Player::setAnimation() const std::string aWalking = statusWalking == PLAYER_STATUS_WALKING_STOP ? "stand" : "walk"; const std::string aFiring = statusFiring == PLAYER_STATUS_FIRING_UP ? "centershoot" : "sideshoot"; - const SDL_RendererFlip flipWalk = statusWalking == PLAYER_STATUS_WALKING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; - const SDL_RendererFlip flipFire = statusFiring == PLAYER_STATUS_FIRING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; + const SDL_FlipMode flipWalk = statusWalking == PLAYER_STATUS_WALKING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; + const SDL_FlipMode flipFire = statusFiring == PLAYER_STATUS_FIRING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; // Establece la animación a partir de las cadenas legsSprite->setCurrentAnimation(aWalking); diff --git a/source/player.h b/source/player.h index cac997e..9a3d217 100644 --- a/source/player.h +++ b/source/player.h @@ -1,7 +1,6 @@ #pragma once -#include // for SDL_Renderer -#include // for Uint8, Uint16, Uint32 +#include #include // for string #include // for vector #include "utils.h" // for circle_t diff --git a/source/screen.cpp b/source/screen.cpp index e071105..b4edc9b 100644 --- a/source/screen.cpp +++ b/source/screen.cpp @@ -1,8 +1,5 @@ #include "screen.h" -#include // for SDL_GetError -#include // for SDL_DISABLE, SDL_ENABLE -#include // for SDL_ShowCursor -#include // for SDL_PIXELFORMAT_RGBA8888 +#include #include // for max, min #include // for basic_ostream, operator<<, cout, endl #include // for basic_string, char_traits, string @@ -77,7 +74,8 @@ void Screen::blit() SDL_RenderClear(renderer); // Copia la textura de juego en el renderizador en la posición adecuada - SDL_RenderCopy(renderer, gameCanvas, nullptr, &dest); + SDL_FRect fdest = {(float)dest.x, (float)dest.y, (float)dest.w, (float)dest.h}; + SDL_RenderTexture(renderer, gameCanvas, nullptr, &fdest); // Muestra por pantalla el renderizador SDL_RenderPresent(renderer); @@ -87,13 +85,13 @@ void Screen::blit() void Screen::setVideoMode(int videoMode) { // Aplica el modo de video - SDL_SetWindowFullscreen(window, videoMode); + SDL_SetWindowFullscreen(window, videoMode != 0); // Si está activo el modo ventana quita el borde if (videoMode == 0) { // Muestra el puntero - SDL_ShowCursor(SDL_ENABLE); + SDL_ShowCursor(); // Esconde la ventana //SDL_HideWindow(window); @@ -121,10 +119,10 @@ void Screen::setVideoMode(int videoMode) } // Si está activo el modo de pantalla completa añade el borde - else if (videoMode == SDL_WINDOW_FULLSCREEN_DESKTOP) + else if (videoMode == SDL_WINDOW_FULLSCREEN) { // Oculta el puntero - SDL_ShowCursor(SDL_DISABLE); + SDL_HideCursor(); // Obten el alto y el ancho de la ventana SDL_GetWindowSize(window, &windowWidth, &windowHeight); @@ -171,7 +169,7 @@ void Screen::setVideoMode(int videoMode) } // Modifica el tamaño del renderizador - SDL_RenderSetLogicalSize(renderer, windowWidth, windowHeight); + SDL_SetRenderLogicalPresentation(renderer, windowWidth, windowHeight, SDL_LOGICAL_PRESENTATION_LETTERBOX); // Actualiza las opciones options->videoMode = videoMode; @@ -182,7 +180,7 @@ void Screen::setVideoMode(int videoMode) // Camibia entre pantalla completa y ventana void Screen::switchVideoMode() { - options->videoMode = (options->videoMode == 0) ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0; + options->videoMode = (options->videoMode == 0) ? SDL_WINDOW_FULLSCREEN : 0; setVideoMode(options->videoMode); } @@ -311,7 +309,7 @@ void Screen::renderFade() return; } - const SDL_Rect rect = {0, 0, gameCanvasWidth, gameCanvasHeight}; + const SDL_FRect rect = {0, 0, (float)gameCanvasWidth, (float)gameCanvasHeight}; color_t color = {0, 0, 0}; const float step = (float)fadeCounter / (float)fadeLenght; const int alpha = 0 + (255 - 0) * step; diff --git a/source/screen.h b/source/screen.h index 951a357..e509810 100644 --- a/source/screen.h +++ b/source/screen.h @@ -1,9 +1,6 @@ #pragma once -#include // for SDL_BlendMode -#include // for SDL_Rect -#include // for SDL_Renderer, SDL_Texture -#include // for SDL_Window +#include #include // for vector #include "utils.h" // for color_t class Asset; diff --git a/source/smartsprite.h b/source/smartsprite.h index be18630..84a94b9 100644 --- a/source/smartsprite.h +++ b/source/smartsprite.h @@ -1,6 +1,6 @@ #pragma once -#include // for SDL_Renderer +#include #include "animatedsprite.h" // for AnimatedSprite class Texture; diff --git a/source/sprite.h b/source/sprite.h index 2dec4a1..bc77065 100644 --- a/source/sprite.h +++ b/source/sprite.h @@ -1,7 +1,6 @@ #pragma once -#include // for SDL_Rect -#include // for SDL_Renderer +#include class Texture; // Clase sprite diff --git a/source/text.h b/source/text.h index 07592cc..e34339a 100644 --- a/source/text.h +++ b/source/text.h @@ -1,7 +1,6 @@ #pragma once -#include // for SDL_Renderer -#include // for Uint8 +#include #include // for string class Sprite; class Texture; diff --git a/source/texture.cpp b/source/texture.cpp index 3faa12f..7fe008d 100644 --- a/source/texture.cpp +++ b/source/texture.cpp @@ -1,9 +1,6 @@ #include "texture.h" -#include // for SDL_GetError -#include // for SDL_Log -#include // for SDL_PIXELFORMAT_RGB24, SDL_PIXELFORMAT... -#include // for SDL_CreateRGBSurfaceWithFormatFrom +#include #include // for exit #include // for basic_ostream, operator<<, cout, endl #define STB_IMAGE_IMPLEMENTATION @@ -55,17 +52,15 @@ bool Texture::loadFromFile(std::string path, SDL_Renderer *renderer, bool verbos } } - int depth, pitch; - Uint32 pixel_format; + int pitch; + SDL_PixelFormat pixel_format; if (req_format == STBI_rgb) { - depth = 24; pitch = 3 * width; // 3 bytes por pixel * pixels per linea pixel_format = SDL_PIXELFORMAT_RGB24; } else { // STBI_rgb_alpha (RGBA) - depth = 32; pitch = 4 * width; pixel_format = SDL_PIXELFORMAT_RGBA32; } @@ -77,7 +72,7 @@ bool Texture::loadFromFile(std::string path, SDL_Renderer *renderer, bool verbos SDL_Texture *newTexture = nullptr; // Carga la imagen desde una ruta específica - SDL_Surface *loadedSurface = SDL_CreateRGBSurfaceWithFormatFrom((void *)data, width, height, depth, pitch, pixel_format); + SDL_Surface *loadedSurface = SDL_CreateSurfaceFrom(width, height, pixel_format, (void *)data, pitch); if (loadedSurface == nullptr) { if (verbose) @@ -104,7 +99,7 @@ bool Texture::loadFromFile(std::string path, SDL_Renderer *renderer, bool verbos } // Elimina la textura cargada - SDL_FreeSurface(loadedSurface); + SDL_DestroySurface(loadedSurface); } // Return success @@ -163,23 +158,41 @@ void Texture::setAlpha(Uint8 alpha) } // Renderiza la textura en un punto específico -void Texture::render(SDL_Renderer *renderer, int x, int y, SDL_Rect *clip, float zoomW, float zoomH, double angle, SDL_Point *center, SDL_RendererFlip flip) +void Texture::render(SDL_Renderer *renderer, int x, int y, SDL_Rect *clip, float zoomW, float zoomH, double angle, SDL_Point *center, SDL_FlipMode flip) { // Establece el destino de renderizado en la pantalla - SDL_Rect renderQuad = {x, y, width, height}; + SDL_FRect renderQuad = {(float)x, (float)y, (float)width, (float)height}; // Obtiene las dimesiones del clip de renderizado if (clip != nullptr) { - renderQuad.w = clip->w; - renderQuad.h = clip->h; + renderQuad.w = (float)clip->w; + renderQuad.h = (float)clip->h; } renderQuad.w = renderQuad.w * zoomW; renderQuad.h = renderQuad.h * zoomH; + // Convierte el clip a SDL_FRect + SDL_FRect srcRect; + SDL_FRect *srcRectPtr = nullptr; + if (clip != nullptr) + { + srcRect = {(float)clip->x, (float)clip->y, (float)clip->w, (float)clip->h}; + srcRectPtr = &srcRect; + } + + // Convierte el centro a SDL_FPoint + SDL_FPoint fCenter; + SDL_FPoint *fCenterPtr = nullptr; + if (center != nullptr) + { + fCenter = {(float)center->x, (float)center->y}; + fCenterPtr = &fCenter; + } + // Renderiza a pantalla - SDL_RenderCopyEx(renderer, texture, clip, &renderQuad, angle, center, flip); + SDL_RenderTextureRotated(renderer, texture, srcRectPtr, &renderQuad, angle, fCenterPtr, flip); } // Establece la textura como objetivo de renderizado diff --git a/source/texture.h b/source/texture.h index 7df00be..a1b826e 100644 --- a/source/texture.h +++ b/source/texture.h @@ -1,9 +1,6 @@ #pragma once -#include // for SDL_BlendMode -#include // for SDL_Point, SDL_Rect -#include // for SDL_Renderer, SDL_FLIP_NONE, SDL_TEX... -#include // for Uint8 +#include #include // for basic_string, string class Texture @@ -44,7 +41,7 @@ public: void setAlpha(Uint8 alpha); // Renderiza la textura en un punto específico - void render(SDL_Renderer *renderer, int x, int y, SDL_Rect *clip = nullptr, float zoomW = 1, float zoomH = 1, double angle = 0.0, SDL_Point *center = nullptr, SDL_RendererFlip flip = SDL_FLIP_NONE); + void render(SDL_Renderer *renderer, int x, int y, SDL_Rect *clip = nullptr, float zoomW = 1, float zoomH = 1, double angle = 0.0, SDL_Point *center = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE); // Establece la textura como objetivo de renderizado void setAsRenderTarget(SDL_Renderer *renderer); diff --git a/source/title.cpp b/source/title.cpp index f33b65b..e07c6a6 100644 --- a/source/title.cpp +++ b/source/title.cpp @@ -1,8 +1,5 @@ #include "title.h" -#include // for SDL_GetError -#include // for SDL_PIXELFORMAT_RGBA8888 -#include // for SDL_GetTicks -#include // for SDL_WINDOW_FULLSCREEN, SDL_WINDOW_FULLS... +#include #include // for rand #include // for basic_ostream, operator<<, basic_ostrea... #include // for basic_string, operator+, char_traits @@ -12,7 +9,7 @@ #include "fade.h" // for Fade #include "game.h" // for Game #include "input.h" // for Input, INPUT_USE_GAMECONTROLLER, INPUT_... -#include "jail_audio.h" // for JA_StopMusic, JA_GetMusicState, JA_Play... +#include "jail_audio.hpp" // for JA_StopMusic, JA_GetMusicState, JA_Play... #include "lang.h" // for Lang, ba_BA, en_UK, es_ES #include "menu.h" // for Menu #include "screen.h" // for Screen, FILTER_LINEAL, FILTER_NEAREST @@ -231,6 +228,9 @@ void Title::init() // Actualiza las variables del objeto void Title::update() { + // Actualiza el audio + JA_Update(); + // Comprueba las entradas checkInput(); @@ -562,7 +562,7 @@ void Title::render() screen->clean(bgColor); // Dibuja el tileado de fondo - SDL_RenderCopy(renderer, background, &backgroundWindow, nullptr); + { SDL_FRect fSrc = {(float)backgroundWindow.x, (float)backgroundWindow.y, (float)backgroundWindow.w, (float)backgroundWindow.h}; SDL_RenderTexture(renderer, background, &fSrc, nullptr); }; // Dibuja el degradado gradient->render(); @@ -594,7 +594,7 @@ void Title::render() screen->clean(bgColor); // Dibuja el tileado de fondo - SDL_RenderCopy(renderer, background, &backgroundWindow, nullptr); + { SDL_FRect fSrc = {(float)backgroundWindow.x, (float)backgroundWindow.y, (float)backgroundWindow.w, (float)backgroundWindow.h}; SDL_RenderTexture(renderer, background, &fSrc, nullptr); }; // Dibuja el degradado gradient->render(); @@ -628,7 +628,7 @@ void Title::render() screen->clean(bgColor); // Dibuja el tileado de fondo - SDL_RenderCopy(renderer, background, &backgroundWindow, nullptr); + { SDL_FRect fSrc = {(float)backgroundWindow.x, (float)backgroundWindow.y, (float)backgroundWindow.w, (float)backgroundWindow.h}; SDL_RenderTexture(renderer, background, &fSrc, nullptr); }; // Dibuja el degradado gradient->render(); @@ -678,20 +678,20 @@ void Title::checkEvents() while (SDL_PollEvent(eventHandler) != 0) { // Evento de salida de la aplicación - if (eventHandler->type == SDL_QUIT) + if (eventHandler->type == SDL_EVENT_QUIT) { section->name = SECTION_PROG_QUIT; break; } - else if (eventHandler->type == SDL_RENDER_DEVICE_RESET || eventHandler->type == SDL_RENDER_TARGETS_RESET) + else if (eventHandler->type == SDL_EVENT_RENDER_DEVICE_RESET || eventHandler->type == SDL_EVENT_RENDER_TARGETS_RESET) { reLoadTextures(); } if (section->subsection == SUBSECTION_TITLE_3) { // Si se pulsa alguna tecla durante la tercera sección del titulo - if ((eventHandler->type == SDL_KEYUP) || (eventHandler->type == SDL_JOYBUTTONUP)) + if ((eventHandler->type == SDL_EVENT_KEY_UP) || (eventHandler->type == SDL_EVENT_JOYSTICK_BUTTON_UP)) { // Muestra el menu menuVisible = true; @@ -752,9 +752,6 @@ void Title::switchFullScreenModeVar() options->videoMode = SDL_WINDOW_FULLSCREEN; break; case SDL_WINDOW_FULLSCREEN: - options->videoMode = SDL_WINDOW_FULLSCREEN_DESKTOP; - break; - case SDL_WINDOW_FULLSCREEN_DESKTOP: options->videoMode = 0; break; @@ -883,10 +880,6 @@ void Title::updateMenuLabels() menu.options->setItemCaption(i, lang->getText(5)); // FULLSCREEN break; - case SDL_WINDOW_FULLSCREEN_DESKTOP: - menu.options->setItemCaption(i, lang->getText(6)); // FAKE FULLSCREEN - break; - default: menu.options->setItemCaption(i, lang->getText(4)); // WINDOW break; diff --git a/source/title.h b/source/title.h index ee07a3a..0453685 100644 --- a/source/title.h +++ b/source/title.h @@ -1,9 +1,6 @@ #pragma once -#include // for SDL_Event -#include // for SDL_Rect -#include // for SDL_Renderer, SDL_Texture -#include // for Uint32, Uint8 +#include #include // for vector #include "instructions.h" // for mode_e #include "utils.h" // for input_t, options_t, section_t diff --git a/source/utils.h b/source/utils.h index 13469f6..6f7c790 100644 --- a/source/utils.h +++ b/source/utils.h @@ -1,7 +1,6 @@ #pragma once -#include // for SDL_Rect, SDL_Point -#include // for Uint8, Uint32 +#include #include // for string, basic_string #include // for vector