Refactor isometric block drawing to only update the vertex buffer once

This commit is contained in:
UnknownShadow200 2023-06-06 17:19:22 +10:00
parent 654ce2079b
commit e2798dcebe
3 changed files with 60 additions and 42 deletions

View File

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

View File

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

View File

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