libgui 2.01
libgui is a GUI library for the GameCube, Wii, and Wii U
 
Loading...
Searching...
No Matches
OgcGlyphRenderer.cpp
1/****************************************************************************
2 * Platform Abstraction Layer (OGC driver)
3 * Daryl Borth 2026
4 * OgcGlyphRenderer.cpp
5 ***************************************************************************/
6#include "OgcVideoDriver.h"
7#include <malloc.h>
8#include <string.h>
9
10#define ALIGN8(x) (((x) + 7) & ~7)
11
12OgcGlyphRenderer::OgcGlyphRenderer(uint8_t vtxFmtIndex) : inText(false), textureCacheStale(true)
13{
14 setVertexFormat(vtxFmtIndex);
15}
16OgcGlyphRenderer::~OgcGlyphRenderer() {}
17
18void OgcGlyphRenderer::setVertexFormat(uint8_t vtxFmtIndex) {
19 this->vertexIndex = vtxFmtIndex;
20
21 GX_SetVtxAttrFmt(this->vertexIndex, GX_VA_POS, GX_POS_XY, GX_S16, 0);
22 GX_SetVtxAttrFmt(this->vertexIndex, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
23 GX_SetVtxAttrFmt(this->vertexIndex, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
24}
25
26void* OgcGlyphRenderer::createTexture(uint16_t width, uint16_t height) {
27 width = ALIGN8(width);
28 if (width == 0) width = 8;
29
30 height = ALIGN8(height);
31 if (height == 0) height = 8;
32
33 uint32_t glyphSize = (width * height) >> 1;
34
35 void* texture = memalign(32, glyphSize);
36 if (texture) {
37 memset(texture, 0x00, glyphSize);
38 textureCacheStale = true;
39 }
40
41 return texture;
42}
43
44void OgcGlyphRenderer::loadTextureData(void* texture, FT_Bitmap* bitmap) {
45 if (!texture || !bitmap) return;
46
47 uint16_t texWidth = ALIGN8(bitmap->width);
48 if (texWidth == 0) texWidth = 8;
49
50 uint16_t texHeight = ALIGN8(bitmap->rows);
51 if (texHeight == 0) texHeight = 8;
52
53 uint32_t glyphSize = (texWidth * texHeight) >> 1;
54
55 uint8_t* dst = static_cast<uint8_t*>(texture);
56 uint8_t* src = static_cast<uint8_t*>(bitmap->buffer);
57 // FreeType's row pitch can be larger than the bitmap width (row padding)
58 uint32_t srcPitch = bitmap->pitch < 0 ? -bitmap->pitch : bitmap->pitch;
59 if (srcPitch == 0) srcPitch = bitmap->width;
60 uint32_t pos, x1, y1, x, y;
61
62 // 8x8 tiled block processing for GX_TF_I4
63 for (y1 = 0; y1 < bitmap->rows; y1 += 8) {
64 for (x1 = 0; x1 < bitmap->width; x1 += 8) {
65 for (y = y1; y < (y1 + 8); y++) {
66 for (x = x1; x < (x1 + 8); x += 2, dst++) {
67 if (x >= bitmap->width || y >= bitmap->rows) {
68 continue;
69 }
70
71 pos = y * srcPitch + x;
72
73 // Extract high bits from current and adjacent pixels
74 *dst = (src[pos] & 0xF0);
75 if (x + 1 < bitmap->width) {
76 *dst |= (src[pos + 1] >> 4);
77 }
78 }
79 }
80 }
81 }
82
83 // Flush the CPU cache to ensure GPU reads valid data
84 DCFlushRange(texture, glyphSize);
85 textureCacheStale = true;
86}
87
89 if (texture) {
90 free(texture);
91 textureCacheStale = true;
92 }
93}
94
95// State for glyph quads, set once for a whole string rather than around every glyph
97 GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
98 GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
99 inText = true;
100}
101
102void OgcGlyphRenderer::endText() {
103 GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
104 GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
105 inText = false;
106}
107
108void OgcGlyphRenderer::drawQuad(void* texture, int16_t screenX, int16_t screenY, uint16_t width, uint16_t height, const PixelColor& color) {
109 if (!texture) return;
110
111 GXTexObj glyphTexture;
112
113 // GX_CLAMP required to avoid wrapping artifacts on small font textures
114 GX_InitTexObj(&glyphTexture, texture, width, height, GX_TF_I4, GX_CLAMP, GX_CLAMP, GX_FALSE);
115 GX_LoadTexObj(&glyphTexture, GX_TEXMAP0);
116
117 // The texture cache is keyed by address, so it only needs emptying when the memory behind a
118 // glyph texture has changed (one was made, filled or freed since the last time)
119 if (textureCacheStale) {
120 GX_InvalidateTexAll();
121 textureCacheStale = false;
122 }
123
124 if (!inText) {
125 GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
126 GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
127 }
128
129 GX_Begin(GX_QUADS, this->vertexIndex, 4);
130
131 // Top-Left
132 GX_Position2s16(screenX, screenY);
133 GX_Color4u8(color.r, color.g, color.b, color.a);
134 GX_TexCoord2f32(0.0f, 0.0f);
135
136 // Top-Right
137 GX_Position2s16(width + screenX, screenY);
138 GX_Color4u8(color.r, color.g, color.b, color.a);
139 GX_TexCoord2f32(1.0f, 0.0f);
140
141 // Bottom-Right
142 GX_Position2s16(width + screenX, height + screenY);
143 GX_Color4u8(color.r, color.g, color.b, color.a);
144 GX_TexCoord2f32(1.0f, 1.0f);
145
146 // Bottom-Left
147 GX_Position2s16(screenX, height + screenY);
148 GX_Color4u8(color.r, color.g, color.b, color.a);
149 GX_TexCoord2f32(0.0f, 1.0f);
150
151 GX_End();
152
153 if (!inText) {
154 GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
155 GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
156 }
157}
158
159void OgcGlyphRenderer::drawFeature(int16_t screenX, int16_t screenY, uint16_t width, uint16_t height, const PixelColor& color) {
160 // Disable textures to draw flat colored quad
161 GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
162 GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
163
164 GX_Begin(GX_QUADS, this->vertexIndex, 4);
165
166 GX_Position2s16(screenX, screenY);
167 GX_Color4u8(color.r, color.g, color.b, color.a);
168
169 GX_Position2s16(width + screenX, screenY);
170 GX_Color4u8(color.r, color.g, color.b, color.a);
171
172 GX_Position2s16(width + screenX, height + screenY);
173 GX_Color4u8(color.r, color.g, color.b, color.a);
174
175 GX_Position2s16(screenX, height + screenY);
176 GX_Color4u8(color.r, color.g, color.b, color.a);
177
178 GX_End();
179
180 GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
181 GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
182}
void loadTextureData(void *texture, FT_Bitmap *bitmap) override
Uploads a rasterized FreeType glyph bitmap into a texture from createTexture().
void setVertexFormat(uint8_t vtxFmtIndex)
Changes which GX vertex format slot subsequent draws use.
void destroyTexture(void *texture) override
Destroys a texture created by createTexture().
void beginText() override
Bracket the drawQuad() calls for the glyphs of one string, so a renderer whose draws need state set u...
void drawFeature(int16_t screenX, int16_t screenY, uint16_t width, uint16_t height, const PixelColor &color) override
Draws a solid-color rectangle used for text decoration (underline/strike-through).
OgcGlyphRenderer(uint8_t vtxFmtIndex=GX_VTXFMT1)
void * createTexture(uint16_t width, uint16_t height) override
Allocates an empty single-channel glyph texture. Returns an opaque handle.
void drawQuad(void *texture, int16_t screenX, int16_t screenY, uint16_t width, uint16_t height, const PixelColor &color) override
Draws a glyph texture as a quad tinted with color.
8-bit-per-channel RGBA color used by the video interfaces.
Definition Mesh.h:16