From e2798dcebe5cbdfa3f6cd82fa6c3bfe9c785fc30 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Tue, 6 Jun 2023 17:19:22 +1000 Subject: [PATCH] Refactor isometric block drawing to only update the vertex buffer once --- src/IsometricDrawer.c | 76 +++++++++++++++++++++++++------------------ src/IsometricDrawer.h | 7 ++-- src/Widgets.c | 19 ++++++----- 3 files changed, 60 insertions(+), 42 deletions(-) diff --git a/src/IsometricDrawer.c b/src/IsometricDrawer.c index 753737d18..52a63321a 100644 --- a/src/IsometricDrawer.c +++ b/src/IsometricDrawer.c @@ -10,7 +10,8 @@ static float iso_scale; static struct VertexTextured* iso_vertices; static struct VertexTextured* iso_vertices_base; -static GfxResourceID iso_vb; +static int* iso_state; +static int* iso_state_base; static cc_bool iso_cacheInited; static PackedCol iso_color = PACKEDCOL_WHITE; @@ -23,7 +24,6 @@ static PackedCol iso_colorXSide, iso_colorZSide, iso_colorYBottom; static struct Matrix iso_transform; static Vec3 iso_pos; -static int iso_lastTexIndex, iso_texIndex; static void IsometricDrawer_RotateX(float cosA, float sinA) { float y = cosA * iso_pos.Y + sinA * iso_pos.Z; @@ -50,35 +50,22 @@ static void IsometricDrawer_InitCache(void) { Matrix_Mul(&iso_transform, &rotY, &rotX); } -static void IsometricDrawer_Flush(void) { - int count; - if (iso_lastTexIndex != -1) { - Gfx_BindTexture(Atlas1D.TexIds[iso_lastTexIndex]); - count = (int)(iso_vertices - iso_vertices_base); - Gfx_UpdateDynamicVb_IndexedTris(iso_vb, iso_vertices_base, count); - } - - iso_lastTexIndex = iso_texIndex; - iso_vertices = iso_vertices_base; -} - static TextureLoc IsometricDrawer_GetTexLoc(BlockID block, Face face) { TextureLoc loc = Block_Tex(block, face); - iso_texIndex = Atlas1D_Index(loc); - - if (iso_lastTexIndex != iso_texIndex) IsometricDrawer_Flush(); + *iso_state++ = Atlas1D_Index(loc); return loc; } static void IsometricDrawer_SpriteZQuad(BlockID block, cc_bool firstPart) { + int texIndex; TextureLoc loc = Block_Tex(block, FACE_ZMAX); - TextureRec rec = Atlas1D_TexRec(loc, 1, &iso_texIndex); + TextureRec rec = Atlas1D_TexRec(loc, 1, &texIndex); struct VertexTextured v; float minX, maxX, minY, maxY; float x1, x2; - if (iso_lastTexIndex != iso_texIndex) IsometricDrawer_Flush(); + *iso_state++ = texIndex; v.Col = iso_color; Block_Tint(v.Col, block); @@ -100,14 +87,15 @@ static void IsometricDrawer_SpriteZQuad(BlockID block, cc_bool firstPart) { } static void IsometricDrawer_SpriteXQuad(BlockID block, cc_bool firstPart) { + int texIndex; TextureLoc loc = Block_Tex(block, FACE_XMAX); - TextureRec rec = Atlas1D_TexRec(loc, 1, &iso_texIndex); + TextureRec rec = Atlas1D_TexRec(loc, 1, &texIndex); struct VertexTextured v; float minY, maxY, minZ, maxZ; float z1, z2; - if (iso_lastTexIndex != iso_texIndex) IsometricDrawer_Flush(); + *iso_state++ = texIndex; v.Col = iso_color; Block_Tint(v.Col, block); @@ -128,17 +116,17 @@ static void IsometricDrawer_SpriteXQuad(BlockID block, cc_bool firstPart) { v.Y = minY; v.V = rec.V2; *iso_vertices++ = v; } -void IsometricDrawer_BeginBatch(struct VertexTextured* vertices, GfxResourceID vb) { +void IsometricDrawer_BeginBatch(struct VertexTextured* vertices, int* state) { IsometricDrawer_InitCache(); - iso_lastTexIndex = -1; - iso_vertices = vertices; + iso_vertices = vertices; iso_vertices_base = vertices; - iso_vb = vb; + iso_state = state; + iso_state_base = state; Gfx_LoadMatrix(MATRIX_VIEW, &iso_transform); } -void IsometricDrawer_DrawBatch(BlockID block, float size, float x, float y) { +void IsometricDrawer_AddBatch(BlockID block, float size, float x, float y) { cc_bool bright = Blocks.FullBright[block]; Vec3 min, max; if (Blocks.Draw[block] == DRAW_GAS) return; @@ -185,12 +173,38 @@ void IsometricDrawer_DrawBatch(BlockID block, float size, float x, float y) { } } -void IsometricDrawer_EndBatch(void) { - if (iso_vertices != iso_vertices_base) { - iso_lastTexIndex = iso_texIndex; - IsometricDrawer_Flush(); +static void IsometricDrawer_Render(GfxResourceID vb) { + int curIdx, batchBeg, batchLen; + int count, i; + + count = (int)(iso_vertices - iso_vertices_base); + Gfx_SetDynamicVbData(vb, iso_vertices_base, count); + + curIdx = iso_state_base[0]; + batchLen = 0; + batchBeg = 0; + + for (i = 0; i < count / 4; i++, batchLen += 4) + { + if (iso_state_base[i] == curIdx) continue; + + /* Flush previous batch */ + Gfx_BindTexture(Atlas1D.TexIds[curIdx]); + Gfx_DrawVb_IndexedTris_Range(batchLen, batchBeg); + + /* Reset for next batch */ + curIdx = iso_state_base[i]; + batchBeg = i * 4; + batchLen = 0; } - iso_lastTexIndex = -1; + Gfx_BindTexture(Atlas1D.TexIds[curIdx]); + Gfx_DrawVb_IndexedTris_Range(batchLen, batchBeg); +} + +void IsometricDrawer_EndBatch(GfxResourceID vb) { + if (iso_state != iso_state_base) { + IsometricDrawer_Render(vb); + } Gfx_LoadIdentityMatrix(MATRIX_VIEW); } diff --git a/src/IsometricDrawer.h b/src/IsometricDrawer.h index c3cba75a9..74bfc658c 100644 --- a/src/IsometricDrawer.h +++ b/src/IsometricDrawer.h @@ -8,10 +8,11 @@ struct VertexTextured; /* Maximum number of vertices used to draw a block in isometric way. */ #define ISOMETRICDRAWER_MAXVERTICES 16 + /* Sets up state to begin drawing blocks isometrically. */ -void IsometricDrawer_BeginBatch(struct VertexTextured* vertices, GfxResourceID vb); +void IsometricDrawer_BeginBatch(struct VertexTextured* vertices, int* state); /* Buffers the vertices needed to draw the given block at the given position. */ -void IsometricDrawer_DrawBatch(BlockID block, float size, float x, float y); +void IsometricDrawer_AddBatch(BlockID block, float size, float x, float y); /* Flushes buffered vertices to the GPU, then restores state. */ -void IsometricDrawer_EndBatch(void); +void IsometricDrawer_EndBatch(GfxResourceID vb); #endif diff --git a/src/Widgets.c b/src/Widgets.c index f7da54e37..65e6c1291 100644 --- a/src/Widgets.c +++ b/src/Widgets.c @@ -403,13 +403,15 @@ static void HotbarWidget_RenderHotbarOutline(struct HotbarWidget* w) { Gfx_Draw2DTexture(&w->selTex, PACKEDCOL_WHITE); } +#define HOTBAR_MAX_VERTICES (INVENTORY_BLOCKS_PER_HOTBAR * ISOMETRICDRAWER_MAXVERTICES) static void HotbarWidget_RenderHotbarBlocks(struct HotbarWidget* w) { /* TODO: Should hotbar use its own VB? */ - struct VertexTextured vertices[INVENTORY_BLOCKS_PER_HOTBAR * ISOMETRICDRAWER_MAXVERTICES]; + struct VertexTextured vertices[HOTBAR_MAX_VERTICES]; + int state[HOTBAR_MAX_VERTICES / 4]; float scale; int i, x, y; - IsometricDrawer_BeginBatch(vertices, Models.Vb); + IsometricDrawer_BeginBatch(vertices, state); scale = w->elemSize / 2.0f; for (i = 0; i < INVENTORY_BLOCKS_PER_HOTBAR; i++) { @@ -419,9 +421,9 @@ static void HotbarWidget_RenderHotbarBlocks(struct HotbarWidget* w) { #ifdef CC_BUILD_TOUCH if (i == HOTBAR_MAX_INDEX && Input_TouchMode) continue; #endif - IsometricDrawer_DrawBatch(Inventory_Get(i), scale, x, y); + IsometricDrawer_AddBatch(Inventory_Get(i), scale, x, y); } - IsometricDrawer_EndBatch(); + IsometricDrawer_EndBatch(Models.Vb); } static int HotbarWidget_ScrolledIndex(struct HotbarWidget* w, float delta, int index, int dir) { @@ -700,6 +702,7 @@ void TableWidget_RecreateBlocks(struct TableWidget* w) { static void TableWidget_Render(void* widget, double delta) { struct TableWidget* w = (struct TableWidget*)widget; struct VertexTextured vertices[TABLE_MAX_VERTICES]; + int state[TABLE_MAX_VERTICES / 4]; int cellSizeX, cellSizeY, size; float off; int i, x, y; @@ -732,14 +735,14 @@ static void TableWidget_Render(void* widget, double delta) { } Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED); - IsometricDrawer_BeginBatch(vertices, w->vb); + IsometricDrawer_BeginBatch(vertices, state); for (i = 0; i < w->blocksCount; i++) { if (!TableWidget_GetCoords(w, i, &x, &y)) continue; /* We want to always draw the selected block on top of others */ /* TODO: Need two size arguments, in case X/Y dpi differs */ if (i == w->selectedIndex) continue; - IsometricDrawer_DrawBatch(w->blocks[i], + IsometricDrawer_AddBatch(w->blocks[i], w->normBlockSize, x + cellSizeX / 2, y + cellSizeY / 2); } @@ -747,10 +750,10 @@ static void TableWidget_Render(void* widget, double delta) { if (i != -1) { TableWidget_GetCoords(w, i, &x, &y); - IsometricDrawer_DrawBatch(w->blocks[i], + IsometricDrawer_AddBatch(w->blocks[i], w->selBlockSize, x + cellSizeX / 2, y + cellSizeY / 2); } - IsometricDrawer_EndBatch(); + IsometricDrawer_EndBatch(w->vb); } static void TableWidget_Free(void* widget) {