#include "Dengine/Debug.h" #include "Dengine/AssetManager.h" #include "Dengine/MemoryArena.h" #include "Dengine/Platform.h" #include "Dengine/Renderer.h" #include "Dengine/Asteroid.h" typedef struct DebugState { b32 init; Font font; i32 *callCount; f32 stringLineGap; /* Debug strings rendered in top left corner */ char debugStrings[64][128]; i32 numDebugStrings; f32 stringUpdateTimer; f32 stringUpdateRate; v2 initialStringP; v2 currStringP; /* Debug gui console log */ char console[20][128]; i32 consoleIndex; v2 initialConsoleP; } DebugState; GLOBAL_VAR DebugState GLOBAL_debug; void debug_init(MemoryArena_ *arena, v2 windowSize, Font font) { GLOBAL_debug.font = font; GLOBAL_debug.callCount = memory_pushBytes(arena, debugcount_num * sizeof(i32)); GLOBAL_debug.stringLineGap = CAST(f32) font.verticalSpacing; /* Init debug string stack */ GLOBAL_debug.numDebugStrings = 0; GLOBAL_debug.stringUpdateTimer = 0.0f; GLOBAL_debug.stringUpdateRate = 0.15f; 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 = font.maxSize.w * 20; f32 consoleYPos = windowSize.h - 1.8f * GLOBAL_debug.stringLineGap; GLOBAL_debug.initialConsoleP = V2(consoleXPos, consoleYPos); GLOBAL_debug.init = TRUE; } void debug_recursivePrintXmlTree(XmlNode *root, i32 levelsDeep) { if (!root) { return; } else { for (i32 i = 0; i < levelsDeep; i++) { printf("-"); } printf("%s ", root->name); XmlAttribute *attribute = &root->attribute; printf("| %s = %s", attribute->name, attribute->value); while (attribute->next) { attribute = attribute->next; printf("| %s = %04s", attribute->name, attribute->value); } printf("\n"); debug_recursivePrintXmlTree(root->child, levelsDeep+1); debug_recursivePrintXmlTree(root->next, levelsDeep); } } void debug_countIncrement(i32 id) { if (GLOBAL_debug.init == FALSE) return; ASSERT(id < debugcount_num); GLOBAL_debug.callCount[id]++; } void debug_clearCounter() { for (i32 i = 0; i < debugcount_num; i++) GLOBAL_debug.callCount[i] = 0; } void debug_consoleLog(char *string, char *file, int lineNum) { i32 maxConsoleStrLen = ARRAY_COUNT(GLOBAL_debug.console[0]); /* Completely clear out current console line */ for (i32 i = 0; i < maxConsoleStrLen; i++) GLOBAL_debug.console[GLOBAL_debug.consoleIndex][i] = 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; } void debug_pushString(char *formatString, void *data, char *dataType) { if (GLOBAL_debug.numDebugStrings >= ARRAY_COUNT(GLOBAL_debug.debugStrings)) { DEBUG_LOG("Debug string stack is full, DEBUG_PUSH() failed"); return; } if (GLOBAL_debug.stringUpdateTimer <= 0) { i32 numDebugStrings = GLOBAL_debug.numDebugStrings; if (common_strcmp(dataType, "v2") == 0) { v2 val = *(CAST(v2 *) data); snprintf(GLOBAL_debug.debugStrings[numDebugStrings], ARRAY_COUNT(GLOBAL_debug.debugStrings[0]), formatString, val.x, val.y); } else if (common_strcmp(dataType, "v3") == 0) { v3 val = *(CAST(v3 *) data); snprintf(GLOBAL_debug.debugStrings[numDebugStrings], ARRAY_COUNT(GLOBAL_debug.debugStrings[0]), formatString, val.x, val.y, val.z); } else if (common_strcmp(dataType, "i32") == 0) { i32 val = *(CAST(i32 *) data); snprintf(GLOBAL_debug.debugStrings[numDebugStrings], ARRAY_COUNT(GLOBAL_debug.debugStrings[0]), formatString, val); } else if (common_strcmp(dataType, "f32") == 0) { f32 val = *(CAST(f32 *) data); snprintf(GLOBAL_debug.debugStrings[numDebugStrings], ARRAY_COUNT(GLOBAL_debug.debugStrings[0]), formatString, val); } else if (common_strcmp(dataType, "char") == 0) { if (data) { char *val = CAST(char *) data; snprintf(GLOBAL_debug.debugStrings[numDebugStrings], ARRAY_COUNT(GLOBAL_debug.debugStrings[0]), formatString, val); } else { snprintf(GLOBAL_debug.debugStrings[numDebugStrings], ARRAY_COUNT(GLOBAL_debug.debugStrings[0]), formatString); } } else { ASSERT(INVALID_CODE_PATH); } GLOBAL_debug.numDebugStrings++; } } INTERNAL void updateAndRenderDebugStack(Renderer *renderer, MemoryArena_ *arena, f32 dt) { for (i32 i = 0; i < GLOBAL_debug.numDebugStrings; i++) { f32 rotate = 0; v4 color = V4(1, 1, 1, 1); renderer_staticString( renderer, arena, &GLOBAL_debug.font, GLOBAL_debug.debugStrings[i], GLOBAL_debug.currStringP, V2(0, 0), rotate, color, 0); GLOBAL_debug.currStringP.y -= (0.9f * GLOBAL_debug.stringLineGap); } if (GLOBAL_debug.stringUpdateTimer <= 0) { GLOBAL_debug.stringUpdateTimer = GLOBAL_debug.stringUpdateRate; } else { GLOBAL_debug.stringUpdateTimer -= dt; if (GLOBAL_debug.stringUpdateTimer <= 0) { GLOBAL_debug.numDebugStrings = 0; } } 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, V2(0, 0), rotate, color, 0); consoleStrP.y -= (0.9f * GLOBAL_debug.stringLineGap); } } void debug_drawUi(GameState *state, f32 dt) { updateAndRenderDebugStack(&state->renderer, &state->transientArena, dt); renderConsole(&state->renderer, &state->transientArena); { // Print Memory Arena Info DEBUG_PUSH_STRING("== MEMORY ARENAS =="); MemoryArena_ *transient = &state->transientArena; i32 transientSizeInKbs = transient->size / 1024; i32 transientUsedInKbs = transient->used / 1024; v2 transientUsage = V2i(transientUsedInKbs, transientSizeInKbs); DEBUG_PUSH_VAR("Transient Usage: %.0f/%.0f", transientUsage, "v2"); MemoryArena_ *persistent = &state->persistentArena; i32 persistentSizeInKbs = persistent->size / 1024; i32 persistentUsedInKbs = persistent->used / 1024; v2 persistentUsage = V2i(persistentUsedInKbs, persistentSizeInKbs); DEBUG_PUSH_VAR("Permanent Usage: %.0f/%.0f", persistentUsage, "v2"); MemoryArena_ *entityArena = &state->world.entityArena; i32 entitySizeInKbs = entityArena->size / 1024; i32 entityUsedInKbs = entityArena->used / 1024; v2 entityUsage = V2i(entityUsedInKbs, entitySizeInKbs); DEBUG_PUSH_VAR("Entity Usage: %.0f/%.0f", entityUsage, "v2"); DEBUG_PUSH_STRING("== =="); } DEBUG_PUSH_VAR("Num Vertex: %d", GLOBAL_debug.callCount[debugcount_numVertex], "i32"); debug_clearCounter(); }