1 /*---------------------------------------------------------------------------*
2   Project:    WPAD Health Demo Program
3   File:       handling_weight.c
4 
5   Copyright (C) 2007 Nintendo.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Log: handling_weight.c,v $
14   Revision 1.4.2.1  2008/08/22 04:44:30  urata
15   Added WPADRegisterBLCWorkarea so that it would run correctly in jp-mode.
16 
17   Revision 1.4  2008/06/17 08:03:33  tojo
18   Removed unused headers.
19 
20   Revision 1.3  2008/04/23 04:05:48  tojo
21   Updated WBCGetTGCWeight to latest spec.
22 
23   Revision 1.2  2008/04/17 05:25:33  tojo
24   Changed API for WBCSetupCalibration.
25 
26   Revision 1.1  2008/04/17 02:55:42  tojo
27   Initial check-in.
28 
29  *---------------------------------------------------------------------------*/
30 
31 #include <revolution.h>
32 #include <revolution/wpad.h>
33 #include <revolution/wpadBalance.h>
34 #include <revolution/wbc.h>
35 
36 #define DEMO_USE_MEMLIB=1 // This turns on the DEMO library's MEM heaps.
37 #include <demo.h>
38 
39 /*---------------------------------------------------------------------------*
40  * Local Definitions
41  *---------------------------------------------------------------------------*/
42 
43 #define SCREEN_WIDTH  320
44 #define SCREEN_HEIGHT 240
45 #define FONT_HEIGHT     8
46 
47 GXColor smoke_clr    = {  61, 61, 61, 255 } ;
48 GXColor red_clr      = { 237, 28, 36, 255 } ;
49 GXColor blue_clr     = {   0, 84,166, 255 } ;
50 GXColor yellow_clr   = { 255,242,  0, 255 } ;
51 GXColor peagreen_clr = { 141,198, 63, 255 } ;
52 
53 WPADBLStatus status;
54 
55 
56 u8  rxBuf[128] ATTRIBUTE_ALIGN(32);
57 u8  txBuf[128] ATTRIBUTE_ALIGN(32);
58 
59 
60 /*---------------------------------------------------------------------------*
61  * Function prototypes
62  *---------------------------------------------------------------------------*/
63 
64 
65 // MEM2 memory allocation routines. The application must provide these to
66 // WPAD, so it can setup the data transfer buffer. This buffer must reside
67 // in MEM2.
68 static void *myAlloc                 ( u32 size );
69 static u8    myFree                  ( void *ptr );
70 
71 
72 // Callbacks for CONNECT and EXTENSION events.
73 void         connectCallback         ( s32 chan, s32 reason );
74 void         extensionCallback       ( s32 chan, s32 result );
75 
76 // Internal functions
77 static void  initialize              ( void );
78 static void  renderStatus            ( void );
79 static void  init_draw_graphic       ( u16 fb_width, u16 fb_height );
80 static void  draw_line               ( f32 x1, f32 y1, f32 x2, f32 y2, GXColor clr, f32 width );
81 static void  draw_box                ( f32 x1, f32 y1, f32 x2, f32 y2, GXColor clr, f32 width );
82 
83 static double zero_point[WPAD_PRESS_UNITS];
84 static double sum;
85 static double ave;
86 static u32    counter;
87 static BOOL   get_weight_flag = FALSE;
88 static BOOL   set_zero_flag   = FALSE;
89 
90 static u8  workarea[WPAD_BLCINT_WORK_LEN] ATTRIBUTE_ALIGN(32);
91 
92 #define NSAMPLES_2SEC 120
93 
94 /*===========================================================================*
95  *                   F U N C T I O N    D E F I N I T I O N S
96  *===========================================================================*/
97 /*---------------------------------------------------------------------------*
98  * Name        : main()
99  * Description :
100  * Arguments   : None.
101  * Returns     : None.
102  *---------------------------------------------------------------------------*/
ctrlWbc(s32 chan,s32 result)103 static void ctrlWbc( s32 chan, s32 result )
104 {
105     OSReport("chan%d [%d]\n", chan, result);
106 }
107 
WaitMilliTime(s32 msec)108 static void WaitMilliTime(s32 msec)
109 {
110     OSTime t=OSGetTime();
111     while(OSTicksToMilliseconds(OSGetTime()-t) < msec)
112         ;
113 }
114 
115 
ZeroSetStart2(s32 chan,s32 result)116 static void ZeroSetStart2( s32 chan, s32 result )
117 {
118     #pragma unused(chan, result)
119 
120     // Wait about 200 ms so that Board's press values rarely become unstable
121     // after updating Balance Wii Board's temperature.
122     WaitMilliTime(200);
123 
124 
125     // Start Zero point correction.
126     set_zero_flag = TRUE;
127     counter = 0;
128     zero_point[0] = 0;
129     zero_point[1] = 0;
130     zero_point[2] = 0;
131     zero_point[3] = 0;
132 }
133 
134 
ZeroSetStart(s32 chan,s32 result)135 static void ZeroSetStart( s32 chan, s32 result )
136 {
137     #pragma unused(chan, result)
138 
139     // Check Board's temperature.
140     WPADRead(WPAD_CHAN3, &status);
141 
142 
143     if((status.temp == 127) || (status.temp == -128))
144     {
145         // Update Board's temperature again if you can not get correct Board's temperature.
146         WPADControlBLC(WPAD_CHAN3, WPAD_BLCMD_UPDATE_TEMP, ZeroSetStart2);
147     }
148     else
149     {
150         // Wait about 200 ms so that Board's press values rarely become unstable
151         // after updating Balance Wii Board's temperature.
152         WaitMilliTime(200);
153 
154         // Start Zero point correction.
155         set_zero_flag = TRUE;
156         counter = 0;
157         zero_point[0] = 0;
158         zero_point[1] = 0;
159         zero_point[2] = 0;
160         zero_point[3] = 0;
161     }
162 }
163 
main(void)164 int main( void )
165 {
166 
167     initialize();
168 
169     // For the Japanese version only, set the working buffer because it is required when the Wii Balance Board is initialized.
170     //
171     // After library initialization is complete, the working buffer will no longer be used and can be released.
172     //
173     //
174     // For markets outside Japan, no problems will occur if this function is not called.
175     //
176     // Additionally, no problems will occur if it is called.
177     WPADRegisterBLCWorkarea( workarea );
178 
179     WPADRegisterAllocator(myAlloc, myFree);
180 
181     WPADInit();
182 
183     WPADSetConnectCallback(WPAD_CHAN3, connectCallback);
184 
185     while (WPAD_STATE_SETUP != WPADGetStatus())
186     {
187         ;
188     }
189 
190     while(1)
191     {
192         DEMOPadRead();
193 
194         if (DEMOPadGetButtonDown(0) & PAD_BUTTON_A)
195         {
196             // Turn on Board's power.
197             WPADControlBLC(WPAD_CHAN3, WPAD_BLCMD_ON, ctrlWbc);
198         }
199         if (DEMOPadGetButtonDown(0) & PAD_BUTTON_B)
200         {
201             // Turn off Board's power.
202             WPADControlBLC(WPAD_CHAN3, WPAD_BLCMD_OFF, ctrlWbc);
203         }
204         if (DEMOPadGetButtonDown(0) & PAD_TRIGGER_Z)
205         {
206             // Update Board's temperature.
207             WPADControlBLC(WPAD_CHAN3, WPAD_BLCMD_UPDATE_TEMP, ctrlWbc);
208         }
209         if (DEMOPadGetButtonDown(0) & PAD_BUTTON_MENU)
210         {
211             if((set_zero_flag == FALSE) && (get_weight_flag == FALSE))
212             {
213                 // Update Board's temperature the eve of zero point correction.
214                 WPADControlBLC(WPAD_CHAN3, WPAD_BLCMD_UPDATE_TEMP, ZeroSetStart);
215             }
216         }
217         if (DEMOPadGetButtonDown(0) & PAD_BUTTON_LEFT)
218         {
219             if((set_zero_flag == FALSE) && (get_weight_flag == FALSE))
220             {
221                 // Get an average value for 2 seconds
222                 get_weight_flag = TRUE;
223                 counter = 0;
224                 sum     = 0;
225             }
226         }
227 
228 
229         // Caption
230         DEMOInitCaption( DM_FT_XLU, SCREEN_WIDTH, SCREEN_HEIGHT );
231         GXSetZMode( GX_ENABLE, GX_ALWAYS, GX_ENABLE );
232         GXSetBlendMode( GX_BM_BLEND, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR );
233 
234         DEMOBeforeRender();
235         renderStatus();
236         DEMODoneRender();
237     }
238 
239 } // End main()
240 
241 /*---------------------------------------------------------------------------*
242  * Name        : connectCallback()
243  *
244  * Description : This callback is invoked when a controller is connected or
245  *               disconnected.
246  *
247  * Arguments   : The channel (chan) for which the event has occurred.
248  *               The channel status (reason):
249  *                 WPAD_ERR_NONE means a controller has been connected.
250  *                 WPAD_ERR_NO_CONTROLLER means a controller disconnected.
251  *
252  * Returns     : None.
253  *---------------------------------------------------------------------------*/
connectCallback(s32 chan,s32 reason)254 void connectCallback(s32 chan, s32 reason)
255 {
256     u32 type;
257 
258     if (reason == WPAD_ERR_NONE)
259     {
260         // Disconnect 4P if 4P is not Wii Balance Board.
261         // 4P is reserved for Wii Balance Board.
262         WPADProbe(chan, &type);
263         if (chan == WPAD_CHAN3 && type != WPAD_DEV_BALANCE_CHECKER)
264         {
265             OSReport("Channel%d is reserved for the balance checker.\n", chan);
266             WPADDisconnect(chan);
267         }
268         else
269         {
270             // Read the calibration value for calculating a weight.
271             if(!WBCSetupCalibration())
272             {
273                 OSHalt("WBC FATAL ERROR!!\n");
274             }
275 
276             OSReport("Channel%d is connected.\n", chan);
277             WPADSetExtensionCallback(chan, extensionCallback);
278         }
279     }
280     else
281     {
282         OSReport("Channel%d is disconnected.\n", chan);
283     }
284 } // End connectCallback()
285 
286 /*---------------------------------------------------------------------------*
287  * Name        : extensionCallback()
288  *
289  * Description : This callback is invoked when an Extension has been attached.
290  *
291  * Arguments   : The channel (chan) for which the extension event occurred.
292  *               The device type (result):
293  *
294  *                 WPAD_DEV_UNKNOWN means that something has been attached, but
295  *                 it's being initialized, and we won't know what it is until
296  *                 initialization is complete.
297  *
298  *                 WPAD_DEV_CORE means that an extension has been removed and
299  *                 we're back to just the core device.
300  *
301  *                 WPAD_DEV_FREESTYLE means that the "NUNCHUK" extension has
302  *                 been attached and initialized.
303  *
304  *                 WPAD_DEV_CLASSIC means that the "CLASSIC" extension has been
305  *                 attached and initialized.
306  *
307  * Returns     : None.
308  *---------------------------------------------------------------------------*/
extensionCallback(s32 chan,s32 result)309 void extensionCallback(s32 chan, s32 result)
310 {
311     switch(result)
312     {
313         case WPAD_DEV_UNKNOWN:
314             OSReport("Initializing extension on channel%d...\n", chan);
315             break;
316 
317         case WPAD_DEV_CORE:
318             WPADControlDpd(chan, WPAD_DPD_EXP, NULL);
319             WPADSetDataFormat(chan, WPAD_FMT_CORE_ACC_DPD);
320 
321             OSReport("Extension removed on channel%d.\n", chan);
322             break;
323 
324         case WPAD_DEV_NOT_SUPPORTED:
325         case WPAD_DEV_FUTURE:
326             WPADControlDpd(chan, WPAD_DPD_EXP, NULL);
327             WPADSetDataFormat(chan, WPAD_FMT_CORE_ACC_DPD);
328 
329             OSReport("Extension is not useful on channel%d.\n", chan);
330             break;
331 
332         case WPAD_DEV_FREESTYLE:
333             WPADControlDpd(chan, WPAD_DPD_STD, NULL);
334             WPADSetDataFormat(chan, WPAD_FMT_FREESTYLE_ACC_DPD);
335 
336             OSReport("Freestyle initialized on channel%d.\n", chan);
337             break;
338 
339         case WPAD_DEV_CLASSIC:
340             WPADControlDpd(chan, WPAD_DPD_STD, NULL);
341             WPADSetDataFormat(chan, WPAD_FMT_CLASSIC_ACC_DPD);
342 
343             OSReport("Classicstyle initialized on channel%d.\n", chan);
344             break;
345 
346         case WPAD_DEV_BALANCE_CHECKER:
347             WPADControlDpd(chan, WPAD_DPD_OFF, NULL);
348             WPADSetDataFormat(chan, WPAD_FMT_BALANCE_CHECKER);
349             WPADControlBLC(chan, WPAD_BLCMD_ON, NULL);
350 
351             OSReport("Balance checker initialized on channel%d.\n", chan);
352             break;
353 
354         default:
355             // Here is WPAD_DEV_NOT_FOUND.
356             // If the controller is disconnected while the extension is initializing
357             // it reaches here. There is nothing to do.
358             break;
359 
360     } // End
361 
362 } // End extensionCallback()
363 
364 /*---------------------------------------------------------------------------*
365  * Name        : myAlloc()
366  * Description : Callback needed by WPAD to allocate memory from MEM2 heap.
367  * Arguments   : size of block, in bytes.
368  * Returns     : pointer to allocated block.
369  *---------------------------------------------------------------------------*/
myAlloc(u32 size)370 static void *myAlloc(u32 size)
371 {
372     void *ptr;
373 
374     ptr = MEMAllocFromAllocator(&DemoAllocator2, size);
375     ASSERTMSG(ptr, "Memory allocation failed\n");
376 
377     return(ptr);
378 
379 } // myAlloc()
380 
381 /*---------------------------------------------------------------------------*
382  * Name        : myFree()
383  * Description : Callback needed by WPAD to deallocate memory from MEM2 heap.
384  * Arguments   : None.
385  * Returns     : Always 1.
386  *---------------------------------------------------------------------------*/
myFree(void * ptr)387 static u8 myFree(void *ptr)
388 {
389 
390     MEMFreeToAllocator(&DemoAllocator2, ptr);
391 
392     // we should ensure that memory is deallocated properly, but oh well
393     return(1);
394 
395 } // myFree()
396 
397 
renderStatus(void)398 static void renderStatus(void)
399 {
400     u32 type;
401     s32 isExist = 0;
402 
403     if (WPADProbe(WPAD_CHAN3, &type) == WPAD_ERR_NO_CONTROLLER)
404     {
405         if (WPADIsRegisteredBLC())
406         {
407             DEMOPrintf( 50, 100, 0, "WBC is not connected.");
408         }
409         else
410         {
411             DEMOPrintf( 20, 100, 0, "WBC is not registered.");
412             DEMOPrintf( 20, 110, 0, "Please regist WBC with SYNC button.");
413         }
414     }
415     else
416     {
417         if (type == WPAD_DEV_BALANCE_CHECKER)
418         {
419             double weight[WPAD_PRESS_UNITS];
420             double tgc_weight;
421             double all;
422 
423 
424             WPADRead(WPAD_CHAN3, &status);
425 
426             DEMOPrintf( 95,  40, 0, "%5d", status.press[0]);
427             DEMOPrintf( 95, 110, 0, "%5d", status.press[1]);
428             DEMOPrintf( 10,  40, 0, "%5d", status.press[2]);
429             DEMOPrintf( 10, 110, 0, "%5d", status.press[3]);
430 
431             isExist = WBCRead(&status, weight, (u32)(sizeof(weight) / sizeof(weight[0])));
432             all = (double)(weight[0] + weight[1] + weight[2] + weight[3]);
433 
434 
435 
436             if((get_weight_flag || set_zero_flag) && counter < NSAMPLES_2SEC)
437             {
438                 counter++;
439                 sum += all;
440                 zero_point[0] += status.press[0];
441                 zero_point[1] += status.press[1];
442                 zero_point[2] += status.press[2];
443                 zero_point[3] += status.press[3];
444             }
445 
446 
447             if(counter == NSAMPLES_2SEC)
448             {
449                 ave  = sum / NSAMPLES_2SEC;
450                 zero_point[0] /= NSAMPLES_2SEC;
451                 zero_point[1] /= NSAMPLES_2SEC;
452                 zero_point[2] /= NSAMPLES_2SEC;
453                 zero_point[3] /= NSAMPLES_2SEC;
454                 get_weight_flag = FALSE;
455 
456                 if(set_zero_flag)
457                 {
458                     // Set the zero point into WBC library.
459                     if(0 == WBCSetZEROPoint( zero_point,(u32)(sizeof(zero_point) / sizeof(zero_point[0])) ))
460                     {
461                         // Success
462                         set_zero_flag = FALSE;
463                     }
464                     else
465                     {
466                         // Retry if failed.
467                         counter = 0;
468                         zero_point[0] = 0;
469                         zero_point[1] = 0;
470                         zero_point[2] = 0;
471                         zero_point[3] = 0;
472                     }
473                 }
474             }
475 
476             WBCGetTGCWeight(ave, &tgc_weight, &status);
477 
478             if(get_weight_flag || set_zero_flag)
479             {
480                 DEMOPrintf( 95,  55, 0, "wait...");
481                 DEMOPrintf( 95, 125, 0, "wait...");
482                 DEMOPrintf( 10,  55, 0, "wait...");
483                 DEMOPrintf( 10, 125, 0, "wait...");
484 
485                 if(get_weight_flag)
486                 {
487                     DEMOPrintf(175,  60, 0, "Wt     :WAIT");
488                     DEMOPrintf(175,  70, 0, "Wt(TGC):WAIT");
489                 }
490                 else
491                 {
492                     DEMOPrintf(175,  60, 0, "Wt     :%3.1f[kg]", ave);
493                     DEMOPrintf(175,  70, 0, "Wt(TGC):%3.1f[kg]", tgc_weight);
494                 }
495             }
496             else
497             {
498                 DEMOPrintf( 95,  55, 0, "%3.1f", weight[0]);
499                 DEMOPrintf( 95, 125, 0, "%3.1f", weight[1]);
500                 DEMOPrintf( 10,  55, 0, "%3.1f", weight[2]);
501                 DEMOPrintf( 10, 125, 0, "%3.1f", weight[3]);
502                 DEMOPrintf(175,  60, 0, "Wt     :%3.1f[kg]", ave);
503                 DEMOPrintf(175,  70, 0, "Wt(TGC):%3.1f[kg]", tgc_weight);
504                 DEMOPrintf(175,  80, 0, "Setup  :%s", WBCGetCalibrationStatus()==TRUE ? "OK":"NG");
505             }
506 
507             DEMOPrintf(175,  20, 0, "Temp %d", status.temp);
508             DEMOPrintf(175,  30, 0, "Batt %d/Level %d", status.battery, WBCGetBatteryLevel(status.battery));
509             DEMOPrintf(175,  40, 0, "IsEXIST = %s", isExist == 1 ? "EXIST" : "NONE");
510 
511             DEMOPrintf( 10, 160, 0, "A: Turn On  SENSOR");
512             DEMOPrintf( 10, 170, 0, "B: Turn Off SENSOR");
513             DEMOPrintf( 10, 180, 0, "MENU: Set ZERO point");
514             DEMOPrintf( 10, 190, 0, "LEFT: Get AVE Weight");
515             DEMOPrintf( 10, 220, 0, "Z: Update the current temperature");
516 
517             init_draw_graphic(SCREEN_WIDTH, SCREEN_HEIGHT);
518             draw_box(-143, -100, -68, -50, peagreen_clr, 2);
519             init_draw_graphic(SCREEN_WIDTH, SCREEN_HEIGHT);
520             draw_box(-143,  -30, -68,  20, yellow_clr, 2);
521             init_draw_graphic(SCREEN_WIDTH, SCREEN_HEIGHT);
522             draw_box(-63,  -100, 12, -50, blue_clr, 2);
523             init_draw_graphic(SCREEN_WIDTH, SCREEN_HEIGHT);
524             draw_box(-63,   -30, 12,  20, red_clr, 2);
525         }
526         else
527         {
528             DEMOPrintf(50, 100, 0, "No balance checker is attached.");
529         }
530     }
531 
532 } // End renderStatus()
533 
534 
initialize(void)535 static void initialize( void )
536 {
537     OSInit();
538 
539     DEMOInit( &GXNtsc480IntDf );
540 
541     GXSetCopyClear( smoke_clr, GX_MAX_Z24 );
542     GXCopyDisp( DEMOGetCurrentBuffer(), GX_TRUE );
543 
544     DEMOPadInit();
545 } // End
546 
547 
init_draw_graphic(u16 fb_width,u16 fb_height)548 static void init_draw_graphic( u16 fb_width, u16 fb_height )
549 {
550     Mtx44   proj_mtx ;
551     Mtx     view_mtx ;
552     f32     canvas_wd, canvas_ht ;
553 
554     // CANVAS
555     canvas_wd = fb_width * 0.91346f ;
556     canvas_ht = fb_height ;
557 
558     // MTX
559     MTXOrtho( proj_mtx, canvas_ht * -0.5f,canvas_ht * 0.5f, canvas_wd * -0.5f,canvas_wd * 0.5f, -10.0f,10.0f ) ;
560     GXSetProjection( proj_mtx, GX_ORTHOGRAPHIC ) ;
561 
562     MTXIdentity( view_mtx ) ;
563     GXLoadPosMtxImm( view_mtx, GX_PNMTX0 ) ;
564     GXSetCurrentMtx( GX_PNMTX0 ) ;
565 
566     // VERTEX
567     GXClearVtxDesc() ;
568     GXSetVtxDesc( GX_VA_POS, GX_DIRECT ) ;
569     GXSetVtxAttrFmt( GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_F32, 0 ) ;
570 
571     // CHANNEL
572     GXSetNumChans( 1 ) ;
573     GXSetChanCtrl( GX_COLOR0A0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ) ;
574     GXSetChanCtrl( GX_COLOR1A1, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ) ;
575 
576     // TEXTURE
577     GXSetNumTexGens( 0 ) ;
578 
579     // TEV
580     GXSetNumTevStages( 1 ) ;
581     GXSetTevOrder( GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL ) ;
582     GXSetTevColorIn( GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0 ) ;
583     GXSetTevColorOp( GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV ) ;
584     GXSetTevAlphaIn( GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0 ) ;
585     GXSetTevAlphaOp( GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV ) ;
586     GXSetAlphaCompare( GX_ALWAYS,0, GX_AOP_OR, GX_ALWAYS,0 ) ;
587 
588     // SCREEN
589     GXSetBlendMode( GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_NOOP ) ;
590     GXSetAlphaUpdate( GX_DISABLE ) ;
591 
592     GXSetZMode( GX_DISABLE, GX_ALWAYS, GX_DISABLE ) ;
593     GXSetCullMode( GX_CULL_BACK ) ;
594 }
595 
596 /*******************************************************************************
597     Draw object
598 *******************************************************************************/
draw_line(f32 x1,f32 y1,f32 x2,f32 y2,GXColor clr,f32 width)599 static void draw_line( f32 x1, f32 y1, f32 x2, f32 y2, GXColor clr, f32 width )
600 {
601     GXSetTevColor( GX_TEVREG0, clr ) ;
602     GXSetLineWidth( (u8)(s32)(width * 6.0f + 0.5f), GX_TO_ZERO ) ;
603 
604     GXBegin( GX_LINES, GX_VTXFMT0, 2 ) ;
605       GXPosition2f32( x1, y1 ) ;
606       GXPosition2f32( x2, y2 ) ;
607     GXEnd() ;
608 }
609 
draw_box(f32 x1,f32 y1,f32 x2,f32 y2,GXColor clr,f32 width)610 static void draw_box( f32 x1, f32 y1, f32 x2, f32 y2, GXColor clr, f32 width )
611 {
612     draw_line(x1, y1, x2, y1, clr, width);
613     draw_line(x2, y1, x2, y2, clr, width);
614     draw_line(x2, y2, x1, y2, clr, width);
615     draw_line(x1, y2, x1, y1, clr, width);
616 }
617 
618