1 /* Copyright (c) 2013-2015 Jeffrey Pfau
2  *
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include <mgba-util/gui/font.h>
7 #include <mgba-util/gui/font-metrics.h>
8 #include "icons.h"
9 #include "font.h"
10 
11 #include <malloc.h>
12 #include <ogc/tpl.h>
13 
14 #define GLYPH_HEIGHT 24
15 #define CELL_HEIGHT 32
16 #define CELL_WIDTH 32
17 
18 struct GUIFont {
19 	TPLFile tdf;
20 	TPLFile iconsTdf;
21 };
22 
GUIFontCreate(void)23 struct GUIFont* GUIFontCreate(void) {
24 	struct GUIFont* guiFont = malloc(sizeof(struct GUIFont));
25 	if (!guiFont) {
26 		return 0;
27 	}
28 
29 	// libogc's TPL code modifies and frees this itself...
30 	void* fontTpl = memalign(32, font_size);
31 	if (!fontTpl) {
32 		free(guiFont);
33 		return 0;
34 	}
35 	memcpy(fontTpl, font, font_size);
36 	TPL_OpenTPLFromMemory(&guiFont->tdf, fontTpl, font_size);
37 
38 	void* iconsTpl = memalign(32, icons_size);
39 	if (!iconsTpl) {
40 		TPL_CloseTPLFile(&guiFont->tdf);
41 		free(guiFont);
42 		return 0;
43 	}
44 	memcpy(iconsTpl, icons, icons_size);
45 	TPL_OpenTPLFromMemory(&guiFont->iconsTdf, iconsTpl, icons_size);
46 	return guiFont;
47 }
48 
GUIFontDestroy(struct GUIFont * font)49 void GUIFontDestroy(struct GUIFont* font) {
50 	TPL_CloseTPLFile(&font->tdf);
51 	TPL_CloseTPLFile(&font->iconsTdf);
52 	free(font);
53 }
54 
GUIFontHeight(const struct GUIFont * font)55 unsigned GUIFontHeight(const struct GUIFont* font) {
56 	UNUSED(font);
57 	return GLYPH_HEIGHT;
58 }
59 
GUIFontGlyphWidth(const struct GUIFont * font,uint32_t glyph)60 unsigned GUIFontGlyphWidth(const struct GUIFont* font, uint32_t glyph) {
61 	UNUSED(font);
62 	if (glyph > 0x7F) {
63 		glyph = '?';
64 	}
65 	return defaultFontMetrics[glyph].width * 2;
66 }
67 
GUIFontIconMetrics(const struct GUIFont * font,enum GUIIcon icon,unsigned * w,unsigned * h)68 void GUIFontIconMetrics(const struct GUIFont* font, enum GUIIcon icon, unsigned* w, unsigned* h) {
69 	UNUSED(font);
70 	if (icon >= GUI_ICON_MAX) {
71 		if (w) {
72 			*w = 0;
73 		}
74 		if (h) {
75 			*h = 0;
76 		}
77 	} else {
78 		if (w) {
79 			*w = defaultIconMetrics[icon].width * 2;
80 		}
81 		if (h) {
82 			*h = defaultIconMetrics[icon].height * 2;
83 		}
84 	}
85 }
86 
GUIFontDrawGlyph(const struct GUIFont * font,int x,int y,uint32_t color,uint32_t glyph)87 void GUIFontDrawGlyph(const struct GUIFont* font, int x, int y, uint32_t color, uint32_t glyph) {
88 	color = (color >> 24) | (color << 8);
89 	GXTexObj tex;
90 	// Grumble grumble, libogc is bad about const-correctness
91 	struct GUIFont* ncfont = font;
92 	TPL_GetTexture(&ncfont->tdf, 0, &tex);
93 	GX_LoadTexObj(&tex, GX_TEXMAP0);
94 
95 	GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_NOOP);
96 	GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
97 
98 	if (glyph > 0x7F) {
99 		glyph = '?';
100 	}
101 	struct GUIFontGlyphMetric metric = defaultFontMetrics[glyph];
102 	s16 tx = (glyph & 15) * CELL_WIDTH + metric.padding.left * 2;
103 	s16 ty = (glyph >> 4) * CELL_HEIGHT + metric.padding.top * 2;
104 	GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
105 	GX_Position2s16(x, y - GLYPH_HEIGHT + metric.padding.top * 2);
106 	GX_Color1u32(color);
107 	GX_TexCoord2f32(tx / 512.f, ty / 256.f);
108 
109 	GX_Position2s16(x + CELL_WIDTH - (metric.padding.left + metric.padding.right) * 2, y - GLYPH_HEIGHT + metric.padding.top * 2);
110 	GX_Color1u32(color);
111 	GX_TexCoord2f32((tx + CELL_WIDTH - (metric.padding.left + metric.padding.right) * 2) / 512.f, ty / 256.f);
112 
113 	GX_Position2s16(x + CELL_WIDTH - (metric.padding.left + metric.padding.right) * 2, y - GLYPH_HEIGHT + CELL_HEIGHT - metric.padding.bottom * 2);
114 	GX_Color1u32(color);
115 	GX_TexCoord2f32((tx + CELL_WIDTH - (metric.padding.left + metric.padding.right) * 2) / 512.f, (ty + CELL_HEIGHT - (metric.padding.top + metric.padding.bottom) * 2) / 256.f);
116 
117 	GX_Position2s16(x, y - GLYPH_HEIGHT + CELL_HEIGHT - metric.padding.bottom * 2);
118 	GX_Color1u32(color);
119 	GX_TexCoord2f32(tx / 512.f, (ty + CELL_HEIGHT - (metric.padding.top + metric.padding.bottom) * 2) / 256.f);
120 	GX_End();
121 }
122 
GUIFontDrawIcon(const struct GUIFont * font,int x,int y,enum GUIAlignment align,enum GUIOrientation orient,uint32_t color,enum GUIIcon icon)123 void GUIFontDrawIcon(const struct GUIFont* font, int x, int y, enum GUIAlignment align, enum GUIOrientation orient, uint32_t color, enum GUIIcon icon) {
124 	if (icon >= GUI_ICON_MAX) {
125 		return;
126 	}
127 
128 	color = (color >> 24) | (color << 8);
129 	GXTexObj tex;
130 
131 	struct GUIFont* ncfont = font;
132 	TPL_GetTexture(&ncfont->iconsTdf, 0, &tex);
133 	GX_LoadTexObj(&tex, GX_TEXMAP0);
134 
135 	GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_NOOP);
136 	GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
137 
138 	struct GUIIconMetric metric = defaultIconMetrics[icon];
139 	switch (align & GUI_ALIGN_HCENTER) {
140 	case GUI_ALIGN_HCENTER:
141 		x -= metric.width;
142 		break;
143 	case GUI_ALIGN_RIGHT:
144 		x -= metric.width * 2;
145 		break;
146 	}
147 	switch (align & GUI_ALIGN_VCENTER) {
148 	case GUI_ALIGN_VCENTER:
149 		y -= metric.height;
150 		break;
151 	case GUI_ALIGN_BOTTOM:
152 		y -= metric.height * 2;
153 		break;
154 	}
155 
156 	float u[4];
157 	float v[4];
158 
159 	switch (orient) {
160 	case GUI_ORIENT_0:
161 	default:
162 		// TODO: Rotations
163 		u[0] = u[3] = metric.x / 256.f;
164 		u[1] = u[2] = (metric.x + metric.width) / 256.f;
165 		v[0] = v[1] = (metric.y + metric.height) / 64.f;
166 		v[2] = v[3] = metric.y / 64.f;
167 		break;
168 	case GUI_ORIENT_HMIRROR:
169 		u[0] = u[3] = (metric.x + metric.width) / 256.f;
170 		u[1] = u[2] = metric.x / 256.f;
171 		v[0] = v[1] = (metric.y + metric.height) / 64.f;
172 		v[2] = v[3] = metric.y / 64.f;
173 		break;
174 	case GUI_ORIENT_VMIRROR:
175 		u[0] = u[3] = metric.x / 256.f;
176 		u[1] = u[2] = (metric.x + metric.width) / 256.f;
177 		v[0] = v[1] = metric.y / 64.f;
178 		v[2] = v[3] = (metric.y + metric.height) / 64.f;
179 		break;
180 	}
181 
182 	GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
183 	GX_Position2s16(x, y + metric.height * 2);
184 	GX_Color1u32(color);
185 	GX_TexCoord2f32(u[0], v[0]);
186 
187 	GX_Position2s16(x + metric.width * 2, y + metric.height * 2);
188 	GX_Color1u32(color);
189 	GX_TexCoord2f32(u[1], v[1]);
190 
191 	GX_Position2s16(x + metric.width * 2, y);
192 	GX_Color1u32(color);
193 	GX_TexCoord2f32(u[2], v[2]);
194 
195 	GX_Position2s16(x, y);
196 	GX_Color1u32(color);
197 	GX_TexCoord2f32(u[3], v[3]);
198 	GX_End();
199 }
200 
GUIFontDrawIconSize(const struct GUIFont * font,int x,int y,int w,int h,uint32_t color,enum GUIIcon icon)201 void GUIFontDrawIconSize(const struct GUIFont* font, int x, int y, int w, int h, uint32_t color, enum GUIIcon icon) {
202 	if (icon >= GUI_ICON_MAX) {
203 		return;
204 	}
205 
206 	color = (color >> 24) | (color << 8);
207 	GXTexObj tex;
208 
209 	struct GUIFont* ncfont = font;
210 	TPL_GetTexture(&ncfont->iconsTdf, 0, &tex);
211 	GX_LoadTexObj(&tex, GX_TEXMAP0);
212 
213 	GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_NOOP);
214 	GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
215 
216 	struct GUIIconMetric metric = defaultIconMetrics[icon];
217 
218 	float u[4];
219 	float v[4];
220 
221 	if (!h) {
222 		h = metric.height * 2;
223 	}
224 	if (!w) {
225 		w = metric.width * 2;
226 	}
227 
228 	u[0] = u[3] = metric.x / 256.f;
229 	u[1] = u[2] = (metric.x + metric.width) / 256.f;
230 	v[0] = v[1] = (metric.y + metric.height) / 64.f;
231 	v[2] = v[3] = metric.y / 64.f;
232 
233 	GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
234 	GX_Position2s16(x, y + h);
235 	GX_Color1u32(color);
236 	GX_TexCoord2f32(u[0], v[0]);
237 
238 	GX_Position2s16(x + w, y + h);
239 	GX_Color1u32(color);
240 	GX_TexCoord2f32(u[1], v[1]);
241 
242 	GX_Position2s16(x + w, y);
243 	GX_Color1u32(color);
244 	GX_TexCoord2f32(u[2], v[2]);
245 
246 	GX_Position2s16(x, y);
247 	GX_Color1u32(color);
248 	GX_TexCoord2f32(u[3], v[3]);
249 	GX_End();
250 }
251