From 4795fe1cb13595f407ffef6b44347e9c0e4f8885 Mon Sep 17 00:00:00 2001 From: Doyle Thai Date: Wed, 9 Nov 2016 22:36:41 +1100 Subject: [PATCH] Switch developing game to asteroids, start project Switch to something of smaller scope in aim to be able to finish a project from start to finish. Also allow refreshed eyes to review the existing API and see what can be improved on after taking a short break from the project. --- Dengine.vcxproj | 6 +- Dengine.vcxproj.filters | 18 +- .clang-format => src/.clang-format | 0 src/Asteroid.c | 241 +++ src/Debug.c | 282 +-- src/Entity.c | 164 +- src/Platform.c | 4 +- src/Renderer.c | 28 +- src/WorldTraveller.c | 2477 -------------------------- src/build.bat | 9 + src/dengine.c | 31 +- src/include/Dengine/Assets.h | 1 - src/include/Dengine/Asteroid.h | 31 + src/include/Dengine/Common.h | 2 + src/include/Dengine/Entity.h | 91 +- src/include/Dengine/MemoryArena.h | 12 +- src/include/Dengine/Platform.h | 10 +- src/include/Dengine/Renderer.h | 2 +- src/include/Dengine/WorldTraveller.h | 109 -- 19 files changed, 358 insertions(+), 3160 deletions(-) rename .clang-format => src/.clang-format (100%) create mode 100644 src/Asteroid.c delete mode 100644 src/WorldTraveller.c create mode 100644 src/include/Dengine/Asteroid.h delete mode 100644 src/include/Dengine/WorldTraveller.h diff --git a/Dengine.vcxproj b/Dengine.vcxproj index 0b3c0cf..d471d3e 100644 --- a/Dengine.vcxproj +++ b/Dengine.vcxproj @@ -121,18 +121,17 @@ + - - @@ -143,14 +142,15 @@ + + - diff --git a/Dengine.vcxproj.filters b/Dengine.vcxproj.filters index e50c137..e816c49 100644 --- a/Dengine.vcxproj.filters +++ b/Dengine.vcxproj.filters @@ -15,9 +15,6 @@ - - Source Files - Source Files @@ -42,9 +39,6 @@ Source Files - - Source Files - Source Files @@ -57,6 +51,9 @@ Source Files + + Source Files + @@ -86,9 +83,6 @@ Header Files - - Header Files - Header Files @@ -116,5 +110,11 @@ Header Files + + Header Files + + + Header Files + \ No newline at end of file diff --git a/.clang-format b/src/.clang-format similarity index 100% rename from .clang-format rename to src/.clang-format diff --git a/src/Asteroid.c b/src/Asteroid.c new file mode 100644 index 0000000..365cb50 --- /dev/null +++ b/src/Asteroid.c @@ -0,0 +1,241 @@ +#include "Dengine/Asteroid.h" +#include "Dengine/Debug.h" + +void initAssetManager(GameState *state) +{ + AssetManager *assetManager = &state->assetManager; + MemoryArena_ *arena = &state->persistentArena; + + i32 audioEntries = 32; + assetManager->audio.size = audioEntries; + assetManager->audio.entries = + memory_pushBytes(arena, audioEntries * sizeof(HashTableEntry)); + + i32 texAtlasEntries = 8; + assetManager->texAtlas.size = texAtlasEntries; + assetManager->texAtlas.entries = + memory_pushBytes(arena, texAtlasEntries * sizeof(HashTableEntry)); + + i32 texEntries = 32; + assetManager->textures.size = texEntries; + assetManager->textures.entries = + memory_pushBytes(arena, texEntries * sizeof(HashTableEntry)); + + i32 animEntries = 1024; + assetManager->anims.size = animEntries; + assetManager->anims.entries = + memory_pushBytes(arena, animEntries * sizeof(HashTableEntry)); + + /* Create empty 1x1 4bpp black texture */ + u32 bitmap = (0xFF << 24) | (0xFF << 16) | (0xFF << 8) | (0xFF << 0); + Texture *tex = asset_getFreeTexSlot(assetManager, arena, "nullTex"); + *tex = texture_gen(1, 1, 4, CAST(u8 *)(&bitmap)); + + /* Load shaders */ + asset_loadShaderFiles(assetManager, arena, "data/shaders/sprite.vert.glsl", + "data/shaders/sprite.frag.glsl", + shaderlist_sprite); + + i32 result = + asset_loadTTFont(assetManager, arena, "C:/Windows/Fonts/Arialbd.ttf"); + + if (result) { + ASSERT(TRUE); + } +} + +void initRenderer(GameState *state, v2 windowSize) { + AssetManager *assetManager = &state->assetManager; + Renderer *renderer = &state->renderer; + renderer->size = windowSize; + + // NOTE(doyle): Value to map a screen coordinate to NDC coordinate + renderer->vertexNdcFactor = + V2(1.0f / renderer->size.w, 1.0f / renderer->size.h); + renderer->shader = asset_getShader(assetManager, shaderlist_sprite); + shader_use(renderer->shader); + + const mat4 projection = + mat4_ortho(0.0f, renderer->size.w, 0.0f, renderer->size.h, 0.0f, 1.0f); + shader_uniformSetMat4fv(renderer->shader, "projection", projection); + GL_CHECK_ERROR(); + + /* Create buffers */ + glGenVertexArrays(1, &renderer->vao); + glGenBuffers(1, &renderer->vbo); + GL_CHECK_ERROR(); + + /* Bind buffers */ + glBindBuffer(GL_ARRAY_BUFFER, renderer->vbo); + glBindVertexArray(renderer->vao); + + /* Configure VAO */ + u32 numVertexElements = 4; + u32 stride = sizeof(Vertex); + glVertexAttribPointer(0, numVertexElements, GL_FLOAT, GL_FALSE, stride, + (GLvoid *)0); + glEnableVertexAttribArray(0); + + GL_CHECK_ERROR(); + + /* Unbind */ + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + GL_CHECK_ERROR(); + + // TODO(doyle): Lazy allocate render group capacity + renderer->groupCapacity = 4096; + for (i32 i = 0; i < ARRAY_COUNT(renderer->groups); i++) + { + renderer->groups[i].vertexList = memory_pushBytes( + &state->persistentArena, renderer->groupCapacity * sizeof(Vertex)); + } +} + +enum ReadKeyType +{ + readkeytype_oneShot, + readkeytype_delayedRepeat, + readkeytype_repeat, + readkeytype_count, +}; + +#define KEY_DELAY_NONE 0.0f +INTERNAL b32 getKeyStatus(KeyState *key, enum ReadKeyType readType, + f32 delayInterval, f32 dt) +{ + + if (!key->endedDown) return FALSE; + + switch(readType) + { + case readkeytype_oneShot: + { + if (key->newHalfTransitionCount > key->oldHalfTransitionCount) + return TRUE; + break; + } + case readkeytype_repeat: + case readkeytype_delayedRepeat: + { + if (key->newHalfTransitionCount > key->oldHalfTransitionCount) + { + if (readType == readkeytype_delayedRepeat) + { + // TODO(doyle): Let user set arbitrary delay after initial input + key->delayInterval = 2 * delayInterval; + } + else + { + key->delayInterval = delayInterval; + } + return TRUE; + } + else if (key->delayInterval <= 0.0f) + { + key->delayInterval = delayInterval; + return TRUE; + } + else + { + key->delayInterval -= dt; + } + break; + } + default: +#ifdef DENGINE_DEBUG + DEBUG_LOG("getKeyStatus() error: Invalid ReadKeyType enum"); + ASSERT(INVALID_CODE_PATH); +#endif + break; + } + + return FALSE; +} + + +void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, + v2 windowSize, f32 dt) +{ + if (!state->init) { + + memory_arenaInit(&state->persistentArena, memory->persistent, + memory->persistentSize); + memory_arenaInit(&state->transientArena, memory->transient, + memory->transientSize); + + initAssetManager(state); + initRenderer(state, windowSize); + + { // Init ship entity + Entity *ship = &state->entityList[state->entityIndex++]; + ship->id = 0; + ship->pos = V2(100.0f, 100.0f); + ship->hitbox = V2(100.0f, 100.0f); + ship->size = V2(100.0f, 100.0f); + ship->scale = 1; + ship->type = entitytype_ship; + ship->direction = direction_null; + ship->tex = asset_getTex(&state->assetManager, "nullTex"); + ship->collides = FALSE; + } + + state->camera.pos = V2(0, 0); + state->camera.size = state->renderer.size; + + state->init = TRUE; + } + { + KeyState *keys = state->input.keys; + for (enum KeyCode code = 0; code < keycode_count; code++) + { + KeyState *keyState = &keys[code]; + + u32 halfTransitionCount = keyState->newHalfTransitionCount - + keyState->oldHalfTransitionCount; + + if (halfTransitionCount > 0) + { + b32 transitionCountIsOdd = ((halfTransitionCount & 1) == 1); + + if (transitionCountIsOdd) + { + if (keyState->endedDown) keyState->endedDown = FALSE; + else keyState->endedDown = TRUE; + } + + keyState->oldHalfTransitionCount = + keyState->newHalfTransitionCount; + } + } + } + + for (i32 i = 0; i < state->entityIndex; i++) + { + Entity *entity = &state->entityList[i]; + ASSERT(entity->type != entitytype_invalid); + + if (entity->type == entitytype_ship) { + + { // Parse input + if (getKeyStatus(&state->input.keys[keycode_up], + readkeytype_repeat, 0.0f, dt)) + { + entity->pos.y += 10.0f; + } + + if (getKeyStatus(&state->input.keys[keycode_down], + readkeytype_repeat, 0.0f, dt)) + { + entity->pos.y -= 10.0f; + } + } + + } + + renderer_entity(&state->renderer, state->camera, entity, V2(0, 0), 0, + V4(1.0f, 1.0f, 1.0f, 1.0f)); + } + + renderer_renderGroups(&state->renderer); +} diff --git a/src/Debug.c b/src/Debug.c index f1d8131..6294bec 100644 --- a/src/Debug.c +++ b/src/Debug.c @@ -1,10 +1,9 @@ #include "Dengine/Debug.h" #include "Dengine/AssetManager.h" -#include "Dengine/Entity.h" #include "Dengine/MemoryArena.h" #include "Dengine/Platform.h" #include "Dengine/Renderer.h" -#include "Dengine/WorldTraveller.h" +#include "Dengine/Asteroid.h" typedef struct DebugState { @@ -29,52 +28,6 @@ typedef struct DebugState GLOBAL_VAR DebugState GLOBAL_debug; -inline char *debug_entitystate_string(i32 val) -{ - char *string; - switch(val) - { - case entitystate_idle: - string = "EntityState_Idle"; - break; - case entitystate_battle: - string = "EntityState_Battle"; - break; - case entitystate_attack: - string = "EntityState_Attack"; - break; - case entitystate_dead: - string = "EntityState_Dead"; - break; - case entitystate_count: - string = "EntityState_Count (Error!)"; - break; - case entitystate_invalid: - string = "EntityState_Invalid (Error!)"; - break; - default: - string = "EntityState Unknown (NOT DEFINED)"; - } - return string; -} - -inline char *debug_entityattack_string(i32 val) -{ - char *string; - switch(val) - { - case entityattack_count: - string = "EntityAttack_Count (Error!)"; - break; - case entityattack_invalid: - string = "EntityAttack_Invalid"; - break; - default: - string = "EntityAttack Unknown (NOT DEFINED)"; - } - return string; -} - void debug_init(MemoryArena_ *arena, v2 windowSize, Font font) { GLOBAL_debug.font = font; @@ -317,238 +270,5 @@ INTERNAL void renderConsole(Renderer *renderer, MemoryArena_ *arena) void debug_drawUi(GameState *state, f32 dt) { - AssetManager *assetManager = &state->assetManager; - Renderer *renderer = &state->renderer; - World *const world = &state->world[state->currWorldIndex]; - Entity *hero = &world->entities[entity_getIndex(world, world->heroId)]; - MemoryArena_ *transientArena = &state->transientArena; - - // TODO(doyle): Dumb copy function from game so we don't expose api - Rect camera = {world->cameraPos, renderer->size}; - // NOTE(doyle): Lock camera if it passes the bounds of the world - if (camera.pos.x <= world->bounds.x) - camera.pos.x = world->bounds.x; - - // TODO(doyle): Allow Y panning when we need it - f32 cameraTopBoundInPixels = camera.pos.y + camera.size.h; - if (cameraTopBoundInPixels >= world->bounds.w) - camera.pos.y = (world->bounds.w - camera.size.h); - - f32 cameraRightBoundInPixels = camera.pos.x + camera.size.w; - if (cameraRightBoundInPixels >= world->bounds.z) - camera.pos.x = (world->bounds.z - camera.size.w); - - if (camera.pos.y <= world->bounds.y) camera.pos.y = world->bounds.y; - - Font *font = &GLOBAL_debug.font; - if (world->numEntitiesInBattle > 0) - { - v4 color = V4(1.0f, 0, 0, 1); - char *battleStr = "IN-BATTLE RANGE"; - f32 strLenInPixels = - CAST(f32)(font->maxSize.w * common_strlen(battleStr)); - v2 strPos = V2((renderer->size.w * 0.5f) - (strLenInPixels * 0.5f), - renderer->size.h - 300.0f); - renderer_staticString(&state->renderer, transientArena, font, battleStr, - strPos, V2(0, 0), 0, color); - } - - for (i32 i = 0; i < world->freeEntityIndex; i++) - { - Entity *const entity = &world->entities[i]; - if (entity->state == entitystate_dead) continue; - - /* Render debug markers on entities */ - v4 color = V4(1, 1, 1, 1); - char *debugString = NULL; - switch (entity->type) - { - case entitytype_mob: - color = V4(1, 0, 0, 1); - debugString = "MOB"; - break; - - case entitytype_hero: - color = V4(0, 0, 1.0f, 1); - debugString = "HERO"; - break; - - case entitytype_npc: - color = V4(0, 1.0f, 0, 1); - debugString = "NPC"; - break; - - default: - break; - } - - if (debugString) - { - v2 strPos = v2_add(entity->pos, entity->hitbox); - i32 indexOfLowerAInMetrics = 'a' - CAST(i32) font->codepointRange.x; - strPos.y += font->charMetrics[indexOfLowerAInMetrics].offset.y; - - renderer_string(&state->renderer, transientArena, camera, font, - debugString, strPos, V2(0, 0), 0, color); - - f32 stringLineGap = 1.1f * font->verticalSpacing; - strPos.y -= GLOBAL_debug.stringLineGap; - - char entityPosStr[128]; - snprintf(entityPosStr, ARRAY_COUNT(entityPosStr), "%06.2f, %06.2f", - entity->pos.x, entity->pos.y); - renderer_string(&state->renderer, transientArena, camera, font, - entityPosStr, strPos, V2(0, 0), 0, color); - - strPos.y -= GLOBAL_debug.stringLineGap; - char entityIDStr[32]; - snprintf(entityIDStr, ARRAY_COUNT(entityIDStr), "ID: %4d/%d", entity->id, - world->uniqueIdAccumulator-1); - renderer_string(&state->renderer, transientArena, camera, font, - entityIDStr, strPos, V2(0, 0), 0, color); - - if (entity->stats) - { - strPos.y -= GLOBAL_debug.stringLineGap; - char entityHealth[32]; - snprintf(entityHealth, ARRAY_COUNT(entityHealth), "HP: %3.0f/%3.0f", - entity->stats->health, entity->stats->maxHealth); - renderer_string(&state->renderer, transientArena, camera, - font, entityHealth, strPos, V2(0, 0), 0, color); - - strPos.y -= GLOBAL_debug.stringLineGap; - char entityTimer[32]; - snprintf(entityTimer, ARRAY_COUNT(entityTimer), "ATB: %3.0f/%3.0f", - entity->stats->actionTimer, entity->stats->actionRate); - renderer_string(&state->renderer, transientArena, camera, - font, entityTimer, strPos, V2(0, 0), 0, color); - - strPos.y -= GLOBAL_debug.stringLineGap; - char entityIdTarget[32]; - snprintf(entityIdTarget, ARRAY_COUNT(entityIdTarget), - "Targetting ID: %d", entity->stats->entityIdToAttack); - renderer_string(&state->renderer, transientArena, camera, - font, entityIdTarget, strPos, V2(0, 0), 0, color); - } - - strPos.y -= GLOBAL_debug.stringLineGap; - char *entityStateStr = debug_entitystate_string(entity->state); - renderer_string(&state->renderer, transientArena, camera, 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, transientArena, camera, - font, entityAudioSourceIndex, strPos, V2(0, 0), - 0, color); - } - } - } - - /* Render debug info stack */ - DEBUG_PUSH_STRING("== Controls =="); - DEBUG_PUSH_STRING(" [: Spawn a mob"); - DEBUG_PUSH_STRING(": Switch UI element"); - DEBUG_PUSH_STRING(": Close program"); - DEBUG_PUSH_STRING(""); - - DEBUG_PUSH_STRING("== Config == "); - DEBUG_PUSH_VAR("Toggle World Audio: %d", state->config.playWorldAudio, - "i32"); - DEBUG_PUSH_VAR("Toggle Debug Display: %d", state->config.showDebugDisplay, - "i32"); - DEBUG_PUSH_STRING(""); - - DEBUG_PUSH_STRING("== Hero Properties == "); - DEBUG_PUSH_VAR("Hero Pos: %06.2f, %06.2f", hero->pos, "v2"); - DEBUG_PUSH_VAR("Hero dPos: %06.2f, %06.2f", hero->dPos, "v2"); - DEBUG_PUSH_VAR("Hero Busy Duration: %05.3f", hero->stats->busyDuration, "f32"); - char *heroStateString = debug_entitystate_string(hero->state); - DEBUG_PUSH_VAR("Hero State: %s", *heroStateString, "char"); - char *heroQueuedAttackStr = - debug_entityattack_string(hero->stats->queuedAttack); - DEBUG_PUSH_VAR("Hero QueuedAttack: %s", *heroQueuedAttackStr, "char"); - DEBUG_PUSH_STRING(""); - - DEBUG_PUSH_STRING("== State Properties == "); - DEBUG_PUSH_VAR("FreeEntityIndex: %d", world->freeEntityIndex, "i32"); - DEBUG_PUSH_VAR("GLDrawArray Calls: %d", - GLOBAL_debug.callCount[debugcount_drawArrays], "i32"); - DEBUG_PUSH_VAR("PlatformMemAlloc Calls: %d", - GLOBAL_debug.callCount[debugcount_platformMemAlloc], "i32"); - DEBUG_PUSH_VAR("PlatformMemFree Calls: %d", - GLOBAL_debug.callCount[debugcount_platformMemFree], "i32"); - - i32 vertexesUsed = GLOBAL_debug.callCount[debugcount_numVertex]; - i32 vertexesAvail = - (ARRAY_COUNT(state->renderer.groups) * state->renderer.groupCapacity); - i32 vertexesLeft = vertexesAvail - vertexesUsed; - v2 vertexData = V2i(vertexesUsed, vertexesAvail); - DEBUG_PUSH_VAR("Vertexes Rendered: %1.0f/%1.0f", vertexData, "v2"); - DEBUG_PUSH_VAR("Vertexes Left: %d", vertexesLeft, "i32"); - - i32 groupsUsed = GLOBAL_debug.callCount[debugcount_renderGroups]; - i32 groupsAvail = ARRAY_COUNT(state->renderer.groups); - v2 groupData = V2i(groupsUsed, groupsAvail); - DEBUG_PUSH_VAR("Render Groups Used: %1.0f/%1.0f", groupData, "v2"); - - DEBUG_PUSH_VAR("Mouse Pos: %06.2f, %06.2f", state->input.mouseP, "v2"); - - /* - ***************** - * MEMORY DISPLAY - ***************** - */ - i32 debug_bAllocated = transientArena->used; - i32 debug_kbAllocated = debug_bAllocated / 1024; - i32 debug_mbAllocated = debug_kbAllocated / 1024; - DEBUG_PUSH_VAR("TransientArena Used: %db", debug_bAllocated, "i32"); - DEBUG_PUSH_VAR("TransientArena Used: %dkb", debug_kbAllocated, "i32"); - DEBUG_PUSH_VAR("TransientArena Used: %dmb", debug_mbAllocated, "i32"); - DEBUG_PUSH_STRING(""); - - debug_bAllocated = state->arena_.used; - debug_kbAllocated = debug_bAllocated / 1024; - debug_mbAllocated = debug_kbAllocated / 1024; - DEBUG_PUSH_VAR("PersistentArena Used: %db", debug_bAllocated, "i32"); - DEBUG_PUSH_VAR("PersistentArena Used: %dkb", debug_kbAllocated, "i32"); - DEBUG_PUSH_VAR("PersistentArena Used: %dmb", debug_mbAllocated, "i32"); - DEBUG_PUSH_STRING(""); - - AudioManager *audioManager = &state->audioManager; - DEBUG_PUSH_STRING("== Audio System =="); - for (i32 i = 0; i < ARRAY_COUNT(audioManager->sourceList); i++) - { - if (audioManager->sourceList[i].isFree) continue; - 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(""); - - DEBUG_PUSH_STRING("== EntityIDs in Battle List == "); - DEBUG_PUSH_VAR("NumEntitiesInBattle: %d", world->numEntitiesInBattle, - "i32"); - if (world->numEntitiesInBattle > 0) - { - for (i32 i = 0; i < world->maxEntities; i++) - { - if (world->entityIdInBattle[i]) - DEBUG_PUSH_VAR("Entity ID: %d", i, "i32"); - } - } - else - { - DEBUG_PUSH_STRING("-none-"); - } - - updateAndRenderDebugStack(&state->renderer, transientArena, dt); - renderConsole(&state->renderer, transientArena); debug_clearCounter(); } diff --git a/src/Entity.c b/src/Entity.c index ea9deeb..1803841 100644 --- a/src/Entity.c +++ b/src/Entity.c @@ -1,12 +1,10 @@ #include "Dengine/Entity.h" #include "Dengine/AssetManager.h" #include "Dengine/Debug.h" -#include "Dengine/MemoryArena.h" -#include "Dengine/WorldTraveller.h" SubTexture entity_getActiveSubTexture(Entity *const entity) { - EntityAnim *entityAnim = &entity->animList[entity->currAnimId]; + EntityAnim *entityAnim = &entity->animList[entity->animListIndex]; Animation *anim = entityAnim->anim; char *frameName = anim->frameList[entityAnim->currFrame]; @@ -14,11 +12,10 @@ SubTexture entity_getActiveSubTexture(Entity *const entity) return result; } -void entity_setActiveAnim(EventQueue *eventQueue, Entity *const entity, - const char *const animName) +void entity_setActiveAnim(Entity *const entity, const char *const animName) { /* Reset current anim data */ - EntityAnim *currEntityAnim = &entity->animList[entity->currAnimId]; + EntityAnim *currEntityAnim = &entity->animList[entity->animListIndex]; currEntityAnim->currDuration = currEntityAnim->anim->frameDuration; currEntityAnim->currFrame = 0; currEntityAnim->timesCompleted = 0; @@ -32,14 +29,11 @@ void entity_setActiveAnim(EventQueue *eventQueue, Entity *const entity, // TODO(doyle): Linear search, but not a problem if list is small if (common_strcmp(anim->key, animName) == 0) { - entity->currAnimId = i; + entity->animListIndex = i; EntityAnim *newEntityAnim = &entity->animList[i]; newEntityAnim->currDuration = newEntityAnim->anim->frameDuration; newEntityAnim->currFrame = 0; - - worldTraveller_registerEvent(eventQueue, eventtype_start_anim, - newEntityAnim); return; } } @@ -48,13 +42,12 @@ void entity_setActiveAnim(EventQueue *eventQueue, Entity *const entity, DEBUG_LOG("Entity does not have access to desired anim"); } -void entity_updateAnim(EventQueue *eventQueue, Entity *const entity, - const f32 dt) +void entity_updateAnim(Entity *const entity, const f32 dt) { if (!entity->tex) return; - EntityAnim *currEntityAnim = &entity->animList[entity->currAnimId]; + EntityAnim *currEntityAnim = &entity->animList[entity->animListIndex]; Animation *anim = currEntityAnim->anim; currEntityAnim->currDuration -= dt; @@ -64,30 +57,15 @@ void entity_updateAnim(EventQueue *eventQueue, Entity *const entity, currEntityAnim->currFrame = currEntityAnim->currFrame % anim->numFrames; if (currEntityAnim->currFrame == 0) { - worldTraveller_registerEvent(eventQueue, eventtype_end_anim, - currEntityAnim); currEntityAnim->timesCompleted++; } currEntityAnim->currDuration = anim->frameDuration; } - // NOTE(doyle): If humanoid entity, let animation dictate render size which - // may exceed the hitbox size of the entity - switch (entity->type) - { - case entitytype_hero: - case entitytype_mob: - case entitytype_npc: - case entitytype_weapon: - case entitytype_projectile: - char *frameName = anim->frameList[currEntityAnim->currFrame]; - SubTexture texRect = - asset_getAtlasSubTex(anim->atlas, frameName); - entity->size = v2_scale(texRect.rect.size, entity->scale); - default: - break; - } + char *frameName = anim->frameList[currEntityAnim->currFrame]; + SubTexture texRect = asset_getAtlasSubTex(anim->atlas, frameName); + entity->size = v2_scale(texRect.rect.size, entity->scale); } void entity_addAnim(AssetManager *const assetManager, Entity *const entity, @@ -108,127 +86,3 @@ void entity_addAnim(AssetManager *const assetManager, Entity *const entity, DEBUG_LOG("No more free entity animation slots"); } - -Entity *const entity_add(MemoryArena_ *const arena, World *const world, - const v2 pos, const v2 size, const f32 scale, - const enum EntityType type, - const enum Direction direction, Texture *const tex, - const b32 collides) -{ - -#ifdef DENGINE_DEBUG - ASSERT(world); - ASSERT(world->freeEntityIndex < world->maxEntities); - ASSERT(type < entitytype_count); -#endif - - Entity entity = {0}; - entity.id = world->uniqueIdAccumulator++; - entity.pos = pos; - entity.size = size; - entity.hitbox = size; - entity.scale = scale; - entity.type = type; - entity.direction = direction; - entity.tex = tex; - entity.collides = collides; - - switch (type) - { - case entitytype_hero: - entity.stats = MEMORY_PUSH_STRUCT(arena, EntityStats); - entity.stats->maxHealth = 100; - entity.stats->health = entity.stats->maxHealth; - entity.stats->actionRate = 100; - entity.stats->actionTimer = entity.stats->actionRate; - entity.stats->actionSpdMul = 100; - entity.stats->entityIdToAttack = -1; - entity.stats->queuedAttack = entityattack_invalid; - entity.state = entitystate_idle; - entity.collidesWith[entitytype_mob] = TRUE; - break; - case entitytype_mob: - { - entity.stats = MEMORY_PUSH_STRUCT(arena, EntityStats); - entity.stats->maxHealth = 100; - entity.stats->health = entity.stats->maxHealth; - entity.stats->actionRate = 80; - entity.stats->actionTimer = entity.stats->actionRate; - entity.stats->actionSpdMul = 100; - entity.stats->entityIdToAttack = -1; - entity.stats->queuedAttack = entityattack_invalid; - entity.state = entitystate_idle; - entity.collidesWith[entitytype_hero] = TRUE; - break; - } - case entitytype_projectile: - case entitytype_attackObject: - entity.stats = MEMORY_PUSH_STRUCT(arena, EntityStats); - entity.stats->maxHealth = 100; - entity.stats->health = entity.stats->maxHealth; - entity.stats->actionRate = 100; - entity.stats->actionTimer = entity.stats->actionRate; - entity.stats->actionSpdMul = 100; - entity.stats->entityIdToAttack = -1; - entity.stats->queuedAttack = entityattack_invalid; - entity.state = entitystate_idle; - break; - - default: - break; - } - - world->entities[world->freeEntityIndex++] = entity; - Entity *result = &world->entities[world->freeEntityIndex - 1]; - - return result; -} - -void entity_clearData(MemoryArena_ *const arena, World *const world, - Entity *const entity) -{ - // TODO(doyle): Mem free// memory leak!! - - /* - if (entity->stats) - PLATFORM_MEM_FREE(arena, entity->stats, sizeof(EntityStats)); - - if (entity->audioRenderer) - PLATFORM_MEM_FREE(arena, entity->audioRenderer, - sizeof(AudioRenderer) * entity->numAudioRenderers); - */ - - entity->type = entitytype_null; -} - -i32 entity_getIndex(World *const world, const i32 entityId) -{ - i32 first = 0; - i32 last = world->freeEntityIndex - 1; - - while (first <= last) - { - i32 middle = (first + last) / 2; - - if (world->entities[middle].id > entityId) - last = middle - 1; - else if (world->entities[middle].id < entityId) - first = middle + 1; - else - return middle; - } - -#ifdef DENGINE_DEBUG - ASSERT(INVALID_CODE_PATH); -#endif - return -1; -} - -Entity *entity_get(World *const world, const i32 entityId) -{ - Entity *result = NULL; - i32 worldIndex = entity_getIndex(world, entityId); - if (worldIndex != -1) result = &world->entities[worldIndex]; - - return result; -} diff --git a/src/Platform.c b/src/Platform.c index 26d7e26..c874b78 100644 --- a/src/Platform.c +++ b/src/Platform.c @@ -6,7 +6,7 @@ #include "Dengine/Debug.h" #include "Dengine/MemoryArena.h" -void platform_memoryFree(MemoryArena_ *arena, void *data, i32 numBytes) +void platform_memoryFree(MemoryArena_ *arena, void *data, size_t numBytes) { if (data) free(data); @@ -16,7 +16,7 @@ void platform_memoryFree(MemoryArena_ *arena, void *data, i32 numBytes) #endif } -void *platform_memoryAlloc(MemoryArena_ *arena, i32 numBytes) +void *platform_memoryAlloc(MemoryArena_ *arena, size_t numBytes) { void *result = calloc(1, numBytes); diff --git a/src/Renderer.c b/src/Renderer.c index 90abc50..df39a4e 100644 --- a/src/Renderer.c +++ b/src/Renderer.c @@ -381,23 +381,31 @@ void renderer_entity(Renderer *renderer, Rect camera, Entity *entity, if (math_pointInRect(camera, leftAlignedP) || math_pointInRect(camera, rightAlignedP)) { - EntityAnim *entityAnim = &entity->animList[entity->currAnimId]; - Animation *anim = entityAnim->anim; - char *frameName = anim->frameList[entityAnim->currFrame]; - SubTexture animRect = asset_getAtlasSubTex(anim->atlas, frameName); + EntityAnim *entityAnim = &entity->animList[entity->animListIndex]; - v4 animTexRect = {0}; - animTexRect.vec2[0] = animRect.rect.pos; - animTexRect.vec2[1] = v2_add(animRect.rect.pos, animRect.rect.size); + v4 texRect = {0}; + if (entityAnim->anim) + { + Animation *anim = entityAnim->anim; + char *frameName = anim->frameList[entityAnim->currFrame]; + SubTexture subTex = asset_getAtlasSubTex(anim->atlas, frameName); - flipTexCoord(&animTexRect, entity->flipX, entity->flipY); + texRect.vec2[0] = subTex.rect.pos; + texRect.vec2[1] = v2_add(subTex.rect.pos, subTex.rect.size); + flipTexCoord(&texRect, entity->flipX, entity->flipY); + } + else + { + texRect = V4(0.0f, 0.0f, (f32)entity->tex->width, + (f32)entity->tex->height); + } if (entity->direction == direction_east) { - flipTexCoord(&animTexRect, TRUE, FALSE); + flipTexCoord(&texRect, TRUE, FALSE); } - RenderTex renderTex = {entity->tex, animTexRect}; + RenderTex renderTex = {entity->tex, texRect}; renderer_rect(renderer, camera, entity->pos, entity->size, pivotPoint, entity->rotation + rotate, renderTex, color); } diff --git a/src/WorldTraveller.c b/src/WorldTraveller.c deleted file mode 100644 index 7b80b0e..0000000 --- a/src/WorldTraveller.c +++ /dev/null @@ -1,2477 +0,0 @@ -#include "Dengine/WorldTraveller.h" -#include "Dengine/Audio.h" -#include "Dengine/Debug.h" -#include "Dengine/Entity.h" -#include "Dengine/Platform.h" -#include "Dengine/String.h" -#include "Dengine/UserInterface.h" - -enum State -{ - state_active, - state_menu, - state_win, -}; - -INTERNAL Entity *getHeroEntity(World *world) -{ - Entity *result = &world->entities[entity_getIndex(world, world->heroId)]; - return result; -} - -INTERNAL void addGenericMob(EventQueue *eventQueue, MemoryArena_ *arena, - AssetManager *assetManager, World *world, v2 pos) -{ -#ifdef DENGINE_DEBUG - DEBUG_LOG("Mob entity spawned"); -#endif - - Entity *hero = &world->entities[entity_getIndex(world, world->heroId)]; - - v2 size = V2(58.0f, 98.0f); - f32 scale = 2; - enum EntityType type = entitytype_mob; - enum Direction dir = direction_west; - Texture *tex = asset_getTex(assetManager, "ClaudeSprite.png"); - b32 collides = TRUE; - Entity *mob = - entity_add(arena, world, pos, size, scale, type, dir, tex, collides); - - mob->numAudioRenderers = 4; - mob->audioRenderer = - memory_pushBytes(arena, mob->numAudioRenderers * sizeof(AudioRenderer)); - - for (i32 i = 0; i < mob->numAudioRenderers; i++) - mob->audioRenderer[i].sourceIndex = AUDIO_SOURCE_UNASSIGNED; - - /* Populate mob animation references */ - entity_addAnim(assetManager, mob, "claudeIdle"); - entity_addAnim(assetManager, mob, "claudeRun"); - entity_addAnim(assetManager, mob, "claudeBattleIdle"); - - entity_addAnim(assetManager, mob, "claudeAttack"); - entity_addAnim(assetManager, mob, "claudeAttackUp"); - entity_addAnim(assetManager, mob, "claudeAttackDown"); - - entity_addAnim(assetManager, mob, "claudeAirSlash"); - entity_addAnim(assetManager, mob, "claudeDragonHowl"); - entity_addAnim(assetManager, mob, "claudeEnergySword"); - entity_addAnim(assetManager, mob, "claudeRipperBlast"); - - entity_setActiveAnim(eventQueue, mob, "claudeIdle"); -} - -INTERNAL void rendererInit(GameState *state, v2 windowSize) -{ - AssetManager *assetManager = &state->assetManager; - Renderer *renderer = &state->renderer; - renderer->size = windowSize; - // NOTE(doyle): Value to map a screen coordinate to NDC coordinate - renderer->vertexNdcFactor = - V2(1.0f / renderer->size.w, 1.0f / renderer->size.h); - renderer->shader = asset_getShader(assetManager, shaderlist_sprite); - shader_use(renderer->shader); - - const mat4 projection = - mat4_ortho(0.0f, renderer->size.w, 0.0f, renderer->size.h, 0.0f, 1.0f); - shader_uniformSetMat4fv(renderer->shader, "projection", projection); - GL_CHECK_ERROR(); - - /* Create buffers */ - glGenVertexArrays(1, &renderer->vao); - glGenBuffers(1, &renderer->vbo); - GL_CHECK_ERROR(); - - /* Bind buffers */ - glBindBuffer(GL_ARRAY_BUFFER, renderer->vbo); - glBindVertexArray(renderer->vao); - - /* Configure VAO */ - u32 numVertexElements = 4; - u32 stride = sizeof(Vertex); - glVertexAttribPointer(0, numVertexElements, GL_FLOAT, GL_FALSE, - stride, (GLvoid *)0); - glEnableVertexAttribArray(0); - - GL_CHECK_ERROR(); - - /* Unbind */ - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - GL_CHECK_ERROR(); - - // TODO(doyle): Lazy allocate render group capacity - renderer->groupCapacity = 4096; - for (i32 i = 0; i < ARRAY_COUNT(renderer->groups); i++) - { - renderer->groups[i].vertexList = memory_pushBytes( - &state->arena_, renderer->groupCapacity * sizeof(Vertex)); - } - -#ifdef DENGINE_DEBUG - DEBUG_LOG("Renderer initialised"); -#endif -} - -INTERNAL void assetInit(GameState *state) -{ - AssetManager *assetManager = &state->assetManager; - MemoryArena_ *arena = &state->arena_; - - i32 audioEntries = 32; - assetManager->audio.size = audioEntries; - assetManager->audio.entries = - memory_pushBytes(arena, audioEntries * sizeof(HashTableEntry)); - - i32 texAtlasEntries = 8; - assetManager->texAtlas.size = texAtlasEntries; - assetManager->texAtlas.entries = - memory_pushBytes(arena, texAtlasEntries * sizeof(HashTableEntry)); - - i32 texEntries = 32; - assetManager->textures.size = texEntries; - assetManager->textures.entries = - memory_pushBytes(arena, texEntries * sizeof(HashTableEntry)); - - i32 animEntries = 1024; - assetManager->anims.size = animEntries; - assetManager->anims.entries = - memory_pushBytes(arena, animEntries * sizeof(HashTableEntry)); - - /* Create empty 1x1 4bpp black texture */ - u32 bitmap = (0xFF << 24) | (0xFF << 16) | (0xFF << 8) | (0xFF << 0); - Texture *tex = asset_getFreeTexSlot(assetManager, arena, "nullTex"); - *tex = texture_gen(1, 1, 4, CAST(u8 *)(&bitmap)); - - /* - ********************************* - * Load terrain texture atlas data - ********************************* - */ - PlatformFileRead terrainXml = {0}; - i32 result = platform_readFileToBuffer( - arena, "data/textures/WorldTraveller/terrain.xml", &terrainXml); - if (result) - { - DEBUG_LOG("Failed to read sprite sheet xml"); - } - else - { - result = asset_loadXmlFile(assetManager, arena, &terrainXml); - - if (!result) - { - TexAtlas *terrainAtlas = - asset_getTexAtlas(assetManager, "terrain.png"); - - i32 numSubTextures = 1; - f32 duration = 1.0f; - char *grassTerrain[1] = {"grass.png"}; - asset_addAnimation(assetManager, arena, "terrainGrass", - terrainAtlas, grassTerrain, numSubTextures, - duration); - } - else - { -#ifdef DENGINE_DEBUG - DEBUG_LOG("Failed to load terrain sprite xml data"); -#endif - } - - platform_closeFileRead(arena, &terrainXml); - } - - /* - ********************************* - * Load Claude texture atlas data - ********************************* - */ - PlatformFileRead claudeXml = {0}; - result = platform_readFileToBuffer( - arena, "data/textures/WorldTraveller/ClaudeSprite.xml", &claudeXml); - - if (result) - { - DEBUG_LOG("Failed to read sprite sheet xml"); - } - else - { - result = asset_loadXmlFile(assetManager, arena, &claudeXml); - - if (!result) - { - TexAtlas *claudeAtlas = - asset_getTexAtlas(assetManager, "ClaudeSprite.png"); - - char *claudeIdle[1] = {"ClaudeSprite_Walk_Left_01"}; - f32 duration = 1.0f; - i32 numRects = ARRAY_COUNT(claudeIdle); - asset_addAnimation(assetManager, arena, "claudeIdle", claudeAtlas, - claudeIdle, numRects, duration); - - // Run animation - char *claudeRun[6] = { - "ClaudeSprite_Run_Left_01", "ClaudeSprite_Run_Left_02", - "ClaudeSprite_Run_Left_03", "ClaudeSprite_Run_Left_04", - "ClaudeSprite_Run_Left_05", "ClaudeSprite_Run_Left_06"}; - duration = 0.1f; - numRects = ARRAY_COUNT(claudeRun); - asset_addAnimation(assetManager, arena, "claudeRun", claudeAtlas, - claudeRun, numRects, duration); - - // Battle Idle animation - char *claudeBattleIdle[3] = {"ClaudeSprite_BattleIdle_Left_01", - "ClaudeSprite_BattleIdle_Left_02", - "ClaudeSprite_BattleIdle_Left_03"}; - numRects = ARRAY_COUNT(claudeBattleIdle); - duration = 0.2f; - asset_addAnimation(assetManager, arena, "claudeBattleIdle", - claudeAtlas, claudeBattleIdle, numRects, - duration); - - // Attack Left animation - char *claudeAttack[6] = { - "ClaudeSprite_Attack_Left_01", "ClaudeSprite_Attack_Left_02", - "ClaudeSprite_Attack_Left_03", "ClaudeSprite_Attack_Left_04", - "ClaudeSprite_Attack_Left_05", "ClaudeSprite_Attack_Left_06"}; - numRects = ARRAY_COUNT(claudeAttack); - duration = 0.1f; - asset_addAnimation(assetManager, arena, "claudeAttack", claudeAtlas, - claudeAttack, numRects, duration); - - char *claudeAttackDown[7] = { - "ClaudeSprite_Attack_Down_01", - "ClaudeSprite_Attack_Down_02", - "ClaudeSprite_Attack_Down_03", - "ClaudeSprite_Attack_Down_04", - "ClaudeSprite_Attack_Down_05", - "ClaudeSprite_Attack_Down_06", - "ClaudeSprite_Attack_Down_07", - }; - - numRects = ARRAY_COUNT(claudeAttackDown); - duration = 0.1f; - asset_addAnimation(assetManager, arena, "claudeAttackDown", - claudeAtlas, claudeAttackDown, numRects, - duration); - - char *claudeAttackUp[3] = { - "ClaudeSprite_Attack_Up_01", - "ClaudeSprite_Attack_Up_02", - "ClaudeSprite_Attack_Up_03", - }; - - numRects = ARRAY_COUNT(claudeAttackUp); - duration = 0.2f; - asset_addAnimation(assetManager, arena, "claudeAttackUp", - claudeAtlas, claudeAttackUp, numRects, - duration); - - char *claudeDragonHowl[3] = { - "ClaudeSprite_Attack_DragonHowl_01", - "ClaudeSprite_Attack_DragonHowl_02", - "ClaudeSprite_Attack_DragonHowl_03", - }; - - numRects = ARRAY_COUNT(claudeDragonHowl); - duration = 0.2f; - asset_addAnimation(assetManager, arena, "claudeDragonHowl", - claudeAtlas, claudeDragonHowl, numRects, - duration); - - char *claudeDragonHowlVfx[7] = { - "ClaudeSprite_Attack_DragonHowl_Vfx_01", - "ClaudeSprite_Attack_DragonHowl_Vfx_02", - "ClaudeSprite_Attack_DragonHowl_Vfx_03", - "ClaudeSprite_Attack_DragonHowl_Vfx_04", - "ClaudeSprite_Attack_DragonHowl_Vfx_05", - "ClaudeSprite_Attack_DragonHowl_Vfx_06", - "ClaudeSprite_Attack_DragonHowl_Vfx_07", - }; - - numRects = ARRAY_COUNT(claudeDragonHowlVfx); - duration = 0.1f; - asset_addAnimation(assetManager, arena, "claudeDragonHowlVfx", - claudeAtlas, claudeDragonHowlVfx, numRects, - duration); - - char *claudeRipperBlast[6] = { - "ClaudeSprite_Attack_RipperBlast_01", - "ClaudeSprite_Attack_RipperBlast_02", - "ClaudeSprite_Attack_RipperBlast_03", - "ClaudeSprite_Attack_RipperBlast_04", - "ClaudeSprite_Attack_RipperBlast_05", - "ClaudeSprite_Attack_RipperBlast_06", - }; - - numRects = ARRAY_COUNT(claudeRipperBlast); - duration = 0.1f; - asset_addAnimation(assetManager, arena, "claudeRipperBlast", - claudeAtlas, claudeRipperBlast, numRects, - duration); - - char *claudeRipperBlastVfx[12] = { - "ClaudeSprite_Attack_RipperBlast_Vfx_01", - "ClaudeSprite_Attack_RipperBlast_Vfx_02", - "ClaudeSprite_Attack_RipperBlast_Vfx_03", - "ClaudeSprite_Attack_RipperBlast_Vfx_04", - "ClaudeSprite_Attack_RipperBlast_Vfx_05", - "ClaudeSprite_Attack_RipperBlast_Vfx_06", - "ClaudeSprite_Attack_RipperBlast_Vfx_07", - "ClaudeSprite_Attack_RipperBlast_Vfx_08", - "ClaudeSprite_Attack_RipperBlast_Vfx_09", - "ClaudeSprite_Attack_RipperBlast_Vfx_10", - "ClaudeSprite_Attack_RipperBlast_Vfx_11", - "ClaudeSprite_Attack_RipperBlast_Vfx_12", - }; - - numRects = ARRAY_COUNT(claudeRipperBlastVfx); - duration = 0.1f; - asset_addAnimation(assetManager, arena, "claudeRipperBlastVfx", - claudeAtlas, claudeRipperBlastVfx, numRects, - duration); - - // Victory animation - char *claudeVictory[8] = {"ClaudeSprite_Battle_Victory_01", - "ClaudeSprite_Battle_Victory_02", - "ClaudeSprite_Battle_Victory_03", - "ClaudeSprite_Battle_Victory_04", - "ClaudeSprite_Battle_Victory_05", - "ClaudeSprite_Battle_Victory_06", - "ClaudeSprite_Battle_Victory_07", - "ClaudeSprite_Battle_Victory_08"}; - numRects = ARRAY_COUNT(claudeVictory); - duration = 0.1f; - asset_addAnimation(assetManager, arena, "claudeVictory", - claudeAtlas, claudeVictory, numRects, duration); - - char *claudeEnergySword[6] = {"ClaudeSprite_Attack_EnergySword_01", - "ClaudeSprite_Attack_EnergySword_02", - "ClaudeSprite_Attack_EnergySword_03", - "ClaudeSprite_Attack_EnergySword_04", - "ClaudeSprite_Attack_EnergySword_05", - "ClaudeSprite_Attack_EnergySword_06"}; - numRects = ARRAY_COUNT(claudeEnergySword); - duration = 0.1f; - asset_addAnimation(assetManager, arena, "claudeEnergySword", - claudeAtlas, claudeEnergySword, numRects, - duration); - - char *claudeAirSlash[7] = {"ClaudeSprite_Attack_AirSlash_01", - "ClaudeSprite_Attack_AirSlash_02", - "ClaudeSprite_Attack_AirSlash_03", - "ClaudeSprite_Attack_AirSlash_04", - "ClaudeSprite_Attack_AirSlash_05", - "ClaudeSprite_Attack_AirSlash_06", - "ClaudeSprite_Attack_AirSlash_07"}; - numRects = ARRAY_COUNT(claudeAirSlash); - duration = 0.075f; - asset_addAnimation(assetManager, arena, "claudeAirSlash", - claudeAtlas, claudeAirSlash, numRects, - duration); - - char *claudeAirSlashVfx[7] = {"ClaudeSprite_Attack_AirSlash_Vfx_01", - "ClaudeSprite_Attack_AirSlash_Vfx_02", - "ClaudeSprite_Attack_AirSlash_Vfx_03", - "ClaudeSprite_Attack_AirSlash_Vfx_04", - "ClaudeSprite_Attack_AirSlash_Vfx_05", - "ClaudeSprite_Attack_AirSlash_Vfx_06", - "ClaudeSprite_Attack_AirSlash_Vfx_07"}; - numRects = ARRAY_COUNT(claudeAirSlashVfx); - duration = 0.075f; - asset_addAnimation(assetManager, arena, "claudeAirSlashVfx", - claudeAtlas, claudeAirSlashVfx, numRects, - duration); - - char *claudeSword[1] = { - "ClaudeSprite_Sword_01", - }; - - numRects = ARRAY_COUNT(claudeSword); - duration = 0.4f; - asset_addAnimation(assetManager, arena, "claudeSword", - claudeAtlas, claudeSword, numRects, - duration); - - char *claudeAttackSlashLeft[4] = { - "ClaudeSprite_Attack_Slash_Left_01", - "ClaudeSprite_Attack_Slash_Left_02", - "ClaudeSprite_Attack_Slash_Left_03", - "ClaudeSprite_Attack_Slash_Left_04", - }; - - numRects = ARRAY_COUNT(claudeAttackSlashLeft); - duration = 0.1f; - asset_addAnimation(assetManager, arena, "claudeAttackSlashLeft", - claudeAtlas, claudeAttackSlashLeft, numRects, - duration); - - } - else - { -#ifdef DENGINE_DEBUG - DEBUG_LOG("Failed to load claude sprite xml data"); -#endif - } - - platform_closeFileRead(arena, &claudeXml); - } - - -#ifdef DENGINE_DEBUG - DEBUG_LOG("Animations created"); -#endif - - /* Load shaders */ - asset_loadShaderFiles(assetManager, arena, "data/shaders/sprite.vert.glsl", - "data/shaders/sprite.frag.glsl", - shaderlist_sprite); - - result = - asset_loadTTFont(assetManager, arena, "C:/Windows/Fonts/Arialbd.ttf"); - -#ifdef DENGINE_DEBUG - if (result) DEBUG_LOG("Font loading failed"); - GL_CHECK_ERROR(); - DEBUG_LOG("Assets loaded"); -#endif - - /* Load sound */ - - i32 before = arena->used; - - char *sfxListPath = "data/audio/sfx/sfx.txt"; - PlatformFileRead sfxList = {0}; - result = platform_readFileToBuffer(arena, sfxListPath, &sfxList); - - char *sfxAudioNames[256]; - i32 sfxAudioIndex = 0; - if (!result) - { - char string[256] = {0}; - i32 stringIndex = 0; - for (i32 i = 0; i < sfxList.size; i++) - { - char c = (CAST(char *)sfxList.buffer)[i]; - switch(c) - { - case 0x0a: - { - i32 actualStrLen = common_strlen(string) + 1; - sfxAudioNames[sfxAudioIndex] = - memory_pushBytes(arena, actualStrLen * sizeof(char)); - common_strncpy(sfxAudioNames[sfxAudioIndex++], string, - actualStrLen); - - common_memset(string, 0, ARRAY_COUNT(string)); - stringIndex = 0; - break; - } - default: - { - if (c >= ' ' && c <= '~') - { - string[stringIndex++] = c; - } - break; - } - } - } - } - - char *sfxDir = "data/audio/sfx/"; - char *sfxExtension = ".ogg"; - i32 sfxDirLen = common_strlen(sfxDir); - i32 sfxExtensionLen = common_strlen(sfxExtension); - - for (i32 i = 0; i < sfxAudioIndex; i++) - { - char *sfxName = sfxAudioNames[i]; - i32 sfxNameLen = common_strlen(sfxName); - - i32 sfxFullPathLen = sfxDirLen + sfxExtensionLen + sfxNameLen + 1; - char *sfxFullPath = - memory_pushBytes(arena, sfxFullPathLen * sizeof(char)); - - common_strncat(sfxFullPath, sfxDir, sfxDirLen); - common_strncat(sfxFullPath, sfxName, sfxNameLen); - common_strncat(sfxFullPath, sfxExtension, sfxExtensionLen); - - i32 result = asset_loadVorbis(assetManager, arena, sfxFullPath, sfxName); - if (result) DEBUG_LOG("Failed to load sfx file"); - - // TODO(doyle): Need better string type to account for null terminating - // character, having to remember to +1 on allocation AND freeing since - // strlen only counts until null char is going to leave memory leaks - // everywhere - // TODO(doyle): Free mem - // PLATFORM_MEM_FREE(arena, sfxName, sfxNameLen * sizeof(char) + 1); - // PLATFORM_MEM_FREE(arena, sfxFullPath, sfxFullPathLen * sizeof(char)); - } - - // TODO(doyle): Free mem - // platform_closeFileRead(arena, &sfxList); - - char *audioPath = - "data/audio/Motoi Sakuraba - Stab the sword of justice.ogg"; - asset_loadVorbis(assetManager, arena, audioPath, "audio_battle"); - audioPath = "data/audio/Motoi Sakuraba - Field of Exper.ogg"; - asset_loadVorbis(assetManager, arena, audioPath, "audio_overworld"); - audioPath = "data/audio/nuindependent_hit22.ogg"; - asset_loadVorbis(assetManager, arena, audioPath, "audio_tackle"); - -#ifdef DENGINE_DEBUG - DEBUG_LOG("Sound assets initialised"); -#endif -} - -INTERNAL void entityInit(GameState *state, v2 windowSize) -{ - AssetManager *assetManager = &state->assetManager; - MemoryArena_ *arena = &state->arena_; - - /* Init world */ - const i32 targetWorldWidth = 100 * METERS_TO_PIXEL; - const i32 targetWorldHeight = 10 * METERS_TO_PIXEL; -#if 0 - v2 worldDimensionInTiles = V2i(targetWorldWidth / state->tileSize, - targetWorldHeight / state->tileSize); -#else - v2 worldDimensionInTiles = - V2i(CAST(i32)(windowSize.w / state->tileSize) * 2, - CAST(i32) windowSize.h / state->tileSize); -#endif - - EventQueue *eventQueue = &state->eventQueue; - for (i32 i = 0; i < ARRAY_COUNT(state->world); i++) - { - World *const world = &state->world[i]; - world->maxEntities = 16384; - world->entities = - memory_pushBytes(arena, world->maxEntities * sizeof(Entity)); - world->entityIdInBattle = - memory_pushBytes(arena, world->maxEntities * sizeof(i32)); - world->numEntitiesInBattle = 0; - world->bounds = - math_getRect(V2(0, 0), v2_scale(worldDimensionInTiles, - CAST(f32) state->tileSize)); - world->uniqueIdAccumulator = 0; - -#if 1 - TexAtlas *const atlas = asset_getTexAtlas(assetManager, "terrain.png"); - - for (i32 y = 0; y < 1; y++) - { - for (i32 x = 0; x < worldDimensionInTiles.x; x++) - { -#ifdef DENGINE_DEBUG - ASSERT(worldDimensionInTiles.x * worldDimensionInTiles.y < - world->maxEntities); -#endif - v2 pos = V2(CAST(f32) x * state->tileSize, - CAST(f32) y * state->tileSize); - v2 size = - V2(CAST(f32) state->tileSize, CAST(f32) state->tileSize); - f32 scale = 1.0f; - enum EntityType type = entitytype_tile; - enum Direction dir = direction_null; - Texture *tex = asset_getTex(assetManager, "terrain.png"); - b32 collides = FALSE; - Entity *tile = entity_add(arena, world, pos, size, scale, type, - dir, tex, collides); - - entity_addAnim(assetManager, tile, "terrainGrass"); - entity_setActiveAnim(eventQueue, tile, "terrainGrass"); - } - } -#endif - } - - World *const world = &state->world[state->currWorldIndex]; - world->cameraPos = V2(0.0f, 0.0f); - - /* Add world soundscape */ - Renderer *renderer = &state->renderer; - v2 size = V2(10.0f, 10.0f); - v2 pos = V2(0, 0); - f32 scale = 1.0f; - enum EntityType type = entitytype_soundscape; - enum Direction dir = direction_null; - Texture *tex = NULL; - b32 collides = FALSE; - Entity *soundscape = - entity_add(arena, world, pos, size, scale, type, dir, tex, collides); - - world->soundscape = soundscape; - soundscape->numAudioRenderers = 1; - soundscape->audioRenderer = memory_pushBytes( - arena, soundscape->numAudioRenderers * sizeof(AudioRenderer)); - for (i32 i = 0; i < soundscape->numAudioRenderers; i++) - soundscape->audioRenderer[i].sourceIndex = AUDIO_SOURCE_UNASSIGNED; - - /* Init hero entity */ - size = V2(58.0f, 98.0f); - pos = V2(size.x, CAST(f32) state->tileSize); - scale = 2.0f; - type = entitytype_hero; - dir = direction_east; - tex = asset_getTex(assetManager, "ClaudeSprite.png"); - collides = TRUE; - - Entity *hero = - entity_add(arena, world, pos, size, scale, type, dir, tex, collides); - - Entity *heroWeapon = - entity_add(arena, world, pos, V2(20, 20), scale, entitytype_weapon, - dir, tex, FALSE); - heroWeapon->flipX = TRUE; - entity_addAnim(assetManager, heroWeapon, "claudeSword"); - - hero->stats->weapon = heroWeapon; - - hero->numAudioRenderers = 4; - hero->audioRenderer = memory_pushBytes(arena, hero->numAudioRenderers * - sizeof(AudioRenderer)); - - for (i32 i = 0; i < hero->numAudioRenderers; i++) - hero->audioRenderer[i].sourceIndex = AUDIO_SOURCE_UNASSIGNED; - - world->heroId = hero->id; - world->cameraFollowingId = hero->id; - - /* Populate hero animation references */ - entity_addAnim(assetManager, hero, "claudeIdle"); - entity_addAnim(assetManager, hero, "claudeRun"); - entity_addAnim(assetManager, hero, "claudeBattleIdle"); - - entity_addAnim(assetManager, hero, "claudeAttack"); - entity_addAnim(assetManager, hero, "claudeAttackUp"); - entity_addAnim(assetManager, hero, "claudeAttackDown"); - - entity_addAnim(assetManager, hero, "claudeDragonHowl"); - entity_addAnim(assetManager, hero, "claudeEnergySword"); - entity_addAnim(assetManager, hero, "claudeRipperBlast"); - entity_addAnim(assetManager, hero, "claudeAirSlash"); - - entity_setActiveAnim(eventQueue, hero, "claudeIdle"); - - /* Create a NPC */ - pos = V2(hero->pos.x * 3, CAST(f32) state->tileSize); - size = hero->hitbox; - type = entitytype_npc; - dir = direction_null; - tex = hero->tex; - collides = FALSE; - Entity *npc = - entity_add(arena, world, pos, size, scale, type, dir, tex, collides); - - /* Populate npc animation references */ - entity_addAnim(assetManager, npc, "claudeVictory"); - entity_setActiveAnim(eventQueue, npc, "claudeVictory"); - - /* Create a Mob */ - pos = V2(renderer->size.w - (renderer->size.w / 3.0f), - CAST(f32) state->tileSize); - addGenericMob(eventQueue, arena, assetManager, world, pos); - -#ifdef DENGINE_DEBUG - DEBUG_LOG("World populated"); -#endif -} - -INTERNAL v2 getPosRelativeToRect(Rect rect, v2 offset, - enum RectBaseline baseline) -{ -#ifdef DENGINE_DEBUG - ASSERT(baseline < rectbaseline_count); -#endif - v2 result = {0}; - - v2 posToOffsetFrom = rect.pos; - switch (baseline) - { - case rectbaseline_top: - posToOffsetFrom.y += (rect.size.h); - posToOffsetFrom.x += (rect.size.w * 0.5f); - break; - case rectbaseline_topLeft: - posToOffsetFrom.y += (rect.size.h); - break; - case rectbaseline_topRight: - posToOffsetFrom.y += (rect.size.h); - posToOffsetFrom.x += (rect.size.w); - break; - case rectbaseline_bottom: - posToOffsetFrom.x += (rect.size.w * 0.5f); - break; - case rectbaseline_bottomRight: - posToOffsetFrom.x += (rect.size.w); - break; - case rectbaseline_left: - posToOffsetFrom.y += (rect.size.h * 0.5f); - break; - case rectbaseline_right: - posToOffsetFrom.x += (rect.size.w); - posToOffsetFrom.y += (rect.size.h * 0.5f); - break; - - case rectbaseline_bottomLeft: - break; - default: -#ifdef DENGINE_DEBUG - DEBUG_LOG( - "getPosRelativeToRect() warning: baseline enum not recognised"); -#endif - break; - } - - result = v2_add(posToOffsetFrom, offset); - return result; -} - -INTERNAL void unitTest(MemoryArena_ *arena) -{ - ASSERT(common_atoi("-2", common_strlen("-2")) == -2); - ASSERT(common_atoi("100", common_strlen("100")) == 100); - ASSERT(common_atoi("1", common_strlen("1")) == 1); - ASSERT(common_atoi("954 32", common_strlen("954 32")) == 954); - - ASSERT(common_atoi("", 0) == -1); - ASSERT(common_atoi(" 32", common_strlen(" 32")) == -1); - ASSERT(common_atoi("+32", common_strlen("+32")) == 32); - ASSERT(common_atoi("+ 32", common_strlen("+ 32")) == 0); - asset_unitTest(arena); - - i32 memBefore = arena->used; - String *hello = string_make(arena, "hello, "); - String *world = string_make(arena, "world"); - ASSERT(string_len(hello) == 7); - ASSERT(string_len(world) == 5); - - hello = string_append(arena, hello, world, string_len(world)); - ASSERT(string_len(hello) == 12); - string_free(arena, hello); - string_free(arena, world); - - hello = string_make(arena, ""); - world = string_make(arena, ""); - hello = string_append(arena, hello, world, string_len(world)); - ASSERT(string_len(hello) == 0); - ASSERT(string_len(world) == 0); - - string_free(arena, hello); - string_free(arena, world); - - i32 memAfter = arena->used; -} - -// TODO(doyle): Remove and implement own random generator! -#include -#include -void worldTraveller_gameInit(GameState *state, v2 windowSize, Memory *memory) -{ - state->memory = memory; - memory_arenaInit(&state->arena_, memory->persistent, - memory->persistentSize); - - memory_arenaInit(&state->transientArena, memory->transient, - memory->transientSize); - -#ifdef DENGINE_DEBUG - unitTest(&state->arena_); -#endif - - i32 result = audio_init(&state->audioManager); - if (result) - { -#ifdef DENGINE_DEBUG - ASSERT(INVALID_CODE_PATH); -#endif - } - - state->state = state_active; - state->currWorldIndex = 0; - state->tileSize = 70; - - state->uiState.uniqueId = 1; - state->uiState.keyEntered = keycode_null; - state->uiState.keyMod = keycode_null; - state->uiState.keyChar = keycode_null; - - common_strncpy(state->uiState.statWindow.title, "Stat Menu", - common_strlen("Stat Menu")); - state->uiState.statWindow.id = 99; - state->uiState.statWindow.rect.pos = V2(300, 400); - state->uiState.statWindow.rect.size = V2(300, 400); - state->uiState.statWindow.prevFrameWindowHeld = FALSE; - state->uiState.statWindow.windowHeld = FALSE; - - - WindowState *debugWindow = &state->uiState.debugWindow; - common_strncpy(debugWindow->title, "Debug Menu", - common_strlen("Debug Menu")); - debugWindow->id = 98; - debugWindow->numChildUiItems = 0; - debugWindow->rect.size = V2(400, 200); - debugWindow->rect.pos = V2(windowSize.w - debugWindow->rect.size.w - 10, - windowSize.h - debugWindow->rect.size.h - 10); - debugWindow->prevFrameWindowHeld = FALSE; - debugWindow->windowHeld = FALSE; - - UiItem *audioBtn = - (debugWindow->childUiItems) + debugWindow->numChildUiItems++; - common_strncpy(audioBtn->label, "Toggle Music", - common_strlen("Toggle Music")); - audioBtn->id = userInterface_generateId(&state->uiState); - audioBtn->rect.size = V2(100, 50); - audioBtn->rect.pos = getPosRelativeToRect(debugWindow->rect, V2(10, -65.0f), - rectbaseline_topLeft); - audioBtn->type = uitype_button; - - UiItem *debugBtn = - (debugWindow->childUiItems) + debugWindow->numChildUiItems++; - common_strncpy(debugBtn->label, "Toggle Debug", - common_strlen("Toggle Debug")); - debugBtn->id = userInterface_generateId(&state->uiState); - debugBtn->rect.size = V2(100, 50); - debugBtn->rect.pos = getPosRelativeToRect(audioBtn->rect, V2(25, 0), - rectbaseline_bottomRight); - debugBtn->type = uitype_button; - - UiItem *scrollbar = - (debugWindow->childUiItems) + debugWindow->numChildUiItems++; - scrollbar->id = userInterface_generateId(&state->uiState); - - scrollbar->rect.size = V2(16, debugWindow->rect.size.h); - scrollbar->rect.pos = - getPosRelativeToRect(debugWindow->rect, V2(-scrollbar->rect.size.w, 0), - rectbaseline_bottomRight); - scrollbar->value = 0; - scrollbar->maxValue = 160; - scrollbar->type = uitype_scrollbar; - - UiItem *textField = - (debugWindow->childUiItems) + debugWindow->numChildUiItems++; - textField->id = userInterface_generateId(&state->uiState); - textField->rect.size = V2(200, 20); - textField->rect.pos = getPosRelativeToRect( - audioBtn->rect, V2(0, -textField->rect.size.h - 10), - rectbaseline_bottomLeft); - - common_strncpy(textField->string, "Hello world", - common_strlen("Hello world")); - textField->type = uitype_textField; - - state->config.playWorldAudio = FALSE; - state->config.showDebugDisplay = TRUE; - - assetInit(state); - rendererInit(state, windowSize); - entityInit(state, windowSize); - - srand(CAST(u32)(time(NULL))); -} - -INTERNAL inline v4 getEntityScreenRect(Entity entity) -{ - v4 result = math_getRect(entity.pos, entity.hitbox); - return result; -} - -enum ReadKeyType -{ - readkeytype_oneShot, - readkeytype_delayedRepeat, - readkeytype_repeat, - readkeytype_count, -}; - -#define KEY_DELAY_NONE 0.0f - -INTERNAL b32 getKeyStatus(KeyState *key, enum ReadKeyType readType, - f32 delayInterval, f32 dt) -{ - - if (!key->endedDown) return FALSE; - - switch(readType) - { - case readkeytype_oneShot: - { - if (key->newHalfTransitionCount > key->oldHalfTransitionCount) - return TRUE; - break; - } - case readkeytype_repeat: - case readkeytype_delayedRepeat: - { - if (key->newHalfTransitionCount > key->oldHalfTransitionCount) - { - if (readType == readkeytype_delayedRepeat) - { - // TODO(doyle): Let user set arbitrary delay after initial input - key->delayInterval = 2 * delayInterval; - } - else - { - key->delayInterval = delayInterval; - } - return TRUE; - } - else if (key->delayInterval <= 0.0f) - { - key->delayInterval = delayInterval; - return TRUE; - } - else - { - key->delayInterval -= dt; - } - break; - } - default: -#ifdef DENGINE_DEBUG - DEBUG_LOG("getKeyStatus() error: Invalid ReadKeyType enum"); - ASSERT(INVALID_CODE_PATH); -#endif - break; - } - - return FALSE; -} - -INTERNAL Rect createWorldBoundedCamera(World *world, v2 size) -{ - Rect camera = {world->cameraPos, size}; - // NOTE(doyle): Lock camera if it passes the bounds of the world - if (camera.pos.x <= world->bounds.x) - camera.pos.x = world->bounds.x; - - // TODO(doyle): Allow Y panning when we need it - f32 cameraTopBoundInPixels = camera.pos.y + camera.size.h; - if (cameraTopBoundInPixels >= world->bounds.w) - camera.pos.y = (world->bounds.w - camera.size.h); - - f32 cameraRightBoundInPixels = camera.pos.x + camera.size.w; - if (cameraRightBoundInPixels >= world->bounds.z) - camera.pos.x = (world->bounds.z - camera.size.w); - - if (camera.pos.y <= world->bounds.y) camera.pos.y = world->bounds.y; - return camera; -} - -#define ENTITY_IN_BATTLE TRUE -#define ENTITY_NOT_IN_BATTLE FALSE -#define ENTITY_NULL_ID -1 -INTERNAL i32 findBestEntityToAttack(World *world, Entity attacker) -{ -#ifdef DENGINE_DEBUG - ASSERT(world); - ASSERT(attacker.type == entitytype_hero || attacker.type == entitytype_mob); -#endif - i32 result = 0; - - // TODO(doyle): If attacker is mob- retrieve hero entity id directly, change - // when we have party members! - if (attacker.type == entitytype_mob) - { - Entity hero = world->entities[entity_getIndex(world, world->heroId)]; - - if (hero.state == entitystate_dead) result = ENTITY_NULL_ID; - else result = hero.id; - - return result; - } - - /* Attacker is hero */ - Entity hero = attacker; - for (i32 i = world->maxEntities; i >= 0; i--) - { - Entity targetEntity = world->entities[i]; - if (hero.id == targetEntity.id) continue; - if (world->entityIdInBattle[targetEntity.id] == ENTITY_IN_BATTLE) - { - result = targetEntity.id; - return result; - } - } - - // NOTE(doyle): Not all "battling" entities have been enumerated yet in the - // update loop, guard against when using function - return ENTITY_NULL_ID; -} - -INTERNAL inline void updateWorldBattleEntities(World *world, Entity *entity, - b32 isInBattle) -{ -#ifdef DENGINE_DEBUG - ASSERT(isInBattle == ENTITY_IN_BATTLE || - isInBattle == ENTITY_NOT_IN_BATTLE); - ASSERT(world && entity); -#endif - world->entityIdInBattle[entity->id] = isInBattle; - - if (isInBattle) - { - world->numEntitiesInBattle++; - } - else - { - world->numEntitiesInBattle--; - } - -#ifdef DENGINE_DEBUG - ASSERT(world->numEntitiesInBattle >= 0); -#endif -} - -// TODO(doyle): Function too vague -INTERNAL inline void resetEntityState(EventQueue *eventQueue, World *world, - Entity *entity) -{ - updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE); - entity_setActiveAnim(eventQueue, entity, "claudeIdle"); - entity->stats->busyDuration = 0; - entity->stats->actionTimer = entity->stats->actionRate; - entity->stats->queuedAttack = entityattack_invalid; - entity->stats->entityIdToAttack = ENTITY_NULL_ID; -} - -void worldTraveller_registerEvent(EventQueue *eventQueue, enum EventType type, void *data) -{ -#ifdef DENGINE_DEBUG - ASSERT(eventQueue && type < eventtype_count); - ASSERT(eventQueue->numEvents+1 < ARRAY_COUNT(eventQueue->queue)); -#endif - i32 currIndex = eventQueue->numEvents++; - eventQueue->queue[currIndex].type = type; - eventQueue->queue[currIndex].data = data; -} - -INTERNAL void entityStateSwitch(EventQueue *eventQueue, World *world, - Entity *entity, enum EntityState newState) -{ -#ifdef DENGINE_DEBUG - ASSERT(world && entity) - ASSERT(entity->type == entitytype_mob || entity->type == entitytype_hero) -#endif - if (entity->state == newState) return; - - switch(entity->state) - { - case entitystate_idle: - switch (newState) - { - case entitystate_battle: - updateWorldBattleEntities(world, entity, ENTITY_IN_BATTLE); - entity->stats->entityIdToAttack = - findBestEntityToAttack(world, *entity); - break; - - // TODO(doyle): Corner case- if move out of range and entity has - // switched to idle mode, we reach the attacker entity and they continue - // attacking it since there's no check before attack if entity is idle - // or not (i.e. has moved out of frame last frame). - case entitystate_dead: - worldTraveller_registerEvent(eventQueue, eventtype_entity_died, - CAST(void *) entity); - entity_setActiveAnim(eventQueue, entity, "claudeIdle"); - entity->stats->busyDuration = 0; - entity->stats->actionTimer = entity->stats->actionRate; - entity->stats->queuedAttack = entityattack_invalid; - entity->stats->entityIdToAttack = ENTITY_NULL_ID; - break; - - case entitystate_attack: - default: -#ifdef DENGINE_DEBUG - ASSERT(INVALID_CODE_PATH); -#endif - break; - } - break; - case entitystate_battle: - switch (newState) - { - case entitystate_attack: - { - break; - } - case entitystate_idle: - resetEntityState(eventQueue, world, entity); - break; - case entitystate_dead: - worldTraveller_registerEvent(eventQueue, eventtype_entity_died, - CAST(void *) entity); - resetEntityState(eventQueue, world, entity); - break; - default: -#ifdef DENGINE_DEBUG - ASSERT(INVALID_CODE_PATH); -#endif - break; - } - break; - case entitystate_attack: - switch (newState) - { - case entitystate_battle: - entity_setActiveAnim(eventQueue, entity, "claudeBattleIdle"); - entity->stats->actionTimer = entity->stats->actionRate; - entity->stats->busyDuration = 0; - break; - // NOTE(doyle): Entity has been forced out of an attack (out of range) - case entitystate_idle: - resetEntityState(eventQueue, world, entity); - break; - case entitystate_dead: - worldTraveller_registerEvent(eventQueue, eventtype_entity_died, - CAST(void *) entity); - resetEntityState(eventQueue, world, entity); - break; - default: -#ifdef DENGINE_DEBUG - ASSERT(INVALID_CODE_PATH); -#endif - break; - } - break; - case entitystate_dead: - switch (newState) - { - case entitystate_idle: - case entitystate_battle: - case entitystate_attack: - default: -#ifdef DENGINE_DEBUG - ASSERT(INVALID_CODE_PATH); -#endif - break; - } - break; - default: -#ifdef DENGINE_DEBUG - ASSERT(INVALID_CODE_PATH); -#endif - break; - } - - entity->state = newState; -} - -typedef struct AttackSpec -{ - Entity *attacker; - Entity *defender; - i32 damage; -} AttackSpec; - -INTERNAL void beginAttack(AssetManager *assetManager, MemoryArena_ *arena, - EventQueue *eventQueue, World *world, - Entity *attacker) -{ -#ifdef DENGINE_DEBUG - ASSERT(attacker->stats->entityIdToAttack != ENTITY_NULL_ID); - ASSERT(attacker->state == entitystate_battle); -#endif - - entityStateSwitch(eventQueue, world, attacker, entitystate_attack); - switch (attacker->stats->queuedAttack) - { - case entityattack_claudeAttack: - { - entity_setActiveAnim(eventQueue, attacker, "claudeAttack"); - if (attacker->direction == direction_east) - attacker->dPos.x += (1.0f * METERS_TO_PIXEL); - else - attacker->dPos.x -= (1.0f * METERS_TO_PIXEL); - break; - } - - case entityattack_claudeAttackUp: - { - entity_setActiveAnim(eventQueue, attacker, "claudeAttackUp"); - if (attacker->direction == direction_east) - attacker->dPos.x += (1.0f * METERS_TO_PIXEL); - else - attacker->dPos.x -= (1.0f * METERS_TO_PIXEL); - break; - } - - case entityattack_claudeAttackDown: - { - entity_setActiveAnim(eventQueue, attacker, "claudeAttackDown"); - if (attacker->direction == direction_east) - attacker->dPos.x += (1.0f * METERS_TO_PIXEL); - else - attacker->dPos.x -= (1.0f * METERS_TO_PIXEL); - break; - } - - case entityattack_claudeDragonHowl: - { - entity_setActiveAnim(eventQueue, attacker, "claudeDragonHowl"); - f32 scale = 1.5f; - v2 size = V2(40, 40); - Entity *projectile = entity_add( - arena, world, attacker->pos, size, scale, - entitytype_projectile, attacker->direction, attacker->tex, TRUE); - - projectile->collidesWith[entitytype_hero] = TRUE; - projectile->collidesWith[entitytype_mob] = TRUE; - projectile->collidesWith[attacker->type] = FALSE; - - projectile->stats->entityIdToAttack = attacker->stats->entityIdToAttack; - entity_addAnim(assetManager, projectile, "claudeDragonHowlVfx"); - entity_setActiveAnim(eventQueue, projectile, "claudeDragonHowlVfx"); - break; - } - - case entityattack_claudeEnergySword: - { - entity_setActiveAnim(eventQueue, attacker, "claudeEnergySword"); - break; - } - - case entityattack_claudeRipperBlast: - { - entity_setActiveAnim(eventQueue, attacker, "claudeRipperBlast"); - f32 scale = 5.0f; - v2 size = V2(20, 20); - - Entity *target = entity_get(world, attacker->stats->entityIdToAttack); - v2 targetPos = v2_add(attacker->pos, V2(100, 0)); - if (target) - { - targetPos = target->pos; - } - - Entity *projectile = entity_add( - arena, world, targetPos, size, scale, - entitytype_attackObject, attacker->direction, attacker->tex, TRUE); - - projectile->collidesWith[entitytype_hero] = TRUE; - projectile->collidesWith[entitytype_mob] = TRUE; - projectile->collidesWith[attacker->type] = FALSE; - - projectile->stats->entityIdToAttack = attacker->stats->entityIdToAttack; - entity_addAnim(assetManager, projectile, "claudeRipperBlastVfx"); - entity_setActiveAnim(eventQueue, projectile, "claudeRipperBlastVfx"); - break; - } - - case entityattack_claudeAirSlash: - { - entity_setActiveAnim(eventQueue, attacker, "claudeAirSlash"); - f32 scale = 1.5f; - v2 size = V2(20, 20); - Entity *projectile = entity_add( - arena, world, attacker->pos, size, scale, - entitytype_projectile, attacker->direction, attacker->tex, TRUE); - - projectile->collidesWith[entitytype_hero] = TRUE; - projectile->collidesWith[entitytype_mob] = TRUE; - projectile->collidesWith[attacker->type] = FALSE; - - projectile->stats->entityIdToAttack = attacker->stats->entityIdToAttack; - entity_addAnim(assetManager, projectile, "claudeAirSlashVfx"); - entity_setActiveAnim(eventQueue, projectile, "claudeAirSlashVfx"); - - v2 initialOffset = V2(size.x * 0.5f, 0); - f32 deltaScale = 0.3f; - projectile->numChilds = 3; - for (i32 i = 0; i < projectile->numChilds; i++) - { - v2 childOffset = v2_scale(initialOffset, CAST(f32) i + 1); - scale -= deltaScale; - - Entity *child = - entity_add(arena, world, v2_sub(projectile->pos, childOffset), - V2(20, 20), scale, entitytype_projectile, - projectile->direction, projectile->tex, FALSE); - - child->collidesWith[entitytype_hero] = FALSE; - child->collidesWith[entitytype_mob] = TRUE; - - child->stats->entityIdToAttack = - projectile->stats->entityIdToAttack; - entity_addAnim(assetManager, child, "claudeAirSlashVfx"); - entity_setActiveAnim(eventQueue, child, "claudeAirSlashVfx"); - projectile->childIds[i] = child->id; - } - break; - } - - default: -#ifdef DENGINE_DEBUG - ASSERT(INVALID_CODE_PATH); -#endif - break; - } - - EntityAnim attackAnim = attacker->animList[attacker->currAnimId]; - f32 busyDuration = - attackAnim.anim->frameDuration * CAST(f32) attackAnim.anim->numFrames; - attacker->stats->busyDuration = busyDuration; -} - -// TODO(doyle): MemArena here is temporary until we incorporate AttackSpec to -// battle in general! -INTERNAL void endAttack(MemoryArena_ *arena, EventQueue *eventQueue, - World *world, Entity *attacker) -{ -#ifdef DENGINE_DEBUG - ASSERT(attacker->stats->entityIdToAttack != ENTITY_NULL_ID); -#endif - - entityStateSwitch(eventQueue, world, attacker, entitystate_battle); - switch (attacker->stats->queuedAttack) - { - case entityattack_claudeAttack: - case entityattack_claudeAttackUp: - case entityattack_claudeAttackDown: - // TODO(doyle): Move animation offsets out and into animation type - if (attacker->direction == direction_east) - attacker->dPos.x -= (1.0f * METERS_TO_PIXEL); - else - attacker->dPos.x += (1.0f * METERS_TO_PIXEL); - - break; - - case entityattack_claudeAirSlash: - case entityattack_claudeRipperBlast: - case entityattack_claudeDragonHowl: - break; - - case entityattack_claudeEnergySword: - attacker->stats->health += 80; - AttackSpec *attackSpec = MEMORY_PUSH_STRUCT(arena, AttackSpec); - attackSpec->attacker = attacker; - attackSpec->defender = attacker; - attackSpec->damage = 30; - worldTraveller_registerEvent(eventQueue, eventtype_end_attack, - attackSpec); - return; - - default: -#ifdef DENGINE_DEBUG - ASSERT(INVALID_CODE_PATH); -#endif - break; - } - - /* Compute attack damage */ - Entity *defender = NULL; - - // TODO(doyle): Implement faster lookup for entity id in entity table - b32 noMoreValidTargets = FALSE; - do - { - /* Get target entity to attack */ - i32 entityIdToAttack = attacker->stats->entityIdToAttack; - i32 entityIndex = entity_getIndex(world, entityIdToAttack); - - if (entityIndex != -1) - { - defender = &world->entities[entityIndex]; -#ifdef DENGINE_DEBUG - ASSERT(defender->type == entitytype_mob || - defender->type == entitytype_hero); -#endif - } - else - { - i32 entityIdToAttack = findBestEntityToAttack(world, *attacker); - if (entityIdToAttack == ENTITY_NULL_ID) - { - noMoreValidTargets = TRUE; - } - else - { - attacker->stats->entityIdToAttack = - findBestEntityToAttack(world, *attacker); - } - } - } while (!defender && noMoreValidTargets == TRUE); - - if (!noMoreValidTargets) - { - i32 damage = 25; - - AttackSpec *attackSpec = MEMORY_PUSH_STRUCT(arena, AttackSpec); - attackSpec->attacker = attacker; - attackSpec->defender = defender; - attackSpec->damage = damage; - - worldTraveller_registerEvent(eventQueue, eventtype_end_attack, - attackSpec); - // TODO(doyle): Use attacker stats in battle equations - if (attacker->type == entitytype_hero) - { - defender->stats->health -= damage; - } - else if (attacker->type == entitytype_mob) - { - defender->stats->health -= damage * 0.25f; - } - - if (defender->stats->health <= 0.0f) defender->stats->health = 10.0f; - - if (defender->stats->health <= 0) - { - entityStateSwitch(eventQueue, world, defender, entitystate_dead); - entityStateSwitch(eventQueue, world, attacker, entitystate_idle); - } - } -} - -INTERNAL void sortWorldEntityList(World *world) -{ - b32 listHasChanged = TRUE; - i32 numUnsortedEntities = world->freeEntityIndex; - while (listHasChanged) - { - listHasChanged = FALSE; - for (i32 i = 0; i < numUnsortedEntities-1; i++) - { - // TODO(doyle): Better sort algorithm - Entity *entityA = &world->entities[i]; - Entity *entityB = &world->entities[i+1]; - if (entityA->type == entitytype_null || - (entityB->type != entitytype_null && entityA->id > entityB->id)) - { - Entity tempEntity = world->entities[i]; - world->entities[i] = world->entities[i + 1]; - world->entities[i + 1] = tempEntity; - listHasChanged = TRUE; - } - } - numUnsortedEntities--; - } -} - -INTERNAL enum EntityAttack selectBestAttack(Entity *entity) -{ - if (entity->stats->health <= 50.0f && entity->type == entitytype_hero) - { - return entityattack_claudeEnergySword; - } - else - { - enum EntityAttack attack = entityattack_claudeAttack; - i32 choice = rand() % 7; - switch(choice) - { - case 0: attack = entityattack_claudeAttack; break; - case 1: attack = entityattack_claudeAttackUp; break; - case 2: attack = entityattack_claudeAttackDown; break; - case 3: attack = entityattack_claudeDragonHowl; break; - case 4: attack = entityattack_claudeEnergySword; break; - case 5: attack = entityattack_claudeRipperBlast; break; - case 6: attack = entityattack_claudeAirSlash; break; - default: break; - } - - return attack; - } -} - -INTERNAL i32 entityGetFreeAudioRendererIndex(Entity *entity) -{ - i32 result = -1; - for (i32 i = 0; i < entity->numAudioRenderers; i++) - { - if (entity->audioRenderer[i].state == audiostate_stopped) - { - result = i; - break; - } - } - - return result; -} - -typedef struct DamageDisplay -{ - char damageStr[12]; - v2 pos; - f32 lifetime; -} DamageDisplay; - -typedef struct BattleState -{ - DamageDisplay damageDisplay[128]; -} BattleState; - -GLOBAL_VAR BattleState battleState = {0}; - -INTERNAL b32 checkCollision(Entity *a, Entity *b) -{ - b32 result = FALSE; - if (a->collides && b->collides && a->collidesWith[b->type]) - { - Rect aRect = {a->pos, a->hitbox}; - - v2 aTopLeftP = - getPosRelativeToRect(aRect, V2(0, 0), rectbaseline_topLeft); - v2 aTopRightP = - getPosRelativeToRect(aRect, V2(0, 0), rectbaseline_topRight); - v2 aBottomLeftP = - getPosRelativeToRect(aRect, V2(0, 0), rectbaseline_bottomLeft); - v2 aBottomRightP = - getPosRelativeToRect(aRect, V2(0, 0), rectbaseline_bottomRight); - - Rect bRect = {b->pos, b->hitbox}; - - if (math_pointInRect(bRect, aTopLeftP) || - math_pointInRect(bRect, aTopRightP) || - math_pointInRect(bRect, aBottomLeftP) || - math_pointInRect(bRect, aBottomRightP)) - { - result = TRUE; - return result; - } - } - - return result; -} - -INTERNAL b32 moveEntityAndReturnCollision(World *world, Entity *entity, - v2 ddPos, f32 speedInMs, f32 dt) -{ - /* - ************************** - * Calculate Hero Speed - ************************** - */ - // NOTE(doyle): Clipping threshold for snapping velocity to 0 - f32 epsilon = 15.0f; - v2 epsilonDpos = v2_sub(V2(epsilon, epsilon), - V2(ABS(entity->dPos.x), ABS(entity->dPos.y))); - - if (epsilonDpos.x >= 0.0f && epsilonDpos.y >= 0.0f) - entity->dPos = V2(0.0f, 0.0f); - - f32 speedInPixels = speedInMs * METERS_TO_PIXEL; - - ddPos = v2_scale(ddPos, speedInPixels); - // TODO(doyle): Counteracting force on player's acceleration is - // arbitrary - ddPos = v2_sub(ddPos, v2_scale(entity->dPos, 5.5f)); - - /* - NOTE(doyle): Calculate new position from acceleration with old - velocity - new Position = (a/2) * (t^2) + (v*t) + p, - acceleration = (a/2) * (t^2) - old velocity = (v*t) - */ - v2 ddPosNew = v2_scale(v2_scale(ddPos, 0.5f), SQUARED(dt)); - v2 dPos = v2_scale(entity->dPos, dt); - - v2 oldP = entity->pos; - v2 newP = v2_add(v2_add(ddPosNew, dPos), entity->pos); - entity->pos = newP; - - /* - ************************** - * Collision Detection - ************************** - */ - // TODO(doyle): Only check collision for entities within small - // bounding box of the hero - b32 entityCollided = FALSE; - if (entity->collides) - { - for (i32 i = 0; i < world->maxEntities; i++) - { - Entity *collider = &world->entities[i]; - if (collider->state == entitystate_dead) continue; - if (collider->id == entity->id) continue; - - entityCollided = checkCollision(entity, collider); - if (entityCollided) break; - } - } - - if (entityCollided) - { - entity->dPos = V2(0.0f, 0.0f); - entity->pos = oldP; - } - else - { - // f'(t) = curr velocity = a*t + v, where v is old velocity - entity->dPos = v2_add(entity->dPos, v2_scale(ddPos, dt)); - entity->pos = newP; - } - - return entityCollided; -} - -void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) -{ - // TODO(doyle): use proper dt limiting techniques - if (dt >= 1.0f) dt = 1.0f; - GL_CHECK_ERROR(); - - memory_arenaInit(&state->transientArena, state->memory->transient, - state->memory->transientSize); - - AssetManager *assetManager = &state->assetManager; - Renderer *renderer = &state->renderer; - World *const world = &state->world[state->currWorldIndex]; - Font *font = &assetManager->font; - MemoryArena_ *arena = &state->arena_; - MemoryArena_ *transientArena = &state->transientArena; - EventQueue *eventQueue = &state->eventQueue; - - /* - ********************** - * Parse Input Keys - ********************** - */ - { - /* - ********************** - * Parse Alphabet Keys - ********************** - */ - KeyState *keys = state->input.keys; - for (enum KeyCode code = 0; code < keycode_count; code++) - { - b32 parseKey = FALSE; - - KeyState *key = &keys[code]; - if (key->newHalfTransitionCount > key->oldHalfTransitionCount) - { - i32 numTransitions = - key->newHalfTransitionCount - key->oldHalfTransitionCount; - - if (!IS_EVEN(numTransitions)) - key->endedDown = (key->endedDown) ? FALSE : TRUE; - } - - if (code >= keycode_a && code <= keycode_z) parseKey = TRUE; - if (code >= keycode_A && code <= keycode_Z) parseKey = TRUE; - if (code >= keycode_0 && code <= keycode_9) parseKey = TRUE; - - if (!parseKey) continue; - - if (getKeyStatus(key, readkeytype_repeat, 0.15f, dt)) - { - // TODO(doyle): Multi press within frame overrides ui parsing - state->uiState.keyChar = code; - } - } - - /* - ************************** - * Parse Game Control Keys - ************************** - */ - if (getKeyStatus(&keys[keycode_enter], readkeytype_oneShot, - KEY_DELAY_NONE, dt)) - { - state->uiState.keyEntered = keycode_enter; - } - - if (getKeyStatus(&keys[keycode_tab], readkeytype_delayedRepeat, 0.25f, - dt)) - { - state->uiState.keyEntered = keycode_tab; - } - - if (getKeyStatus(&keys[keycode_space], readkeytype_delayedRepeat, 0.25f, - dt)) - { - state->uiState.keyChar = keycode_space; - } - - if (getKeyStatus(&keys[keycode_backspace], readkeytype_delayedRepeat, - 0.1f, dt)) - { - state->uiState.keyEntered = keycode_backspace; - } - - if (getKeyStatus(&keys[keycode_left_square_bracket], - readkeytype_delayedRepeat, 0.0f, dt)) - { - - Renderer *renderer = &state->renderer; - f32 yPos = CAST(f32)(rand() % CAST(i32) renderer->size.h); - f32 xModifier = 5.0f - CAST(f32)(rand() % 3); - - v2 pos = - V2(renderer->size.w - (renderer->size.w / xModifier), yPos); - addGenericMob(eventQueue, &state->arena_, &state->assetManager, world, pos); - } - } - - /* - ****************************** - * Update entities and render - ****************************** - */ - Rect camera = createWorldBoundedCamera(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]; - - /* Reposition camera if entity is targeted id */ - if (world->cameraFollowingId == entity->id) - { - // NOTE(doyle): Set the camera such that the hero is centered - v2 offsetFromEntityToCameraOrigin = - V2((entity->pos.x - (0.5f * state->renderer.size.w)), (0.0f)); - - // NOTE(doyle): Account for the hero's origin being the bottom left - offsetFromEntityToCameraOrigin.x += (entity->hitbox.w * 0.5f); - world->cameraPos = offsetFromEntityToCameraOrigin; - } - - if (entity->state == entitystate_dead) continue; - if (entity->invisible == TRUE) continue; - - if (entity->type == entitytype_soundscape) - { - AudioRenderer *audioRenderer = &entity->audioRenderer[0]; - if (!state->config.playWorldAudio) - { - // TODO(doyle): Use is playing flag, not just streaming flag - if (audioRenderer->state == audiostate_playing) - { - audio_pauseVorbis(&state->audioManager, audioRenderer); - } - } - else - { - if (world->numEntitiesInBattle > 0) - { - AudioVorbis *battleTheme = - asset_getVorbis(assetManager, "audio_battle"); - if (audioRenderer->audio) - { - if (common_strcmp(audioRenderer->audio->key, - "audio_battle") != 0) - { - 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, "audio_overworld"); - if (audioRenderer->audio) - { - if (common_strcmp(audioRenderer->audio->key, - "audio_overworld") != 0) - { - audio_streamPlayVorbis( - arena, &state->audioManager, audioRenderer, - overworldTheme, AUDIO_REPEAT_INFINITE); - } - } - else - { - audio_streamPlayVorbis(arena, &state->audioManager, - audioRenderer, overworldTheme, - AUDIO_REPEAT_INFINITE); - } - } - - if (audioRenderer->state == audiostate_paused) - { - audio_resumeVorbis(&state->audioManager, audioRenderer); - } - } - } - - /* - ***************************************************** - * Calculate Mob In Battle Range - ***************************************************** - */ - if (entity->type == entitytype_mob) - { - // TODO(doyle): Currently calculated in pixels, how about meaningful - // game units? - f32 battleThreshold = 500.0f; - Entity *hero = getHeroEntity(world); - f32 distance = v2_magnitude(hero->pos, entity->pos); - - enum EntityState newState = entitystate_invalid; - if (distance <= battleThreshold) - { - // NOTE(doyle): If in range but in battle, no state change - if (entity->state == entitystate_battle || - entity->state == entitystate_attack) - { - newState = entity->state; - } - else - { - newState = entitystate_battle; - } - } - else - { - newState = entitystate_idle; - } - - i32 numEntitiesInBattleBefore = world->numEntitiesInBattle; - entityStateSwitch(eventQueue, world, entity, newState); - - if (numEntitiesInBattleBefore == 0 && - world->numEntitiesInBattle > 0) - { - i32 freeAudioIndex = entityGetFreeAudioRendererIndex(hero); - if (freeAudioIndex != -1) - { - char *battleTaunt[11] = { - "Battle_come_on", - "Battle_heh", - "Battle_heres_the_enemy", - "Battle_hey", - "Battle_oh_its_just_them", - "Battle_shouldnt_you_run_away", - "Battle_things_will_work_out_somehow", - "Battle_things_will_work_out", - "Battle_were_gonna_win", - "Battle_we_can_win_this", - "Battle_you_think_you_can_win_over_the_hero_of_light"}; - - i32 battleTauntSfxIndex = rand() % ARRAY_COUNT(battleTaunt); - audio_playVorbis( - arena, audioManager, - &hero->audioRenderer[freeAudioIndex], - asset_getVorbis(assetManager, - battleTaunt[battleTauntSfxIndex]), - 1); - } - } - } - else if (entity->type == entitytype_hero) - { - /* - ************************** - * Calculate Hero Movement - ************************** - */ - - /* - Equations of Motion - f(t) = position m - f'(t) = velocity m/s - f"(t) = acceleration m/s^2 - - The user supplies an acceleration, a, and by integrating - f"(t) = a, where a is a constant, acceleration - f'(t) = a*t + v, where v is a constant, old velocity - f (t) = (a/2)*t^2 + v*t + p, where p is a constant, old position - */ - - Entity *hero = entity; - KeyState *keys = state->input.keys; - - v2 ddPos = V2(0, 0); - if (hero->stats->busyDuration <= 0) - { - if (getKeyStatus(&keys[keycode_right], readkeytype_repeat, - KEY_DELAY_NONE, dt)) - { - ddPos.x = 1.0f; - hero->direction = direction_east; - } - - if (getKeyStatus(&keys[keycode_left], readkeytype_repeat, - KEY_DELAY_NONE, dt)) - { - ddPos.x = -1.0f; - hero->direction = direction_west; - } - - if (getKeyStatus(&keys[keycode_up], readkeytype_repeat, - KEY_DELAY_NONE, dt)) - { - ddPos.y = 1.0f; - } - - if (getKeyStatus(&keys[keycode_down], readkeytype_repeat, - KEY_DELAY_NONE, dt)) - { - ddPos.y = -1.0f; - } - - if (ddPos.x != 0.0f && ddPos.y != 0.0f) - { - // NOTE(doyle): Cheese it and pre-compute the vector for - // diagonal using pythagoras theorem on a unit triangle 1^2 - // + 1^2 = c^2 - ddPos = v2_scale(ddPos, 0.70710678118f); - } - } - - f32 heroSpeed = 6.2f; - if (getKeyStatus(&state->input.keys[keycode_leftShift], - readkeytype_repeat, KEY_DELAY_NONE, dt)) - { - // TODO: Context sensitive command separation - state->uiState.keyMod = keycode_leftShift; - heroSpeed *= 10.0f; - } - else - { - state->uiState.keyMod = keycode_null; - } - - moveEntityAndReturnCollision(world, hero, ddPos, heroSpeed, dt); - - char *currAnimName = hero->animList[hero->currAnimId].anim->key; - if (ABS(entity->dPos.x) > 0.0f || ABS(entity->dPos.y) > 0.0f) - { - if (common_strcmp(currAnimName, "claudeIdle") == 0) - { - entity_setActiveAnim(eventQueue, hero, "claudeRun"); - } - } - else - { - if (common_strcmp(currAnimName, "claudeRun") == 0) - { - entity_setActiveAnim(eventQueue, hero, "claudeIdle"); - } - } - - } - else if (entity->type == entitytype_projectile) - { - Entity *projectile = entity; - i32 targetIndex = - entity_getIndex(world, projectile->stats->entityIdToAttack); - Entity *target = &world->entities[targetIndex]; - - v2 ddPos = V2(0, 0); - f32 projectileSpeed = 10.0f; - - v2 difference = v2_sub(target->pos, projectile->pos); - f32 longSide = (ABS(difference.x) > ABS(difference.y)) - ? ABS(difference.x) - : ABS(difference.y); - - ddPos.x = (difference.x / longSide); - ddPos.y = (difference.y / longSide); - - if (ddPos.x != 0.0f && ddPos.y != 0.0f) - { - // NOTE(doyle): Cheese it and pre-compute the vector for - // diagonal using pythagoras theorem on a unit triangle 1^2 - // + 1^2 = c^2 - ddPos = v2_scale(ddPos, 0.70710678118f); - } - - b32 collided = moveEntityAndReturnCollision( - world, projectile, ddPos, projectileSpeed, dt); - - if (collided) - { - // TODO(doyle): Unify concept of dead entity for mobs and - // projectiles - projectile->state = entitystate_dead; - // TODO(doyle): register endattack event - worldTraveller_registerEvent(eventQueue, eventtype_entity_died, - projectile); - } - } - else if (entity->type == entitytype_attackObject) - { - if (entity->animList[entity->currAnimId].timesCompleted == 1) - { - entity->state = entitystate_dead; - worldTraveller_registerEvent(eventQueue, eventtype_entity_died, - entity); - } - } - - /* - ************************************************** - * Conduct Battle For Mobs In Range - ************************************************** - */ - if (entity->type == entitytype_mob || entity->type == entitytype_hero) - { - EntityStats *stats = entity->stats; - - if (stats->weapon) - { - Entity *weapon = stats->weapon; - weapon->pos = entity->pos; - - // TODO(doyle): Add concept of entity origin and make all - // transform start from that origin point - if (entity->direction == direction_east) - { - weapon->pos.x += entity->size.w; - weapon->pos.x -= weapon->size.w; - } - weapon->direction = entity->direction; - - SubTexture entitySubTexture = - entity_getActiveSubTexture(entity); - weapon->pos.y += entitySubTexture.offset.y; - - if (weapon->direction == direction_west) - { - weapon->pos.x += entitySubTexture.offset.x; - // TODO(doyle): Typedef rotation to degrees for type safety - weapon->rotation = DEGREES_TO_RADIANS(30.0f); - } - else - { - LOCAL_PERSIST f32 rotation = -30.0f; - rotation -= 1.5f; - weapon->pos.x -= entitySubTexture.offset.x; - weapon->rotation = DEGREES_TO_RADIANS(rotation); - } - } - - if (entity->state == entitystate_battle) - { - - if (stats->actionTimer > 0) - stats->actionTimer -= dt * stats->actionSpdMul; - - if (stats->actionTimer <= 0) - { - stats->actionTimer = 0; - if (stats->queuedAttack == entityattack_invalid) - { - enum EntityAttack attack = selectBestAttack(entity); - stats->queuedAttack = attack; - } - - /* Launch up attack animation */ - beginAttack(assetManager, &state->arena_, eventQueue, world, - entity); - } - } - else if (entity->state == entitystate_attack) - { - // TODO(doyle): Untested if the attacker and the defender same - Entity *attacker = entity; - stats->busyDuration -= dt; - if (stats->busyDuration <= 0) - { - /* Apply attack damage */ - endAttack(transientArena, eventQueue, world, entity); - } - } - } - - /* - **************** - * Update Entity - **************** - */ - for (i32 i = 0; i < entity->numAudioRenderers; i++) - { - audio_updateAndPlay(&state->arena_, &state->audioManager, - &entity->audioRenderer[i]); - } - - if (entity->tex) - { - entity_updateAnim(eventQueue, entity, dt); - /* Calculate region to render */ - renderer_entity(renderer, camera, entity, - v2_scale(entity->size, 0.5f), 0, V4(1, 1, 1, 1.0f)); - } - } - - /* - ***************************************** - * Process Events From Entity Update Loop - ***************************************** - */ - i32 numDeadEntities = 0; - for (i32 i = 0; i < eventQueue->numEvents; i++) - { - Event event = eventQueue->queue[i]; - - eventQueue->queue[i].type = eventtype_null; - eventQueue->queue[i].data = NULL; - - switch(event.type) - { - case eventtype_end_attack: - { - if (!event.data) continue; - - AttackSpec *attackSpec = (CAST(AttackSpec *) event.data); - Entity *attacker = attackSpec->attacker; - Entity *defender = attackSpec->defender; - - if (attacker->stats->queuedAttack == entityattack_claudeAttack || - attacker->stats->queuedAttack == entityattack_claudeAttackUp || - attacker->stats->queuedAttack == entityattack_claudeAttackDown) - { - i32 freeAudioIndex = entityGetFreeAudioRendererIndex(attacker); - if (freeAudioIndex != -1) - { - char *attackSfx[11] = { - "Attack_1", "Attack_2", "Attack_3", - "Attack_4", "Attack_5", "Attack_6", - "Attack_7", "Attack_hit_it", "Attack_take_that", - "Attack_hya", "Attack_burn"}; - - i32 attackSfxIndex = rand() % ARRAY_COUNT(attackSfx); - audio_playVorbis(arena, audioManager, - &attacker->audioRenderer[freeAudioIndex], - asset_getVorbis(assetManager, - attackSfx[attackSfxIndex]), - 1); - } - - freeAudioIndex = entityGetFreeAudioRendererIndex(defender); - if (freeAudioIndex != -1) - { - char *hurtSfx[10] = {"Hurt_1", "Hurt_2", - "Hurt_3", "Hurt_hows_this", - "Hurt_battlecry", "Hurt_ow", - "Hurt_uh_oh", "Hurt_ugh", - "Hurt_woah", "Hurt_yearning"}; - - i32 hurtSfxIndex = rand() % ARRAY_COUNT(hurtSfx); - - audio_playVorbis( - arena, audioManager, - &defender->audioRenderer[freeAudioIndex], - asset_getVorbis(assetManager, hurtSfx[hurtSfxIndex]), - 1); - } - } - else if (attacker->stats->queuedAttack == - entityattack_claudeEnergySword) - { - i32 freeAudioIndex = entityGetFreeAudioRendererIndex(attacker); - if (freeAudioIndex != -1) - { - audio_playVorbis( - arena, audioManager, - &attacker->audioRenderer[freeAudioIndex], - asset_getVorbis(assetManager, "Attack_energy_sword"), - 1); - } - } - else if (attacker->stats->queuedAttack == - entityattack_claudeAirSlash) - { - i32 freeAudioIndex = entityGetFreeAudioRendererIndex(attacker); - if (freeAudioIndex != -1) - { - audio_playVorbis( - arena, audioManager, - &attacker->audioRenderer[freeAudioIndex], - asset_getVorbis(assetManager, "Attack_air_slash"), - 1); - } - } - else if (attacker->stats->queuedAttack == - entityattack_claudeDragonHowl) - { - i32 freeAudioIndex = entityGetFreeAudioRendererIndex(attacker); - if (freeAudioIndex != -1) - { - audio_playVorbis( - arena, audioManager, - &attacker->audioRenderer[freeAudioIndex], - asset_getVorbis(assetManager, "Attack_Dragon_howl"), - 1); - } - } - else if (attacker->stats->queuedAttack == - entityattack_claudeRipperBlast) - { - i32 freeAudioIndex = entityGetFreeAudioRendererIndex(attacker); - if (freeAudioIndex != -1) - { - audio_playVorbis( - arena, audioManager, - &attacker->audioRenderer[freeAudioIndex], - asset_getVorbis(assetManager, "Attack_tear_into_pieces"), - 1); - } - } - else - { - //ASSERT(INVALID_CODE_PATH); - } - - attacker->stats->queuedAttack = entityattack_invalid; - - /* Get first free string position and store the damage str data */ - for (i32 i = 0; i < ARRAY_COUNT(battleState.damageDisplay); i++) - { - if (battleState.damageDisplay[i].lifetime <= 0.0f) - { - common_memset( - battleState.damageDisplay[i].damageStr, 0, - ARRAY_COUNT(battleState.damageDisplay[i].damageStr)); - - battleState.damageDisplay[i].lifetime = 1.0f; - battleState.damageDisplay[i].pos = defender->pos; - common_itoa( - attackSpec->damage, - battleState.damageDisplay[i].damageStr, - ARRAY_COUNT(battleState.damageDisplay[i].damageStr)); - - break; - } - } - break; - } - // NOTE(doyle): We delete dead entities at the end of the update - // loop incase a later indexed entity deletes an earlier indexed - // entity, the entity will exist for an additional frame - case eventtype_entity_died: - { -#ifdef DEGINE_DEBUG - DEBUG_LOG("Entity died: being deleted"); -#endif - if (!event.data) continue; - - Entity *entity = (CAST(Entity *) event.data); - for (i32 i = 0; i < entity->numAudioRenderers; i++) - { - audio_stopVorbis(&state->arena_, audioManager, - &entity->audioRenderer[i]); - } - entity_clearData(&state->arena_, world, entity); - numDeadEntities++; - - for (i32 i = 0; i < entity->numChilds; i++) - { - Entity *child = entity_get(world, entity->childIds[i]); - if (child) - { - for (i32 i = 0; i < child->numAudioRenderers; i++) - { - audio_stopVorbis(&state->arena_, audioManager, - &child->audioRenderer[i]); - } - entity_clearData(&state->arena_, world, child); - numDeadEntities++; - } - else - { - DEBUG_LOG("Entity child expected but not found"); - } - } - break; - } - default: - { - break; - } - } - } - eventQueue->numEvents = 0; - - /* - **************************** - * Update World From Results - **************************** - */ - // TODO(doyle): Dead hero not accounted for here - Entity *hero = getHeroEntity(world); - if (world->numEntitiesInBattle > 0) - { - // NOTE(doyle): If battle entities is 1 then only the hero left - if (hero->state == entitystate_battle && - world->numEntitiesInBattle == 1) - { - entityStateSwitch(eventQueue, world, hero, entitystate_idle); - } - else if (hero->state != entitystate_attack) - { - entityStateSwitch(eventQueue, world, hero, entitystate_battle); - } - } - else - { - if (hero->state == entitystate_battle) - { - hero->state = entitystate_idle; - world->entityIdInBattle[hero->id] = FALSE; - entity_setActiveAnim(eventQueue, hero, "claudeIdle"); - } - hero->stats->entityIdToAttack = -1; - hero->stats->actionTimer = hero->stats->actionRate; - hero->stats->busyDuration = 0; - } - - sortWorldEntityList(world); - world->freeEntityIndex -= numDeadEntities; - - /* - ******************** - * UI Rendering Code - ******************** - */ - /* Render all damage strings */ - for (i32 i = 0; i < ARRAY_COUNT(battleState.damageDisplay); i++) - { - if (battleState.damageDisplay[i].lifetime > 0.0f) - { - battleState.damageDisplay[i].lifetime -= dt; - - char *damageString = battleState.damageDisplay[i].damageStr; - v2 damagePos = battleState.damageDisplay[i].pos; - f32 lifetime = battleState.damageDisplay[i].lifetime; - - // TODO(doyle): Incorporate UI into entity list or it's own list - // with a rendering lifetime value - renderer_string(renderer, transientArena, camera, font, - damageString, damagePos, V2(0, 0), 0, - V4(1, 1, 1, lifetime)); - } - } - - // INIT IMGUI - state->uiState.hotItem = 0; - - /* Draw ui */ - if (state->uiState.keyChar == keycode_i) - { - state->config.showStatMenu = - (state->config.showStatMenu == TRUE) ? FALSE : TRUE; - } - - if (state->config.showStatMenu) - { - WindowState *statWindow = &state->uiState.statWindow; - userInterface_window(&state->uiState, transientArena, assetManager, - renderer, font, state->input, statWindow); - } - - /* Draw debug window */ - WindowState *debugWindow = &state->uiState.debugWindow; - i32 activeId = - userInterface_window(&state->uiState, transientArena, assetManager, - renderer, font, state->input, debugWindow); - - // TODO(doyle): Name lookup to user interface id - if (activeId == 1) - { - state->config.playWorldAudio = - (state->config.playWorldAudio == TRUE) ? FALSE : TRUE; - } - else if (activeId == 2) - { - state->config.showDebugDisplay = - (state->config.showDebugDisplay == TRUE) ? FALSE : TRUE; - } - - // RESET IMGUI - if (!state->input.keys[keycode_mouseLeft].endedDown) - state->uiState.activeItem = 0; - else if (state->uiState.activeItem == 0) - state->uiState.activeItem = -1; - - if (state->uiState.keyEntered == keycode_tab) state->uiState.kbdItem = 0; - state->uiState.keyEntered = keycode_null; - state->uiState.keyChar = keycode_null; - - /* Draw hero avatar */ - TexAtlas *heroAtlas = - asset_getTexAtlas(assetManager, "ClaudeSprite.png"); - SubTexture heroAvatarRect = - asset_getAtlasSubTex(heroAtlas, "ClaudeSprite_Avatar_01"); - v2 heroAvatarP = V2(10.0f, (renderer->size.h * 0.5f) - - (0.5f * heroAvatarRect.rect.size.h)); - - // TODO(doyle): Use rect in rendering not V4 - v4 heroAvatarTexRect = {0}; - heroAvatarTexRect.vec2[0] = heroAvatarRect.rect.pos; - heroAvatarTexRect.vec2[1] = - v2_add(heroAvatarRect.rect.pos, heroAvatarRect.rect.size); - - RenderTex heroRenderTex = {hero->tex, heroAvatarTexRect}; - renderer_staticRect(renderer, heroAvatarP, heroAvatarRect.rect.size, V2(0, 0), 0, - heroRenderTex, V4(1, 1, 1, 1)); - - char heroAvatarStr[20]; - snprintf(heroAvatarStr, ARRAY_COUNT(heroAvatarStr), "HP: %3.0f/%3.0f", - hero->stats->health, hero->stats->maxHealth); - f32 strLenInPixels = - CAST(f32)(font->maxSize.w * common_strlen(heroAvatarStr)); - v2 strPos = - V2(heroAvatarP.x, heroAvatarP.y - (0.5f * heroAvatarRect.rect.size.h)); - renderer_staticString(&state->renderer, transientArena, font, heroAvatarStr, - strPos, V2(0, 0), 0, V4(0, 0, 1, 1)); - - renderer_staticString(&state->renderer, transientArena, font, heroAvatarStr, - strPos, V2(0, 0), 0, V4(0, 0, 1, 1)); - - for (i32 i = 0; i < world->maxEntities; i++) - { - Entity *entity = &world->entities[i]; - if (entity->id == hero->id) - continue; - - if (entity->state == entitystate_attack || - entity->state == entitystate_battle) - { - v2 difference = v2_sub(entity->pos, hero->pos); - f32 angle = math_atan2f(difference.y, difference.x); - - v2 heroCenter = v2_add(hero->pos, v2_scale(hero->hitbox, 0.5f)); - RenderTex renderTex = renderer_createNullRenderTex(assetManager); - f32 distance = v2_magnitude(hero->pos, entity->pos); - v2 size = V2(distance, 2.0f); - renderer_rect(&state->renderer, camera, heroCenter, - size, V2(0, 0), angle, renderTex, - V4(1, 0, 0, 1.0f)); - } - } - - for (i32 i = 0; i < keycode_count; i++) - { - state->input.keys[i].oldHalfTransitionCount = - state->input.keys[i].newHalfTransitionCount; - } - - /* - ******************** - * DEBUG CODE - ******************** - */ -#ifdef DENGINE_DEBUG - for (i32 i = 0; i < world->freeEntityIndex-1; i++) - { - ASSERT(world->entities[i].type != entitytype_null); - ASSERT(world->entities[i].id < world->entities[i+1].id); - } -#endif - -#ifdef DENGINE_DEBUG - if (state->config.showDebugDisplay) - { - debug_drawUi(state, dt); - } -#endif - - renderer_renderGroups(renderer); -} diff --git a/src/build.bat b/src/build.bat index 6cd7464..7215d53 100644 --- a/src/build.bat +++ b/src/build.bat @@ -1,4 +1,13 @@ @echo OFF + +REM Build tags file +ctags -R + +REM Check if build tool is on path +REM >nul, 2>nul will remove the output text from the where command +where cl.exe >nul 2>nul +if %errorlevel%==1 call msvc86.bat + REM Drop compilation files into build folder IF NOT EXIST ..\bin mkdir ..\bin pushd ..\bin diff --git a/src/dengine.c b/src/dengine.c index a276c8f..8a10878 100644 --- a/src/dengine.c +++ b/src/dengine.c @@ -3,7 +3,8 @@ #include "Dengine/Debug.h" #include "Dengine/Math.h" #include "Dengine/OpenGL.h" -#include "Dengine/WorldTraveller.h" +#include "Dengine/MemoryArena.h" +#include "Dengine/Asteroid.h" INTERNAL inline void processKey(KeyState *state, int action) { @@ -142,6 +143,7 @@ i32 main(void) i32 frameBufferWidth, frameBufferHeight; glfwGetFramebufferSize(window, &frameBufferWidth, &frameBufferHeight); glViewport(0, 0, frameBufferWidth, frameBufferHeight); + v2 windowSize = V2i(frameBufferWidth, frameBufferHeight); glfwSetKeyCallback(window, keyCallback); glfwSetCursorPosCallback(window, mouseCallback); @@ -161,9 +163,8 @@ i32 main(void) ******************* */ Memory memory = {0}; - - size_t persistentSize = MEGABYTES(128); - size_t transientSize = MEGABYTES(128); + MemoryIndex persistentSize = MEGABYTES(128); + MemoryIndex transientSize = MEGABYTES(128); memory.persistentSize = persistentSize; memory.persistent = PLATFORM_MEM_ALLOC_(NULL, persistentSize, u8); @@ -171,15 +172,8 @@ i32 main(void) memory.transientSize = transientSize; memory.transient = PLATFORM_MEM_ALLOC_(NULL, transientSize, u8); - GameState worldTraveller = {0}; - worldTraveller_gameInit(&worldTraveller, - V2i(frameBufferWidth, frameBufferHeight), &memory); -#ifdef DENGINE_DEBUG - debug_init(&worldTraveller.arena_, V2i(windowWidth, windowHeight), - worldTraveller.assetManager.font); -#endif - - glfwSetWindowUserPointer(window, CAST(void *)(&worldTraveller)); + GameState gameState = {0}; + glfwSetWindowUserPointer(window, CAST(void *)(&gameState)); /* ******************* @@ -206,10 +200,11 @@ i32 main(void) glfwPollEvents(); /* Rendering commands here*/ - glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - worldTraveller_gameUpdateAndRender(&worldTraveller, secondsElapsed); + asteroid_gameUpdateAndRender(&gameState, &memory, windowSize, + secondsElapsed); GL_CHECK_ERROR(); /* Swap the buffers */ @@ -235,14 +230,10 @@ i32 main(void) f32 msPerFrame = secondsElapsed * 1000.0f; f32 framesPerSecond = 1.0f / secondsElapsed; - i32 entityCount = - worldTraveller.world[worldTraveller.currWorldIndex] - .freeEntityIndex; - char textBuffer[256]; snprintf(textBuffer, ARRAY_COUNT(textBuffer), "Dengine | %f ms/f | %f fps | Entity Count: %d", - msPerFrame, framesPerSecond, entityCount); + msPerFrame, framesPerSecond, 0); glfwSetWindowTitle(window, textBuffer); titleUpdateFrequencyInSeconds = 0.5f; diff --git a/src/include/Dengine/Assets.h b/src/include/Dengine/Assets.h index 67466f6..f07635b 100644 --- a/src/include/Dengine/Assets.h +++ b/src/include/Dengine/Assets.h @@ -94,7 +94,6 @@ typedef struct AudioVorbis * Texture Assets ********************************* */ - typedef struct SubTexture { Rect rect; diff --git a/src/include/Dengine/Asteroid.h b/src/include/Dengine/Asteroid.h new file mode 100644 index 0000000..54a9523 --- /dev/null +++ b/src/include/Dengine/Asteroid.h @@ -0,0 +1,31 @@ +#ifndef ASTEROID_H +#define ASTEROID_H + +#include "Dengine/AssetManager.h" +#include "Dengine/Common.h" +#include "Dengine/Entity.h" +#include "Dengine/MemoryArena.h" +#include "Dengine/Platform.h" +#include "Dengine/Renderer.h" + +typedef struct GameState { + b32 init; + + Entity entityList[1024]; + i32 entityIndex; + + Rect camera; + + AssetManager assetManager; + KeyInput input; + + MemoryArena_ transientArena; + MemoryArena_ persistentArena; + + Renderer renderer; +} GameState; + +void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, + v2 windowSize, f32 dt); + +#endif diff --git a/src/include/Dengine/Common.h b/src/include/Dengine/Common.h index 5281a5c..bd525f0 100644 --- a/src/include/Dengine/Common.h +++ b/src/include/Dengine/Common.h @@ -14,6 +14,8 @@ typedef i32 b32; typedef float f32; typedef double f64; +typedef size_t MemoryIndex; + #define TRUE 1 #define FALSE 0 diff --git a/src/include/Dengine/Entity.h b/src/include/Dengine/Entity.h index 842d488..c90f30b 100644 --- a/src/include/Dengine/Entity.h +++ b/src/include/Dengine/Entity.h @@ -1,17 +1,10 @@ -#ifndef DENGINE_ENTITY_H -#define DENGINE_ENTITY_H +#ifndef ENTITY_H +#define ENTITY_H -#include "Dengine/Common.h" -#include "Dengine/Math.h" #include "Dengine/Assets.h" +#include "Dengine/Common.h" -typedef struct AssetManager AssetManager; typedef struct AudioRenderer AudioRenderer; -typedef struct MemoryArena MemoryArena_; -typedef struct World World; -typedef struct EventQueue EventQueue; - -typedef struct Entity Entity; enum Direction { @@ -19,63 +12,17 @@ enum Direction direction_west, direction_south, direction_east, - direction_num, direction_null, + direction_num, }; enum EntityType { - entitytype_null, - entitytype_hero, - entitytype_weapon, - entitytype_projectile, - entitytype_attackObject, - entitytype_npc, - entitytype_mob, - entitytype_tile, - entitytype_soundscape, + entitytype_invalid, + entitytype_ship, entitytype_count, }; -enum EntityState -{ - entitystate_idle, - entitystate_battle, - entitystate_attack, - entitystate_dead, - entitystate_count, - entitystate_invalid, -}; - -enum EntityAttack -{ - entityattack_claudeAttack, - entityattack_claudeAttackUp, - entityattack_claudeAttackDown, - entityattack_claudeDragonHowl, - entityattack_claudeEnergySword, - entityattack_claudeRipperBlast, - entityattack_claudeAirSlash, - entityattack_count, - entityattack_invalid, -}; - -typedef struct EntityStats -{ - f32 maxHealth; - f32 health; - - f32 actionRate; - f32 actionTimer; - f32 actionSpdMul; - - f32 busyDuration; - i32 entityIdToAttack; - enum EntityAttack queuedAttack; - - Entity *weapon; -} EntityStats; - typedef struct EntityAnim { Animation *anim; @@ -85,7 +32,7 @@ typedef struct EntityAnim u32 timesCompleted; } EntityAnim; -struct Entity +typedef struct Entity { i32 id; @@ -102,7 +49,6 @@ struct Entity b32 invisible; - enum EntityState state; enum EntityType type; enum Direction direction; @@ -116,32 +62,13 @@ struct Entity // allow for early-exit in collision check if the entity doesn't collide at // all b32 collides; - enum EntityType collidesWith[entitytype_count]; EntityAnim animList[16]; - i32 currAnimId; - - EntityStats *stats; + i32 animListIndex; // TODO(doyle): Audio mixing instead of multiple renderers AudioRenderer *audioRenderer; i32 numAudioRenderers; -}; +} Entity; -SubTexture entity_getActiveSubTexture(Entity *const entity); -void entity_setActiveAnim(EventQueue *eventQueue, Entity *const entity, - const char *const animName); -void entity_updateAnim(EventQueue *eventQueue, Entity *const entity, - const f32 dt); -void entity_addAnim(AssetManager *const assetManager, Entity *const entity, - const char *const animName); -Entity *const entity_add(MemoryArena_ *const arena, World *const world, - const v2 pos, const v2 size, const f32 scale, - const enum EntityType type, - const enum Direction direction, Texture *const tex, - const b32 collides); -void entity_clearData(MemoryArena_ *const arena, World *const world, - Entity *const entity); -Entity *entity_get(World *const world, const i32 entityId); -i32 entity_getIndex(World *const world, const i32 entityId); #endif diff --git a/src/include/Dengine/MemoryArena.h b/src/include/Dengine/MemoryArena.h index 17f60cd..2e16a38 100644 --- a/src/include/Dengine/MemoryArena.h +++ b/src/include/Dengine/MemoryArena.h @@ -5,25 +5,25 @@ typedef struct MemoryArena { - size_t size; - size_t used; + MemoryIndex size; + MemoryIndex used; u8 *base; } MemoryArena_; typedef struct Memory { void *persistent; - size_t persistentSize; + MemoryIndex persistentSize; void *transient; - size_t transientSize; + MemoryIndex transientSize; b32 init; } Memory; #define MEMORY_PUSH_STRUCT(arena, type) (type *)memory_pushBytes(arena, sizeof(type)) #define MEMORY_PUSH_ARRAY(arena, count, type) (type *)memory_pushBytes(arena, (count)*sizeof(type)) -inline void *memory_pushBytes(MemoryArena_ *arena, size_t size) +inline void *memory_pushBytes(MemoryArena_ *arena, MemoryIndex size) { ASSERT((arena->used + size) <= arena->size); void *result = arena->base + arena->used; @@ -32,6 +32,6 @@ inline void *memory_pushBytes(MemoryArena_ *arena, size_t size) return result; } -void memory_arenaInit(MemoryArena_ *arena, void *base, size_t size); +void memory_arenaInit(MemoryArena_ *arena, void *base, MemoryIndex size); #endif diff --git a/src/include/Dengine/Platform.h b/src/include/Dengine/Platform.h index 01e2eb6..159cff2 100644 --- a/src/include/Dengine/Platform.h +++ b/src/include/Dengine/Platform.h @@ -140,14 +140,16 @@ typedef struct PlatformFileRead } PlatformFileRead; // TODO(doyle): Create own custom memory allocator -#define PLATFORM_MEM_FREE_(arena, ptr, bytes) platform_memoryFree(arena, CAST(void *) ptr, bytes) +#define PLATFORM_MEM_FREE_(arena, ptr, bytes) \ + platform_memoryFree(arena, CAST(void *) ptr, bytes) // TODO(doyle): numBytes in mem free is temporary until we create custom // allocator since we haven't put in a system to track memory usage per // allocation -void platform_memoryFree(MemoryArena_ *arena, void *data, i32 numBytes); +void platform_memoryFree(MemoryArena_ *arena, void *data, MemoryIndex numBytes); -#define PLATFORM_MEM_ALLOC_(arena, num, type) CAST(type *) platform_memoryAlloc(arena, num * sizeof(type)) -void *platform_memoryAlloc(MemoryArena_ *arena, i32 numBytes); +#define PLATFORM_MEM_ALLOC_(arena, num, type) \ + CAST(type *) platform_memoryAlloc(arena, num * sizeof(type)) +void *platform_memoryAlloc(MemoryArena_ *arena, MemoryIndex numBytes); void platform_closeFileRead(MemoryArena_ *arena, PlatformFileRead *file); i32 platform_readFileToBuffer(MemoryArena_ *arena, const char *const filePath, diff --git a/src/include/Dengine/Renderer.h b/src/include/Dengine/Renderer.h index aad3dee..fa6f2df 100644 --- a/src/include/Dengine/Renderer.h +++ b/src/include/Dengine/Renderer.h @@ -6,8 +6,8 @@ /* Forward Declaration */ typedef struct AssetManager AssetManager; -typedef struct Entity Entity; typedef struct Font Font; +typedef struct Entity Entity; typedef struct MemoryArena MemoryArena_; typedef struct Shader Shader; typedef struct Texture Texture; diff --git a/src/include/Dengine/WorldTraveller.h b/src/include/Dengine/WorldTraveller.h deleted file mode 100644 index 7f38bfc..0000000 --- a/src/include/Dengine/WorldTraveller.h +++ /dev/null @@ -1,109 +0,0 @@ -#ifndef WORLDTRAVELLER_GAME_H -#define WORLDTRAVELLER_GAME_H - -#include "Dengine/AssetManager.h" -#include "Dengine/Audio.h" -#include "Dengine/Common.h" -#include "Dengine/Math.h" -#include "Dengine/MemoryArena.h" -#include "Dengine/Platform.h" -#include "Dengine/Renderer.h" -#include "Dengine/UserInterface.h" - -#define NUM_KEYS 1024 -#define METERS_TO_PIXEL 240 - -/* Forward declaration */ -typedef struct Entity Entity; - -enum EventType -{ - eventtype_null = 0, - eventtype_start_attack, - eventtype_end_attack, - eventtype_start_anim, - eventtype_end_anim, - eventtype_entity_died, - eventtype_count, -}; - -typedef struct Event -{ - enum EventType type; - void *data; -} Event; - -typedef struct EventQueue -{ - Event queue[1024]; - i32 numEvents; -} EventQueue; - -enum RectBaseline -{ - rectbaseline_top, - rectbaseline_topLeft, - rectbaseline_topRight, - rectbaseline_bottom, - rectbaseline_bottomRight, - rectbaseline_bottomLeft, - rectbaseline_left, - rectbaseline_right, - rectbaseline_center, - rectbaseline_count, - -}; - -typedef struct Config -{ - b32 playWorldAudio; - b32 showStatMenu; - b32 showDebugDisplay; -} Config; - -typedef struct World -{ - Entity *entities; - i32 maxEntities; - b32 *entityIdInBattle; - i32 numEntitiesInBattle; - - i32 cameraFollowingId; - v2 cameraPos; // In pixels - v4 bounds; // In pixels - - i32 heroId; - i32 freeEntityIndex; - u32 uniqueIdAccumulator; - - Entity *soundscape; -} World; - -typedef struct GameState -{ - Memory *memory; - MemoryArena_ arena_; - MemoryArena_ transientArena; - - enum State state; - KeyInput input; - v2 mouse; - - Renderer renderer; - - World world[4]; - i32 currWorldIndex; - i32 tileSize; - - AssetManager assetManager; - AudioManager audioManager; - Config config; - UiState uiState; - EventQueue eventQueue; -} GameState; - -void worldTraveller_gameInit(GameState *state, v2 windowSize, Memory *memory); -void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt); -void worldTraveller_registerEvent(EventQueue *eventQueue, enum EventType type, - void *data); -#endif