1 /*---------------------------------------------------------------------------*
2 Project: KPAD Sample Program
3 File: main.c
4 Programmer: Keizo Ohta
5 HIRATSU Daisuke
6 Haruki Tojo
7
8 Copyright 2005-2008 Nintendo. All rights reserved.
9
10 These coded instructions, statements, and computer programs contain
11 proprietary information of Nintendo of America Inc. and/or Nintendo
12 Company Ltd., and are protected by Federal copyright law. They may
13 not be disclosed to third parties or copied or duplicated in any form,
14 in whole or in part, without the prior written consent of Nintendo.
15 *---------------------------------------------------------------------------*/
16
17 #include <revolution.h>
18 #include <math.h>
19
20 #include <revolution/wpad.h>
21 #include <revolution/kpad.h>
22 #include <revolution/mem.h>
23
24 #include "main.h"
25 #include "kfont.h"
26 #include "sample.h"
27
28 /***************************************************************
29 GXFIFO
30 ***************************************************************/
31 #define GX_FIFO_SIZE ( 1 * 1024*1024 ) // Large enough (the smaller the FIFO, the greater the chance of having to wait for space to open when a command is issued)
32
33 static void *gx_fifo_p ; // Pointer to buffer
34 static GXFifoObj *gx_fifo_obj ; // Management structure
35
36
37 /***************************************************************
38 Frame Buffer
39 ***************************************************************/
40 GXRenderModeObj *rmode_p ; // Pointer to the rendering mode
41 static u8 vfilter[ 7 ] = { 0,8, 16,16,16, 8,0 } ;
42
43 static void *xfb_p[ 2 ] ; // Pointer to double buffer
44 static s32 draw_xfb_idx ; // XFB being rendered by GX
45 static s32 disp_xfb_idx ; // XFB being displayed by VI
46
47
48 /***************************************************************
49 Working buffer
50 ***************************************************************/
51 KPADUnifiedWpadStatus uniRingBufs[ WPAD_MAX_CONTROLLERS * KPAD_BUF_SIZE ] ;
52
53
54 /***************************************************************
55 Controllers
56 ***************************************************************/
57 KPADStatus kpads[ WPAD_MAX_CONTROLLERS ][ KPAD_BUF_SIZE * 2 ] ;
58 s32 kpad_reads ;
59 s32 kpad_err ;
60
61 PADStatus pads[ PAD_MAX_CONTROLLERS ] ;
62 PADStatus padsTmp[ PAD_MAX_CONTROLLERS ] ;
63 PADStatus padsTrig[ PAD_MAX_CONTROLLERS ] ;
64
65
66 /*******************************************************************************
67 Memory initialization
68 *******************************************************************************/
init_memory(void)69 static void init_memory( void )
70 {
71 void *arenaLo, *arenaHi ;
72 OSHeapHandle heap ;
73
74
75 //----- Check available memory
76 arenaLo = OSGetArenaLo() ;
77 arenaHi = OSGetArenaHi() ;
78
79 //----- Declare the creation of a single heap that takes up all available memory
80 arenaLo = OSInitAlloc( arenaLo, arenaHi, 1 ) ;
81 OSSetArenaLo( arenaLo ) ; // Reset because the available memory changes
82
83 //----- Create a heap that takes up all available memory and set it as the current heap
84 heap = OSCreateHeap( arenaLo, arenaHi ) ;
85 (void)OSSetCurrentHeap( heap ) ;
86
87 //----- Make it clear ahead of time that available memory has been all consumed
88 arenaLo = arenaHi ;
89 OSSetArenaLo( arenaLo ) ;
90 }
91
92
93 /*******************************************************************************
94 Initialize memory (MEM2)
95 *******************************************************************************/
96 static MEMAllocator s_mem2Allocator ;
97 static MEMHeapHandle s_handle ;
98
init_memory2(void)99 static void init_memory2( void )
100 {
101 void *lo = OSGetMEM2ArenaLo() ;
102 void *hi = OSGetMEM2ArenaHi() ;
103 s_handle = MEMCreateFrmHeap( lo, (u32)hi - (u32)lo ) ;
104 if ( s_handle == MEM_HEAP_INVALID_HANDLE )
105 {
106 OSHalt("MEM2 heap allocation error.\n") ;
107 }
108 else
109 {
110 OSSetMEM2ArenaLo(hi) ;
111 MEMInitAllocatorForFrmHeap( &s_mem2Allocator, s_handle, 32 ) ; // Buffer requires 32-byte alignment.
112 }
113 }
114
alloc32(u32 size)115 void* alloc32( u32 size )
116 {
117 return MEMAllocFromAllocator( &s_mem2Allocator, size ) ;
118
119 }
120
free32(void * addr)121 u8 free32( void *addr )
122 {
123 MEMFreeToAllocator( &s_mem2Allocator, addr ) ;
124 return 1 ;
125 }
126
127
128 /*******************************************************************************
129 Display device-related initialization
130 *******************************************************************************/
init_display(void)131 static void init_display( void )
132 {
133 u32 xfb_size ;
134
135
136 //----- Select rendering mode
137 rmode_p = &GXNtsc480IntDf ;
138
139 //----- Allocate frame buffer
140 xfb_size = VIPadFrameBufferWidth(rmode_p->fbWidth) * rmode_p->xfbHeight * (u32)VI_DISPLAY_PIX_SZ ;
141 xfb_p[ 0 ] = OSAlloc( xfb_size ) ;
142 xfb_p[ 1 ] = OSAlloc( xfb_size ) ;
143
144 //----- Decide a rendering buffer and display buffer
145 draw_xfb_idx = 0 ;
146 disp_xfb_idx = 1 ;
147
148 //----- Initialize VI
149 VIConfigure( rmode_p ) ;
150 VISetNextFrameBuffer( xfb_p[ disp_xfb_idx ] ) ;
151 VIFlush() ;
152
153 VIWaitForRetrace() ; // In order to enable Configure, you need to wait two cycles
154 VIWaitForRetrace() ; //
155 }
156
157
158 /*******************************************************************************
159 GX-related initialization
160 *******************************************************************************/
init_gx(void)161 static void init_gx( void )
162 {
163 GXColor clear_clr = { 0,0,0, 0 } ;
164
165
166 //----- Create GXFIFO
167 gx_fifo_p = OSAlloc( GX_FIFO_SIZE ) ;
168 gx_fifo_obj = GXInit( gx_fifo_p, GX_FIFO_SIZE ) ;
169
170 //----- Determine pixel format
171 GXSetPixelFmt( GX_PF_RGB8_Z24, GX_ZC_LINEAR ) ;
172 GXSetDither( GX_DISABLE ) ;
173
174 //----- Initialize settings for copying from EFB to XFB
175 GXSetDispCopySrc( 0, 0, rmode_p->fbWidth, rmode_p->efbHeight ) ;
176 GXSetDispCopyDst( rmode_p->fbWidth, rmode_p->xfbHeight ) ;
177 (void)GXSetDispCopyYScale( (f32)(rmode_p->xfbHeight) / (f32)(rmode_p->efbHeight) ) ;
178 GXSetDispCopyGamma( GX_GM_1_0 ) ;
179
180 GXSetCopyFilter( rmode_p->aa, rmode_p->sample_pattern, GX_ENABLE, vfilter ) ;
181 GXSetCopyClear( clear_clr, 0x00FFFFFF ) ;
182
183 //----- Initialize EFB rendering area
184 GXSetViewport( 0.0f, 0.0f, (f32)(rmode_p->fbWidth), (f32)(rmode_p->efbHeight), 0.0f, 1.0f ) ;
185 GXSetScissor( 0, 0, (u32)rmode_p->fbWidth, (u32)rmode_p->efbHeight ) ;
186
187 //----- Clear EFB and XFB
188 GXCopyDisp( xfb_p[ 0 ], GX_ENABLE ) ; // The EFB is cleared and garbage is placed in XFB[0]
189 GXCopyDisp( xfb_p[ 0 ], GX_DISABLE ) ; // The cleared EFB is placed in XFB[0]
190 GXCopyDisp( xfb_p[ 1 ], GX_DISABLE ) ; // The cleared EFB is placed in XFB[1]
191 GXDrawDone() ;
192 }
193
194 /***************************************************************
195 KPAD callback
196 ***************************************************************/
work_callback(s32 chan,s32 reason,int idx)197 static void work_callback( s32 chan, s32 reason, int idx )
198 {
199 #pragma unused(chan)
200
201 u32 i ;
202 u32 smallest = MY_START_COUNT_DEFAULT ;
203 u32 smallestIdx = 0 ;
204
205 for (i = 0; i < MY_START_COUNTS_MAX; i++) {
206 if ( MyCallbackStatusBuf[ idx ][ i ].count == 0 ) {
207 break ;
208 } else {
209 if (smallest > MyCallbackStatusBuf[ idx ][ i ].count) {
210 smallest = MyCallbackStatusBuf[ idx ][ i ].count ;
211 smallestIdx = i ;
212 }
213 }
214 }
215 if ( i == MY_START_COUNTS_MAX ) {
216 i = smallestIdx ;
217 }
218
219 MyCallbackStatusBuf[ idx ][ i ].count = MY_START_COUNT_DEFAULT ;
220 MyCallbackStatusBuf[ idx ][ i ].reason = reason ;
221 MyCallbackLatestIdx[ idx ] = (s32)i ;
222 }
223
dpd_callback(s32 chan,s32 reason)224 void dpd_callback( s32 chan, s32 reason )
225 {
226 work_callback( chan, reason, 0 );
227 }
228
mpls_callback(s32 chan,s32 reason)229 void mpls_callback( s32 chan, s32 reason )
230 {
231 work_callback( chan, reason, 1 );
232 }
233
sampling_callback(s32 chan)234 void sampling_callback( s32 chan )
235 {
236 #pragma unused(chan)
237 MySamplingCount++ ;
238 }
239
read_pad(s32 chan)240 static void read_pad( s32 chan )
241 {
242 padsTrig[ chan ] = pads[ chan ] ;
243 PADRead( padsTmp ) ;
244 if ( padsTmp[ chan ].err == PAD_ERR_NONE ) {
245 pads[ chan ] = padsTmp[ chan ] ;
246 }
247 padsTrig[ chan ].button = (u16)( (padsTrig[ chan ].button ^ pads[ chan ].button) & pads[ chan ].button ) ;
248 }
249
250 /*******************************************************************************
251 Main
252 *******************************************************************************/
main(void)253 void main( void )
254 {
255 /***********************************************************************
256 Initialization
257 ***********************************************************************/
258 //----- Highest-priority hardware initialization
259 VIInit() ;
260
261 //----- Other high-priority initializations
262 init_memory() ; // Enable allocation and release of memory
263 init_memory2() ;
264 init_display() ; // Display device-related
265 init_gx() ; // GX-related
266
267 //----- Initialize application
268 init_kfont_texture() ;
269 init_sample() ; // Initialize KPAD
270
271 //----- Screen display ON
272 VISetBlack( FALSE ) ;
273 VIFlush() ;
274
275 PADInit();
276
277 /***********************************************************************
278 Main loop
279 ***********************************************************************/
280 while ( 1 ) {
281
282 //----- Get GameCube controller data
283 read_pad( 0 ) ;
284
285 /***************************************************************
286 First, perform calculations by the CPU
287 Find coordinates based on controller input, and prepare the data necessary to issue a GX command.
288
289 ***************************************************************/
290 //----- Get KPAD data (and miscellaneous processing)
291 work_kpad() ;
292
293 //----- Various calculations
294 work_sample() ;
295
296 /***************************************************************
297 Issue GX command and go on rendering to EFB
298 ***************************************************************/
299 //-----Hocus-pocus here to start issuing the command
300 GXInvalidateVtxCache() ;
301 GXInvalidateTexAll() ;
302
303 //----- Issue various commands
304 draw_sample() ;
305
306 //----- Finally, copy from EFB to XFB
307 GXCopyDisp( xfb_p[ draw_xfb_idx ], GX_ENABLE ) ;
308 GXDrawDone() ;
309
310
311 /***************************************************************
312 Switch the XFB just copied so that it can display on the TV
313 ***************************************************************/
314 disp_xfb_idx = draw_xfb_idx ;
315 VISetNextFrameBuffer( xfb_p[ disp_xfb_idx ] ) ;
316 VIFlush() ;
317
318 //----- Wait for it to actually switch
319 VIWaitForRetrace() ;
320
321 //----- Switch to the no-longer-displayed XFB ahead of time for the next render destination
322 draw_xfb_idx ^= 1 ;
323 }
324 }
325
326