From f6ada44b41d591c93bea28aa044ffb31fedfcdcd Mon Sep 17 00:00:00 2001 From: Doyle Thai Date: Fri, 8 Jul 2016 21:06:43 +1000 Subject: [PATCH] Add rudimentary camera and side scrolling support --- src/Renderer.c | 21 +++- src/WorldTraveller.c | 100 +++++++++++--------- src/include/Dengine/Entity.h | 1 - src/include/Dengine/Renderer.h | 4 +- src/include/WorldTraveller/WorldTraveller.h | 2 + 5 files changed, 76 insertions(+), 52 deletions(-) diff --git a/src/Renderer.c b/src/Renderer.c index 3b11851..a7ec7ca 100644 --- a/src/Renderer.c +++ b/src/Renderer.c @@ -80,12 +80,18 @@ void renderer_debugString(Renderer *const renderer, Font *const font, debugRenderer.stringPos.y -= (0.9f * asset_getVFontSpacing(font->metrics)); } -void renderer_entity(Renderer *renderer, Entity *entity, f32 dt, f32 rotate, +void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, f32 dt, f32 rotate, v3 color) { // TODO(doyle): Batch into render groups - if ((entity->pos.x < renderer->size.w && entity->pos.x >= 0) && - (entity->pos.y < renderer->size.h && entity->pos.y >= 0)) + + // NOTE(doyle): Pos + Size since the origin of an entity is it's bottom left + // corner. Add the two together so that the clipping point is the far right + // side of the entity + v2 rightAlignedP = v2_add(entity->pos, entity->size); + v2 leftAlignedP = entity->pos; + if ((leftAlignedP.x < cameraBounds.z && rightAlignedP.x >= cameraBounds.x) && + (leftAlignedP.y < cameraBounds.y && rightAlignedP.y >= cameraBounds.w)) { EntityAnim *anim = &entity->anim[entity->currAnimIndex]; v4 texRect = anim->rect[anim->currRectIndex]; @@ -107,8 +113,13 @@ void renderer_entity(Renderer *renderer, Entity *entity, f32 dt, f32 rotate, RenderQuad entityQuad = renderer_createDefaultQuad(renderer, texRect, entity->tex); updateBufferObject(renderer, &entityQuad, 1); - renderer_object(renderer, entity->pos, entity->size, rotate, color, - entity->tex); + + // NOTE(doyle): The camera origin is 0,0 in world positions + v2 offsetFromCamOrigin = V2(cameraBounds.x, cameraBounds.w); + v2 entityRelativeToCamera = v2_sub(entity->pos, offsetFromCamOrigin); + + renderer_object(renderer, entityRelativeToCamera, entity->size, rotate, + color, entity->tex); } } diff --git a/src/WorldTraveller.c b/src/WorldTraveller.c index d06c1ad..b5e327d 100644 --- a/src/WorldTraveller.c +++ b/src/WorldTraveller.c @@ -6,8 +6,9 @@ //choose to load assets outside of WorldTraveller! #include -INTERNAL Entity *addEntity(World *world, v2 pos, v2 size, enum EntityType type, - enum Direction direction, Texture *tex, b32 collides) +INTERNAL Entity *addEntity(World *world, v2 pos, v2 size, + enum EntityType type, enum Direction direction, + Texture *tex, b32 collides) { #ifdef WT_DEBUG @@ -74,6 +75,42 @@ void worldTraveller_gameInit(GameState *state, v2i windowSize) state->currWorldIndex = 0; state->tileSize = 64; + /* Init renderer */ + Renderer *renderer = &state->renderer; + renderer->size = V2(CAST(f32) windowSize.x, CAST(f32) windowSize.y); + // NOTE(doyle): Value to map a screen coordinate to NDC coordinate + renderer->vertexNdcFactor = + V2(1.0f / renderer->size.w, 1.0f / renderer->size.h); + renderer->shader = asset_getShader(assetManager, shaderlist_sprite); + shader_use(renderer->shader); + + const mat4 projection = + mat4_ortho(0.0f, renderer->size.w, 0.0f, renderer->size.h, 0.0f, 1.0f); + shader_uniformSetMat4fv(renderer->shader, "projection", projection); + glCheckError(); + + /* Create buffers */ + glGenVertexArrays(1, &renderer->vao); + glGenBuffers(1, &renderer->vbo); + glCheckError(); + + /* Bind buffers */ + glBindBuffer(GL_ARRAY_BUFFER, renderer->vbo); + glBindVertexArray(renderer->vao); + + /* Configure VAO */ + const GLuint numVertexElements = 4; + const GLuint vertexSize = sizeof(v4); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, numVertexElements, GL_FLOAT, GL_FALSE, vertexSize, + (GLvoid *)0); + glCheckError(); + + /* Unbind */ + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + glCheckError(); + /* Init world */ const i32 targetWorldWidth = 500 * METERS_TO_PIXEL; const i32 targetWorldHeight = 15 * METERS_TO_PIXEL; @@ -120,12 +157,14 @@ void worldTraveller_gameInit(GameState *state, v2i windowSize) } World *const world = &state->world[state->currWorldIndex]; + world->cameraPos = V2(0.0f, 0.0f); /* Init hero entity */ world->heroIndex = world->freeEntityIndex; - v2 pos = V2(0.0f, 0.0f); v2 size = V2(58.0f, 98.0f); + v2 pos = V2(((renderer->size.w * 0.5f) - (size.w * 0.5f)), + CAST(f32) state->tileSize); enum EntityType type = entitytype_hero; enum Direction dir = direction_east; Texture *tex = asset_getTexture(assetManager, texlist_hero); @@ -133,15 +172,15 @@ void worldTraveller_gameInit(GameState *state, v2i windowSize) Entity *hero = addEntity(world, pos, size, type, dir, tex, collides); /* Add idle animation */ - f32 duration = 1.0f; - i32 numRects = 1; + f32 duration = 1.0f; + i32 numRects = 1; v4 *heroIdleRects = CAST(v4 *) calloc(numRects, sizeof(v4)); heroIdleRects[0] = V4(746.0f, 1018.0f, 804.0f, 920.0f); addAnim(hero, heroIdleRects, numRects, duration); /* Add walking animation */ - duration = 0.10f; - numRects = 3; + duration = 0.10f; + numRects = 3; v4 *heroWalkRects = CAST(v4 *) calloc(numRects, sizeof(v4)); heroWalkRects[0] = V4(641.0f, 1018.0f, 699.0f, 920.0f); heroWalkRects[1] = V4(746.0f, 1018.0f, 804.0f, 920.0f); @@ -175,42 +214,6 @@ void worldTraveller_gameInit(GameState *state, v2i windowSize) npcWavingRects[1] = V4(944.0f, 812.0f, 1010.0f, 710.0f); addAnim(npc, npcWavingRects, numRects, duration); - /* Init renderer */ - Renderer *renderer = &state->renderer; - renderer->size = V2(CAST(f32)windowSize.x, CAST(f32)windowSize.y); - // NOTE(doyle): Value to map a screen coordinate to NDC coordinate - renderer->vertexNdcFactor = - V2(1.0f / renderer->size.w, 1.0f / renderer->size.h); - renderer->shader = asset_getShader(assetManager, shaderlist_sprite); - shader_use(renderer->shader); - - const mat4 projection = - mat4_ortho(0.0f, renderer->size.w, 0.0f, renderer->size.h, 0.0f, 1.0f); - shader_uniformSetMat4fv(renderer->shader, "projection", projection); - glCheckError(); - - /* Create buffers */ - glGenVertexArrays(1, &renderer->vao); - glGenBuffers(1, &renderer->vbo); - glCheckError(); - - /* Bind buffers */ - glBindBuffer(GL_ARRAY_BUFFER, renderer->vbo); - glBindVertexArray(renderer->vao); - - /* Configure VAO */ - const GLuint numVertexElements = 4; - const GLuint vertexSize = sizeof(v4); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, numVertexElements, GL_FLOAT, GL_FALSE, vertexSize, - (GLvoid *)0); - glCheckError(); - - /* Unbind */ - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - glCheckError(); - } INTERNAL void parseInput(GameState *state, const f32 dt) @@ -346,6 +349,13 @@ INTERNAL void parseInput(GameState *state, const f32 dt) // f'(t) = curr velocity = a*t + v, where v is old velocity hero->dPos = v2_add(hero->dPos, v2_scale(ddPos, dt)); hero->pos = newHeroP; + + v2 offsetFromHeroToOrigin = + V2((hero->pos.x - (0.5f * state->renderer.size.w)), (0.0f)); + + // NOTE(doyle): Hero position is offset to the center so -recenter it + offsetFromHeroToOrigin.x += (hero->size.x * 0.5f); + world->cameraPos = offsetFromHeroToOrigin; } } @@ -362,10 +372,12 @@ void worldTraveller_gameUpdateAndRender(GameState *state, const f32 dt) /* Render entities */ ASSERT(world->freeEntityIndex < world->maxEntities); + v4 cameraBounds = getRect(world->cameraPos, renderer->size); for (i32 i = 0; i < world->freeEntityIndex; i++) { Entity *const entity = &world->entities[i]; - renderer_entity(&state->renderer, entity, dt, 0.0f, V3(0, 0, 0)); + renderer_entity(&state->renderer, cameraBounds, entity, dt, 0.0f, + V3(0, 0, 0)); } // TODO(doyle): Clean up lines diff --git a/src/include/Dengine/Entity.h b/src/include/Dengine/Entity.h index 4259c42..8cf2dac 100644 --- a/src/include/Dengine/Entity.h +++ b/src/include/Dengine/Entity.h @@ -18,7 +18,6 @@ enum EntityType { entitytype_null, entitytype_hero, - entitytype_camera, entitytype_npc, entitytype_tile, entitytype_count, diff --git a/src/include/Dengine/Renderer.h b/src/include/Dengine/Renderer.h index 3b51598..db75a85 100644 --- a/src/include/Dengine/Renderer.h +++ b/src/include/Dengine/Renderer.h @@ -40,8 +40,8 @@ void renderer_string(Renderer *const renderer, Font *const font, void renderer_debugString(Renderer *const renderer, Font *const font, const char *const string); -void renderer_entity(Renderer *renderer, Entity *entity, f32 dt, f32 rotate, - v3 color); +void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, + f32 dt, f32 rotate, v3 color); void renderer_object(Renderer *renderer, v2 pos, v2 size, f32 rotate, v3 color, Texture *tex); diff --git a/src/include/WorldTraveller/WorldTraveller.h b/src/include/WorldTraveller/WorldTraveller.h index 8d572e4..50808bd 100644 --- a/src/include/WorldTraveller/WorldTraveller.h +++ b/src/include/WorldTraveller/WorldTraveller.h @@ -22,6 +22,8 @@ typedef struct World enum TexList texType; + v2 cameraPos; + i32 heroIndex; i32 freeEntityIndex;