1 /*****************************************************************************
2 * font.c
3 *
4 * IPL font engine (using GX rendering)
5 *
6 * Copyright Eke-Eke (2009-2016)
7 *
8 * Redistribution and use of this code or any derivative works are permitted
9 * provided that the following conditions are met:
10 *
11 * - Redistributions may not be sold, nor may they be used in a commercial
12 * product or activity.
13 *
14 * - Redistributions that are modified from the original source must include the
15 * complete source code, including the source code for all components used by a
16 * binary built from the modified sources. However, as a special exception, the
17 * source code distributed need not include anything that is normally distributed
18 * (in either source or binary form) with the major components (compiler, kernel,
19 * and so on) of the operating system on which the executable runs, unless that
20 * component itself accompanies the executable.
21 *
22 * - Redistributions must reproduce the above copyright notice, this list of
23 * conditions and the following disclaimer in the documentation and/or other
24 * materials provided with the distribution.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 *
38 ****************************************************************************************/
39
40 #include "shared.h"
41 #include "font.h"
42
43 #define _SHIFTR(v, s, w) \
44 ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1)))
45
46 typedef struct _yay0header {
47 unsigned int id ATTRIBUTE_PACKED;
48 unsigned int dec_size ATTRIBUTE_PACKED;
49 unsigned int links_offset ATTRIBUTE_PACKED;
50 unsigned int chunks_offset ATTRIBUTE_PACKED;
51 } yay0header;
52
53 static u8 *fontImage;
54 static u8 *fontTexture;
55 static GXTexObj fontTexObj;
56 static void *ipl_fontarea;
57 static sys_fontheader *fontHeader;
58 static u8 font_size[256];
59
60 #ifndef HW_RVL
61
62 /* disable Qoob Modchip before IPL access (emukiddid) */
ipl_set_config(unsigned char c)63 static void ipl_set_config(unsigned char c)
64 {
65 volatile unsigned long* exi = (volatile unsigned long*)0xCC006800;
66 unsigned long val,addr;
67 addr=0xc0000000;
68 val = c << 24;
69 exi[0] = ((((exi[0]) & 0x405) | 256) | 48); //select IPL
70 //write addr of IPL
71 exi[0 * 5 + 4] = addr;
72 exi[0 * 5 + 3] = ((4 - 1) << 4) | (1 << 2) | 1;
73 while (exi[0 * 5 + 3] & 1);
74 //write the ipl we want to send
75 exi[0 * 5 + 4] = val;
76 exi[0 * 5 + 3] = ((4 - 1) << 4) | (1 << 2) | 1;
77 while (exi[0 * 5 + 3] & 1);
78 exi[0] &= 0x405; //deselect IPL
79 }
80
81 #endif
82
decode_szp(void * src,void * dest)83 static void decode_szp(void *src,void *dest)
84 {
85 u32 i,k,link;
86 u8 *dest8,*tmp;
87 u32 loff,coff,roff;
88 u32 size,cnt,cmask,bcnt;
89 yay0header *header;
90
91 dest8 = (u8*)dest;
92 header = (yay0header*)src;
93 size = header->dec_size;
94 loff = header->links_offset;
95 coff = header->chunks_offset;
96
97 roff = sizeof(yay0header);
98 cmask = 0;
99 cnt = 0;
100 bcnt = 0;
101
102 do {
103 if(!bcnt) {
104 cmask = *(u32*)(src+roff);
105 roff += 4;
106 bcnt = 32;
107 }
108
109 if(cmask&0x80000000) {
110 dest8[cnt++] = *(u8*)(src+coff);
111 coff++;
112 } else {
113 link = *(u16*)(src+loff);
114 loff += 2;
115
116 tmp = dest8+(cnt-(link&0x0fff)-1);
117 k = link>>12;
118 if(k==0) {
119 k = (*(u8*)(src+coff))+18;
120 coff++;
121 } else k += 2;
122
123 for(i=0;i<k;i++) {
124 dest8[cnt++] = tmp[i];
125 }
126 }
127 cmask <<= 1;
128 bcnt--;
129 } while(cnt<size);
130 }
131
expand_font(u8 * src,u8 * dest)132 static void expand_font(u8 *src,u8 *dest)
133 {
134 s32 cnt;
135 u32 idx;
136 u8 val1,val2;
137 sys_fontheader *sys_fontdata = fontHeader;
138 u8 *data = (u8*)sys_fontdata+44;
139
140 if(sys_fontdata->sheet_format==0x0000) {
141 cnt = (sys_fontdata->sheet_fullsize/2)-1;
142
143 while(cnt>=0) {
144 idx = _SHIFTR(src[cnt],6,2);
145 val1 = data[idx];
146
147 idx = _SHIFTR(src[cnt],4,2);
148 val2 = data[idx];
149
150 dest[(cnt<<1)+0] =((val1&0xf0)|(val2&0x0f));
151
152 idx = _SHIFTR(src[cnt],2,2);
153 val1 = data[idx];
154
155 idx = _SHIFTR(src[cnt],0,2);
156 val2 = data[idx];
157
158 dest[(cnt<<1)+1] =((val1&0xf0)|(val2&0x0f));
159
160 cnt--;
161 }
162 }
163 DCStoreRange(dest,sys_fontdata->sheet_fullsize);
164 }
165
GetFontTexel(s32 c,void * image,s32 pos,s32 stride)166 static void GetFontTexel(s32 c,void *image,s32 pos,s32 stride)
167 {
168 u32 sheets,rem;
169 u32 xoff,yoff;
170 u32 xpos,ypos;
171 u8 *img_start;
172 u8 *ptr1,*ptr2;
173 sys_fontheader *sys_fontdata = fontHeader;
174
175 if(c<sys_fontdata->first_char || c>sys_fontdata->last_char) c = sys_fontdata->inval_char;
176 else c -= sys_fontdata->first_char;
177
178 sheets = sys_fontdata->sheet_column*sys_fontdata->sheet_row;
179 rem = c%sheets;
180 sheets = c/sheets;
181 xoff = (rem%sys_fontdata->sheet_column)*sys_fontdata->cell_width;
182 yoff = (rem/sys_fontdata->sheet_column)*sys_fontdata->cell_height;
183 img_start = fontImage+(sys_fontdata->sheet_size*sheets);
184
185 ypos = 0;
186 while(ypos<sys_fontdata->cell_height) {
187 xpos = 0;
188 while(xpos<sys_fontdata->cell_width) {
189 ptr1 = img_start+(((sys_fontdata->sheet_width/8)<<5)*((ypos+yoff)/8));
190 ptr1 = ptr1+(((xpos+xoff)/8)<<5);
191 ptr1 = ptr1+(((ypos+yoff)%8)<<2);
192 ptr1 = ptr1+(((xpos+xoff)%8)/2);
193
194 ptr2 = image+((ypos/8)*(((stride<<1)/8)<<5));
195 ptr2 = ptr2+(((xpos+pos)/8)<<5);
196 ptr2 = ptr2+(((xpos+pos)%8)/2);
197 ptr2 = ptr2+((ypos%8)<<2);
198
199 *ptr2 = *ptr1;
200
201 xpos += 2;
202 }
203 ypos++;
204 }
205 }
206
DrawChar(unsigned char c,int xpos,int ypos,int size,GXColor color)207 static void DrawChar(unsigned char c, int xpos, int ypos, int size, GXColor color)
208 {
209 /* get font texture data */
210 memset(fontTexture,0,fontHeader->cell_width * fontHeader->cell_height / 2);
211 GetFontTexel(c,fontTexture,0,fontHeader->cell_width/2);
212 DCStoreRange(fontTexture, fontHeader->cell_width * fontHeader->cell_height / 2);
213 GX_InvalidateTexAll();
214
215 /* adjust texture width */
216 s32 width = (fontHeader->cell_width * size * vmode->fbWidth) / (fontHeader->cell_height * vmode->viWidth);
217
218 /* adjust texture height */
219 size = (size * vmode->efbHeight) / 480;
220
221 /* GX rendering */
222 GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
223 GX_Position2s16(xpos, ypos - size);
224 GX_Color4u8(color.r, color.g, color.b, 0xff);
225 GX_TexCoord2f32(0.0, 0.0);
226 GX_Position2s16(xpos + width, ypos - size);
227 GX_Color4u8(color.r, color.g, color.b, 0xff);
228 GX_TexCoord2f32(1.0, 0.0);
229 GX_Position2s16(xpos + width, ypos);
230 GX_Color4u8(color.r, color.g, color.b, 0xff);
231 GX_TexCoord2f32(1.0, 1.0);
232 GX_Position2s16(xpos, ypos);
233 GX_Color4u8(color.r, color.g, color.b, 0xff);
234 GX_TexCoord2f32(0.0, 1.0);
235 GX_End();
236 GX_DrawDone();
237 }
238
239 /****************************************************************************
240 * IPL font support
241 *
242 ****************************************************************************/
243 extern void __SYS_ReadROM(void *buf,u32 len,u32 offset);
244
FONT_Init(void)245 int FONT_Init(void)
246 {
247 #ifndef HW_RVL
248 /* --- Game Cube --- disable Qoob before accessing IPL */
249 ipl_set_config(6);
250 #endif
251
252 /* read IPL font (ASCII) from Mask ROM */
253 ipl_fontarea = memalign(32,131360);
254 if (!ipl_fontarea)
255 return 0;
256 memset(ipl_fontarea,0,131360);
257 __SYS_ReadROM(ipl_fontarea+119072,12288,0x1FCF00);
258
259 /* YAY0 decompression */
260 decode_szp(ipl_fontarea+119072,ipl_fontarea);
261
262 /* retrieve IPL font data */
263 fontHeader = (sys_fontheader*)ipl_fontarea;
264 fontImage = (u8*)((((u32)ipl_fontarea+fontHeader->sheet_image)+31)&~31);
265
266 /* expand to I4 format */
267 expand_font((u8*)ipl_fontarea+fontHeader->sheet_image,fontImage);
268
269 /* character width table */
270 int i,c;
271 for (i=0; i<256; ++i)
272 {
273 if ((i < fontHeader->first_char) || (i > fontHeader->last_char))
274 c = fontHeader->inval_char;
275 else
276 c = i - fontHeader->first_char;
277
278 font_size[i] = ((u8*)fontHeader)[fontHeader->width_table + c];
279 }
280
281 /* initialize texture data */
282 fontTexture = memalign(32, fontHeader->cell_width * fontHeader->cell_height / 2);
283 if (!fontTexture)
284 {
285 free(ipl_fontarea);
286 return 0;
287 }
288
289 /* initialize texture object */
290 GX_InitTexObj(&fontTexObj, fontTexture, fontHeader->cell_width, fontHeader->cell_height, GX_TF_I4, GX_CLAMP, GX_CLAMP, GX_FALSE);
291
292 return 1;
293 }
294
FONT_Shutdown(void)295 void FONT_Shutdown(void)
296 {
297 if (fontHeader)
298 free(ipl_fontarea);
299 if (fontTexture)
300 free(fontTexture);
301 }
302
FONT_write(char * string,int size,int x,int y,int max_width,GXColor color)303 int FONT_write(char *string, int size, int x, int y, int max_width, GXColor color)
304 {
305 int w, ox;
306
307 GX_LoadTexObj(&fontTexObj, GX_TEXMAP0);
308
309 x -= (vmode->fbWidth / 2);
310 y -= (vmode->efbHeight / 2);
311
312 ox = x;
313
314 while (*string)
315 {
316 if (*string == '\n')
317 {
318 x = ox;
319 y += size;
320 }
321 else
322 {
323 w = (font_size[(u8)*string] * size * vmode->fbWidth) / (fontHeader->cell_height * vmode->viWidth);
324 if ((x + w) > (ox + max_width)) return strlen(string);
325 DrawChar(*string, x, y, size,color);
326 x += w;
327 }
328 string++;
329 }
330
331 return 0;
332 }
333
FONT_writeCenter(char * string,int size,int x1,int x2,int y,GXColor color)334 int FONT_writeCenter(char *string, int size, int x1, int x2, int y, GXColor color)
335 {
336 int x;
337 int i = 0;
338 int w = 0;
339
340 GX_LoadTexObj(&fontTexObj, GX_TEXMAP0);
341
342 while (string[i] && (string[i] != '\n'))
343 {
344 w += (font_size[(u8)string[i++]] * size * vmode->fbWidth) / (fontHeader->cell_height * vmode->viWidth);
345 }
346
347 if ((x1 + w) > x2) w = x2 - x1;
348 x = x1 + (x2 - x1 - w - vmode->fbWidth) / 2;
349 x2 -= (vmode->fbWidth / 2);
350 y -= (vmode->efbHeight / 2);
351
352 while (*string && (*string != '\n'))
353 {
354 w = (font_size[(u8)*string] * size * vmode->fbWidth) / (fontHeader->cell_height * vmode->viWidth);
355 if ((x + w) > x2) return strlen(string);
356 DrawChar(*string, x, y, size,color);
357 x += w;
358 string++;
359 }
360
361 if (*string == '\n')
362 {
363 string++;
364 return FONT_writeCenter(string, size, x1, x2 + (vmode->fbWidth / 2), y + size + (vmode->efbHeight / 2), color);
365 }
366
367 return 0;
368 }
369
FONT_alignRight(char * string,int size,int x,int y,GXColor color)370 int FONT_alignRight(char *string, int size, int x, int y, GXColor color)
371 {
372 int ox;
373 int i = 0;
374 int w = 0;
375
376 GX_LoadTexObj(&fontTexObj, GX_TEXMAP0);
377
378 while (string[i] && (string[i] != '\n'))
379 {
380 w += (font_size[(u8)string[i++]] * size * vmode->fbWidth) / (fontHeader->cell_height * vmode->viWidth);
381 }
382
383 x -= (vmode->fbWidth / 2);
384 y -= (vmode->efbHeight / 2);
385
386 ox = x;
387 x -= w;
388
389 while (*string && (*string != '\n'))
390 {
391 w = (font_size[(u8)*string] * size * vmode->fbWidth) / (fontHeader->cell_height * vmode->viWidth);
392 if ((x + w) > ox) return strlen(string);
393 DrawChar(*string, x, y, size,color);
394 x += w;
395 string++;
396 }
397
398 if (*string == '\n')
399 {
400 string++;
401 return FONT_alignRight(string, size, ox + (vmode->fbWidth / 2), y + size + (vmode->efbHeight / 2), color);
402 }
403
404 return 0;
405 }
406