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