diff --git a/src/AssetManager.c b/src/AssetManager.c index 02b6d27..2c38736 100644 --- a/src/AssetManager.c +++ b/src/AssetManager.c @@ -48,6 +48,15 @@ const i32 asset_loadTextureImage(AssetManager *assetManager, u8 *image = stbi_load(path, &imgWidth, &imgHeight, &bytesPerPixel, 0); +#ifdef DENGINE_DEBUG + if (imgWidth != imgHeight) + { + printf( + "worldTraveller_gameInit() warning: Sprite sheet is not square: " + "%dx%dpx\n", imgWidth, imgHeight); + } +#endif + if (!image) { printf("stdbi_load() failed: %s\n", stbi_failure_reason()); diff --git a/src/Debug.c b/src/Debug.c index 77fb4a7..4aaa2c9 100644 --- a/src/Debug.c +++ b/src/Debug.c @@ -58,8 +58,8 @@ void debug_stringUpdateAndRender(Renderer *renderer, Font *font, f32 dt) { f32 rotate = 0; v4 color = V4(0, 0, 0, 1); - renderer_string(renderer, font, GLOBAL_debugState.debugStrings[i], - GLOBAL_debugState.stringPos, rotate, color); + renderer_staticString(renderer, font, GLOBAL_debugState.debugStrings[i], + GLOBAL_debugState.stringPos, rotate, color); GLOBAL_debugState.stringPos.y -= (0.9f * GLOBAL_debugState.stringLineGap); } diff --git a/src/Renderer.c b/src/Renderer.c index fdc0b01..3f4cf1a 100644 --- a/src/Renderer.c +++ b/src/Renderer.c @@ -18,50 +18,65 @@ INTERNAL void updateBufferObject(Renderer *const renderer, glBindBuffer(GL_ARRAY_BUFFER, 0); } -void renderer_string(Renderer *const renderer, Font *const font, - const char *const string, v2 pos, f32 rotate, - v4 color) +void renderer_string(Renderer *const renderer, v4 cameraBounds, + Font *const font, const char *const string, v2 pos, + f32 rotate, v4 color) { - i32 quadIndex = 0; - i32 strLen = common_strlen(string); - RenderQuad *stringQuads = PLATFORM_MEM_ALLOC(strLen, RenderQuad); - - f32 baseline = pos.y; - for (i32 i = 0; i < strLen; i++) + i32 strLen = common_strlen(string); + // TODO(doyle): Slightly incorrect string length in pixels calculation, + // because we use the advance metric of each character for length not + // maximum character size in rendering + v2 rightAlignedP = + v2_add(pos, V2((CAST(f32) font->maxSize.w * CAST(f32) strLen), + CAST(f32) font->maxSize.h)); + v2 leftAlignedP = pos; + if ((leftAlignedP.x < cameraBounds.z && rightAlignedP.x >= cameraBounds.x) && + (leftAlignedP.y < cameraBounds.y && rightAlignedP.y >= cameraBounds.w)) { - // NOTE(doyle): Atlas packs fonts tightly, so offset the codepoint to - // its actual atlas index, i.e. we skip the first 31 glyphs - i32 codepoint = string[i]; - i32 relativeIndex = codepoint - font->codepointRange.x; - CharMetrics charMetric = font->charMetrics[relativeIndex]; - pos.y = baseline - charMetric.offset.y; + i32 quadIndex = 0; + RenderQuad *stringQuads = PLATFORM_MEM_ALLOC(strLen, RenderQuad); - const v4 charRectOnScreen = getRect( - pos, V2(CAST(f32) font->maxSize.w, CAST(f32) font->maxSize.h)); + v2 offsetFromCamOrigin = V2(cameraBounds.x, cameraBounds.w); + v2 entityRelativeToCamera = v2_sub(pos, offsetFromCamOrigin); - pos.x += charMetric.advance; - - /* Get texture out */ - v4 charTexRect = font->atlas->texRect[relativeIndex]; - renderer_flipTexCoord(&charTexRect, FALSE, TRUE); + pos = entityRelativeToCamera; + f32 baseline = pos.y; + for (i32 i = 0; i < strLen; i++) + { + // NOTE(doyle): Atlas packs fonts tightly, so offset the codepoint + // to + // its actual atlas index, i.e. we skip the first 31 glyphs + i32 codepoint = string[i]; + i32 relativeIndex = codepoint - font->codepointRange.x; + CharMetrics charMetric = font->charMetrics[relativeIndex]; + pos.y = baseline - charMetric.offset.y; - RenderQuad charQuad = renderer_createQuad(renderer, charRectOnScreen, - charTexRect, font->tex); - stringQuads[quadIndex++] = charQuad; + const v4 charRectOnScreen = getRect( + pos, V2(CAST(f32) font->maxSize.w, CAST(f32) font->maxSize.h)); + + pos.x += charMetric.advance; + + /* Get texture out */ + v4 charTexRect = font->atlas->texRect[relativeIndex]; + renderer_flipTexCoord(&charTexRect, FALSE, TRUE); + + RenderQuad charQuad = renderer_createQuad( + renderer, charRectOnScreen, charTexRect, font->tex); + stringQuads[quadIndex++] = charQuad; + } + + // NOTE(doyle): We render at the renderer's size because we create quads + // relative to the window size, hence we also render at the origin since + // we're rendering a window sized buffer + updateBufferObject(renderer, stringQuads, quadIndex); + renderer_object(renderer, V2(0.0f, 0.0f), renderer->size, rotate, color, + font->tex); + PLATFORM_MEM_FREE(stringQuads, strLen * sizeof(RenderQuad)); } - - // NOTE(doyle): We render at the renderer's size because we create quads - // relative to the window size, hence we also render at the origin since - // we're rendering a window sized buffer - updateBufferObject(renderer, stringQuads, quadIndex); - renderer_object(renderer, V2(0.0f, 0.0f), renderer->size, rotate, color, - font->tex); - PLATFORM_MEM_FREE(stringQuads, strLen * sizeof(RenderQuad)); - } -void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, f32 dt, f32 rotate, - v4 color) +void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, + f32 dt, f32 rotate, v4 color) { // TODO(doyle): Batch into render groups @@ -101,7 +116,6 @@ void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, f32 dt renderer_object(renderer, entityRelativeToCamera, entity->size, rotate, color, entity->tex); } - } void renderer_object(Renderer *renderer, v2 pos, v2 size, f32 rotate, v4 color, diff --git a/src/WorldTraveller.c b/src/WorldTraveller.c index f63cdc4..019b612 100644 --- a/src/WorldTraveller.c +++ b/src/WorldTraveller.c @@ -201,23 +201,13 @@ void worldTraveller_gameInit(GameState *state, v2i windowSize) heroWalkRects[2] = V4(849.0f, 1018.0f, 904.0f, 920.0f); addAnim(hero, heroWalkRects, numRects, duration); - Texture *heroSheet = hero->tex; - v2 sheetSize = V2(CAST(f32) heroSheet->width, CAST(f32) heroSheet->height); - if (sheetSize.x != sheetSize.y) - { - printf( - "worldTraveller_gameInit() warning: Sprite sheet is not square: " - "%dx%dpx\n", - CAST(i32) sheetSize.w, CAST(i32) sheetSize.h); - } - /* Create a NPC */ - pos = V2(300.0f, 300.0f); + pos = V2((renderer->size.w / 3.0f), CAST(f32) state->tileSize); size = hero->size; - type = entitytype_hero; + type = entitytype_npc; dir = direction_null; tex = hero->tex; - collides = TRUE; + collides = FALSE; Entity *npc = addEntity(world, pos, size, type, dir, tex, collides); /* Add npc waving animation */ @@ -228,6 +218,32 @@ void worldTraveller_gameInit(GameState *state, v2i windowSize) npcWavingRects[1] = V4(944.0f, 812.0f, 1010.0f, 710.0f); addAnim(npc, npcWavingRects, numRects, duration); + /* Create a Mob */ + pos = V2(renderer->size.w - (renderer->size.w / 3.0f), + CAST(f32) state->tileSize); + size = hero->size; + type = entitytype_mob; + dir = direction_west; + tex = hero->tex; + collides = TRUE; + Entity *mob = addEntity(world, pos, size, type, dir, tex, collides); + + /* Add mob idle animation */ + duration = 1.0f; + numRects = 1; + v4 *mobIdleRects = PLATFORM_MEM_ALLOC(numRects, v4); + mobIdleRects[0] = heroIdleRects[0]; + addAnim(mob, mobIdleRects, numRects, duration); + + /* Add mob walking animation */ + duration = 0.10f; + numRects = 3; + v4 *mobWalkRects = PLATFORM_MEM_ALLOC(numRects, v4); + mobWalkRects[0] = heroWalkRects[0]; + mobWalkRects[1] = heroWalkRects[1]; + mobWalkRects[2] = heroWalkRects[2]; + addAnim(mob, mobWalkRects, numRects, duration); + } INTERNAL void parseInput(GameState *state, const f32 dt) @@ -406,18 +422,63 @@ void worldTraveller_gameUpdateAndRender(GameState *state, const f32 dt) if (cameraBounds.w <= world->bounds.w) cameraBounds.w = world->bounds.w; + Font *font = &assetManager->font; for (i32 i = 0; i < world->freeEntityIndex; i++) { Entity *const entity = &world->entities[i]; renderer_entity(&state->renderer, cameraBounds, entity, dt, 0.0f, V4(1, 1, 1, 1)); + +#ifdef DENGINE_DEBUG + 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->size); + i32 indexOfLowerAInMetrics = 'a' - font->codepointRange.x; + strPos.y += font->charMetrics[indexOfLowerAInMetrics].offset.y; + + renderer_string(&state->renderer, cameraBounds, font, debugString, + strPos, 0, color); + + f32 stringLineGap = 1.1f * asset_getVFontSpacing(font->metrics); + strPos.y -= GLOBAL_debugState.stringLineGap; + + char entityPosStr[256]; + snprintf(entityPosStr, ARRAY_COUNT(entityPosStr), "%06.2f, %06.2f", + entity->pos.x, entity->pos.y); + renderer_string(&state->renderer, cameraBounds, font, entityPosStr, + strPos, 0, color); + } +#endif + } // TODO(doyle): Clean up lines // Renderer::~Renderer() { glDeleteVertexArrays(1, &this->quadVAO); } #ifdef DENGINE_DEBUG - Font *font = &assetManager->font; Entity *hero = &world->entities[world->heroIndex]; DEBUG_PUSH_STRING("Hero Pos: %06.2f, %06.2f", &hero->pos, "v2"); DEBUG_PUSH_STRING("Hero dPos: %06.2f, %06.2f", &hero->dPos, "v2"); diff --git a/src/include/Dengine/Entity.h b/src/include/Dengine/Entity.h index 8cf2dac..719685a 100644 --- a/src/include/Dengine/Entity.h +++ b/src/include/Dengine/Entity.h @@ -19,6 +19,7 @@ enum EntityType entitytype_null, entitytype_hero, entitytype_npc, + entitytype_mob, entitytype_tile, entitytype_count, }; diff --git a/src/include/Dengine/Renderer.h b/src/include/Dengine/Renderer.h index e8fa585..6fe9303 100644 --- a/src/include/Dengine/Renderer.h +++ b/src/include/Dengine/Renderer.h @@ -19,8 +19,17 @@ typedef struct RenderQuad v4 vertex[4]; } RenderQuad; -void renderer_string(Renderer *const renderer, Font *const font, - const char *const string, v2 pos, f32 rotate, v4 color); +void renderer_string(Renderer *const renderer, v4 cameraBounds, + Font *const font, const char *const string, 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) +{ + renderer_string(renderer, V4(0, renderer->size.h, renderer->size.w, 0), + font, string, pos, rotate, color); +} void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, f32 dt, f32 rotate, v4 color);