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