diff --git a/src/AssetManager.c b/src/AssetManager.c index 7a3f738..bfbc35b 100644 --- a/src/AssetManager.c +++ b/src/AssetManager.c @@ -305,35 +305,47 @@ Texture *asset_texLoadImage(AssetManager *assetManager, MemoryArena_ *arena, { /* Open the texture image */ i32 imgWidth, imgHeight, bytesPerPixel; - stbi_set_flip_vertically_on_load(TRUE); u8 *image = - stbi_load(path, &imgWidth, &imgHeight, &bytesPerPixel, 0); + asset_imageLoad(&imgWidth, &imgHeight, &bytesPerPixel, path, TRUE); -#ifdef DENGINE_DEBUG - if (imgWidth != imgHeight) + Texture *result = NULL; + if (image) + { + result = asset_texGetFreeSlot(assetManager, arena, key); + *result = textureGen(CAST(GLuint)(imgWidth), CAST(GLuint)(imgHeight), + CAST(GLint)(bytesPerPixel), image); + + GL_CHECK_ERROR(); + asset_imageFree(image); + } + + return result; +} + +u8 *asset_imageLoad(i32 *width, i32 *height, i32 *bpp, const char *const path, + b32 flipVertically) +{ + stbi_set_flip_vertically_on_load(flipVertically); + u8 *image = stbi_load(path, width, height, bpp, 0); + + if (*width != *height) { printf( "asset_texLoadImage() warning: Sprite sheet is not square: " - "%dx%dpx\n", imgWidth, imgHeight); + "%dx%dpx\n", + *width, *height); } -#endif if (!image) { printf("stdbi_load() failed: %s\n", stbi_failure_reason()); - return NULL; } - Texture *result = asset_texGetFreeSlot(assetManager, arena, key); - *result = textureGen(CAST(GLuint)(imgWidth), CAST(GLuint)(imgHeight), - CAST(GLint)(bytesPerPixel), image); - - GL_CHECK_ERROR(); - stbi_image_free(image); - - return result; + return image; } +void asset_imageFree(u8 *image) { stbi_image_free(image); } + /* ********************************* * Animation Asset Managing diff --git a/src/Asteroid.c b/src/Asteroid.c index d3ad93b..d61d211 100644 --- a/src/Asteroid.c +++ b/src/Asteroid.c @@ -340,17 +340,17 @@ INTERNAL void addAsteroidWithSpec(GameWorldState *world, i32 randValue = rand(); if (!spec) { - i32 randX = (randValue % (i32)world->worldSize.w); - i32 randY = (randValue % (i32)world->worldSize.h); + i32 randX = (randValue % (i32)world->size.w); + i32 randY = (randValue % (i32)world->size.h); - v2 midpoint = v2_scale(world->worldSize, 0.5f); + v2 midpoint = v2_scale(world->size, 0.5f); Rect topLeftQuadrant = {V2(0, midpoint.y), - V2(midpoint.x, world->worldSize.y)}; + V2(midpoint.x, world->size.y)}; Rect botLeftQuadrant = {V2(0, 0), midpoint}; - Rect topRightQuadrant = {midpoint, world->worldSize}; + Rect topRightQuadrant = {midpoint, world->size}; Rect botRightQuadrant = {V2(midpoint.x, 0), - V2(world->worldSize.x, midpoint.y)}; + V2(world->size.x, midpoint.y)}; // NOTE(doyle): Off-screen so asteroids "float" into view. There's no // particular order, just pushing things offscreen when they get @@ -577,9 +577,9 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) u8 *arenaBase = state->transientArena.base + state->transientArena.size; memory_arenaInit(&world->entityArena, arenaBase, entityArenaSize); - world->camera.min = V2(0, 0); - world->camera.max = state->renderer.size; - world->worldSize = state->renderer.size; + world->camera.min = V2(0, 0); + world->camera.max = state->renderer.size; + world->size = state->renderer.size; { // Init null entity Entity *nullEntity = &world->entityList[world->entityIndex++]; @@ -617,8 +617,8 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) for (i32 i = 0; i < world->numStarP; i++) { - i32 randX = rand() % (i32)world->worldSize.x; - i32 randY = rand() % (i32)world->worldSize.y; + i32 randX = rand() % (i32)world->size.x; + i32 randY = rand() % (i32)world->size.y; world->starPList[i] = V2i(randX, randY); } @@ -821,15 +821,15 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) } /* Loop entity around world */ - if (entity->pos.y >= world->worldSize.h) + if (entity->pos.y >= world->size.h) entity->pos.y = 0; else if (entity->pos.y < 0) - entity->pos.y = world->worldSize.h; + entity->pos.y = world->size.h; - if (entity->pos.x >= world->worldSize.w) + if (entity->pos.x >= world->size.w) entity->pos.x = 0; else if (entity->pos.x < 0) - entity->pos.x = world->worldSize.w; + entity->pos.x = world->size.w; i32 collisionIndex = moveEntity(world, &state->transientArena, entity, i, ddP, dt, ddPSpeedInMs); @@ -1007,57 +1007,104 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt) v2 screenCenter = v2_scale(renderer->size, 0.5f); - const char *const title = "Asteroids"; - v2 titleDim = asset_fontStringDimInPixels(arial25, title); - v2 halfTitleDim = v2_scale(titleDim, 0.5f); - v2 titleP = v2_add(screenCenter, V2(0, 40)); - titleP = v2_sub(titleP, halfTitleDim); - - renderer_stringFixed(renderer, transientArena, arial25, title, titleP, - V2(0, 0), 0, V4(1, 0, 0, 1), 0); - ui_beginState(uiState); - { // Draw blinking Start Game prompt - menuState->startMenuGameStartBlinkTimer -= dt; - if (menuState->startMenuGameStartBlinkTimer < 0.0f) + if (menuState->optionsShow) + { + if (platform_queryKey(&inputBuffer->keys[keycode_o], + readkeytype_one_shot, KEY_DELAY_NONE) || + platform_queryKey(&inputBuffer->keys[keycode_backspace], + readkeytype_one_shot, KEY_DELAY_NONE)) { - menuState->startMenuGameStartBlinkTimer = 1.0f; - menuState->startMenuToggleShow = - (menuState->startMenuToggleShow) ? FALSE : TRUE; + menuState->optionsShow = FALSE; + } + else + { + f32 textYOffset = arial25->size * 1.5f;; + const char *const title = "Options"; + v2 p = v2_add(screenCenter, V2(0, textYOffset)); + renderer_stringFixedCentered(renderer, transientArena, arial25, + title, p, V2(0, 0), 0, V4(1, 0, 1, 1), + 0); + + const char *const resolutionLabel = "Resolution"; + p = v2_add(screenCenter, V2(0, 0)); + + renderer_stringFixedCentered(renderer, transientArena, arial25, + resolutionLabel, p, V2(0, 0), 0, + V4(1, 0, 1, 1), 0); + + const char *const resSizeLabel = "< 800x600 >"; + p = v2_add(screenCenter, V2(0, -textYOffset)); + + renderer_stringFixedCentered(renderer, transientArena, arial25, + resSizeLabel, p, V2(0, 0), 0, + V4(1, 0, 1, 1), 0); + + if (platform_queryKey(&inputBuffer->keys[keycode_enter], + readkeytype_one_shot, KEY_DELAY_NONE)) + { + menuState->newResolutionRequest = TRUE; + menuState->newResolution = V2(800, 600); + + renderer->size = menuState->newResolution; + + GameWorldState *world = GET_STATE_DATA( + state, &state->persistentArena, GameWorldState); + world->size = menuState->newResolution; + world->camera.max = menuState->newResolution; + } + } + } + else + { + /* Draw title text */ + const char *const title = "Asteroids"; + v2 p = v2_add(screenCenter, V2(0, 40)); + renderer_stringFixedCentered(renderer, transientArena, arial25, title, + p, V2(0, 0), 0, V4(1, 0, 0, 1), 0); + + /* Draw blinking start game prompt */ + menuState->startPromptBlinkTimer -= dt; + if (menuState->startPromptBlinkTimer < 0.0f) + { + menuState->startPromptBlinkTimer = 1.0f; + menuState->startPromptShow = + (menuState->startPromptShow) ? FALSE : TRUE; } - if (menuState->startMenuToggleShow) + if (menuState->startPromptShow) { 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); + v2 p = v2_add(screenCenter, V2(0, -40)); + renderer_stringFixedCentered(renderer, transientArena, arial25, + gameStart, p, 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); - } + { // Draw show options prompt + const char *const optionPrompt = "Press [o] for options "; + v2 p = v2_add(screenCenter, V2(0, -120)); + renderer_stringFixedCentered(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->currState = appstate_GameWorldState; + if (platform_queryKey(&inputBuffer->keys[keycode_enter], + readkeytype_one_shot, KEY_DELAY_NONE)) + { - GameWorldState *world = - GET_STATE_DATA(state, &state->persistentArena, GameWorldState); - addPlayer(world); + GameWorldState *world = + GET_STATE_DATA(state, &state->persistentArena, GameWorldState); + addPlayer(world); + + state->currState = appstate_GameWorldState; + } + else if (platform_queryKey(&inputBuffer->keys[keycode_o], + readkeytype_one_shot, KEY_DELAY_NONE)) + { + menuState->optionsShow = TRUE; + } } ui_endState(uiState, inputBuffer); diff --git a/src/dengine.c b/src/dengine.c index c22a7d0..3e21409 100644 --- a/src/dengine.c +++ b/src/dengine.c @@ -97,6 +97,14 @@ INTERNAL void scrollCallback(GLFWwindow *window, double xOffset, double yOffset) { } +INTERNAL void setGlfwWindowHints() +{ + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); +} + i32 main(void) { /* @@ -105,10 +113,7 @@ i32 main(void) ************************** */ glfwInit(); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); + setGlfwWindowHints(); i32 windowWidth = 1600; i32 windowHeight = 900; @@ -181,6 +186,19 @@ i32 main(void) glfwSetWindowUserPointer(window, CAST(void *)(gameState)); + { + i32 width, height; + char *iconPath = "data/textures/Asteroids/icon.png"; + u8 *pixels = asset_imageLoad(&width, &height, NULL, iconPath, FALSE); + + if (pixels) + { + GLFWimage image = {width, height, pixels}; + glfwSetWindowIcon(window, 1, &image); + asset_imageFree(pixels); + } + } + /* ******************* * GAME LOOP @@ -252,6 +270,19 @@ i32 main(void) } startTime = endTime; + + StartMenuState *menuState = + ASTEROID_GET_STATE_DATA(gameState, StartMenuState); + if (menuState) + { + if (menuState->newResolutionRequest) + { + windowSize = menuState->newResolution; + glfwSetWindowSize(window, (i32)windowSize.w, (i32)windowSize.h); + + menuState->newResolutionRequest = FALSE; + } + } } glfwTerminate(); diff --git a/src/include/Dengine/AssetManager.h b/src/include/Dengine/AssetManager.h index 16db192..27cb366 100644 --- a/src/include/Dengine/AssetManager.h +++ b/src/include/Dengine/AssetManager.h @@ -41,8 +41,13 @@ TexAtlas *asset_atlasGet(AssetManager *const assetManager, const char *const key); Texture *asset_texGetFreeSlot(AssetManager *const assetManager, MemoryArena_ *const arena, const char *const key); -Texture *asset_loadTextureImage(AssetManager *assetManager, MemoryArena_ *arena, - const char *const path, const char *const key); +Texture *asset_texLoadImage(AssetManager *assetManager, MemoryArena_ *arena, + const char *const path, const char *const key); + +u8 *asset_imageLoad(i32 *width, i32 *height, i32 *bpp, const char *const path, + b32 flipVertically); + +void asset_imageFree(u8 *image); /* ********************************* diff --git a/src/include/Dengine/Asteroid.h b/src/include/Dengine/Asteroid.h index 94544eb..5ba5107 100644 --- a/src/include/Dengine/Asteroid.h +++ b/src/include/Dengine/Asteroid.h @@ -45,8 +45,8 @@ typedef struct GameWorldState i32 numAudioRenderers; f32 pixelsPerMeter; - v2 worldSize; Rect camera; + v2 size; // TODO(doyle): Ensure we change this if it gets too big b32 collisionTable[entitytype_count][entitytype_count]; @@ -54,8 +54,13 @@ typedef struct GameWorldState typedef struct StartMenuState { - f32 startMenuGameStartBlinkTimer; - b32 startMenuToggleShow; + f32 startPromptBlinkTimer; + b32 startPromptShow; + + b32 optionsShow; + + b32 newResolutionRequest; + v2 newResolution; } StartMenuState; typedef struct GameState diff --git a/src/include/Dengine/Renderer.h b/src/include/Dengine/Renderer.h index ea4c370..7285712 100644 --- a/src/include/Dengine/Renderer.h +++ b/src/include/Dengine/Renderer.h @@ -3,10 +3,9 @@ #include "Dengine/Common.h" #include "Dengine/Math.h" -#include "Dengine/Assets.h" +#include "Dengine/AssetManager.h" /* Forward Declaration */ -typedef struct AssetManager AssetManager; typedef struct Font Font; typedef struct Entity Entity; typedef struct MemoryArena MemoryArena_; @@ -125,6 +124,22 @@ inline void renderer_stringFixed(Renderer *const renderer, MemoryArena_ *arena, pivotPoint, rotate, color, flags); } +inline void renderer_stringFixedCentered(Renderer *const renderer, + MemoryArena_ *arena, Font *const font, + const char *const string, v2 pos, + v2 pivotPoint, Radians rotate, + v4 color, RenderFlags flags) +{ + Rect staticCamera = {V2(0, 0), renderer->size}; + + v2 dim = asset_fontStringDimInPixels(font, string); + v2 halfDim = v2_scale(dim, 0.5f); + pos = v2_sub(pos, halfDim); + + renderer_string(renderer, arena, staticCamera, font, string, pos, + pivotPoint, rotate, color, flags); +} + void renderer_entity(Renderer *renderer, MemoryArena_ *transientArena, Rect camera, Entity *entity, v2 pivotPoint, Degrees rotate, v4 color, RenderFlags flags);