From ec7a9e41ff12eed13d65d3daa52a6cf6506880ba Mon Sep 17 00:00:00 2001 From: Doyle Thai Date: Wed, 21 Sep 2016 19:21:27 +1000 Subject: [PATCH] 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. --- src/Renderer.c | 85 ++++++++++++++++++++++++++++------ src/WorldTraveller.c | 21 +++------ src/include/Dengine/Renderer.h | 34 +++++++++++--- 3 files changed, 106 insertions(+), 34 deletions(-) diff --git a/src/Renderer.c b/src/Renderer.c index 44f151f..c62cb64 100644 --- a/src/Renderer.c +++ b/src/Renderer.c @@ -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; + } } } diff --git a/src/WorldTraveller.c b/src/WorldTraveller.c index 2718bb7..149391f 100644 --- a/src/WorldTraveller.c +++ b/src/WorldTraveller.c @@ -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,22 +2071,15 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) { entity_updateAnim(eventQueue, entity, dt); /* Calculate region to render */ - - 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)); - } + renderer_entity(renderer, camera, entity, + v2_scale(entity->size, 0.5f), 0, V4(1, 1, 1, 1.0f)); } } +#if RENDERER_USE_RENDER_GROUPS + renderer_renderGroups(renderer); +#endif + /* ***************************************** * Process Events From Entity Update Loop diff --git a/src/include/Dengine/Renderer.h b/src/include/Dengine/Renderer.h index 209662a..4f9589e 100644 --- a/src/include/Dengine/Renderer.h +++ b/src/include/Dengine/Renderer.h @@ -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