Implemented load audio and music files as well the basic audio playback
functionality.
This commit is contained in:
1 parent
dfee36ffe9
commit
e3f4f9c94f
9 files changed
+464
-61
No files matched your search
@@ -27,7 +27,7 @@ void remove_asset_from_manager(AssetManager *am, AssetID *id_ptr);
|
|||||||
SDL_Texture *get_texture(AssetManager *am, AssetID id);
|
SDL_Texture *get_texture(AssetManager *am, AssetID id);
|
||||||
Mix_Chunk *get_audio_chunk(AssetManager *am, AssetID id);
|
Mix_Chunk *get_audio_chunk(AssetManager *am, AssetID id);
|
||||||
Mix_Music *get_music(AssetManager *am, AssetID id);
|
Mix_Music *get_music(AssetManager *am, AssetID id);
|
||||||
void destroy_asset_manager(AssetManager *am);
|
void destroy_asset_manager(AssetManager **am);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-2
@@ -6,19 +6,50 @@
|
|||||||
#include "SDL_pixels.h"
|
#include "SDL_pixels.h"
|
||||||
#include "reusable_ids.h"
|
#include "reusable_ids.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif // !__cplusplus
|
#endif // !__cplusplus
|
||||||
|
|
||||||
bool init_game(const char *game_name, int window_width, int window_height,
|
bool init_game(const char *game_name, uint32_t window_width,
|
||||||
SDL_Color window_background_color, bool full_screen);
|
uint32_t window_height, SDL_Color window_background_color,
|
||||||
|
bool full_screen, uint8_t audio_tracks);
|
||||||
bool game_running();
|
bool game_running();
|
||||||
ObjectID add_object(void *object, EventHandlerPtr eh, UpdateFuncPtr uf,
|
ObjectID add_object(void *object, EventHandlerPtr eh, UpdateFuncPtr uf,
|
||||||
RenderFuncPtr rf);
|
RenderFuncPtr rf);
|
||||||
void remove_object(ObjectID *id);
|
void remove_object(ObjectID *id);
|
||||||
AssetID load_asset(const char *path, AssetType type);
|
AssetID load_asset(const char *path, AssetType type);
|
||||||
void render_texture_asset(AssetID id, float x, float y, float w, float h);
|
void render_texture_asset(AssetID id, float x, float y, float w, float h);
|
||||||
|
int8_t play_audio_asset(AssetID id, int16_t loops, bool fade_in,
|
||||||
|
uint32_t fade_length_in_ms);
|
||||||
|
void pause_audio_asset_on_track(AssetID id, uint8_t track);
|
||||||
|
void resume_audio_asset_on_track(AssetID id, uint8_t track);
|
||||||
|
void stop_audio_asset_on_track(AssetID id, uint8_t track);
|
||||||
|
void fade_out_audio_asset_on_track(AssetID id, uint8_t track,
|
||||||
|
uint32_t fade_length_in_ms);
|
||||||
|
void pause_all_instances_of_audio_asset(AssetID id);
|
||||||
|
void resume_all_instances_of_audio_asset(AssetID id);
|
||||||
|
void stop_all_instances_of_audio_asset(AssetID id);
|
||||||
|
void fade_out_all_instances_of_audio_asset(AssetID id,
|
||||||
|
uint32_t fade_length_in_ms);
|
||||||
|
int8_t get_audio_asset_volume(AssetID id);
|
||||||
|
void set_audio_asset_volume(AssetID id, int8_t volume);
|
||||||
|
void play_music_asset(AssetID id, int16_t loops, bool fade_in,
|
||||||
|
uint32_t fade_length_in_ms);
|
||||||
|
void pause_music_asset(AssetID id);
|
||||||
|
void resume_music_asset(AssetID id);
|
||||||
|
void stop_music_asset(AssetID id);
|
||||||
|
void fade_out_music_asset(AssetID id, uint32_t fade_length_in_ms);
|
||||||
|
int8_t get_music_asset_volume(AssetID id);
|
||||||
|
void set_music_asset_volume(AssetID id, int8_t volume);
|
||||||
|
bool is_music_asset_playing(AssetID id);
|
||||||
|
void pause_playing_music();
|
||||||
|
void resume_playing_music();
|
||||||
|
void stop_playing_music();
|
||||||
|
void fade_out_playing_music(uint32_t fade_length_in_ms);
|
||||||
|
void set_playing_music_volume(int8_t volume);
|
||||||
|
bool is_music_playing();
|
||||||
void close_asset(AssetID *id);
|
void close_asset(AssetID *id);
|
||||||
void handle_events();
|
void handle_events();
|
||||||
void update();
|
void update();
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ void remove_object_from_store(ObjectStore *os, ObjectID *id_ptr);
|
|||||||
void handle_all_objects_events(ObjectStore *os, const SDL_Event *event);
|
void handle_all_objects_events(ObjectStore *os, const SDL_Event *event);
|
||||||
void update_all_objects(ObjectStore *os, float delta);
|
void update_all_objects(ObjectStore *os, float delta);
|
||||||
void render_all_objects(ObjectStore *os);
|
void render_all_objects(ObjectStore *os);
|
||||||
void destroy_object_store(ObjectStore *os);
|
void destroy_object_store(ObjectStore **os);
|
||||||
|
|
||||||
#ifdef DEBUG_ENGINE
|
#ifdef DEBUG_ENGINE
|
||||||
void print_objects(ObjectStore *os);
|
void print_objects(ObjectStore *os);
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ void render_clear(const Renderer *renderer, SDL_Color color);
|
|||||||
void render_texture(const Renderer *renderer, SDL_Texture *texture, float x,
|
void render_texture(const Renderer *renderer, SDL_Texture *texture, float x,
|
||||||
float y, float w, float h);
|
float y, float w, float h);
|
||||||
void swap_buffers(const Renderer *renderer);
|
void swap_buffers(const Renderer *renderer);
|
||||||
void destroy_renderer(Renderer *renderer);
|
void destroy_renderer(Renderer **renderer);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
+49
-26
@@ -171,7 +171,16 @@ AssetID load_asset_to_manager(AssetManager *am, const char *path,
|
|||||||
|
|
||||||
AssetID existing_id =
|
AssetID existing_id =
|
||||||
get_asset_id_from_id_node(am, &(am->hashed_path_ids[hash_index]), path);
|
get_asset_id_from_id_node(am, &(am->hashed_path_ids[hash_index]), path);
|
||||||
|
|
||||||
if (existing_id != INVALID_ID) {
|
if (existing_id != INVALID_ID) {
|
||||||
|
if (am->assets[existing_id].type != type) {
|
||||||
|
// If the user tries to load an asset that is already loaded, but they
|
||||||
|
// try to load it as a type that doesn't match the asset's actual type,
|
||||||
|
// we return an INVALID_ID to ensure that the user doesn't try using the
|
||||||
|
// asset with functions that work on the wrong type
|
||||||
|
return INVALID_ID;
|
||||||
|
}
|
||||||
|
|
||||||
++(am->user_counter[existing_id]);
|
++(am->user_counter[existing_id]);
|
||||||
return existing_id;
|
return existing_id;
|
||||||
}
|
}
|
||||||
@@ -189,16 +198,25 @@ AssetID load_asset_to_manager(AssetManager *am, const char *path,
|
|||||||
asset.data.texture = load_texture(renderer, path);
|
asset.data.texture = load_texture(renderer, path);
|
||||||
|
|
||||||
if (!(asset.data.texture)) {
|
if (!(asset.data.texture)) {
|
||||||
printf("Error loading %s: %s\n", path, SDL_GetError());
|
|
||||||
loaded = false;
|
loaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ASSET_TYPE_AUDIO_FX:
|
case ASSET_TYPE_AUDIO_FX:
|
||||||
// TODO (Abdelrahman): Implement loading audio chunks
|
asset.data.chunk = Mix_LoadWAV(path);
|
||||||
|
|
||||||
|
if (!(asset.data.chunk)) {
|
||||||
|
loaded = false;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ASSET_TYPE_MUSIC:
|
case ASSET_TYPE_MUSIC:
|
||||||
// TODO (Abdelrahman): Implement loading music
|
asset.data.music = Mix_LoadMUS(path);
|
||||||
|
|
||||||
|
if (!(asset.data.music)) {
|
||||||
|
loaded = false;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
loaded = false;
|
loaded = false;
|
||||||
@@ -206,6 +224,7 @@ AssetID load_asset_to_manager(AssetManager *am, const char *path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!loaded) {
|
if (!loaded) {
|
||||||
|
printf("Error loading %s: %s\n", path, SDL_GetError());
|
||||||
return INVALID_ID;
|
return INVALID_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,7 +285,7 @@ void remove_asset_from_manager(AssetManager *am, AssetID *id_ptr) {
|
|||||||
remove_id_node(&(am->hashed_path_ids[hash_index]), id);
|
remove_id_node(&(am->hashed_path_ids[hash_index]), id);
|
||||||
|
|
||||||
free(am->assets[id].path);
|
free(am->assets[id].path);
|
||||||
am->assets[id].path = 0;
|
am->assets[id].path = NULL;
|
||||||
|
|
||||||
switch (am->assets[id].type) {
|
switch (am->assets[id].type) {
|
||||||
case ASSET_TYPE_IMAGE:
|
case ASSET_TYPE_IMAGE:
|
||||||
@@ -274,10 +293,12 @@ void remove_asset_from_manager(AssetManager *am, AssetID *id_ptr) {
|
|||||||
am->assets[id].data.texture = NULL;
|
am->assets[id].data.texture = NULL;
|
||||||
break;
|
break;
|
||||||
case ASSET_TYPE_AUDIO_FX:
|
case ASSET_TYPE_AUDIO_FX:
|
||||||
// TODO (Abdelrahman): Implement closing audio chunk
|
Mix_FreeChunk(am->assets[id].data.chunk);
|
||||||
|
am->assets[id].data.chunk = NULL;
|
||||||
break;
|
break;
|
||||||
case ASSET_TYPE_MUSIC:
|
case ASSET_TYPE_MUSIC:
|
||||||
// TODO (Abdelrahman): Implement closing music
|
Mix_FreeMusic(am->assets[id].data.music);
|
||||||
|
am->assets[id].data.music = NULL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -289,7 +310,7 @@ void remove_asset_from_manager(AssetManager *am, AssetID *id_ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SDL_Texture *get_texture(AssetManager *am, AssetID id) {
|
SDL_Texture *get_texture(AssetManager *am, AssetID id) {
|
||||||
if (am->assets[id].type != ASSET_TYPE_IMAGE) {
|
if (id < 0 || am->assets[id].type != ASSET_TYPE_IMAGE) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,7 +318,7 @@ SDL_Texture *get_texture(AssetManager *am, AssetID id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Mix_Chunk *get_audio_chunk(AssetManager *am, AssetID id) {
|
Mix_Chunk *get_audio_chunk(AssetManager *am, AssetID id) {
|
||||||
if (am->assets[id].type != ASSET_TYPE_AUDIO_FX) {
|
if (id < 0 || am->assets[id].type != ASSET_TYPE_AUDIO_FX) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,46 +326,48 @@ Mix_Chunk *get_audio_chunk(AssetManager *am, AssetID id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Mix_Music *get_music(AssetManager *am, AssetID id) {
|
Mix_Music *get_music(AssetManager *am, AssetID id) {
|
||||||
if (am->assets[id].type != ASSET_TYPE_MUSIC) {
|
if (id < 0 || am->assets[id].type != ASSET_TYPE_MUSIC) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return am->assets[id].data.music;
|
return am->assets[id].data.music;
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy_asset_manager(AssetManager *am) {
|
void destroy_asset_manager(AssetManager **am) {
|
||||||
if (!am) {
|
if (!(*am)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < am->count; ++i) {
|
for (size_t i = 0; i < (*am)->count; ++i) {
|
||||||
am->user_counter[i] = 0;
|
(*am)->user_counter[i] = 0;
|
||||||
|
|
||||||
size_t hash_index = hash_path(am->assets[i].path);
|
size_t hash_index = hash_path((*am)->assets[i].path);
|
||||||
remove_id_node(&(am->hashed_path_ids[hash_index]), i);
|
remove_id_node(&((*am)->hashed_path_ids[hash_index]), i);
|
||||||
|
|
||||||
free(am->assets[i].path);
|
free((*am)->assets[i].path);
|
||||||
am->assets[i].path = NULL;
|
(*am)->assets[i].path = NULL;
|
||||||
|
|
||||||
switch (am->assets[i].type) {
|
switch ((*am)->assets[i].type) {
|
||||||
case ASSET_TYPE_IMAGE:
|
case ASSET_TYPE_IMAGE:
|
||||||
SDL_DestroyTexture(am->assets[i].data.texture);
|
SDL_DestroyTexture((*am)->assets[i].data.texture);
|
||||||
am->assets[i].data.texture = NULL;
|
(*am)->assets[i].data.texture = NULL;
|
||||||
break;
|
break;
|
||||||
case ASSET_TYPE_AUDIO_FX:
|
case ASSET_TYPE_AUDIO_FX:
|
||||||
// TODO (Abdelrahman): Implement closing audio chunk
|
Mix_FreeChunk((*am)->assets[i].data.chunk);
|
||||||
|
(*am)->assets[i].data.chunk = NULL;
|
||||||
break;
|
break;
|
||||||
case ASSET_TYPE_MUSIC:
|
case ASSET_TYPE_MUSIC:
|
||||||
// TODO (Abdelrahman): Implement closing music
|
Mix_FreeMusic((*am)->assets[i].data.music);
|
||||||
|
(*am)->assets[i].data.music = NULL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
am->count = 0;
|
(*am)->count = 0;
|
||||||
am->deleted_count = 0;
|
(*am)->deleted_count = 0;
|
||||||
|
|
||||||
free(am);
|
free(*am);
|
||||||
am = NULL;
|
*am = NULL;
|
||||||
}
|
}
|
||||||
+360
-10
@@ -6,6 +6,7 @@
|
|||||||
#include "SDL_error.h"
|
#include "SDL_error.h"
|
||||||
#include "SDL_events.h"
|
#include "SDL_events.h"
|
||||||
#include "SDL_image.h"
|
#include "SDL_image.h"
|
||||||
|
#include "SDL_mixer.h"
|
||||||
#include "SDL_pixels.h"
|
#include "SDL_pixels.h"
|
||||||
#include "SDL_render.h"
|
#include "SDL_render.h"
|
||||||
#include "SDL_timer.h"
|
#include "SDL_timer.h"
|
||||||
@@ -13,8 +14,8 @@
|
|||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "engine_build_config.h"
|
#include "engine_build_config.h"
|
||||||
#include "reusable_ids.h"
|
#include "reusable_ids.h"
|
||||||
#include <SDL2/SDL_mixer.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
@@ -32,8 +33,9 @@ INTERNAL struct game_engine {
|
|||||||
AssetManager *asset_manager;
|
AssetManager *asset_manager;
|
||||||
} GameEngine;
|
} GameEngine;
|
||||||
|
|
||||||
bool init_game(const char *game_name, int window_width, int window_height,
|
bool init_game(const char *game_name, uint32_t window_width,
|
||||||
SDL_Color window_background_color, bool full_screen) {
|
uint32_t window_height, SDL_Color window_background_color,
|
||||||
|
bool full_screen, uint8_t audio_tracks) {
|
||||||
bool initialisation_complete = true;
|
bool initialisation_complete = true;
|
||||||
|
|
||||||
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
|
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
|
||||||
@@ -47,11 +49,36 @@ bool init_game(const char *game_name, int window_width, int window_height,
|
|||||||
uint32_t img_flags = IMG_INIT_PNG | IMG_INIT_TIF;
|
uint32_t img_flags = IMG_INIT_PNG | IMG_INIT_TIF;
|
||||||
if ((IMG_Init(img_flags) & img_flags) != img_flags) {
|
if ((IMG_Init(img_flags) & img_flags) != img_flags) {
|
||||||
#ifdef DEBUG_ENGINE
|
#ifdef DEBUG_ENGINE
|
||||||
printf("Failed to initialise SDL. Error: %s\n", IMG_GetError());
|
printf("Failed to initialise SDL_image. Error: %s\n", IMG_GetError());
|
||||||
#endif /* DEBUG_ENGINE */
|
#endif /* DEBUG_ENGINE */
|
||||||
initialisation_complete = false;
|
initialisation_complete = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We're only interested in initialising SDL_mixer with WAVE files, so no
|
||||||
|
// need to pass any flags
|
||||||
|
if (Mix_Init(0) != 0) {
|
||||||
|
#ifdef DEBUG_ENGINE
|
||||||
|
printf("Failed to initialise SDL_mixer. Error: %s\n", Mix_GetError());
|
||||||
|
#endif /* DEBUG_ENGINE */
|
||||||
|
initialisation_complete = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Mix_OpenAudio(48000, MIX_DEFAULT_FORMAT, 2, 2048) < 0) {
|
||||||
|
#ifdef DEBUG_ENGINE
|
||||||
|
printf("Failed to open audio device. Error: %s\n", Mix_GetError());
|
||||||
|
#endif /* DEBUG_ENGINE */
|
||||||
|
initialisation_complete = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audio_tracks > 0) {
|
||||||
|
if (Mix_AllocateChannels(audio_tracks) != audio_tracks) {
|
||||||
|
#ifdef DEBUG_ENGINE
|
||||||
|
printf("Failed to allocate the required tracks.\n");
|
||||||
|
#endif /* DEBUG_ENGINE */
|
||||||
|
initialisation_complete = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!init_window(&(GameEngine.window), game_name, window_width, window_height,
|
if (!init_window(&(GameEngine.window), game_name, window_width, window_height,
|
||||||
window_background_color, full_screen)) {
|
window_background_color, full_screen)) {
|
||||||
#ifdef DEBUG_ENGINE
|
#ifdef DEBUG_ENGINE
|
||||||
@@ -62,13 +89,11 @@ bool init_game(const char *game_name, int window_width, int window_height,
|
|||||||
}
|
}
|
||||||
|
|
||||||
GameEngine.object_store = create_object_store();
|
GameEngine.object_store = create_object_store();
|
||||||
|
|
||||||
if (!(GameEngine.object_store)) {
|
if (!(GameEngine.object_store)) {
|
||||||
initialisation_complete = false;
|
initialisation_complete = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameEngine.asset_manager = create_asset_manager();
|
GameEngine.asset_manager = create_asset_manager();
|
||||||
|
|
||||||
if (!(GameEngine.asset_manager)) {
|
if (!(GameEngine.asset_manager)) {
|
||||||
initialisation_complete = false;
|
initialisation_complete = false;
|
||||||
}
|
}
|
||||||
@@ -125,10 +150,333 @@ void render_texture_asset(AssetID id, float x, float y, float w, float h) {
|
|||||||
|
|
||||||
SDL_Texture *texture = get_texture(GameEngine.asset_manager, id);
|
SDL_Texture *texture = get_texture(GameEngine.asset_manager, id);
|
||||||
|
|
||||||
|
if (!texture) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
render_texture(GameEngine.window.renderer, texture, x, y, w, h);
|
render_texture(GameEngine.window.renderer, texture, x, y, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int8_t play_audio_asset(AssetID id, int16_t loops, bool fade_in,
|
||||||
|
uint32_t fade_length_in_ms) {
|
||||||
|
if (id < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
|
||||||
|
if (!chunk) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fade_in) {
|
||||||
|
return Mix_FadeInChannel(-1, chunk, loops, fade_length_in_ms);
|
||||||
|
} else {
|
||||||
|
return Mix_PlayChannel(-1, chunk, loops);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pause_audio_asset_on_track(AssetID id, uint8_t track) {
|
||||||
|
if (id < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
|
||||||
|
if (!chunk || chunk != Mix_GetChunk(track)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Pause(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resume_audio_asset_on_track(AssetID id, uint8_t track) {
|
||||||
|
if (id < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
|
||||||
|
if (!chunk || chunk != Mix_GetChunk(track)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Resume(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop_audio_asset_on_track(AssetID id, uint8_t track) {
|
||||||
|
if (id < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
|
||||||
|
if (!chunk || chunk != Mix_GetChunk(track)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_HaltChannel(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fade_out_audio_asset_on_track(AssetID id, uint8_t track,
|
||||||
|
uint32_t fade_length_in_ms) {
|
||||||
|
if (id < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
|
||||||
|
if (!chunk || chunk != Mix_GetChunk(track)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_FadeOutChannel(track, fade_length_in_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pause_all_instances_of_audio_asset(AssetID id) {
|
||||||
|
if (id < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
|
||||||
|
if (!chunk) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t channel_count = Mix_AllocateChannels(-1);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < channel_count; ++i) {
|
||||||
|
if (chunk == Mix_GetChunk(i)) {
|
||||||
|
Mix_Pause(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void resume_all_instances_of_audio_asset(AssetID id) {
|
||||||
|
if (id < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
|
||||||
|
if (!chunk) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t channel_count = Mix_AllocateChannels(-1);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < channel_count; ++i) {
|
||||||
|
if (chunk == Mix_GetChunk(i)) {
|
||||||
|
Mix_Resume(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop_all_instances_of_audio_asset(AssetID id) {
|
||||||
|
if (id < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
|
||||||
|
if (!chunk) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t channel_count = Mix_AllocateChannels(-1);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < channel_count; ++i) {
|
||||||
|
if (chunk == Mix_GetChunk(i)) {
|
||||||
|
Mix_HaltChannel(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fade_out_all_instances_of_audio_asset(AssetID id,
|
||||||
|
uint32_t fade_length_in_ms) {
|
||||||
|
if (id < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
|
||||||
|
if (!chunk) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t channel_count = Mix_AllocateChannels(-1);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < channel_count; ++i) {
|
||||||
|
if (chunk == Mix_GetChunk(i)) {
|
||||||
|
Mix_FadeOutChannel(i, fade_length_in_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t get_audio_asset_volume(AssetID id) {
|
||||||
|
if (id < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
|
||||||
|
if (!chunk) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunk->volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_audio_asset_volume(AssetID id, int8_t volume) {
|
||||||
|
if (id < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
|
||||||
|
if (!chunk) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_VolumeChunk(chunk, volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
void play_music_asset(AssetID id, int16_t loops, bool fade_in,
|
||||||
|
uint32_t fade_length_in_ms) {
|
||||||
|
if (id < 0 || is_music_asset_playing(id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Music *music = get_music(GameEngine.asset_manager, id);
|
||||||
|
if (!music) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fade_in) {
|
||||||
|
Mix_FadeInMusic(music, loops, fade_length_in_ms);
|
||||||
|
} else {
|
||||||
|
Mix_PlayMusic(music, loops);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pause_music_asset(AssetID id) {
|
||||||
|
if (id < 0 || !is_music_asset_playing(id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Music *music = get_music(GameEngine.asset_manager, id);
|
||||||
|
if (!music) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_PauseMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
void resume_music_asset(AssetID id) {
|
||||||
|
if (id < 0 || !is_music_asset_playing(id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Music *music = get_music(GameEngine.asset_manager, id);
|
||||||
|
if (!music) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_ResumeMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop_music_asset(AssetID id) {
|
||||||
|
if (id < 0 || !is_music_asset_playing(id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Music *music = get_music(GameEngine.asset_manager, id);
|
||||||
|
if (!music) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_HaltMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
void fade_out_music_asset(AssetID id, uint32_t fade_length_in_ms) {
|
||||||
|
if (id < 0 || !is_music_asset_playing(id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Music *music = get_music(GameEngine.asset_manager, id);
|
||||||
|
if (!music) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_FadeOutMusic(fade_length_in_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t get_music_asset_volume(AssetID id) {
|
||||||
|
if (id < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Music *music = get_music(GameEngine.asset_manager, id);
|
||||||
|
if (!music) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Mix_GetMusicVolume(music);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_music_asset_volume(AssetID id, int8_t volume) {
|
||||||
|
if (id < 0 || !is_music_asset_playing(id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Music *music = get_music(GameEngine.asset_manager, id);
|
||||||
|
if (!music) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_VolumeMusic(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_music_object_playing(Mix_Music *music) {
|
||||||
|
if (!Mix_PlayingMusic()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Mix_GetMusic* functions used here all return the result for the
|
||||||
|
// currently playing music when passed a NULL pointer. We use that to compare
|
||||||
|
// the data of the Mix_Music object passed to the function to the data of the
|
||||||
|
// currently playing music.
|
||||||
|
//
|
||||||
|
// TODO (Abdelrahman): This is a bit of a hack. Figure out if there is
|
||||||
|
// a better alternative to check if a Mix_Music object is currently playing.
|
||||||
|
return Mix_GetMusicType(music) == Mix_GetMusicType(NULL) &&
|
||||||
|
Mix_GetMusicTitle(music) == Mix_GetMusicTitle(NULL) &&
|
||||||
|
Mix_GetMusicArtistTag(music) == Mix_GetMusicArtistTag(NULL) &&
|
||||||
|
Mix_GetMusicAlbumTag(music) == Mix_GetMusicAlbumTag(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_music_asset_playing(AssetID id) {
|
||||||
|
if (id < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mix_Music *music = get_music(GameEngine.asset_manager, id);
|
||||||
|
if (!music) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_music_object_playing(music);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pause_playing_music() { Mix_PauseMusic(); }
|
||||||
|
|
||||||
|
void resume_playing_music() { Mix_ResumeMusic(); }
|
||||||
|
|
||||||
|
void stop_playing_music() { Mix_HaltMusic(); }
|
||||||
|
|
||||||
|
void fade_out_playing_music(uint32_t fade_length_in_ms) {
|
||||||
|
Mix_FadeOutMusic(fade_length_in_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_playing_music_volume(int8_t volume) { Mix_VolumeMusic(volume); }
|
||||||
|
|
||||||
|
bool is_music_playing() { return Mix_PlayingMusic(); }
|
||||||
|
|
||||||
void close_asset(AssetID *id) {
|
void close_asset(AssetID *id) {
|
||||||
|
if (*id < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
remove_asset_from_manager(GameEngine.asset_manager, id);
|
remove_asset_from_manager(GameEngine.asset_manager, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,11 +531,9 @@ void render() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void close_game() {
|
void close_game() {
|
||||||
destroy_asset_manager(GameEngine.asset_manager);
|
destroy_asset_manager(&(GameEngine.asset_manager));
|
||||||
GameEngine.asset_manager = NULL;
|
|
||||||
|
|
||||||
destroy_object_store(GameEngine.object_store);
|
destroy_object_store(&(GameEngine.object_store));
|
||||||
GameEngine.object_store = NULL;
|
|
||||||
|
|
||||||
destroy_window(&(GameEngine.window));
|
destroy_window(&(GameEngine.window));
|
||||||
|
|
||||||
@@ -197,6 +543,10 @@ void close_game() {
|
|||||||
|
|
||||||
GameEngine.running = false;
|
GameEngine.running = false;
|
||||||
|
|
||||||
|
Mix_CloseAudio();
|
||||||
|
|
||||||
|
Mix_Quit();
|
||||||
|
|
||||||
IMG_Quit();
|
IMG_Quit();
|
||||||
|
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
|
|||||||
+11
-11
@@ -136,23 +136,23 @@ void render_all_objects(ObjectStore *os) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy_object_store(ObjectStore *os) {
|
void destroy_object_store(ObjectStore **os) {
|
||||||
if (!os) {
|
if (!(*os)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < os->count; ++i) {
|
for (size_t i = 0; i < (*os)->count; ++i) {
|
||||||
os->object_ptrs[i] = NULL;
|
(*os)->object_ptrs[i] = NULL;
|
||||||
os->event_handlers[i] = NULL;
|
(*os)->event_handlers[i] = NULL;
|
||||||
os->update_funcs[i] = NULL;
|
(*os)->update_funcs[i] = NULL;
|
||||||
os->render_funcs[i] = NULL;
|
(*os)->render_funcs[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
os->count = 0;
|
(*os)->count = 0;
|
||||||
os->deleted_count = 0;
|
(*os)->deleted_count = 0;
|
||||||
|
|
||||||
free(os);
|
free(*os);
|
||||||
os = NULL;
|
*os = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_ENGINE
|
#ifdef DEBUG_ENGINE
|
||||||
|
|||||||
+7
-7
@@ -68,15 +68,15 @@ SDL_Texture *load_texture(const Renderer *renderer, const char *path) {
|
|||||||
return IMG_LoadTexture(renderer->SDL_base_renderer, path);
|
return IMG_LoadTexture(renderer->SDL_base_renderer, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy_renderer(Renderer *renderer) {
|
void destroy_renderer(Renderer **renderer) {
|
||||||
if (renderer) {
|
if (*renderer) {
|
||||||
if (renderer->SDL_base_renderer) {
|
if ((*renderer)->SDL_base_renderer) {
|
||||||
SDL_DestroyRenderer(renderer->SDL_base_renderer);
|
SDL_DestroyRenderer((*renderer)->SDL_base_renderer);
|
||||||
renderer->SDL_base_renderer = NULL;
|
(*renderer)->SDL_base_renderer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(renderer);
|
free(*renderer);
|
||||||
renderer = NULL;
|
*renderer = NULL;
|
||||||
|
|
||||||
#ifdef DEBUG_ENGINE
|
#ifdef DEBUG_ENGINE
|
||||||
printf("Renderer destroyed successfully\n");
|
printf("Renderer destroyed successfully\n");
|
||||||
|
|||||||
+1
-2
@@ -71,8 +71,7 @@ void destroy_window(Window *wnd) {
|
|||||||
|
|
||||||
if (wnd->SDL_base_window) {
|
if (wnd->SDL_base_window) {
|
||||||
if (wnd->renderer) {
|
if (wnd->renderer) {
|
||||||
destroy_renderer(wnd->renderer);
|
destroy_renderer(&(wnd->renderer));
|
||||||
wnd->renderer = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_DestroyWindow(wnd->SDL_base_window);
|
SDL_DestroyWindow(wnd->SDL_base_window);
|
||||||
|
|||||||
Reference in new issue
Block a user