Custom font rendering.

This commit is contained in:
2025-06-22 18:29:05 -05:00
parent 9b07cf710b
commit c176078df2
8 changed files with 128 additions and 58 deletions

View File

@ -6,14 +6,4 @@
*/
#pragma once
#include "ui/fontdata.h"
#define FONT_HEIGHT 8
#define FONT_WIDTH FONT_HEIGHT
#define FONT_LINE_SPACING 1
#define FONT_LINE_HEIGHT ( \
FONT_HEIGHT + FONT_LINE_SPACING \
)
//
#include "ui/fontdata.h"

View File

@ -20,21 +20,17 @@ void uiTextboxUpdate() {
if(UI_TEXTBOX.visible == false) return;
if(UI_TEXTBOX.charsRevealed < UI_TEXTBOX.pageChars[UI_TEXTBOX.page]) {
if((RENDER_FRAME % 4) == 0) {
UI_TEXTBOX.charsRevealed++;
} else if(inputIsDown(INPUT_BIND_ACTION)) {
UI_TEXTBOX.charsRevealed++;
if(inputIsDown(INPUT_BIND_ACTION)) {
UI_TEXTBOX.charsRevealed++;
}
} else {
if(inputPressed(INPUT_BIND_ACTION)) {
if(UI_TEXTBOX.page < UI_TEXTBOX.pageCount - 1) {
uitextbox_t *textbox = &UI_TEXTBOX;
printf("next page?\n");
UI_TEXTBOX.page++;
UI_TEXTBOX.charsRevealed = 0;
} else {
printf("Closing textbox\n");
// Close the textbox
UI_TEXTBOX.visible = false;
UI_TEXTBOX.page = 0;
@ -45,8 +41,6 @@ void uiTextboxUpdate() {
}
void uiTextboxSetText(const char_t *text) {
uitextbox_t *textbox = &UI_TEXTBOX;
assertNotNull(text, "Text pointer cannot be NULL, call uiTextboxClose()");
memoryZero(UI_TEXTBOX.text, sizeof(UI_TEXTBOX.text));

View File

@ -12,13 +12,13 @@
#define UI_TEXTBOX_LINES_PER_PAGE 4
#define UI_TEXTBOX_WIDTH RENDER_WIDTH
#define UI_TEXTBOX_HEIGHT_INNER ( \
FONT_LINE_HEIGHT * UI_TEXTBOX_LINES_PER_PAGE \
FONT_TILE_HEIGHT * UI_TEXTBOX_LINES_PER_PAGE \
)
#define UI_TEXTBOX_BORDER_WIDTH 4
#define UI_TEXTBOX_BORDER_HEIGHT 4
#define UI_TEXTBOX_PADDING_X 4
#define UI_TEXTBOX_PADDING_Y 4
#define UI_TEXTBOX_BORDER_HEIGHT UI_TEXTBOX_BORDER_WIDTH
#define UI_TEXTBOX_PADDING_X 2
#define UI_TEXTBOX_PADDING_Y UI_TEXTBOX_PADDING_X
#define UI_TEXTBOX_WIDTH_INNER ( \
UI_TEXTBOX_WIDTH - (UI_TEXTBOX_BORDER_WIDTH * 2) - \
(UI_TEXTBOX_PADDING_X * 2) \
@ -28,7 +28,7 @@
(UI_TEXTBOX_PADDING_Y * 2) \
)
#define UI_TEXTBOX_CHARS_PER_LINE (UI_TEXTBOX_WIDTH_INNER / FONT_WIDTH)
#define UI_TEXTBOX_CHARS_PER_LINE (UI_TEXTBOX_WIDTH_INNER / FONT_TILE_WIDTH)
#define UI_TEXTBOX_CHARS_PER_PAGE ( \
UI_TEXTBOX_CHARS_PER_LINE * UI_TEXTBOX_LINES_PER_PAGE \
)
@ -40,6 +40,8 @@
UI_TEXTBOX_CHARS_PER_PAGE * UI_TEXTBOX_PAGE_COUNT_MAX \
)
#define UI_TEXTBOX_REVEAL_RATE 2
typedef struct {
char_t text[UI_TEXTBOX_CHARS_MAX];
uint8_t lineLengths[UI_TEXTBOX_LINE_COUNT];
@ -65,6 +67,11 @@ void uiTextboxInit(void);
*/
void uiTextboxUpdate(void);
/**
* Sets the text for the UI textbox.
*
* @param text The text to display in the textbox.
*/
void uiTextboxSetText(
const char_t *text
);

View File

@ -9,6 +9,7 @@
#include "ui/uitextbox.h"
#include "util/memory.h"
#include "assert/assert.h"
#include "display/render.h"
void drawUIInit(void) {
}
@ -20,22 +21,21 @@ void drawUI() {
void drawUITextbox() {
if(!UI_TEXTBOX.visible) return;
uitextbox_t *textbox = &UI_TEXTBOX;
// Semi-transparent dark blue
Color background = (Color){ 0, 0, 128, 128 };
uint32_t x = 0;
uint32_t y = RENDER_HEIGHT - UI_TEXTBOX_HEIGHT;
DrawRectangle(
0, RENDER_HEIGHT - UI_TEXTBOX_HEIGHT,
x, y,
UI_TEXTBOX_WIDTH, UI_TEXTBOX_HEIGHT,
background
);
BeginBlendMode(BLEND_ALPHA);
if(UI_TEXTBOX.charsRevealed > 0) {
char_t buffer[UI_TEXTBOX_CHARS_PER_LINE + 1];// +1 for null term
uint8_t charsRendered = 0;
uitextbox_t *textbox = &UI_TEXTBOX;
// For each line
for(uint8_t i = 0; i < UI_TEXTBOX_LINES_PER_PAGE; i++) {
@ -55,33 +55,66 @@ void drawUITextbox() {
// Update how many rendered
charsRendered += lineChars;
// Copy string from VN Textbox...
memoryCopy(
buffer,
UI_TEXTBOX.text + (UI_TEXTBOX.page * UI_TEXTBOX_CHARS_PER_PAGE) +
(i * UI_TEXTBOX_CHARS_PER_LINE),
lineChars
);
// Null term string
buffer[lineChars] = '\0'; // Null-terminate the string
// Render the text
DrawText(
buffer,
UI_TEXTBOX_PADDING_X + UI_TEXTBOX_BORDER_WIDTH,
(
(RENDER_HEIGHT - UI_TEXTBOX_HEIGHT) +
UI_TEXTBOX_PADDING_Y + UI_TEXTBOX_BORDER_HEIGHT +
(i * FONT_LINE_HEIGHT)
),
FONT_HEIGHT,
WHITE
);
for(uint8_t j = 0; j < lineChars; j++) {
drawUIChar(
UI_TEXTBOX.text[
(i * UI_TEXTBOX_CHARS_PER_LINE) + j +
(UI_TEXTBOX.page * UI_TEXTBOX_CHARS_PER_PAGE)
],
x + UI_TEXTBOX_PADDING_X + UI_TEXTBOX_BORDER_WIDTH + (
j * FONT_TILE_WIDTH
),
y + UI_TEXTBOX_PADDING_Y + UI_TEXTBOX_BORDER_HEIGHT + (
i * FONT_TILE_HEIGHT
),
WHITE
);
}
// Check if we're done rendering text
if(UI_TEXTBOX.charsRevealed - charsRendered == 0) break;
}
}
EndBlendMode();
}
void drawUIText(
const uint8_t *text,
const uint16_t length,
const int32_t x,
const int32_t y,
const Color color
) {
assertNotNull(text, "Text to draw cannot be NULL");
if(length == 0) return;
for(uint16_t i = 0; i < length; i++) {
drawUIChar(text[i], x + (i * FONT_TILE_WIDTH), y, color);
}
}
void drawUIChar(
const char_t c,
const int32_t x,
const int32_t y,
const Color color
) {
if(c < ' ' || c > '~') return; // Only print printable ASCII characters
int32_t charIndex = TILE_INDEXES[c - FONT_CHAR_START];
int32_t charX = (charIndex % FONT_COLUMN_COUNT) * FONT_TILE_WIDTH;
int32_t charY = (charIndex / FONT_COLUMN_COUNT) * FONT_TILE_HEIGHT;
// FLip Y coordinate for raylib texture coordinates
DrawTextureRec(
RENDER_FONT_TEXTURE,
(Rectangle) {
(float) charX,
(float) charY, // Flip Y by adding height
(float) FONT_TILE_WIDTH,
(float) FONT_TILE_HEIGHT // Negative height to flip the texture
},
(Vector2) { x, y }, // Add FONT_HEIGHT to flip Y
color
);
}

View File

@ -21,4 +21,36 @@ void drawUI(void);
/**
* Draws the UI textbox to the screen.
*/
void drawUITextbox(void);
void drawUITextbox(void);
/**
* Draws text to the screen at the specified position with the given color.
*
* @param text The text to draw.
* @param length The length of the text to draw.
* @param x The x-coordinate to draw the text at.
* @param y The y-coordinate to draw the text at.
* @param color The color of the text.
*/
void drawUIText(
const uint8_t *text,
const uint16_t length,
const int32_t x,
const int32_t y,
const Color color
);
/**
* Draws a single character to the screen at the specified position with the given color.
*
* @param c The character to draw.
* @param x The x-coordinate to draw the character at.
* @param y The y-coordinate to draw the character at.
* @param color The color of the character.
*/
void drawUIChar(
const char_t c,
const int32_t x,
const int32_t y,
const Color color
);

View File

@ -14,6 +14,7 @@
RenderTexture2D RENDER_SCREEN_TEXTURE;
Texture2D RENDER_TILEMAP_TEXTURE;
Texture2D RENDER_ENTITIES_TEXTURE;
Texture2D RENDER_FONT_TEXTURE;
void renderInit(void) {
InitWindow(
@ -31,6 +32,7 @@ void renderInit(void) {
RENDER_SCREEN_TEXTURE = LoadRenderTexture(RENDER_WIDTH, RENDER_HEIGHT);
RENDER_TILEMAP_TEXTURE = LoadTexture("../data/tilemap.png");
RENDER_ENTITIES_TEXTURE = LoadTexture("../data/entities.png");
RENDER_FONT_TEXTURE = LoadTexture("../data/minogram_6x10.png");
drawOverworldInit();
drawUIInit();

View File

@ -11,4 +11,5 @@
extern RenderTexture2D RENDER_SCREEN_TEXTURE;
extern Texture2D RENDER_TILEMAP_TEXTURE;
extern Texture2D RENDER_ENTITIES_TEXTURE;
extern Texture2D RENDER_ENTITIES_TEXTURE;
extern Texture2D RENDER_FONT_TEXTURE;

View File

@ -119,7 +119,17 @@ with open(outputFile, 'w') as f:
f.write(f"#define FONT_TILE_HEIGHT {root.attrib['tileheight']}\n")
f.write(f"#define FONT_TILE_COUNT {len(outputTileIndexes)}\n")
f.write(f"#define FONT_CHAR_START {CHAR_START}\n")
f.write(f"#define FONT_CHAR_END {CHAR_END}\n\n")
f.write(f"#define FONT_CHAR_END {CHAR_END}\n")
f.write(f"#define FONT_CHAR_COUNT {CHARS_TOTAL}\n")
f.write(f"#define FONT_COLUMN_COUNT {img.width // int(root.attrib['tilewidth'])}\n")
f.write(f"#define FONT_ROW_COUNT {img.height // int(root.attrib['tileheight'])}\n\n")
f.write("static const uint8_t TILE_INDEXES[FONT_CHAR_COUNT] = {\n")
f.write(" ")
for i in range(len(outputTileIndexes)):
tileIndex = outputTileIndexes[i]
f.write(f"{tileIndex}, ")
f.write("\n};\n\n")
f.write("static const uint8_t TILE_PIXEL_DATA[FONT_TILE_COUNT][FONT_TILE_WIDTH * FONT_TILE_HEIGHT] = {\n")
for i in range(len(outputTileIndexes)):
@ -137,6 +147,7 @@ with open(outputFile, 'w') as f:
for x in range(int(root.attrib['tilewidth'])):
pixel = tile.getpixel((x, y))
f.write(f"0x{1 if pixel[3] > 0 else 0:02X}, ")
f.write("},\n\n")
f.write("},\n")
f.write("};\n\n")