diff --git a/src/Asteroid.c b/src/Asteroid.c index 3fa4637..d3ad93b 100644 --- a/src/Asteroid.c +++ b/src/Asteroid.c @@ -191,7 +191,7 @@ INTERNAL b32 checkEdgeProjectionOverlap(v2 *vertexList, i32 listSize, return result; } -INTERNAL u32 moveEntity(World *world, MemoryArena_ *transientArena, +INTERNAL u32 moveEntity(GameWorldState *world, MemoryArena_ *transientArena, Entity *entity, i32 entityIndex, v2 ddP, f32 dt, f32 ddPSpeed) { @@ -301,7 +301,8 @@ typedef struct { v2 dP; } AsteroidSpec; -INTERNAL void addAsteroidWithSpec(World *world, enum AsteroidSize asteroidSize, +INTERNAL void addAsteroidWithSpec(GameWorldState *world, + enum AsteroidSize asteroidSize, AsteroidSpec *spec) { world->asteroidCounter++; @@ -405,15 +406,15 @@ INTERNAL void addAsteroidWithSpec(World *world, enum AsteroidSize asteroidSize, } asteroid->vertexPoints = vertexCache[cacheIndex]; - asteroid->color = V4(0.0f, 0.5f, 0.5f, 1.0f); + asteroid->color = V4(1.0f, 1.0f, 1.0f, 1.0f); } -INTERNAL void addAsteroid(World *world, enum AsteroidSize asteroidSize) +INTERNAL void addAsteroid(GameWorldState *world, enum AsteroidSize asteroidSize) { addAsteroidWithSpec(world, asteroidSize, NULL); } -INTERNAL void addBullet(World *world, Entity *shooter) +INTERNAL void addBullet(GameWorldState *world, Entity *shooter) { Entity *bullet = &world->entityList[world->entityIndex++]; bullet->id = world->entityIdCounter++; @@ -442,7 +443,7 @@ INTERNAL void addBullet(World *world, Entity *shooter) bullet->color = V4(1.0f, 1.0f, 0, 1.0f); } -INTERNAL void setCollisionRule(World *world, enum EntityType a, +INTERNAL void setCollisionRule(GameWorldState *world, enum EntityType a, enum EntityType b, b32 rule) { ASSERT(a <= entitytype_count); @@ -451,7 +452,8 @@ INTERNAL void setCollisionRule(World *world, enum EntityType a, world->collisionTable[b][a] = rule; } -INTERNAL AudioRenderer *getFreeAudioRenderer(World *world, AudioVorbis *vorbis, +INTERNAL AudioRenderer *getFreeAudioRenderer(GameWorldState *world, + AudioVorbis *vorbis, i32 maxSimultaneousPlayers) { i32 freeIndex = -1; @@ -480,7 +482,7 @@ INTERNAL AudioRenderer *getFreeAudioRenderer(World *world, AudioVorbis *vorbis, return result; } -INTERNAL void addPlayer(World *world) +INTERNAL void addPlayer(GameWorldState *world) { Entity *ship = &world->entityList[world->entityIndex++]; ship->id = world->entityIdCounter++; @@ -507,7 +509,7 @@ INTERNAL void addPlayer(World *world) ship->color = V4(1.0f, 0.5f, 0.5f, 1.0f); } -INTERNAL void deleteEntity(World *world, i32 entityIndex) +INTERNAL void deleteEntity(GameWorldState *world, i32 entityIndex) { ASSERT(entityIndex > 0); ASSERT(entityIndex < ARRAY_COUNT(world->entityList)); @@ -520,9 +522,51 @@ INTERNAL void deleteEntity(World *world, i32 entityIndex) world->entityList[--world->entityIndex] = emptyEntity; } +#define GET_STATE_DATA(state, arena, type) \ + (type *)getStateData_(state, arena, appstate_##type) +INTERNAL void *getStateData_(GameState *state, MemoryArena_ *persistentArena, + enum AppState appState) +{ + void *result = NULL; + switch (appState) + { + case appstate_StartMenuState: + { + if (!state->appStateData[appState]) + { + state->appStateData[appState] = + MEMORY_PUSH_STRUCT(persistentArena, StartMenuState); + } + } + break; + + case appstate_GameWorldState: + { + if (!state->appStateData[appState]) + { + state->appStateData[appState] = + MEMORY_PUSH_STRUCT(persistentArena, GameWorldState); + } + } + break; + + default: + { + ASSERT(INVALID_CODE_PATH); + } + break; + } + + ASSERT(state->appStateData[appState]); + result = state->appStateData[appState]; + return result; +} + INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) { - World *world = &state->world; + GameWorldState *world = + GET_STATE_DATA(state, &state->persistentArena, GameWorldState); + if (!world->init) { world->pixelsPerMeter = 70.0f; @@ -946,9 +990,6 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) } } -LOCAL_PERSIST f32 flashingGameStartTimerThreshold = 1.0f; -LOCAL_PERSIST f32 flashingGameStartTimer = 1.0f; -LOCAL_PERSIST b32 toggleShowGameStart = TRUE; INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt) { AssetManager *assetManager = &state->assetManager; @@ -956,7 +997,8 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt) Renderer *renderer = &state->renderer; MemoryArena_ *transientArena = &state->transientArena; UiState *uiState = &state->uiState; - World *world = &state->world; + StartMenuState *menuState = + GET_STATE_DATA(state, &state->persistentArena, StartMenuState); Font *arial15 = asset_fontGetOrCreateOnDemand( assetManager, &state->persistentArena, transientArena, "Arial", 15); @@ -976,35 +1018,59 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt) ui_beginState(uiState); - flashingGameStartTimer -= dt; - if (flashingGameStartTimer < 0) - { - toggleShowGameStart = (toggleShowGameStart) ? FALSE : TRUE; - flashingGameStartTimer = flashingGameStartTimerThreshold; + { // Draw blinking Start Game prompt + menuState->startMenuGameStartBlinkTimer -= dt; + if (menuState->startMenuGameStartBlinkTimer < 0.0f) + { + menuState->startMenuGameStartBlinkTimer = 1.0f; + menuState->startMenuToggleShow = + (menuState->startMenuToggleShow) ? FALSE : TRUE; + } + + if (menuState->startMenuToggleShow) + { + const char *const gameStart = "Press enter to start"; + v2 gameStartDim = asset_fontStringDimInPixels(arial25, gameStart); + v2 halfGameStartDim = v2_scale(gameStartDim, 0.5f); + v2 gameStartP = v2_add(screenCenter, V2(0, -40)); + gameStartP = v2_sub(gameStartP, halfGameStartDim); + + renderer_stringFixed(renderer, transientArena, arial25, gameStart, + gameStartP, V2(0, 0), 0, V4(1, 1, 0, 1), 0); + } } - if (toggleShowGameStart) { - const char *const gameStart = "Press enter to start"; - v2 gameStartDim = asset_fontStringDimInPixels(arial25, gameStart); - v2 halfGameStartDim = v2_scale(gameStartDim, 0.5f); - v2 gameStartP = v2_add(screenCenter, V2(0, -40)); - gameStartP = v2_sub(gameStartP, halfGameStartDim); - - renderer_stringFixed(renderer, transientArena, arial25, gameStart, - gameStartP, V2(0, 0), 0, V4(1, 1, 0, 1), 0); + const char *const optionPrompt = "Press [o] for options "; + v2 dim = asset_fontStringDimInPixels(arial25, optionPrompt); + v2 halfDim = v2_scale(dim, 0.5f); + v2 p = v2_add(screenCenter, V2(0, -120)); + p = v2_sub(p, halfDim); + renderer_stringFixed(renderer, transientArena, arial25, optionPrompt, p, + V2(0, 0), 0, V4(1, 1, 0, 1), 0); } if (platform_queryKey(&inputBuffer->keys[keycode_enter], readkeytype_one_shot, KEY_DELAY_NONE)) { - state->appState = appstate_game; - addPlayer(&state->world); + state->currState = appstate_GameWorldState; + + GameWorldState *world = + GET_STATE_DATA(state, &state->persistentArena, GameWorldState); + addPlayer(world); } ui_endState(uiState, inputBuffer); } +#define ASTEROID_GET_STATE_DATA(state, type) \ + (type *)asteroid_getStateData_(state, appstate_##type) +void *asteroid_getStateData_(GameState *state, enum AppState appState) +{ + void *result = state->appStateData[appState]; + return result; +} + void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, v2 windowSize, f32 dt) { @@ -1028,21 +1094,21 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, Font *arial15 = asset_fontGet(&state->assetManager, "Arial", 15); debug_init(&state->persistentArena, windowSize, *arial15); - state->appState = appstate_start_menu; - state->init = TRUE; + state->currState = appstate_StartMenuState; + state->init = TRUE; } platform_inputBufferProcess(&state->input, dt); - switch (state->appState) + switch (state->currState) { - case appstate_start_menu: + case appstate_StartMenuState: { // NOTE(doyle): Let menu overlay the game menu. We add player on "enter" // So fall through to appstate_game is valid here! startMenuUpdate(state, memory, dt); } - case appstate_game: + case appstate_GameWorldState: { gameUpdate(state, memory, dt); } diff --git a/src/Debug.c b/src/Debug.c index 5886d8e..565c542 100644 --- a/src/Debug.c +++ b/src/Debug.c @@ -278,12 +278,16 @@ void debug_drawUi(GameState *state, f32 dt) 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("== =="); + GameWorldState *world = ASTEROID_GET_STATE_DATA(state, GameWorldState); + if (world) + { + MemoryArena_ *entityArena = &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", diff --git a/src/dengine.c b/src/dengine.c index 7c5233e..c22a7d0 100644 --- a/src/dengine.c +++ b/src/dengine.c @@ -206,7 +206,7 @@ i32 main(void) glfwPollEvents(); /* Rendering commands here*/ - glClearColor(0.2f, 0.2f, 0.2f, 1.0f); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); asteroid_gameUpdateAndRender(gameState, &memory, windowSize, @@ -236,10 +236,16 @@ i32 main(void) f32 msPerFrame = secondsElapsed * 1000.0f; f32 framesPerSecond = 1.0f / secondsElapsed; + i32 entityCount = 0; + GameWorldState *world = + ASTEROID_GET_STATE_DATA(gameState, GameWorldState); + + if (world) entityCount = world->entityIndex; + char textBuffer[256]; snprintf(textBuffer, ARRAY_COUNT(textBuffer), "Dengine | %f ms/f | %f fps | Entity Count: %d", - msPerFrame, framesPerSecond, gameState->world.entityIndex); + msPerFrame, framesPerSecond, entityCount); glfwSetWindowTitle(window, textBuffer); titleUpdateFrequencyInSeconds = 0.5f; diff --git a/src/include/Dengine/Asteroid.h b/src/include/Dengine/Asteroid.h index 39dd041..94544eb 100644 --- a/src/include/Dengine/Asteroid.h +++ b/src/include/Dengine/Asteroid.h @@ -12,14 +12,15 @@ enum AppState { - appstate_start_menu, - appstate_game, + appstate_StartMenuState, + appstate_GameWorldState, appstate_count, }; -typedef struct World +typedef struct GameWorldState { b32 init; + MemoryArena_ entityArena; v2 *entityVertexListCache[entitytype_count]; @@ -49,12 +50,20 @@ typedef struct World // TODO(doyle): Ensure we change this if it gets too big b32 collisionTable[entitytype_count][entitytype_count]; -} World; +} GameWorldState; -typedef struct GameState { +typedef struct StartMenuState +{ + f32 startMenuGameStartBlinkTimer; + b32 startMenuToggleShow; +} StartMenuState; + +typedef struct GameState +{ b32 init; - - enum AppState appState; + + enum AppState currState; + void *appStateData[appstate_count]; MemoryArena_ transientArena; MemoryArena_ persistentArena; @@ -65,9 +74,12 @@ typedef struct GameState { Renderer renderer; UiState uiState; - World world; } GameState; +#define ASTEROID_GET_STATE_DATA(state, type) \ + (type *)asteroid_getStateData_(state, appstate_##type) +void *asteroid_getStateData_(GameState *state, enum AppState appState); + void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, v2 windowSize, f32 dt);