2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
\r
5 This file is part of GtkRadiant.
\r
7 GtkRadiant is free software; you can redistribute it and/or modify
\r
8 it under the terms of the GNU General Public License as published by
\r
9 the Free Software Foundation; either version 2 of the License, or
\r
10 (at your option) any later version.
\r
12 GtkRadiant is distributed in the hope that it will be useful,
\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 GNU General Public License for more details.
\r
17 You should have received a copy of the GNU General Public License
\r
18 along with GtkRadiant; if not, write to the Free Software
\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\r
25 #include "imagelib.h"
\r
28 int fgetLittleShort (FILE *f)
\r
35 return (short)(b1 + b2*256);
\r
38 int fgetLittleLong (FILE *f)
\r
40 byte b1, b2, b3, b4;
\r
47 return b1 + (b2<<8) + (b3<<16) + (b4<<24);
\r
50 int bufLittleShort (byte *buf, int len, int *pos)
\r
54 if ((len - *pos) < 2)
\r
55 Error ("Unexpected buffer end");
\r
57 b1 = buf[*pos]; *pos += 1;
\r
58 b2 = buf[*pos]; *pos += 1;
\r
60 return (short)(b1 + b2*256);
\r
63 int bufLittleLong (byte *buf, int len, int *pos)
\r
65 byte b1, b2, b3, b4;
\r
67 if ((len - *pos) < 4)
\r
68 Error ("Unexpected buffer end");
\r
70 b1 = buf[*pos]; *pos += 1;
\r
71 b2 = buf[*pos]; *pos += 1;
\r
72 b3 = buf[*pos]; *pos += 1;
\r
73 b4 = buf[*pos]; *pos += 1;
\r
75 return b1 + (b2<<8) + (b3<<16) + (b4<<24);
\r
80 ============================================================================
\r
84 ============================================================================
\r
88 typedef unsigned char UBYTE;
\r
89 //conflicts with windows typedef short WORD;
\r
90 typedef unsigned short UWORD;
\r
115 UWORD transparentColor;
\r
116 UBYTE xAspect,yAspect;
\r
117 short pageWidth,pageHeight;
\r
120 extern bmhd_t bmhd; // will be in native byte order
\r
124 #define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24))
\r
125 #define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24))
\r
126 #define PBMID ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24))
\r
127 #define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24))
\r
128 #define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24))
\r
129 #define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24))
\r
147 Source must be evenly aligned!
\r
150 byte *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth)
\r
163 rept = (rept^0xff)+2;
\r
165 memset(unpacked,b,rept);
\r
168 else if (rept < 0x80)
\r
171 memcpy(unpacked,source,rept);
\r
176 rept = 0; // rept of 0x80 is NOP
\r
180 } while (count<bpwidth);
\r
183 Error ("Decompression exceeded width!\n");
\r
195 void LoadLBM (const char *filename, byte **picture, byte **palette)
\r
197 byte *LBMbuffer, *picbuffer, *cmapbuffer;
\r
199 byte *LBM_P, *LBMEND_P;
\r
203 int formtype,formlength;
\r
204 int chunktype,chunklength;
\r
206 // qiet compiler warnings
\r
213 LoadFile (filename, (void **)&LBMbuffer);
\r
216 // parse the LBM header
\r
219 if ( *(int *)LBMbuffer != LittleLong(FORMID) )
\r
220 Error ("No FORM ID at start of file!\n");
\r
223 formlength = BigLong( *(int *)LBM_P );
\r
225 LBMEND_P = LBM_P + Align(formlength);
\r
227 formtype = LittleLong(*(int *)LBM_P);
\r
229 if (formtype != ILBMID && formtype != PBMID)
\r
230 Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff
\r
231 ,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff);
\r
239 while (LBM_P < LBMEND_P)
\r
241 chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24);
\r
243 chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24);
\r
246 switch ( chunktype )
\r
249 memcpy (&bmhd,LBM_P,sizeof(bmhd));
\r
250 bmhd.w = BigShort(bmhd.w);
\r
251 bmhd.h = BigShort(bmhd.h);
\r
252 bmhd.x = BigShort(bmhd.x);
\r
253 bmhd.y = BigShort(bmhd.y);
\r
254 bmhd.pageWidth = BigShort(bmhd.pageWidth);
\r
255 bmhd.pageHeight = BigShort(bmhd.pageHeight);
\r
259 cmapbuffer = safe_malloc (768);
\r
260 memset (cmapbuffer, 0, 768);
\r
261 memcpy (cmapbuffer, LBM_P, chunklength);
\r
267 pic_p = picbuffer = safe_malloc (bmhd.w*bmhd.h);
\r
268 if (formtype == PBMID)
\r
273 for (y=0 ; y<bmhd.h ; y++, pic_p += bmhd.w)
\r
275 if (bmhd.compression == cm_rle1)
\r
276 body_p = LBMRLEDecompress ((byte *)body_p
\r
278 else if (bmhd.compression == cm_none)
\r
280 memcpy (pic_p,body_p,bmhd.w);
\r
281 body_p += Align(bmhd.w);
\r
291 Error ("%s is an interlaced LBM, not packed", filename);
\r
296 LBM_P += Align(chunklength);
\r
301 *picture = picbuffer;
\r
304 *palette = cmapbuffer;
\r
309 ============================================================================
\r
313 ============================================================================
\r
321 void WriteLBMfile (const char *filename, byte *data,
\r
322 int width, int height, byte *palette)
\r
324 byte *lbm, *lbmptr;
\r
325 int *formlength, *bmhdlength, *cmaplength, *bodylength;
\r
329 lbm = lbmptr = safe_malloc (width*height+1000);
\r
339 formlength = (int*)lbmptr;
\r
340 lbmptr+=4; // leave space for length
\r
355 bmhdlength = (int *)lbmptr;
\r
356 lbmptr+=4; // leave space for length
\r
358 memset (&basebmhd,0,sizeof(basebmhd));
\r
359 basebmhd.w = BigShort((short)width);
\r
360 basebmhd.h = BigShort((short)height);
\r
361 basebmhd.nPlanes = BigShort(8);
\r
362 basebmhd.xAspect = BigShort(5);
\r
363 basebmhd.yAspect = BigShort(6);
\r
364 basebmhd.pageWidth = BigShort((short)width);
\r
365 basebmhd.pageHeight = BigShort((short)height);
\r
367 memcpy (lbmptr,&basebmhd,sizeof(basebmhd));
\r
368 lbmptr += sizeof(basebmhd);
\r
370 length = lbmptr-(byte *)bmhdlength-4;
\r
371 *bmhdlength = BigLong(length);
\r
373 *lbmptr++ = 0; // pad chunk to even offset
\r
383 cmaplength = (int *)lbmptr;
\r
384 lbmptr+=4; // leave space for length
\r
386 memcpy (lbmptr,palette,768);
\r
389 length = lbmptr-(byte *)cmaplength-4;
\r
390 *cmaplength = BigLong(length);
\r
392 *lbmptr++ = 0; // pad chunk to even offset
\r
402 bodylength = (int *)lbmptr;
\r
403 lbmptr+=4; // leave space for length
\r
405 memcpy (lbmptr,data,width*height);
\r
406 lbmptr += width*height;
\r
408 length = lbmptr-(byte *)bodylength-4;
\r
409 *bodylength = BigLong(length);
\r
411 *lbmptr++ = 0; // pad chunk to even offset
\r
416 length = lbmptr-(byte *)formlength-4;
\r
417 *formlength = BigLong(length);
\r
419 *lbmptr++ = 0; // pad chunk to even offset
\r
422 // write output file
\r
424 SaveFile (filename, lbm, lbmptr-lbm);
\r
430 ============================================================================
\r
434 ============================================================================
\r
442 char bits_per_pixel;
\r
443 unsigned short xmin,ymin,xmax,ymax;
\r
444 unsigned short hres,vres;
\r
445 unsigned char palette[48];
\r
448 unsigned short bytes_per_line;
\r
449 unsigned short palette_type;
\r
451 unsigned char data; // unbounded
\r
462 #define DECODEPCX( b, d, r ) d=*b++;if((d&0xC0)==0xC0){r=d&0x3F;d=*b++;}else{r=1;}
\r
464 void LoadPCX( const char *filename, byte **pic, byte **palette, int *width, int *height )
\r
470 int dataByte, runLength;
\r
474 /* load the file */
\r
475 len = vfsLoadFile (filename, (void **)&raw, 0);
\r
477 Error( "LoadPCX: Couldn't read %s", filename );
\r
480 /* parse the PCX file */
\r
481 pcx = (pcx_t *)raw;
\r
484 pcx->xmin = LittleShort(pcx->xmin);
\r
485 pcx->ymin = LittleShort(pcx->ymin);
\r
486 pcx->xmax = LittleShort(pcx->xmax);
\r
487 pcx->ymax = LittleShort(pcx->ymax);
\r
488 pcx->hres = LittleShort(pcx->hres);
\r
489 pcx->vres = LittleShort(pcx->vres);
\r
490 pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
\r
491 pcx->palette_type = LittleShort(pcx->palette_type);
\r
493 if (pcx->manufacturer != 0x0a
\r
494 || pcx->version != 5
\r
495 || pcx->encoding != 1
\r
496 || pcx->bits_per_pixel != 8
\r
497 || pcx->xmax >= 640
\r
498 || pcx->ymax >= 480)
\r
499 Error ("Bad pcx file %s", filename);
\r
503 *palette = safe_malloc(768);
\r
504 memcpy (*palette, (byte *)pcx + len - 768, 768);
\r
508 *width = pcx->xmax+1;
\r
510 *height = pcx->ymax+1;
\r
515 out = safe_malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
\r
517 Error( "LoadPCX: couldn't allocate");
\r
522 /* RR2DO2: pcx fix */
\r
523 lsize = pcx->color_planes * pcx->bytes_per_line;
\r
525 /* go scanline by scanline */
\r
526 for( y = 0; y <= pcx->ymax; y++, pix += pcx->xmax + 1 )
\r
528 /* do a scanline */
\r
529 for( x=0; x <= pcx->xmax; )
\r
532 DECODEPCX( raw, dataByte, runLength );
\r
533 while( runLength-- > 0 )
\r
534 pix[ x++ ] = dataByte;
\r
537 /* RR2DO2: discard any other data */
\r
540 DECODEPCX( raw, dataByte, runLength );
\r
543 while( runLength-- > 0 )
\r
547 /* validity check */
\r
548 if( raw - (byte *) pcx > len)
\r
549 Error( "PCX file %s was malformed", filename );
\r
560 void WritePCXfile (const char *filename, byte *data,
\r
561 int width, int height, byte *palette)
\r
567 pcx = safe_malloc (width*height*2+1000);
\r
568 memset (pcx, 0, sizeof(*pcx));
\r
570 pcx->manufacturer = 0x0a; // PCX id
\r
571 pcx->version = 5; // 256 color
\r
572 pcx->encoding = 1; // uncompressed
\r
573 pcx->bits_per_pixel = 8; // 256 color
\r
576 pcx->xmax = LittleShort((short)(width-1));
\r
577 pcx->ymax = LittleShort((short)(height-1));
\r
578 pcx->hres = LittleShort((short)width);
\r
579 pcx->vres = LittleShort((short)height);
\r
580 pcx->color_planes = 1; // chunky image
\r
581 pcx->bytes_per_line = LittleShort((short)width);
\r
582 pcx->palette_type = LittleShort(1); // not a grey scale
\r
587 for (i=0 ; i<height ; i++)
\r
589 for (j=0 ; j<width ; j++)
\r
591 if ( (*data & 0xc0) != 0xc0)
\r
601 // write the palette
\r
602 *pack++ = 0x0c; // palette ID byte
\r
603 for (i=0 ; i<768 ; i++)
\r
604 *pack++ = *palette++;
\r
606 // write output file
\r
607 length = pack - (byte *)pcx;
\r
608 SaveFile (filename, pcx, length);
\r
614 ============================================================================
\r
618 ============================================================================
\r
624 // we can't just use these structures, because
\r
625 // compiler structure alignment will not be portable
\r
626 // on this unaligned stuff
\r
628 typedef struct tagBITMAPFILEHEADER { // bmfh
\r
634 } BITMAPFILEHEADER;
\r
636 typedef struct tagBITMAPINFOHEADER{ // bmih
\r
642 DWORD biCompression;
\r
643 DWORD biSizeImage;
\r
644 LONG biXPelsPerMeter;
\r
645 LONG biYPelsPerMeter;
\r
647 DWORD biClrImportant;
\r
648 } BITMAPINFOHEADER;
\r
650 typedef struct tagBITMAPINFO { // bmi
\r
651 BITMAPINFOHEADER bmiHeader;
\r
652 RGBQUAD bmiColors[1];
\r
655 typedef struct tagBITMAPCOREHEADER { // bmch
\r
661 } BITMAPCOREHEADER;
\r
663 typedef struct _BITMAPCOREINFO { // bmci
\r
664 BITMAPCOREHEADER bmciHeader;
\r
665 RGBTRIPLE bmciColors[1];
\r
675 void LoadBMP (const char *filename, byte **pic, byte **palette, int *width, int *height)
\r
686 byte bcPalette[1024];
\r
691 len = vfsLoadFile (filename, (void **)&in, 0);
\r
694 Error ("Couldn't read %s", filename);
\r
697 i = bufLittleShort (in, len, &pos);
\r
698 if (i != 'B' + ('M'<<8) ) {
\r
699 Error ("%s is not a bmp file", filename);
\r
702 bfSize = bufLittleLong (in, len, &pos);
\r
703 bufLittleShort(in, len, &pos);
\r
704 bufLittleShort(in, len, &pos);
\r
705 bfOffBits = bufLittleLong (in, len, &pos);
\r
707 // the size will tell us if it is a
\r
708 // bitmapinfo or a bitmapcore
\r
709 structSize = bufLittleLong (in, len, &pos);
\r
710 if (structSize == 40)
\r
713 bcWidth = bufLittleLong(in, len, &pos);
\r
714 bcHeight= bufLittleLong(in, len, &pos);
\r
715 bcPlanes = bufLittleShort(in, len, &pos);
\r
716 bcBitCount = bufLittleShort(in, len, &pos);
\r
722 memcpy (bcPalette, in+pos, 1024);
\r
724 *palette = safe_malloc(768);
\r
726 for (i = 0 ; i < 256 ; i++)
\r
728 (*palette)[i * 3 + 0] = bcPalette[i * 4 + 2];
\r
729 (*palette)[i * 3 + 1] = bcPalette[i * 4 + 1];
\r
730 (*palette)[i * 3 + 2] = bcPalette[i * 4 + 0];
\r
734 else if (structSize == 12)
\r
737 bcWidth = bufLittleShort(in, len, &pos);
\r
738 bcHeight= bufLittleShort(in, len, &pos);
\r
739 bcPlanes = bufLittleShort(in, len, &pos);
\r
740 bcBitCount = bufLittleShort(in, len, &pos);
\r
744 memcpy (bcPalette, in+pos, 768);
\r
746 *palette = safe_malloc(768);
\r
748 for (i = 0 ; i < 256 ; i++) {
\r
749 (*palette)[i * 3 + 0] = bcPalette[i * 3 + 2];
\r
750 (*palette)[i * 3 + 1] = bcPalette[i * 3 + 1];
\r
751 (*palette)[i * 3 + 2] = bcPalette[i * 3 + 0];
\r
755 Error ("%s had strange struct size", filename);
\r
758 if (bcPlanes != 1) {
\r
759 Error ("%s was not a single plane image", filename);
\r
762 if (bcBitCount != 8) {
\r
763 Error ("%s was not an 8 bit image", filename);
\r
766 if (bcHeight < 0) {
\r
767 bcHeight = -bcHeight;
\r
776 *height = bcHeight;
\r
783 out = safe_malloc ( bcWidth * bcHeight );
\r
788 for (i = 0 ; i < bcHeight ; i++) {
\r
789 memcpy (out + bcWidth * (bcHeight - 1 - i), in+pos, bcWidth);
\r
793 memcpy (out, in+pos, bcWidth*bcHeight);
\r
794 pos += bcWidth*bcHeight;
\r
802 ============================================================================
\r
806 ============================================================================
\r
813 Will load either an lbm or pcx, depending on extension.
\r
814 Any of the return pointers can be NULL if you don't want them.
\r
817 void Load256Image (const char *name, byte **pixels, byte **palette, int *width, int *height)
\r
821 ExtractFileExtension (name, ext);
\r
822 if (!Q_stricmp (ext, "lbm"))
\r
824 LoadLBM (name, pixels, palette);
\r
830 else if (!Q_stricmp (ext, "pcx"))
\r
832 LoadPCX (name, pixels, palette, width, height);
\r
834 else if (!Q_stricmp (ext, "bmp"))
\r
836 LoadBMP (name, pixels, palette, width, height);
\r
839 Error ("%s doesn't have a known image extension", name);
\r
847 Will save either an lbm or pcx, depending on extension.
\r
850 void Save256Image (const char *name, byte *pixels, byte *palette,
\r
851 int width, int height)
\r
855 ExtractFileExtension (name, ext);
\r
856 if (!Q_stricmp (ext, "lbm"))
\r
858 WriteLBMfile (name, pixels, width, height, palette);
\r
860 else if (!Q_stricmp (ext, "pcx"))
\r
862 WritePCXfile (name, pixels, width, height, palette);
\r
865 Error ("%s doesn't have a known image extension", name);
\r
872 ============================================================================
\r
876 ============================================================================
\r
879 typedef struct _TargaHeader {
\r
880 unsigned char id_length, colormap_type, image_type;
\r
881 unsigned short colormap_index, colormap_length;
\r
882 unsigned char colormap_size;
\r
883 unsigned short x_origin, y_origin, width, height;
\r
884 unsigned char pixel_size, attributes;
\r
892 void LoadTGABuffer ( byte *buffer, byte **pic, int *width, int *height)
\r
894 int columns, rows, numPixels;
\r
898 TargaHeader targa_header;
\r
905 targa_header.id_length = *buf_p++;
\r
906 targa_header.colormap_type = *buf_p++;
\r
907 targa_header.image_type = *buf_p++;
\r
909 targa_header.colormap_index = LittleShort ( *(short *)buf_p );
\r
911 targa_header.colormap_length = LittleShort ( *(short *)buf_p );
\r
913 targa_header.colormap_size = *buf_p++;
\r
914 targa_header.x_origin = LittleShort ( *(short *)buf_p );
\r
916 targa_header.y_origin = LittleShort ( *(short *)buf_p );
\r
918 targa_header.width = LittleShort ( *(short *)buf_p );
\r
920 targa_header.height = LittleShort ( *(short *)buf_p );
\r
922 targa_header.pixel_size = *buf_p++;
\r
923 targa_header.attributes = *buf_p++;
\r
925 if (targa_header.image_type!=2
\r
926 && targa_header.image_type!=10
\r
927 && targa_header.image_type != 3 )
\r
929 Error("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n");
\r
932 if ( targa_header.colormap_type != 0 )
\r
934 Error("LoadTGA: colormaps not supported\n" );
\r
937 if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 )
\r
939 Error("LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
\r
942 columns = targa_header.width;
\r
943 rows = targa_header.height;
\r
944 numPixels = columns * rows;
\r
951 targa_rgba = safe_malloc (numPixels*4);
\r
954 if (targa_header.id_length != 0)
\r
955 buf_p += targa_header.id_length; // skip TARGA image comment
\r
957 if ( targa_header.image_type==2 || targa_header.image_type == 3 )
\r
959 // Uncompressed RGB or gray scale image
\r
960 for(row=rows-1; row>=0; row--)
\r
962 pixbuf = targa_rgba + row*columns*4;
\r
963 for(column=0; column<columns; column++)
\r
965 unsigned char red,green,blue,alphabyte;
\r
966 switch (targa_header.pixel_size)
\r
992 alphabyte = *buf_p++;
\r
996 *pixbuf++ = alphabyte;
\r
999 //Error("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
\r
1005 else if (targa_header.image_type==10) { // Runlength encoded RGB images
\r
1006 unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
\r
1013 for(row=rows-1; row>=0; row--) {
\r
1014 pixbuf = targa_rgba + row*columns*4;
\r
1015 for(column=0; column<columns; ) {
\r
1016 packetHeader= *buf_p++;
\r
1017 packetSize = 1 + (packetHeader & 0x7f);
\r
1018 if (packetHeader & 0x80) { // run-length packet
\r
1019 switch (targa_header.pixel_size) {
\r
1030 alphabyte = *buf_p++;
\r
1033 //Error("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
\r
1037 for(j=0;j<packetSize;j++) {
\r
1041 *pixbuf++=alphabyte;
\r
1043 if (column==columns) { // run spans across rows
\r
1049 pixbuf = targa_rgba + row*columns*4;
\r
1053 else { // non run-length packet
\r
1054 for(j=0;j<packetSize;j++) {
\r
1055 switch (targa_header.pixel_size) {
\r
1061 *pixbuf++ = green;
\r
1069 alphabyte = *buf_p++;
\r
1071 *pixbuf++ = green;
\r
1073 *pixbuf++ = alphabyte;
\r
1076 //Sysprintf("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
\r
1080 if (column==columns) { // pixel packet run spans across rows
\r
1086 pixbuf = targa_rgba + row*columns*4;
\r
1095 // vertically flipped
\r
1096 if ( (targa_header.attributes & (1<<5)) ) {
\r
1098 for (row = 0; row < .5f * rows; row++)
\r
1100 for (column = 0; column < columns; column++)
\r
1102 flip = *( (int*)targa_rgba + row * columns + column);
\r
1103 *( (int*)targa_rgba + row * columns + column) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column );
\r
1104 *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip;
\r
1119 void LoadTGA (const char *name, byte **pixels, int *width, int *height)
\r
1126 nLen = vfsLoadFile ( ( char * ) name, (void **)&buffer, 0);
\r
1129 Error ("Couldn't read %s", name);
\r
1132 LoadTGABuffer(buffer, pixels, width, height);
\r
1142 void WriteTGA (const char *filename, byte *data, int width, int height) {
\r
1148 buffer = safe_malloc(width*height*4 + 18);
\r
1149 memset (buffer, 0, 18);
\r
1150 buffer[2] = 2; // uncompressed type
\r
1151 buffer[12] = width&255;
\r
1152 buffer[13] = width>>8;
\r
1153 buffer[14] = height&255;
\r
1154 buffer[15] = height>>8;
\r
1155 buffer[16] = 32; // pixel size
\r
1157 // swap rgb to bgr
\r
1158 c = 18 + width * height * 4;
\r
1159 for (i=18 ; i<c ; i+=4)
\r
1161 buffer[i] = data[i-18+2]; // blue
\r
1162 buffer[i+1] = data[i-18+1]; // green
\r
1163 buffer[i+2] = data[i-18+0]; // red
\r
1164 buffer[i+3] = data[i-18+3]; // alpha
\r
1167 f = fopen (filename, "wb");
\r
1168 fwrite (buffer, 1, c, f);
\r
1175 ============================================================================
\r
1179 ============================================================================
\r
1186 Any of the return pointers can be NULL if you don't want them.
\r
1189 void Load32BitImage (const char *name, unsigned **pixels, int *width, int *height)
\r
1199 ExtractFileExtension (name, ext);
\r
1200 if (!Q_stricmp (ext, "tga")) {
\r
1201 LoadTGA (name, (byte **)pixels, width, height);
\r
1203 Load256Image (name, &pixels8, &palette, width, height);
\r
1207 size = *width * *height;
\r
1208 pixels32 = safe_malloc(size * 4);
\r
1209 *pixels = (unsigned *)pixels32;
\r
1210 for (i = 0 ; i < size ; i++) {
\r
1212 pixels32[i*4 + 0] = palette[ v * 3 + 0 ];
\r
1213 pixels32[i*4 + 1] = palette[ v * 3 + 1 ];
\r
1214 pixels32[i*4 + 2] = palette[ v * 3 + 2 ];
\r
1215 pixels32[i*4 + 3] = 0xff;
\r