Mobs battle with hero, engine architect. changes

Mobs battle in real-time with the hero when in range. Start encapsulating
logic into entityStateSwitch() to organise entity properties changing
between different states.

Introduce basic concept of memory management in MemoryArena. Begin passing
around a memory object to track memory usage and eventually delegate
memory allocations through. Remove the old memory tracker in the debug
object and incorporate into engine primarily.

Add a debug console for logging information and events to the screen in
a console-like fashion. Debug is now initialised after the game, this is
so that you can pass the game's memory arena and font file to the debug
services. Debug services now properly initialise debug element positions
from this information and not through the update routine.
This commit is contained in:
Doyle Thai 2016-07-19 21:19:26 +10:00
parent 5fc58ca643
commit fd94eb5afd
17 changed files with 386 additions and 163 deletions

View File

@ -140,6 +140,7 @@
<ItemGroup> <ItemGroup>
<ClInclude Include="src\include\Dengine\Assets.h" /> <ClInclude Include="src\include\Dengine\Assets.h" />
<ClInclude Include="src\include\Dengine\Debug.h" /> <ClInclude Include="src\include\Dengine\Debug.h" />
<ClInclude Include="src\include\Dengine\MemoryArena.h" />
<ClInclude Include="src\include\Dengine\Platform.h" /> <ClInclude Include="src\include\Dengine\Platform.h" />
<ClInclude Include="src\include\Dengine\AssetManager.h" /> <ClInclude Include="src\include\Dengine\AssetManager.h" />
<ClInclude Include="src\include\Dengine\Common.h" /> <ClInclude Include="src\include\Dengine\Common.h" />

View File

@ -92,5 +92,8 @@
<ClInclude Include="src\include\Dengine\Assets.h"> <ClInclude Include="src\include\Dengine\Assets.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\include\Dengine\MemoryArena.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -95,11 +95,11 @@ Shader *asset_getShader(AssetManager *assetManager, const enum ShaderList type)
return NULL; return NULL;
} }
INTERNAL GLuint createShaderFromPath(const char *const path, GLuint shadertype) INTERNAL GLuint createShaderFromPath(MemoryArena *arena, const char *const path, GLuint shadertype)
{ {
PlatformFileRead file = {0}; PlatformFileRead file = {0};
i32 status = platform_readFileToBuffer(path, &file); i32 status = platform_readFileToBuffer(arena, path, &file);
if (status) if (status)
return status; return status;
@ -118,7 +118,7 @@ INTERNAL GLuint createShaderFromPath(const char *const path, GLuint shadertype)
printf("glCompileShader() failed: %s\n", infoLog); printf("glCompileShader() failed: %s\n", infoLog);
} }
platform_closeFileRead(&file); platform_closeFileRead(arena, &file);
return result; return result;
} }
@ -147,14 +147,14 @@ INTERNAL i32 shaderLoadProgram(Shader *const shader, const GLuint vertexShader,
return 0; return 0;
} }
const i32 asset_loadShaderFiles(AssetManager *assetManager, const i32 asset_loadShaderFiles(AssetManager *assetManager, MemoryArena *arena,
const char *const vertexPath, const char *const vertexPath,
const char *const fragmentPath, const char *const fragmentPath,
const enum ShaderList type) const enum ShaderList type)
{ {
GLuint vertexShader = createShaderFromPath(vertexPath, GL_VERTEX_SHADER); GLuint vertexShader = createShaderFromPath(arena, vertexPath, GL_VERTEX_SHADER);
GLuint fragmentShader = GLuint fragmentShader =
createShaderFromPath(fragmentPath, GL_FRAGMENT_SHADER); createShaderFromPath(arena, fragmentPath, GL_FRAGMENT_SHADER);
Shader shader; Shader shader;
i32 result = shaderLoadProgram(&shader, vertexShader, fragmentShader); i32 result = shaderLoadProgram(&shader, vertexShader, fragmentShader);
@ -173,10 +173,11 @@ typedef struct GlyphBitmap
i32 codepoint; i32 codepoint;
} GlyphBitmap; } GlyphBitmap;
const i32 asset_loadTTFont(AssetManager *assetManager, const char *filePath) const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena,
const char *filePath)
{ {
PlatformFileRead fontFileRead = {0}; PlatformFileRead fontFileRead = {0};
platform_readFileToBuffer(filePath, &fontFileRead); platform_readFileToBuffer(arena, filePath, &fontFileRead);
stbtt_fontinfo fontInfo = {0}; stbtt_fontinfo fontInfo = {0};
stbtt_InitFont(&fontInfo, fontFileRead.buffer, stbtt_InitFont(&fontInfo, fontFileRead.buffer,
@ -188,7 +189,8 @@ const i32 asset_loadTTFont(AssetManager *assetManager, const char *filePath)
v2 codepointRange = font->codepointRange; v2 codepointRange = font->codepointRange;
const i32 numGlyphs = CAST(i32)(codepointRange.y - codepointRange.x); const i32 numGlyphs = CAST(i32)(codepointRange.y - codepointRange.x);
GlyphBitmap *glyphBitmaps = PLATFORM_MEM_ALLOC(numGlyphs, GlyphBitmap); GlyphBitmap *glyphBitmaps =
PLATFORM_MEM_ALLOC(arena, numGlyphs, GlyphBitmap);
v2 largestGlyphDimension = V2(0, 0); v2 largestGlyphDimension = V2(0, 0);
const f32 targetFontHeight = 15.0f; const f32 targetFontHeight = 15.0f;
@ -203,7 +205,7 @@ const i32 asset_loadTTFont(AssetManager *assetManager, const char *filePath)
font->metrics = CAST(FontMetrics){ascent, descent, lineGap}; font->metrics = CAST(FontMetrics){ascent, descent, lineGap};
font->charMetrics = PLATFORM_MEM_ALLOC(numGlyphs, CharMetrics); font->charMetrics = PLATFORM_MEM_ALLOC(arena, numGlyphs, CharMetrics);
/* Use STB_TrueType to generate a series of bitmap characters */ /* Use STB_TrueType to generate a series of bitmap characters */
i32 glyphIndex = 0; i32 glyphIndex = 0;
@ -218,7 +220,7 @@ const i32 asset_loadTTFont(AssetManager *assetManager, const char *filePath)
&height, &xOffset, &yOffset); &height, &xOffset, &yOffset);
u8 *source = monoBitmap; u8 *source = monoBitmap;
u32 *colorBitmap = PLATFORM_MEM_ALLOC(width * height, u32); u32 *colorBitmap = PLATFORM_MEM_ALLOC(arena, width * height, u32);
u32 *dest = colorBitmap; u32 *dest = colorBitmap;
// NOTE(doyle): STB generates 1 byte per pixel bitmaps, we use 4bpp, so // NOTE(doyle): STB generates 1 byte per pixel bitmaps, we use 4bpp, so
@ -294,7 +296,7 @@ const i32 asset_loadTTFont(AssetManager *assetManager, const char *filePath)
#endif #endif
i32 bitmapSize = SQUARED(TARGET_TEXTURE_SIZE) * TARGET_BYTES_PER_PIXEL; i32 bitmapSize = SQUARED(TARGET_TEXTURE_SIZE) * TARGET_BYTES_PER_PIXEL;
u32 *fontBitmap = PLATFORM_MEM_ALLOC(bitmapSize, u32); u32 *fontBitmap = PLATFORM_MEM_ALLOC(arena, bitmapSize, u32);
const i32 pitch = MAX_TEXTURE_SIZE * TARGET_BYTES_PER_PIXEL; const i32 pitch = MAX_TEXTURE_SIZE * TARGET_BYTES_PER_PIXEL;
// Check value to determine when a row of glyphs is completely printed // Check value to determine when a row of glyphs is completely printed
@ -394,7 +396,7 @@ const i32 asset_loadTTFont(AssetManager *assetManager, const char *filePath)
stbi_write_png("out.png", MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE, 4, fontBitmap, stbi_write_png("out.png", MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE, 4, fontBitmap,
MAX_TEXTURE_SIZE * 4); MAX_TEXTURE_SIZE * 4);
#endif #endif
PLATFORM_MEM_FREE(fontBitmap, bitmapSize); PLATFORM_MEM_FREE(arena, fontBitmap, bitmapSize);
font->tex = &assetManager->textures[texlist_font]; font->tex = &assetManager->textures[texlist_font];
font->atlas = &assetManager->texAtlas[texlist_font]; font->atlas = &assetManager->texAtlas[texlist_font];
@ -404,18 +406,18 @@ const i32 asset_loadTTFont(AssetManager *assetManager, const char *filePath)
i32 glyphBitmapSizeInBytes = CAST(i32) glyphBitmaps[i].dimensions.w * i32 glyphBitmapSizeInBytes = CAST(i32) glyphBitmaps[i].dimensions.w *
CAST(i32) glyphBitmaps[i].dimensions.h * CAST(i32) glyphBitmaps[i].dimensions.h *
sizeof(u32); sizeof(u32);
PLATFORM_MEM_FREE(glyphBitmaps[i].pixels, glyphBitmapSizeInBytes); PLATFORM_MEM_FREE(arena, glyphBitmaps[i].pixels, glyphBitmapSizeInBytes);
} }
PLATFORM_MEM_FREE(glyphBitmaps, numGlyphs * sizeof(GlyphBitmap)); PLATFORM_MEM_FREE(arena, glyphBitmaps, numGlyphs * sizeof(GlyphBitmap));
platform_closeFileRead(&fontFileRead); platform_closeFileRead(arena, &fontFileRead);
return 0; return 0;
} }
void asset_addAnimation(AssetManager *assetManager, i32 texId, void asset_addAnimation(AssetManager *assetManager, MemoryArena *arena,
i32 animId, i32 *frameIndex, i32 numFrames, i32 texId, i32 animId, i32 *frameIndex, i32 numFrames,
f32 frameDuration) f32 frameDuration)
{ {
#ifdef DENGINE_DEBUG #ifdef DENGINE_DEBUG
ASSERT(assetManager && frameIndex) ASSERT(assetManager && frameIndex)
@ -425,7 +427,7 @@ void asset_addAnimation(AssetManager *assetManager, i32 texId,
Animation anim = {0}; Animation anim = {0};
anim.atlas = asset_getTextureAtlas(assetManager, texId); anim.atlas = asset_getTextureAtlas(assetManager, texId);
anim.frameIndex = PLATFORM_MEM_ALLOC(numFrames, i32); anim.frameIndex = PLATFORM_MEM_ALLOC(arena, numFrames, i32);
for (i32 i = 0; i < numFrames; i++) anim.frameIndex[i] = frameIndex[i]; for (i32 i = 0; i < numFrames; i++) anim.frameIndex[i] = frameIndex[i];
anim.numFrames = numFrames; anim.numFrames = numFrames;

View File

@ -1,4 +1,5 @@
#include "Dengine\Common.h" #include "Dengine/Common.h"
#include "Dengine/Math.h"
i32 common_strlen(const char *const string) i32 common_strlen(const char *const string)
{ {
@ -19,3 +20,24 @@ i32 common_strcmp(const char *a, const char *b)
return ((*a < *b) ? -1 : 1); return ((*a < *b) ? -1 : 1);
} }
void common_itoa(i32 value, char *buf, i32 bufSize)
{
if (!buf || bufSize == 0) return;
// NOTE(doyle): Max 32bit integer (+-)2147483647
i32 charIndex = 0;
b32 negative = FALSE;
if (value < 0) negative = TRUE;
if (negative) buf[charIndex++] = '-';
i32 val = ABS(value);
while (val != 0 && charIndex < bufSize)
{
i32 rem = val % 10;
buf[charIndex++] = rem + '0';
val /= 10;
}
}

View File

@ -4,16 +4,30 @@
DebugState GLOBAL_debug; DebugState GLOBAL_debug;
void debug_init() void debug_init(MemoryArena *arena, v2 windowSize, Font font)
{ {
GLOBAL_debug.totalMemoryAllocated = 0; GLOBAL_debug.font = font;
GLOBAL_debug.callCount = PLATFORM_MEM_ALLOC(debugcallcount_num, i32); GLOBAL_debug.callCount = PLATFORM_MEM_ALLOC(arena, debugcallcount_num, i32);
GLOBAL_debug.stringLineGap = 1.1f * asset_getVFontSpacing(font.metrics);
/* Init debug string stack */
GLOBAL_debug.numDebugStrings = 0; GLOBAL_debug.numDebugStrings = 0;
GLOBAL_debug.stringUpdateTimer = 0.0f; GLOBAL_debug.stringUpdateTimer = 0.0f;
GLOBAL_debug.stringUpdateRate = 0.15f; GLOBAL_debug.stringUpdateRate = 0.15f;
GLOBAL_debug.stringLineGap = -1; GLOBAL_debug.initialStringP =
V2(0.0f, (windowSize.h - 1.8f * GLOBAL_debug.stringLineGap));
GLOBAL_debug.currStringP = GLOBAL_debug.initialStringP;
/* Init gui console */
i32 maxConsoleStrLen = ARRAY_COUNT(GLOBAL_debug.console[0]);
GLOBAL_debug.consoleIndex = 0;
// TODO(doyle): Font max size not entirely correct? using 1 * font.maxSize.w
// reveals around 4 characters ..
f32 consoleXPos = windowSize.x - (font.maxSize.w * 38);
f32 consoleYPos = windowSize.h - 1.8f * GLOBAL_debug.stringLineGap;
GLOBAL_debug.initialConsoleP = V2(consoleXPos, consoleYPos);
} }
void debug_pushString(char *formatString, void *data, char *dataType) void debug_pushString(char *formatString, void *data, char *dataType)
@ -65,29 +79,22 @@ void debug_pushString(char *formatString, void *data, char *dataType)
ASSERT(INVALID_CODE_PATH); ASSERT(INVALID_CODE_PATH);
} }
GLOBAL_debug.numDebugStrings++; GLOBAL_debug.numDebugStrings++;
ASSERT(GLOBAL_debug.numDebugStrings <
ARRAY_COUNT(GLOBAL_debug.debugStrings[0]));
} }
} }
void debug_stringUpdateAndRender(Renderer *renderer, Font *font, f32 dt) INTERNAL void updateAndRenderDebugStack(Renderer *renderer, MemoryArena *arena,
f32 dt)
{ {
if (GLOBAL_debug.stringLineGap == -1)
{
GLOBAL_debug.stringLineGap =
1.1f * asset_getVFontSpacing(font->metrics);
GLOBAL_debug.initialStringPos =
V2(0.0f,
(renderer->size.y - 1.8f * GLOBAL_debug.stringLineGap));
GLOBAL_debug.stringPos = GLOBAL_debug.initialStringPos;
}
for (i32 i = 0; i < GLOBAL_debug.numDebugStrings; i++) for (i32 i = 0; i < GLOBAL_debug.numDebugStrings; i++)
{ {
f32 rotate = 0; f32 rotate = 0;
v4 color = V4(0, 0, 0, 1); v4 color = V4(0, 0, 0, 1);
renderer_staticString(renderer, font, GLOBAL_debug.debugStrings[i], renderer_staticString(renderer, arena, &GLOBAL_debug.font,
GLOBAL_debug.stringPos, rotate, color); GLOBAL_debug.debugStrings[i],
GLOBAL_debug.stringPos.y -= GLOBAL_debug.currStringP, rotate, color);
(0.9f * GLOBAL_debug.stringLineGap); GLOBAL_debug.currStringP.y -= (0.9f * GLOBAL_debug.stringLineGap);
} }
if (GLOBAL_debug.stringUpdateTimer <= 0) if (GLOBAL_debug.stringUpdateTimer <= 0)
@ -104,7 +111,23 @@ void debug_stringUpdateAndRender(Renderer *renderer, Font *font, f32 dt)
} }
} }
GLOBAL_debug.stringPos = GLOBAL_debug.initialStringPos; GLOBAL_debug.currStringP = GLOBAL_debug.initialStringP;
}
INTERNAL void renderConsole(Renderer *renderer, MemoryArena *arena)
{
i32 maxConsoleLines = ARRAY_COUNT(GLOBAL_debug.console);
v2 consoleStrP = GLOBAL_debug.initialConsoleP;
for (i32 i = 0; i < maxConsoleLines; i++)
{
f32 rotate = 0;
v4 color = V4(0, 0, 0, 1);
renderer_staticString(renderer, arena, &GLOBAL_debug.font,
GLOBAL_debug.console[i], consoleStrP,
rotate, color);
consoleStrP.y -= (0.9f * GLOBAL_debug.stringLineGap);
}
} }
void debug_drawUi(GameState *state, f32 dt) void debug_drawUi(GameState *state, f32 dt)
@ -113,7 +136,6 @@ void debug_drawUi(GameState *state, f32 dt)
Renderer *renderer = &state->renderer; Renderer *renderer = &state->renderer;
World *const world = &state->world[state->currWorldIndex]; World *const world = &state->world[state->currWorldIndex];
Entity *hero = &world->entities[world->heroIndex]; Entity *hero = &world->entities[world->heroIndex];
Font *font = &assetManager->font;
// TODO(doyle): Dumb copy function from game so we don't expose api // TODO(doyle): Dumb copy function from game so we don't expose api
v4 cameraBounds = math_getRect(world->cameraPos, renderer->size); v4 cameraBounds = math_getRect(world->cameraPos, renderer->size);
@ -140,6 +162,7 @@ void debug_drawUi(GameState *state, f32 dt)
V2(distance, 5.0f), 0, renderTex, V4(1, 0, 0, 0.25f)); V2(distance, 5.0f), 0, renderTex, V4(1, 0, 0, 0.25f));
#endif #endif
Font *font = &GLOBAL_debug.font;
if (world->numEntitiesInBattle > 0) if (world->numEntitiesInBattle > 0)
{ {
v4 color = V4(1.0f, 0, 0, 1); v4 color = V4(1.0f, 0, 0, 1);
@ -148,8 +171,8 @@ void debug_drawUi(GameState *state, f32 dt)
CAST(f32)(font->maxSize.w * common_strlen(battleStr)); CAST(f32)(font->maxSize.w * common_strlen(battleStr));
v2 strPos = V2((renderer->size.w * 0.5f) - (strLenInPixels * 0.5f), v2 strPos = V2((renderer->size.w * 0.5f) - (strLenInPixels * 0.5f),
renderer->size.h - 300.0f); renderer->size.h - 300.0f);
renderer_staticString(&state->renderer, font, battleStr, strPos, 0, renderer_staticString(&state->renderer, &state->arena, font, battleStr,
color); strPos, 0, color);
} }
for (i32 i = 0; i < world->maxEntities; i++) for (i32 i = 0; i < world->maxEntities; i++)
@ -185,8 +208,8 @@ void debug_drawUi(GameState *state, f32 dt)
i32 indexOfLowerAInMetrics = 'a' - CAST(i32) font->codepointRange.x; i32 indexOfLowerAInMetrics = 'a' - CAST(i32) font->codepointRange.x;
strPos.y += font->charMetrics[indexOfLowerAInMetrics].offset.y; strPos.y += font->charMetrics[indexOfLowerAInMetrics].offset.y;
renderer_string(&state->renderer, cameraBounds, font, debugString, renderer_string(&state->renderer, &state->arena, cameraBounds, font,
strPos, 0, color); debugString, strPos, 0, color);
f32 stringLineGap = 1.1f * asset_getVFontSpacing(font->metrics); f32 stringLineGap = 1.1f * asset_getVFontSpacing(font->metrics);
strPos.y -= GLOBAL_debug.stringLineGap; strPos.y -= GLOBAL_debug.stringLineGap;
@ -194,15 +217,15 @@ void debug_drawUi(GameState *state, f32 dt)
char entityPosStr[128]; char entityPosStr[128];
snprintf(entityPosStr, ARRAY_COUNT(entityPosStr), "%06.2f, %06.2f", snprintf(entityPosStr, ARRAY_COUNT(entityPosStr), "%06.2f, %06.2f",
entity->pos.x, entity->pos.y); entity->pos.x, entity->pos.y);
renderer_string(&state->renderer, cameraBounds, font, entityPosStr, renderer_string(&state->renderer, &state->arena, cameraBounds, font,
strPos, 0, color); entityPosStr, strPos, 0, color);
strPos.y -= GLOBAL_debug.stringLineGap; strPos.y -= GLOBAL_debug.stringLineGap;
char entityIDStr[32]; char entityIDStr[32];
snprintf(entityIDStr, ARRAY_COUNT(entityIDStr), "ID: %4d/%d", entity->id, snprintf(entityIDStr, ARRAY_COUNT(entityIDStr), "ID: %4d/%d", entity->id,
world->uniqueIdAccumulator-1); world->uniqueIdAccumulator-1);
renderer_string(&state->renderer, cameraBounds, font, entityIDStr, renderer_string(&state->renderer, &state->arena, cameraBounds, font,
strPos, 0, color); entityIDStr, strPos, 0, color);
if (entity->stats) if (entity->stats)
{ {
@ -210,20 +233,20 @@ void debug_drawUi(GameState *state, f32 dt)
char entityHealth[32]; char entityHealth[32];
snprintf(entityHealth, ARRAY_COUNT(entityHealth), "HP: %3.0f/%3.0f", snprintf(entityHealth, ARRAY_COUNT(entityHealth), "HP: %3.0f/%3.0f",
entity->stats->health, entity->stats->maxHealth); entity->stats->health, entity->stats->maxHealth);
renderer_string(&state->renderer, cameraBounds, font, renderer_string(&state->renderer, &state->arena, cameraBounds,
entityHealth, strPos, 0, color); font, entityHealth, strPos, 0, color);
strPos.y -= GLOBAL_debug.stringLineGap; strPos.y -= GLOBAL_debug.stringLineGap;
char entityTimer[32]; char entityTimer[32];
snprintf(entityTimer, ARRAY_COUNT(entityTimer), "ATB: %3.0f/%3.0f", snprintf(entityTimer, ARRAY_COUNT(entityTimer), "ATB: %3.0f/%3.0f",
entity->stats->actionTimer, entity->stats->actionRate); entity->stats->actionTimer, entity->stats->actionRate);
renderer_string(&state->renderer, cameraBounds, font, renderer_string(&state->renderer, &state->arena, cameraBounds,
entityTimer, strPos, 0, color); font, entityTimer, strPos, 0, color);
} }
strPos.y -= GLOBAL_debug.stringLineGap; strPos.y -= GLOBAL_debug.stringLineGap;
char *entityStateStr = debug_entitystate_string(entity->state); char *entityStateStr = debug_entitystate_string(entity->state);
renderer_string(&state->renderer, cameraBounds, font, renderer_string(&state->renderer, &state->arena, cameraBounds, font,
entityStateStr, strPos, 0, color); entityStateStr, strPos, 0, color);
} }
} }
@ -243,7 +266,8 @@ void debug_drawUi(GameState *state, f32 dt)
DEBUG_PUSH_VAR("FreeEntityIndex: %d", world->freeEntityIndex, "i32"); DEBUG_PUSH_VAR("FreeEntityIndex: %d", world->freeEntityIndex, "i32");
DEBUG_PUSH_VAR("glDrawArray Calls: %d", DEBUG_PUSH_VAR("glDrawArray Calls: %d",
GLOBAL_debug.callCount[debugcallcount_drawArrays], "i32"); GLOBAL_debug.callCount[debugcallcount_drawArrays], "i32");
i32 debug_kbAllocated = GLOBAL_debug.totalMemoryAllocated / 1024;
i32 debug_kbAllocated = state->arena.bytesAllocated / 1024;
DEBUG_PUSH_VAR("TotalMemoryAllocated: %dkb", debug_kbAllocated, "i32"); DEBUG_PUSH_VAR("TotalMemoryAllocated: %dkb", debug_kbAllocated, "i32");
DEBUG_PUSH_STRING("== EntityIDs in Battle List == "); DEBUG_PUSH_STRING("== EntityIDs in Battle List == ");
@ -262,6 +286,56 @@ void debug_drawUi(GameState *state, f32 dt)
DEBUG_PUSH_STRING("-none-"); DEBUG_PUSH_STRING("-none-");
} }
debug_stringUpdateAndRender(&state->renderer, font, dt); updateAndRenderDebugStack(&state->renderer, &state->arena, dt);
renderConsole(&state->renderer, &state->arena);
debug_clearCallCounter(); debug_clearCallCounter();
} }
void debug_consoleLog(char *string, char *file, int lineNum)
{
i32 maxConsoleStrLen = ARRAY_COUNT(GLOBAL_debug.console[0]);
i32 strIndex = 0;
i32 fileStrLen = common_strlen(file);
for (i32 count = 0; strIndex < maxConsoleStrLen; strIndex++, count++)
{
if (fileStrLen <= count) break;
GLOBAL_debug.console[GLOBAL_debug.consoleIndex][strIndex] = file[count];
}
if (strIndex < maxConsoleStrLen)
GLOBAL_debug.console[GLOBAL_debug.consoleIndex][strIndex++] = ':';
char line[12] = {0};
common_itoa(lineNum, line, ARRAY_COUNT(line));
i32 lineStrLen = common_strlen(line);
for (i32 count = 0; strIndex < maxConsoleStrLen; strIndex++, count++)
{
if (lineStrLen <= count) break;
GLOBAL_debug.console[GLOBAL_debug.consoleIndex][strIndex] = line[count];
}
if (strIndex < maxConsoleStrLen)
GLOBAL_debug.console[GLOBAL_debug.consoleIndex][strIndex++] = ':';
i32 stringStrLen = common_strlen(string);
for (i32 count = 0; strIndex < maxConsoleStrLen; strIndex++, count++)
{
if (stringStrLen <= count) break;
GLOBAL_debug.console[GLOBAL_debug.consoleIndex][strIndex] = string[count];
}
if (strIndex >= maxConsoleStrLen)
{
GLOBAL_debug.console[GLOBAL_debug.consoleIndex][maxConsoleStrLen-4] = '.';
GLOBAL_debug.console[GLOBAL_debug.consoleIndex][maxConsoleStrLen-3] = '.';
GLOBAL_debug.console[GLOBAL_debug.consoleIndex][maxConsoleStrLen-2] = '.';
GLOBAL_debug.console[GLOBAL_debug.consoleIndex][maxConsoleStrLen-1] = 0;
}
i32 maxConsoleLines = ARRAY_COUNT(GLOBAL_debug.console);
GLOBAL_debug.consoleIndex++;
if (GLOBAL_debug.consoleIndex >= maxConsoleLines)
GLOBAL_debug.consoleIndex = 0;
}

View File

@ -5,32 +5,32 @@
#include "Dengine/Platform.h" #include "Dengine/Platform.h"
#include "Dengine/Debug.h" #include "Dengine/Debug.h"
void platform_memoryFree(void *data, i32 numBytes) void platform_memoryFree(MemoryArena *arena, void *data, i32 numBytes)
{ {
if (data) free(data); if (data) free(data);
#ifdef DENGINE_DEBUG #ifdef DENGINE_DEBUG
GLOBAL_debug.totalMemoryAllocated -= numBytes; arena->bytesAllocated -= numBytes;
#endif #endif
} }
void *platform_memoryAlloc(i32 numBytes) void *platform_memoryAlloc(MemoryArena *arena, i32 numBytes)
{ {
void *result = calloc(1, numBytes); void *result = calloc(1, numBytes);
#ifdef DENGINE_DEBUG #ifdef DENGINE_DEBUG
if (result) if (result)
GLOBAL_debug.totalMemoryAllocated += numBytes; arena->bytesAllocated += numBytes;
#endif #endif
return result; return result;
} }
void platform_closeFileRead(PlatformFileRead *file) void platform_closeFileRead(MemoryArena *arena, PlatformFileRead *file)
{ {
PLATFORM_MEM_FREE(file->buffer, file->size); PLATFORM_MEM_FREE(arena, file->buffer, file->size);
} }
i32 platform_readFileToBuffer(const char *const filePath, i32 platform_readFileToBuffer(MemoryArena *arena, const char *const filePath,
PlatformFileRead *file) PlatformFileRead *file)
{ {
HANDLE fileHandle = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, HANDLE fileHandle = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ,
@ -52,7 +52,7 @@ i32 platform_readFileToBuffer(const char *const filePath,
} }
// TODO(doyle): Warning we assume files less than 4GB // TODO(doyle): Warning we assume files less than 4GB
file->buffer = PLATFORM_MEM_ALLOC(fileSize.LowPart, char); file->buffer = PLATFORM_MEM_ALLOC(arena, fileSize.LowPart, char);
file->size = fileSize.LowPart; file->size = fileSize.LowPart;
DWORD numBytesRead = 0; DWORD numBytesRead = 0;
@ -63,7 +63,7 @@ i32 platform_readFileToBuffer(const char *const filePath,
{ {
printf("ReadFile() failed: %d error number\n", printf("ReadFile() failed: %d error number\n",
status); status);
PLATFORM_MEM_FREE(file->buffer, file->size); PLATFORM_MEM_FREE(arena, file->buffer, file->size);
return status; return status;
} }
else if (numBytesRead != file->size) else if (numBytesRead != file->size)
@ -71,7 +71,7 @@ i32 platform_readFileToBuffer(const char *const filePath,
printf( printf(
"ReadFile() failed: Number of bytes read doesn't match file " "ReadFile() failed: Number of bytes read doesn't match file "
"size\n"); "size\n");
PLATFORM_MEM_FREE(file->buffer, file->size); PLATFORM_MEM_FREE(arena, file->buffer, file->size);
return -1; return -1;
} }

View File

@ -152,9 +152,9 @@ void renderer_rect(Renderer *const renderer, v4 cameraBounds, v2 pos, v2 size,
renderTex.tex); renderTex.tex);
} }
void renderer_string(Renderer *const renderer, v4 cameraBounds, void renderer_string(Renderer *const renderer, MemoryArena *arena,
Font *const font, const char *const string, v2 pos, v4 cameraBounds, Font *const font,
f32 rotate, v4 color) const char *const string, v2 pos, f32 rotate, v4 color)
{ {
i32 strLen = common_strlen(string); i32 strLen = common_strlen(string);
// TODO(doyle): Scale, not too important .. but rudimentary infrastructure // TODO(doyle): Scale, not too important .. but rudimentary infrastructure
@ -172,7 +172,7 @@ void renderer_string(Renderer *const renderer, v4 cameraBounds,
(leftAlignedP.y < cameraBounds.y && rightAlignedP.y >= cameraBounds.w)) (leftAlignedP.y < cameraBounds.y && rightAlignedP.y >= cameraBounds.w))
{ {
i32 quadIndex = 0; i32 quadIndex = 0;
RenderQuad *stringQuads = PLATFORM_MEM_ALLOC(strLen, RenderQuad); RenderQuad *stringQuads = PLATFORM_MEM_ALLOC(arena, strLen, RenderQuad);
v2 offsetFromCamOrigin = V2(cameraBounds.x, cameraBounds.w); v2 offsetFromCamOrigin = V2(cameraBounds.x, cameraBounds.w);
v2 entityRelativeToCamera = v2_sub(pos, offsetFromCamOrigin); v2 entityRelativeToCamera = v2_sub(pos, offsetFromCamOrigin);
@ -210,7 +210,7 @@ void renderer_string(Renderer *const renderer, v4 cameraBounds,
updateBufferObject(renderer, stringQuads, quadIndex); updateBufferObject(renderer, stringQuads, quadIndex);
renderObject(renderer, V2(0.0f, 0.0f), renderer->size, rotate, color, renderObject(renderer, V2(0.0f, 0.0f), renderer->size, rotate, color,
font->tex); font->tex);
PLATFORM_MEM_FREE(stringQuads, strLen * sizeof(RenderQuad)); PLATFORM_MEM_FREE(arena, stringQuads, strLen * sizeof(RenderQuad));
} }
} }

View File

@ -10,8 +10,9 @@ enum State
state_win, state_win,
}; };
INTERNAL Entity *addEntity(World *world, v2 pos, v2 size, enum EntityType type, INTERNAL Entity *addEntity(MemoryArena *arena, World *world, v2 pos, v2 size,
enum Direction direction, Texture *tex, b32 collides) enum EntityType type, enum Direction direction,
Texture *tex, b32 collides)
{ {
#ifdef DENGINE_DEBUG #ifdef DENGINE_DEBUG
@ -35,7 +36,7 @@ INTERNAL Entity *addEntity(World *world, v2 pos, v2 size, enum EntityType type,
case entitytype_hero: case entitytype_hero:
case entitytype_mob: case entitytype_mob:
{ {
entity.stats = PLATFORM_MEM_ALLOC(1, EntityStats); entity.stats = PLATFORM_MEM_ALLOC(arena, 1, EntityStats);
entity.stats->maxHealth = 100; entity.stats->maxHealth = 100;
entity.stats->health = entity.stats->maxHealth; entity.stats->health = entity.stats->maxHealth;
entity.stats->actionRate = 100; entity.stats->actionRate = 100;
@ -107,6 +108,7 @@ INTERNAL void addAnim(AssetManager *assetManager, i32 animId, Entity *entity)
void worldTraveller_gameInit(GameState *state, v2 windowSize) void worldTraveller_gameInit(GameState *state, v2 windowSize)
{ {
AssetManager *assetManager = &state->assetManager; AssetManager *assetManager = &state->assetManager;
MemoryArena *arena = &state->arena;
/* Initialise assets */ /* Initialise assets */
/* Create empty 1x1 4bpp black texture */ /* Create empty 1x1 4bpp black texture */
u32 bitmap = (0xFF << 24) | (0xFF << 16) | (0xFF << 8) | (0xFF << 0); u32 bitmap = (0xFF << 24) | (0xFF << 16) | (0xFF << 8) | (0xFF << 0);
@ -142,29 +144,33 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize)
texOrigin.y - atlasTileSize); texOrigin.y - atlasTileSize);
/* Load shaders */ /* Load shaders */
asset_loadShaderFiles(assetManager, "data/shaders/sprite.vert.glsl", asset_loadShaderFiles(assetManager, arena, "data/shaders/sprite.vert.glsl",
"data/shaders/sprite.frag.glsl", "data/shaders/sprite.frag.glsl",
shaderlist_sprite); shaderlist_sprite);
asset_loadTTFont(assetManager, "C:/Windows/Fonts/Arialbd.ttf"); asset_loadTTFont(assetManager, arena, "C:/Windows/Fonts/Arialbd.ttf");
glCheckError(); glCheckError();
#ifdef DENGINE_DEBUG
DEBUG_LOG("Assets loaded");
#endif
/* Load animations */ /* Load animations */
f32 duration = 1.0f; f32 duration = 1.0f;
i32 numRects = 1; i32 numRects = 1;
v4 *animRects = PLATFORM_MEM_ALLOC(numRects, v4); v4 *animRects = PLATFORM_MEM_ALLOC(arena, numRects, v4);
i32 terrainAnimAtlasIndexes[1] = {terrainrects_ground}; i32 terrainAnimAtlasIndexes[1] = {terrainrects_ground};
// TODO(doyle): Optimise animation storage, we waste space having 1:1 with // TODO(doyle): Optimise animation storage, we waste space having 1:1 with
// animlist when some textures don't have certain animations // animlist when some textures don't have certain animations
asset_addAnimation(assetManager, texlist_terrain, animlist_terrain, asset_addAnimation(assetManager, arena, texlist_terrain, animlist_terrain,
terrainAnimAtlasIndexes, numRects, duration); terrainAnimAtlasIndexes, numRects, duration);
// Idle animation // Idle animation
duration = 1.0f; duration = 1.0f;
numRects = 1; numRects = 1;
i32 idleAnimAtlasIndexes[1] = {herorects_idle}; i32 idleAnimAtlasIndexes[1] = {herorects_idle};
asset_addAnimation(assetManager, texlist_hero, animlist_hero_idle, asset_addAnimation(assetManager, arena, texlist_hero, animlist_hero_idle,
idleAnimAtlasIndexes, numRects, duration); idleAnimAtlasIndexes, numRects, duration);
// Walk animation // Walk animation
@ -172,21 +178,21 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize)
numRects = 3; numRects = 3;
i32 walkAnimAtlasIndexes[3] = {herorects_walkA, herorects_idle, i32 walkAnimAtlasIndexes[3] = {herorects_walkA, herorects_idle,
herorects_walkB}; herorects_walkB};
asset_addAnimation(assetManager, texlist_hero, animlist_hero_walk, asset_addAnimation(assetManager, arena, texlist_hero, animlist_hero_walk,
walkAnimAtlasIndexes, numRects, duration); walkAnimAtlasIndexes, numRects, duration);
// Wave animation // Wave animation
duration = 0.30f; duration = 0.30f;
numRects = 2; numRects = 2;
i32 waveAnimAtlasIndexes[2] = {herorects_waveA, herorects_waveB}; i32 waveAnimAtlasIndexes[2] = {herorects_waveA, herorects_waveB};
asset_addAnimation(assetManager, texlist_hero, animlist_hero_wave, asset_addAnimation(assetManager, arena, texlist_hero, animlist_hero_wave,
waveAnimAtlasIndexes, numRects, duration); waveAnimAtlasIndexes, numRects, duration);
// Battle Stance animation // Battle Stance animation
duration = 1.0f; duration = 1.0f;
numRects = 1; numRects = 1;
i32 battleStanceAnimAtlasIndexes[1] = {herorects_battlePose}; i32 battleStanceAnimAtlasIndexes[1] = {herorects_battlePose};
asset_addAnimation(assetManager, texlist_hero, animlist_hero_battlePose, asset_addAnimation(assetManager, arena, texlist_hero, animlist_hero_battlePose,
battleStanceAnimAtlasIndexes, numRects, duration); battleStanceAnimAtlasIndexes, numRects, duration);
// Battle tackle animation // Battle tackle animation
@ -194,8 +200,11 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize)
numRects = 3; numRects = 3;
i32 tackleAnimAtlasIndexes[3] = {herorects_castA, herorects_castB, i32 tackleAnimAtlasIndexes[3] = {herorects_castA, herorects_castB,
herorects_castC}; herorects_castC};
asset_addAnimation(assetManager, texlist_hero, animlist_hero_tackle, asset_addAnimation(assetManager, arena, texlist_hero, animlist_hero_tackle,
tackleAnimAtlasIndexes, numRects, duration); tackleAnimAtlasIndexes, numRects, duration);
#ifdef DENGINE_DEBUG
DEBUG_LOG("Animations created");
#endif
state->state = state_active; state->state = state_active;
@ -204,6 +213,9 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize)
/* Init renderer */ /* Init renderer */
rendererInit(state, windowSize); rendererInit(state, windowSize);
#ifdef DENGINE_DEBUG
DEBUG_LOG("Renderer initialised");
#endif
/* Init world */ /* Init world */
const i32 targetWorldWidth = 100 * METERS_TO_PIXEL; const i32 targetWorldWidth = 100 * METERS_TO_PIXEL;
@ -215,8 +227,9 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize)
{ {
World *const world = &state->world[i]; World *const world = &state->world[i];
world->maxEntities = 16384; world->maxEntities = 16384;
world->entities = PLATFORM_MEM_ALLOC(world->maxEntities, Entity); world->entities = PLATFORM_MEM_ALLOC(arena, world->maxEntities, Entity);
world->entityIdInBattle = PLATFORM_MEM_ALLOC(world->maxEntities, i32); world->entityIdInBattle =
PLATFORM_MEM_ALLOC(arena, world->maxEntities, i32);
world->numEntitiesInBattle = 0; world->numEntitiesInBattle = 0;
world->texType = texlist_terrain; world->texType = texlist_terrain;
world->bounds = world->bounds =
@ -243,8 +256,8 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize)
enum Direction dir = direction_null; enum Direction dir = direction_null;
Texture *tex = asset_getTexture(assetManager, world->texType); Texture *tex = asset_getTexture(assetManager, world->texType);
b32 collides = FALSE; b32 collides = FALSE;
Entity *tile = Entity *tile = addEntity(arena, world, pos, size, type, dir,
addEntity(world, pos, size, type, dir, tex, collides); tex, collides);
addAnim(assetManager, animlist_terrain, tile); addAnim(assetManager, animlist_terrain, tile);
tile->currAnimId = animlist_terrain; tile->currAnimId = animlist_terrain;
@ -265,7 +278,7 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize)
enum Direction dir = direction_east; enum Direction dir = direction_east;
Texture *tex = asset_getTexture(assetManager, texlist_hero); Texture *tex = asset_getTexture(assetManager, texlist_hero);
b32 collides = TRUE; b32 collides = TRUE;
Entity *hero = addEntity(world, pos, size, type, dir, tex, collides); Entity *hero = addEntity(arena, world, pos, size, type, dir, tex, collides);
/* Populate hero animation references */ /* Populate hero animation references */
addAnim(assetManager, animlist_hero_idle, hero); addAnim(assetManager, animlist_hero_idle, hero);
@ -282,7 +295,7 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize)
dir = direction_null; dir = direction_null;
tex = hero->tex; tex = hero->tex;
collides = FALSE; collides = FALSE;
Entity *npc = addEntity(world, pos, size, type, dir, tex, collides); Entity *npc = addEntity(arena, world, pos, size, type, dir, tex, collides);
/* Populate npc animation references */ /* Populate npc animation references */
addAnim(assetManager, animlist_hero_wave, npc); addAnim(assetManager, animlist_hero_wave, npc);
@ -296,7 +309,7 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize)
dir = direction_west; dir = direction_west;
tex = hero->tex; tex = hero->tex;
collides = TRUE; collides = TRUE;
Entity *mob = addEntity(world, pos, size, type, dir, tex, collides); Entity *mob = addEntity(arena, world, pos, size, type, dir, tex, collides);
/* Populate mob animation references */ /* Populate mob animation references */
addAnim(assetManager, animlist_hero_idle, mob); addAnim(assetManager, animlist_hero_idle, mob);
@ -304,6 +317,11 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize)
addAnim(assetManager, animlist_hero_battlePose, mob); addAnim(assetManager, animlist_hero_battlePose, mob);
addAnim(assetManager, animlist_hero_tackle, mob); addAnim(assetManager, animlist_hero_tackle, mob);
hero->currAnimId = animlist_hero_idle; hero->currAnimId = animlist_hero_idle;
#ifdef DENGINE_DEBUG
DEBUG_LOG("World populated");
#endif
} }
INTERNAL inline void setActiveEntityAnim(Entity *entity, INTERNAL inline void setActiveEntityAnim(Entity *entity,
@ -519,8 +537,14 @@ INTERNAL void updateEntityAnim(Entity *entity, f32 dt)
} }
} }
#define ENTITY_NULL_ID -1
INTERNAL void beginAttack(Entity *attacker) INTERNAL void beginAttack(Entity *attacker)
{ {
#ifdef DENGINE_DEBUG
ASSERT(attacker->stats->entityIdToAttack != ENTITY_NULL_ID);
#endif
attacker->state = entitystate_attack; attacker->state = entitystate_attack;
switch (attacker->stats->queuedAttack) switch (attacker->stats->queuedAttack)
{ {
@ -549,6 +573,10 @@ INTERNAL void beginAttack(Entity *attacker)
// etc // etc
INTERNAL void endAttack(World *world, Entity *attacker) INTERNAL void endAttack(World *world, Entity *attacker)
{ {
#ifdef DENGINE_DEBUG
ASSERT(attacker->stats->entityIdToAttack != ENTITY_NULL_ID);
#endif
switch (attacker->stats->queuedAttack) switch (attacker->stats->queuedAttack)
{ {
case entityattack_tackle: case entityattack_tackle:
@ -602,20 +630,69 @@ INTERNAL v4 createCameraBounds(World *world, v2 size)
#define ENTITY_IN_BATTLE TRUE #define ENTITY_IN_BATTLE TRUE
#define ENTITY_NOT_IN_BATTLE FALSE #define ENTITY_NOT_IN_BATTLE FALSE
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[world->heroIndex];
result = hero.id;
return result;
}
/* Attacker is hero */
Entity hero = attacker;
for (i32 i = 0; i < world->maxEntities; 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, INTERNAL inline void updateWorldBattleEntities(World *world, Entity *entity,
b32 isInBattle) b32 isInBattle)
{ {
#ifdef DENGINE_DEBUG
ASSERT(isInBattle == ENTITY_IN_BATTLE ||
isInBattle == ENTITY_NOT_IN_BATTLE);
ASSERT(world && entity);
#endif
world->entityIdInBattle[entity->id] = isInBattle; world->entityIdInBattle[entity->id] = isInBattle;
if (isInBattle) if (isInBattle)
world->numEntitiesInBattle++; world->numEntitiesInBattle++;
else else
world->numEntitiesInBattle--; world->numEntitiesInBattle--;
#ifdef DENGINE_DEBUG
ASSERT(world->numEntitiesInBattle >= 0);
#endif
} }
INTERNAL void entityStateSwitch(World *world, Entity *entity, INTERNAL void entityStateSwitch(World *world, Entity *entity,
enum EntityState newState) enum EntityState newState)
{ {
#ifdef DENGINE_DEBUG
ASSERT(world && entity)
ASSERT(entity->type == entitytype_mob || entity->type == entitytype_hero)
#endif
if (entity->state == newState) return; if (entity->state == newState) return;
switch(entity->state) switch(entity->state)
@ -625,11 +702,16 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity,
{ {
case entitystate_battle: case entitystate_battle:
updateWorldBattleEntities(world, entity, ENTITY_IN_BATTLE); updateWorldBattleEntities(world, entity, ENTITY_IN_BATTLE);
entity->stats->entityIdToAttack =
findBestEntityToAttack(world, *entity);
break;
case entitystate_attack: case entitystate_attack:
case entitystate_dead: case entitystate_dead:
break;
default: default:
#ifdef DENGINE_DEBUG
ASSERT(INVALID_CODE_PATH); ASSERT(INVALID_CODE_PATH);
#endif
} }
break; break;
case entitystate_battle: case entitystate_battle:
@ -637,36 +719,52 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity,
{ {
case entitystate_idle: case entitystate_idle:
updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE); updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE);
entity->stats->actionTimer = entity->stats->actionRate;
entity->stats->queuedAttack = entityattack_invalid;
setActiveEntityAnim(entity, animlist_hero_idle); setActiveEntityAnim(entity, animlist_hero_idle);
entity->stats->actionTimer = entity->stats->actionRate;
entity->stats->queuedAttack = entityattack_invalid;
entity->stats->entityIdToAttack = ENTITY_NULL_ID;
break; break;
case entitystate_attack: case entitystate_attack:
case entitystate_dead: case entitystate_dead:
break; return;
default: default:
#ifdef DENGINE_DEBUG
ASSERT(INVALID_CODE_PATH); ASSERT(INVALID_CODE_PATH);
#endif
} }
break;
case entitystate_attack: case entitystate_attack:
switch (newState) switch (newState)
{ {
case entitystate_idle:
case entitystate_battle: case entitystate_battle:
case entitystate_idle:
return;
case entitystate_dead: case entitystate_dead:
break;
default: default:
#ifdef DENGINE_DEBUG
ASSERT(INVALID_CODE_PATH); ASSERT(INVALID_CODE_PATH);
#endif
} }
break;
case entitystate_dead: case entitystate_dead:
switch (newState) switch (newState)
{ {
case entitystate_idle: case entitystate_idle:
case entitystate_battle: case entitystate_battle:
case entitystate_attack: case entitystate_attack:
break;
default: default:
#ifdef DENGINE_DEBUG
ASSERT(INVALID_CODE_PATH); ASSERT(INVALID_CODE_PATH);
#endif
} }
break;
default:
#ifdef DENGINE_DEBUG
ASSERT(INVALID_CODE_PATH);
#endif
} }
entity->state = newState; entity->state = newState;
@ -674,11 +772,10 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity,
INTERNAL void updateEntityAndRender(Renderer *renderer, World *world, f32 dt) INTERNAL void updateEntityAndRender(Renderer *renderer, World *world, f32 dt)
{ {
Entity *hero = &world->entities[world->heroIndex];
for (i32 i = 0; i < world->freeEntityIndex; i++) for (i32 i = 0; i < world->freeEntityIndex; i++)
{ {
Entity *const entity = &world->entities[i]; Entity *const entity = &world->entities[i];
Entity *hero = &world->entities[world->heroIndex];
switch(entity->type) switch(entity->type)
{ {
case entitytype_mob: case entitytype_mob:
@ -696,7 +793,7 @@ INTERNAL void updateEntityAndRender(Renderer *renderer, World *world, f32 dt)
entityStateSwitch(world, entity, newState); entityStateSwitch(world, entity, newState);
} }
// NOTE(doyle): Allow fall through to entitytype_hero here // NOTE(doyle): Let entitytype_mob fall through to entitytype_hero here
case entitytype_hero: case entitytype_hero:
{ {
if (entity->state == entitystate_battle || if (entity->state == entitystate_battle ||
@ -728,8 +825,11 @@ INTERNAL void updateEntityAndRender(Renderer *renderer, World *world, f32 dt)
} }
else else
{ {
#ifdef DENGINE_DEBUG
ASSERT(INVALID_CODE_PATH);
#endif
// TODO(doyle): Generalise for all entities // TODO(doyle): Generalise for all entities
hero->stats->entityIdToAttack = -1; hero->stats->entityIdToAttack = ENTITY_NULL_ID;
hero->state = entitystate_idle; hero->state = entitystate_idle;
entity->state = entitystate_dead; entity->state = entitystate_dead;
} }
@ -740,38 +840,37 @@ INTERNAL void updateEntityAndRender(Renderer *renderer, World *world, f32 dt)
break; break;
} }
if (world->numEntitiesInBattle > 0)
{
if (hero->state == entitystate_idle)
{
hero->state = entitystate_battle;
world->entityIdInBattle[hero->id] = TRUE;
}
if (hero->stats->entityIdToAttack == -1)
hero->stats->entityIdToAttack = i;
}
else
{
if (hero->state == entitystate_battle)
{
hero->state = entitystate_idle;
world->entityIdInBattle[hero->id] = FALSE;
setActiveEntityAnim(hero, animlist_hero_idle);
}
hero->stats->entityIdToAttack = -1;
hero->stats->actionTimer = hero->stats->actionRate;
hero->stats->busyDuration = 0;
}
updateEntityAnim(entity, dt); updateEntityAnim(entity, dt);
/* Calculate region to render */ /* Calculate region to render */
v4 cameraBounds = createCameraBounds(world, renderer->size); v4 cameraBounds = createCameraBounds(world, renderer->size);
renderer_entity(renderer, cameraBounds, entity, 0, V4(1, 1, 1, 1)); renderer_entity(renderer, cameraBounds, entity, 0, V4(1, 1, 1, 1));
} }
if (world->numEntitiesInBattle > 0)
{
// NOTE(doyle): If battle entities is 1 then only the hero is left
if (hero->state == entitystate_battle &&
world->numEntitiesInBattle == 1)
entityStateSwitch(world, hero, entitystate_idle);
else
entityStateSwitch(world, hero, entitystate_battle);
}
else
{
if (hero->state == entitystate_battle)
{
hero->state = entitystate_idle;
world->entityIdInBattle[hero->id] = FALSE;
setActiveEntityAnim(hero, animlist_hero_idle);
}
hero->stats->entityIdToAttack = -1;
hero->stats->actionTimer = hero->stats->actionRate;
hero->stats->busyDuration = 0;
}
} }
LOCAL_PERSIST b32 count = 0;
void worldTraveller_gameUpdateAndRender(GameState *state, const f32 dt) void worldTraveller_gameUpdateAndRender(GameState *state, const f32 dt)
{ {
/* Update */ /* Update */
@ -802,8 +901,8 @@ void worldTraveller_gameUpdateAndRender(GameState *state, const f32 dt)
f32 strLenInPixels = f32 strLenInPixels =
CAST(f32)(font->maxSize.w * common_strlen(heroAvatarStr)); CAST(f32)(font->maxSize.w * common_strlen(heroAvatarStr));
v2 strPos = V2(heroAvatarP.x, heroAvatarP.y - (0.5f * heroAvatarSize.h)); v2 strPos = V2(heroAvatarP.x, heroAvatarP.y - (0.5f * heroAvatarSize.h));
renderer_staticString(&state->renderer, font, heroAvatarStr, strPos, 0, renderer_staticString(&state->renderer, &state->arena, font, heroAvatarStr,
V4(0, 0, 1, 1)); strPos, 0, V4(0, 0, 1, 1));
#ifdef DENGINE_DEBUG #ifdef DENGINE_DEBUG
debug_drawUi(state, dt); debug_drawUi(state, dt);

View File

@ -78,14 +78,15 @@ int main()
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glCullFace(GL_BACK); glCullFace(GL_BACK);
#ifdef DENGINE_DEBUG
debug_init();
#endif
GameState worldTraveller = {0}; GameState worldTraveller = {0};
worldTraveller_gameInit(&worldTraveller, worldTraveller_gameInit(&worldTraveller,
V2i(frameBufferWidth, frameBufferHeight)); V2i(frameBufferWidth, frameBufferHeight));
#ifdef DENGINE_DEBUG
debug_init(&worldTraveller.arena, V2i(windowWidth, windowHeight),
worldTraveller.assetManager.font);
#endif
glfwSetWindowUserPointer(window, CAST(void *)(&worldTraveller)); glfwSetWindowUserPointer(window, CAST(void *)(&worldTraveller));
f32 startTime = CAST(f32)(glfwGetTime()); f32 startTime = CAST(f32)(glfwGetTime());

View File

@ -2,8 +2,10 @@
#define DENGINE_ASSET_MANAGER_H #define DENGINE_ASSET_MANAGER_H
#include "Dengine/Assets.h" #include "Dengine/Assets.h"
#include "Dengine/MemoryArena.h"
#include "Dengine/Shader.h" #include "Dengine/Shader.h"
#include "Dengine/Texture.h" #include "Dengine/Texture.h"
#include "Dengine/MemoryArena.h"
#define MAX_TEXTURE_SIZE 1024 #define MAX_TEXTURE_SIZE 1024
@ -29,12 +31,13 @@ const i32 asset_loadTextureImage(AssetManager *assetManager,
const char *const path, const char *const path,
const enum TexList type); const enum TexList type);
const i32 asset_loadShaderFiles(AssetManager *assetManager, const i32 asset_loadShaderFiles(AssetManager *assetManager, MemoryArena *arena,
const char *const vertexPath, const char *const vertexPath,
const char *const fragmentPath, const char *const fragmentPath,
const enum ShaderList type); const enum ShaderList type);
const i32 asset_loadTTFont(AssetManager *assetManager, const char *filePath); const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena,
const char *filePath);
inline i32 asset_getVFontSpacing(FontMetrics metrics) inline i32 asset_getVFontSpacing(FontMetrics metrics)
{ {
@ -43,8 +46,8 @@ inline i32 asset_getVFontSpacing(FontMetrics metrics)
return result; return result;
} }
void asset_addAnimation(AssetManager *assetManager, i32 texId, void asset_addAnimation(AssetManager *assetManager, MemoryArena *arena,
i32 animId, i32 *atlasIndexes, i32 numFrames, i32 texId, i32 animId, i32 *atlasIndexes, i32 numFrames,
f32 frameDuration); f32 frameDuration);
#endif #endif

View File

@ -28,5 +28,6 @@ typedef double f64;
i32 common_strlen(const char *const string); i32 common_strlen(const char *const string);
i32 common_strcmp(const char *a, const char *b); i32 common_strcmp(const char *a, const char *b);
void common_itoa(i32 value, char *buf, i32 bufSize);
#endif #endif

View File

@ -9,7 +9,7 @@
#include "WorldTraveller/WorldTraveller.h" #include "WorldTraveller/WorldTraveller.h"
#define INVALID_CODE_PATH TRUE #define INVALID_CODE_PATH 0
enum DebugCallCount enum DebugCallCount
{ {
debugcallcount_drawArrays, debugcallcount_drawArrays,
@ -18,19 +18,22 @@ enum DebugCallCount
typedef struct DebugState typedef struct DebugState
{ {
i32 totalMemoryAllocated; Font font;
i32 *callCount; i32 *callCount;
f32 stringLineGap;
/* Debug strings rendered in top left corner */ /* Debug strings rendered in top left corner */
char debugStrings[256][64]; char debugStrings[64][128];
i32 numDebugStrings; i32 numDebugStrings;
f32 stringUpdateTimer; f32 stringUpdateTimer;
f32 stringUpdateRate; f32 stringUpdateRate;
v2 initialStringP;
v2 currStringP;
v2 initialStringPos; /* Debug gui console log */
v2 stringPos; char console[20][128];
i32 consoleIndex;
f32 stringLineGap; v2 initialConsoleP;
} DebugState; } DebugState;
extern DebugState GLOBAL_debug; extern DebugState GLOBAL_debug;
@ -97,14 +100,16 @@ inline char *debug_entityattack_string(i32 val)
} }
void debug_init(); void debug_init(MemoryArena *arena, v2 windowSize, Font font);
#define DEBUG_PUSH_STRING(string) debug_pushString(string, NULL, "char") #define DEBUG_PUSH_STRING(string) debug_pushString(string, NULL, "char")
#define DEBUG_PUSH_VAR(formatString, data, type) \ #define DEBUG_PUSH_VAR(formatString, data, type) \
debug_pushString(formatString, CAST(void *)&data, type) debug_pushString(formatString, CAST(void *)&data, type)
void debug_pushString(char *formatString, void *data, char *dataType); void debug_pushString(char *formatString, void *data, char *dataType);
void debug_stringUpdateAndRender(Renderer *renderer, Font *font, f32 dt);
void debug_drawUi(GameState *state, f32 dt); void debug_drawUi(GameState *state, f32 dt);
#define DEBUG_LOG(string) debug_consoleLog(string, __FILE__, __LINE__);
void debug_consoleLog(char *string, char *file, int lineNum);
#endif #endif

View File

@ -65,7 +65,7 @@ typedef struct EntityAnim_
typedef struct Entity typedef struct Entity
{ {
u32 id; i32 id;
v2 pos; // Position v2 pos; // Position
v2 dPos; // Velocity v2 dPos; // Velocity

View File

@ -0,0 +1,9 @@
#ifndef DENGINE_MEMORY_ARENA_H
#define DENGINE_MEMORY_ARENA_H
typedef struct MemoryArena
{
i32 bytesAllocated;
} MemoryArena;
#endif

View File

@ -2,6 +2,7 @@
#define DENGINE_PLATFORM_H #define DENGINE_PLATFORM_H
#include "Dengine/Common.h" #include "Dengine/Common.h"
#include "Dengine/MemoryArena.h"
typedef struct PlatformFileRead typedef struct PlatformFileRead
{ {
@ -10,17 +11,17 @@ typedef struct PlatformFileRead
} PlatformFileRead; } PlatformFileRead;
// TODO(doyle): Create own custom memory allocator // TODO(doyle): Create own custom memory allocator
#define PLATFORM_MEM_FREE(ptr, bytes) platform_memoryFree(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 // 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 // allocator since we haven't put in a system to track memory usage per
// allocation // allocation
void platform_memoryFree(void *data, i32 numBytes); void platform_memoryFree(MemoryArena *arena, void *data, i32 numBytes);
#define PLATFORM_MEM_ALLOC(num, type) CAST(type *) platform_memoryAlloc(num * sizeof(type)) #define PLATFORM_MEM_ALLOC(arena, num, type) CAST(type *) platform_memoryAlloc(arena, num * sizeof(type))
void *platform_memoryAlloc(i32 numBytes); void *platform_memoryAlloc(MemoryArena *arena, i32 numBytes);
void platform_closeFileRead(PlatformFileRead *file); void platform_closeFileRead(MemoryArena *arena, PlatformFileRead *file);
i32 platform_readFileToBuffer(const char *const filePath, i32 platform_readFileToBuffer(MemoryArena *arena, const char *const filePath,
PlatformFileRead *file); PlatformFileRead *file);
#endif #endif

View File

@ -6,6 +6,7 @@
#include "Dengine/Entity.h" #include "Dengine/Entity.h"
#include "Dengine/Math.h" #include "Dengine/Math.h"
#include "Dengine/Shader.h" #include "Dengine/Shader.h"
#include "Dengine/MemoryArena.h"
typedef struct Renderer typedef struct Renderer
{ {
@ -36,18 +37,17 @@ inline void renderer_staticRect(Renderer *const renderer, v2 pos, v2 size,
color); color);
} }
void renderer_string(Renderer *const renderer, MemoryArena *arena,
v4 cameraBounds, Font *const font,
const char *const string, v2 pos, f32 rotate, v4 color);
void renderer_string(Renderer *const renderer, v4 cameraBounds, inline void renderer_staticString(Renderer *const renderer, MemoryArena *arena,
Font *const font, const char *const string, v2 pos, Font *const font, const char *const string,
f32 rotate, v4 color); v2 pos, f32 rotate, v4 color)
inline void renderer_staticString(Renderer *const renderer, Font *const font,
const char *const string, v2 pos, f32 rotate,
v4 color)
{ {
v4 staticCameraBounds = math_getRect(V2(0, 0), renderer->size); v4 staticCameraBounds = math_getRect(V2(0, 0), renderer->size);
renderer_string(renderer, staticCameraBounds, font, string, pos, rotate, renderer_string(renderer, arena, staticCameraBounds, font, string, pos,
color); rotate, color);
} }
void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity,

View File

@ -5,6 +5,7 @@
#include "Dengine/Common.h" #include "Dengine/Common.h"
#include "Dengine/Entity.h" #include "Dengine/Entity.h"
#include "Dengine/Math.h" #include "Dengine/Math.h"
#include "Dengine/MemoryArena.h"
#include "Dengine/Renderer.h" #include "Dengine/Renderer.h"
#define NUM_KEYS 1024 #define NUM_KEYS 1024
@ -41,6 +42,7 @@ typedef struct GameState
i32 tileSize; i32 tileSize;
AssetManager assetManager; AssetManager assetManager;
MemoryArena arena;
} GameState; } GameState;
void worldTraveller_gameInit(GameState *state, v2 windowSize); void worldTraveller_gameInit(GameState *state, v2 windowSize);