diff --git a/src/Debug.c b/src/Debug.c index 1ddbf26..608a853 100644 --- a/src/Debug.c +++ b/src/Debug.c @@ -290,21 +290,21 @@ void debug_drawUi(GameState *state, f32 dt) Entity *hero = &world->entities[entity_getIndex(world, world->heroId)]; // TODO(doyle): Dumb copy function from game so we don't expose api - v4 cameraBounds = math_getRect(world->cameraPos, renderer->size); - if (cameraBounds.x <= world->bounds.x) - { - cameraBounds.x = world->bounds.x; - cameraBounds.z = cameraBounds.x + renderer->size.w; - } + Rect camera = {world->cameraPos, renderer->size}; + // NOTE(doyle): Lock camera if it passes the bounds of the world + if (camera.pos.x <= world->bounds.x) + camera.pos.x = world->bounds.x; - if (cameraBounds.y >= world->bounds.y) cameraBounds.y = world->bounds.y; + // TODO(doyle): Do the Y component when we need it + f32 cameraTopBoundInPixels = camera.pos.y + camera.size.h; + if (cameraTopBoundInPixels >= world->bounds.y) + camera.pos.y = (world->bounds.y - camera.size.h); - if (cameraBounds.z >= world->bounds.z) - { - cameraBounds.z = world->bounds.z; - cameraBounds.x = cameraBounds.z - renderer->size.w; - } - if (cameraBounds.w <= world->bounds.w) cameraBounds.w = world->bounds.w; + f32 cameraRightBoundInPixels = camera.pos.x + camera.size.w; + if (cameraRightBoundInPixels >= world->bounds.z) + camera.pos.x = (world->bounds.z - camera.size.w); + + if (camera.pos.y <= world->bounds.w) camera.pos.y = world->bounds.w; Font *font = &GLOBAL_debug.font; if (world->numEntitiesInBattle > 0) @@ -354,7 +354,7 @@ void debug_drawUi(GameState *state, f32 dt) i32 indexOfLowerAInMetrics = 'a' - CAST(i32) font->codepointRange.x; strPos.y += font->charMetrics[indexOfLowerAInMetrics].offset.y; - renderer_string(&state->renderer, &state->arena, cameraBounds, font, + renderer_string(&state->renderer, &state->arena, camera, font, debugString, strPos, V2(0, 0), 0, color); f32 stringLineGap = 1.1f * asset_getVFontSpacing(font->metrics); @@ -363,14 +363,14 @@ void debug_drawUi(GameState *state, f32 dt) char entityPosStr[128]; snprintf(entityPosStr, ARRAY_COUNT(entityPosStr), "%06.2f, %06.2f", entity->pos.x, entity->pos.y); - renderer_string(&state->renderer, &state->arena, cameraBounds, font, + renderer_string(&state->renderer, &state->arena, camera, font, entityPosStr, strPos, V2(0, 0), 0, color); strPos.y -= GLOBAL_debug.stringLineGap; char entityIDStr[32]; snprintf(entityIDStr, ARRAY_COUNT(entityIDStr), "ID: %4d/%d", entity->id, world->uniqueIdAccumulator-1); - renderer_string(&state->renderer, &state->arena, cameraBounds, font, + renderer_string(&state->renderer, &state->arena, camera, font, entityIDStr, strPos, V2(0, 0), 0, color); if (entity->stats) @@ -379,27 +379,27 @@ void debug_drawUi(GameState *state, f32 dt) char entityHealth[32]; snprintf(entityHealth, ARRAY_COUNT(entityHealth), "HP: %3.0f/%3.0f", entity->stats->health, entity->stats->maxHealth); - renderer_string(&state->renderer, &state->arena, cameraBounds, + renderer_string(&state->renderer, &state->arena, camera, font, entityHealth, strPos, V2(0, 0), 0, color); strPos.y -= GLOBAL_debug.stringLineGap; char entityTimer[32]; snprintf(entityTimer, ARRAY_COUNT(entityTimer), "ATB: %3.0f/%3.0f", entity->stats->actionTimer, entity->stats->actionRate); - renderer_string(&state->renderer, &state->arena, cameraBounds, + renderer_string(&state->renderer, &state->arena, camera, font, entityTimer, strPos, V2(0, 0), 0, color); strPos.y -= GLOBAL_debug.stringLineGap; char entityIdTarget[32]; snprintf(entityIdTarget, ARRAY_COUNT(entityIdTarget), "Targetting ID: %d", entity->stats->entityIdToAttack); - renderer_string(&state->renderer, &state->arena, cameraBounds, + renderer_string(&state->renderer, &state->arena, camera, font, entityIdTarget, strPos, V2(0, 0), 0, color); } strPos.y -= GLOBAL_debug.stringLineGap; char *entityStateStr = debug_entitystate_string(entity->state); - renderer_string(&state->renderer, &state->arena, cameraBounds, font, + renderer_string(&state->renderer, &state->arena, camera, font, entityStateStr, strPos, V2(0, 0), 0, color); if (entity->audioRenderer) @@ -410,7 +410,7 @@ void debug_drawUi(GameState *state, f32 dt) ARRAY_COUNT(entityAudioSourceIndex), "AudioSource Index: %d", entity->audioRenderer->sourceIndex); - renderer_string(&state->renderer, &state->arena, cameraBounds, + renderer_string(&state->renderer, &state->arena, camera, font, entityAudioSourceIndex, strPos, V2(0, 0), 0, color); } diff --git a/src/Renderer.c b/src/Renderer.c index 52391e6..5f4cd04 100644 --- a/src/Renderer.c +++ b/src/Renderer.c @@ -12,6 +12,9 @@ typedef struct RenderQuad { + // Vertex composition + // x, y: Coordinates + // z, w: Texture Coords v4 vertex[4]; } RenderQuad; @@ -140,6 +143,14 @@ INTERNAL void renderObject(Renderer *renderer, v2 pos, v2 size, v2 pivotPoint, GL_CHECK_ERROR(); } +INTERNAL v2 mapWorldToCameraSpace(v2 worldPos, v4 cameraBounds) +{ + // Convert the world position to the camera coordinate system + v2 cameraBottomLeftBound = V2(cameraBounds.x, cameraBounds.w); + v2 posInCameraSpace = v2_sub(worldPos, cameraBottomLeftBound); + return posInCameraSpace; +} + RenderTex renderer_createNullRenderTex(AssetManager *assetManager) { Texture *emptyTex = asset_getTexture(assetManager, texlist_empty); @@ -147,25 +158,22 @@ RenderTex renderer_createNullRenderTex(AssetManager *assetManager) return result; } -void renderer_rect(Renderer *const renderer, v4 cameraBounds, v2 pos, v2 size, +void renderer_rect(Renderer *const renderer, Rect camera, v2 pos, v2 size, v2 pivotPoint, f32 rotate, RenderTex renderTex, v4 color) { RenderQuad quad = createDefaultTexQuad(renderer, renderTex); updateBufferObject(renderer, &quad, 1); - // NOTE(doyle): Get the origin of cameraBounds in world space, bottom left - v2 offsetFromCamOrigin = V2(cameraBounds.x, cameraBounds.w); - v2 rectRelativeToCamera = v2_sub(pos, offsetFromCamOrigin); - renderObject(renderer, rectRelativeToCamera, size, pivotPoint, rotate, + v2 posInCameraSpace = v2_sub(pos, camera.pos); + renderObject(renderer, posInCameraSpace, size, pivotPoint, rotate, color, renderTex.tex); } -void renderer_string(Renderer *const renderer, MemoryArena *arena, - v4 cameraBounds, Font *const font, - const char *const string, v2 pos, v2 pivotPoint, - f32 rotate, v4 color) +void renderer_string(Renderer *const renderer, MemoryArena *arena, Rect camera, + Font *const font, const char *const string, v2 pos, + v2 pivotPoint, f32 rotate, v4 color) { - i32 strLen = common_strlen(string); + i32 strLen = common_strlen(string); // TODO(doyle): Scale, not too important .. but rudimentary infrastructure // laid out here f32 scale = 1.0f; @@ -177,16 +185,15 @@ void renderer_string(Renderer *const renderer, MemoryArena *arena, v2_add(pos, V2(scale *(CAST(f32) font->maxSize.w * CAST(f32) strLen), scale * 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)) + if (math_pointInRect(camera, leftAlignedP) || + math_pointInRect(camera, rightAlignedP)) { i32 quadIndex = 0; RenderQuad *stringQuads = PLATFORM_MEM_ALLOC(arena, strLen, RenderQuad); - v2 offsetFromCamOrigin = V2(cameraBounds.x, cameraBounds.w); - v2 entityRelativeToCamera = v2_sub(pos, offsetFromCamOrigin); + v2 posInCameraSpace = v2_sub(pos, camera.pos); - pos = entityRelativeToCamera; + pos = posInCameraSpace; f32 baseline = pos.y; for (i32 i = 0; i < strLen; i++) { @@ -223,7 +230,7 @@ void renderer_string(Renderer *const renderer, MemoryArena *arena, } } -void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, +void renderer_entity(Renderer *renderer, Rect camera, Entity *entity, v2 pivotPoint, f32 rotate, v4 color) { // TODO(doyle): Batch into render groups @@ -233,8 +240,8 @@ void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, // side of the entity v2 rightAlignedP = v2_add(entity->pos, entity->hitboxSize); v2 leftAlignedP = entity->pos; - if ((leftAlignedP.x < cameraBounds.z && rightAlignedP.x >= cameraBounds.x) && - (leftAlignedP.y < cameraBounds.y && rightAlignedP.y >= cameraBounds.w)) + if (math_pointInRect(camera, leftAlignedP) || + math_pointInRect(camera, rightAlignedP)) { EntityAnim_ *entityAnim = &entity->anim[entity->currAnimId]; Animation *anim = entityAnim->anim; @@ -252,10 +259,8 @@ void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, createDefaultTexQuad(renderer, renderTex); updateBufferObject(renderer, &entityQuad, 1); - v2 offsetFromCamOrigin = V2(cameraBounds.x, cameraBounds.w); - v2 entityRelativeToCamera = v2_sub(entity->pos, offsetFromCamOrigin); - - renderObject(renderer, entityRelativeToCamera, entity->renderSize, + v2 posInCameraSpace = v2_sub(entity->pos, camera.pos); + renderObject(renderer, posInCameraSpace, entity->renderSize, pivotPoint, rotate, color, entity->tex); } } diff --git a/src/WorldTraveller.c b/src/WorldTraveller.c index 95d03ba..c288f5c 100644 --- a/src/WorldTraveller.c +++ b/src/WorldTraveller.c @@ -234,7 +234,7 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize) v2 worldDimensionInTiles = V2i(targetWorldWidth / state->tileSize, targetWorldHeight / state->tileSize); #else - v2 worldDimensionInTiles = V2i(CAST(i32) windowSize.w / state->tileSize, + v2 worldDimensionInTiles = V2i(CAST(i32) (windowSize.w / state->tileSize) * 2, CAST(i32) windowSize.h / state->tileSize); #endif @@ -510,27 +510,24 @@ INTERNAL void parseInput(GameState *state, const f32 dt) } } -INTERNAL v4 createCameraBounds(World *world, v2 size) +INTERNAL Rect createWorldBoundedCamera(World *world, v2 size) { - v4 result = math_getRect(world->cameraPos, size); + Rect camera = {world->cameraPos, size}; // NOTE(doyle): Lock camera if it passes the bounds of the world - if (result.x <= world->bounds.x) - { - result.x = world->bounds.x; - result.z = result.x + size.w; - } + if (camera.pos.x <= world->bounds.x) + camera.pos.x = world->bounds.x; // TODO(doyle): Do the Y component when we need it - if (result.y >= world->bounds.y) result.y = world->bounds.y; + f32 cameraTopBoundInPixels = camera.pos.y + camera.size.h; + if (cameraTopBoundInPixels >= world->bounds.y) + camera.pos.y = (world->bounds.y - camera.size.h); - if (result.z >= world->bounds.z) - { - result.z = world->bounds.z; - result.x = result.z - size.w; - } + f32 cameraRightBoundInPixels = camera.pos.x + camera.size.w; + if (cameraRightBoundInPixels >= world->bounds.z) + camera.pos.x = (world->bounds.z - camera.size.w); - if (result.w <= world->bounds.w) result.w = world->bounds.w; - return result; + if (camera.pos.y <= world->bounds.w) camera.pos.y = world->bounds.w; + return camera; } #define ENTITY_IN_BATTLE TRUE @@ -876,24 +873,10 @@ INTERNAL void sortWorldEntityList(World *world, i32 numDeadEntities) world->freeEntityIndex -= numDeadEntities; } -INTERNAL b32 pointInRect(Rect rect, v2 point) -{ - b32 outsideOfRectX = FALSE; - if (point.x < rect.pos.x || point.x > (rect.pos.x + rect.size.w)) - outsideOfRectX = TRUE; - - b32 outsideOfRectY = FALSE; - if (point.y < rect.pos.y || point.y > (rect.pos.y + rect.size.h)) - outsideOfRectY = TRUE; - - if (outsideOfRectX || outsideOfRectY) return FALSE; - else return TRUE; -} - INTERNAL i32 button(UiState *uiState, AssetManager *assetManager, Renderer *renderer, KeyInput input, i32 id, Rect rect) { - if (pointInRect(rect, input.mouseP)) + if (math_pointInRect(rect, input.mouseP)) { DEBUG_PUSH_STRING("POINT IN RECT"); uiState->hotItem = id; @@ -951,8 +934,8 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) * Update entities and render ****************************** */ - EventQueue eventQueue = {0}; - v4 cameraBounds = createCameraBounds(world, renderer->size); + EventQueue eventQueue = {0}; + Rect camera = createWorldBoundedCamera(world, renderer->size); AudioManager *audioManager = &state->audioManager; ASSERT(world->freeEntityIndex < world->maxEntities); for (i32 i = 0; i < world->freeEntityIndex; i++) @@ -1092,7 +1075,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) { entity_updateAnim(entity, dt); /* Calculate region to render */ - renderer_entity(renderer, cameraBounds, entity, V2(0, 0), 0, + renderer_entity(renderer, camera, entity, V2(0, 0), 0, V4(1, 1, 1, 1)); } } @@ -1122,7 +1105,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) // TODO(doyle): Incorporate UI into entity list or it's own list // with a rendering lifetime value renderer_string(renderer, &state->arena, - cameraBounds, font, + camera, font, damageStr, defender->pos, V2(0, 0), 0, V4(1, 1, 1, 1)); @@ -1235,7 +1218,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) v2 heroCenter = v2_add(hero->pos, v2_scale(hero->hitboxSize, 0.5f)); RenderTex renderTex = renderer_createNullRenderTex(assetManager); f32 distance = v2_magnitude(hero->pos, entity->pos); - renderer_rect(&state->renderer, cameraBounds, heroCenter, + renderer_rect(&state->renderer, camera, heroCenter, V2(distance, 2.0f), V2(0, 0), angle, renderTex, V4(1, 0, 0, 1.0f)); } diff --git a/src/include/Dengine/Math.h b/src/include/Dengine/Math.h index 43b7bdb..97a1d01 100644 --- a/src/include/Dengine/Math.h +++ b/src/include/Dengine/Math.h @@ -290,6 +290,21 @@ INTERNAL inline v4 mat4_mul_v4(const mat4 a, const v4 b) return result; } +INTERNAL inline b32 math_pointInRect(Rect rect, v2 point) +{ + b32 outsideOfRectX = FALSE; + if (point.x < rect.pos.x || point.x > (rect.pos.x + rect.size.w)) + outsideOfRectX = TRUE; + + b32 outsideOfRectY = FALSE; + if (point.y < rect.pos.y || point.y > (rect.pos.y + rect.size.h)) + outsideOfRectY = TRUE; + + if (outsideOfRectX || outsideOfRectY) return FALSE; + else return TRUE; +} + + INTERNAL inline v4 math_getRect(v2 origin, v2 size) { v2 upperLeftBound = v2_add(origin, V2(0.0f, size.y)); diff --git a/src/include/Dengine/Renderer.h b/src/include/Dengine/Renderer.h index 3e17e12..91a13b6 100644 --- a/src/include/Dengine/Renderer.h +++ b/src/include/Dengine/Renderer.h @@ -32,20 +32,20 @@ RenderTex renderer_createNullRenderTex(AssetManager *assetManager); // TODO(doyle): Clean up lines // Renderer::~Renderer() { glDeleteVertexArrays(1, &this->quadVAO); } -void renderer_rect(Renderer *const renderer, v4 cameraBounds, v2 pos, v2 size, +void renderer_rect(Renderer *const renderer, Rect camera, v2 pos, v2 size, v2 pivotPoint, f32 rotate, RenderTex renderTex, v4 color); inline void renderer_staticRect(Renderer *const renderer, v2 pos, v2 size, v2 pivotPoint, f32 rotate, RenderTex renderTex, v4 color) { - v4 staticCameraBounds = math_getRect(V2(0, 0), renderer->size); - renderer_rect(renderer, staticCameraBounds, pos, size, pivotPoint, rotate, + Rect staticCamera = {V2(0, 0), renderer->size}; + renderer_rect(renderer, staticCamera, pos, size, pivotPoint, rotate, renderTex, color); } void renderer_string(Renderer *const renderer, MemoryArena *arena, - v4 cameraBounds, Font *const font, + Rect camera, Font *const font, const char *const string, v2 pos, v2 pivotPoint, f32 rotate, v4 color); @@ -53,12 +53,12 @@ inline void renderer_staticString(Renderer *const renderer, MemoryArena *arena, Font *const font, const char *const string, v2 pos, v2 pivotPoint, f32 rotate, v4 color) { - v4 staticCameraBounds = math_getRect(V2(0, 0), renderer->size); - renderer_string(renderer, arena, staticCameraBounds, font, string, pos, + Rect staticCamera = {V2(0, 0), renderer->size}; + renderer_string(renderer, arena, staticCamera, font, string, pos, pivotPoint, rotate, color); } -void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, +void renderer_entity(Renderer *renderer, Rect camera, Entity *entity, v2 pivotPoint, f32 rotate, v4 color); #endif