1 /*---------------------------------------------------------------------------*
2 Project: Viewer for BMP file
3 File: viewer.c
4
5 Copyright 1998, 1999 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 $Log: viewer.c,v $
14 Revision 1.4 2008/06/26 02:46:26 urata
15 Removed MPAL defines
16
17 Revision 1.3 2006/03/06 09:59:00 kawaset
18 Eliminated warnings.
19
20 Revision 1.2 2006/02/20 04:13:13 mitu
21 Changed include path from dolphin/ to revolution/.
22
23 Revision 1.1 2005/12/16 08:34:25 urata
24 Initial check-in.
25
26
27 15 2001/11/08 17:02 Hashida
28 Added PAL support.
29
30 14 2001/05/10 3:18p Carl
31 Added button control feature, XFB load feature.
32
33 13 2000/06/07 5:39p Tian
34 Updated idle function API
35
36 12 2000/05/15 1:37p Hashida
37 Changed maximum vi height from 482 to 480 for NTSC and MPAL.
38
39 11 2000/03/01 5:29p Hashida
40 Modified so that it doesn't have to include vicommon.h.
41
42 10 2000/03/01 5:17p Hashida
43 Removed tga file view.
44
45 9 2000/03/01 1:14p Hashida
46 Renamed dirent->filename to name.
47
48 8 2000/02/28 7:26p Hashida
49 Added to set viHeight for assertion.
50
51 7 2000/02/04 11:43a Hashida
52 Changed to do the read and conversion as background.
53 Support for single field interlaced images.
54
55 6 2000/01/28 9:02p Hashida
56 Added VIFlush.
57 Added code to safely change modes.
58 Changed because VI APIs doesn't set registers immediately anymore.
59
60 5 2000/01/26 3:56p Hashida
61 Changed to use VIConfigure.
62
63 4 2000/01/21 2:15a Hashida
64 Make it work for non-interlace mode
65
66 3 2000/01/20 2:57p Hashida
67 Make it work for NTSC_NONINTERLACE
68
69 2 2000/01/17 10:18a Hashida
70 Removed a warning.
71
72 1 2000/01/15 3:04a Hashida
73 Initial revision
74
75 1 2000/01/13 12:17p Hashida
76 Initial revision
77
78 $NoKeywords: $
79 *---------------------------------------------------------------------------*/
80
81 /*
82 * Open files under /pictures and show it on screen
83 */
84 #include <revolution.h>
85 #include <string.h>
86 #include <ctype.h>
87 #include "bmp.h"
88
89 // for X frame buffer
90 static u8* xfb1;
91 static u8* xfb2;
92
93 u32 first=1; // used to bring up first image immediately
94 u32 mode=0; // flip mode; 0 = timer, 1 = button control
95
96 #if defined(NTSC)
97
98 #define XFB_WD 720
99 #define XFB_HT 480
100
101 #define SCREEN_WD 720
102 #ifndef NON_INTERLACE
103 #define SCREEN_HT 480
104 #else // #ifndef NON_INTERLACE
105 #define SCREEN_HT 240
106 #endif // #ifndef NON_INTERLACE
107
108 #else // #if defined(NTSC)
109
110 #define XFB_WD 720
111 #define XFB_HT 574
112
113 #define SCREEN_WD 720
114 #ifndef NON_INTERLACE
115 #define SCREEN_HT 574
116 #else // #ifndef NON_INTERLACE
117 #define SCREEN_HT 287
118 #endif // #ifndef NON_INTERLACE
119
120 #endif // #if defined(NTSC)
121
122
123 #define IS_BMP(p) (! mystrcmp(p, "bmp"))
124 #define IS_BMA(p) (! mystrcmp(p, "bma"))
125 #define IS_XFB(p) (! mystrcmp(p, "xfb"))
126
127 static void MyOSInit( void );
128 static void printOneLevel(char* pathName);
129
130 #define TYPE_INIT 0
131 #define TYPE_BMP 1
132 #define TYPE_BMA 2
133 #define TYPE_XFB 3
134
135 u8 Stack[4096];
136
137 typedef struct
138 {
139 // input
140 u8* image; // processed image
141 DVDDir* dir;
142
143 // output
144 u32 height; // image height
145 u32 width; // image width
146 u8* image2; // processed image2 (for INT-SF mode)
147 u32 imageType;
148 BOOL end;
149 } idleParam_s;
150
151 struct dirs_t
152 {
153 struct dirs_t* next; // must be first
154 DVDDirEntry dirEntry;
155 };
156
157 typedef struct dirs_t dirs;
158
159
160 // case insensitive strcmp
mystrcmp(char * str1,char * str2)161 static int mystrcmp(char* str1, char* str2)
162 {
163 while(*str1)
164 {
165 if (tolower(*str1) != tolower(*str2))
166 return (tolower(*str1) - tolower(*str2));
167 str1++;
168 str2++;
169 }
170
171 return 0;
172 }
173
174
readConvertBmp(char * fileName,u8 * dest,u32 * width,u32 * height)175 static void readConvertBmp(char* fileName, u8* dest, u32* width, u32* height)
176 {
177 DVDFileInfo finfo;
178 u32 length;
179 u8* buf;
180 bmpInfo_s bInfo;
181
182 if (FALSE == DVDOpen(fileName, &finfo))
183 {
184 OSReport("Can't open file %s\n", fileName);
185 return;
186 }
187
188 length = DVDGetLength(&finfo);
189
190 OSReport("F %9d %s\n", length, fileName);
191
192 if( NULL == (buf = OSAlloc(OSRoundUp32B(length))) )
193 {
194 OSReport("Alloc failed. Exit\n");
195 return;
196 }
197
198 if (OSRoundUp32B(length) !=
199 DVDRead(&finfo, buf, (s32)OSRoundUp32B(length), 0))
200 {
201 OSReport("Error occurred when reading %s\n", fileName);
202 OSHalt("");
203 }
204
205 if (FALSE == openBmp(&bInfo, buf))
206 {
207 OSReport("Failed to analyze %s as a bmp file\n",
208 fileName);
209 OSHalt("");
210 }
211
212 OSReport(" bfOffBits: %d\n", bInfo.bfOffBits);
213 OSReport(" width: %d\n", bInfo.width);
214 OSReport(" height: %d\n", bInfo.height);
215 OSReport(" biBitCount: %d\n", bInfo.biBitCount);
216 OSReport(" biCompression: %d\n", bInfo.biCompression);
217 OSReport(" biSizeImage: %d\n", bInfo.biSizeImage);
218 OSReport(" paletteOff: %d\n", bInfo.paletteOff);
219
220 if (FALSE == bmpToYCbCr(&bInfo, buf, dest))
221 {
222 OSReport("Failed to convert bmp to YCbCr\n");
223 OSHalt("");
224 }
225
226 *width = (bInfo.width + 15) / 16 * 16;
227 *height = (bInfo.height + 1) / 2 * 2;
228
229 DVDClose(&finfo);
230 OSFree(buf);
231 }
232
233
getRenderMode(GXRenderModeObj * rm,u16 dispPosX,u16 dispPosY,u16 dispSizeX,VITVMode tvMode,u16 xfbSizeX,u16 xfbSizeY,VIXFBMode xfbMode)234 static void getRenderMode(GXRenderModeObj* rm, u16 dispPosX, u16 dispPosY,
235 u16 dispSizeX, VITVMode tvMode,
236 u16 xfbSizeX, u16 xfbSizeY,
237 VIXFBMode xfbMode)
238 {
239 rm->viTVmode = tvMode;
240 rm->fbWidth = xfbSizeX;
241 rm->xfbHeight = xfbSizeY;
242 rm->viXOrigin = dispPosX;
243 rm->viYOrigin = dispPosY;
244 rm->viWidth = dispSizeX;
245 rm->xFBmode = xfbMode;
246
247 rm->viHeight = (u16)((xfbMode == VI_XFBMODE_DF)? xfbSizeY : (u16)(xfbSizeY*2));
248 }
249
idle(void * param)250 static void idle(void* param)
251 {
252 DVDDirEntry dirent;
253 idleParam_s* ip;
254 u32 width;
255 u32 height;
256 char* p;
257
258 ip = (idleParam_s*)param;
259 ip->end = FALSE;
260 ip->imageType = 0;
261
262 do
263 {
264 if (FALSE == DVDReadDir(ip->dir, &dirent))
265 {
266 ip->end = TRUE;
267 return;
268 }
269
270 p = dirent.name;
271 while(*p++ != '.')
272 ;
273
274 if (IS_BMP(p))
275 ip->imageType = TYPE_BMP;
276 #ifndef NON_INTERLACE
277 else if (IS_BMA(p))
278 ip->imageType = TYPE_BMA;
279 #endif
280 else if (IS_XFB(p))
281 ip->imageType = TYPE_XFB;
282
283 } while ( (ip->imageType == 0) || (dirent.isDir) );
284
285 if (ip->imageType == TYPE_BMP)
286 {
287 readConvertBmp(dirent.name, ip->image, &width, &height);
288 }
289 else if (ip->imageType == TYPE_BMA)
290 {
291 u32 firstLength;
292 u32 fnlength;
293 char* fn;
294
295 readConvertBmp(dirent.name, ip->image, &width, &height);
296
297 firstLength = width * height * 2;
298
299 // read "bmb"
300 fnlength = strlen(dirent.name) + 1;
301 if( NULL == (fn = OSAlloc(OSRoundUp32B(fnlength))) )
302 {
303 OSReport("Alloc failed. Exit\n");
304 return;
305 }
306
307 strcpy(fn, dirent.name);
308 fn[fnlength - 2] = 'b';
309
310 OSReport("fn is %s\n", fn);
311
312 readConvertBmp(fn, ip->image + firstLength, &width, &height);
313
314 ip->image2 = ip->image + firstLength;
315 }
316 else if (ip->imageType == TYPE_XFB)
317 {
318 DVDFileInfo finfo;
319 u32 length;
320
321 // read file into ip->image
322
323 if (FALSE == DVDOpen(dirent.name, &finfo))
324 {
325 OSReport("Can't open file %s\n", dirent.name);
326 return;
327 }
328
329 length = DVDGetLength(&finfo);
330
331 OSReport("F %9d %s\n", length, dirent.name);
332
333 width = 640;
334 height = length / (640*2);
335
336 if (OSRoundUp32B(length) !=
337 DVDRead(&finfo, ip->image, (s32)OSRoundUp32B(length), 0))
338 {
339 OSReport("Error occurred when reading %s\n", dirent.name);
340 OSHalt("");
341 }
342 DVDClose(&finfo);
343 }
344
345 if (height > SCREEN_HT)
346 height = SCREEN_HT;
347
348 if (ip->imageType != TYPE_BMA)
349 DCStoreRange((void*)ip->image, width * height * 2);
350 else // store caches for two images
351 DCStoreRange((void*)ip->image, width * height * 2 * 2);
352
353 ip->height = height;
354 ip->width = width;
355 }
356
printOneLevel(char * pathName)357 static void printOneLevel(char* pathName)
358 {
359 DVDDir dir;
360 dirs* start = (dirs*)NULL;
361 dirs* curr;
362 char path[256];
363 static u32 imageReady = 0;
364 static u8* xfb;
365 static u32 frame = 0;
366 static u32 prevCount;
367 static u32 width;
368 static u32 height;
369 static u32 isBma;
370 GXRenderModeObj rm;
371 OSThread* background;
372 idleParam_s ip;
373 u32 startProcessNext;
374
375 PADStatus pstat[PAD_MAX_CONTROLLERS];
376 u32 plast=0;
377
378 #pragma unused(pathName)
379
380 curr = (dirs*)&start;
381
382 if (FALSE == DVDOpenDir(".", &dir))
383 {
384 OSReport("Can't open dir %s\n", path);
385 return;
386 }
387
388 xfb = (frame)? xfb2 : xfb1;
389
390 startProcessNext = 1;
391 while(1)
392 {
393 VIWaitForRetrace();
394
395 if (startProcessNext)
396 {
397 ip.image = (xfb == xfb1)? xfb2 : xfb1;
398 ip.dir = &dir;
399 background = OSSetIdleFunction(idle, (void*)&ip,
400 Stack + sizeof Stack,
401 sizeof Stack);
402 startProcessNext = 0;
403 }
404
405 PADRead(pstat);
406
407 if ((pstat[0].button & PAD_BUTTON_B) &&
408 !(plast & PAD_BUTTON_B))
409 {
410 mode = 1 - mode;
411 if (mode)
412 OSReport("Button A control mode\n");
413 else
414 OSReport("Timer control mode\n");
415 }
416
417 if (OSGetIdleFunction() == 0)
418 {
419 if (ip.end)
420 return;
421
422 if ( (mode && (pstat[0].button & PAD_BUTTON_A) &&
423 !(plast & PAD_BUTTON_A)) || first ||
424 (!mode && (VIGetRetraceCount() - prevCount >= 300)) )
425 {
426 first = 0;
427
428 prevCount = VIGetRetraceCount();
429
430 frame ^= 1;
431 xfb = (frame)? xfb2 : xfb1;
432
433 width = ip.width;
434 height = ip.height;
435 isBma = (ip.imageType == TYPE_BMA);
436
437 #ifndef NON_INTERLACE
438 if (isBma)
439 getRenderMode(&rm, (u16)((SCREEN_WD - width) / 2),
440 (u16)((SCREEN_HT - height * 2) / 2),
441 (u16)width,
442 #ifdef PAL
443 VI_TVMODE_PAL_INT,
444 #else
445 VI_TVMODE_NTSC_INT,
446 #endif
447 (u16)width, (u16)height,
448 VI_XFBMODE_SF);
449 else
450 getRenderMode(&rm, (u16)((SCREEN_WD - width) / 2),
451 (u16)((SCREEN_HT - height) / 2),
452 (u16)width,
453 #ifdef PAL
454 VI_TVMODE_PAL_INT,
455 #else
456 VI_TVMODE_NTSC_INT,
457 #endif
458 (u16)width, (u16)height,
459 VI_XFBMODE_DF);
460 #else
461 getRenderMode(&rm, (u16)((SCREEN_WD - width) / 2),
462 (u16)((SCREEN_HT - height) / 2),
463 (u16)width,
464 #ifdef PAL
465 VI_TVMODE_PAL_DS,
466 #else
467 VI_TVMODE_NTSC_DS,
468 #endif
469 (u16)width, (u16)height,
470 VI_XFBMODE_SF);
471 #endif
472
473 VIConfigure(&rm);
474
475 startProcessNext = 1;
476 imageReady = 1; // holds 1 after the first image gets ready
477 }
478
479 }
480
481 plast = pstat[0].button;
482
483 if (isBma)
484 {
485 u8* xfbSF;
486
487 xfbSF = xfb;
488
489 if (VIGetNextField() == VI_FIELD_ABOVE)
490 xfbSF = xfb;
491 else
492 xfbSF = xfb + width * height * 2;
493
494 VISetNextFrameBuffer(xfbSF);
495 }
496 else
497 VISetNextFrameBuffer(xfb);
498
499 if (imageReady)
500 {
501 VISetBlack(FALSE);
502 }
503
504 VIFlush();
505
506 } // while(1)
507
508 } // void printOneLevel(char*)
509
510
main(void)511 void main(void)
512 {
513 MyOSInit();
514
515 PADInit();
516
517 OSReport("Image File Viewer\n\n");
518 OSReport("Press Button B to change flip mode\n\n");
519
520 if (FALSE == DVDChangeDir("pictures"))
521 {
522 OSReport("Can't change dir to pictures\n");
523 return;
524 }
525
526 while(1)
527 printOneLevel(".");
528
529 OSHalt("End of program");
530
531 // NOT REACHED HERE
532 }
533
534
535 /*---------------------------------------------------------------------------*
536 Name: MyOSInit
537
538 Description: Initialize the operating system.
539 Create a heap so we can use OSAlloc().
540
541 Arguments: None.
542
543 Returns: None.
544 *---------------------------------------------------------------------------*/
MyOSInit(void)545 static void MyOSInit ( void )
546 {
547 void* arenaLo;
548 void* arenaHi;
549
550 OSInit();
551 DVDInit();
552 VIInit();
553
554 arenaLo = OSGetArenaLo();
555 arenaHi = OSGetArenaHi();
556
557 // allocate memory for frame buffer here.
558 xfb1 = (u8*)OSRoundUp32B(arenaLo);
559 xfb2 = (u8*)OSRoundUp32B(arenaLo)
560 + XFB_HT * XFB_WD * VI_DISPLAY_PIX_SZ;
561 arenaLo = (void*)(xfb1 + XFB_HT * XFB_WD * VI_DISPLAY_PIX_SZ * 2);
562 OSSetArenaLo(arenaLo);
563
564 // OSInitAlloc should only ever be invoked once.
565 arenaLo = OSInitAlloc(arenaLo, arenaHi, 1); // 1 heap
566 OSSetArenaLo(arenaLo);
567
568 // The boundaries given to OSCreateHeap should be 32B aligned
569 OSSetCurrentHeap(OSCreateHeap((void*)OSRoundUp32B(arenaLo),
570 (void*)OSRoundDown32B(arenaHi)));
571 // From here on out, OSAlloc and OSFree behave like malloc and free
572 // respectively
573
574 OSSetArenaLo(arenaLo = arenaHi);
575
576 return;
577 }
578