1 /*---------------------------------------------------------------------------*
2 Project: WPAD demo program
3 File: pointing.c
4 Programmer: HIRATSU Daisuke
5
6 Copyright (C) 2005-2006 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 $Log: pointing.c,v $
15 Revision 1.8 06/16/2006 14:10:56 ekwon
16 Ensured that WPADProbe() is used to check channel status and to update device type.
17
18 Revision 1.7 06/13/2006 04:55:58 tojo
19 (none)
20
21 Revision 1.6 06/13/2006 01:57:12 ekwon
22 Pointing demo.
23
24 Revision 1.1 06/01/2006 00:40:11 hiratsu
25 Moved from $(SDK)/build/demos/wpaddemo
26
27 Revision 1.4 2006/03/13 02:10:46 yasuh-to
28 Modified copyright.
29
30 *---------------------------------------------------------------------------*/
31
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stddef.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <ctype.h>
38
39 #include <revolution.h>
40 #include <revolution/wpad.h>
41
42 #define DEMO_USE_MEMLIB=1 // This turns on the DEMO library's MEM heaps.
43 #include <demo.h>
44
45
46
47 #define SCREEN_WIDTH 320
48 #define SCREEN_HEIGHT 240
49
50
51
52 // MEM2 memory allocation routines. The application must provide these to
53 // WPAD, so it can setup the data transfer buffer. This buffer must reside
54 // in MEM2.
55 static void *myAlloc (u32 size);
56 static u8 myFree (void *ptr);
57
58 static void initialize (void);
59 static void renderLuminousSources (const WPADStatus *stat);
60 static void renderStatus (const WPADStatus *stat);
61 static void renderAiming (const WPADStatus *stat);
62 static void getMidpoint (const WPADStatus *stat, s16 *x, s16 *y );
63
64
65
66 /*===========================================================================*
67 * F U N C T I O N D E F I N I T I O N S
68 *===========================================================================*/
69
70
71 /*---------------------------------------------------------------------------*
72 * Name : main()
73 * Description :
74 * Arguments : None.
75 * Returns : None.
76 *---------------------------------------------------------------------------*/
77
main(void)78 int main( void )
79 {
80
81 WPADStatus wpad;
82
83 s32 wpad_state;
84
85 s32 status;
86 u32 type;
87
88
89 initialize();
90
91 // we should clear the WPADStatus block returned by
92 // WPADRead(), because if no channel is connected, nothing
93 // is copied. So we would be staring at garbage data.
94 memset( (void *)(&wpad), 0, sizeof(WPADStatus));
95
96 // - We must now register memory allocation/free functions
97 // for MEM2.
98 // - WPAD requires some memory in MEM2 for data transfers
99 // between the controller and WPAD driver stack.
100 // - Memory allocation only occurs once, at the initialization.
101 // - Memory usage is on the order of 1KB.
102 // - NOTE: We are using the MEM library allocators defined by
103 // the DEMO library.
104 //
105 WPADRegisterAllocator(myAlloc, myFree);
106
107
108 // Initialize WPAD!
109 WPADInit();
110
111 // The WPAD initialization process is asynchronous.
112 // So we should wait until it's completed.
113 do
114 {
115 wpad_state = WPADGetStatus();
116
117 } while (WPAD_STATE_SETUP != wpad_state);
118
119
120
121 // Main loop
122 while( 1 )
123 {
124
125 status = WPADProbe(WPAD_CHAN0, &type);
126
127 WPADRead( WPAD_CHAN0, &wpad );
128
129 if (WPAD_ERR_NONE == status)
130 {
131
132 // A controller is connected. Is it the correct type?
133 if ((WPAD_DEV_CORE == type) || (WPAD_DEV_FREESTYLE == type))
134 {
135 // yes, it's the right kind of controller.
136 // now check if DPD/ACC are enabled...
137 if (FALSE == WPADIsDpdEnabled(WPAD_CHAN0))
138 {
139 // if not, then set the format and turn on DPD and accelerometer
140 WPADControlDpd(WPAD_CHAN0, WPAD_DPD_EXP, NULL);
141 WPADSetDataFormat(WPAD_CHAN0, WPAD_FMT_CORE_ACC_DPD);
142
143 } // if DPD enabled...
144
145 } // if correct device type
146
147 } // if controller is connected ok
148
149
150 DEMOBeforeRender();
151 renderLuminousSources( &wpad );
152 renderStatus( &wpad );
153 renderAiming( &wpad );
154 DEMODoneRender();
155
156 } // while(1)
157
158
159 return 0;
160
161 } // end
162
163
164 /*---------------------------------------------------------------------------*
165 * Name : myAlloc()
166 * Description : Callback needed by WPAD to allocate mem from MEM2 heap
167 * Arguments : size of block, in bytes.
168 * Returns : pointer to allocated block.
169 *---------------------------------------------------------------------------*/
myAlloc(u32 size)170 static void *myAlloc(u32 size)
171 {
172 void *ptr;
173
174 ptr = MEMAllocFromAllocator(&DemoAllocator2, size);
175 ASSERTMSG(ptr, "Memory allocation failed\n");
176
177 return(ptr);
178
179 } // myAlloc()
180
181 /*---------------------------------------------------------------------------*
182 * Name : myFree()
183 * Description : Callback needed by WPAD to free mem from MEM2 heap
184 * Arguments : None.
185 * Returns : Always 1.
186 *---------------------------------------------------------------------------*/
myFree(void * ptr)187 static u8 myFree(void *ptr)
188 {
189
190 MEMFreeToAllocator(&DemoAllocator2, ptr);
191
192 // we should ensure that memory is free'd properly, but oh well
193 return(1);
194
195 } // myFree()
196
197 /*---------------------------------------------------------------------------*
198 * Name : initialize()
199 * Description :
200 * Arguments : None.
201 * Returns : None.
202 *---------------------------------------------------------------------------*/
initialize(void)203 static void initialize( void )
204 {
205 const GXColor DARKBLUE = { 0, 0, 40, 255 };
206
207
208 OSInit();
209
210 DEMOInit( &GXNtsc480IntDf );
211 GXSetCopyClear( DARKBLUE, GX_MAX_Z24 );
212 GXCopyDisp( DEMOGetCurrentBuffer(), GX_TRUE );
213 DEMOInitCaption( DM_FT_XLU, SCREEN_WIDTH, SCREEN_HEIGHT );
214 GXSetZMode( GX_ENABLE, GX_ALWAYS, GX_ENABLE ); // Set pixel processing mode
215 GXSetBlendMode( GX_BM_BLEND, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR ); // Translucent mode
216
217 } // end
218
219 /*---------------------------------------------------------------------------*
220 * Name : renderLuminousSources()
221 * Description :
222 * Arguments : None.
223 * Returns : None.
224 *---------------------------------------------------------------------------*/
renderLuminousSources(const WPADStatus * stat)225 static void renderLuminousSources(const WPADStatus *stat)
226 {
227 int i;
228
229 for( i = 0; i < 2; ++i )
230 {
231 s16 x = (s16)( stat->obj[i].x*SCREEN_WIDTH/WPAD_DPD_IMG_RESO_WX );
232 s16 y = (s16)( stat->obj[i].y*SCREEN_HEIGHT/WPAD_DPD_IMG_RESO_WY );
233 DEMOPrintf( x, y, 0, "O" );
234 }
235
236 } // end
237
238 /*---------------------------------------------------------------------------*
239 * Name : renderStatus()
240 * Description :
241 * Arguments : None.
242 * Returns : None.
243 *---------------------------------------------------------------------------*/
renderStatus(const WPADStatus * stat)244 static void renderStatus(const WPADStatus *stat)
245 {
246 const int FONT_HEIGHT = 8;
247 s16 x = FONT_HEIGHT;
248 s16 y = FONT_HEIGHT;
249 int i;
250
251 y+=FONT_HEIGHT;
252 DEMOPrintf( x, y+=FONT_HEIGHT, 0, "DPD-ID X Y SIZE");
253
254 for( i=0; i<WPAD_DPD_MAX_OBJECTS; ++i )
255 {
256 const DPDObject *p = &( stat->obj[i] );
257
258
259 DEMOPrintf( x, y+=FONT_HEIGHT, 0, "%1d %4d %4d %3d", p->traceId, p->x, p->y, p->size );
260
261 }
262
263 y+=FONT_HEIGHT;
264 DEMOPrintf( x, y+=FONT_HEIGHT, 0, "Controller Type: %d", stat->dev );
265 DEMOPrintf( x, y+=FONT_HEIGHT, 0, "ERROR Info : %d", stat->err );
266
267 if (WPAD_ERR_NO_CONTROLLER == stat->err)
268 {
269 y+=FONT_HEIGHT;
270 y+=FONT_HEIGHT;
271 DEMOPrintf(x, y+=FONT_HEIGHT, 0, ">> No controller is connected!");
272 DEMOPrintf(x, y+=FONT_HEIGHT, 0, ">> Please press a button on a paired");
273 DEMOPrintf(x, y+=FONT_HEIGHT, 0, ">> controller to connect.");
274 }
275
276
277 } // end
278
279 /*---------------------------------------------------------------------------*
280 * Name : renderAiming()
281 * Description :
282 * Arguments : Pointer to latest WPADStatus block.
283 * Returns : None.
284 *---------------------------------------------------------------------------*/
285
renderAiming(const WPADStatus * stat)286 static void renderAiming( const WPADStatus *stat )
287 {
288 s16 x;
289 s16 y;
290
291
292 getMidpoint( stat, &x, &y );
293
294 x=(s16)((WPAD_DPD_IMG_RESO_WX - x)*SCREEN_WIDTH /WPAD_DPD_IMG_RESO_WX);
295 y=(s16)((WPAD_DPD_IMG_RESO_WY - y)*SCREEN_HEIGHT/WPAD_DPD_IMG_RESO_WY);
296
297 DEMOPrintf( x, y, 0, "+" );
298
299
300 } // end
301
302 /*---------------------------------------------------------------------------*
303 * Name : getMidpoint()
304 * Description :
305 * Arguments : Pointer to latest WPADStatus block.
306 * Pointer to X value.
307 * Pointer to Y value.
308 * Returns : None.
309 *---------------------------------------------------------------------------*/
310
getMidpoint(const WPADStatus * stat,s16 * x,s16 * y)311 static void getMidpoint( const WPADStatus *stat, s16 *x, s16 *y )
312 {
313 static int s_prevX[2];
314 static int s_prevY[2];
315 static int s_width;
316
317 // Compute pointing position from obj data
318 // We assume [0] means left, [1] means right.
319 int cx[2];
320 int cy[2];
321 int i;
322
323
324 if((stat->obj[0].size > 0) && (stat->obj[1].size > 0))
325 {
326 for(i=0; i<2; ++i)
327 {
328 cx[i]=stat->obj[i].x;
329 cy[i]=stat->obj[i].y;
330 }
331
332 // swap.
333 if(cx[0] > cx[1])
334 {
335 int tmp=cx[0];
336 cx[0]=cx[1];
337 cx[1]=tmp;
338 tmp=cy[0];
339 cy[0]=cy[1];
340 cy[1]=tmp;
341 }
342
343 for(i=0; i<2; ++i)
344 {
345 s_prevX[i]=cx[i];
346 s_prevY[i]=cy[i];
347 }
348 s_width=cx[1]-cx[0];
349 }
350 else if(stat->obj[0].size > 1)
351 {
352 int x0=stat->obj[0].x;
353 int y0=stat->obj[0].y;
354 f32 diff0=(s_prevX[0]-x0)*(s_prevX[0]-x0)+(s_prevY[0]-y0)*(s_prevY[0]-y0);
355 f32 diff1=(s_prevX[1]-x0)*(s_prevX[1]-x0)+(s_prevY[1]-y0)*(s_prevY[1]-y0);
356 if(diff0 < diff1)
357 {
358 // current [0] is previous [0]. We create [1] data by computation.
359 cx[0]=x0;
360 cy[0]=y0;
361 cx[1]=cx[0]+s_width;
362 cy[1]=s_prevY[1];
363 for(i=0; i<2; ++i){
364 s_prevX[i]=cx[i];
365 s_prevY[i]=cy[i];
366 }
367 }
368 else
369 {
370 // current [0] is previous [1].
371 cx[1]=x0;
372 cy[1]=y0;
373 cx[0]=cx[1]-s_width;
374 cy[0]=s_prevY[1];
375 for(i=0; i<2; ++i){
376 s_prevX[i]=cx[i];
377 s_prevY[i]=cy[i];
378 }
379 }
380 }
381 else
382 {
383 for(i=0; i<2; ++i)
384 {
385 cx[i]=s_prevX[i];
386 cy[i]=s_prevY[i];
387 }
388 }
389
390 *x = (s16)((cx[0]+cx[1])/2);
391 *y = (s16)((cy[0]+cy[1])/2);
392
393 } // end
394