Begin draft imeplementation of batched rendering

Render all entities with the same texture in one call. Currently only
implemented for humanoid entities. Since we are rendering using triangle strips,
between entities there is invalid rastered data between entities. Using
degenerate triangles this may be mitigated, by indicating to OGL which triangles
it can skip in the rendering process.
This commit is contained in:
Doyle Thai 2016-09-21 19:21:27 +10:00
parent 7cb13b3cf8
commit ec7a9e41ff
3 changed files with 106 additions and 34 deletions

View File

@ -10,13 +10,39 @@
#define RENDER_BOUNDING_BOX FALSE
typedef struct RenderQuad
INTERNAL addToRenderGroup(Renderer *renderer, Texture *texture,
RenderQuad renderQuad)
{
// Vertex composition
// x, y: Coordinates
// z, w: Texture Coords
v4 vertex[4];
} RenderQuad;
/* Find vacant/matching render group */
RenderGroup *targetGroup = NULL;
for (i32 i = 0; i < ARRAY_COUNT(renderer->groups); i++)
{
RenderGroup *group = &renderer->groups[i];
if (group->tex == NULL || group->tex->id == texture->id)
{
if (!group->tex) group->tex = texture;
targetGroup = &renderer->groups[i];
break;
}
}
/* Valid group, add to the render group for rendering */
if (targetGroup)
{
if (targetGroup->quadIndex < ARRAY_COUNT(targetGroup->quads))
{
targetGroup->quads[targetGroup->quadIndex++] = renderQuad;
}
else
{
// TODO(doyle): Log no remaining render quad slots in group
}
}
else
{
// TODO(doyle): Log no remaining render groups
}
}
INTERNAL inline void flipTexCoord(v4 *texCoords, b32 flipX, b32 flipY)
{
@ -48,6 +74,11 @@ INTERNAL void updateBufferObject(Renderer *const renderer,
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
INTERNAL void bufferRenderGroupToGL(Renderer *renderer, RenderGroup *group)
{
updateBufferObject(renderer, group->quads, group->quadIndex);
}
INTERNAL RenderQuad createTexQuad(Renderer *renderer, v4 quadRect,
RenderTex renderTex)
{
@ -204,9 +235,7 @@ void renderer_string(Renderer *const renderer, MemoryArena *arena, Rect camera,
pos.y = baseline - (charMetric.offset.y);
const v4 charRectOnScreen =
math_getRect(pos, V2(CAST(f32) font->maxSize.w,
CAST(f32) font->maxSize.h));
math_getRect(pos, font->maxSize);
pos.x += charMetric.advance;
/* Get texture out */
@ -254,7 +283,6 @@ void renderer_entity(Renderer *renderer, Rect camera, Entity *entity,
char *frameName = anim->frameList[entityAnim->currFrame];
SubTexture animRect = asset_getAtlasSubTex(anim->atlas, frameName);
// TODO(doyle): Switch to rect
v4 animTexRect = {0};
animTexRect.vec2[0] = animRect.rect.pos;
animTexRect.vec2[1] = v2_add(animRect.rect.pos, animRect.rect.size);
@ -267,13 +295,44 @@ void renderer_entity(Renderer *renderer, Rect camera, Entity *entity,
}
RenderTex renderTex = {entity->tex, animTexRect};
RenderQuad entityQuad =
createDefaultTexQuad(renderer, renderTex);
updateBufferObject(renderer, &entityQuad, 1);
#if RENDERER_USE_RENDER_GROUPS
// TODO(doyle): getRect needs a better name
v2 posInCameraSpace = v2_sub(entity->pos, camera.pos);
v4 entityVertexOnScreen = math_getRect(posInCameraSpace, entity->size);
RenderQuad entityQuad =
createTexQuad(renderer, entityVertexOnScreen, renderTex);
addToRenderGroup(renderer, entity->tex, entityQuad);
#else
RenderQuad entityQuad = createDefaultTexQuad(renderer, renderTex);
// TODO(doyle): getRect needs a better name
updateBufferObject(renderer, &entityQuad, 1);
v2 posInCameraSpace = v2_sub(entity->pos, camera.pos);
renderObject(renderer, posInCameraSpace,
entity->size, pivotPoint,
entity->rotation + rotate, color, entity->tex);
#endif
}
}
void renderer_renderGroups(Renderer *renderer)
{
for (i32 i = 0; i < ARRAY_COUNT(renderer->groups); i++)
{
RenderGroup *currGroup = &renderer->groups[i];
if (currGroup->tex)
{
bufferRenderGroupToGL(renderer, currGroup);
v2 pivotPoint = V2(0, 0);
f32 rotate = 0;
v4 color = V4(1, 1, 1, 1);
renderObject(renderer, V2(0.0f, 0.0f), renderer->size, pivotPoint,
rotate, color, currGroup->tex);
RenderGroup clear = {0};
*currGroup = clear;
}
}
}

View File

@ -640,7 +640,7 @@ INTERNAL void entityInit(GameState *state, v2 windowSize)
entity_addAnim(assetManager, hero, "claudeRipperBlast");
entity_addAnim(assetManager, hero, "claudeAirSlash");
entity_setActiveAnim(eventQueue, hero, "claudeBattleIdle");
entity_setActiveAnim(eventQueue, hero, "claudeIdle");
/* Create a NPC */
pos = V2(hero->pos.x * 3, CAST(f32) state->tileSize);
@ -2071,21 +2071,14 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
{
entity_updateAnim(eventQueue, entity, dt);
/* Calculate region to render */
renderer_entity(renderer, camera, entity,
v2_scale(entity->size, 0.5f), 0, V4(1, 1, 1, 1.0f));
}
}
if (entity->type == entitytype_weapon)
{
renderer_entity(renderer, camera, entity,
v2_scale(entity->size, 0.5f), 0,
V4(1, 1, 1, 1.0f));
}
else
{
renderer_entity(renderer, camera, entity,
v2_scale(entity->size, 0.5f), 0,
V4(1, 1, 1, 1));
}
}
}
#if RENDERER_USE_RENDER_GROUPS
renderer_renderGroups(renderer);
#endif
/*
*****************************************

View File

@ -12,6 +12,28 @@ typedef struct MemoryArena MemoryArena;
typedef struct Shader Shader;
typedef struct Texture Texture;
typedef struct RenderQuad
{
// Vertex composition
// x, y: Coordinates - of entity on screen
// z, w: Texture Coords - of texture for this quad
v4 vertex[4];
} RenderQuad;
typedef struct RenderTex
{
Texture *tex;
// TODO(doyle): Switch to rect
v4 texRect;
} RenderTex;
typedef struct RenderGroup
{
Texture *tex;
RenderQuad quads[100];
i32 quadIndex;
} RenderGroup;
typedef struct Renderer
{
Shader *shader;
@ -20,15 +42,11 @@ typedef struct Renderer
i32 numVertexesInVbo;
v2 vertexNdcFactor;
v2 size;
RenderGroup groups[100];
} Renderer;
typedef struct RenderTex
{
Texture *tex;
// TODO(doyle): Switch to rect
v4 texRect;
} RenderTex;
#define RENDERER_USE_RENDER_GROUPS TRUE
// TODO(doyle): Use z-index occluding for rendering
RenderTex renderer_createNullRenderTex(AssetManager *const assetManager);
@ -64,4 +82,6 @@ inline void renderer_staticString(Renderer *const renderer, MemoryArena *arena,
void renderer_entity(Renderer *renderer, Rect camera, Entity *entity,
v2 pivotPoint, f32 rotate, v4 color);
void renderer_renderGroups(Renderer *renderer);
#endif