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