source: trunk/src/opengl/glide/swlibs/fxmisc/fximg.c

Last change on this file was 2887, checked in by sandervl, 26 years ago

Created swlibs dir

File size: 50.1 KB
Line 
1/*
2** THIS SOFTWARE IS SUBJECT TO COPYRIGHT PROTECTION AND IS OFFERED ONLY
3** PURSUANT TO THE 3DFX GLIDE GENERAL PUBLIC LICENSE. THERE IS NO RIGHT
4** TO USE THE GLIDE TRADEMARK WITHOUT PRIOR WRITTEN PERMISSION OF 3DFX
5** INTERACTIVE, INC. A COPY OF THIS LICENSE MAY BE OBTAINED FROM THE
6** DISTRIBUTOR OR BY CONTACTING 3DFX INTERACTIVE INC(info@3dfx.com).
7** THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
8** EXPRESSED OR IMPLIED. SEE THE 3DFX GLIDE GENERAL PUBLIC LICENSE FOR A
9** FULL TEXT OF THE NON-WARRANTY PROVISIONS.
10**
11** USE, DUPLICATION OR DISCLOSURE BY THE GOVERNMENT IS SUBJECT TO
12** RESTRICTIONS AS SET FORTH IN SUBDIVISION (C)(1)(II) OF THE RIGHTS IN
13** TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013,
14** AND/OR IN SIMILAR OR SUCCESSOR CLAUSES IN THE FAR, DOD OR NASA FAR
15** SUPPLEMENT. UNPUBLISHED RIGHTS RESERVED UNDER THE COPYRIGHT LAWS OF
16** THE UNITED STATES.
17**
18** COPYRIGHT 3DFX INTERACTIVE, INC. 1999, ALL RIGHTS RESERVED
19**
20** $Revision: 1.1 $
21** $Date: 2000-02-25 00:33:51 $
22**
23*/
24
25
26#include <stdlib.h>
27#include <stdio.h>
28#include <string.h>
29#include <time.h>
30#include "3dfx.h"
31#include "fximg.h"
32#include "fxos.h"
33
34/*
35** PRIVATE GLOBAL DATA
36*/
37
38char *imgErrorString = "No error.";
39
40/*
41** PRIVATE UTILITY FUNCTIONS
42*/
43
44/* _fixStream
45**
46** Summary: UNPUBLISHED - change mode for input / output streams so that
47** they are are in binary mode for dos apps.
48*/
49#if defined( __DOS__ ) || defined( WIN32 )
50/*
51** On dos-compatible platforms, iostreams must be set to binary( untranslated )
52** mode
53*/
54#include <fcntl.h>
55#include <io.h>
56void _fixStream( FILE *stream )
57{
58 setmode( fileno( stream ), O_BINARY );
59}
60#else
61/*
62** Otherwise do nothing
63*/
64#define _fixStream( X ) X = X
65#endif
66
67
68/* _imgStrUpr
69**
70** Summary: UNPUBLISHED - upper case the provided string in place.
71** Provided because strupr isn't provided in all clib implementations.
72*/
73void _imgStrUpr( char *str )
74{
75 FxU32 index;
76 for ( index = 0; index < strlen( str ); index++ )
77 {
78 if ( str[index] >= 'a' && str[index] <= 'z' )
79 {
80 str[index] -= 'a' - 'A';
81 }
82 }
83}
84
85/* _imgIsLittleEndian
86**
87** UNPUBLISHED - returns FXTRUE if the host architecture
88** stores memory in little endian format
89*/
90FxBool _imgIsLittleEndian( void )
91{
92 unsigned long x = 0x0000FFFF;
93 return( *((char *)&x)?FXTRUE:FXFALSE );
94}
95
96/* _imgTxDecodeColorFormat
97**
98** UNPUBLISHED - returns the integer color format give in a tdf color format
99**
100*/
101imgTxColorFormat _imgTxDecodeColorFormat( char * String )
102{
103 if(!strcmp(String,"true") ||
104 !strcmp(String,"TRUE"))
105 return txColorTrue;
106 else if(!strcmp(String,"i8") ||
107 !strcmp(String,"I8"))
108 return txColorI_8;
109 else if(!strcmp(String,"a8") ||
110 !strcmp(String,"A8"))
111 return txColorA_8;
112 else if(!strcmp(String,"ai44") ||
113 !strcmp(String,"AI44"))
114 return txColorAI_44;
115 else if(!strcmp(String,"yiq") ||
116 !strcmp(String,"YIQ"))
117 return txColorYIQ;
118 else if(!strcmp(String,"rgb332") ||
119 !strcmp(String,"RGB332"))
120 return txColorRGB_332;
121 else if(!strcmp(String,"rgb565") ||
122 !strcmp(String,"RGB565"))
123 return txColorRGB_565;
124 else if(!strcmp(String,"argb8332") ||
125 !strcmp(String,"ARGB8332"))
126 return txColorARGB_8332;
127 else if(!strcmp(String,"argb1555") ||
128 !strcmp(String,"ARGB1555"))
129 return txColorARGB_1555;
130 else if(!strcmp(String,"ayiq8422") ||
131 !strcmp(String,"AYIQ8422"))
132 return txColorAYIQ_8422;
133 else if(!strcmp(String,"argb4444") ||
134 !strcmp(String,"ARGB4444"))
135 return txColorARGB_4444;
136 else if(!strcmp(String,"ai88") ||
137 !strcmp(String,"AI88"))
138 return txColorAI_88;
139 else if(!strcmp(String,"argb8888") ||
140 !strcmp(String,"ARGB8888"))
141 return txColorARGB_8888;
142 else
143 return txColorUnknown;
144}
145
146/* _imgMSBReplicate
147**
148** Summary: UNPUBLISHED - Replicates the msb's of the input value to fill
149** in an 8-bit color channel;
150*/
151#define _imgMSBReplicate( COLOR, LEFT_SHIFT, RIGHT_SHIFT ) (COLOR << LEFT_SHIFT) | (COLOR >> RIGHT_SHIFT)
152
153/* _imgGuessType
154**
155** Summary: UNPUBLISHED - read the first word of an image file stream
156** determine the file type.
157*/
158FxBool _imgGuessType( FILE *stream, ImgType *type )
159{
160 FxU32 cookie = 0;
161 int c;
162
163 if ( stream == NULL )
164 {
165 imgErrorString = "Bad File Handle";
166 return FXFALSE;
167 }
168
169 if ( ( c = fgetc( stream ) ) == EOF )
170 {
171 imgErrorString = "Unexpected end of file";
172 return FXFALSE;
173 }
174
175 cookie = (c << 8);
176
177 if ( ( c = fgetc( stream ) ) == EOF )
178 {
179 imgErrorString = "Unexpected end of file";
180 return FXFALSE;
181 }
182
183 cookie |= c;
184
185 switch( cookie )
186 {
187 case ('P' << 8) | '9': // SBI
188 *type = IMG_SBI;
189 break;
190 case ('P' << 8) | '6': // PPM
191 *type = IMG_P6;
192 break;
193 case ('3' << 8) | 'd': // 3df
194 case ('3' << 8) | 'D': // 3df
195 *type = IMG_3DF;
196 break;
197 case 0xDA01:
198 *type = IMG_RGT;
199 break;
200 case 'EL':
201 cookie = 0;
202 if ( ( c = fgetc( stream ) ) == EOF )
203 {
204 imgErrorString = "Unexpected end of file";
205 return FXFALSE;
206 }
207 cookie = (cookie << 8) | c;
208 if ( ( c = fgetc( stream ) ) == EOF )
209 {
210 imgErrorString = "Unexpected end of file";
211 return FXFALSE;
212 }
213 cookie = (cookie << 8) | c;
214 if (cookie == 'RS')
215 *type = IMG_SRLE;
216 break;
217 default: // Might Be TGA
218 if ( ( c = fgetc( stream ) ) == EOF )
219 {
220 imgErrorString = "Unexpected end of file";
221 return FXFALSE;
222 }
223 cookie <<= 8;
224 cookie |= c;
225
226 if ( (cookie & 0x00FFFF) == 0x0002 ) *type = IMG_TGA32;
227 else *type = IMG_UNKNOWN;
228 break;
229 }
230 return FXTRUE;
231}
232
233
234/* _imgReadSbiHeader
235**
236** Summary: UNPUBLISHED - read header and fill in header info
237*/
238FxBool _imgReadSbiHeader( FILE *stream, SbiInfo *info )
239{
240 char buffer[256];
241 FxU32 state = 1;
242 FxBool done = FXFALSE;
243
244 if ( stream == NULL )
245 {
246 imgErrorString = "Bad file handle.";
247 return FXFALSE;
248 }
249
250 while( !done && fgets( buffer, 256, stream ) )
251 {
252 char *token;
253
254 if ( buffer[0] == '#' ) continue;
255 for (token = strtok( buffer, " \t\n\r" );
256 token != NULL;
257 token = strtok( NULL, " \t\n\r" ))
258 switch( state )
259 {
260 case 1: // YOrigin
261 if ( token[1] == '+' ) info->yOrigin = 1;
262 else if ( token[1] == '-' ) info->yOrigin = 0;
263 else
264 {
265 imgErrorString = "Error parsing y-origin.";
266 return FXFALSE;
267 }
268 state++;
269 break;
270 case 2: // Width
271 info->width = atoi( token );
272 state++;
273 break;
274 case 3: // height
275 info->height = atoi( token );
276 state++;
277 break;
278 case 4: // 'R'
279 if ( token[0] != 'R' )
280 {
281 imgErrorString = "Error parsing R color channel.";
282 return FXFALSE;
283 }
284 state++;
285 break;
286 case 5: // Red Channel
287 info->redBits = atoi( token );
288 state++;
289 break;
290 case 6: // 'G'
291 if ( token[0] != 'G' )
292 {
293 imgErrorString = "Error parsing G color channel.";
294 return FXFALSE;
295 }
296 state++;
297 break;
298 case 7: // Green Channel
299 info->greenBits = atoi( token );
300 state++;
301 break;
302 case 8: // 'B'
303 if ( token[0] != 'B' )
304 {
305 imgErrorString = "Error parsing B color channel.";
306 return FXFALSE;
307 }
308 state++;
309 break;
310 case 9: // Blue Channel
311 info->blueBits = atoi( token );
312 done = FXTRUE;
313 state++;
314 break;
315 default:
316 break;
317 }
318 }
319
320 if ( state < 10 )
321 {
322 imgErrorString = "Read error before end of header.";
323 return FXFALSE;
324 }
325
326 info->sizeInBytes = info->width * info->height * 4;
327
328 return FXTRUE;
329}
330
331/* _imgReadP6Header
332**
333** Summary: UNPUBLISHED - read header and fill in header info
334*/
335FxBool _imgReadP6Header( FILE *stream, P6Info *info )
336{
337 char buffer[256];
338 FxU32 state = 1;
339 FxBool done = FXFALSE;
340
341 if ( stream == NULL )
342 {
343 imgErrorString = "Bad file handle.";
344 return FXFALSE;
345 }
346
347 while( !done && fgets( buffer, 256, stream ) )
348 {
349 char *token;
350
351 if ( buffer[0] == '#' ) continue;
352 for (token = strtok( buffer, " \t\n\r" );
353 token != NULL;
354 token = strtok( NULL, " \t\n\r" ))
355 switch( state )
356 {
357 case 1: // Width
358 info->width = atoi( token );
359 state++;
360 break;
361 case 2: // height
362 info->height = atoi( token );
363 state++;
364 break;
365 case 3: // Color Depth
366 info->colorChannelMax = atoi( token );
367 if ( info->colorChannelMax != 255 )
368 {
369 imgErrorString = "Unsupported max color value. Must be 255.";
370 return FXFALSE;
371 }
372 state++;
373 done = FXTRUE;
374 break;
375 default:
376 imgErrorString = "General parse error reading header.";
377 return FXFALSE;
378 break;
379 }
380 }
381
382 if ( state < 4 )
383 {
384 imgErrorString = "Read error before end of header.";
385 return FXFALSE;
386 }
387
388 info->sizeInBytes = info->width * info->height * 4;
389
390 return FXTRUE;
391}
392
393/* _imgReadTGAHeader
394**
395** Summary: UNPUBLISHED - read header and fill in header info
396*/
397FxBool _imgReadTGAHeader( FILE *stream, TgaInfo *info )
398{
399 struct {
400 FxU8 CMapStartLo;
401 FxU8 CMapStartHi;
402 FxU8 CMapLengthLo;
403 FxU8 CMapLengthHi;
404 FxU8 CMapDepth;
405 FxU8 XOffSetLo;
406 FxU8 XOffSetHi;
407 FxU8 YOffSetLo;
408 FxU8 YOffSetHi;
409 FxU8 WidthLo;
410 FxU8 WidthHi;
411 FxU8 HeightLo;
412 FxU8 HeightHi;
413 FxU8 PixelDepth;
414 FxU8 ImageDescriptor;
415 } partialTGAHeader;
416
417 if ( stream == NULL )
418 {
419 imgErrorString = "Bad file handle.";
420 return FXFALSE;
421 }
422
423 if ( fread( &partialTGAHeader, 1, 15, stream ) != 15 )
424 {
425 imgErrorString = "Unexpected end of file.";
426 return FXFALSE;
427 }
428
429 info->width = partialTGAHeader.WidthHi << 8 | partialTGAHeader.WidthLo;
430 info->height = partialTGAHeader.HeightHi << 8 | partialTGAHeader.HeightLo;
431 info->yOrigin = 0x01 & partialTGAHeader.ImageDescriptor;
432 info->sizeInBytes = info->width * info->height * 4;
433
434 return FXTRUE;
435}
436
437/* _imgWriteTGAHeader
438**
439** Summary: UNPUBLISHED - write header
440*/
441FxBool _imgWriteTGAHeader( FILE *stream, const TgaInfo *info ) {
442
443 struct {
444 FxU8 IDLength;
445 FxU8 ColorMapType;
446 FxU8 ImgType;
447 FxU8 CMapStartLo;
448 FxU8 CMapStartHi;
449 FxU8 CMapLengthLo;
450 FxU8 CMapLengthHi;
451 FxU8 CMapDepth;
452 FxU8 XOffSetLo;
453 FxU8 XOffSetHi;
454 FxU8 YOffSetLo;
455 FxU8 YOffSetHi;
456 FxU8 WidthLo;
457 FxU8 WidthHi;
458 FxU8 HeightLo;
459 FxU8 HeightHi;
460 FxU8 PixelDepth;
461 FxU8 ImageDescriptor;
462 } tgaHeader;
463
464 if ( stream == NULL )
465 {
466 imgErrorString = "Bad file handle.";
467 return FXFALSE;
468 }
469
470 tgaHeader.IDLength = 0;
471 tgaHeader.ColorMapType = 0;
472 tgaHeader.ImgType = 0x2;
473 tgaHeader.CMapStartLo = 0;
474 tgaHeader.CMapStartHi = 0;
475 tgaHeader.CMapLengthLo = 0;
476 tgaHeader.CMapLengthHi = 0;
477 tgaHeader.CMapDepth = 0;
478 tgaHeader.XOffSetLo = 0;
479 tgaHeader.XOffSetHi = 0;
480 tgaHeader.YOffSetLo = 0;
481 tgaHeader.YOffSetHi = 0;
482 tgaHeader.WidthHi = (FxU8)(info->width >> 8) & 0xFF;
483 tgaHeader.WidthLo = (FxU8)info->width & 0xFF;
484 tgaHeader.HeightHi = (FxU8)(info->height >> 8) & 0xFF;
485 tgaHeader.HeightLo = (FxU8)info->height & 0xFF;
486 tgaHeader.PixelDepth = 32;
487 tgaHeader.ImageDescriptor = info->yOrigin ? ( 0x1 ) : ( 0x0 );
488
489
490 if ( fwrite( &tgaHeader, 1, 18, stream ) != 18 ) {
491 imgErrorString = "TGA Header stream write error.";
492 return FXFALSE;
493 }
494
495 return FXTRUE;
496}
497
498/* _imgReadRGTHeader
499**
500** Summary: UNPUBLISHED - read header and fill in header info
501*/
502FxBool _imgReadRGTHeader( FILE *stream, RgtInfo *info )
503{
504 const FxU16 ITYPE_RLE = 0x01;
505 const FxU16 ITYPE_NCC = 0x02;
506 const FxU16 ITYPE_BGR = 0x04;
507 const FxU16 ITYPE_RGT = 0x08;
508
509 struct {
510 FxU8 typeLo;
511 FxU8 typeHi;
512 FxU8 dimLo;
513 FxU8 dimHi;
514 FxU8 sizeXLo;
515 FxU8 sizeXHi;
516 FxU8 sizeYLo;
517 FxU8 sizeYHi;
518 FxU8 sizeZLo;
519 FxU8 sizeZHigh;
520 } partialRGTHeader;
521
522 if ( stream == NULL )
523 {
524 imgErrorString = "Bad file handle.";
525 return FXFALSE;
526 }
527
528 if ( fread( &partialRGTHeader, 1, 10, stream ) != 10 )
529 {
530 imgErrorString = "Unexpected end of file.";
531 return FXFALSE;
532 }
533
534 info->width = partialRGTHeader.sizeXHi << 8 | partialRGTHeader.sizeXLo;
535 info->height = partialRGTHeader.sizeYHi << 8 | partialRGTHeader.sizeYLo;
536 info->sizeInBytes = info->width * info->height * 4;
537 info->rle = partialRGTHeader.typeHi & ITYPE_RLE;
538 info->bgr = partialRGTHeader.typeHi & ITYPE_BGR;
539 info->rgb = partialRGTHeader.typeHi & ITYPE_RGT;
540 info->ncc = partialRGTHeader.typeHi & ITYPE_NCC;
541
542 return FXTRUE;
543}
544
545/* _imgRead3DFHeader
546**
547** Summary: UNPUBLISHED - read header and fill in header info
548*/
549FxBool _imgRead3DFHeader( FILE *stream, TdfInfo *info ) {
550 FxBool done = FXFALSE;
551 char buffer[256];
552 FxU32 state = 0;
553 float tempFloat;
554
555 if ( stream == NULL ) {
556 imgErrorString = "Bad file handle.";
557 return FXFALSE;
558 }
559
560 while( !done && fgets( buffer, 256, stream ) ) {
561 char *token;
562
563 if ( buffer[0] == '#' ) continue;
564 for (token = strtok( buffer, " \t\n\r" );
565 token != NULL;
566 token = strtok( NULL, " \t\n\r" ))
567 switch( state ) {
568 case 0: // 'f'
569 if ( token[0] != 'f' ) {
570 imgErrorString = "Bad cookie( \"3df\" ).";
571 return FXFALSE;
572 }
573 state++;
574 break;
575 case 1: // Version
576 if ( sscanf( token,
577 "v%f",
578 &tempFloat ) == 0 ) {
579 imgErrorString = "Couldn't determine version of 3DF file.";
580 return FXFALSE;
581 }
582 info->version = tempFloat;
583 state++;
584 break;
585 case 2: // Color Format
586 if ( (info->colorFormat = _imgTxDecodeColorFormat( token ))==txColorUnknown ) {
587 imgErrorString = "3DF Unknown color format.";
588 return FXFALSE;
589 }
590 state++;
591 break;
592 case 3: // "lod"
593 if ( strcmp( token, "lod" ) ) {
594 imgErrorString = "Bad lod range identifier.";
595 return FXFALSE;
596 }
597 state++;
598 break;
599 case 4: // "range:"
600 if ( strcmp( token, "range:" ) ) {
601 imgErrorString = "Bad lod range identifier.";
602 return FXFALSE;
603 }
604 state++;
605 break;
606 case 5: // lodMin
607 info->lodMin = atoi( token );
608 state++;
609 break;
610 case 6: // lodMax
611 info->lodMax = atoi( token );
612 state++;
613 break;
614 case 7: // "aspect"
615 if ( strcmp( token , "aspect" ) ) {
616 imgErrorString = "Bad aspect ratio identifier.";
617 return FXFALSE;
618 }
619 state++;
620 break;
621 case 8: // "ratio:"
622 if ( strcmp( token, "ratio:" ) ) {
623 imgErrorString = "Bad aspect ratio identifier.";
624 return FXFALSE;
625 }
626 state++;
627 break;
628 case 9: // aspectWidth
629 info->aspectWidth = atoi( token );
630 state++;
631 break;
632 case 10: // aspectHeight
633 info->aspectHeight = atoi( token );
634 done = FXTRUE;
635 break;
636 default:
637 imgErrorString = "General parse error reading header.";
638 return FXFALSE;
639 break;
640 }
641 }
642
643 if ( state != 10 ) {
644 imgErrorString = "Read error before end of header.";
645 return FXFALSE;
646 }
647
648 if ( info->lodMin > info->lodMax ) {
649 imgErrorString = "3DF Format Error. lodMin must be <= lodMax.";
650 return FXFALSE;
651 }
652
653 // Calculate Width and Height with All Mipmaps
654 if ( info->aspectWidth < info->aspectHeight ) {
655 FxU32 lod;
656 info->height = info->lodMax;
657 info->width = info->lodMax / info->aspectHeight;
658 for ( lod = info->lodMax / 2; lod >= info->lodMin; lod /= 2 ) {
659 info->width += lod > 1 ? lod / info->aspectHeight : 1;
660 }
661 } else {
662 FxU32 lod;
663 info->width = info->lodMax;
664 info->height = info->lodMax / info->aspectWidth;
665 for ( lod = info->lodMax / 2; lod >= info->lodMin; lod /= 2 ) {
666 info->height += lod > 1 ? lod / info->aspectWidth : 1;
667 }
668 }
669
670 info->sizeInBytes = info->width * info->height * 4;
671
672 return FXTRUE;
673}
674
675
676/* _imgRead3DFData
677**
678** Summary: UNPUBLISHED - read data from a 3DF file.
679** when the texuslib has an owner, and it
680** is reliably maintained, this will be
681** converted over to calls to the library.
682*/
683/* Read in data from a 3DF file. */
684FxBool _imgRead3DFData( FILE *stream, const TdfInfo *info, ImgData *data )
685{
686 FxBool doVerticalDisplay;
687 ImgData *destPtr, *destOrigin;
688 FxU32 xBound, yBound;
689 FxU32 lod;
690
691 struct {
692 FxU8 yRGB[16];
693 FxI16 iRGB[4][3];
694 FxI16 qRGB[4][3];
695 } imgYIQTable;
696
697 if ( stream == NULL ) {
698 imgErrorString = "Bad file handle.";
699 return FXFALSE;
700 }
701
702 /* Read in the YIQ decompression table, if necessary. */
703 if( (info->colorFormat == txColorYIQ) || (info->colorFormat == txColorAYIQ_8422) ) {
704 FxU32 index;
705 for( index=0; index < 16; index++ ) {
706 getc( stream );
707 imgYIQTable.yRGB[index] = (FxU8) getc( stream );
708 }
709 for( index=0; index < 4;index++ ) {
710 FxI16 msb = (FxI16) ( getc( stream ) & 0xFF ) << 8;
711 FxI16 lsb = (FxI16) ( getc( stream ) & 0xFF );
712 imgYIQTable.iRGB[index][0] = msb | lsb;
713 msb = (FxI16) ( getc( stream ) & 0xFF ) << 8;
714 lsb = (FxI16) ( getc( stream ) & 0xFF );
715 imgYIQTable.iRGB[index][1] = msb | lsb;
716 msb = (FxI16) ( getc( stream ) & 0xFF ) << 8;
717 lsb = (FxI16) ( getc( stream ) & 0xFF );
718 imgYIQTable.iRGB[index][2] = msb | lsb;
719 }
720 for( index=0; index < 4;index++ ) {
721 FxI16 msb = (FxI16) ( getc( stream ) & 0xFF ) << 8;
722 FxI16 lsb = (FxI16) ( getc( stream ) & 0xFF );
723 imgYIQTable.qRGB[index][0] = msb | lsb;
724 msb = (FxI16) ( getc( stream ) & 0xFF ) << 8;
725 lsb = (FxI16) ( getc( stream ) & 0xFF );
726 imgYIQTable.qRGB[index][1] = msb | lsb;
727 msb = (FxI16) ( getc( stream ) & 0xFF ) << 8;
728 lsb = (FxI16) ( getc( stream ) & 0xFF );
729 imgYIQTable.qRGB[index][2] = msb | lsb;
730 }
731 if ( feof( stream ) ) {
732 imgErrorString = "Unexpected end of file reading YIQ Table.";
733 return FXFALSE;
734 }
735 }
736
737 /* Read in the Image One mipmap level at a time */
738
739 doVerticalDisplay = (info->aspectHeight <= info->aspectWidth ) ? FXTRUE : FXFALSE;
740
741 destPtr = destOrigin = data;
742 if ( doVerticalDisplay ) {
743 yBound = info->lodMax / info->aspectWidth;
744 xBound = info->lodMax;
745 } else {
746 yBound = info->lodMax;
747 xBound = info->lodMax / info->aspectHeight;
748 }
749
750 for ( lod = info->lodMax; lod >= info->lodMin; lod /= 2 ) {
751 FxU32 x, y;
752 switch( info->colorFormat ) {
753 case txColorTrue: /* True color, 24-bit color (RGB) + 8-bit alpha. */
754 case txColorARGB_8888: /* 8-bits of Alpha, Red, Green, and Blue. Not yet supported. */
755 for ( y = 0; y < yBound; y++ ) {
756 for( x = 0; x < xBound; x++ ) {
757 FxU8 r, g, b, a;
758 a = getc( stream );
759 r = getc( stream );
760 g = getc( stream );
761 b = getc( stream );
762 *destPtr++ = b;
763 *destPtr++ = g;
764 *destPtr++ = r;
765 *destPtr++ = a;
766 }
767 destPtr += (info->width - xBound) * 4;
768 }
769 break;
770 case txColorI_8: /* 8-bit intensity. */
771 /* For this, an intensity is calculated by averaging the */
772 /* RG and B channels, and placed back into all three channels */
773 /* so that outputs of TGA's and PPM's will look okay. */
774 for ( y = 0; y < yBound; y++ ) {
775 for ( x = 0; x < xBound; x++ ) {
776 FxU8 intensity;
777 intensity = getc( stream );
778 *destPtr++ = intensity;
779 *destPtr++ = intensity;
780 *destPtr++ = intensity;
781 *destPtr++ = intensity;
782 }
783 destPtr += (info->width - xBound) * 4;
784 }
785 break;
786 case txColorA_8: /* 8-bit alpha. */
787 for ( y = 0; y < yBound; y++ ) {
788 for ( x = 0; x < xBound; x++ ) {
789 FxU8 alpha;
790 alpha = getc( stream );
791 *destPtr++ = alpha;
792 *destPtr++ = alpha;
793 *destPtr++ = alpha;
794 *destPtr++ = alpha;
795 }
796 destPtr += (info->width - xBound) * 4;
797 }
798 break;
799 case txColorARGB_1555:
800 for ( y = 0; y < yBound; y++ ) {
801 for ( x = 0; x < xBound; x++ ) {
802 FxU16 color;
803 FxU8 a,r,g,b;
804 color = ( 0xFF & getc( stream ) ) << 8;
805 color |= ( 0xFF & getc( stream ) );
806 a = ( color >> 15 ) & 0x01;
807 r = ( color >> 10 ) & 0x1F;
808 g = ( color >> 5 ) & 0x1F;
809 b = color & 0x1F;
810
811 *destPtr++ = _imgMSBReplicate( b, 3, 2);
812 *destPtr++ = _imgMSBReplicate( g, 3, 2);
813 *destPtr++ = _imgMSBReplicate( r, 3, 2);
814 *destPtr++ = a ? 0x0 : 0xFF;
815 }
816 destPtr += (info->width - xBound) * 4;
817 }
818 break;
819 case txColorARGB_4444:
820 for ( y = 0; y < yBound; y++ ) {
821 for ( x = 0; x < xBound; x++ ) {
822 FxU16 color;
823 FxU8 a,r,g,b;
824 color = ( 0xFF & getc( stream ) ) << 8;
825 color |= ( 0xFF & getc( stream ) );
826 a = ( color >> 12 ) & 0x0F;
827 r = ( color >> 8 ) & 0x0F;
828 g = ( color >> 4 ) & 0x0F;
829 b = ( color >> 0 ) & 0x0F;
830
831 *destPtr++ = _imgMSBReplicate( b, 4, 0 );
832 *destPtr++ = _imgMSBReplicate( g, 4, 0 );
833 *destPtr++ = _imgMSBReplicate( r, 4, 0 );
834 *destPtr++ = _imgMSBReplicate( a, 4, 0 );
835 }
836 destPtr += (info->width - xBound) * 4;
837 }
838 break;
839 case txColorRGB_565:
840 for ( y = 0; y < yBound; y++ ) {
841 for ( x = 0; x < xBound; x++ ) {
842 FxU16 color;
843 FxU8 r,g,b;
844 color = ( 0xFF & getc( stream ) ) << 8;
845 color |= ( 0xFF & getc( stream ) );
846 r = ( color >> 11 ) & 0x1F;
847 g = ( color >> 5 ) & 0x3F;
848 b = ( color >> 0 ) & 0x1F;
849
850 *destPtr++ = _imgMSBReplicate( b, 3, 2 );
851 *destPtr++ = _imgMSBReplicate( g, 2, 4);
852 *destPtr++ = _imgMSBReplicate( r, 3, 2);
853 *destPtr++ = 0x0; // Alpha
854 }
855 destPtr += (info->width - xBound) * 4;
856 }
857 break;
858 case txColorAI_44:
859 default:
860 imgErrorString = "Unhandled 3df color format.";
861 return FXFALSE;
862 }
863 if ( doVerticalDisplay ) {
864 destPtr = destOrigin + ( yBound * info->width * 4 );
865 } else {
866 destPtr = destOrigin + (xBound * 4);
867 }
868 destOrigin = destPtr;
869 if ( yBound > 1 ) yBound /= 2;
870 if ( xBound > 1 ) xBound /= 2;
871 }
872
873#if 0
874 case txColorAI_44: /* 4-bit alpha, 4-bit intensity. */
875 /* For this conversion, the alpha is shredded to four bits, */
876 /* the intensities are averaged and then shredded into four */
877 /* bits, and then the intensity is placed into all three */
878 /* color channels. */
879 /* Loop through the entire image. */
880 for(index=0;index<((Image->Width)*(Image->Height));index++)
881 {
882 /* Read in both alpha and intensity. */
883 fread(&tmpChar,1,1,ImageFile);
884 tmpColor = tmpChar;
885
886 /* Extract the alpha portion. */
887 Image->AlphaChannel[index] = (tmpColor & 0xf0);
888
889 /* Extract the color portion. */
890 Image->RedChannel[index] =
891 Image->GreenChannel[index] =
892 Image->BlueChannel[index] = ((tmpColor & 0x0f)<<4);
893 }
894
895 break;
896
897 case txColorYIQ: /* Narrow-channel, compressed color. */
898 /* Get a copy of the YIQ table so that it doesn't have to be dereferenced
899 every single time it's used. */
900 YIQTable = Image->YIQTable;
901
902 /* Loop through the entire image. */
903 for(index=0;index<((Image->Width)*(Image->Height));index++)
904 {
905 /* Get the YIQ pixel into a temporary value. */
906 fread(&tmpChar,1,1,ImageFile);
907 tmpColor = (tmpChar & 0xff);
908
909 /* Rip out YIQ from that pixel. */
910 y = tmpColor >> 4;
911 i = (tmpColor >> 2) & 0x3;
912 q = (tmpColor >> 0) & 0x3;
913
914 /* Convert the colors back out. */
915 r = YIQTable.yRGB[y] + YIQTable.iRGB[i][0] + YIQTable.qRGB[q][0];
916 g = YIQTable.yRGB[y] + YIQTable.iRGB[i][1] + YIQTable.qRGB[q][1];
917 b = YIQTable.yRGB[y] + YIQTable.iRGB[i][2] + YIQTable.qRGB[q][2];
918
919 /* Clamp the values. */
920 if( r < 0 ) r = 0; else if ( r > 0xff ) r = 0xff;
921 if( g < 0 ) g = 0; else if ( g > 0xff ) g = 0xff;
922 if( b < 0 ) b = 0; else if ( b > 0xff ) b = 0xff;
923
924 /* Stick the values into the image structure. */
925 Image->RedChannel[index] = (unsigned char)r;
926 Image->GreenChannel[index] = (unsigned char)g;
927 Image->BlueChannel[index] = (unsigned char)b;
928
929 /* Make up something for alpha. */
930 Image->AlphaChannel[index] = 0xff;
931 }
932
933 break;
934
935 case txColorRGB_332: /* 3-bit red, 3-bit green, 2-bit blue. */
936 /* Shred bits off of the color channels, and tip the alpha */
937 /* channel up to 0xff. */
938 /* Loop through the entire image. */
939 for(index=0;index<((Image->Width)*(Image->Height));index++)
940 {
941 /* Combine the whole color into one byte. */
942 fread(&tmpChar,1,1,ImageFile);
943
944 /* Rip the byte apart into colors. */
945 Image->RedChannel[index] = (tmpChar & 0xe0);
946 Image->GreenChannel[index] = (tmpChar & 0x1c)<<3;
947 Image->BlueChannel[index] = (tmpChar & 0x03)<<6;
948
949 /* Make up something for alpha. */
950 Image->AlphaChannel[index] = 0xff;
951 }
952
953 break;
954 case txColorRGB_565: /* 5-bit red, 6-bit green, 5-bit blue. */
955 /* Shred bits off of the color channels, and tip the alpha */
956 /* channel up to 0xff. */
957 /* Loop through the entire image. */
958 for(index=0;index<((Image->Width)*(Image->Height));index++)
959 {
960 /* Read both bytes into a tmp color. */
961 fread(&tmpChar,1,1,ImageFile);
962 tmpColor = (tmpChar & 0xff)<<8;
963 fread(&tmpChar,1,1,ImageFile);
964 tmpColor |= (tmpChar & 0xff);
965
966 /* Rip the short apart into colors. */
967 Image->RedChannel[index] = (tmpColor & 0xf800)>>8;
968 Image->GreenChannel[index] = (tmpColor & 0x07e0)>>3;
969 Image->BlueChannel[index] = (tmpColor & 0x001f)<<3;
970
971 /* Make up something for alpha. */
972 Image->AlphaChannel[index] = 0xff;
973 }
974
975 break;
976 case txColorARGB_8332: /* 8-bit alpha, 3-bit red, 3-bit green, 2-bit blue. */
977 /* Nothing but shredding. */
978 /* Loop through the entire image. */
979 for(index=0;index<((Image->Width)*(Image->Height));index++)
980 {
981 /* Read both bytes into a tmp color. */
982 fread(&tmpChar,1,1,ImageFile);
983 tmpColor = (tmpChar & 0xff)<<8;
984 fread(&tmpChar,1,1,ImageFile);
985 tmpColor |= (tmpChar & 0xff);
986
987 /* Read out the alpha. */
988 Image->AlphaChannel[index] = ((tmpColor & 0xff00)>>8);
989
990 /* Rip the byte apart into colors. */
991 Image->RedChannel[index] = (tmpColor & 0xe0);
992 Image->GreenChannel[index] = (tmpColor & 0x1c)<<3;
993 Image->BlueChannel[index] = (tmpColor & 0x03)<<6;
994 }
995
996 break;
997 case txColorARGB_1555: /* 1-bit alpha, 5-bit red, 5-bit green, 5-bit blue. */
998 /* Nothing but shredding. */
999 /* Loop through the entire image. */
1000 for(index=0;index<((Image->Width)*(Image->Height));index++)
1001 {
1002 /* Read both bytes into a tmp color. */
1003 fread(&tmpChar,1,1,ImageFile);
1004 tmpColor = (tmpChar & 0xff)<<8;
1005 fread(&tmpChar,1,1,ImageFile);
1006 tmpColor |= (tmpChar & 0xff);
1007
1008 /* Rip the color apart. */
1009 Image->AlphaChannel[index] = (tmpColor & 0x8000)>>8;
1010 Image->RedChannel[index] = (tmpColor & 0x7c00)>>7;
1011 Image->GreenChannel[index] = (tmpColor & 0x03e0)>>2;
1012 Image->BlueChannel[index] = (tmpColor & 0x001f)<<3;
1013 }
1014
1015 break;
1016
1017 case txColorAYIQ_8422: /* 8-bit alpha + narrow-channel compressed color. */
1018 /* Get a copy of the YIQ table so that it doesn't have to be dereferenced
1019 every single time it's used. */
1020 YIQTable = Image->YIQTable;
1021
1022 /* Loop through the entire image. */
1023 for(index=0;index<((Image->Width)*(Image->Height));index++)
1024 {
1025 /* Get alpha from the first byte. */
1026 fread(&tmpChar,1,1,ImageFile);
1027 (Image->AlphaChannel[index]) = (unsigned char)tmpChar;
1028
1029 /* Get the YIQ pixel into a temporary value. */
1030 fread(&tmpChar,1,1,ImageFile);
1031 tmpColor = (tmpChar & 0xff);
1032
1033 /* Rip out YIQ from that pixel. */
1034 y = tmpColor >> 4;
1035 i = (tmpColor >> 2) & 0x3;
1036 q = (tmpColor >> 0) & 0x3;
1037
1038 /* Convert the colors back out. */
1039 r = YIQTable.yRGB[y] + YIQTable.iRGB[i][0] + YIQTable.qRGB[q][0];
1040 g = YIQTable.yRGB[y] + YIQTable.iRGB[i][1] + YIQTable.qRGB[q][1];
1041 b = YIQTable.yRGB[y] + YIQTable.iRGB[i][2] + YIQTable.qRGB[q][2];
1042
1043 /* Clamp the values. */
1044 if( r < 0 ) r = 0; else if ( r > 0xff ) r = 0xff;
1045 if( g < 0 ) g = 0; else if ( g > 0xff ) g = 0xff;
1046 if( b < 0 ) b = 0; else if ( b > 0xff ) b = 0xff;
1047
1048 /* Stick the values into the image structure. */
1049 Image->RedChannel[index] = (unsigned char)r;
1050 Image->GreenChannel[index] = (unsigned char)g;
1051 Image->BlueChannel[index] = (unsigned char)b;
1052
1053 /* Make up something for alpha. */
1054 Image->AlphaChannel[index] = 0xff;
1055 }
1056
1057 break;
1058 case txColorARGB_4444: /* 4-bit alpha, 4-bit red, 4-bit green, 4-bit blue. */
1059 /* Nothing but shredding. */
1060 /* Loop through the entire image. */
1061 for(index=0;index<((Image->Width)*(Image->Height));index++)
1062 {
1063 /* Read both bytes into a tmp color. */
1064 fread(&tmpChar,1,1,ImageFile);
1065 tmpColor = (tmpChar & 0xff)<<8;
1066 fread(&tmpChar,1,1,ImageFile);
1067 tmpColor |= (tmpChar & 0xff);
1068
1069 /* Rip that color apart. */
1070 Image->AlphaChannel[index] = (tmpColor & 0xf000)>>8;
1071 Image->RedChannel[index] = (tmpColor & 0x0f00)>>4;
1072 Image->GreenChannel[index] = (tmpColor & 0x00f0);
1073 Image->BlueChannel[index] = (tmpColor & 0x000f)<<4;
1074 }
1075
1076 break;
1077 case txColorAI_88: /* 8-bit alpha, 8-bit itensity. */
1078 /* Same as txColorAI_44, minus the shredding. */
1079 /* Loop through the entire image. */
1080 for(index=0;index<((Image->Width)*(Image->Height));index++)
1081 {
1082 /* Grab alpha from the first byte. */
1083 fread(&tmpChar,1,1,ImageFile);
1084 (Image->AlphaChannel[index]) = (tmpChar & 0xff);
1085
1086 /* And grab the intensity from the second byte. */
1087 fread(&tmpChar,1,1,ImageFile);
1088 Image->RedChannel[index] =
1089 Image->GreenChannel[index] =
1090 Image->BlueChannel[index] = (tmpChar & 0xff);
1091 }
1092
1093 break;
1094 }
1095 }
1096
1097 /* Close the file. */
1098 fclose(ImageFile);
1099#endif
1100
1101 return FXTRUE;
1102}
1103
1104
1105
1106/* _imgReadTGAData
1107**
1108** Summary: UNPUBLISHED - read data from a TGA file
1109** TGA is BGRA
1110*/
1111FxBool _imgReadTGAData( FILE *stream, const TgaInfo *info, ImgData *data )
1112{
1113 FxI32 y, y0, y1, dy, scanlineLength;
1114 const int bytesPerPixel = 4;
1115
1116 if ( stream == NULL )
1117 {
1118 imgErrorString = "Bad file handle.";
1119 return FXFALSE;
1120 }
1121
1122 if ( info->height == 0 ) return FXTRUE;
1123
1124 if ( info->yOrigin == 0 )
1125 {
1126 dy = -1;
1127 y0 = info->height - 1;
1128 y1 = -1;
1129 }
1130 else
1131 {
1132 dy = 1;
1133 y0 = 0;
1134 y1 = info->height;
1135 }
1136
1137 scanlineLength = info->width * bytesPerPixel;
1138
1139 for ( y = y0; y != y1; y += dy )
1140 {
1141 if ( fread( data + scanlineLength * y, 1, scanlineLength, stream ) !=
1142 (FxU32) scanlineLength )
1143 {
1144 imgErrorString = "Unexpected end of file";
1145 return FXFALSE;
1146 }
1147 }
1148
1149 return FXTRUE;
1150}
1151
1152
1153
1154/* _imgWriteTGAData
1155**
1156** Summary: UNPUBLISHED - write data out to a tga
1157** TGA is BGRA
1158*/
1159FxBool _imgWriteTGAData( FILE *stream, const TgaInfo *info, const ImgData *data )
1160{
1161 FxI32 y, scanlineLength;
1162 const int bytesPerPixel = 4;
1163
1164 if ( stream == NULL )
1165 {
1166 imgErrorString = "Bad file handle.";
1167 return FXFALSE;
1168 }
1169
1170 scanlineLength = info->width * bytesPerPixel;
1171
1172 for ( y = info->height - 1; y >= 0; y-- )
1173 {
1174 if ( fwrite( data + scanlineLength * y, 1, scanlineLength, stream ) !=
1175 (FxU32) scanlineLength )
1176 {
1177 imgErrorString = "TGA stream write error.";
1178 return FXFALSE;
1179 }
1180 }
1181
1182 return FXTRUE;
1183}
1184
1185/* _imgReadRGTData
1186**
1187** Summary: UNPUBLISHED - read data from an RGT file ( rgt's are bottom up )
1188** RGT is RGBA in memory (low byte to high byte), or ABGR in a register
1189*/
1190FxBool _imgReadRGTData( FILE *stream, const RgtInfo *info, ImgData *data )
1191{
1192 FxU32 scanlineSize = info->width * 4;
1193 FxU32 x,y;
1194
1195 if ( stream == NULL ) {
1196 imgErrorString = "Bad file handle.";
1197 return FXFALSE;
1198 }
1199
1200 if ( info->ncc != 0 ) {
1201 imgErrorString = "Compressed RGT's not yet supported.";
1202 return FXFALSE;
1203 }
1204
1205 // load rgt, rgt's are bottom up
1206 for ( y = 0; y < info->height; y++ ) {
1207 ImgData *scanlineBuffer = data + scanlineSize * ( (info->height-1) - y );
1208 if ( fread( scanlineBuffer, 1, scanlineSize, stream ) != scanlineSize ) {
1209 imgErrorString = "Unexpected end of file.";
1210 return FXFALSE;
1211 }
1212 }
1213
1214 if ( info->rgb ) {
1215 fprintf(stderr," (RGB->BGR)"); fflush(stderr);
1216 for ( y = 0; y < info->height; y++ ) {
1217 for ( x = 0; x < info->width; x++ ) {
1218 ImgData swap;
1219 swap = data[2];
1220 data[2] = data[0];
1221 data[0] = swap;
1222 data += 4;
1223 }
1224 }
1225
1226 }
1227
1228 return FXTRUE;
1229}
1230
1231/* _imgReadSbiData
1232**
1233** Summary: UNPUBLISHED - read data from an SBI file
1234*/
1235FxBool _imgReadSbiData( FILE *stream, const SbiInfo *info, ImgData *data )
1236{
1237 FxI32 y, y0, y1, dy;
1238 FxU32 x;
1239 FxU32 rShift, gShift, bShift, rMask, gMask, bMask;
1240 FxU32 rRightShift, rLeftShift;
1241 FxU32 gRightShift, gLeftShift;
1242 FxU32 bRightShift, bLeftShift;
1243 FxU32 scanlineWidth;
1244 ImgData *baseOfData;
1245
1246 if ( stream == NULL )
1247 {
1248 imgErrorString = "Bad file handle.";
1249 return FXFALSE;
1250 }
1251
1252 bShift = 0;
1253 gShift = info->blueBits;
1254 rShift = gShift + info->greenBits;
1255
1256 rMask = (FxU32) ~0;
1257 rMask >>= sizeof( FxU32 ) * 8 - info->redBits;
1258 rLeftShift = 8 - info->redBits;
1259 rRightShift = info->redBits - rLeftShift;
1260
1261 gMask = (FxU32) ~0;
1262 gMask >>= sizeof( FxU32 ) * 8 - info->greenBits;
1263 gLeftShift = 8 - info->greenBits;
1264 gRightShift = info->greenBits - gLeftShift;
1265
1266 bMask = (FxU32) ~0;
1267 bMask >>= sizeof( FxU32 ) * 8 - info->blueBits;
1268 bLeftShift = 8 - info->blueBits;
1269 bRightShift = info->blueBits - bLeftShift;
1270
1271 scanlineWidth = info->width * 4;
1272 baseOfData = data;
1273
1274 if ( info->yOrigin == 0 )
1275 {
1276 y0 = info->height - 1;
1277 y1 = -1;
1278 dy = -1;
1279 }
1280 else
1281 {
1282 y0 = 0;
1283 y1 = info->height;
1284 dy = 1;
1285 }
1286
1287 for( y = y0; y != y1; y += dy )
1288 {
1289 //point data at apropriate scanline
1290 data = baseOfData + y * scanlineWidth;
1291
1292 for ( x = 0; x < info->width; x++ )
1293 {
1294 int r, g, b;
1295 int inchar;
1296 FxU32 color;
1297
1298 color = getc( stream );
1299 if ( (inchar = getc( stream ))==EOF )
1300 {
1301 imgErrorString = "Unexpected end of file.";
1302 return FXFALSE;
1303 }
1304 color |= (inchar << 8);
1305
1306 // Get sig bits
1307 r = (color >> rShift ) & rMask;
1308 g = (color >> gShift ) & gMask;
1309 b = (color >> bShift ) & bMask;
1310
1311 // Expand to 8 bits/color
1312 // Current implementation is only meaningful if
1313 // using more than 4Bits/Channel color precision.....
1314 // Needs to be fixed, but this is much, much faster....
1315 *data++ = _imgMSBReplicate( b, bLeftShift, bRightShift );
1316 *data++ = _imgMSBReplicate( g, gLeftShift, gRightShift );
1317 *data++ = _imgMSBReplicate( r, rLeftShift, rRightShift );
1318 data++; // Blank A
1319 }
1320 }
1321 return FXTRUE;
1322}
1323
1324/* _imgReadP6Data
1325**
1326** Summary: UNPUBLISHED - read data from a PPM
1327** PPM is RGB
1328** Memory format is B - G - R - A
1329*/
1330FxBool _imgReadP6Data( FILE *stream, const P6Info *info, ImgData *data )
1331{
1332 FxU32 numPixels;
1333
1334 numPixels = info->width * info->height;
1335
1336 if ( stream == NULL )
1337 {
1338 imgErrorString = "Bad file handle.";
1339 return FXFALSE;
1340 }
1341
1342 // Read in image data
1343 for( ;numPixels;numPixels-- )
1344 {
1345 int r, g, b;
1346 r = getc( stream );
1347 g = getc( stream );
1348 b = getc( stream );
1349 if ( b == EOF )
1350 {
1351 imgErrorString = "Unexpected end of file.";
1352 return FXFALSE;
1353 }
1354 *data++ = (ImgData)b;
1355 *data++ = (ImgData)g;
1356 *data++ = (ImgData)r;
1357 data++; // A
1358 }
1359
1360 return FXTRUE;
1361}
1362
1363/* _imgReadSRLEHeader
1364**
1365** Summary: UNPUBLISHED - read header and fill in header info
1366** The simple rle format is intended for glide test programs image comparison
1367** The file format is as follows:
1368** 4 bytes file signature
1369** 2 bytes image width
1370** 2 bytes image height
1371** 1 byte image depth
1372** 1 byte compression method (1 for rle compression)
1373** image data
1374**
1375** The image data started with a control byte and followed by pixel data
1376** Each control byte has two parts. Bit 7 (msb) equals to 1 indicates a run,
1377** 0 indicates a literal string. Bit 6 - 0 id the counter. It is zero based.
1378*/
1379FxBool _imgReadSRLEHeader( FILE *stream, SrleInfo *info )
1380{
1381 FxU16 tmp16;
1382 FxU8 tmp8;
1383
1384 if ( stream == NULL )
1385 {
1386 imgErrorString = "Bad file handle.";
1387 return FXFALSE;
1388 }
1389
1390 fread(&tmp16, sizeof(FxU16), 1, stream);
1391 info->width = tmp16;
1392 fread(&tmp16, sizeof(FxU16), 1, stream);
1393 info->height = tmp16;
1394 fread(&tmp8, sizeof(FxU8), 1, stream);
1395 info->pixelsize = tmp8 / 8;
1396 fread(&tmp8 , sizeof(FxU8), 1, stream);
1397 info->c_type = tmp8;
1398
1399 info->sizeInBytes = info->width * info->height * 4;
1400
1401 return FXTRUE;
1402}
1403
1404/* _imgReadSRLE
1405**
1406** Summary: UNPUBLISHED - read data from a simple rle format
1407*/
1408FxBool _imgReadSRLEData( FILE *stream, const SrleInfo *info, ImgData *data )
1409{
1410 int numPixels;
1411 FxU16 color;
1412 FxU8 r,g,b,a;
1413 FxU8 ctl, repeat, run;
1414 FxBool flag;
1415
1416 numPixels = info->width * info->height;
1417
1418 if ( stream == NULL )
1419 {
1420 imgErrorString = "Bad file handle.";
1421 return FXFALSE;
1422 }
1423
1424 while (numPixels) {
1425 ctl = getc( stream );
1426 flag = ctl & 0x80;
1427 run = repeat = (ctl & 0x7f) + 1;
1428 numPixels -= repeat;
1429 while (repeat) {
1430 switch (info->pixelsize)
1431 {
1432 case 2:
1433 if (((flag) && (repeat == run)) || (!flag))
1434 fread(&color,2,1,stream);
1435 r = ( color >> 11 ) & 0x1F;
1436 g = ( color >> 5 ) & 0x3F;
1437 b = ( color >> 0 ) & 0x1F;
1438
1439 *data++ = _imgMSBReplicate( b, 3, 2 );
1440 *data++ = _imgMSBReplicate( g, 2, 4);
1441 *data++ = _imgMSBReplicate( r, 3, 2);
1442 *data++ = 0x0;
1443 break;
1444 case 4:
1445 if (((flag) && (repeat == run)) || (!flag)) {
1446 a = getc( stream );
1447 r = getc( stream );
1448 g = getc( stream );
1449 b = getc( stream );
1450 }
1451 *data++ = b;
1452 *data++ = g;
1453 *data++ = r;
1454 *data++ = a;
1455 break;
1456 }
1457 repeat--;
1458 }
1459 if (numPixels < 0)
1460 return FXFALSE;
1461 }
1462 return FXTRUE;
1463}
1464
1465/* _imgWriteP6Header
1466**
1467** Summary: UNPUBLISHED - write out formatted header for a P6
1468*/
1469FxBool _imgWriteP6Header( FILE *stream, const P6Info *info )
1470{
1471 imgErrorString = "Image write error.";
1472 if ( 0 > fprintf( stream, "P6\n" ) ) return FXFALSE;
1473 if ( 0 > fprintf( stream, "# PPM Comment\n", info->width ) ) return FXFALSE;
1474 if ( 0 > fprintf( stream, "%d ", info->width ) ) return FXFALSE;
1475 if ( 0 > fprintf( stream, "%d\n", info->height ) ) return FXFALSE;
1476 if ( 0 > fprintf( stream, "255\n" ) ) return FXFALSE;
1477 imgErrorString = "No error.";
1478 return FXTRUE;
1479}
1480
1481/* _imgWriteSbiHeader
1482**
1483** Summary: UNPUBLISHED - write out formatted header for an SBI
1484*/
1485FxBool _imgWriteSbiHeader( FILE *stream, const SbiInfo *info )
1486{
1487 imgErrorString = "Image write error.";
1488 if ( 0 > fprintf( stream, "P9\n" ) ) return FXFALSE;
1489 if ( 0 > !fprintf( stream, "Y%c\n", info->yOrigin? '+' : '-' ) ) return FXFALSE;
1490 if ( 0 > !fprintf( stream, "%d ", info->width ) ) return FXFALSE;
1491 if ( 0 > !fprintf( stream, "%d\n", info->height ) ) return FXFALSE;
1492 if ( 0 > !fprintf( stream, "R %d ", info->redBits ) ) return FXFALSE;
1493 if ( 0 > !fprintf( stream, "G %d ", info->greenBits ) ) return FXFALSE;
1494 if ( 0 > !fprintf( stream, "B %d\n", info->blueBits ) ) return FXFALSE;
1495 imgErrorString = "No Error.";
1496 return FXTRUE;
1497}
1498
1499/* _imgWriteP6Data
1500**
1501** Summary: UNPUBLISHED - write P6 image data
1502*/
1503FxBool _imgWriteP6Data( FILE *stream, const P6Info *info, const ImgData *data )
1504{
1505 FxU32 dataSize = info->width * info->height * 4;
1506 const ImgData *dataEnd = data + dataSize;
1507
1508 while( data < dataEnd )
1509 {
1510 ImgData r, g, b;
1511 b = *data++;
1512 g = *data++;
1513 r = *data++;
1514 data++;
1515
1516 putc( r, stream );
1517 putc( g, stream );
1518 if ( putc( b, stream ) == EOF )
1519 {
1520 imgErrorString = "Image write error.";
1521 return FXFALSE;
1522 }
1523 }
1524 return FXTRUE;
1525}
1526
1527/* _imgWriteSbiData
1528**
1529** Summary: UNPUBLISHED - write sbi image data
1530*/
1531FxBool _imgWriteSbiData( FILE *stream, const SbiInfo *info, const ImgData *data )
1532{
1533 // convert each pixel, then write it out as two byte-writes
1534 FxU32 x;
1535 FxU32 y;
1536 FxU32 sbiPixel;
1537
1538 FxI32 scanlineIncrement;
1539
1540 if ( info->yOrigin == 0 ) // Lower
1541 {
1542 scanlineIncrement = (4 * (-(long)info->width)) + 1;
1543 // point at beginning of last SL
1544 data = data + (( info->height - 2 ) * info->width * 4);
1545 }
1546 else // upper
1547 {
1548 scanlineIncrement = 0;
1549 }
1550
1551 imgErrorString = "Image write error.";
1552 for( y = 0; y < info->height; y++ )
1553 {
1554 for( x = 0; x < info->width; x++ )
1555 {
1556 FxU32 r, g, b;
1557 b = *data++ & 0xF8;
1558 g = *data++ & 0xFC;
1559 r = *data++ & 0xF8;
1560 data++;
1561 sbiPixel = (r << 8) | (g << 3) | (b >> 3);
1562
1563 if ( putc( sbiPixel, stream ) == EOF ) return FXFALSE;
1564 if ( putc( sbiPixel >> 8, stream ) == EOF ) return FXFALSE;
1565 }
1566 data += scanlineIncrement;
1567 }
1568 imgErrorString = "No error.";
1569 return FXTRUE;
1570}
1571
1572
1573/* _imgWriteSbiDataWide
1574**
1575** Summary: UNPUBLISHED - write sbi image data
1576*/
1577FxBool _imgWriteSbiDataWide( FILE *stream, const SbiInfo *info, const ImgData *data, FxU32 slWidth )
1578{
1579 // convert each pixel, then write it out as two byte-writes
1580 FxU32 x;
1581 FxU32 y;
1582 FxU32 sbiPixel;
1583
1584 FxI32 scanlineIncrement;
1585
1586 if ( info->yOrigin == 0 ) // Lower
1587 {
1588 scanlineIncrement = (4 * slWidth) + 1;
1589 // point at beginning of last SL
1590 data = data + (( info->height - 2 ) * info->width * 4);
1591 }
1592 else // upper
1593 {
1594 scanlineIncrement = (slWidth * 4) - (4*info->width);
1595 }
1596
1597 imgErrorString = "Image write error.";
1598 for( y = 0; y < info->height; y++ )
1599 {
1600 for( x = 0; x < info->width; x++ )
1601 {
1602 FxU32 r, g, b;
1603 b = *data++ & 0xF8;
1604 g = *data++ & 0xFC;
1605 r = *data++ & 0xF8;
1606 data++;
1607
1608 sbiPixel = (r << 8) | (g << 3) | (b >> 3);
1609
1610 if ( putc( sbiPixel, stream ) == EOF ) return FXFALSE;
1611 if ( putc( sbiPixel >> 8, stream ) == EOF ) return FXFALSE;
1612 }
1613 data += scanlineIncrement;
1614 }
1615 imgErrorString = "No error.";
1616 return FXTRUE;
1617}
1618
1619
1620/*
1621** PUBLIC INTERFACE
1622*/
1623
1624/*
1625** PUBLIC DATA
1626*/
1627
1628const char *imgTypeString[] =
1629{
1630 "UNKNOWN",
1631 "SBI",
1632 "Binary PPM",
1633 "3DF",
1634 "RGT",
1635 "TGA32"
1636};
1637
1638const char *imgTxColorFormatNames[] =
1639{
1640 "unknown",
1641 "true",
1642 "i8",
1643 "a8",
1644 "ai44",
1645 "yiq",
1646 "rgb332",
1647 "rgb565",
1648 "argb8332",
1649 "argb1555",
1650 "ayiq8422",
1651 "argb4444",
1652 "ai88",
1653 "argb8888"
1654};
1655
1656
1657/* imgGetErrorString
1658**
1659** Summary: Get a pointer to the buffer that contains a string describing
1660** the most recent error in the Image Library
1661**
1662** Returns: Point to an error description string. Probably a bad idea to write
1663** to this address as it will likely be a static string.
1664*/
1665const char *imgGetErrorString( void )
1666{
1667 return imgErrorString;
1668}
1669
1670/* imgReadInfo
1671**
1672** Summary: Fill the Info union and return the proper image type
1673**
1674** Parameters: info - pointer to an ImgInfo structure including type
1675** stream - pointer file stream
1676**
1677** Returns: FXTRUE if header read in correctly.
1678** FXFALSE if header not read, error described
1679** in string obtainable by sbiGetErrorString();
1680*/
1681FxBool imgReadInfo( FILE *stream, ImgInfo *info )
1682{
1683 if ( stream == NULL )
1684 {
1685 imgErrorString = "Bad file handle.";
1686 return FXFALSE;
1687 }
1688
1689 _fixStream( stream );
1690 info->any.data = NULL;
1691
1692 // Determine the Type of File and Fill The Appropriate Header Structure
1693 if ( _imgGuessType( stream, &info->any.type ) == FXFALSE ) return FXFALSE;
1694
1695 switch( info->any.type )
1696 {
1697 case IMG_SBI:
1698 return _imgReadSbiHeader( stream, &(info->sbiInfo) );
1699 case IMG_RGT:
1700 return _imgReadRGTHeader( stream, &(info->rgtInfo) );
1701 case IMG_TGA32:
1702 return _imgReadTGAHeader( stream, &(info->tgaInfo) );
1703 case IMG_P6:
1704 return _imgReadP6Header( stream, &(info->p6Info) );
1705 case IMG_3DF:
1706 return _imgRead3DFHeader( stream, &(info->tdfInfo) );
1707 case IMG_SRLE:
1708 return _imgReadSRLEHeader( stream, &(info->srleInfo) );
1709 case IMG_UNKNOWN:
1710 default:
1711 imgErrorString = "Unknown image file format.";
1712 break;
1713 }
1714 return FXFALSE;
1715}
1716
1717/* imgReadData
1718**
1719** Summary: Read all of the image data from an image stream given
1720** that the header has already been read by imgReadInfo.
1721**
1722** Parameters: stream - a readable file stream
1723** info - pointer to filled info structure (except data)
1724** - if data is NULL then we malloc data large enough
1725** Returns: FXTRUE if data was read successfully
1726** FXFALSE if an error occured, reason may be
1727** obtained with imgGetErrorString().
1728*/
1729FxBool imgReadData( FILE *stream, ImgInfo *info )
1730{
1731 if ( stream == NULL )
1732 {
1733 imgErrorString = "Bad file handle.";
1734 return FXFALSE;
1735 }
1736
1737 _fixStream( stream );
1738
1739 // if data pointer is NULL then malloc something big enough
1740 if ( info->any.data == NULL ) {
1741 info->any.data = (ImgData*) malloc( info->any.sizeInBytes );
1742 if ( info->any.data == NULL ) {
1743 imgErrorString = "Malloc failed.";
1744 return FXFALSE;
1745 }
1746 }
1747
1748 switch( info->any.type )
1749 {
1750 case IMG_TGA32:
1751 return _imgReadTGAData( stream, &(info->tgaInfo), info->any.data );
1752 case IMG_RGT:
1753 return _imgReadRGTData( stream, &(info->rgtInfo), info->any.data );
1754 case IMG_3DF:
1755 return _imgRead3DFData( stream, &(info->tdfInfo), info->any.data );
1756 case IMG_SBI:
1757 return _imgReadSbiData( stream, &(info->sbiInfo), info->any.data );
1758 case IMG_P6:
1759 return _imgReadP6Data( stream, &(info->p6Info), info->any.data );
1760 case IMG_SRLE:
1761 return _imgReadSRLEData( stream, &(info->srleInfo), info->any.data );
1762 case IMG_UNKNOWN:
1763 default:
1764 imgErrorString = "Unknown file type.";
1765 break;
1766 }
1767 return FXFALSE;
1768}
1769
1770/* imgWriteImage
1771**
1772** Summary: Write out an image file in the format specified by *type.
1773**
1774** Parameters: stream - a writeable file stream
1775** info - pointer to initialized image info struct appropriate
1776** to type described in *type
1777** type - desired image type to write
1778** data - pointer to 32BPP xRGB data in linear memory storage
1779**
1780** Returns: FXTRUE if data was written sucessfully
1781** FXFALSE if an error occured, reason may be
1782** obtained with imgGetErrorString().
1783*/
1784
1785
1786FxBool imgWriteImage( FILE *stream, const ImgInfo *info, const ImgType type, const ImgData *data )
1787{
1788 // Try to catch obvious bugs.
1789 if ( stream == NULL )
1790 {
1791 imgErrorString = "Bad file handle.";
1792 return FXFALSE;
1793 }
1794
1795 _fixStream( stream );
1796
1797 if ( data == NULL )
1798 {
1799 imgErrorString = "Bad data pointer.";
1800 return FXFALSE;
1801 }
1802
1803 switch( type )
1804 {
1805 case IMG_SBI:
1806 if ( !_imgWriteSbiHeader( stream, &(info->sbiInfo) ) )
1807 {
1808 imgErrorString = "Couldn't write SBI info.";
1809 return FXFALSE;
1810 }
1811 return _imgWriteSbiData( stream, &(info->sbiInfo), data );
1812 case IMG_P6:
1813 if ( !_imgWriteP6Header( stream, &(info->p6Info)) )
1814 {
1815 imgErrorString = "Couldn't write P6 info.";
1816 return FXFALSE;
1817 }
1818 return _imgWriteP6Data( stream, &(info->p6Info), data );
1819 case IMG_RGT:
1820 imgErrorString = "RGT writes unimplemented.";
1821 break;
1822 case IMG_TGA32:
1823 if ( !_imgWriteTGAHeader( stream, &(info->tgaInfo)) )
1824 {
1825 imgErrorString = "Couldn't write tga info.";
1826 return FXFALSE;
1827 }
1828 return _imgWriteTGAData( stream, &(info->tgaInfo), data );
1829 break;
1830 case IMG_UNKNOWN:
1831 default:
1832 imgErrorString = "Can't write unknown format.";
1833 break;
1834 }
1835
1836 return FXFALSE;
1837}
1838
1839// returns a 3-letter abbreviation for the image type
1840const char *imgTypeName( const ImgInfo *info )
1841{
1842 switch( info->any.type ) {
1843 case IMG_UNKNOWN: return "???";
1844 case IMG_P6: return "ppm";
1845 case IMG_SBI: return "sbi";
1846 case IMG_3DF: return "3df";
1847 case IMG_TGA32: return "tga";
1848 case IMG_SRLE: return "srle";
1849 case IMG_RGT:
1850 if (info->rgtInfo.rle) return "rle";
1851 if (info->rgtInfo.bgr) return "bgr";
1852 if (info->rgtInfo.rgb) return "rgb";
1853 if (info->rgtInfo.ncc) return "ncc";
1854
1855 default: return "ERR";
1856 }
1857}
1858
1859//----------------------------------------------------------------------
1860// high level routine: reads an image file thru a search path
1861// exits upon failure, prints out trace messages
1862//----------------------------------------------------------------------
1863FxBool imgReadFile(const char *filename, ImgInfo *info)
1864{
1865 const char *prefix;
1866 FILE *file;
1867
1868 file = fxFopenPath(filename,READ_ATTRIBS, getenv(IMAGE_PATH), &prefix);
1869 if (file == NULL) {
1870 fprintf(stderr,"Error: can't open input file %s\n",filename);
1871 exit(2);
1872 }
1873 if ( imgReadInfo( file, info ) == FXFALSE ) {
1874 fprintf(stderr,"Error: reading info for %s, %s\n",filename,imgGetErrorString());
1875 exit(2);
1876 }
1877 fprintf(stderr,"Loading %s image file ", imgTypeName(info));
1878 if (prefix) { // if there's a path prefix
1879 char buf[1024], *p;
1880 strcpy(buf,prefix); // copy and replace semicolon
1881 if (p = strchr(buf,';')) *p = '\0';
1882 fprintf(stderr,buf);
1883 fprintf(stderr,"/");
1884 }
1885 fprintf (stderr,"%s (%dx%d) ...", filename, info->any.width,info->any.height);
1886 fflush(stderr);
1887
1888 if ( imgReadData( file, info ) == FXFALSE ) {
1889 fprintf(stderr, "\nError: reading data for %s, %s\n",filename,imgGetErrorString());
1890 exit(4);
1891 }
1892 fclose(file);
1893 fprintf(stderr," done.\n");
1894 fflush(stderr);
1895 return FXTRUE;
1896}
1897
1898//----------------------------------------------------------------------
1899// high level routine: writes an image file
1900// exits upon failure, prints out trace messages
1901//----------------------------------------------------------------------
1902FxBool imgWriteFile(const char *filename, const ImgInfo *info, const ImgType type, const ImgData *data)
1903{
1904 FxBool retval;
1905 ImgInfo tempInfo = *info; // make a local copy
1906 FILE *file;
1907
1908 file = fopen(filename,WRITE_ATTRIBS);
1909 if (file == NULL) {
1910 fprintf(stderr,"Error: can't open output file %s\n",filename);
1911 exit(2);
1912 }
1913 tempInfo.any.type = type; // set the new type
1914 fprintf(stderr,"Storing %s image file %s (%dx%d) ...",
1915 imgTypeName(&tempInfo), filename, info->any.width,info->any.height);
1916 fflush(stderr);
1917
1918 retval = imgWriteImage( file, info, type, data );
1919 fclose(file);
1920 fprintf(stderr,retval ? " done.\n" : " aborted.\n");
1921 fflush(stderr);
1922 return retval;
1923}
Note: See TracBrowser for help on using the repository browser.