sdk-world v2026.11.05
PS2 SDK - world tier (copyleft-allowed, non-essential packages)
Loading...
Searching...
No Matches
gsFontM.c
1// ____ ___ | / _____ _____
2// | __ | |___/ | |
3// |___| ___| | \ __|__ | gsKit Open Source Project.
4// ----------------------------------------------------------------------
5// Copyright 2004 - Chris "Neovanglist" Gilbert <Neovanglist@LainOS.org>
6// Licenced under Academic Free License version 2.0
7// Review gsKit README & LICENSE files for further details.
8//
9// gsFontM.c - Font loading, manipulation, handling, and printing.
10//
11// FONTM Unpacking Code (_unpack_raw and _unpack_raw_1 routines) borrowed from
12// [RO]man's unpack.c @ http://ps2dev.pgamers.com/
13//
14// Other FONTM help and info from adresd.
15//
16// Greets and thanks to both of you!
17//
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <fcntl.h>
22#include <unistd.h>
23#include <string.h>
24#include <malloc.h>
25
26#include "gsKit.h"
27#include "gsInline.h"
28
29GSFONTM *gsKit_init_fontm(void)
30{
31 int pgindx;
32 GSFONTM *gsFontM;
33
34 gsFontM = calloc(1, sizeof(GSFONTM));
35 for (pgindx=0; pgindx<GS_FONTM_PAGE_COUNT; pgindx++)
36 gsFontM->Texture[pgindx] = calloc(1, sizeof(GSTEXTURE));
37
38 return gsFontM;
39}
40
41void gsKit_free_fontm(GSGLOBAL *gsGlobal, GSFONTM *gsFontM)
42{
43 int pgindx;
44
45 for (pgindx=0; pgindx<GS_FONTM_PAGE_COUNT; pgindx++) {
46 // Free from vram
48 // clut was pointing to static memory, so do not free
49 gsFontM->Texture[pgindx]->Clut = NULL;
50 // mem was pointing to 'TexBase', so do not free
51 gsFontM->Texture[pgindx]->Mem = NULL;
52 // free texture
53 free(gsFontM->Texture[pgindx]);
54 gsFontM->Texture[pgindx] = NULL;
55 }
56
57 if (gsFontM->Header.offset_table != NULL)
58 free(gsFontM->Header.offset_table);
59
60 if (gsFontM->TexBase != NULL)
61 free(gsFontM->TexBase);
62
63 free(gsFontM);
64}
65
69static u32 gsKit_fontm_clut[16] __attribute__((aligned(128))) = {
70 0x00000000,
71 0x11111111,
72 0x22222222,
73 0x33333333,
74 0x44444444,
75 0x55555555,
76 0x66666666,
77 0x77777777,
78 0x80888888,
79 0x80999999,
80 0x80AAAAAA,
81 0x80BBBBBB,
82 0x80CCCCCC,
83 0x80DDDDDD,
84 0x80EEEEEE,
85 0x80FFFFFF
86};
87
88int gsKit_fontm_upload(GSGLOBAL *gsGlobal, GSFONTM *gsFontM)
89{
90 int pgindx;
91
93 return -1;
94
95 for (pgindx=0; pgindx<GS_FONTM_PAGE_COUNT; pgindx++) {
96 gsFontM->Texture[pgindx]->Width = 52;
97 gsFontM->Texture[pgindx]->Height = 832;
98 gsFontM->Texture[pgindx]->PSM = GS_PSM_T4;
101 gsFontM->Texture[pgindx]->Clut = gsKit_fontm_clut;
102 gsKit_setup_tbw(gsFontM->Texture[pgindx]);
103 }
104
105 gsFontM->VramIdx = 0;
106 gsFontM->Spacing = 1.0f;
107 gsFontM->Align = GSKIT_FALIGN_LEFT;
108
109 return 0;
110}
111
112int gsKit_fontm_unpack(GSFONTM *gsFontM)
113{
114 void *packed;
115 void *unpacked;
116 int FontMFile;
117 int PackedSize;
118 struct gsKit_fontm_unpack updata;
119 int TableSize;
120 u8 *temp;
121 int TexSize;
122 u8 *temp2;
123
124 u8 numlines, lineno, mask;
125
126 u32 offset;
127
128 struct line
129 {
130 u64 blah1;
131 u32 blah2;
132 u8 blah3;
133 } __attribute__ ((packed));
134
135 typedef struct line PADLINE;
136
137 PADLINE *olddata;
138 PADLINE *newdata;
139
140 u32 linemax;
141
142 u32 mask32;
143
144 int byte;
145
146 u8 *tmpdst;
147 u8 *tmpsrc;
148
149 FontMFile = open("rom0:FONTM", O_RDONLY);
150 if(FontMFile < 0)
151 {
152 printf("Failed to open FONTM from ROM0\n");
153 return -1;
154 }
155
156 PackedSize = lseek(FontMFile, 0, SEEK_END);
157
158 lseek(FontMFile, 0, SEEK_SET);
159
160 packed = malloc(PackedSize);
161
162 if(read(FontMFile, packed, PackedSize) != PackedSize)
163 {
164 printf("Error Reading Packed FONTM Data\n");
165 close(FontMFile);
166 return -1;
167 }
168
169 close(FontMFile);
170
171 updata.size = *(u32 *)packed;
172 updata.ptr = (void *)((u8 *)packed + 4);
173
174 unpacked = malloc(updata.size);
175
176 gsKit_fontm_unpack_raw(unpacked, &updata);
177
178 free(packed);
179
180/*
181 // Use this to dump the unpacked fontm file to host:
182 int DumpFile = open("host:fontm.dump", O_RDWR);
183
184 write(DumpFile, unpacked, updata.size);
185
186 close(DumpFile);
187*/
188
189 gsFontM->Header.sig = *(u32 *)unpacked;
190 gsFontM->Header.version = *(u32 *)((u8 *)unpacked + 4);
191 gsFontM->Header.bitsize = *(u32 *)((u8 *)unpacked + 8);
192 gsFontM->Header.baseoffset = *(u32 *)((u8 *)unpacked + 12);
193 gsFontM->Header.num_entries = *(u32 *)((u8 *)unpacked + 16);
194 gsFontM->Header.eof = *(u32 *)((u8 *)unpacked + 20);
195 TableSize = (gsFontM->Header.num_entries * 4);
196 gsFontM->Header.offset_table = malloc(TableSize);
197
198 temp = (u8 *)((u32)unpacked + gsFontM->Header.baseoffset + 17680);
199
200 TexSize = (338 * gsFontM->Header.num_entries);
201
202 gsFontM->TexBase = memalign(128, TexSize);
203
204 temp2 = malloc(TexSize);
205
206 olddata = (PADLINE *)temp;
207 newdata = (PADLINE *)temp2;
208
209 linemax = (gsFontM->Header.num_entries * 26) - 52;
210
211 // Interleave lines so we can deal with it as two columns of glyphs in vram
212 for(offset = 0; offset < linemax; offset += 52)
213 {
214 lineno = 0;
215 for(numlines = 0; numlines < 52; numlines++)
216 {
217 mask = (numlines << 7);
218 if(mask)
219 {
220 newdata[numlines + offset] = olddata[offset + lineno + 26];
221 lineno++;
222 }
223 else
224 {
225 newdata[numlines + offset] = olddata[offset + lineno];
226 }
227 }
228 }
229
230
231 // Create our new offset table
232 for(offset = 0; offset < gsFontM->Header.num_entries; offset++)
233 {
234 mask32 = (offset << 31);
235 if(mask32)
236 gsFontM->Header.offset_table[offset] = gsFontM->Header.offset_table[offset - 1];
237 else
238 gsFontM->Header.offset_table[offset] = (offset * 338);
239 }
240
241 // Swap nibbles around so it shows up correctly
242 tmpdst = (u8 *)((u32)gsFontM->TexBase | 0x30000000);
243 tmpsrc = (u8 *)temp2;
244
245 for(byte = 0; byte < TexSize; byte++)
246 {
247 tmpdst[byte] = (tmpsrc[byte] << 4) | (tmpsrc[byte] >> 4);
248 }
249
250 free(temp2);
251
252 free(unpacked);
253
254#ifdef GSKIT_DEBUG
255 printf("FONTM Header:\n");
256 printf("\tSIG: 0x%08X\n", gsFontM->Header.sig);
257 printf("\tVersion: 0x%08X\n", gsFontM->Header.version);
258 printf("\tBitsize: 0x%08X\n", gsFontM->Header.bitsize);
259 printf("\tBaseOffset: 0x%08X\n", gsFontM->Header.baseoffset);
260 printf("\tNum Entries: 0x%08X\n", gsFontM->Header.num_entries);
261 printf("\tEOF: 0x%08X\n", gsFontM->Header.eof);
262#endif
263
264 return 0;
265}
266
267void gsKit_fontm_unpack_raw(u8 *base, struct gsKit_fontm_unpack *oke)
268{
269 u32 val, count, i;
270 u8 *p, *src;
271
272 for (i=0, p=base; p < base+oke->size; i--, oke->data <<= 1)
273 {
274 if (i == 0)
275 {
276 i = 30;
277 gsKit_fontm_unpack_raw_1(oke);
278 }
279
280 if (oke->data & 0x80000000)
281 {
282 val = *oke->ptr++ << 8;
283 val |= *oke->ptr++;
284 src = p - (val & oke->shft) - 1;
285 count = (val >> oke->dif) + 2;
286
287
288 do
289 {
290 *p++ = *src++;
291 }while(count--);
292 }
293 else
294 *p++ = *oke->ptr++;
295 }
296}
297
298void gsKit_fontm_unpack_raw_1(struct gsKit_fontm_unpack *oke)
299{
300 oke->data = *oke->ptr++ << 8;
301 oke->data = (oke->data | *oke->ptr++) << 8;
302 oke->data = (oke->data | *oke->ptr++) << 8;
303 oke->data = oke->data | *oke->ptr++;
304 oke->shft=0x3FFF >> (oke->data & 3);
305 oke->dif=14 - (oke->data & 3);
306 oke->ande=oke->data & 3;
307}
308
312static u32 gsKit_fontm_ascii[128] = { 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 7
313 0, 0, 0, 0, 0, 0, 0, 0, // 8 - 15
314 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 23
315 0, 0, 0, 0, 0, 0, 0, 0, // 24 - 31
316 0, 9, 40, 83, 79, 82, 84, 38, // 32 - 39
317 41, 42, 85, 59, 3, 60, 4, 30, // 40 - 47
318 203, 204, 205, 206, 207, 208, 209, 210, // 48 - 55
319 211, 212, 6, 7, 66, 64, 67, 8, // 56 - 63
320 86, 220, 221, 222, 223, 224, 225, 226, // 64 - 71
321 227, 228, 229, 230, 231, 232, 233, 234, // 72 - 79
322 235, 236, 237, 238, 239, 240, 241, 242, // 80 - 87
323 243, 244, 245, 45, 31, 46, 15, 17, // 88 - 95
324 13, 252, 253, 254, 255, 256, 257, 258, // 96 - 103
325 259, 260, 261, 262, 263, 264, 265, 266, // 104 - 111
326 267, 268, 269, 270, 271, 272, 273, 274, // 112 - 119
327 275, 276, 277, 47, 34, 48, 32, 0 }; // 120 - 127
328
329void gsKit_fontm_print_scaled(GSGLOBAL *gsGlobal, GSFONTM *gsFontM, float X, float Y, int Z,
330 float scale, unsigned long color, const char *String)
331{
332 u64 oldalpha;
333 u8 oldpabe;
334 u8 fixate;
335
336 int length;
337 int pos;
338
339 u32 linechars[GSKIT_FONTM_MAXLINES];
340
341 float posx[GSKIT_FONTM_MAXLINES];
342 float posy;
343
344 char cur;
345
346 u32 aligned, idxoffset, idxremain;
347
348 u8 numlines;
349 u8 curline;
350 int tabscale;
351
352 oldalpha = gsGlobal->PrimAlpha;
353 oldpabe = gsGlobal->PABE;
354 fixate = 0;
355
356 if(gsGlobal->Test->ATE)
357 {
359 fixate = 1;
360 }
362 posy = Y;
363 length = strlen(String);
364
365 numlines = 0;
366 curline = 0;
367 linechars[0] = 0;
368
369 tabscale = (104.0f * scale);
370
371 for(pos = 0; pos < length; pos++)
372 {
373 cur = String[pos];
374 if(cur != '\n' && cur != '\t')
375 {
376 linechars[numlines]++;
377 }
378 else if(cur == '\n')
379 {
380 numlines++;
381 linechars[numlines] = 0;
382 }
383 else if(cur == '\t' && gsFontM->Align != GSKIT_FALIGN_LEFT)
384 {
385 printf("WARNING: Tabs not supported in GSKIT_FALIGN_CENTER/RIGHT\n");
386 break;
387 }
388 }
389 numlines++;
390
391 for(curline = 0; curline < numlines; curline++)
392 {
393 if(gsFontM->Align == GSKIT_FALIGN_LEFT)
394 posx[curline] = X;
395 else if(gsFontM->Align == GSKIT_FALIGN_CENTER)
396 posx[curline] = X - (((26.0f * linechars[curline]) * gsFontM->Spacing * scale) / 2.0f);
397 else if(gsFontM->Align == GSKIT_FALIGN_RIGHT)
398 posx[curline] = X - ((26.0f * linechars[curline]) * gsFontM->Spacing * scale);
399 }
400
401 curline = 0;
402
403 for(pos = 0; pos < length; pos++)
404 {
405 cur = String[pos];
406
407 if(cur == '\n')
408 {
409 curline++;
410 posy += (26.0f * scale);
411 }
412 else if(cur == '\t')
413 {
414
415 u8 tab = (posx[curline] / tabscale);
416 if((int)posx % tabscale)
417 tab++;
418 posx[curline] = (tab * tabscale);
419 }
420 else if(cur == ' ')
421 {
422 posx[curline] += (26.0f * gsFontM->Spacing * scale);
423 }
424 else
425 {
426 int idx;
427 int pgindx;
428 u32 uoffset;
429 u32 voffset;
430 u64 *p_data;
431
432 uoffset = 0;
433
434 if(cur == '\f')
435 {
436 char code[4];
437 memcpy(code, &String[pos+1], 4);
438 pos+=4;
439 idx = atoi(code);
440 }
441 else if(cur == '\e')
442 {
443 u32 slen = 0;
444 pos++;
445 for(slen = 0; ((pos + slen) < length) &&
446 String[pos + slen] >= 'a' &&
447 String[pos + slen] <= 'z'; slen++);
448
449 if((pos+slen) <= length)
450 {
451 char extstr[slen + 1];
452 memcpy(extstr, &String[pos], slen);
453 extstr[slen] = 0x00;
454
455 pos += slen;
456
457 if(!strcmp(extstr, "le"))
458 idx = 68;
459 else if(!strcmp(extstr, "ge"))
460 idx = 69;
461 else if(!strcmp(extstr, "inf"))
462 idx = 70;
463 else if(!strcmp(extstr, "male"))
464 idx = 72;
465 else if(!strcmp(extstr, "female"))
466 idx = 73;
467 else if(!strcmp(extstr, "degc"))
468 idx = 77;
469 else if(!strcmp(extstr, "yen"))
470 idx = 78;
471 else if(!strcmp(extstr, "cent"))
472 idx = 80;
473 else if(!strcmp(extstr, "pound"))
474 idx = 81;
475 else if(!strcmp(extstr, "left"))
476 idx = 793;
477 else if(!strcmp(extstr, "right"))
478 idx = 792;
479 else if(!strcmp(extstr, "fup"))
480 idx = 798;
481 else if(!strcmp(extstr, "fdown"))
482 idx = 799;
483 else if(!strcmp(extstr, "fleft"))
484 idx = 797;
485 else if(!strcmp(extstr, "fright"))
486 idx = 796;
487 else if(!strcmp(extstr, "hup"))
488 idx = 802;
489 else if(!strcmp(extstr, "hdown"))
490 idx = 803;
491 else if(!strcmp(extstr, "hleft"))
492 idx = 801;
493 else if(!strcmp(extstr, "hright"))
494 idx = 800;
495 else if(!strcmp(extstr, "ms"))
496 idx = 864;
497 else if(!strcmp(extstr, "us"))
498 idx = 865;
499 else if(!strcmp(extstr, "ns"))
500 idx = 866;
501 else if(!strcmp(extstr, "degf"))
502 idx = 868;
503 else if(!strcmp(extstr, "mbit"))
504 idx = 869;
505 else if(!strcmp(extstr, "hz"))
506 idx = 871;
507 else if(!strcmp(extstr, "kb"))
508 idx = 873;
509 else if(!strcmp(extstr, "mb"))
510 idx = 874;
511 else if(!strcmp(extstr, "gb"))
512 idx = 875;
513 else if(!strcmp(extstr, "tb"))
514 idx = 876;
515 else
516 idx = 0;
517 }
518 else
519 idx = 0;
520
521 pos--;
522 }
523 else
524 idx = gsKit_fontm_ascii[(int)cur];
525
526 idxoffset = idx / 64;
527 idxremain = idx % 64;
528
529 aligned = ((u32)gsFontM->TexBase + gsFontM->Header.offset_table[idxoffset * 64]);
530
531 if(idxremain % 2)
532 uoffset = 26;
533
534 idxremain /= 2;
535
536 voffset = (idxremain * 26);
537
538 p_data = gsKit_heap_alloc(gsGlobal, 1, 16, GIF_AD);
539
540 *p_data++ = GIF_TAG_AD(1);
541 *p_data++ = GIF_AD;
542
544 uoffset, uoffset + 25,
545 voffset, voffset + 25);
546
547 *p_data++ = GS_CLAMP_1+gsGlobal->PrimContext;
548
549 for (pgindx=0; pgindx<GS_FONTM_PAGE_COUNT; pgindx++) {
550 if (gsFontM->Texture[pgindx]->Mem == (void *)aligned) {
551 // Page found
552 break;
553 }
554 }
555 if (pgindx >= GS_FONTM_PAGE_COUNT) {
556 // Page not found
557 // Try to find unused page first
558 for (pgindx=0; pgindx<GS_FONTM_PAGE_COUNT; pgindx++) {
559 if (gsFontM->Texture[pgindx]->Mem == 0) {
560 // Unused page found
561 break;
562 }
563 }
564 // Invalidate a page if no free page found
565 if (pgindx >= GS_FONTM_PAGE_COUNT) {
566 pgindx = (gsFontM->VramIdx + 1) % GS_FONTM_PAGE_COUNT;
568 }
569
570 gsFontM->Texture[pgindx]->Mem = (void *)aligned;
571 //printf("Mem[%d] = 0x%x\n", pgindx, aligned);
572 }
573
574 gsFontM->VramIdx = pgindx; // Last used page index
576 gsKit_prim_sprite_texture(gsGlobal, gsFontM->Texture[pgindx], posx[curline], posy, uoffset, voffset,
577 (float)posx[curline] + (26.0f * scale), (float)posy + (26.0f * scale), uoffset + 26, voffset + 27, Z, color);
578
579 posx[curline] += (26.0f * gsFontM->Spacing * scale);
580 }
581 }
582
583 gsGlobal->PABE = oldpabe;
584 gsGlobal->PrimAlpha=oldalpha;
587
588 if(fixate)
590}
#define GS_ATEST_OFF
Turns off Alpha Testing (Source).
Definition gsCore.h:62
#define GS_ATEST_ON
Turns on Alpha Testing (Source).
Definition gsCore.h:64
void gsKit_set_clamp(GSGLOBAL *gsGlobal, u8 Preset)
Definition gsCore.c:318
#define GS_CMODE_RESET
Resets CLAMP vales to whatever is in gsGlobal->Clamp.
Definition gsCore.h:52
#define GS_FILTER_LINEAR
Use bilinear filter on texture.
Definition gsCore.h:73
#define GS_CMODE_REGION_CLAMP
Stretches Texture Across the Region Defined by MINU, MAXU, MINV, and MAXV.
Definition gsCore.h:48
void gsKit_set_primalpha(GSGLOBAL *gsGlobal, u64 AlphaMode, u8 PerPixel)
Sets the Alpha Blending Parameters.
Definition gsCore.c:356
void gsKit_set_test(GSGLOBAL *gsGlobal, u8 Preset)
Definition gsCore.c:286
void gsKit_free_fontm(GSGLOBAL *gsGlobal, GSFONTM *gsFontM)
Free Font Object.
Definition gsFontM.c:41
GSFONTM * gsKit_init_fontm()
Create Font Object.
Definition gsFontM.c:29
#define GIF_TAG_AD(NLOOP)
A+D GIFTAG.
Definition gsInit.h:308
#define GS_PSM_CT32
R8 G8 B8 A8 (RGBA32) Texture.
Definition gsInit.h:115
#define GS_CLAMP_1
GS Texture Wrap Mode (Context 1).
Definition gsInit.h:172
#define GS_PSM_T4
4 Bit Texture with CLUT
Definition gsInit.h:127
#define GS_SETREG_ALPHA(A, B, C, D, FIX)
GS ALPHA Packing Macro.
Definition gsInit.h:796
#define GIF_AD
GIF_TAG Address+Data Setting. (Used after GIF_TAG).
Definition gsInit.h:494
#define GS_SETREG_CLAMP(wms, wmt, minu, maxu, minv, maxv)
GS CLAMP Packing Macro.
Definition gsInit.h:790
unsigned int gsKit_TexManager_bind(GSGLOBAL *gsGlobal, GSTEXTURE *tex)
Bind a texture to VRAM, will automatically transfer the texture.
void gsKit_TexManager_invalidate(GSGLOBAL *gsGlobal, GSTEXTURE *tex)
Invalidate a texture, will automatically transfer the texture on next bind call.
void gsKit_TexManager_free(GSGLOBAL *gsGlobal, GSTEXTURE *tex)
GSFONTMHDR Header
FONTM Header.
Definition gsFontM.h:69
GSTEXTURE * Texture[GS_FONTM_PAGE_COUNT]
Font Texture Objects.
Definition gsFontM.h:68
u32 VramIdx
FONTM Current Double Buffer Index.
Definition gsFontM.h:70
float Spacing
FONTM Glyph Spacing.
Definition gsFontM.h:72
u8 Align
FONTM Line Alignment.
Definition gsFontM.h:71
void * TexBase
Glyphs Texture Base.
Definition gsFontM.h:73
GSTEST * Test
TEST Register Value Structure Pointer.
Definition gsInit.h:932
int PrimContext
Primitive Context.
Definition gsInit.h:942
u64 PrimAlpha
Primitive Alpha Value.
Definition gsInit.h:946
u8 PABE
Choose if to do Alpha Blend on a Per-Pixel Basis.
Definition gsInit.h:947
u8 ATE
Alpha Test Enable.
Definition gsInit.h:826
u32 * Clut
EE CLUT Memory Pointer.
Definition gsInit.h:962
u32 * Mem
EE Memory Pointer.
Definition gsInit.h:961
u8 ClutPSM
CLUT Pixel Storage Method (Color Format).
Definition gsInit.h:959
u8 PSM
Pixel Storage Method (Color Format).
Definition gsInit.h:958
u32 Height
Height of the Texture.
Definition gsInit.h:957
u32 Width
Width of the Texture.
Definition gsInit.h:956
u32 Filter
NEAREST or LINEAR.
Definition gsInit.h:965