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