Add rudimentary camera and side scrolling support

This commit is contained in:
Doyle Thai 2016-07-08 21:06:43 +10:00
parent ad48dd5062
commit f6ada44b41
5 changed files with 76 additions and 52 deletions

View File

@ -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);
}
}

View File

@ -6,8 +6,9 @@
//choose to load assets outside of WorldTraveller!
#include <stdlib.h>
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

View File

@ -18,7 +18,6 @@ enum EntityType
{
entitytype_null,
entitytype_hero,
entitytype_camera,
entitytype_npc,
entitytype_tile,
entitytype_count,

View File

@ -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);

View File

@ -22,6 +22,8 @@ typedef struct World
enum TexList texType;
v2 cameraPos;
i32 heroIndex;
i32 freeEntityIndex;