1 /*---------------------------------------------------------------------------*
2   Project:     KPAD sample program
3   File:        main.c
4   Programmer:  Keizo Ohta
5                HIRATSU Daisuke
6 
7   Copyright 2005-2006 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    <revolution/wpad.h>
20 #include	<revolution/kpad.h>
21 #include	<revolution/mem.h>
22 
23 #include	"main.h"
24 #include	"kfont.h"
25 #include	"sample.h"
26 
27 static void dpd_callback( s32 chan, s32 reason ) ;
28 static void sampling_callback( s32 chan ) ;
29 
30 /***************************************************************
31 	GXFIFO
32  ***************************************************************/
33 #define GX_FIFO_SIZE	( 1 * 1024*1024 )	// Large enough (The smaller the FIFO, the larger the chance of waiting for space to open when a command is issued.)
34 
35 static void      *gx_fifo_p ;       // Pointer to buffer
36 static GXFifoObj *gx_fifo_obj ;     // Management structure
37 
38 
39 /***************************************************************
40 	Frame buffer
41  ***************************************************************/
42 GXRenderModeObj		*rmode_p ;		// Pointer to the rendering mode
43 static u8		vfilter[ 7 ] = { 0,8, 16,16,16, 8,0 } ;
44 
45 static void		*xfb_p[ 2 ] ;		// Pointer to double buffer
46 static s32		draw_xfb_idx ;		// XFB being drawn by GX
47 static s32		disp_xfb_idx ;		// XFB being displayed by VI
48 
49 
50 /***************************************************************
51     Working buffer
52  ***************************************************************/
53 KPADUnifiedWpadStatus   uniRingBufs[ WPAD_MAX_CONTROLLERS * KPAD_BUF_SIZE ] ;
54 
55 
56 /***************************************************************
57 	Controllers
58  ***************************************************************/
59 KPADStatus	kpads[ WPAD_MAX_CONTROLLERS ][ KPAD_BUF_SIZE * 2 ] ;
60 s32		kpad_reads ;
61 s32     kpad_err ;
62 
63 PADStatus pads[ PAD_MAX_CONTROLLERS ] ;
64 PADStatus padsTmp[ PAD_MAX_CONTROLLERS ] ;
65 PADStatus padsTrig[ PAD_MAX_CONTROLLERS ] ;
66 
67 
68 /*******************************************************************************
69 	Memory initialization
70  *******************************************************************************/
init_memory(void)71 static void init_memory( void )
72 {
73     void         *arenaLo, *arenaHi ;
74     OSHeapHandle  heap ;
75 
76 
77     //----- Check available memory
78     arenaLo = OSGetArenaLo() ;
79     arenaHi = OSGetArenaHi() ;
80 
81     //----- Declare the creation of one heap that takes up all available memory
82     arenaLo = OSInitAlloc( arenaLo, arenaHi, 1 ) ;
83     OSSetArenaLo( arenaLo ) ;	// Reset because the available memory changes
84 
85     //----- Create a heap which takes up all available memory and set it as the current heap
86     heap = OSCreateHeap( arenaLo, arenaHi ) ;
87     (void)OSSetCurrentHeap( heap ) ;
88 
89     //----- Make it clear ahead of time that available memory has been utilized
90     arenaLo = arenaHi ;
91     OSSetArenaLo( arenaLo ) ;
92 }
93 
94 
95 /*******************************************************************************
96 	Initialize memory (MEM2)
97  *******************************************************************************/
98 static MEMAllocator  s_mem2Allocator ;
99 static MEMHeapHandle s_handle ;
100 
init_memory2(void)101 static void init_memory2( void )
102 {
103     void *lo = OSGetMEM2ArenaLo() ;
104     void *hi = OSGetMEM2ArenaHi() ;
105     s_handle = MEMCreateFrmHeap( lo, (u32)hi - (u32)lo ) ;
106     if ( s_handle == MEM_HEAP_INVALID_HANDLE )
107     {
108         OSHalt("MEM2 heap allocation error.\n") ;
109     }
110     else
111     {
112         OSSetMEM2ArenaLo(hi) ;
113         MEMInitAllocatorForFrmHeap( &s_mem2Allocator, s_handle, 32 ) ;   // Buffer requires 32byte alignment.
114     }
115 }
116 
alloc32(u32 size)117 static void* alloc32( u32 size )
118 {
119     return MEMAllocFromAllocator( &s_mem2Allocator, size ) ;
120 
121 }
122 
free32(void * addr)123 static u8 free32( void *addr )
124 {
125     MEMFreeToAllocator( &s_mem2Allocator, addr ) ;
126     return 1 ;
127 }
128 
129 
130 /*******************************************************************************
131 	Initialize relationship with display device
132  *******************************************************************************/
init_display(void)133 static void init_display( void )
134 {
135     u32			xfb_size ;
136 
137 
138     //----- Select drawing mode
139     rmode_p = &GXNtsc480IntDf ;
140 
141     //----- Allocate frame buffer
142     xfb_size = VIPadFrameBufferWidth(rmode_p->fbWidth) * rmode_p->xfbHeight * (u32)VI_DISPLAY_PIX_SZ ;
143     xfb_p[ 0 ] = OSAlloc( xfb_size ) ;
144     xfb_p[ 1 ] = OSAlloc( xfb_size ) ;
145 
146     //----- Select a drawing buffer and display buffer
147     draw_xfb_idx = 0 ;
148     disp_xfb_idx = 1 ;
149 
150     //----- Initialize VI
151     VIConfigure( rmode_p ) ;
152     VISetNextFrameBuffer( xfb_p[ disp_xfb_idx ] ) ;
153     VIFlush() ;
154 
155     VIWaitForRetrace() ;	// In order to enable Configure,
156     VIWaitForRetrace() ;	//  you need to wait two times.
157 }
158 
159 
160 /*******************************************************************************
161 	Initialize GX relationship
162  *******************************************************************************/
init_gx(void)163 static void init_gx( void )
164 {
165     GXColor		clear_clr = { 0,0,0, 0 } ;
166 
167 
168     //----- Create GXFIFO
169     gx_fifo_p   = OSAlloc( GX_FIFO_SIZE ) ;
170     gx_fifo_obj = GXInit( gx_fifo_p, GX_FIFO_SIZE ) ;
171 
172     //----- Select pixel format
173     GXSetPixelFmt( GX_PF_RGB8_Z24, GX_ZC_LINEAR ) ;
174     GXSetDither( GX_DISABLE ) ;
175 
176     //----- Initialize settings for copying from EFB to XFB
177     GXSetDispCopySrc( 0, 0, rmode_p->fbWidth, rmode_p->efbHeight ) ;
178     GXSetDispCopyDst( rmode_p->fbWidth, rmode_p->xfbHeight ) ;
179     (void)GXSetDispCopyYScale( (f32)(rmode_p->xfbHeight) / (f32)(rmode_p->efbHeight) ) ;
180     GXSetDispCopyGamma( GX_GM_1_0 ) ;
181 
182     GXSetCopyFilter( rmode_p->aa, rmode_p->sample_pattern, GX_ENABLE, vfilter ) ;
183     GXSetCopyClear( clear_clr, 0x00FFFFFF ) ;
184 
185     //----- Initialize EFB drawing area
186     GXSetViewport( 0.0f, 0.0f, rmode_p->fbWidth, rmode_p->efbHeight, 0.0f, 1.0f ) ;
187     GXSetScissor( 0, 0, (u32)rmode_p->fbWidth, (u32)rmode_p->efbHeight ) ;
188 
189     //----- Clear EFB and XFB
190     GXCopyDisp( xfb_p[ 0 ], GX_ENABLE ) ;	// The EFB is cleared and garbage is placed in XFB[0]
191     GXCopyDisp( xfb_p[ 0 ], GX_DISABLE ) ;	// The cleared EFB is placed in XFB[0]
192     GXCopyDisp( xfb_p[ 1 ], GX_DISABLE ) ;	// The cleared EFB is placed in XFB[1]
193     GXDrawDone() ;
194 }
195 
196 /***************************************************************
197 	KPAD DPD callback
198  ***************************************************************/
dpd_callback(s32 chan,s32 reason)199 static void dpd_callback( s32 chan, s32 reason )
200 {
201 #pragma unused(chan)
202     u32 i ;
203     u32 smallest = MY_DPD_START_COUNT_DEFAULT ;
204     u32 smallestIdx = 0 ;
205 
206     for (i = 0; i < MY_DPD_START_COUNTS_MAX; i++) {
207         if ( MyDpdCallbackStatusBuf[ i ].count == 0 ) {
208             break ;
209         } else {
210             if (smallest > MyDpdCallbackStatusBuf[i].count) {
211                 smallest = MyDpdCallbackStatusBuf[i].count ;
212                 smallestIdx = i ;
213             }
214         }
215     }
216     if ( i == MY_DPD_START_COUNTS_MAX ) {
217         i = smallestIdx ;
218     }
219 
220     MyDpdCallbackStatusBuf[ i ].count = MY_DPD_START_COUNT_DEFAULT ;
221     MyDpdCallbackStatusBuf[ i ].reason = reason ;
222     MyDpdCallbackLatestIdx = (s32)i ;
223 }
224 
sampling_callback(s32 chan)225 static void sampling_callback( s32 chan )
226 {
227 #pragma unused(chan)
228     MySamplingCount++ ;
229 }
230 
231 /*******************************************************************************
232 	Main
233  *******************************************************************************/
main(void)234 void main( void )
235 {
236     int rev  = 0 ;
237     int init = 0 ;
238     u8  btn  = KPAD_BUTTON_PROC_MODE_LOOSE ;
239 
240     /***********************************************************************
241 		Initialization processing
242      ***********************************************************************/
243     //----- Highest-priority hardware initialization
244     VIInit() ;
245 
246     //----- Other priority initializations
247     init_memory() ;		// Enable allocation and release of memory
248     init_memory2() ;
249     init_display() ;	// Display device-related
250     init_gx() ;		// GX-related
251     WPADRegisterAllocator( alloc32, free32 ) ;
252     KPADInit() ; // Controllers
253     KPADSetControlDpdCallback( 0, dpd_callback ) ;
254     KPADSetSamplingCallback( 0, sampling_callback ) ;
255 
256     //----- Initialize application
257     init_kfont_texture() ;
258     init_sample() ;
259 
260     //----- Screen display ON
261     VISetBlack( FALSE ) ;
262     VIFlush() ;
263 
264     PADInit();
265 
266     /***********************************************************************
267 		Main loop
268      ***********************************************************************/
269     while ( 1 ) {
270 
271         padsTrig[ 0 ] = pads[ 0 ] ;
272         PADRead( padsTmp ) ;
273         if ( padsTmp[ 0 ].err == PAD_ERR_NONE ) {
274             pads[ 0 ] = padsTmp[ 0 ] ;
275         }
276         padsTrig[ 0 ].button = (u16)( (padsTrig[ 0 ].button ^ pads[ 0 ].button) & pads[ 0 ].button ) ;
277 
278         /***************************************************************
279 			First, perform calculations by the CPU
280 			Find coordinates based on controller input, and prepare the data necessary to issue a GX command
281 
282          ***************************************************************/
283         //----- Load controller
284         if ( padsTrig[ 0 ].button & PAD_BUTTON_A ) {
285             OSReport("KPADReset() from main()\n") ;
286             KPADReset() ;
287         }
288         if ( pads[ 0 ].button & PAD_BUTTON_B ) {
289             kpad_reads = 0 ;
290         } else {
291             kpad_reads = KPADReadEx( 0, &kpads[ 0 ][ 0 ], (u32)( KPAD_BUF_SIZE * ( init + 1 ) ), &kpad_err ) ;
292             if ( kpad_reads == 0 && kpad_err == KPAD_READ_ERR_NO_DATA ) {
293                 // Only the last piece of data is preserved
294                 kpad_reads = 1 ;
295             }
296         }
297         if ( padsTrig[ 0 ].button & PAD_BUTTON_X ) {
298             rev = ( rev ) ? 0 : 1 ;
299 
300             KPADSetReviseMode( 0, rev ) ;
301         }
302         if ( padsTrig[ 0 ].button & PAD_BUTTON_Y ) {
303             if ( kpad_err == KPAD_READ_ERR_INIT ) {
304                 init = ( init ) ? 0 : 1 ;
305                 if ( init ) {
306                     KPADInitEx( uniRingBufs, sizeof(uniRingBufs)/sizeof(KPADUnifiedWpadStatus) ) ;
307                 } else {
308                     KPADInit() ;
309                 }
310                 KPADSetControlDpdCallback( 0, dpd_callback ) ;
311                 KPADSetSamplingCallback( 0, sampling_callback ) ;
312             } else {
313                 KPADShutdown() ;
314             }
315         }
316         if ( padsTrig[ 0 ].button & PAD_TRIGGER_Z ) {
317             btn = (u8)( ( btn == KPAD_BUTTON_PROC_MODE_LOOSE ) ? KPAD_BUTTON_PROC_MODE_TIGHT : KPAD_BUTTON_PROC_MODE_LOOSE ) ;
318 
319             KPADSetButtonProcMode( 0, btn ) ;
320         }
321 
322         //----- Various calculations
323         work_sample() ;
324 
325         /***************************************************************
326 			Issue GX command and go on drawing to EFB
327          ***************************************************************/
328         //----- Cast spell to start issuing the command
329         GXInvalidateVtxCache() ;
330         GXInvalidateTexAll() ;
331 
332         //----- Issue various commands
333         draw_sample() ;
334 
335         //----- Finally, copy from EFB to XFB
336         GXCopyDisp( xfb_p[ draw_xfb_idx ], GX_ENABLE ) ;
337         GXDrawDone() ;
338 
339 
340         /***************************************************************
341 			The XFB copied here can be selected for display on the TV
342          ***************************************************************/
343         disp_xfb_idx = draw_xfb_idx ;
344         VISetNextFrameBuffer( xfb_p[ disp_xfb_idx ] ) ;
345         VIFlush() ;
346 
347         //----- Wait for the display to actually switch
348         VIWaitForRetrace() ;
349 
350         //----- Switch to the no longer displayed XFB ahead of time for the next drawing
351         draw_xfb_idx ^= 1 ;
352     }
353 }
354 
355