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 #define RENDER_BOUNDING_BOX FALSE
typedef struct RenderQuad INTERNAL addToRenderGroup(Renderer *renderer, Texture *texture,
RenderQuad renderQuad)
{ {
// Vertex composition /* Find vacant/matching render group */
// x, y: Coordinates RenderGroup *targetGroup = NULL;
// z, w: Texture Coords for (i32 i = 0; i < ARRAY_COUNT(renderer->groups); i++)
v4 vertex[4]; {
} RenderQuad; 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) 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); 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, INTERNAL RenderQuad createTexQuad(Renderer *renderer, v4 quadRect,
RenderTex renderTex) RenderTex renderTex)
{ {
@ -204,9 +235,7 @@ void renderer_string(Renderer *const renderer, MemoryArena *arena, Rect camera,
pos.y = baseline - (charMetric.offset.y); pos.y = baseline - (charMetric.offset.y);
const v4 charRectOnScreen = const v4 charRectOnScreen =
math_getRect(pos, V2(CAST(f32) font->maxSize.w, math_getRect(pos, font->maxSize);
CAST(f32) font->maxSize.h));
pos.x += charMetric.advance; pos.x += charMetric.advance;
/* Get texture out */ /* Get texture out */
@ -254,7 +283,6 @@ void renderer_entity(Renderer *renderer, Rect camera, Entity *entity,
char *frameName = anim->frameList[entityAnim->currFrame]; char *frameName = anim->frameList[entityAnim->currFrame];
SubTexture animRect = asset_getAtlasSubTex(anim->atlas, frameName); SubTexture animRect = asset_getAtlasSubTex(anim->atlas, frameName);
// TODO(doyle): Switch to rect
v4 animTexRect = {0}; v4 animTexRect = {0};
animTexRect.vec2[0] = animRect.rect.pos; animTexRect.vec2[0] = animRect.rect.pos;
animTexRect.vec2[1] = v2_add(animRect.rect.pos, animRect.rect.size); 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}; 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); v2 posInCameraSpace = v2_sub(entity->pos, camera.pos);
renderObject(renderer, posInCameraSpace, renderObject(renderer, posInCameraSpace,
entity->size, pivotPoint, entity->size, pivotPoint,
entity->rotation + rotate, color, entity->tex); 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, "claudeRipperBlast");
entity_addAnim(assetManager, hero, "claudeAirSlash"); entity_addAnim(assetManager, hero, "claudeAirSlash");
entity_setActiveAnim(eventQueue, hero, "claudeBattleIdle"); entity_setActiveAnim(eventQueue, hero, "claudeIdle");
/* Create a NPC */ /* Create a NPC */
pos = V2(hero->pos.x * 3, CAST(f32) state->tileSize); pos = V2(hero->pos.x * 3, CAST(f32) state->tileSize);
@ -2071,22 +2071,15 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
{ {
entity_updateAnim(eventQueue, entity, dt); entity_updateAnim(eventQueue, entity, dt);
/* Calculate region to render */ /* Calculate region to render */
renderer_entity(renderer, camera, entity,
if (entity->type == entitytype_weapon) v2_scale(entity->size, 0.5f), 0, V4(1, 1, 1, 1.0f));
{
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
/* /*
***************************************** *****************************************
* Process Events From Entity Update Loop * Process Events From Entity Update Loop

View File

@ -12,6 +12,28 @@ typedef struct MemoryArena MemoryArena;
typedef struct Shader Shader; typedef struct Shader Shader;
typedef struct Texture Texture; 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 typedef struct Renderer
{ {
Shader *shader; Shader *shader;
@ -20,15 +42,11 @@ typedef struct Renderer
i32 numVertexesInVbo; i32 numVertexesInVbo;
v2 vertexNdcFactor; v2 vertexNdcFactor;
v2 size; v2 size;
RenderGroup groups[100];
} Renderer; } Renderer;
typedef struct RenderTex #define RENDERER_USE_RENDER_GROUPS TRUE
{
Texture *tex;
// TODO(doyle): Switch to rect
v4 texRect;
} RenderTex;
// TODO(doyle): Use z-index occluding for rendering // TODO(doyle): Use z-index occluding for rendering
RenderTex renderer_createNullRenderTex(AssetManager *const assetManager); 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, void renderer_entity(Renderer *renderer, Rect camera, Entity *entity,
v2 pivotPoint, f32 rotate, v4 color); v2 pivotPoint, f32 rotate, v4 color);
void renderer_renderGroups(Renderer *renderer);
#endif #endif