Convert debug UI overlays to uilabel

uiconsole, uifps, and uiplayerpos now render through uilabel instead
of calling textDraw per character every frame. Each owns its label(s)
plus backing text/sprite buffers and marks them dirty only when their
content or position actually changes. Also drops console.h's per-line
buffer from 512 to 128 chars, since the sprite cache backing each
console line label scales with it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-20 12:43:43 -05:00
parent af4cb53e5f
commit 52d1e7414d
7 changed files with 137 additions and 43 deletions
+1 -1
View File
@@ -10,7 +10,7 @@
#include "dusk.h" #include "dusk.h"
#include "thread/thread.h" #include "thread/thread.h"
#define CONSOLE_LINE_MAX 512 #define CONSOLE_LINE_MAX 128
#define CONSOLE_HISTORY_MAX 16 #define CONSOLE_HISTORY_MAX 16
#define CONSOLE_EXEC_BUFFER_MAX 32 #define CONSOLE_EXEC_BUFFER_MAX 32
+20 -9
View File
@@ -6,23 +6,34 @@
*/ */
#include "uiconsole.h" #include "uiconsole.h"
#include "console/console.h"
#include "display/screen/screen.h" #include "display/screen/screen.h"
#include "display/text/text.h" #include "display/text/text.h"
#include "display/spritebatch/spritebatch.h" #include "display/spritebatch/spritebatch.h"
uiconsole_t UICONSOLE;
errorret_t uiConsoleInit(void) {
float_t lineH = (float_t)FONT_DEFAULT.tileset->tileHeight;
for(uint32_t i = 0; i < CONSOLE_HISTORY_MAX; i++) {
uiLabelInit(
&UICONSOLE.labels[i],
CONSOLE.line[i],
UICONSOLE.sprites[i], CONSOLE_LINE_MAX
);
uiLabelSetX(&UICONSOLE.labels[i], (float_t)SCREEN.scanX);
uiLabelSetY(&UICONSOLE.labels[i], (float_t)SCREEN.scanY + lineH * (float_t)i);
}
errorOk();
}
errorret_t uiConsoleDraw(void) { errorret_t uiConsoleDraw(void) {
if(!CONSOLE.visible) errorOk(); if(!CONSOLE.visible) errorOk();
float_t lineH = (float_t)FONT_DEFAULT.tileset->tileHeight;
for(uint32_t i = 0; i < CONSOLE_HISTORY_MAX; i++) { for(uint32_t i = 0; i < CONSOLE_HISTORY_MAX; i++) {
errorChain(textDraw( UICONSOLE.labels[i].dirty = true;
(float_t)SCREEN.scanX, errorChain(uiLabelRender(&UICONSOLE.labels[i], COLOR_RED));
(float_t)SCREEN.scanY + lineH * (float_t)i,
CONSOLE.line[i],
COLOR_RED,
&FONT_DEFAULT
));
} }
return spriteBatchFlush(); return spriteBatchFlush();
} }
+16
View File
@@ -7,6 +7,22 @@
#pragma once #pragma once
#include "error/error.h" #include "error/error.h"
#include "console/console.h"
#include "ui/widget/uilabel.h"
typedef struct {
uilabel_t labels[CONSOLE_HISTORY_MAX];
spritebatchsprite_t sprites[CONSOLE_HISTORY_MAX][CONSOLE_LINE_MAX];
} uiconsole_t;
extern uiconsole_t UICONSOLE;
/**
* Initializes the console's history labels.
*
* @return Any error that occurs.
*/
errorret_t uiConsoleInit(void);
/** /**
* Renders the console history into the scan-safe area. * Renders the console history into the scan-safe area.
+35 -21
View File
@@ -7,16 +7,42 @@
#include "uifps.h" #include "uifps.h"
#include "time/time.h" #include "time/time.h"
#include "util/string.h"
#include "display/spritebatch/spritebatch.h" #include "display/spritebatch/spritebatch.h"
#include "display/text/text.h" #include "display/color.h"
#include "display/screen/screen.h" #include "display/screen/screen.h"
#include "engine/engine.h" #include "engine/engine.h"
uifps_t UIFPS; uifps_t UIFPS;
errorret_t uiFPSDraw() { errorret_t uiFPSInit() {
char_t fpsText[32]; uiLabelInit(
&UIFPS.fpsLabel,
UIFPS.fpsText,
UIFPS.fpsSprites, UI_FPS_SPRITES_MAX
);
uiLabelSetX(&UIFPS.fpsLabel, (float_t)SCREEN.scanX);
uiLabelSetY(&UIFPS.fpsLabel, (float_t)SCREEN.scanY);
uiLabelInit(
&UIFPS.versionLabel,
UIFPS.versionText,
UIFPS.versionSprites, UI_FPS_VERSION_SPRITES_MAX
);
stringCopy(UIFPS.versionText, ENGINE.version, UI_FPS_VERSION_TEXT_MAX - 1);
UIFPS.versionLabel.dirty = true;
uiLabelRebuffer(&UIFPS.versionLabel);
uiLabelSetX(&UIFPS.versionLabel, (float_t)(
SCREEN.scanX + SCREEN.scanWidth - UIFPS.versionLabel.width
));
uiLabelSetY(&UIFPS.versionLabel, (float_t)(
SCREEN.scanY + SCREEN.scanHeight - UIFPS.versionLabel.height
));
errorOk();
}
errorret_t uiFPSDraw() {
// Get now. // Get now.
dusktimeepoch_t now = timeGetEpoch(); dusktimeepoch_t now = timeGetEpoch();
double_t delta = now.time - UIFPS.lastTick.time; double_t delta = now.time - UIFPS.lastTick.time;
@@ -33,13 +59,14 @@ errorret_t uiFPSDraw() {
UIFPS.fpsAverage = alpha * fps + (1.0f - alpha) * UIFPS.fpsAverage; UIFPS.fpsAverage = alpha * fps + (1.0f - alpha) * UIFPS.fpsAverage;
} }
snprintf( stringFormat(
fpsText, UIFPS.fpsText,
sizeof(fpsText), UI_FPS_TEXT_MAX - 1,
"%.1f/%.1fms", "%.1f/%.1fms",
UIFPS.fpsAverage, UIFPS.fpsAverage,
delta * 1000.0f delta * 1000.0f
); );
UIFPS.fpsLabel.dirty = true;
color_t textColor; color_t textColor;
if(fps >= 55.0f) { if(fps >= 55.0f) {
@@ -50,23 +77,10 @@ errorret_t uiFPSDraw() {
textColor = COLOR_RED; textColor = COLOR_RED;
} }
errorChain(textDraw( errorChain(uiLabelRender(&UIFPS.fpsLabel, textColor));
(float_t)SCREEN.scanX,
(float_t)SCREEN.scanY,
fpsText, textColor,
&FONT_DEFAULT
));
errorChain(spriteBatchFlush()); errorChain(spriteBatchFlush());
int32_t versionWidth, versionHeight; errorChain(uiLabelRender(&UIFPS.versionLabel, color(255, 255, 255, 128)));
textMeasure(ENGINE.version, &FONT_DEFAULT, &versionWidth, &versionHeight);
errorChain(textDraw(
(float_t)(SCREEN.scanX + SCREEN.scanWidth - versionWidth),
(float_t)(SCREEN.scanY + SCREEN.scanHeight - versionHeight),
ENGINE.version,
color(255, 255, 255, 128),
&FONT_DEFAULT
));
return spriteBatchFlush(); return spriteBatchFlush();
} }
+21
View File
@@ -8,14 +8,35 @@
#pragma once #pragma once
#include "error/error.h" #include "error/error.h"
#include "time/timeepoch.h" #include "time/timeepoch.h"
#include "ui/widget/uilabel.h"
#define UI_FPS_TEXT_MAX 32
#define UI_FPS_SPRITES_MAX UI_FPS_TEXT_MAX
#define UI_FPS_VERSION_TEXT_MAX 32
#define UI_FPS_VERSION_SPRITES_MAX UI_FPS_VERSION_TEXT_MAX
typedef struct { typedef struct {
dusktimeepoch_t lastTick; dusktimeepoch_t lastTick;
float_t fpsAverage; float_t fpsAverage;
uilabel_t fpsLabel;
char_t fpsText[UI_FPS_TEXT_MAX];
spritebatchsprite_t fpsSprites[UI_FPS_SPRITES_MAX];
uilabel_t versionLabel;
char_t versionText[UI_FPS_VERSION_TEXT_MAX];
spritebatchsprite_t versionSprites[UI_FPS_VERSION_SPRITES_MAX];
} uifps_t; } uifps_t;
extern uifps_t UIFPS; extern uifps_t UIFPS;
/**
* Initializes the FPS counter's labels.
*
* @return Any error that occurs.
*/
errorret_t uiFPSInit();
/** /**
* Draws the FPS counter on the screen, and also does the update (for now). * Draws the FPS counter on the screen, and also does the update (for now).
* *
+22 -9
View File
@@ -6,6 +6,7 @@
*/ */
#include "uiplayerpos.h" #include "uiplayerpos.h"
#include "util/string.h"
#include "display/screen/screen.h" #include "display/screen/screen.h"
#include "display/text/text.h" #include "display/text/text.h"
#include "display/spritebatch/spritebatch.h" #include "display/spritebatch/spritebatch.h"
@@ -13,6 +14,22 @@
#include "rpg/entity/entitytype.h" #include "rpg/entity/entitytype.h"
#include "rpg/overworld/worldpos.h" #include "rpg/overworld/worldpos.h"
uiplayerpos_t UIPLAYERPOS;
errorret_t uiPlayerPosInit() {
uiLabelInit(
&UIPLAYERPOS.label,
UIPLAYERPOS.text,
UIPLAYERPOS.sprites, UI_PLAYERPOS_SPRITES_MAX
);
uiLabelSetX(&UIPLAYERPOS.label, (float_t)SCREEN.scanX);
uiLabelSetY(&UIPLAYERPOS.label, (float_t)SCREEN.scanY +
(float_t)FONT_DEFAULT.tileset->tileHeight
);
errorOk();
}
errorret_t uiPlayerPosDraw() { errorret_t uiPlayerPosDraw() {
entity_t *player = NULL; entity_t *player = NULL;
for(uint8_t i = 0; i < ENTITY_COUNT; i++) { for(uint8_t i = 0; i < ENTITY_COUNT; i++) {
@@ -26,10 +43,9 @@ errorret_t uiPlayerPosDraw() {
chunkpos_t chunkPos; chunkpos_t chunkPos;
worldPosToChunkPos(&player->position, &chunkPos); worldPosToChunkPos(&player->position, &chunkPos);
char_t text[64]; stringFormat(
snprintf( UIPLAYERPOS.text,
text, UI_PLAYERPOS_TEXT_MAX - 1,
sizeof(text),
"%d,%d,%d[%d,%d,%d]", "%d,%d,%d[%d,%d,%d]",
(int_t)player->position.x, (int_t)player->position.x,
(int_t)player->position.y, (int_t)player->position.y,
@@ -38,11 +54,8 @@ errorret_t uiPlayerPosDraw() {
(int_t)chunkPos.y, (int_t)chunkPos.y,
(int_t)chunkPos.z (int_t)chunkPos.z
); );
UIPLAYERPOS.label.dirty = true;
float_t y = (float_t)SCREEN.scanY + errorChain(uiLabelRender(&UIPLAYERPOS.label, COLOR_GREEN));
(float_t)FONT_DEFAULT.tileset->tileHeight;
errorChain(textDraw(
(float_t)SCREEN.scanX, y, text, COLOR_GREEN, &FONT_DEFAULT
));
return spriteBatchFlush(); return spriteBatchFlush();
} }
+19
View File
@@ -7,6 +7,25 @@
#pragma once #pragma once
#include "error/error.h" #include "error/error.h"
#include "ui/widget/uilabel.h"
#define UI_PLAYERPOS_TEXT_MAX 64
#define UI_PLAYERPOS_SPRITES_MAX UI_PLAYERPOS_TEXT_MAX
typedef struct {
uilabel_t label;
char_t text[UI_PLAYERPOS_TEXT_MAX];
spritebatchsprite_t sprites[UI_PLAYERPOS_SPRITES_MAX];
} uiplayerpos_t;
extern uiplayerpos_t UIPLAYERPOS;
/**
* Initializes the player position label.
*
* @return Any error that occurs.
*/
errorret_t uiPlayerPosInit();
/** /**
* Draws the player world and chunk position on screen. * Draws the player world and chunk position on screen.