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