Skip to content

Commit 9c333b8

Browse files
piepie62fincs
authored andcommitted
Custom Font Support (#9)
1 parent b275da3 commit 9c333b8

6 files changed

Lines changed: 415 additions & 10 deletions

File tree

include/c2d/font.h

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/**
2+
* @file font.h
3+
* @brief Font loading and management
4+
*/
5+
#pragma once
6+
#include "base.h"
7+
8+
struct C2D_Font_s;
9+
typedef struct C2D_Font_s* C2D_Font;
10+
11+
/** @defgroup Font Font functions
12+
* @{
13+
*/
14+
15+
/** @brief Load a font from a file
16+
* @param[in] filename Name of the font file (.bcfnt)
17+
* @returns Font handle
18+
* @retval NULL Error
19+
*/
20+
C2D_Font C2D_FontLoad(const char* filename);
21+
22+
/** @brief Load a font from memory
23+
* @param[in] data Data to load
24+
* @param[in] size Size of the data to load
25+
* @returns Font handle
26+
* @retval NULL Error
27+
*/
28+
C2D_Font C2D_FontLoadFromMem(const void* data, size_t size);
29+
30+
/** @brief Load a font from file descriptor
31+
* @param[in] fd File descriptor used to load data
32+
* @returns Font handle
33+
* @retval NULL Error
34+
*/
35+
C2D_Font C2D_FontLoadFromFD(int fd);
36+
37+
/** @brief Load font from stdio file handle
38+
* @param[in] f File handle used to load data
39+
* @returns Font handle
40+
* @retval NULL Error
41+
*/
42+
C2D_Font C2D_FontLoadFromHandle(FILE* f);
43+
44+
/** @brief Load corresponding font from system archive
45+
* @param[in] region Region to get font from
46+
* @returns Font handle
47+
* @retval NULL Error
48+
* @remark JPN, USA, EUR, and AUS all use the same font.
49+
*/
50+
C2D_Font C2D_FontLoadSystem(CFG_Region region);
51+
52+
/** @brief Free a font
53+
* @param[in] font Font handle
54+
*/
55+
void C2D_FontFree(C2D_Font font);
56+
57+
/** @brief Find the glyph index of a codepoint, or returns the default
58+
* @param[in] font Font to search, or NULL for system font
59+
* @param[in] codepoint Codepoint to search for
60+
* @returns Glyph index
61+
* @retval font->cfnt->finf.alterCharIndex The codepoint does not exist in the font
62+
*/
63+
int C2D_FontGlyphIndexFromCodePoint(C2D_Font font, u32 codepoint);
64+
65+
/** @brief Get character width info for a given index
66+
* @param[in] font Font to read from, or NULL for system font
67+
* @param[in] glyphIndex Index to get the width of
68+
* @returns Width info for glyph
69+
*/
70+
charWidthInfo_s* C2D_FontGetCharWidthInfo(C2D_Font font, int glyphIndex);
71+
72+
/** @brief Calculate glyph position of given index
73+
* @param[in] font Font to read from, or NULL for system font
74+
* @param[out] out Glyph position
75+
* @param[in] glyphIndex Index to get position of
76+
* @param[in] flags Misc flags
77+
* @param[in] scaleX Size to scale in X
78+
* @param[in] scaleY Size to scale in Y
79+
*/
80+
void C2D_FontCalcGlyphPos(C2D_Font font, fontGlyphPos_s* out, int glyphIndex, u32 flags, float scaleX, float scaleY);
81+
82+
/** @brief Get the font info structure associated with the font
83+
* @param[in] font Font to read from, or NULL for the system font
84+
* @returns FINF associated with the font
85+
*/
86+
FINF_s* C2D_FontGetInfo(C2D_Font font);
87+
88+
/** @} */

include/c2d/text.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
#pragma once
66
#include "base.h"
7+
#include "font.h"
78

89
struct C2D_TextBuf_s;
910
typedef struct C2D_TextBuf_s* C2D_TextBuf;
@@ -20,6 +21,7 @@ typedef struct
2021
size_t end; ///< Reserved for internal use.
2122
float width; ///< Width of the text in pixels, according to 1x scale metrics.
2223
u32 lines; ///< Number of lines in the text, according to 1x scale metrics;
24+
C2D_Font font; ///< Font used to draw the text, or NULL for system font
2325
} C2D_Text;
2426

2527
enum
@@ -74,6 +76,21 @@ size_t C2D_TextBufGetNumGlyphs(C2D_TextBuf buf);
7476
*/
7577
const char* C2D_TextParseLine(C2D_Text* text, C2D_TextBuf buf, const char* str, u32 lineNo);
7678

79+
/** @brief Parses and adds a single line of text to a text buffer.
80+
* @param[out] text Pointer to text object to store information in.
81+
* @param[in] font Font to get glyphs from, or null for system font
82+
* @param[in] buf Text buffer handle.
83+
* @param[in] str String to parse.
84+
* @param[in] lineNo Line number assigned to the text (used to calculate vertical position).
85+
* @remarks Whitespace doesn't add any glyphs to the text buffer and is thus "free".
86+
* @returns On success, a pointer to the character on which string processing stopped, which
87+
* can be a newline ('\n'; indicating that's where the line ended), the null character
88+
* ('\0'; indicating the end of the string was reached), or any other character
89+
* (indicating the text buffer is full and no more glyphs can be added).
90+
* On failure, NULL.
91+
*/
92+
const char* C2D_TextFontParseLine(C2D_Text* text, C2D_Font font, C2D_TextBuf buf, const char* str, u32 lineNo);
93+
7794
/** @brief Parses and adds arbitrary text (including newlines) to a text buffer.
7895
* @param[out] text Pointer to text object to store information in.
7996
* @param[in] buf Text buffer handle.
@@ -86,6 +103,19 @@ const char* C2D_TextParseLine(C2D_Text* text, C2D_TextBuf buf, const char* str,
86103
*/
87104
const char* C2D_TextParse(C2D_Text* text, C2D_TextBuf buf, const char* str);
88105

106+
/** @brief Parses and adds arbitrary text (including newlines) to a text buffer.
107+
* @param[out] text Pointer to text object to store information in.
108+
* @param[in] font Font to get glyphs from, or null for system font
109+
* @param[in] buf Text buffer handle.
110+
* @param[in] str String to parse.
111+
* @remarks Whitespace doesn't add any glyphs to the text buffer and is thus "free".
112+
* @returns On success, a pointer to the character on which string processing stopped, which
113+
* can be the null character ('\0'; indicating the end of the string was reached),
114+
* or any other character (indicating the text buffer is full and no more glyphs can be added).
115+
* On failure, NULL.
116+
*/
117+
const char* C2D_TextFontParse(C2D_Text* text, C2D_Font font, C2D_TextBuf buf, const char* str);
118+
89119
/** @brief Optimizes a text object in order to be drawn more efficiently.
90120
* @param[in] text Pointer to text object.
91121
*/

include/citro2d.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ extern "C" {
1919
#include "c2d/spritesheet.h"
2020
#include "c2d/sprite.h"
2121
#include "c2d/text.h"
22+
#include "c2d/font.h"
2223

2324
#ifdef __cplusplus
2425
}

source/font.c

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <unistd.h>
4+
#include "internal.h"
5+
#include <c2d/font.h>
6+
7+
C2D_Font C2D_FontLoad(const char* filename)
8+
{
9+
FILE* f = fopen(filename, "rb");
10+
if (!f) return NULL;
11+
C2D_Font ret = C2D_FontLoadFromHandle(f);
12+
fclose(f);
13+
return ret;
14+
}
15+
16+
static inline C2D_Font C2Di_FontAlloc(void)
17+
{
18+
return (C2D_Font)malloc(sizeof(struct C2D_Font_s));
19+
}
20+
21+
static C2D_Font C2Di_PostLoadFont(C2D_Font font)
22+
{
23+
if (!font->cfnt)
24+
{
25+
free(font);
26+
font = NULL;
27+
} else
28+
{
29+
fontFixPointers(font->cfnt);
30+
31+
TGLP_s* glyphInfo = font->cfnt->finf.tglp;
32+
font->glyphSheets = malloc(sizeof(C3D_Tex)*glyphInfo->nSheets);
33+
font->textScale = 30.0f / glyphInfo->cellHeight;
34+
if (!font->glyphSheets)
35+
{
36+
C2D_FontFree(font);
37+
return NULL;
38+
}
39+
40+
int i;
41+
for (i = 0; i < glyphInfo->nSheets; i++)
42+
{
43+
C3D_Tex* tex = &font->glyphSheets[i];
44+
tex->data = &glyphInfo->sheetData[glyphInfo->sheetSize*i];
45+
tex->fmt = glyphInfo->sheetFmt;
46+
tex->size = glyphInfo->sheetSize;
47+
tex->width = glyphInfo->sheetWidth;
48+
tex->height = glyphInfo->sheetHeight;
49+
tex->param = GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR)
50+
| GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_BORDER) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_BORDER);
51+
tex->border = 0xFFFFFFFF;
52+
tex->lodParam = 0;
53+
}
54+
}
55+
return font;
56+
}
57+
58+
C2D_Font C2D_FontLoadFromMem(const void* data, size_t size)
59+
{
60+
C2D_Font font = C2Di_FontAlloc();
61+
if (font)
62+
{
63+
font->cfnt = linearAlloc(size);
64+
if (font->cfnt)
65+
memcpy(font->cfnt, data, size);
66+
font = C2Di_PostLoadFont(font);
67+
}
68+
return font;
69+
}
70+
71+
C2D_Font C2D_FontLoadFromFD(int fd)
72+
{
73+
C2D_Font font = C2Di_FontAlloc();
74+
if (font)
75+
{
76+
CFNT_s cfnt;
77+
read(fd, &cfnt, sizeof(CFNT_s));
78+
font->cfnt = linearAlloc(cfnt.fileSize);
79+
if (font->cfnt)
80+
{
81+
memcpy(font->cfnt, &cfnt, sizeof(CFNT_s));
82+
read(fd, (u8*)(font->cfnt) + sizeof(CFNT_s), cfnt.fileSize - sizeof(CFNT_s));
83+
}
84+
font = C2Di_PostLoadFont(font);
85+
}
86+
return font;
87+
}
88+
89+
C2D_Font C2D_FontLoadFromHandle(FILE* handle)
90+
{
91+
C2D_Font font = C2Di_FontAlloc();
92+
if (font)
93+
{
94+
CFNT_s cfnt;
95+
fread(&cfnt, 1, sizeof(CFNT_s), handle);
96+
font->cfnt = linearAlloc(cfnt.fileSize);
97+
if (font->cfnt)
98+
{
99+
memcpy(font->cfnt, &cfnt, sizeof(CFNT_s));
100+
fread((u8*)(font->cfnt) + sizeof(CFNT_s), 1, cfnt.fileSize - sizeof(CFNT_s), handle);
101+
}
102+
font = C2Di_PostLoadFont(font);
103+
}
104+
return font;
105+
}
106+
107+
static C2D_Font C2Di_FontLoadFromArchive(u64 binary_lowpath)
108+
{
109+
C2D_Font font = C2Di_FontAlloc();
110+
if (font)
111+
{
112+
int fontNum = (binary_lowpath & 0x300) >> 8;
113+
const u8 sizeMod = fontNum == 0 ? 0xA0 : 0xB0;
114+
u64 lowPath[] = { binary_lowpath, 0x00000001FFFFFE00 };
115+
Handle romfs_handle;
116+
u64 romfs_size = 0;
117+
u32 romfs_bytes_read = 0;
118+
119+
FS_Path savedatacheck_path = { PATH_BINARY, 16, (u8*)lowPath };
120+
u8 file_binary_lowpath[20] = {};
121+
FS_Path romfs_path = { PATH_BINARY, 20, file_binary_lowpath };
122+
123+
if (R_FAILED(FSUSER_OpenFileDirectly(&romfs_handle, (FS_ArchiveID)0x2345678a, savedatacheck_path, romfs_path, FS_OPEN_READ, 0)))
124+
{
125+
free(font);
126+
return NULL;
127+
}
128+
if (R_FAILED(FSFILE_GetSize(romfs_handle, &romfs_size)))
129+
{
130+
free(font);
131+
FSFILE_Close(romfs_handle);
132+
return NULL;
133+
}
134+
135+
u8* romfs_data_buffer = malloc(romfs_size);
136+
if (!romfs_data_buffer)
137+
{
138+
free(font);
139+
FSFILE_Close(romfs_handle);
140+
return NULL;
141+
}
142+
if (R_FAILED(FSFILE_Read(romfs_handle, &romfs_bytes_read, 0, romfs_data_buffer, romfs_size)))
143+
{
144+
free(romfs_data_buffer);
145+
free(font);
146+
FSFILE_Close(romfs_handle);
147+
return NULL;
148+
}
149+
FSFILE_Close(romfs_handle);
150+
151+
u8* compFontData = romfs_data_buffer + sizeMod;
152+
153+
u32 fontSize = *(u32*)(compFontData) >> 8;
154+
font->cfnt = linearAlloc(fontSize);
155+
if (font->cfnt)
156+
{
157+
if (!decompress_LZ11(font->cfnt, fontSize, NULL, compFontData + 4, romfs_size - sizeMod - 4))
158+
{
159+
C2D_FontFree(font);
160+
return NULL;
161+
}
162+
}
163+
164+
free(romfs_data_buffer);
165+
166+
font = C2Di_PostLoadFont(font);
167+
}
168+
169+
return font;
170+
}
171+
172+
C2D_Font C2D_FontLoadSystem(CFG_Region region)
173+
{
174+
u8 systemRegion;
175+
if (R_FAILED(CFGU_SecureInfoGetRegion(&systemRegion)))
176+
return NULL;
177+
178+
switch (region)
179+
{
180+
case 0:
181+
case 1:
182+
case 2:
183+
case 3:
184+
if (systemRegion > 3)
185+
return C2Di_FontLoadFromArchive(0x0004009b00014002);
186+
break;
187+
case 4:
188+
if (systemRegion == 4)
189+
break;
190+
return C2Di_FontLoadFromArchive(0x0004009b00014102);
191+
case 5:
192+
if (systemRegion == 5)
193+
break;
194+
return C2Di_FontLoadFromArchive(0x0004009b00014202);
195+
case 6:
196+
if (systemRegion == 6)
197+
break;
198+
return C2Di_FontLoadFromArchive(0x0004009b00014302);
199+
}
200+
return NULL;
201+
}
202+
203+
void C2D_FontFree(C2D_Font font)
204+
{
205+
if (font)
206+
{
207+
if (font->cfnt)
208+
linearFree(font->cfnt);
209+
free(font->glyphSheets);
210+
}
211+
}
212+
213+
int C2D_FontGlyphIndexFromCodePoint(C2D_Font font, u32 codepoint)
214+
{
215+
if (!font)
216+
return fontGlyphIndexFromCodePoint(fontGetSystemFont(), codepoint);
217+
else
218+
return fontGlyphIndexFromCodePoint(font->cfnt, codepoint);
219+
}
220+
221+
charWidthInfo_s* C2D_FontGetCharWidthInfo(C2D_Font font, int glyphIndex)
222+
{
223+
if (!font)
224+
return fontGetCharWidthInfo(fontGetSystemFont(), glyphIndex);
225+
else
226+
return fontGetCharWidthInfo(font->cfnt, glyphIndex);
227+
}
228+
229+
void C2D_FontCalcGlyphPos(C2D_Font font, fontGlyphPos_s* out, int glyphIndex, u32 flags, float scaleX, float scaleY)
230+
{
231+
if (!font)
232+
fontCalcGlyphPos(out, fontGetSystemFont(), glyphIndex, flags, scaleX, scaleY);
233+
else
234+
fontCalcGlyphPos(out, font->cfnt, glyphIndex, flags, scaleX, scaleY);
235+
}
236+
237+
FINF_s* C2D_FontGetInfo(C2D_Font font)
238+
{
239+
if (!font)
240+
return fontGetInfo(NULL);
241+
else
242+
return fontGetInfo(font->cfnt);
243+
}

0 commit comments

Comments
 (0)