1 /*---------------------------------------------------------------------------*
2 Project: RevolutionDWC Demos
3 File: ./common/src/main.c
4
5 Copyright 2005-2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 *---------------------------------------------------------------------------*/
14 /**
15 *
16 *
17 * Brief comment: Common code for demos
18 *
19 * This is common code used by the demos.
20 *
21 * -Main entry point
22 * -Establishment of network connection
23 * -Console output
24 * -Initialization and termination of RVLDWC
25 * -NAND read/write
26 * -Pad input
27 * -Sleep/Halt/V-Blank waiting
28 *
29 */
30
31 #include <demo.h>
32 #include "include/common.h"
33 #include <revolution/so.h>
34 #include "include/d_net_connect.h"
35
36 #define CONSOLE_ROWS 22
37 #define CONSOLE_COLS 40
38 #define CONSOLEBUF_SIZE (CONSOLE_ROWS * CONSOLE_COLS)
39
40 void FreeFunc( DWCAllocType name, void* ptr, u32 size );
41 void* AllocFunc( DWCAllocType name, u32 size, int align );
42
43 const GXColor Bkcolor =
44 {
45 0, 0, 64, 0
46 };
47 char s_consolebuf[CONSOLEBUF_SIZE];
48 u16 s_cursor = 0;
49
50 char s_console_fixedrow_buf[CONSOLE_COLS+1];
51
52 static OSFontHeader* FontData;
53
54 static MEMHeapHandle s_hmem2heap;
55 static OSMutex s_mutex;
56
57 /*---------------------------------------------------------------------------*
58 Check for inclusion in the Shift-JIS range
59 *---------------------------------------------------------------------------*/
IsShiftJISRange(unsigned char c)60 static BOOL IsShiftJISRange(unsigned char c)
61 {
62 return (c >= 0x81 && c <=0x9f) || (c >= 0xe0 && c <= 0xfc);
63 }
64
65 /*---------------------------------------------------------------------------*
66 Renders a character
67 *---------------------------------------------------------------------------*/
DrawCell(int x,int y,int xChar,int yChar)68 static void DrawCell(int x, int y, int xChar, int yChar)
69 {
70 s16 posLeft = (s16) x;
71 s16 posRight = (s16) (posLeft + FontData->cellWidth);
72 s16 posTop = (s16) y;
73 s16 posBottom = (s16) (posTop + FontData->cellHeight);
74
75 s16 texLeft = (s16) xChar;
76 s16 texRight = (s16) (xChar + FontData->cellWidth);
77 s16 texTop = (s16) yChar;
78 s16 texBottom = (s16) (yChar + FontData->cellHeight);
79
80 GXBegin(GX_QUADS, GX_VTXFMT0, 4);
81 GXPosition3s16(posLeft , posTop , 0);
82 GXTexCoord2s16(texLeft , texTop);
83
84 GXPosition3s16(posRight, posTop , 0);
85 GXTexCoord2s16(texRight, texTop);
86
87 GXPosition3s16(posRight, posBottom, 0);
88 GXTexCoord2s16(texRight, texBottom);
89
90 GXPosition3s16(posLeft , posBottom, 0);
91 GXTexCoord2s16(texLeft , texBottom);
92 GXEnd();
93 }
94
95 /*---------------------------------------------------------------------------*
96 Loads the font
97 *---------------------------------------------------------------------------*/
LoadSheet(void * image)98 static void LoadSheet(void* image)
99 {
100 Mtx mtx;
101 GXTexObj texObj;
102
103 // Set up and load texture object
104 GXInitTexObj(&texObj, // obj
105 image, // image_ptr
106 FontData->sheetWidth, // weight
107 FontData->sheetHeight, // height
108 (GXTexFmt) FontData->sheetFormat, // format
109 GX_CLAMP, // wrap_s (don't care)
110 GX_CLAMP, // wrap_t (don't care)
111 GX_FALSE); // mipmap (don't care)
112
113 GXInitTexObjLOD(&texObj,
114 GX_LINEAR, // min_filt
115 GX_LINEAR, // max_filt
116 0.0f, // min_lod (don't care)
117 0.0f, // max_lod (don't care)
118 0.0f, // lod_bias (don't care)
119 GX_DISABLE, // bias_clamp (don't care)
120 GX_FALSE, // do_edge_lod (don't care)
121 GX_ANISO_1); // max_aniso (don't care)
122
123 GXLoadTexObj(&texObj, GX_TEXMAP0);
124 MTXScale(mtx, 1.0f / FontData->sheetWidth,
125 1.0f / FontData->sheetHeight,
126 1.0f);
127 GXLoadTexMtxImm(mtx, GX_TEXMTX0, GX_MTX2x4);
128 GXSetNumTexGens(1);
129 GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX0);
130 }
131
132 /*---------------------------------------------------------------------------*
133 Renders a character
134 *---------------------------------------------------------------------------*/
DrawChar(int x,int y,u16 code)135 static s32 DrawChar(int x, int y, u16 code)
136 {
137 char buffer[3];
138 s32 width;
139 void* image;
140 s32 xChar;
141 s32 yChar;
142
143 if (code == 0)
144 {
145 return 0;
146 }
147
148 if (code < 256)
149 {
150 buffer[0] = (char) code;
151 buffer[1] = '\0';
152 }
153 else
154 {
155 buffer[0] = (char) (code >> 8);
156 buffer[1] = (char) (code & 0xff);
157 buffer[2] = '\0';
158 }
159
160 OSGetFontTexture(buffer, &image, &xChar, &yChar, &width);
161 LoadSheet(image);
162 DrawCell(x, y, xChar, yChar);
163
164 return width;
165 }
166
167 /*---------------------------------------------------------------------------*
168 Renders a string
169 *---------------------------------------------------------------------------*/
DrawString(int x,int y,const char * string)170 static s32 DrawString(int x, int y, const char* string)
171 {
172 s32 cx = 0;
173 int counter = 0;
174
175 while (*string)
176 {
177 void* image;
178 s32 xChar;
179 s32 yChar;
180 s32 width;
181
182 if ( (*string == '\n') || (*string == '\0') )
183 break;
184
185 // Multibyte (Shift_JIS) check
186 if (IsShiftJISRange((unsigned char)*string))
187 {
188 counter += 2;
189 }
190 else
191 {
192 counter++;
193 }
194
195 if ( counter > CONSOLE_COLS )
196 break;
197
198 string = OSGetFontTexture(string, &image, &xChar, &yChar, &width);
199 LoadSheet(image);
200 DrawCell(x + cx, y, xChar, yChar);
201 cx += width;
202 }
203
204 return cx;
205 }
206
207 /*---------------------------------------------------------------------------*
208 Initializes the console output
209 *---------------------------------------------------------------------------*/
ConsoleInit()210 static void ConsoleInit()
211 {
212
213 Mtx44 projection;
214 Mtx modelview;
215 GXRenderModeObj* rmp;
216 u16 top = 0x00;
217
218 if (OSGetFontEncode() == OS_FONT_ENCODE_SJIS)
219 {
220 FontData = OSAlloc(OS_FONT_SIZE_SJIS);
221 }
222 else
223 {
224 FontData = OSAlloc(OS_FONT_SIZE_ANSI);
225 }
226
227 OSInitFont(FontData);
228
229 // Clear EFB
230 GXSetCopyClear(Bkcolor, 0x00ffffff);
231 GXCopyDisp(DEMOGetCurrentBuffer(), GX_TRUE);
232
233 // Set matrices up to screen coordinates system
234 rmp = DEMOGetRenderModeObj();
235 MTXOrtho(projection, 0.0f, (f32) rmp->efbHeight, 0.0f, (f32) rmp->fbWidth, 0.0f, -100.0f);
236 GXSetProjection(projection, GX_ORTHOGRAPHIC);
237 MTXIdentity(modelview);
238 GXLoadPosMtxImm(modelview, GX_PNMTX0);
239 GXSetCurrentMtx(GX_PNMTX0);
240
241 // Set pixel processing mode
242 GXSetZMode(GX_ENABLE, GX_ALWAYS, GX_ENABLE);
243
244 // Set TEV parameters to "REPLACE COLOR"
245 GXSetNumChans(0);
246 GXSetNumTevStages(1);
247 GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE);
248 GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
249
250 // Translucent mode
251 GXSetBlendMode(GX_BM_BLEND, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR);
252
253 // Set up vertex descriptors
254 GXClearVtxDesc();
255 GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
256 GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
257 GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 0);
258 GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S16, 0);
259
260 s_console_fixedrow_buf[0] = '\0';
261 }
262
263 /*---------------------------------------------------------------------------*
264 Updates the console
265 *---------------------------------------------------------------------------*/
ConsoleFlush()266 static void ConsoleFlush()
267 {
268
269 u8 i;
270
271 for (i=0; i<CONSOLE_ROWS; i++)
272 DrawString( 0, i*19, &s_consolebuf[i*CONSOLE_COLS] );
273
274 // Display additional information at the very bottom
275 DrawString( 0, i*19, s_console_fixedrow_buf );
276 }
277
278 /*---------------------------------------------------------------------------*
279 Outputs a string to the console
280 *---------------------------------------------------------------------------*/
ConsolePut(char * text)281 static void ConsolePut(char* text)
282 {
283
284 int i;
285
286 while (*text != '\0')
287 {
288
289 switch (*text)
290 {
291
292 // Move the cursor to the next line when there is a newline character
293 case '\n':
294 s_consolebuf[s_cursor] = '\0';
295 s_cursor += CONSOLE_COLS;
296 s_cursor -= s_cursor % CONSOLE_COLS;
297 text++;
298 break;
299
300 // Write a normal character
301 default:
302 {
303 if (IsShiftJISRange((unsigned char)*(text)))
304 {
305 if (s_cursor % CONSOLE_COLS == CONSOLE_COLS-1)
306 {
307 s_consolebuf[s_cursor++] = ' '; // Fill with blank because there is only one character's worth free
308 }
309 else
310 {
311 s_consolebuf[s_cursor++] = *(text++); // Write two characters
312 s_consolebuf[s_cursor++] = *(text++);
313 }
314 }
315 else
316 {
317 s_consolebuf[s_cursor++] = *(text++);
318 }
319 }
320 }
321
322 // Shift everything once we arrive at the end of the buffer
323 if (s_cursor >= CONSOLEBUF_SIZE)
324 {
325
326 s_cursor -= CONSOLE_COLS;
327
328 for (i=0; i<CONSOLEBUF_SIZE-CONSOLE_COLS; i++)
329 {
330 s_consolebuf[i] = s_consolebuf[i+CONSOLE_COLS];
331 }
332
333 for (; i<CONSOLEBUF_SIZE; i++)
334 {
335 s_consolebuf[i] = ' ';
336 }
337 }
338 }
339 }
340
341
342 /*---------------------------------------------------------------------------*
343 Memory allocation function for DWC
344 *---------------------------------------------------------------------------*/
AllocFunc(DWCAllocType name,u32 size,int align)345 void* AllocFunc( DWCAllocType name, u32 size, int align )
346 {
347 void* ptr = NULL;
348
349 (void)name;
350 (void)align;
351
352 OSLockMutex( &s_mutex );
353 ptr = MEMAllocFromExpHeapEx( s_hmem2heap, size, align );
354 OSUnlockMutex( &s_mutex );
355
356 return ptr;
357 }
358
359 /*---------------------------------------------------------------------------*
360 Memory deallocation function for DWC
361 *---------------------------------------------------------------------------*/
FreeFunc(DWCAllocType name,void * ptr,u32 size)362 void FreeFunc( DWCAllocType name, void* ptr, u32 size )
363 {
364 (void)name;
365 (void)size;
366
367 // Make it possible to handle deallocation requests for unallocated areas (NULL pointers)
368 if ( ptr != NULL )
369 {
370 OSLockMutex( &s_mutex );
371 MEMFreeToExpHeap( s_hmem2heap, ptr );
372 OSUnlockMutex( &s_mutex );
373 }
374 }
375
376 /*---------------------------------------------------------------------------*
377 main function
378 *---------------------------------------------------------------------------*/
379
380 #define MAX_PARAMETER_NUM 24 // arbitrary
381 char* g_argv1 = NULL;
382 char* parameters[MAX_PARAMETER_NUM]; // Parameter set
383 u8 parameter_num = 0; // Number of parameters
384
main(int argc,char ** argv)385 int main(int argc, char** argv)
386 {
387 if (argc >= 2)
388 {
389 g_argv1 = argv[1];
390 }
391
392 if (argc > 0)
393 { // Set up arguments
394 int i;
395 if ((argc + 1) >= MAX_PARAMETER_NUM)
396 {
397 DWCDemoPrintf("*** too parameters!! (%d)\n", argc);
398 argc = MAX_PARAMETER_NUM;
399 }
400 for (i=0; i<(argc - 1); i++)
401 {
402 parameters[i] = argv[i + 1];
403 DWCDemoPrintf("parameters[%d]:%s\n", i, parameters[i]);
404 }
405 parameter_num = (u8)(argc - 1);
406 }
407
408 // Demo library initialization
409 //
410 DEMOInit(NULL); // to init heap
411
412 // Initialize the console screen
413 //
414 ConsoleInit();
415
416 // Pad input initialization
417 //
418 DEMOPadInit();
419
420 // Initialize NAND
421 //
422 NANDInit();
423
424 // Set up the Mutex for the DWC memory allocator
425 //
426 OSInitMutex( &s_mutex );
427
428 // Create an allocator to allocate from MEM2
429 //
430 s_hmem2heap = MEMCreateExpHeap( OSGetMEM2ArenaLo(),
431 (u32)OSGetMEM2ArenaHi() - (u32)OSGetMEM2ArenaLo() );
432
433 OSSetMEM2ArenaLo( OSGetMEM2ArenaHi() );
434
435 // Network connection
436 DWCDemoPrintf( "Connecting to the network...\n" );
437 DWCDemoUpdate();
438 if ( dNetConnect_Start() == FALSE )
439 {
440 DWCDemoPrintf( "Failed to conect to the network\n" );
441 OSHalt("");
442 }
443
444 // Initialize DWC
445 //
446 DWCDemoPrintf( "DWC_Init()\n" );
447 DWCDemoUpdate();
448 DWC_Init( DWC_AUTHSERVER_DEBUG, GAME_NAME, INITIAL_CODE, AllocFunc, FreeFunc );
449
450 // Set DWC's debug output level
451 //
452 DWC_SetReportLevel( DWC_REPORTFLAG_ALL );
453
454 // Start of DemoMain
455 //
456 DWCDemoPrintf( "DWCDemoMain start!!\n" );
457 DWCDemoUpdate();
458 DWCDemoMain();
459
460 // Shutdown of DWC
461 //
462 DWC_Shutdown();
463
464 // Network disconnection
465 DWCDemoPrintf("dNetConnect_Finish\n");
466 dNetConnect_Finish();
467
468 DWCDemoUpdate();
469
470 // Quit
471 OSHalt( "exit" );
472
473 return 0;
474 }
475
476 /*---------------------------------------------------------------------------*
477 Get key input
478 *---------------------------------------------------------------------------*/
DWCDemoPadRead()479 u32 DWCDemoPadRead()
480 {
481
482 u32 keyflag = 0;
483 u16 tmp = 0;
484
485 // Load pad information
486 DEMOPadRead();
487
488 // Read information from all four pads
489 tmp = DEMOPadGetButtonDown( 0 );
490 tmp |= DEMOPadGetButtonDown( 1 );
491 tmp |= DEMOPadGetButtonDown( 2 );
492 tmp |= DEMOPadGetButtonDown( 3 );
493
494 // Apply the latest samples
495 if ( tmp & PAD_BUTTON_UP )
496 keyflag |= DWCDEMO_KEY_UP;
497 if ( tmp & PAD_BUTTON_DOWN )
498 keyflag |= DWCDEMO_KEY_DOWN;
499 if ( tmp & PAD_BUTTON_LEFT )
500 keyflag |= DWCDEMO_KEY_LEFT;
501 if ( tmp & PAD_BUTTON_RIGHT )
502 keyflag |= DWCDEMO_KEY_RIGHT;
503 if ( tmp & PAD_BUTTON_A )
504 keyflag |= DWCDEMO_KEY_A;
505 if ( tmp & PAD_BUTTON_B )
506 keyflag |= DWCDEMO_KEY_B;
507 if ( tmp & PAD_BUTTON_X )
508 keyflag |= DWCDEMO_KEY_X;
509 if ( tmp & PAD_BUTTON_Y )
510 keyflag |= DWCDEMO_KEY_Y;
511
512 if ( tmp & PAD_TRIGGER_L )
513 keyflag |= DWCDEMO_KEY_L;
514 if ( tmp & PAD_TRIGGER_R )
515 keyflag |= DWCDEMO_KEY_R;
516
517 if ( tmp & PAD_TRIGGER_Z )
518 keyflag |= DWCDEMO_KEY_Z;
519 if ( tmp & PAD_BUTTON_START )
520 keyflag |= DWCDEMO_KEY_START;
521
522 return keyflag;
523
524 }
525
526 /*---------------------------------------------------------------------------*
527 Sleep
528 *---------------------------------------------------------------------------*/
DWCDemoSleep(u32 millisec)529 void DWCDemoSleep(u32 millisec)
530 {
531
532 OSSleepMilliseconds( millisec );
533
534 }
535
536 /*---------------------------------------------------------------------------*
537 Console output
538 *---------------------------------------------------------------------------*/
DWCDemoPrintf(const char * format,...)539 void DWCDemoPrintf(const char* format, ... )
540 {
541
542 char buf[1024];
543 va_list vlist;
544
545 OSLockMutex( &s_mutex );
546
547 va_start(vlist, format);
548 (void)vsnprintf(buf, sizeof(buf), format, vlist);
549 va_end(vlist);
550
551 // Debugging output
552 printf( buf );
553
554 // Screen output
555 ConsolePut( buf );
556
557 OSUnlockMutex( &s_mutex );
558 }
559
560 /*---------------------------------------------------------------------------*
561 Output to the console's bottom-most fixed row.
562 This will be applied at the next ConsoleFlush.
563 *---------------------------------------------------------------------------*/
DWCDemoPrintfToFixedRow(const char * format,...)564 void DWCDemoPrintfToFixedRow(const char* format, ... )
565 {
566 va_list vlist;
567
568 OSLockMutex( &s_mutex );
569
570 va_start(vlist, format);
571 (void)vsnprintf(s_console_fixedrow_buf, sizeof(s_console_fixedrow_buf), format, vlist);
572 va_end(vlist);
573
574 OSUnlockMutex( &s_mutex );
575 }
576
577 /*---------------------------------------------------------------------------*
578 Screen update
579 *---------------------------------------------------------------------------*/
DWCDemoUpdate()580 void DWCDemoUpdate()
581 {
582
583 // Flush
584 //
585 // One frame is consumed here
586 //
587 DEMOBeforeRender();
588
589 ConsoleFlush();
590
591 DEMODoneRender();
592
593 }
594
595 /*---------------------------------------------------------------------------*
596 Panic
597 *---------------------------------------------------------------------------*/
DWCDemoPanic(const char * msg)598 void DWCDemoPanic(const char* msg)
599 {
600
601 OSHalt( msg );
602
603 }
604
605 /*---------------------------------------------------------------------------*
606 Load data from NAND
607 *---------------------------------------------------------------------------*/
DWCDemoLoadNAND(const char * filename,s32 seek,u8 * buf,u32 bufsize)608 void DWCDemoLoadNAND( const char* filename, s32 seek, u8* buf, u32 bufsize)
609 {
610
611 NANDFileInfo info;
612 char homedir[NAND_MAX_PATH];
613 char path[NAND_MAX_PATH];
614
615 // Must be 32-byte aligned.
616 ASSERT( (bufsize & 0x1f) == 0 );
617 ASSERT( (((u32)buf) & 0x1f) == 0 );
618
619 DWCi_Np_CpuClear32( buf, bufsize );
620
621 // Get the home directory
622 if ( NANDGetHomeDir( homedir ) != NAND_RESULT_OK )
623 {
624 // Failed
625 DWCDemoPrintf( "[error] Failed to get the home directory.\n" );
626 DWCDemoPrintf( "[error] Couldn't load data from NAND.\n" );
627 return;
628 }
629
630 // Open the file
631 snprintf( path, sizeof(path), "%s/nocopy/%s", homedir, filename );
632
633 switch ( NANDOpen( path, &info, NAND_ACCESS_READ ) )
634 {
635
636 case NAND_RESULT_OK:
637 break;
638
639 case NAND_RESULT_NOEXISTS:
640
641 DWCDemoPrintf( "Create new file.\n");
642
643 // There is none, so make one
644 DWCDemoSaveNAND( filename, seek, buf, bufsize );
645
646 return;
647
648 default:
649 // File could not be opened
650 DWCDemoPanic("Couldn't open a file.");
651 break;
652
653 }
654
655 // Seek
656 NANDSeek( &info, seek, NAND_SEEK_SET );
657
658 // Read
659 NANDRead( &info, (void*)buf, bufsize );
660
661 // Close
662 NANDClose( &info );
663
664 }
665
666 /*---------------------------------------------------------------------------*
667 Save the data in NAND
668 *---------------------------------------------------------------------------*/
DWCDemoSaveNAND(const char * filename,s32 seek,u8 * buf,u32 bufsize)669 void DWCDemoSaveNAND( const char* filename, s32 seek, u8* buf, u32 bufsize)
670 {
671
672 NANDFileInfo info;
673 char currentdir[NAND_MAX_PATH];
674 char homedir[NAND_MAX_PATH];
675 char path[NAND_MAX_PATH];
676
677 // Must be 32-byte aligned.
678 ASSERT( (bufsize & 0x1f) == 0 );
679 ASSERT( (((u32)buf) & 0x1f) == 0 );
680
681 // Save the current directory
682 if ( NANDGetCurrentDir( currentdir ) != NAND_RESULT_OK )
683 {
684 // Failed
685 DWCDemoPrintf( "[error] Failed to get the current directory.\n" );
686 DWCDemoPrintf( "[error] Couldn't load data from NAND.\n" );
687 return;
688 }
689
690 // Get the home directory
691 if ( NANDGetHomeDir( homedir ) != NAND_RESULT_OK )
692 {
693 // Failed
694 DWCDemoPrintf( "[error] Failed to get the home directory.\n" );
695 DWCDemoPrintf( "[error] Couldn't load data from NAND.\n" );
696 return;
697 }
698
699 // Create the nocopy directory
700 if ( NANDChangeDir( homedir ) != NAND_RESULT_OK )
701 {
702 // Failed
703 DWCDemoPrintf( "[error] Failed to move to the home directory.\n" );
704 DWCDemoPrintf( "[error] Couldn't load data from NAND.\n" );
705 return;
706 }
707
708 switch ( NANDChangeDir( "nocopy" ) )
709 {
710 case NAND_RESULT_OK:
711 break;
712
713 case NAND_RESULT_NOEXISTS:
714 // There is none, so make one
715 if ( NANDCreateDir( "nocopy", NAND_PERM_OWNER_READ|NAND_PERM_OWNER_WRITE, 0 )
716 != NAND_RESULT_OK )
717 {
718 // Failed
719 DWCDemoPrintf( "[error] Failed to create the nocopy directory.\n" );
720 DWCDemoPrintf( "[error] Couldn't load data from NAND.\n" );
721 NANDChangeDir( currentdir );
722 return;
723 }
724
725 break;
726
727 case NAND_RESULT_ACCESS:
728 case NAND_RESULT_INVALID:
729 case NAND_RESULT_UNKNOWN:
730 case NAND_RESULT_FATAL_ERROR:
731 // Failed
732 DWCDemoPrintf( "[error] Failed to move to the \"nocopy\" directory.\n" );
733 DWCDemoPrintf( "[error] Couldn't load data from NAND.\n" );
734 NANDChangeDir( currentdir );
735 return;
736 }
737
738 NANDChangeDir( currentdir );
739
740 // Open the file
741 snprintf( path, sizeof(path), "%s/nocopy/%s", homedir, filename );
742
743 switch ( NANDOpen( path, &info, NAND_ACCESS_WRITE ) )
744 {
745
746 case NAND_RESULT_OK:
747 break;
748
749 case NAND_RESULT_NOEXISTS:
750
751 // There is none, so make one
752 NANDCreate( path, NAND_PERM_OWNER_READ|NAND_PERM_OWNER_WRITE, 0);
753
754 if ( NANDOpen( path, &info, NAND_ACCESS_WRITE ) != NAND_RESULT_OK )
755 {
756 // File could not be opened
757 DWCDemoPanic("Couldn't open a file.");
758 return;
759 }
760
761 break;
762
763 default:
764 // File could not be opened
765 DWCDemoPanic("Couldn't open a file.");
766 break;
767
768 }
769
770 // Seek
771 NANDSeek( &info, seek, NAND_SEEK_SET );
772
773 // Write
774 NANDWrite( &info, (void*)buf, bufsize );
775
776 // Close
777 NANDClose( &info );
778
779 }
780
781 /*---------------------------------------------------------------------------*
782 Display friend status
783 *---------------------------------------------------------------------------*/
784 #ifndef DWC_NOGS
DWCDemoGetFriendStatusString(const DWCFriendData * param)785 const char* DWCDemoGetFriendStatusString(const DWCFriendData* param)
786 {
787 u8 status;
788
789 if (param == NULL) return "IGNORED!!";
790 status = DWC_GetFriendStatusSC(param, NULL, NULL, NULL);
791 switch (status)
792 {
793 case DWC_STATUS_OFFLINE:
794 return "OFFLINE";
795 case DWC_STATUS_ONLINE:
796 return "ONLINE";
797 case DWC_STATUS_PLAYING:
798 return "PLAYING";
799 case DWC_STATUS_MATCH_ANYBODY:
800 return "ANYBODY";
801 case DWC_STATUS_MATCH_FRIEND:
802 return "FRIEND";
803 case DWC_STATUS_MATCH_SC_SV:
804 return "SERVER";
805 case DWC_STATUS_MATCH_SC_CL:
806 return "CLIENT";
807 }
808
809 return "IGNORED!!";
810 }
811 #endif
812