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-06-04#$
14   $Rev: 10698 $
15   $Author: okubata_ryoma $
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 
100     if( search )
101     {
102         PutScreen(1, 2, 0xff, "Iterate Search" );
103     }
104     else
105     {
106         PutScreen(1, 2, 0xff, "Random Search" );
107         PutScreen(1, 17, 0xff, "Left  Key > Select Draw Index" );
108         PutScreen(1, 18, 0xff, "Right Key > Select Draw Index" );
109     }
110 }
111 
112 /*---------------------------------------------------------------------------*
113   Name:         DownSampling
114 
115   Description:  Size reduction.
116 
117   Arguments:    org_img: Original image
118                 org_wdt: Original image width
119                 org_hgt: Original image height
120                 new_img: New image
121                 new_wdt: New image width
122                 new_hgt: New image height
123 
124   Returns:      None.
125  *---------------------------------------------------------------------------*/
DownSampling(const u16 * org_img,int org_wdt,int org_hgt,u16 * new_img,int new_wdt,int new_hgt)126 void DownSampling( const u16* org_img, int org_wdt, int org_hgt,
127                          u16* new_img, int new_wdt, int new_hgt )
128 {
129     int h, w, i = 0;
130 
131     if( org_wdt == TCL_JPEG_WIDTH )
132     {
133         // Normal photograph
134         for ( h = 0; h < new_hgt; ++h )
135         {
136             for ( w = 0; w < new_wdt; ++w )
137             {
138                 new_img[ h * new_wdt + w ] = org_img[ ( h * org_hgt / new_hgt ) * org_wdt +
139                                                       w * org_wdt / new_wdt ];
140             }
141         }
142     }
143     else
144     {
145         // Thumbnail
146         u16* thumb_img = &new_img[ ( HEIGHT - SSP_JPEG_THUMBNAIL_HEIGHT ) / 2 * WIDTH +
147                                    ( WIDTH - SSP_JPEG_THUMBNAIL_WIDTH ) / 2 ];
148 
149         for ( h = 0; h < org_hgt; ++h )
150         {
151             for ( w = 0; w < org_wdt; ++w )
152             {
153                 thumb_img[ h * new_wdt + w ] = org_img[ i ];
154                 ++i;
155             }
156         }
157     }
158 }
159 
160 /*---------------------------------------------------------------------------*
161   Name:         TwlMain
162 
163   Description:  Main.
164 
165   Arguments:    None.
166 
167   Returns:      None.
168  *---------------------------------------------------------------------------*/
TwlMain(void)169 void TwlMain(void)
170 {
171     OSHeapHandle handle;
172     char  pict_path[TCL_PATH_LEN];
173     void* nstart;
174 
175     void* pTableBuf;
176     void* pWorkBuf;
177 
178     FSResult fs_result;
179     TCLResult result;
180 
181     // TCL accessor
182     TCLAccessor accessor;
183 
184     // Search condition object
185     TCLSearchObject search_obj;
186     TCLSortType sort_type = TCL_SORT_TYPE_DATE;
187 
188     // Initialization process
189     DEMOInitCommon();
190     DEMOInitVRAM();
191 
192     FS_Init( FS_DMA_NOT_USE );
193 
194     InitScreen();
195     ClearScreen();
196 
197     // GX-related settings
198     GX_SetBankForBG( GX_VRAM_BG_128_A );
199 
200     GX_SetGraphicsMode( GX_DISPMODE_GRAPHICS, GX_BGMODE_3, GX_BG0_AS_2D );
201 
202     GX_SetVisiblePlane( GX_PLANEMASK_BG3 );
203     G2_SetBG3Priority( 0 );
204     G2_BG3Mosaic( FALSE );
205 
206     G2_SetBG3ControlDCBmp( GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x00000 );
207 
208     MI_CpuClearFast( draw_buffer, WIDTH * HEIGHT * sizeof(u16) );
209     GX_LoadBG3Bmp( draw_buffer, 0, WIDTH * HEIGHT * sizeof(u16) );
210 
211     // Create heap
212     nstart = OS_InitAlloc( OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1 );
213     OS_SetMainArenaLo( nstart );
214 
215     handle = OS_CreateHeap( OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi() );
216     if (handle < 0)
217     {
218         OS_Panic("ARM9: Fail to create heap...\n");
219     }
220     handle = OS_SetCurrentHeap( OS_ARENA_MAIN, handle );
221 
222     // TCL initialization
223     // 32-byte alignment necessary
224     pTableBuf = OS_Alloc( TCL_GetTableBufferSize() );
225     pWorkBuf = OS_Alloc( TCL_GetWorkBufferSize() );
226     if( pTableBuf == NULL || pWorkBuf == NULL )
227     {
228         OS_Panic("Cannot allocate memory!");
229     }
230 
231     result = TCL_LoadTable( &accessor,
232                             pTableBuf,
233                             TCL_GetTableBufferSize(),
234                             pWorkBuf,
235                             TCL_GetWorkBufferSize(),
236                             &fs_result );
237 
238 #if 1
239 
240     // End the following processes when loading of the management file fails
241 
242     switch ( result )
243     {
244       case TCL_RESULT_SUCCESS: break; // Success
245       case TCL_RESULT_ERROR_EXIST_OTHER_FILE:
246       case TCL_RESULT_ERROR_ALREADY_MANAGED:
247         // Error indicating no obstacle to getting a photo
248         OS_TPrintf("failed TCL_LoadTable : %d\n", result );
249         break;
250       default:
251         // For other errors, prompt Nintendo DSi camera startup and end the process
252         //OS_TPrintf ("appropriate text here")
253 
254         OS_Panic("failed TCL_LoadTable : %d\n", result );
255         break;
256     }
257 
258 #else
259 
260     // Try recovering if loading of the management file failed
261 
262     switch( result )
263     {
264     case TCL_RESULT_SUCCESS: break; // Success
265     case TCL_RESULT_ERROR_EXIST_OTHER_FILE:
266     case TCL_RESULT_ERROR_ALREADY_MANAGED:
267         // Error indicating no obstacle to getting a photo
268         OS_TPrintf("failed TCL_LoadTable : %d\n", result );
269         break;
270     default:
271         OS_TPrintf("failed TCL_LoadTable : %d\n", result );
272 
273         // The management file is recreated because read processing cannot be carried out
274         result = TCL_CreateTable( &accessor,
275                                   pTableBuf,
276                                   TCL_GetTableBufferSize(),
277                                   pWorkBuf,
278                                   TCL_GetWorkBufferSize(),
279                                   &fs_result );
280 
281         if( result != TCL_RESULT_SUCCESS )
282         {
283             OS_Panic("failed TCL_CreateTable : %d\n", result );
284         }
285         break;
286     }
287 
288 #endif
289 
290     // Initialize SearchObject
291     TCL_InitSearchObject( &search_obj, TCL_SEARCH_CONDITION_PICTURE );
292 
293     // How many photos in all?
294     num_pict = TCL_GetNumPictures( &accessor, &search_obj );
295 
296     // Sort the table as conditions indicate
297     TCL_SortTable( &accessor,  sort_type );
298 
299     Print();
300 
301     DEMOStartDisplay();
302 
303     // Updates text display
304     UpdateScreen();
305 
306     while (1)
307     {
308         // Reading pad information and controls
309         DEMOReadKey();
310 
311         if( num_pict != 0 && DEMO_IS_TRIG( PAD_BUTTON_A | PAD_BUTTON_B | PAD_BUTTON_R ) )
312         {
313             BOOL success_flag = FALSE;
314 
315             // Display thumbnails when the B Button is pressed
316             BOOL thumbnail_flag = DEMO_IS_TRIG( PAD_BUTTON_B );
317 
318             BOOL delete_flag = DEMO_IS_TRIG( PAD_BUTTON_R );
319 
320             const TCLPictureInfo* pPicInfo = NULL;
321             const TCLMakerNote* pMakerNote = NULL;
322 
323             MI_CpuClear( pict_path, TCL_PATH_LEN );
324 
325             if( search )
326             {
327                 do
328                 {
329                     draw_id = search_obj.startIdx;
330 
331                     // Get photo information
332                     result = TCL_SearchNextPictureInfo( &accessor,
333                                                         &pPicInfo,
334                                                         &search_obj );
335 
336                     if( result == TCL_RESULT_ERROR_NO_FIND_PICTURE )
337                     {
338                         // Initialize SearchObject as one full search has been completed
339                         TCL_InitSearchObject( &search_obj, search_obj.condition );
340                         OS_TPrintf("finished TCL_SearchNextPicturePath\n" );
341                     }
342                 } while( result == TCL_RESULT_ERROR_NO_FIND_PICTURE );
343             }
344             else
345             {
346                 result = TCL_SearchPictureInfoByIndex( &accessor,
347                                                        &pPicInfo,
348                                                        &search_obj,
349                                                        draw_id );
350             }
351 
352             if( result != TCL_RESULT_SUCCESS )
353             {
354                 OS_TPrintf("failed TCL_Search* : %d\n", result );
355             }
356             else if( delete_flag )
357             {
358                 TCLPictureInfo* pGetPicInfo = NULL;
359                 FSResult result;
360 
361                 // For the test, get the picture's path and then get TCLPictureInfo again.
362                 ( void ) TCL_PrintPicturePath( pict_path, TCL_PATH_LEN, pPicInfo );
363                 if(TCL_GetPictureInfoFromPath( &accessor, &pGetPicInfo, (const char*)pict_path, (u32)STD_StrLen(pict_path) ) == FALSE)
364                 {
365                     OS_TPrintf("failed TCL_PrintPictureInfo\n");
366                 }
367                 else
368                 {
369                     // Allow picture data to be deleted only if it was created by one of your game titles.
370                     // You may also restrict this to only items created by this application.
371                     if(TCL_DeletePicture(&accessor, pGetPicInfo, &result) != TCL_RESULT_SUCCESS)
372                         OS_TPrintf("failed TCL_DeletePicture\n");
373 
374                     search_obj.condition = TCL_SEARCH_CONDITION_PICTURE;
375                     sort_type = TCL_SORT_TYPE_DATE;
376 
377                     switch( condition_id )
378                     {
379                     case 0: break;
380                     case 1:
381                         search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_1;
382                         sort_type = TCL_SORT_TYPE_FAVORITE_1;
383                         break;
384                     case 2:
385                         search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_2;
386                         sort_type = TCL_SORT_TYPE_FAVORITE_2;
387                         break;
388                     case 3:
389                         search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_3;
390                         sort_type = TCL_SORT_TYPE_FAVORITE_3;
391                         break;
392                     case 4:
393                         search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_ALL;
394                         sort_type = TCL_SORT_TYPE_FAVORITE_ALL;
395                         break;
396                     }
397 
398                     if( search ) TCL_InitSearchObject( &search_obj, search_obj.condition );
399                     num_pict = TCL_GetNumPictures( &accessor, &search_obj );
400                     TCL_SortTable( &accessor, sort_type );
401                     draw_id = 0;
402 
403                     Print();
404                 }
405             }
406             else
407             {
408                 FSFile file;
409                 u32 size;
410                 s32 read_size;
411                 s16 width, height;
412                 TCLResult decodeResult;
413                 u32 decodeOptiion;
414 
415                 // JPEG buffer
416                 u8*  pJpegBuf = NULL;
417                 u16* pDecodeTmpBuf = NULL;
418 
419                 if( thumbnail_flag )
420                 {
421                     width  = SSP_JPEG_THUMBNAIL_WIDTH;
422                     height = SSP_JPEG_THUMBNAIL_HEIGHT;
423                     decodeOptiion = SSP_JPEG_THUMBNAIL | SSP_JPEG_RGB555;
424                 }
425                 else
426                 {
427                     width  = TCL_JPEG_WIDTH;
428                     height = TCL_JPEG_HEIGHT;
429                     decodeOptiion = SSP_JPEG_RGB555;
430                 }
431 
432                 // Get the photo path
433                 ( void ) TCL_PrintPicturePath( pict_path, TCL_PATH_LEN, pPicInfo );
434 
435                 // Get photo
436                 FS_InitFile( &file );
437                 if( FS_OpenFileEx( &file, pict_path, FS_FILEMODE_R ) )
438                 {
439                     pJpegBuf = (u8*)OS_Alloc( TCL_MAX_JPEG_SIZE );
440 
441                     // Allocate the necessary memory for whether it is a normal photograph or a thumbnail
442                     pDecodeTmpBuf = (u16*)OS_Alloc( width * height * sizeof(u16) );
443 
444                     if( pJpegBuf == NULL || pDecodeTmpBuf == NULL )
445                     {
446                         OS_Panic("Cannot allocate memory!");
447                     }
448 
449                     size = FS_GetFileLength( &file );
450                     read_size = FS_ReadFile( &file, pJpegBuf, (s32)size );
451 
452                     if( read_size > 0 )
453                     {
454                         // JPEG decoding
455                         decodeResult = TCL_DecodePicture( pJpegBuf,
456                                                           size,
457                                                           (u8*)pDecodeTmpBuf,
458                                                           width, height,
459                                                           decodeOptiion );
460 
461                         if( decodeResult == TCL_RESULT_SUCCESS )
462                         {
463                             // Get manufacturer's notes
464                             pMakerNote = ( TCLMakerNote* ) SSP_GetJpegDecoderMakerNoteAddrEx( SSP_MAKERNOTE_PHOTO );
465 
466                             // Display if image type is same
467                             if( TCL_IsSameImageType( pPicInfo, pMakerNote ) != FALSE )
468                             {
469                                 MI_CpuClearFast( draw_buffer, WIDTH * HEIGHT * sizeof(u16) );
470 
471                                 // Shrink to image size
472                                 DownSampling( pDecodeTmpBuf, width, height,
473                                               draw_buffer, WIDTH, HEIGHT );
474 
475                                 success_flag = TRUE;
476                             }
477                             else OS_TPrintf("Not Same Image Type\n");
478                         }
479                         else OS_TPrintf("failed JPEG Decode %d\n", decodeResult);
480                     }
481                     else OS_TPrintf("failed FS_ReadFile\n");
482 
483                     ( void ) FS_CloseFile( &file );
484 
485                     OS_Free( pJpegBuf );
486                     OS_Free( pDecodeTmpBuf );
487                 }
488                 else OS_TPrintf("failed FS_Open\n");
489             }
490 
491             if( !success_flag ) MI_CpuClearFast( draw_buffer, WIDTH * HEIGHT * sizeof(u16) );
492             DC_FlushRange( draw_buffer, WIDTH * HEIGHT * sizeof(u16) );
493 
494             Print();
495         }
496         else if( DEMO_IS_TRIG( PAD_BUTTON_X ) )
497         {
498             // Modify search conditions
499             if( ++condition_id > 4 ) condition_id = 0;
500 
501             search_obj.condition = TCL_SEARCH_CONDITION_PICTURE;
502             sort_type = TCL_SORT_TYPE_DATE;
503 
504             switch( condition_id )
505             {
506             case 0: break;
507             case 1:
508                 search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_1;
509                 sort_type = TCL_SORT_TYPE_FAVORITE_1;
510                 break;
511             case 2:
512                 search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_2;
513                 sort_type = TCL_SORT_TYPE_FAVORITE_2;
514                 break;
515             case 3:
516                 search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_3;
517                 sort_type = TCL_SORT_TYPE_FAVORITE_3;
518                 break;
519             case 4:
520                 search_obj.condition |= TCL_SEARCH_CONDITION_FAVORITE_ALL;
521                 sort_type = TCL_SORT_TYPE_FAVORITE_ALL;
522                 break;
523             }
524 
525             if( search ) TCL_InitSearchObject( &search_obj, search_obj.condition );
526             num_pict = TCL_GetNumPictures( &accessor, &search_obj );
527             TCL_SortTable( &accessor, sort_type );
528             draw_id = 0;
529 
530             Print();
531         }
532         else if( DEMO_IS_TRIG( PAD_BUTTON_Y ) )
533         {
534             // Modify search method
535             search ^= 1;
536             draw_id = 0;
537 
538             if( search ) TCL_InitSearchObject( &search_obj, search_obj.condition );
539             Print();
540         }
541         else if( num_pict != 0 && !search )
542         {
543             // Modify ID of displayed photo
544             if( DEMO_IS_TRIG( PAD_KEY_RIGHT ) )
545             {
546                 if( ++draw_id >= num_pict ) draw_id = 0;
547                 Print();
548             }
549             else if( DEMO_IS_TRIG( PAD_KEY_LEFT ) )
550             {
551                 if( --draw_id < 0 ) draw_id = num_pict - 1;
552                 Print();
553             }
554         }
555 
556         OS_WaitVBlankIntr();
557 
558         // Updates text display
559         UpdateScreen();
560 
561         GX_LoadBG3Bmp( draw_buffer, 0, WIDTH * HEIGHT * sizeof(u16) );
562     }
563 
564     OS_Free( pTableBuf );
565     OS_Free( pWorkBuf );
566 
567     OS_Terminate();
568 }
569