1 /*---------------------------------------------------------------------------*
2   Project:     KPAD sample program
3   File:        kfont.c
4   Programmer:  Keizo Ohta
5 
6   Copyright 2005 Nintendo. All rights reserved.
7 
8   These coded instructions, statements, and computer programs contain
9   proprietary information of Nintendo of America Inc. and/or Nintendo
10   Company Ltd., and are protected by Federal copyright law.  They may
11   not be disclosed to third parties or copied or duplicated in any form,
12   in whole or in part, without the prior written consent of Nintendo.
13  *---------------------------------------------------------------------------*/
14 
15 #include <revolution.h>
16 #include <math.h>
17 
18 #include "kfont.h"
19 
20 
21 /***************************************************************
22     Definitions
23 ***************************************************************/
24 #define KFONT_MAX       (10+26+2)               // "0~9" "A~Z" "." "-"
25 #define KFONT_WD        24                      // SDK fixed
26 #define KFONT_HT        24                      // SDK fixed
27 #define KFONT_SHEET_WD  (KFONT_WD * KFONT_MAX)  // Support up to 1024.
28 #define KFONT_SHEET_HT   KFONT_HT
29 #define KFONT_TEX_SIZE  (KFONT_SHEET_WD * KFONT_SHEET_HT * 4 / 8)
30 
31 
32 /***************************************************************
33     Variables
34 ***************************************************************/
35 static f32 canvas_wd,canvas_ht ;    // Virtual canvas size
36 static f32 cursor_wd,cursor_ht ;    // Cursor size
37 static s32 cursor_nx,cursor_ny ;    // Number of cursors arranged on canvas
38 static f32 cursor_x1,cursor_y1 ;    // Coordinate of upper leftmost cursor
39 static f32 letter_ox,letter_oy ;    // Offset from the cursor position to the character position
40 static f32 letter_wd,letter_ht ;    // Character size
41 
42 static char     *kfont_str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.-" ;
43 static void     *kfont_tex ;
44 static GXTexObj  kfont_tobj ;
45 
46 static f32 s1_ofs ;    // Adjust the display of fonts that differ between the Japanese and US versions of the console
47 static f32 s2_ofs ;    //
48 static f32 t1_ofs ;    //
49 
50 
51 /*******************************************************************************
52     Prepare a texture from a built-in font
53 *******************************************************************************/
init_kfont_texture(void)54 void init_kfont_texture( void )
55 {
56     OSFontHeader *font ;
57     void         *tmp ;
58     void         *tex_p ;
59     char         *str_p ;
60     u32          *ptr ;
61     s32           wd, ofs ;
62 
63 
64     //----- Allocate texture buffer
65     kfont_tex = OSAlloc( KFONT_TEX_SIZE ) ;
66 
67     //----- Clear texture buffer
68     ptr = (u32*)( (u32)kfont_tex + KFONT_TEX_SIZE ) - 1 ;
69     do {
70         *ptr = 0x00000000 ;
71     } while ( --ptr != (u32*)kfont_tex ) ;
72 
73     //----- Load font data
74     if ( OSGetFontEncode() == OS_FONT_ENCODE_SJIS ) {
75         font = (OSFontHeader*)OSAlloc( OS_FONT_DATA_SIZE_SJIS ) ;
76         tmp  = OSAlloc( OS_FONT_ROM_SIZE_SJIS ) ;
77 
78         s1_ofs =  0.15f * (f32)KFONT_WD / (f32)KFONT_SHEET_WD ;
79         s2_ofs = -0.30f * (f32)KFONT_WD / (f32)KFONT_SHEET_WD ;
80         t1_ofs =  0.00f ;
81     } else {
82         font = (OSFontHeader*)OSAlloc( OS_FONT_DATA_SIZE_ANSI ) ;
83         tmp  = OSAlloc( OS_FONT_ROM_SIZE_ANSI ) ;
84 
85         s1_ofs =  0.05f * (f32)KFONT_WD / (f32)KFONT_SHEET_WD ;
86         s2_ofs = -0.10f * (f32)KFONT_WD / (f32)KFONT_SHEET_WD ;
87         t1_ofs = 0.13f ;
88     }
89     (void)OSLoadFont( font, tmp ) ;
90 
91     //----- Convert font data to a texture
92     tex_p = kfont_tex ;
93     str_p = kfont_str ;
94     do {
95         (void)OSGetFontWidth( str_p, &wd ) ;
96         ofs = ( KFONT_WD - wd ) / 2 ;
97         (void)OSGetFontTexel( str_p, tex_p, ofs+1, KFONT_SHEET_WD/4, &wd ) ;
98         str_p = OSGetFontTexel( str_p, tex_p, ofs, KFONT_SHEET_WD/4, &wd ) ;
99         tex_p = (void*)( (u32)tex_p + KFONT_WD / 8 * 32 ) ;
100     } while ( *str_p != '\0' ) ;
101 
102     DCStoreRange( kfont_tex, KFONT_TEX_SIZE ) ;
103     GXInitTexObj( &kfont_tobj, kfont_tex, KFONT_SHEET_WD,KFONT_SHEET_HT, GX_TF_I4, GX_CLAMP,GX_CLAMP, GX_FALSE ) ;
104     GXInitTexObjLOD( &kfont_tobj, GX_LINEAR,GX_LINEAR, 0.0f,0.0f, 0.0f, GX_DISABLE, GX_FALSE, GX_ANISO_1 ) ;
105 
106     //----- Free font data
107     OSFree( font ) ;
108     OSFree( tmp ) ;
109 }
110 
111 
112 /*******************************************************************************
113     Initialize drawing of simple graphics
114     fb_width  :Horizontal resolution of frame buffer
115     fb_height :Vertical resolution of frame buffer
116     lt_width  :Letter width (line from center to center)
117     lt_height :Letter height (line from center to center)
118 ******************************************************************************/
init_draw_kfont(u16 fb_width,u16 fb_height,f32 lt_width,f32 lt_height)119 void init_draw_kfont( u16 fb_width, u16 fb_height, f32 lt_width, f32 lt_height )
120 {
121     Mtx44 proj_mtx ;
122     Mtx   view_mtx ;
123 
124 
125     //----- Calculate variables
126     canvas_wd = fb_width * 0.91346f ;
127     canvas_ht = fb_height ;
128     letter_wd = lt_width  ;
129     letter_ht = lt_height ;
130     cursor_wd = letter_wd * 0.90f ;        // Reduce the space between letters a bit
131     cursor_ht = letter_ht * 1.05f ;        // Make a little extra room in the vertical direction
132     letter_ox = ( cursor_wd - letter_wd ) * 0.5f ;
133     letter_oy = ( cursor_ht - letter_ht ) * 0.5f ;
134     cursor_nx = (s32)( canvas_wd / cursor_wd  ) ;
135     cursor_ny = (s32)( canvas_ht / cursor_ht ) ;
136     cursor_x1 = (f32)cursor_nx * cursor_wd * -0.5f ;
137     cursor_y1 = (f32)cursor_ny * cursor_ht * -0.5f ;
138 
139     //----- MTX
140     MTXOrtho( proj_mtx, canvas_ht * -0.5f,canvas_ht * 0.5f, canvas_wd * -0.5f,canvas_wd * 0.5f, -10.0f,10.0f ) ;
141     GXSetProjection( proj_mtx, GX_ORTHOGRAPHIC ) ;
142 
143     MTXIdentity( view_mtx ) ;
144     GXLoadPosMtxImm( view_mtx, GX_PNMTX0 ) ;
145     GXSetCurrentMtx( GX_PNMTX0 ) ;
146 
147     //----- VERTEX
148     GXClearVtxDesc() ;
149     GXSetVtxDesc( GX_VA_POS , GX_DIRECT ) ;
150     GXSetVtxDesc( GX_VA_TEX0, GX_DIRECT ) ;
151     GXSetVtxAttrFmt( GX_VTXFMT0, GX_VA_POS , GX_POS_XY, GX_F32, 0 ) ;
152     GXSetVtxAttrFmt( GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0 ) ;
153 
154     //----- CHANNEL
155     GXSetNumChans( 0 ) ;
156     GXSetChanCtrl( GX_COLOR0A0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ) ;
157     GXSetChanCtrl( GX_COLOR1A1, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ) ;
158 
159     //----- TEXTURE
160     GXSetNumTexGens( 1 ) ;
161     GXSetTexCoordGen( GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY ) ;
162     GXLoadTexObj( &kfont_tobj, GX_TEXMAP0 ) ;
163 
164     //----- TEV
165     GXSetNumTevStages( 1 ) ;
166     GXSetTevOrder( GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL ) ;
167     GXSetTevColorIn( GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_C0, GX_CC_TEXC, GX_CC_ZERO ) ;
168     GXSetTevColorOp( GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV ) ;
169     GXSetTevAlphaIn( GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_A0, GX_CA_TEXA, GX_CA_ZERO ) ;
170     GXSetTevAlphaOp( GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV ) ;
171     GXSetAlphaCompare( GX_ALWAYS,0, GX_AOP_OR, GX_ALWAYS,0 ) ;
172 
173     //----- SCREEN
174     GXSetBlendMode( GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_NOOP ) ;
175     GXSetAlphaUpdate( GX_DISABLE ) ;
176 
177     GXSetZMode( GX_DISABLE, GX_ALWAYS, GX_DISABLE ) ;
178     GXSetCullMode( GX_CULL_BACK ) ;
179 }
180 
181 
182 /*******************************************************************************
183     Draw font character
184 *******************************************************************************/
draw_kfont_one(f32 cx,f32 cy,char c)185 static void draw_kfont_one( f32 cx, f32 cy, char c )
186 {
187     f32 x1,x2, y1,y2, s1,s2 ;
188     s32 i ;
189 
190 
191     if ( c >= 'A' && c <= 'Z' ) {
192         i = c - 'A' + 10 ;
193     } else if ( c >= '0' && c <= '9' ) {
194         i = c - '0' ;
195     } else if ( c == '.' ) {
196         i = 10 + 26 ;
197     } else if ( c == '-' ) {
198         i = 10 + 26 + 1 ;
199     } else {
200         return ;
201     }
202 
203     s1 = (f32)( i * KFONT_WD ) / (f32)KFONT_SHEET_WD + s1_ofs ;
204     s2 = s1 + (f32)KFONT_WD / (f32)KFONT_SHEET_WD + s2_ofs ;
205 
206     x1 = cx * cursor_wd + cursor_x1 + letter_ox ;
207     x2 = x1 + letter_wd ;
208 
209     y1 = cy * cursor_ht + cursor_y1 + letter_oy ;
210     y2 = y1 + letter_ht ;
211 
212     GXBegin( GX_QUADS, GX_VTXFMT0, 4 ) ;
213       GXPosition2f32( x1,y1 ) ; GXTexCoord2f32( s1,t1_ofs ) ;
214       GXPosition2f32( x2,y1 ) ; GXTexCoord2f32( s2,t1_ofs ) ;
215       GXPosition2f32( x2,y2 ) ; GXTexCoord2f32( s2,1.0f   ) ;
216       GXPosition2f32( x1,y2 ) ; GXTexCoord2f32( s1,1.0f   ) ;
217     GXEnd() ;
218 }
219 
220 
221 /*******************************************************************************
222     Draw integer (return the number of characters that were drawn)
223 *******************************************************************************/
draw_kfont_s32(f32 cx,f32 cy,GXColor clr,s32 val)224 s32 draw_kfont_s32( f32 cx, f32 cy, GXColor clr, s32 val )
225 {
226     s32 v,a, rt = 0 ;
227     f32 x ;
228 
229 
230     GXSetTevColor( GX_TEVREG0, clr ) ;
231 
232     //----- Prepare positive number
233     if ( val < 0 ) {
234         v = -val ;
235     } else {
236         v = val ;
237     }
238 
239     //----- Draw number beginning from the lowest digit
240     x = cx ;
241     do {
242         a = v % 10 ;
243         draw_kfont_one( x, cy, (char)('0'+ a ) ) ;
244         x -= 1.0f ;
245         ++ rt ;
246         v -= a ;
247         v /= 10 ;
248     } while ( v != 0 ) ;
249 
250     //----- Draw sign
251     if ( val < 0 ) {
252         draw_kfont_one( x, cy, '-' ) ;
253         ++ rt ;
254     }
255 
256     return ( rt ) ;
257 }
258 
259 
260 /*******************************************************************************
261     Draw floating point (also specify the number of digits following the decimal point)
262 *******************************************************************************/
draw_kfont_f32(f32 cx,f32 cy,GXColor clr,f32 val,s32 keta)263 s32 draw_kfont_f32( f32 cx, f32 cy, GXColor clr, f32 val, s32 keta )
264 {
265     s32 v,a, k,n, rt ;
266     f32 x, vf ;
267 
268 
269     GXSetTevColor( GX_TEVREG0, clr ) ;
270 
271     //----- Prepare positive number
272     if ( val < 0.0f ) {
273         vf = -val ;
274     } else {
275         vf = val ;
276     }
277 
278     //----- Calculate the number of displayed digits that follow the decimal point
279     k = (s32)keta ;
280     if ( k < 1 ) k = 1 ;
281 
282     //----- Shift digits so that the portion to be displayed following the decimal point is a positive number
283     n = k ;
284     do {
285         vf *= 10.0f ;
286     } while ( --n != 0 ) ;
287 
288     //----- Draw the number following the decimal point
289     v = (s32)( vf + 0.5f ) ;
290     x = cx + 1.0f + (f32)k ;
291     n = k ;
292     do {
293         a = v % 10 ;
294         draw_kfont_one( x, cy, (char)('0'+ a ) ) ;
295         x -= 1.0f ;
296         v -= a ;
297         v /= 10 ;
298     } while ( --n != 0 ) ;
299 
300     //----- Draw decimal point
301     draw_kfont_one( x, cy, '.' ) ;
302     x -= 1.0f ;
303     rt = 1 + k ;
304 
305     //----- Draw the integer part of the number as an integer
306     if ( val < 0.0f ) {
307         v = -v ;
308     }
309     rt += draw_kfont_s32( cx, cy, clr, v ) ;
310 
311     return ( rt ) ;
312 }
313 
314 
315 /*******************************************************************************
316     Draw binary number (also specify the number of bits to be displayed)
317 *******************************************************************************/
draw_kfont_bit(f32 cx,f32 cy,GXColor clr,u32 val,s32 keta)318 void draw_kfont_bit( f32 cx, f32 cy, GXColor clr, u32 val, s32 keta )
319 {
320     u32 bit = 1 ;
321     s32 n = keta ;
322     f32 x = cx ;
323 
324 
325     GXSetTevColor( GX_TEVREG0, clr ) ;
326 
327     do {
328         if ( (bit & 0x01010100) != 0 ) {
329             draw_kfont_one( x, cy, '-' ) ;
330             x -= 1.0f ;
331         }
332         if ( (val & bit) != 0 ) {
333             draw_kfont_one( x, cy, '1' ) ;
334         } else {
335             draw_kfont_one( x, cy, '0' ) ;
336         }
337         x -= 1.0f ;
338         bit <<= 1 ;
339     } while ( --n != 0 ) ;
340 }
341 
342 
343 /*******************************************************************************
344     Draw character string
345 *******************************************************************************/
draw_kfont_letter(f32 cx,f32 cy,GXColor clr,char * str)346 void draw_kfont_letter( f32 cx, f32 cy, GXColor clr, char *str )
347 {
348     f32  x = cx ;
349     char *cp = str ;
350 
351 
352     GXSetTevColor( GX_TEVREG0, clr ) ;
353 
354     do {
355         draw_kfont_one( x, cy, *cp ) ;
356         x += 1.0f ;
357     } while ( *++cp != '\0' ) ;
358 }
359 
360 
361 /*******************************************************************************
362     Calculate the rectangular coordinate of the character under current canvas settings: Upper left (x1, y1), Lower right (x2, y2)
363 *******************************************************************************/
calc_kfont_x1(f32 cx)364 f32 calc_kfont_x1( f32 cx )
365 {
366     return ( cx * cursor_wd + cursor_x1 + letter_ox ) ;
367 }
368 
calc_kfont_y1(f32 cy)369 f32 calc_kfont_y1( f32 cy )
370 {
371     return ( cy * cursor_ht + cursor_y1 + letter_oy ) ;
372 }
373 
calc_kfont_x2(f32 cx)374 f32 calc_kfont_x2( f32 cx )
375 {
376     return ( cx * cursor_wd + cursor_x1 + letter_ox + letter_wd ) ;
377 }
378 
calc_kfont_y2(f32 cy)379 f32 calc_kfont_y2( f32 cy )
380 {
381     return ( cy * cursor_ht + cursor_y1 + letter_oy + letter_ht ) ;
382 }
383