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