1 /*
2    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4 
5    This file is part of GtkRadiant.
6 
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11 
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 // lbmlib.c
22 
23 #include "cmdlib.h"
24 #include "inout.h"
25 #include "lbmlib.h"
26 
27 
28 
29 /*
30    ============================================================================
31 
32                         LBM STUFF
33 
34    ============================================================================
35  */
36 
37 
38 typedef unsigned char UBYTE;
39 //conflicts with windows typedef short			WORD;
40 typedef unsigned short UWORD;
41 typedef long LONG;
42 
43 typedef enum
44 {
45 	ms_none,
46 	ms_mask,
47 	ms_transcolor,
48 	ms_lasso
49 } mask_t;
50 
51 typedef enum
52 {
53 	cm_none,
54 	cm_rle1
55 } compress_t;
56 
57 typedef struct
58 {
59 	UWORD w,h;
60 	short x,y;
61 	UBYTE nPlanes;
62 	UBYTE masking;
63 	UBYTE compression;
64 	UBYTE pad1;
65 	UWORD transparentColor;
66 	UBYTE xAspect,yAspect;
67 	short pageWidth,pageHeight;
68 } bmhd_t;
69 
70 extern bmhd_t bmhd;                         // will be in native byte order
71 
72 
73 
74 #define FORMID ( 'F' + ( 'O' << 8 ) + ( (int)'R' << 16 ) + ( (int)'M' << 24 ) )
75 #define ILBMID ( 'I' + ( 'L' << 8 ) + ( (int)'B' << 16 ) + ( (int)'M' << 24 ) )
76 #define PBMID  ( 'P' + ( 'B' << 8 ) + ( (int)'M' << 16 ) + ( (int)' ' << 24 ) )
77 #define BMHDID ( 'B' + ( 'M' << 8 ) + ( (int)'H' << 16 ) + ( (int)'D' << 24 ) )
78 #define BODYID ( 'B' + ( 'O' << 8 ) + ( (int)'D' << 16 ) + ( (int)'Y' << 24 ) )
79 #define CMAPID ( 'C' + ( 'M' << 8 ) + ( (int)'A' << 16 ) + ( (int)'P' << 24 ) )
80 
81 
82 bmhd_t bmhd;
83 
Align(int l)84 int    Align( int l ){
85 	if ( l & 1 ) {
86 		return l + 1;
87 	}
88 	return l;
89 }
90 
91 
92 
93 /*
94    ================
95    LBMRLEdecompress
96 
97    Source must be evenly aligned!
98    ================
99  */
LBMRLEDecompress(byte * source,byte * unpacked,int bpwidth)100 byte  *LBMRLEDecompress( byte *source,byte *unpacked, int bpwidth ){
101 	int count;
102 	byte b,rept;
103 
104 	count = 0;
105 
106 	do
107 	{
108 		rept = *source++;
109 
110 		if ( rept > 0x80 ) {
111 			rept = ( rept ^ 0xff ) + 2;
112 			b = *source++;
113 			memset( unpacked,b,rept );
114 			unpacked += rept;
115 		}
116 		else if ( rept < 0x80 ) {
117 			rept++;
118 			memcpy( unpacked,source,rept );
119 			unpacked += rept;
120 			source += rept;
121 		}
122 		else{
123 			rept = 0;               // rept of 0x80 is NOP
124 
125 		}
126 		count += rept;
127 
128 	} while ( count < bpwidth );
129 
130 	if ( count > bpwidth ) {
131 		Error( "Decompression exceeded width!\n" );
132 	}
133 
134 
135 	return source;
136 }
137 
138 
139 /*
140    =================
141    LoadLBM
142    =================
143  */
LoadLBM(char * filename,byte ** picture,byte ** palette)144 void LoadLBM( char *filename, byte **picture, byte **palette ){
145 	byte    *LBMbuffer, *picbuffer, *cmapbuffer;
146 	int y;
147 	byte    *LBM_P, *LBMEND_P;
148 	byte    *pic_p;
149 	byte    *body_p;
150 
151 	int formtype,formlength;
152 	int chunktype,chunklength;
153 
154 // qiet compiler warnings
155 	picbuffer = NULL;
156 	cmapbuffer = NULL;
157 
158 //
159 // load the LBM
160 //
161 	LoadFile( filename, (void **)&LBMbuffer );
162 
163 //
164 // parse the LBM header
165 //
166 	LBM_P = LBMbuffer;
167 	if ( *(int *)LBMbuffer != LittleLong( FORMID ) ) {
168 		Error( "No FORM ID at start of file!\n" );
169 	}
170 
171 	LBM_P += 4;
172 	formlength = BigLong( *(int *)LBM_P );
173 	LBM_P += 4;
174 	LBMEND_P = LBM_P + Align( formlength );
175 
176 	formtype = LittleLong( *(int *)LBM_P );
177 
178 	if ( formtype != ILBMID && formtype != PBMID ) {
179 		Error( "Unrecognized form type: %c%c%c%c\n", formtype & 0xff
180 			   ,( formtype >> 8 ) & 0xff,( formtype >> 16 ) & 0xff,( formtype >> 24 ) & 0xff );
181 	}
182 
183 	LBM_P += 4;
184 
185 //
186 // parse chunks
187 //
188 
189 	while ( LBM_P < LBMEND_P )
190 	{
191 		chunktype = LBM_P[0] + ( LBM_P[1] << 8 ) + ( LBM_P[2] << 16 ) + ( LBM_P[3] << 24 );
192 		LBM_P += 4;
193 		chunklength = LBM_P[3] + ( LBM_P[2] << 8 ) + ( LBM_P[1] << 16 ) + ( LBM_P[0] << 24 );
194 		LBM_P += 4;
195 
196 		switch ( chunktype )
197 		{
198 		case BMHDID:
199 			memcpy( &bmhd,LBM_P,sizeof( bmhd ) );
200 			bmhd.w = BigShort( bmhd.w );
201 			bmhd.h = BigShort( bmhd.h );
202 			bmhd.x = BigShort( bmhd.x );
203 			bmhd.y = BigShort( bmhd.y );
204 			bmhd.pageWidth = BigShort( bmhd.pageWidth );
205 			bmhd.pageHeight = BigShort( bmhd.pageHeight );
206 			break;
207 
208 		case CMAPID:
209 			cmapbuffer = malloc( 768 );
210 			memset( cmapbuffer, 0, 768 );
211 			memcpy( cmapbuffer, LBM_P, chunklength );
212 			break;
213 
214 		case BODYID:
215 			body_p = LBM_P;
216 
217 			pic_p = picbuffer = malloc( bmhd.w * bmhd.h );
218 			if ( formtype == PBMID ) {
219 				//
220 				// unpack PBM
221 				//
222 				for ( y = 0 ; y < bmhd.h ; y++, pic_p += bmhd.w )
223 				{
224 					if ( bmhd.compression == cm_rle1 ) {
225 						body_p = LBMRLEDecompress( (byte *)body_p
226 												   , pic_p, bmhd.w );
227 					}
228 					else if ( bmhd.compression == cm_none ) {
229 						memcpy( pic_p,body_p,bmhd.w );
230 						body_p += Align( bmhd.w );
231 					}
232 				}
233 
234 			}
235 			else
236 			{
237 				//
238 				// unpack ILBM
239 				//
240 				Error( "%s is an interlaced LBM, not packed", filename );
241 			}
242 			break;
243 		}
244 
245 		LBM_P += Align( chunklength );
246 	}
247 
248 	free( LBMbuffer );
249 
250 	*picture = picbuffer;
251 
252 	if ( palette ) {
253 		*palette = cmapbuffer;
254 	}
255 }
256 
257 
258 /*
259    ============================================================================
260 
261                             WRITE LBM
262 
263    ============================================================================
264  */
265 
266 /*
267    ==============
268    WriteLBMfile
269    ==============
270  */
WriteLBMfile(char * filename,byte * data,int width,int height,byte * palette)271 void WriteLBMfile( char *filename, byte *data,
272 				   int width, int height, byte *palette ){
273 	byte    *lbm, *lbmptr;
274 	int    *formlength, *bmhdlength, *cmaplength, *bodylength;
275 	int length;
276 	bmhd_t basebmhd;
277 
278 	lbm = lbmptr = malloc( width * height + 1000 );
279 
280 //
281 // start FORM
282 //
283 	*lbmptr++ = 'F';
284 	*lbmptr++ = 'O';
285 	*lbmptr++ = 'R';
286 	*lbmptr++ = 'M';
287 
288 	formlength = (int*)lbmptr;
289 	lbmptr += 4;                      // leave space for length
290 
291 	*lbmptr++ = 'P';
292 	*lbmptr++ = 'B';
293 	*lbmptr++ = 'M';
294 	*lbmptr++ = ' ';
295 
296 //
297 // write BMHD
298 //
299 	*lbmptr++ = 'B';
300 	*lbmptr++ = 'M';
301 	*lbmptr++ = 'H';
302 	*lbmptr++ = 'D';
303 
304 	bmhdlength = (int *)lbmptr;
305 	lbmptr += 4;                      // leave space for length
306 
307 	memset( &basebmhd,0,sizeof( basebmhd ) );
308 	basebmhd.w = BigShort( (short)width );
309 	basebmhd.h = BigShort( (short)height );
310 	basebmhd.nPlanes = BigShort( 8 );
311 	basebmhd.xAspect = BigShort( 5 );
312 	basebmhd.yAspect = BigShort( 6 );
313 	basebmhd.pageWidth = BigShort( (short)width );
314 	basebmhd.pageHeight = BigShort( (short)height );
315 
316 	memcpy( lbmptr,&basebmhd,sizeof( basebmhd ) );
317 	lbmptr += sizeof( basebmhd );
318 
319 	length = lbmptr - (byte *)bmhdlength - 4;
320 	*bmhdlength = BigLong( length );
321 	if ( length & 1 ) {
322 		*lbmptr++ = 0;          // pad chunk to even offset
323 
324 	}
325 //
326 // write CMAP
327 //
328 	*lbmptr++ = 'C';
329 	*lbmptr++ = 'M';
330 	*lbmptr++ = 'A';
331 	*lbmptr++ = 'P';
332 
333 	cmaplength = (int *)lbmptr;
334 	lbmptr += 4;                      // leave space for length
335 
336 	memcpy( lbmptr,palette,768 );
337 	lbmptr += 768;
338 
339 	length = lbmptr - (byte *)cmaplength - 4;
340 	*cmaplength = BigLong( length );
341 	if ( length & 1 ) {
342 		*lbmptr++ = 0;          // pad chunk to even offset
343 
344 	}
345 //
346 // write BODY
347 //
348 	*lbmptr++ = 'B';
349 	*lbmptr++ = 'O';
350 	*lbmptr++ = 'D';
351 	*lbmptr++ = 'Y';
352 
353 	bodylength = (int *)lbmptr;
354 	lbmptr += 4;                      // leave space for length
355 
356 	memcpy( lbmptr,data,width * height );
357 	lbmptr += width * height;
358 
359 	length = lbmptr - (byte *)bodylength - 4;
360 	*bodylength = BigLong( length );
361 	if ( length & 1 ) {
362 		*lbmptr++ = 0;          // pad chunk to even offset
363 
364 	}
365 //
366 // done
367 //
368 	length = lbmptr - (byte *)formlength - 4;
369 	*formlength = BigLong( length );
370 	if ( length & 1 ) {
371 		*lbmptr++ = 0;          // pad chunk to even offset
372 
373 	}
374 //
375 // write output file
376 //
377 	SaveFile( filename, lbm, lbmptr - lbm );
378 	free( lbm );
379 }
380 
381 
382 /*
383    ============================================================================
384 
385    LOAD PCX
386 
387    ============================================================================
388  */
389 
390 typedef struct
391 {
392 	char manufacturer;
393 	char version;
394 	char encoding;
395 	char bits_per_pixel;
396 	unsigned short xmin,ymin,xmax,ymax;
397 	unsigned short hres,vres;
398 	unsigned char palette[48];
399 	char reserved;
400 	char color_planes;
401 	unsigned short bytes_per_line;
402 	unsigned short palette_type;
403 	char filler[58];
404 	unsigned char data;             // unbounded
405 } pcx_t;
406 
407 
408 /*
409    ==============
410    LoadPCX
411    ==============
412  */
LoadPCX(char * filename,byte ** pic,byte ** palette,int * width,int * height)413 void LoadPCX( char *filename, byte **pic, byte **palette, int *width, int *height ){
414 	byte    *raw;
415 	pcx_t   *pcx;
416 	int x, y;
417 	int len;
418 	int dataByte, runLength;
419 	byte    *out, *pix;
420 
421 	//
422 	// load the file
423 	//
424 	len = LoadFile( filename, (void **)&raw );
425 
426 	//
427 	// parse the PCX file
428 	//
429 	pcx = (pcx_t *)raw;
430 	raw = &pcx->data;
431 
432 	pcx->xmin = LittleShort( pcx->xmin );
433 	pcx->ymin = LittleShort( pcx->ymin );
434 	pcx->xmax = LittleShort( pcx->xmax );
435 	pcx->ymax = LittleShort( pcx->ymax );
436 	pcx->hres = LittleShort( pcx->hres );
437 	pcx->vres = LittleShort( pcx->vres );
438 	pcx->bytes_per_line = LittleShort( pcx->bytes_per_line );
439 	pcx->palette_type = LittleShort( pcx->palette_type );
440 
441 	if ( pcx->manufacturer != 0x0a
442 		 || pcx->version != 5
443 		 || pcx->encoding != 1
444 		 || pcx->bits_per_pixel != 8
445 		 || pcx->xmax >= 640
446 		 || pcx->ymax >= 480 ) {
447 		Error( "Bad pcx file %s", filename );
448 	}
449 
450 	if ( palette ) {
451 		*palette = malloc( 768 );
452 		memcpy( *palette, (byte *)pcx + len - 768, 768 );
453 	}
454 
455 	if ( width ) {
456 		*width = pcx->xmax + 1;
457 	}
458 	if ( height ) {
459 		*height = pcx->ymax + 1;
460 	}
461 
462 	if ( !pic ) {
463 		return;
464 	}
465 
466 	out = malloc( ( pcx->ymax + 1 ) * ( pcx->xmax + 1 ) );
467 	if ( !out ) {
468 		Error( "Skin_Cache: couldn't allocate" );
469 	}
470 
471 	*pic = out;
472 
473 	pix = out;
474 
475 	for ( y = 0 ; y <= pcx->ymax ; y++, pix += pcx->xmax + 1 )
476 	{
477 		for ( x = 0 ; x <= pcx->xmax ; )
478 		{
479 			dataByte = *raw++;
480 
481 			if ( ( dataByte & 0xC0 ) == 0xC0 ) {
482 				runLength = dataByte & 0x3F;
483 				dataByte = *raw++;
484 			}
485 			else{
486 				runLength = 1;
487 			}
488 
489 			while ( runLength-- > 0 )
490 				pix[x++] = dataByte;
491 		}
492 
493 	}
494 
495 	if ( raw - (byte *)pcx > len ) {
496 		Error( "PCX file %s was malformed", filename );
497 	}
498 
499 	free( pcx );
500 }
501 
502 /*
503    ==============
504    WritePCXfile
505    ==============
506  */
WritePCXfile(char * filename,byte * data,int width,int height,byte * palette)507 void WritePCXfile( char *filename, byte *data,
508 				   int width, int height, byte *palette ){
509 	int i, j, length;
510 	pcx_t   *pcx;
511 	byte        *pack;
512 
513 	pcx = malloc( width * height * 2 + 1000 );
514 	memset( pcx, 0, sizeof( *pcx ) );
515 
516 	pcx->manufacturer = 0x0a;   // PCX id
517 	pcx->version = 5;           // 256 color
518 	pcx->encoding = 1;      // uncompressed
519 	pcx->bits_per_pixel = 8;        // 256 color
520 	pcx->xmin = 0;
521 	pcx->ymin = 0;
522 	pcx->xmax = LittleShort( (short)( width - 1 ) );
523 	pcx->ymax = LittleShort( (short)( height - 1 ) );
524 	pcx->hres = LittleShort( (short)width );
525 	pcx->vres = LittleShort( (short)height );
526 	pcx->color_planes = 1;      // chunky image
527 	pcx->bytes_per_line = LittleShort( (short)width );
528 	pcx->palette_type = LittleShort( 2 );     // not a grey scale
529 
530 	// pack the image
531 	pack = &pcx->data;
532 
533 	for ( i = 0 ; i < height ; i++ )
534 	{
535 		for ( j = 0 ; j < width ; j++ )
536 		{
537 			if ( ( *data & 0xc0 ) != 0xc0 ) {
538 				*pack++ = *data++;
539 			}
540 			else
541 			{
542 				*pack++ = 0xc1;
543 				*pack++ = *data++;
544 			}
545 		}
546 	}
547 
548 	// write the palette
549 	*pack++ = 0x0c; // palette ID byte
550 	for ( i = 0 ; i < 768 ; i++ )
551 		*pack++ = *palette++;
552 
553 // write output file
554 	length = pack - (byte *)pcx;
555 	SaveFile( filename, pcx, length );
556 
557 	free( pcx );
558 }
559 
560 
561 /*
562    ============================================================================
563 
564    LOAD IMAGE
565 
566    ============================================================================
567  */
568 
569 /*
570    ==============
571    Load256Image
572 
573    Will load either an lbm or pcx, depending on extension.
574    Any of the return pointers can be NULL if you don't want them.
575    ==============
576  */
Load256Image(char * name,byte ** pixels,byte ** palette,int * width,int * height)577 void Load256Image( char *name, byte **pixels, byte **palette,
578 				   int *width, int *height ){
579 	char ext[128];
580 
581 	ExtractFileExtension( name, ext );
582 	if ( !Q_strncasecmp( ext, "lbm", strlen( ext ) ) ) {
583 		LoadLBM( name, pixels, palette );
584 		if ( width ) {
585 			*width = bmhd.w;
586 		}
587 		if ( height ) {
588 			*height = bmhd.h;
589 		}
590 	}
591 	else if ( !Q_strncasecmp( ext, "pcx",strlen( ext ) ) ) {
592 		LoadPCX( name, pixels, palette, width, height );
593 	}
594 	else{
595 		Error( "%s doesn't have a known image extension", name );
596 	}
597 }
598 
599 
600 /*
601    ==============
602    Save256Image
603 
604    Will save either an lbm or pcx, depending on extension.
605    ==============
606  */
Save256Image(char * name,byte * pixels,byte * palette,int width,int height)607 void Save256Image( char *name, byte *pixels, byte *palette,
608 				   int width, int height ){
609 	char ext[128];
610 
611 	ExtractFileExtension( name, ext );
612 	if ( !Q_strncasecmp( ext, "lbm",strlen( ext ) ) ) {
613 		WriteLBMfile( name, pixels, width, height, palette );
614 	}
615 	else if ( !Q_strncasecmp( ext, "pcx",strlen( ext ) ) ) {
616 		WritePCXfile( name, pixels, width, height, palette );
617 	}
618 	else{
619 		Error( "%s doesn't have a known image extension", name );
620 	}
621 }
622 
623 
624 
625 
626 /*
627    ============================================================================
628 
629    TARGA IMAGE
630 
631    ============================================================================
632  */
633 
634 typedef struct _TargaHeader {
635 	unsigned char id_length, colormap_type, image_type;
636 	unsigned short colormap_index, colormap_length;
637 	unsigned char colormap_size;
638 	unsigned short x_origin, y_origin, width, height;
639 	unsigned char pixel_size, attributes;
640 } TargaHeader;
641 
fgetLittleShort(FILE * f)642 int fgetLittleShort( FILE *f ){
643 	byte b1, b2;
644 
645 	b1 = fgetc( f );
646 	b2 = fgetc( f );
647 
648 	return (short)( b1 + b2 * 256 );
649 }
650 
fgetLittleLong(FILE * f)651 int fgetLittleLong( FILE *f ){
652 	byte b1, b2, b3, b4;
653 
654 	b1 = fgetc( f );
655 	b2 = fgetc( f );
656 	b3 = fgetc( f );
657 	b4 = fgetc( f );
658 
659 	return b1 + ( b2 << 8 ) + ( b3 << 16 ) + ( b4 << 24 );
660 }
661 
662 
663 /*
664    =============
665    LoadTGA
666    =============
667  */
LoadTGA(char * name,byte ** pixels,int * width,int * height)668 void LoadTGA( char *name, byte **pixels, int *width, int *height ){
669 	int columns, rows, numPixels;
670 	byte            *pixbuf;
671 	int row, column;
672 	FILE            *fin;
673 	byte            *targa_rgba;
674 	TargaHeader targa_header;
675 
676 	fin = fopen( name, "rb" );
677 	if ( !fin ) {
678 		Error( "Couldn't read %s", name );
679 	}
680 
681 	targa_header.id_length = fgetc( fin );
682 	targa_header.colormap_type = fgetc( fin );
683 	targa_header.image_type = fgetc( fin );
684 
685 	targa_header.colormap_index = fgetLittleShort( fin );
686 	targa_header.colormap_length = fgetLittleShort( fin );
687 	targa_header.colormap_size = fgetc( fin );
688 	targa_header.x_origin = fgetLittleShort( fin );
689 	targa_header.y_origin = fgetLittleShort( fin );
690 	targa_header.width = fgetLittleShort( fin );
691 	targa_header.height = fgetLittleShort( fin );
692 	targa_header.pixel_size = fgetc( fin );
693 	targa_header.attributes = fgetc( fin );
694 
695 	if ( targa_header.image_type != 2
696 		 && targa_header.image_type != 10 ) {
697 		Error( "LoadTGA: Only type 2 and 10 targa RGB images supported\n" );
698 	}
699 
700 	if ( targa_header.colormap_type != 0
701 		 || ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) ) {
702 		Error( "Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n" );
703 	}
704 
705 	columns = targa_header.width;
706 	rows = targa_header.height;
707 	numPixels = columns * rows;
708 
709 	if ( width ) {
710 		*width = columns;
711 	}
712 	if ( height ) {
713 		*height = rows;
714 	}
715 	targa_rgba = malloc( numPixels * 4 );
716 	*pixels = targa_rgba;
717 
718 	if ( targa_header.id_length != 0 ) {
719 		fseek( fin, targa_header.id_length, SEEK_CUR );  // skip TARGA image comment
720 
721 	}
722 	if ( targa_header.image_type == 2 ) {  // Uncompressed, RGB images
723 		for ( row = rows - 1; row >= 0; row-- ) {
724 			pixbuf = targa_rgba + row * columns * 4;
725 			for ( column = 0; column < columns; column++ ) {
726 				unsigned char red,green,blue,alphabyte;
727 				switch ( targa_header.pixel_size ) {
728 				case 24:
729 
730 					blue = getc( fin );
731 					green = getc( fin );
732 					red = getc( fin );
733 					*pixbuf++ = red;
734 					*pixbuf++ = green;
735 					*pixbuf++ = blue;
736 					*pixbuf++ = 255;
737 					break;
738 				case 32:
739 					blue = getc( fin );
740 					green = getc( fin );
741 					red = getc( fin );
742 					alphabyte = getc( fin );
743 					*pixbuf++ = red;
744 					*pixbuf++ = green;
745 					*pixbuf++ = blue;
746 					*pixbuf++ = alphabyte;
747 					break;
748 				}
749 			}
750 		}
751 	}
752 	else if ( targa_header.image_type == 10 ) {   // Runlength encoded RGB images
753 		unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
754 		for ( row = rows - 1; row >= 0; row-- ) {
755 			pixbuf = targa_rgba + row * columns * 4;
756 			for ( column = 0; column < columns; ) {
757 				packetHeader = getc( fin );
758 				packetSize = 1 + ( packetHeader & 0x7f );
759 				if ( packetHeader & 0x80 ) {        // run-length packet
760 					switch ( targa_header.pixel_size ) {
761 					case 24:
762 						blue = getc( fin );
763 						green = getc( fin );
764 						red = getc( fin );
765 						alphabyte = 255;
766 						break;
767 					case 32:
768 						blue = getc( fin );
769 						green = getc( fin );
770 						red = getc( fin );
771 						alphabyte = getc( fin );
772 						break;
773 					}
774 
775 					for ( j = 0; j < packetSize; j++ ) {
776 						*pixbuf++ = red;
777 						*pixbuf++ = green;
778 						*pixbuf++ = blue;
779 						*pixbuf++ = alphabyte;
780 						column++;
781 						if ( column == columns ) { // run spans across rows
782 							column = 0;
783 							if ( row > 0 ) {
784 								row--;
785 							}
786 							else{
787 								goto breakOut;
788 							}
789 							pixbuf = targa_rgba + row * columns * 4;
790 						}
791 					}
792 				}
793 				else {                            // non run-length packet
794 					for ( j = 0; j < packetSize; j++ ) {
795 						switch ( targa_header.pixel_size ) {
796 						case 24:
797 							blue = getc( fin );
798 							green = getc( fin );
799 							red = getc( fin );
800 							*pixbuf++ = red;
801 							*pixbuf++ = green;
802 							*pixbuf++ = blue;
803 							*pixbuf++ = 255;
804 							break;
805 						case 32:
806 							blue = getc( fin );
807 							green = getc( fin );
808 							red = getc( fin );
809 							alphabyte = getc( fin );
810 							*pixbuf++ = red;
811 							*pixbuf++ = green;
812 							*pixbuf++ = blue;
813 							*pixbuf++ = alphabyte;
814 							break;
815 						}
816 						column++;
817 						if ( column == columns ) { // pixel packet run spans across rows
818 							column = 0;
819 							if ( row > 0 ) {
820 								row--;
821 							}
822 							else{
823 								goto breakOut;
824 							}
825 							pixbuf = targa_rgba + row * columns * 4;
826 						}
827 					}
828 				}
829 			}
830 breakOut:;
831 		}
832 	}
833 
834 	// vertically flipped
835 	if ( ( targa_header.attributes & ( 1 << 5 ) ) ) {
836 		int flip;
837 		for ( row = 0; row < .5f * rows; row++ )
838 		{
839 			for ( column = 0; column < columns; column++ )
840 			{
841 				flip = *( (int*)targa_rgba + row * columns + column );
842 				*( (int*)targa_rgba + row * columns + column ) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column );
843 				*( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip;
844 			}
845 		}
846 	}
847 
848 	fclose( fin );
849 }
850