1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - tcl - demos.TWL - tcl-1
3   File:     main.c
4 
5   Copyright 2008-2009 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   $Date:: 2009-10-15#$
14   $Rev: 11095 $
15   $Author: kitase_hirotake $
16  *---------------------------------------------------------------------------*/
17 #include <twl.h>
18 #include <twl/tcl.h>
19 #include <twl/ssp/ARM9/jpegdec.h>
20 #include <twl/ssp/ARM9/exifdec.h>
21 
22 #include "DEMO.h"
23 #include "screen.h"
24 
25 /*---------------------------------------------------------------------------*
26     Constant Definitions
27  *---------------------------------------------------------------------------*/
28 #define WIDTH       256         // Image width
29 #define HEIGHT      192         // Image height
30 
31 /*---------------------------------------------------------------------------*
32     Internal Functions and Definitions
33  *---------------------------------------------------------------------------*/
34 void VBlankIntr(void);
35 void Print(void);
36 void DownSampling( const u16* org_img, int org_wdt, int org_hgt,
37                          u16* new_img, int new_wdt, int new_hgt );
38 int GetR ( u16 color );
39 int GetG ( u16 color );
40 int GetB ( u16 color );
41 
42 /*---------------------------------------------------------------------------*
43     Internal Variable Definitions
44  *---------------------------------------------------------------------------*/
45 // Buffer storing images
46 static u16 draw_buffer[ WIDTH * HEIGHT ] ATTRIBUTE_ALIGN(32);
47 
48 int condition_id = 0;
49 int search = 0;
50 int num_pict = 0;
51 int draw_id = 0;
52 
53 // Get the color value (from 0 to 31)
GetR(u16 color)54 int GetR ( u16 color ) { return (color & GX_RGB_R_MASK) >> GX_RGB_R_SHIFT; }
GetG(u16 color)55 int GetG ( u16 color ) { return (color & GX_RGB_G_MASK) >> GX_RGB_G_SHIFT; }
GetB(u16 color)56 int GetB ( u16 color ) { return (color & GX_RGB_B_MASK) >> GX_RGB_B_SHIFT; }
57 
58 /*---------------------------------------------------------------------------*
59   Name:         VBlankIntr
60 
61   Description:  V-Blank interrupt handler.
62 
63   Arguments:    None.
64 
65   Returns:      None.
66  *---------------------------------------------------------------------------*/
VBlankIntr(void)67 void VBlankIntr(void)
68 {
69     OS_SetIrqCheckFlag( OS_IE_V_BLANK );
70 }
71 
72 /*---------------------------------------------------------------------------*
73   Name:         Print
74 
75   Description:  Renders debug information.
76 
77   Arguments:    None.
78 
79   Returns:      None.
80  *---------------------------------------------------------------------------*/
Print(void)81 void Print(void)
82 {
83     const char* condition_name[] = { "All Picture", "Favorite1", "Favorite2", "Favorite3", "FavoriteAll" };
84 
85     ClearScreen();
86 
87     PutScreen(0, 0, 0xff, "TCL-1 Search Picture Demo");
88 
89     PutScreen(2, 4, 0xff, "TCL Condition : %s", condition_name[condition_id] );
90     PutScreen(2, 5, 0xff, "Draw Index    : %d", draw_id );
91 
92     PutScreen(2, 7, 0xff, "Num Pictures  : %d", num_pict );
93 
94     PutScreen(1, 12, 0xff, "A Button > Draw Picture" );
95     PutScreen(1, 13, 0xff, "B Button > Draw Thumbnail" );
96     PutScreen(1, 14, 0xff, "X Button > Select Condition" );
97     PutScreen(1, 15, 0xff, "Y Button > Change Search Method" );
98     PutScreen(1, 16, 0xff, "R Button > Delete Picture" );
99     PutScreen(1, 17, 0xff, "L Button > Change FavoriteType" );
100 
101     if( search )
102     {
103         PutScreen(1, 2, 0xff, "Iterate Search" );
104     }
105     else
106     {
107         PutScreen(1, 2, 0xff, "Random Search" );
108         PutScreen(1, 18, 0xff, "Left  Key > Select Draw Index" );
109         PutScreen(1, 19, 0xff, "Right Key > Select Draw Index" );
110     }
111 }
112 
113 /*---------------------------------------------------------------------------*
114   Name:         DownSampling
115 
116   Description:  Size reduction.
117 
118   Arguments:    org_img: Original image
119                 org_wdt: Original image width
120                 org_hgt: Original image height
121                 new_img: New image
122                 new_wdt: New image width
123                 new_hgt: New image height
124 
125   Returns:      None.
126  *---------------------------------------------------------------------------*/
DownSampling(const u16 * org_img,int org_wdt,int org_hgt,u16 * new_img,int new_wdt,int new_hgt)127 void DownSampling( const u16* org_img, int org_wdt, int org_hgt,
128                          u16* new_img, int new_wdt, int new_hgt )
129 {
130     int h, w, i = 0;
131 
132     if( org_wdt == TCL_JPEG_WIDTH )
133     {
134         // Normal photograph
135         for ( h = 0; h < new_hgt; ++h )
136         {
137             for ( w = 0; w < new_wdt; ++w )
138             {
139                 new_img[ h * new_wdt + w ] = org_img[ ( h * org_hgt / new_hgt ) * org_wdt +
140                                                       w * org_wdt / new_wdt ];
141             }
142         }
143     }
144     else
145     {
146         // Thumbnail
147         u16* thumb_img = &new_img[ ( HEIGHT - SSP_JPEG_THUMBNAIL_HEIGHT ) / 2 * WIDTH +
148                                    ( WIDTH - SSP_JPEG_THUMBNAIL_WIDTH ) / 2 ];
149 
150         for ( h = 0; h < org_hgt; ++h )
151         {
152             for ( w = 0; w < org_wdt; ++w )
153             {
154                 thumb_img[ h * new_wdt + w ] = org_img[ i ];
155                 ++i;
156             }
157         }
158     }
159 }
160 
161 /*---------------------------------------------------------------------------*
162   Name:         TwlMain
163 
164   Description:  Main.
165 
166   Arguments:    None.
167 
168   Returns:      None.
169  *---------------------------------------------------------------------------*/
TwlMain(void)170 void TwlMain(void)
171 {
172     OSHeapHandle handle;
173     char  pict_path[TCL_PATH_LEN];
174     void* nstart;
175 
176     void* pTableBuf;
177     void* pWorkBuf;
178 
179     FSResult fs_result;
180     TCLResult result;
181 
182     // TCL accessor
183     TCLAccessor accessor;
184 
185     // Search condition object
186     TCLSearchObject search_obj;
187     TCLSortType sort_type = TCL_SORT_TYPE_DATE;
188 
189     // Initialization process
190     DEMOInitCommon();
191     DEMOInitVRAM();
192 
193     FS_Init( FS_DMA_NOT_USE );
194 
195     InitScreen();
196     ClearScreen();
197 
198     // GX-related settings
199     GX_SetBankForBG( GX_VRAM_BG_128_A );
200 
201     GX_SetGraphicsMode( GX_DISPMODE_GRAPHICS, GX_BGMODE_3, GX_BG0_AS_2D );
202 
203     GX_SetVisiblePlane( GX_PLANEMASK_BG3 );
204     G2_SetBG3Priority( 0 );
205     G2_BG3Mosaic( FALSE );
206 
207     G2_SetBG3ControlDCBmp( GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x00000 );
208 
209     MI_CpuClearFast( draw_buffer, WIDTH * HEIGHT * sizeof(u16) );
210     GX_LoadBG3Bmp( draw_buffer, 0, WIDTH * HEIGHT * sizeof(u16) );
211 
212     // Create heap
213     nstart = OS_InitAlloc( OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1 );
214     OS_SetMainArenaLo( nstart );
215 
216     handle = OS_CreateHeap( OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi() );
217     if (handle < 0)
218     {
219         OS_Panic("ARM9: Fail to create heap...\n");
220     }
221     handle = OS_SetCurrentHeap( OS_ARENA_MAIN, handle );
222 
223     // TCL initialization
224     // 32-byte alignment necessary
225     pTableBuf = OS_Alloc( TCL_GetTableBufferSize() );
226     pWorkBuf = OS_Alloc( TCL_GetWorkBufferSize() );
227     if( pTableBuf == NULL || pWorkBuf == NULL )
228     {
229         OS_Panic("Cannot allocate memory!");
230     }
231 
232     result = TCL_LoadTable( &accessor,
233                             pTableBuf,
234                             TCL_GetTableBufferSize(),
235                             pWorkBuf,
236                             TCL_GetWorkBufferSize(),
237                             &fs_result );
238 
239 #if 1
240 
241     // End the following processes when loading of the management file fails
242 
243     switch ( result )
244     {
245       case TCL_RESULT_SUCCESS: break; // Success
246       case TCL_RESULT_ERROR_EXIST_OTHER_FILE:
247       case TCL_RESULT_ERROR_ALREADY_MANAGED:
248         // Error indicating no obstacle to getting a photo
249         OS_TPrintf("failed TCL_LoadTable : %d\n", result );
250         break;
251       default:
252         // For other errors, prompt Nintendo DSi camera startup and end the process
253         //OS_TPrintf ("appropriate text here")
254 
255         OS_Panic("failed TCL_LoadTable : %d\n", result );
256         break;
257     }
258 
259 #else
260 
261     // Try recovering if loading of the management file failed
262 
263     switch( result )
264     {
265     case TCL_RESULT_SUCCESS: break; // Success
266     case TCL_RESULT_ERROR_EXIST_OTHER_FILE:
267     case TCL_RESULT_ERROR_ALREADY_MANAGED:
268         // Error indicating no obstacle to getting a photo
269         OS_TPrintf("failed TCL_LoadTable : %d\n", result );
270         break;
271     default:
272         OS_TPrintf("failed TCL_LoadTable : %d\n", result );
273 
274         // The management file is recreated because read processing cannot be carried out
275         result = TCL_CreateTable( &accessor,
276                                   pTableBuf,
277                                   TCL_GetTableBufferSize(),
278                                   pWorkBuf,
279                                   TCL_GetWorkBufferSize(),
280                                   &fs_result );
281 
282         if( result != TCL_RESULT_SUCCESS )
283         {
284             OS_Panic("failed TCL_CreateTable : %d\n", result );
285         }
286         break;
287     }
288 
289 #endif
290 
291     // Initialize SearchObject
292     TCL_InitSearchObject( &search_obj, TCL_SEARCH_CONDITION_PICTURE );
293 
294     // How many photos in all?
295     num_pict = TCL_GetNumPictures( &accessor, &search_obj );
296 
297     // Sort the table as conditions indicate
298     TCL_SortTable( &accessor,  sort_type );
299 
300     Print();
301 
302     DEMOStartDisplay();
303 
304     // Updates text display
305     UpdateScreen();
306 
307     while (1)
308     {
309         // Reading pad information and controls
310         DEMOReadKey();
311 
312         if( num_pict != 0 && DEMO_IS_TRIG( PAD_BUTTON_A | PAD_BUTTON_B | PAD_BUTTON_R | PAD_BUTTON_L ) )
313         {
314             BOOL success_flag = FALSE;
315 
316             // Display thumbnails when the B Button is pressed
317             BOOL thumbnail_flag = DEMO_IS_TRIG( PAD_BUTTON_B );
318 
319             BOOL delete_flag = DEMO_IS_TRIG( PAD_BUTTON_R );
320 
321             BOOL favorite_flag = DEMO_IS_TRIG( PAD_BUTTON_L );
322 
323             const TCLPictureInfo* pPicInfo = NULL;
324             const TCLMakerNote* pMakerNote = NULL;
325 
326             MI_CpuClear( pict_path, TCL_PATH_LEN );
327 
328             if( search )
329             {
330                 do
331                 {
332                     draw_id = search_obj.startIdx;
333 
334                     // Get photo information
335                     result = TCL_SearchNextPictureInfo( &accessor,
336                                                         &pPicInfo,
337                                                         &search_obj );
338 
339                     if( result == TCL_RESULT_ERROR_NO_FIND_PICTURE )
340                     {
341                         // Initialize SearchObject as one full search has been completed
342                         TCL_InitSearchObject( &search_obj, search_obj.condition );
343                         OS_TPrintf("finished TCL_SearchNextPicturePath\n" );
344                     }
345                 } while( result == TCL_RESULT_ERROR_NO_FIND_PICTURE );
346             }
347             else
348             {
349                 result = TCL_SearchPictureInfoByIndex( &accessor,
350                                                        &pPicInfo,
351                                                        &search_obj,
352                                                        draw_id );
353             }
354 
355             if( result != TCL_RESULT_SUCCESS )
356             {
357                 OS_TPrintf("failed TCL_Search* : %d\n", result );
358             }
359             else if( delete_flag )
360             {
361                 TCLPictureInfo* pGetPicInfo = NULL;
362                 FSResult result;
363 
364                 // For the test, get the picture's path and then get TCLPictureInfo again.
365                 ( void ) TCL_PrintPicturePath( pict_path, TCL_PATH_LEN, pPicInfo );
366                 if(TCL_GetPictureInfoFromPath( &accessor, &pGetPicInfo, (const char*)pict_path, (u32)STD_StrLen(pict_path) ) == FALSE)
367                 {
368                     OS_TPrintf("failed TCL_PrintPictureInfo\n");
369                 }
370                 else
371                 {
372                     // Allow picture data to be deleted only if it was created by one of your game titles.
373                     // You may also restrict this to only items created by this application.
374                     if(TCL_DeletePicture(&accessor, pGetPicInfo, &result) != TCL_RESULT_SUCCESS)
375                         OS_TPrintf("failed TCL_DeletePicture\n");
376 
377                     search_obj.condition = TCL_SEARCH_CONDITION_PICTURE;
378                     sort_type = TCL_SORT_TYPE_DATE;
379 
380                     switch( condition_id )
381                     {
382                     case 0: break;
383                     case 1:
384                         search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_1;
385                         sort_type = TCL_SORT_TYPE_FAVORITE_1;
386                         break;
387                     case 2:
388                         search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_2;
389                         sort_type = TCL_SORT_TYPE_FAVORITE_2;
390                         break;
391                     case 3:
392                         search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_3;
393                         sort_type = TCL_SORT_TYPE_FAVORITE_3;
394                         break;
395                     case 4:
396                         search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_ALL;
397                         sort_type = TCL_SORT_TYPE_FAVORITE_ALL;
398                         break;
399                     }
400 
401                     if( search ) TCL_InitSearchObject( &search_obj, search_obj.condition );
402                     num_pict = TCL_GetNumPictures( &accessor, &search_obj );
403                     TCL_SortTable( &accessor, sort_type );
404                     draw_id = 0;
405 
406                     Print();
407                 }
408             }
409             else if( favorite_flag )
410             {
411                 TCLPictureInfo* pChangePicInfo = (TCLPictureInfo*)pPicInfo;
412                 TCLFavoriteType nextFavoriteType;
413                 FSResult result;
414 
415                 switch ( pChangePicInfo->favoriteType )
416                 {
417                 case TCL_FAVORITE_TYPE_NONE:
418                     nextFavoriteType = TCL_FAVORITE_TYPE_1;
419                     break;
420                 case TCL_FAVORITE_TYPE_1:
421                     nextFavoriteType = TCL_FAVORITE_TYPE_2;
422                     break;
423                 case TCL_FAVORITE_TYPE_2:
424                     nextFavoriteType = TCL_FAVORITE_TYPE_3;
425                     break;
426                 case TCL_FAVORITE_TYPE_3:
427                 default:
428                     nextFavoriteType = TCL_FAVORITE_TYPE_NONE;
429                     break;
430                 }
431 
432                 OS_TPrintf("change favoriteType %d -> %d\n", pChangePicInfo->favoriteType, nextFavoriteType);
433 
434                 if(TCL_ChangePictureFavoriteType(&accessor, pChangePicInfo, nextFavoriteType, &result) != TCL_RESULT_SUCCESS)
435                     OS_TPrintf("failed TCL_ChangePictureFavoriteType\n");
436 
437                 search_obj.condition = TCL_SEARCH_CONDITION_PICTURE;
438                 sort_type = TCL_SORT_TYPE_DATE;
439 
440                 switch( condition_id )
441                 {
442                 case 0: break;
443                 case 1:
444                     search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_1;
445                     sort_type = TCL_SORT_TYPE_FAVORITE_1;
446                     break;
447                 case 2:
448                     search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_2;
449                     sort_type = TCL_SORT_TYPE_FAVORITE_2;
450                     break;
451                 case 3:
452                     search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_3;
453                     sort_type = TCL_SORT_TYPE_FAVORITE_3;
454                     break;
455                 case 4:
456                     search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_ALL;
457                     sort_type = TCL_SORT_TYPE_FAVORITE_ALL;
458                     break;
459                 }
460 
461                 if( search ) TCL_InitSearchObject( &search_obj, search_obj.condition );
462                 num_pict = TCL_GetNumPictures( &accessor, &search_obj );
463                 TCL_SortTable( &accessor, sort_type );
464                 draw_id = 0;
465 
466                 Print();
467             }
468             else
469             {
470                 FSFile file;
471                 u32 size;
472                 s32 read_size;
473                 s16 width, height;
474                 TCLResult decodeResult;
475                 u32 decodeOptiion;
476 
477                 // JPEG buffer
478                 u8*  pJpegBuf = NULL;
479                 u16* pDecodeTmpBuf = NULL;
480 
481                 if( thumbnail_flag )
482                 {
483                     width  = SSP_JPEG_THUMBNAIL_WIDTH;
484                     height = SSP_JPEG_THUMBNAIL_HEIGHT;
485                     decodeOptiion = SSP_JPEG_THUMBNAIL | SSP_JPEG_RGB555;
486                 }
487                 else
488                 {
489                     width  = TCL_JPEG_WIDTH;
490                     height = TCL_JPEG_HEIGHT;
491                     decodeOptiion = SSP_JPEG_RGB555;
492                 }
493 
494                 // Get the photo path
495                 ( void ) TCL_PrintPicturePath( pict_path, TCL_PATH_LEN, pPicInfo );
496 
497                 // Get photo
498                 FS_InitFile( &file );
499                 if( FS_OpenFileEx( &file, pict_path, FS_FILEMODE_R ) )
500                 {
501                     pJpegBuf = (u8*)OS_Alloc( TCL_MAX_JPEG_SIZE );
502 
503                     // Allocate the necessary memory for whether it is a normal photograph or a thumbnail
504                     pDecodeTmpBuf = (u16*)OS_Alloc( width * height * sizeof(u16) );
505 
506                     if( pJpegBuf == NULL || pDecodeTmpBuf == NULL )
507                     {
508                         OS_Panic("Cannot allocate memory!");
509                     }
510 
511                     size = FS_GetFileLength( &file );
512                     read_size = FS_ReadFile( &file, pJpegBuf, (s32)size );
513 
514                     if( read_size > 0 )
515                     {
516                         // JPEG decoding
517                         decodeResult = TCL_DecodePicture( pJpegBuf,
518                                                           size,
519                                                           (u8*)pDecodeTmpBuf,
520                                                           width, height,
521                                                           decodeOptiion );
522 
523                         if( decodeResult == TCL_RESULT_SUCCESS )
524                         {
525                             // Get manufacturer's notes
526                             pMakerNote = ( TCLMakerNote* ) SSP_GetJpegDecoderMakerNoteAddrEx( SSP_MAKERNOTE_PHOTO );
527 
528                             // Display if image type is same
529                             if( TCL_IsSameImageType( pPicInfo, pMakerNote ) != FALSE )
530                             {
531                                 MI_CpuClearFast( draw_buffer, WIDTH * HEIGHT * sizeof(u16) );
532 
533                                 // Shrink to image size
534                                 DownSampling( pDecodeTmpBuf, width, height,
535                                               draw_buffer, WIDTH, HEIGHT );
536 
537                                 success_flag = TRUE;
538                             }
539                             else OS_TPrintf("Not Same Image Type\n");
540                         }
541                         else OS_TPrintf("failed JPEG Decode %d\n", decodeResult);
542                     }
543                     else OS_TPrintf("failed FS_ReadFile\n");
544 
545                     ( void ) FS_CloseFile( &file );
546 
547                     OS_Free( pJpegBuf );
548                     OS_Free( pDecodeTmpBuf );
549                 }
550                 else OS_TPrintf("failed FS_Open\n");
551             }
552 
553             if( !success_flag ) MI_CpuClearFast( draw_buffer, WIDTH * HEIGHT * sizeof(u16) );
554             DC_FlushRange( draw_buffer, WIDTH * HEIGHT * sizeof(u16) );
555 
556             Print();
557         }
558         else if( DEMO_IS_TRIG( PAD_BUTTON_X ) )
559         {
560             // Modify search conditions
561             if( ++condition_id > 4 ) condition_id = 0;
562 
563             search_obj.condition = TCL_SEARCH_CONDITION_PICTURE;
564             sort_type = TCL_SORT_TYPE_DATE;
565 
566             switch( condition_id )
567             {
568             case 0: break;
569             case 1:
570                 search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_1;
571                 sort_type = TCL_SORT_TYPE_FAVORITE_1;
572                 break;
573             case 2:
574                 search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_2;
575                 sort_type = TCL_SORT_TYPE_FAVORITE_2;
576                 break;
577             case 3:
578                 search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_3;
579                 sort_type = TCL_SORT_TYPE_FAVORITE_3;
580                 break;
581             case 4:
582                 search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_ALL;
583                 sort_type = TCL_SORT_TYPE_FAVORITE_ALL;
584                 break;
585             }
586 
587             if( search ) TCL_InitSearchObject( &search_obj, search_obj.condition );
588             num_pict = TCL_GetNumPictures( &accessor, &search_obj );
589             TCL_SortTable( &accessor, sort_type );
590             draw_id = 0;
591 
592             Print();
593         }
594         else if( DEMO_IS_TRIG( PAD_BUTTON_Y ) )
595         {
596             // Modify search method
597             search ^= 1;
598             draw_id = 0;
599 
600             if( search ) TCL_InitSearchObject( &search_obj, search_obj.condition );
601             Print();
602         }
603         else if( num_pict != 0 && !search )
604         {
605             // Modify ID of displayed photo
606             if( DEMO_IS_TRIG( PAD_KEY_RIGHT ) )
607             {
608                 if( ++draw_id >= num_pict ) draw_id = 0;
609                 Print();
610             }
611             else if( DEMO_IS_TRIG( PAD_KEY_LEFT ) )
612             {
613                 if( --draw_id < 0 ) draw_id = num_pict - 1;
614                 Print();
615             }
616         }
617 
618         OS_WaitVBlankIntr();
619 
620         // Updates text display
621         UpdateScreen();
622 
623         GX_LoadBG3Bmp( draw_buffer, 0, WIDTH * HEIGHT * sizeof(u16) );
624     }
625 
626     OS_Free( pTableBuf );
627     OS_Free( pWorkBuf );
628 
629     OS_Terminate();
630 }
631