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;