diff --git a/Dengine.vcxproj b/Dengine.vcxproj index 076fd51..810de60 100644 --- a/Dengine.vcxproj +++ b/Dengine.vcxproj @@ -131,7 +131,6 @@ - diff --git a/Dengine.vcxproj.filters b/Dengine.vcxproj.filters index 9c094ae..98651a6 100644 --- a/Dengine.vcxproj.filters +++ b/Dengine.vcxproj.filters @@ -15,9 +15,6 @@ - - Source Files - Source Files diff --git a/src/AssetManager.c b/src/AssetManager.c index 37e4e89..1b9d983 100644 --- a/src/AssetManager.c +++ b/src/AssetManager.c @@ -80,6 +80,7 @@ const i32 asset_loadVorbis(AssetManager *assetManager, MemoryArena *arena, i32 error; AudioVorbis audio = {0}; + audio.type = type; audio.file = stb_vorbis_open_memory(fileRead.buffer, fileRead.size, &error, NULL); @@ -94,6 +95,8 @@ const i32 asset_loadVorbis(AssetManager *assetManager, MemoryArena *arena, audio.info = stb_vorbis_get_info(audio.file); audio.lengthInSamples = stb_vorbis_stream_length_in_samples(audio.file); audio.lengthInSeconds = stb_vorbis_stream_length_in_seconds(audio.file); + audio.data = CAST(u8 *) fileRead.buffer; + audio.size = fileRead.size; assetManager->audio[type] = audio; diff --git a/src/Audio.c b/src/Audio.c index 46bb7b3..41a232b 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -6,6 +6,8 @@ #include "Dengine/Assets.h" #include "Dengine/Audio.h" #include "Dengine/Debug.h" +#include "Dengine/MemoryArena.h" +#include "dengine/Platform.h" #define AL_CHECK_ERROR() alCheckError_(__FILE__, __LINE__); void alCheckError_(const char *file, int line) @@ -101,13 +103,8 @@ const i32 audio_init(AudioManager *audioManager) alGenSources(1, &audioManager->sourceList[i].id); AL_CHECK_ERROR(); - // NOTE(doyle): If last entry, loop the free source to front of list - if (i + 1 >= ARRAY_COUNT(audioManager->sourceList)) - audioManager->sourceList[i].nextFreeIndex = 0; - else - audioManager->sourceList[i].nextFreeIndex = i+1; + audioManager->sourceList[i].isFree = TRUE; } - audioManager->freeSourceIndex = 0; return 0; } @@ -119,44 +116,41 @@ INTERNAL inline u32 getSourceId(AudioManager *audioManager, return result; } -INTERNAL i32 rendererAcquire(AudioManager *audioManager, +INTERNAL i32 rendererAcquire(MemoryArena *arena, AudioManager *audioManager, AudioRenderer *audioRenderer) { - - i32 vacantSource = audioManager->freeSourceIndex; - #ifdef DENGINE_DEBUG - ASSERT(audioManager && audioRenderer); - ASSERT(vacantSource >= 0); + ASSERT(arena && audioManager && audioRenderer); #endif - - if (audioManager->sourceList[vacantSource].nextFreeIndex == - AUDIO_NO_FREE_SOURCE) - { - // TODO(doyle): Error messaging return paths - DEBUG_LOG("rendererAcquire(): Failed to acquire free source, all busy"); - return -1; - } - u32 checkSource = getSourceId(audioManager, audioRenderer); if (alIsSource(checkSource) == AL_TRUE) { DEBUG_LOG( "rendererAcquire(): Renderer has not been released before " "acquiring, force release by stopping stream"); - audio_streamStopVorbis(audioManager, audioRenderer); + audio_streamStopVorbis(arena, audioManager, audioRenderer); + } + + // TODO(doyle): Super bad linear O(n) search for every audio-enabled entity + i32 vacantSource = AUDIO_SOURCE_UNASSIGNED; + for (i32 i = 0; i < ARRAY_COUNT(audioManager->sourceList); i++) + { + if (audioManager->sourceList[i].isFree) + { + vacantSource = i; + audioManager->sourceList[i].isFree = FALSE; + break; + } + } + + if (vacantSource == AUDIO_SOURCE_UNASSIGNED) + { + DEBUG_LOG("rendererAcquire(): Failed to acquire free source, all busy"); + return -1; } - /* Assign a vacant source slot to renderer */ audioRenderer->sourceIndex = vacantSource; - /* Update the immediate free source index */ - audioManager->freeSourceIndex = - audioManager->sourceList[vacantSource].nextFreeIndex; - - /* Mark current source as in use */ - audioManager->sourceList[vacantSource].nextFreeIndex = AUDIO_NO_FREE_SOURCE; - /* Generate audio data buffers */ alGenBuffers(ARRAY_COUNT(audioRenderer->bufferId), audioRenderer->bufferId); AL_CHECK_ERROR(); @@ -166,8 +160,8 @@ INTERNAL i32 rendererAcquire(AudioManager *audioManager, return 0; } -INTERNAL const i32 rendererRelease(AudioManager *audioManager, - AudioRenderer *audioRenderer) +INTERNAL const i32 rendererRelease(MemoryArena *arena, AudioManager *audioManager, + AudioRenderer *audioRenderer) { i32 result = 0; @@ -181,8 +175,29 @@ INTERNAL const i32 rendererRelease(AudioManager *audioManager, return result; } - alSourceUnqueueBuffers(alSourceId, ARRAY_COUNT(audioRenderer->bufferId), - audioRenderer->bufferId); + /* + NOTE(doyle): Doing an alSourceRewind will result in the source going to + the AL_INITIAL state, but the properties of the source (position, + velocity, etc.) will not change. + */ + alSourceRewind(alSourceId); + AL_CHECK_ERROR(); + + // TODO(doyle): We can possible remove this by just attaching the null buffer .. + ALint numProcessedBuffers; + alGetSourcei(alSourceId, AL_BUFFERS_PROCESSED, &numProcessedBuffers); + if (numProcessedBuffers > 0) + { + alSourceUnqueueBuffers(alSourceId, numProcessedBuffers, + audioRenderer->bufferId); + } + AL_CHECK_ERROR(); + + // NOTE(doyle): Any buffer queued up that has not been played cannot be + // deleted without being played once. We can set the source buffers to NULL + // (0) to free up the buffer, since we still hold the reference ids for the + // buffer in our audio structure we can delete it afterwards .. + alSourcei(alSourceId, AL_BUFFER, 0); alDeleteBuffers(ARRAY_COUNT(audioRenderer->bufferId), audioRenderer->bufferId); AL_CHECK_ERROR(); @@ -192,21 +207,22 @@ INTERNAL const i32 rendererRelease(AudioManager *audioManager, audioRenderer->bufferId[i] = 0; } - audioRenderer->audio = NULL; - audioRenderer->numPlays = 0; + stb_vorbis_close(audioRenderer->audio->file); + PLATFORM_MEM_FREE(arena, audioRenderer->audio, sizeof(AudioVorbis)); + + audioRenderer->audio = NULL; + audioRenderer->numPlays = 0; u32 sourceIndexToFree = audioRenderer->sourceIndex; audioRenderer->sourceIndex = AUDIO_SOURCE_UNASSIGNED; - audioManager->sourceList[sourceIndexToFree].nextFreeIndex = - audioManager->freeSourceIndex; - audioManager->freeSourceIndex = sourceIndexToFree; + audioManager->sourceList[sourceIndexToFree].isFree = TRUE; return result; } #define AUDIO_CHUNK_SIZE_ 65536 -const i32 audio_streamPlayVorbis(AudioManager *audioManager, +const i32 audio_streamPlayVorbis(MemoryArena *arena, AudioManager *audioManager, AudioRenderer *audioRenderer, AudioVorbis *vorbis, i32 numPlays) { @@ -218,7 +234,7 @@ const i32 audio_streamPlayVorbis(AudioManager *audioManager, } #endif - i32 result = rendererAcquire(audioManager, audioRenderer); + i32 result = rendererAcquire(arena, audioManager, audioRenderer); if (result) { DEBUG_LOG("audio_streamPlayVorbis() failed: Could not acquire renderer"); @@ -237,14 +253,31 @@ const i32 audio_streamPlayVorbis(AudioManager *audioManager, #endif } - audioRenderer->audio = vorbis; + // NOTE(doyle): We make a copy of the audio vorbis file using all the same + // data except the file pointer. If the same sound is playing twice + // simultaneously, we need unique file pointers into the data to track song + // position uniquely + AudioVorbis *copyAudio = PLATFORM_MEM_ALLOC(arena, 1, AudioVorbis); + copyAudio->type = vorbis->type; + copyAudio->info = vorbis->info; + copyAudio->lengthInSamples = vorbis->lengthInSamples; + copyAudio->lengthInSeconds = vorbis->lengthInSeconds; + + copyAudio->data = vorbis->data; + copyAudio->size = vorbis->size; + + i32 error; + copyAudio->file = + stb_vorbis_open_memory(copyAudio->data, copyAudio->size, &error, NULL); + + audioRenderer->audio = copyAudio; audioRenderer->numPlays = numPlays; return 0; } -const i32 audio_streamStopVorbis(AudioManager *audioManager, - AudioRenderer *audioRenderer) +const i32 audio_streamStopVorbis(MemoryArena *arena, AudioManager *audioManager, + AudioRenderer *audioRenderer) { i32 result = 0; u32 alSourceId = getSourceId(audioManager, audioRenderer); @@ -252,7 +285,7 @@ const i32 audio_streamStopVorbis(AudioManager *audioManager, { alSourceStop(alSourceId); AL_CHECK_ERROR(); - result = rendererRelease(audioManager, audioRenderer); + result = rendererRelease(arena, audioManager, audioRenderer); } else { @@ -300,18 +333,20 @@ const i32 audio_streamResumeVorbis(AudioManager *audioManager, return result; } -const i32 audio_updateAndPlay(AudioManager *audioManager, +const i32 audio_updateAndPlay(MemoryArena *arena, AudioManager *audioManager, AudioRenderer *audioRenderer) { AudioVorbis *audio = audioRenderer->audio; if (!audio) return 0; +#if 0 if (audioRenderer->numPlays != AUDIO_REPEAT_INFINITE && audioRenderer->numPlays <= 0) { - i32 result = rendererRelease(audioManager, audioRenderer); + i32 result = rendererRelease(arena, audioManager, audioRenderer); return result; } +#endif u32 alSourceId = getSourceId(audioManager, audioRenderer); if (alIsSource(alSourceId) == AL_FALSE) @@ -345,13 +380,12 @@ const i32 audio_updateAndPlay(AudioManager *audioManager, } else { - i32 result = rendererRelease(audioManager, audioRenderer); + i32 result = + rendererRelease(arena, audioManager, audioRenderer); return result; } } - // TODO(doyle): Possible bug! Multiple sources playing same file seeking - // file ptr to start may interrupt other stream stb_vorbis_seek_start(audio->file); for (i32 i = 0; i < ARRAY_COUNT(audioRenderer->bufferId); i++) { @@ -380,6 +414,7 @@ const i32 audio_updateAndPlay(AudioManager *audioManager, AL_CHECK_ERROR(); if (numProcessedBuffers > 0) { + // TODO(doyle): Possibly wrong, we should pass in all processed buffers? ALint numBuffersToUnqueue = 1; ALuint emptyBufferId; alSourceUnqueueBuffers(alSourceId, numBuffersToUnqueue, diff --git a/src/Debug.c b/src/Debug.c index 88e49ed..5cdc562 100644 --- a/src/Debug.c +++ b/src/Debug.c @@ -189,6 +189,13 @@ void debug_pushString(char *formatString, void *data, char *dataType) ARRAY_COUNT(GLOBAL_debug.debugStrings[0]), formatString, val.x, val.y); } + else if (common_strcmp(dataType, "v3") == 0) + { + v3 val = *(CAST(v3 *) data); + snprintf(GLOBAL_debug.debugStrings[numDebugStrings], + ARRAY_COUNT(GLOBAL_debug.debugStrings[0]), + formatString, val.x, val.y, val.z); + } else if (common_strcmp(dataType, "i32") == 0) { i32 val = *(CAST(i32 *) data); @@ -394,6 +401,19 @@ void debug_drawUi(GameState *state, f32 dt) char *entityStateStr = debug_entitystate_string(entity->state); renderer_string(&state->renderer, &state->arena, cameraBounds, font, entityStateStr, strPos, V2(0, 0), 0, color); + + if (entity->audioRenderer) + { + strPos.y -= GLOBAL_debug.stringLineGap; + char entityAudioSourceIndex[32]; + snprintf(entityAudioSourceIndex, + ARRAY_COUNT(entityAudioSourceIndex), + "AudioSource Index: %d", + entity->audioRenderer->sourceIndex); + renderer_string(&state->renderer, &state->arena, cameraBounds, + font, entityAudioSourceIndex, strPos, V2(0, 0), + 0, color); + } } } @@ -418,6 +438,15 @@ void debug_drawUi(GameState *state, f32 dt) i32 debug_kbAllocated = state->arena.bytesAllocated / 1024; DEBUG_PUSH_VAR("TotalMemoryAllocated: %dkb", debug_kbAllocated, "i32"); + AudioManager *audioManager = &state->audioManager; + DEBUG_PUSH_STRING("== Audio System =="); + for (i32 i = 0; i < ARRAY_COUNT(audioManager->sourceList); i++) + { + v3 tmp = V3i(i, audioManager->sourceList[i].id, + audioManager->sourceList[i].isFree); + DEBUG_PUSH_VAR("Source ID[%02.0f].id[%02.0f].isFree: %1.0f", tmp, "v3"); + } + DEBUG_PUSH_STRING("== EntityIDs in Battle List == "); DEBUG_PUSH_VAR("NumEntitiesInBattle: %d", world->numEntitiesInBattle, "i32"); diff --git a/src/Entity.c b/src/Entity.c index 04d2beb..773cf1a 100644 --- a/src/Entity.c +++ b/src/Entity.c @@ -77,13 +77,16 @@ void entity_addGenericMob(MemoryArena *arena, AssetManager *assetManager, b32 collides = TRUE; Entity *mob = entity_add(arena, world, pos, size, type, dir, tex, collides); + mob->audioRenderer = PLATFORM_MEM_ALLOC(arena, 1, AudioRenderer); + mob->audioRenderer->sourceIndex = AUDIO_SOURCE_UNASSIGNED; + /* Populate mob animation references */ entity_addAnim(assetManager, mob, animlist_hero_idle); entity_addAnim(assetManager, mob, animlist_hero_walk); entity_addAnim(assetManager, mob, animlist_hero_wave); entity_addAnim(assetManager, mob, animlist_hero_battlePose); entity_addAnim(assetManager, mob, animlist_hero_tackle); - mob->currAnimId = animlist_hero_idle; + mob->currAnimId = animlist_hero_idle; } Entity *entity_add(MemoryArena *arena, World *world, v2 pos, v2 size, @@ -125,7 +128,7 @@ Entity *entity_add(MemoryArena *arena, World *world, v2 pos, v2 size, entity.stats = PLATFORM_MEM_ALLOC(arena, 1, EntityStats); entity.stats->maxHealth = 100; entity.stats->health = entity.stats->maxHealth; - entity.stats->actionRate = 100; + entity.stats->actionRate = 80; entity.stats->actionTimer = entity.stats->actionRate; entity.stats->actionSpdMul = 100; entity.stats->entityIdToAttack = -1; @@ -147,7 +150,12 @@ Entity *entity_add(MemoryArena *arena, World *world, v2 pos, v2 size, void entity_delete(MemoryArena *arena, World *world, i32 entityIndex) { Entity *entity = &world->entities[entityIndex]; - PLATFORM_MEM_FREE(arena, entity->stats, sizeof(EntityStats)); + + if (entity->stats) + PLATFORM_MEM_FREE(arena, entity->stats, sizeof(EntityStats)); + + if (entity->audioRenderer) + PLATFORM_MEM_FREE(arena, entity->audioRenderer, sizeof(AudioRenderer)); // TODO(doyle): Inefficient shuffle down all elements for (i32 i = entityIndex; i < world->freeEntityIndex - 1; i++) diff --git a/src/WorldTraveller.c b/src/WorldTraveller.c index 9c7d4d0..3b50675 100644 --- a/src/WorldTraveller.c +++ b/src/WorldTraveller.c @@ -187,6 +187,8 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize) asset_loadVorbis(assetManager, arena, audioPath, audiolist_battle); audioPath = "data/audio/Yuki Kajiura - Swordland.ogg"; asset_loadVorbis(assetManager, arena, audioPath, audiolist_overworld); + audioPath = "data/audio/nuindependent_hit22.ogg"; + asset_loadVorbis(assetManager, arena, audioPath, audiolist_tackle); #ifdef DENGINE_DEBUG DEBUG_LOG("Sound assets initialised"); @@ -278,6 +280,8 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize) tex = asset_getTexture(assetManager, texlist_hero); collides = TRUE; Entity *hero = entity_add(arena, world, pos, size, type, dir, tex, collides); + hero->audioRenderer = PLATFORM_MEM_ALLOC(arena, 1, AudioRenderer); + hero->audioRenderer->sourceIndex = AUDIO_SOURCE_UNASSIGNED; /* Populate hero animation references */ entity_addAnim(assetManager, hero, animlist_hero_idle); @@ -579,7 +583,6 @@ INTERNAL inline void resetEntityState(World *world, Entity *entity) INTERNAL void beginAttack(World *world, Entity *attacker) { - #ifdef DENGINE_DEBUG ASSERT(attacker->stats->entityIdToAttack != ENTITY_NULL_ID); ASSERT(attacker->state == entitystate_battle); @@ -596,17 +599,18 @@ INTERNAL void beginAttack(World *world, Entity *attacker) attacker->dPos.x += (1.0f * METERS_TO_PIXEL); else attacker->dPos.x -= (1.0f * METERS_TO_PIXEL); - break; default: #ifdef DENGINE_DEBUG ASSERT(INVALID_CODE_PATH); #endif + break; } - } -INTERNAL void endAttack(World *world, Entity *attacker) +INTERNAL void endAttack(MemoryArena *arena, AssetManager *assetManager, + AudioManager *audioManager, World *world, + Entity *attacker) { #ifdef DENGINE_DEBUG ASSERT(attacker->stats->entityIdToAttack != ENTITY_NULL_ID); @@ -621,11 +625,18 @@ INTERNAL void endAttack(World *world, Entity *attacker) else attacker->dPos.x += (1.0f * METERS_TO_PIXEL); +#if 1 + audio_streamPlayVorbis(arena, audioManager, attacker->audioRenderer, + asset_getVorbis(assetManager, audiolist_tackle), + 1); +#endif + break; default: #ifdef DENGINE_DEBUG ASSERT(INVALID_CODE_PATH); #endif + break; } /* Compute attack damage */ @@ -681,8 +692,9 @@ INTERNAL void endAttack(World *world, Entity *attacker) } } -INTERNAL void entityStateSwitch(World *world, Entity *entity, - enum EntityState newState) +INTERNAL void entityStateSwitch(MemoryArena *arena, AssetManager *assetManager, + AudioManager *audioManager, World *world, + Entity *entity, enum EntityState newState) { #ifdef DENGINE_DEBUG ASSERT(world && entity) @@ -718,6 +730,7 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity, #ifdef DENGINE_DEBUG ASSERT(INVALID_CODE_PATH); #endif + break; } break; case entitystate_battle: @@ -736,13 +749,14 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity, #ifdef DENGINE_DEBUG ASSERT(INVALID_CODE_PATH); #endif + break; } break; case entitystate_attack: switch (newState) { case entitystate_battle: - endAttack(world, entity); + endAttack(arena, assetManager, audioManager, world, entity); entity_setActiveAnim(entity, animlist_hero_battlePose); entity->stats->actionTimer = entity->stats->actionRate; entity->stats->busyDuration = 0; @@ -756,6 +770,7 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity, #ifdef DENGINE_DEBUG ASSERT(INVALID_CODE_PATH); #endif + break; } break; case entitystate_dead: @@ -768,12 +783,14 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity, #ifdef DENGINE_DEBUG ASSERT(INVALID_CODE_PATH); #endif + break; } break; default: #ifdef DENGINE_DEBUG ASSERT(INVALID_CODE_PATH); #endif + break; } entity->state = newState; @@ -790,45 +807,64 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) Renderer *renderer = &state->renderer; World *const world = &state->world[state->currWorldIndex]; Font *font = &assetManager->font; + MemoryArena *arena = &state->arena; /* ****************************** * Update entities and render ****************************** */ - Entity *hero = getHeroEntity(world); - v4 cameraBounds = createCameraBounds(world, renderer->size); + Entity *hero = getHeroEntity(world); + v4 cameraBounds = createCameraBounds(world, renderer->size); + AudioManager *audioManager = &state->audioManager; ASSERT(world->freeEntityIndex < world->maxEntities); for (i32 i = 0; i < world->freeEntityIndex; i++) { Entity *const entity = &world->entities[i]; - if (entity->audioRenderer) + if (entity->type == entitytype_soundscape) { AudioRenderer *audioRenderer = entity->audioRenderer; if (world->numEntitiesInBattle > 0) { AudioVorbis *battleTheme = asset_getVorbis(assetManager, audiolist_battle); - if (audioRenderer->audio != battleTheme) + if (audioRenderer->audio) { - audio_streamPlayVorbis(&state->audioManager, audioRenderer, - battleTheme, AUDIO_REPEAT_INFINITE); + if (audioRenderer->audio->type != audiolist_battle) + { + audio_streamPlayVorbis(arena, &state->audioManager, + audioRenderer, battleTheme, + AUDIO_REPEAT_INFINITE); + } + } + else + { + audio_streamPlayVorbis(arena, &state->audioManager, + audioRenderer, battleTheme, + AUDIO_REPEAT_INFINITE); } } else { AudioVorbis *overworldTheme = asset_getVorbis(assetManager, audiolist_overworld); - if (audioRenderer->audio != overworldTheme) + if (audioRenderer->audio) { - audio_streamPlayVorbis(&state->audioManager, audioRenderer, - overworldTheme, + if (audioRenderer->audio->type != audiolist_overworld) + { + audio_streamPlayVorbis(arena, &state->audioManager, + audioRenderer, overworldTheme, + AUDIO_REPEAT_INFINITE); + } + } + else + { + audio_streamPlayVorbis(arena, &state->audioManager, + audioRenderer, overworldTheme, AUDIO_REPEAT_INFINITE); } } - - audio_updateAndPlay(&state->audioManager, entity->audioRenderer); } if (entity->state == entitystate_dead) @@ -849,6 +885,8 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) // an entity dies #if 1 i32 entityIndexInArray = i; + audio_streamStopVorbis(arena, &state->audioManager, + entity->audioRenderer); entity_delete(&state->arena, world, entityIndexInArray); // TODO(doyle): DeleteEntity moves elements down 1, so account for i @@ -888,7 +926,8 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) newState = entitystate_idle; } - entityStateSwitch(world, entity, newState); + entityStateSwitch(arena, assetManager, audioManager, world, entity, + newState); } /* @@ -911,7 +950,8 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) stats->queuedAttack = entityattack_tackle; /* Launch up attack animation */ - entityStateSwitch(world, entity, entitystate_attack); + entityStateSwitch(arena, assetManager, audioManager, world, + entity, entitystate_attack); } } else if (entity->state == entitystate_attack) @@ -922,7 +962,8 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) if (stats->busyDuration <= 0) { /* Apply attack damage */ - entityStateSwitch(world, entity, entitystate_battle); + entityStateSwitch(arena, assetManager, audioManager, world, + entity, entitystate_battle); /* Get target entity that was attacked */ Entity *defender = NULL; @@ -946,13 +987,21 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) #ifdef DENGINE_DEBUG DEBUG_LOG("Entity has died"); #endif - entityStateSwitch(world, defender, entitystate_dead); - entityStateSwitch(world, attacker, entitystate_idle); + entityStateSwitch(arena, assetManager, audioManager, world, defender, + entitystate_dead); + entityStateSwitch(arena, assetManager, audioManager, world, attacker, + entitystate_idle); } } } } + if (entity->audioRenderer) + { + audio_updateAndPlay(&state->arena, &state->audioManager, + entity->audioRenderer); + } + /* ************************************************** * Update animations and render entity @@ -973,10 +1022,10 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) // NOTE(doyle): If battle entities is 1 then only the hero left if (hero->state == entitystate_battle && world->numEntitiesInBattle == 1) - entityStateSwitch(world, hero, entitystate_idle); + entityStateSwitch(arena, assetManager, audioManager, world, hero, entitystate_idle); else if (hero->state != entitystate_attack) { - entityStateSwitch(world, hero, entitystate_battle); + entityStateSwitch(arena, assetManager, audioManager, world, hero, entitystate_battle); } } else diff --git a/src/include/Dengine/Assets.h b/src/include/Dengine/Assets.h index 27bdcf8..24ea2c7 100644 --- a/src/include/Dengine/Assets.h +++ b/src/include/Dengine/Assets.h @@ -62,17 +62,22 @@ enum AudioList { audiolist_battle, audiolist_overworld, + audiolist_tackle, audiolist_count, audiolist_invalid, }; typedef struct AudioVorbis { + enum AudioList type; stb_vorbis *file; stb_vorbis_info info; u32 lengthInSamples; f32 lengthInSeconds; + + u8 *data; + i32 size; } AudioVorbis; typedef struct TexAtlas diff --git a/src/include/Dengine/Audio.h b/src/include/Dengine/Audio.h index 06fd87c..8a2e61e 100644 --- a/src/include/Dengine/Audio.h +++ b/src/include/Dengine/Audio.h @@ -5,20 +5,22 @@ #include "Dengine/Common.h" +/* Forward Declaration */ +typedef struct MemoryArena MemoryArena; + #define AUDIO_NO_FREE_SOURCE -1 typedef struct AudioSourceEntry { u32 id; - i32 nextFreeIndex; + b32 isFree; } AudioSourceEntry; +// TODO(doyle): Incorporate memory arena into managers? #define AUDIO_MAX_SOURCES 32 typedef struct AudioManager { // NOTE(doyle): Source entries point to the next free index AudioSourceEntry sourceList[AUDIO_MAX_SOURCES]; - i32 freeSourceIndex; - } AudioManager; @@ -36,15 +38,15 @@ typedef struct AudioRenderer const i32 audio_init(AudioManager *audioManager); -const i32 audio_streamPlayVorbis(AudioManager *audioManager, +const i32 audio_streamPlayVorbis(MemoryArena *arena, AudioManager *audioManager, AudioRenderer *audioRenderer, AudioVorbis *vorbis, i32 numPlays); -const i32 audio_streamStopVorbis(AudioManager *audioManager, +const i32 audio_streamStopVorbis(MemoryArena *arena, AudioManager *audioManager, AudioRenderer *audioRenderer); const i32 audio_streamPauseVorbis(AudioManager *audioManager, AudioRenderer *audioRenderer); const i32 audio_streamResumeVorbis(AudioManager *audioManager, AudioRenderer *audioRenderer); -const i32 audio_updateAndPlay(AudioManager *audioManager, +const i32 audio_updateAndPlay(MemoryArena *arena, AudioManager *audioManager, AudioRenderer *audioRenderer); #endif diff --git a/src/include/Dengine/Math.h b/src/include/Dengine/Math.h index a635941..b1dc035 100644 --- a/src/include/Dengine/Math.h +++ b/src/include/Dengine/Math.h @@ -55,6 +55,11 @@ INTERNAL inline v2 V2(const f32 x, const f32 y) v2 result = {x, y}; return result; } +INTERNAL inline v3 V3i(const i32 x, const i32 y, const i32 z) +{ + v3 result = {CAST(f32)x, CAST(f32)y, CAST(f32)z}; + return result; +} INTERNAL inline v3 V3(const f32 x, const f32 y, const f32 z) { v3 result = {x, y, z}; diff --git a/src/include/Dengine/WorldTraveller.h b/src/include/Dengine/WorldTraveller.h index f808418..67bf108 100644 --- a/src/include/Dengine/WorldTraveller.h +++ b/src/include/Dengine/WorldTraveller.h @@ -15,7 +15,6 @@ typedef struct MemoryArena MemoryArena; #define NUM_KEYS 1024 #define METERS_TO_PIXEL 240 - typedef struct World { Entity *entities;