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