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 
22 // imagelib.c
23 
24 #include "inout.h"
25 #include "cmdlib.h"
26 #include "imagelib.h"
27 #include "vfs.h"
28 
fgetLittleShort(FILE * f)29 int fgetLittleShort (FILE *f)
30 {
31 	byte	b1, b2;
32 
33 	b1 = fgetc(f);
34 	b2 = fgetc(f);
35 
36 	return (short)(b1 + b2*256);
37 }
38 
fgetLittleLong(FILE * f)39 int fgetLittleLong (FILE *f)
40 {
41 	byte	b1, b2, b3, b4;
42 
43 	b1 = fgetc(f);
44 	b2 = fgetc(f);
45 	b3 = fgetc(f);
46 	b4 = fgetc(f);
47 
48 	return b1 + (b2<<8) + (b3<<16) + (b4<<24);
49 }
50 
bufLittleShort(byte * buf,int len,int * pos)51 int bufLittleShort (byte *buf, int len, int *pos)
52 {
53   byte	b1, b2;
54 
55   if ((len - *pos) < 2)
56     Error ("Unexpected buffer end");
57 
58   b1 = buf[*pos]; *pos += 1;
59   b2 = buf[*pos]; *pos += 1;
60 
61   return (short)(b1 + b2*256);
62 }
63 
bufLittleLong(byte * buf,int len,int * pos)64 int bufLittleLong (byte *buf, int len, int *pos)
65 {
66   byte b1, b2, b3, b4;
67 
68   if ((len - *pos) < 4)
69     Error ("Unexpected buffer end");
70 
71   b1 = buf[*pos]; *pos += 1;
72   b2 = buf[*pos]; *pos += 1;
73   b3 = buf[*pos]; *pos += 1;
74   b4 = buf[*pos]; *pos += 1;
75 
76   return b1 + (b2<<8) + (b3<<16) + (b4<<24);
77 }
78 
79 
80 /*
81 ============================================================================
82 
83 						LBM STUFF
84 
85 ============================================================================
86 */
87 
88 
89 typedef unsigned char	UBYTE;
90 //conflicts with windows typedef short			WORD;
91 typedef unsigned short	UWORD;
92 typedef long			LONG;
93 
94 typedef enum
95 {
96 	ms_none,
97 	ms_mask,
98 	ms_transcolor,
99 	ms_lasso
100 } mask_t;
101 
102 typedef enum
103 {
104 	cm_none,
105 	cm_rle1
106 } compress_t;
107 
108 typedef struct
109 {
110 	UWORD		w,h;
111 	short		x,y;
112 	UBYTE		nPlanes;
113 	UBYTE		masking;
114 	UBYTE		compression;
115 	UBYTE		pad1;
116 	UWORD		transparentColor;
117 	UBYTE		xAspect,yAspect;
118 	short		pageWidth,pageHeight;
119 } bmhd_t;
120 
121 extern	bmhd_t	bmhd;						// will be in native byte order
122 
123 
124 
125 #define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24))
126 #define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24))
127 #define PBMID  ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24))
128 #define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24))
129 #define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24))
130 #define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24))
131 
132 
133 bmhd_t  bmhd;
134 
Align(int l)135 int    Align (int l)
136 {
137 	if (l&1)
138 		return l+1;
139 	return l;
140 }
141 
142 
143 
144 /*
145 ================
146 LBMRLEdecompress
147 
148 Source must be evenly aligned!
149 ================
150 */
LBMRLEDecompress(byte * source,byte * unpacked,int bpwidth)151 byte  *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth)
152 {
153 	int     count;
154 	byte    b,rept;
155 
156 	count = 0;
157 
158 	do
159 	{
160 		rept = *source++;
161 
162 		if (rept > 0x80)
163 		{
164 			rept = (rept^0xff)+2;
165 			b = *source++;
166 			memset(unpacked,b,rept);
167 			unpacked += rept;
168 		}
169 		else if (rept < 0x80)
170 		{
171 			rept++;
172 			memcpy(unpacked,source,rept);
173 			unpacked += rept;
174 			source += rept;
175 		}
176 		else
177 			rept = 0;               // rept of 0x80 is NOP
178 
179 		count += rept;
180 
181 	} while (count<bpwidth);
182 
183 	if (count>bpwidth)
184 		Error ("Decompression exceeded width!\n");
185 
186 
187 	return source;
188 }
189 
190 
191 /*
192 =================
193 LoadLBM
194 =================
195 */
LoadLBM(const char * filename,byte ** picture,byte ** palette)196 void LoadLBM (const char *filename, byte **picture, byte **palette)
197 {
198 	byte    *LBMbuffer, *picbuffer, *cmapbuffer;
199 	int             y;
200 	byte    *LBM_P, *LBMEND_P;
201 	byte    *pic_p;
202 	byte    *body_p;
203 
204 	int    formtype,formlength;
205 	int    chunktype,chunklength;
206 
207 // qiet compiler warnings
208 	picbuffer = NULL;
209 	cmapbuffer = NULL;
210 
211 //
212 // load the LBM
213 //
214 	LoadFile (filename, (void **)&LBMbuffer);
215 
216 //
217 // parse the LBM header
218 //
219 	LBM_P = LBMbuffer;
220 	if ( *(int *)LBMbuffer != LittleLong(FORMID) )
221 	   Error ("No FORM ID at start of file!\n");
222 
223 	LBM_P += 4;
224 	formlength = BigLong( *(int *)LBM_P );
225 	LBM_P += 4;
226 	LBMEND_P = LBM_P + Align(formlength);
227 
228 	formtype = LittleLong(*(int *)LBM_P);
229 
230 	if (formtype != ILBMID && formtype != PBMID)
231 		Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff
232 		,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff);
233 
234 	LBM_P += 4;
235 
236 //
237 // parse chunks
238 //
239 
240 	while (LBM_P < LBMEND_P)
241 	{
242 		chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24);
243 		LBM_P += 4;
244 		chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24);
245 		LBM_P += 4;
246 
247 		switch ( chunktype )
248 		{
249 		case BMHDID:
250 			memcpy (&bmhd,LBM_P,sizeof(bmhd));
251 			bmhd.w = BigShort(bmhd.w);
252 			bmhd.h = BigShort(bmhd.h);
253 			bmhd.x = BigShort(bmhd.x);
254 			bmhd.y = BigShort(bmhd.y);
255 			bmhd.pageWidth = BigShort(bmhd.pageWidth);
256 			bmhd.pageHeight = BigShort(bmhd.pageHeight);
257 			break;
258 
259 		case CMAPID:
260 			cmapbuffer = safe_malloc (768);
261 			memset (cmapbuffer, 0, 768);
262 			memcpy (cmapbuffer, LBM_P, chunklength);
263 			break;
264 
265 		case BODYID:
266 			body_p = LBM_P;
267 
268 			pic_p = picbuffer = safe_malloc (bmhd.w*bmhd.h);
269 			if (formtype == PBMID)
270 			{
271 			//
272 			// unpack PBM
273 			//
274 				for (y=0 ; y<bmhd.h ; y++, pic_p += bmhd.w)
275 				{
276 					if (bmhd.compression == cm_rle1)
277 						body_p = LBMRLEDecompress ((byte *)body_p
278 						, pic_p , bmhd.w);
279 					else if (bmhd.compression == cm_none)
280 					{
281 						memcpy (pic_p,body_p,bmhd.w);
282 						body_p += Align(bmhd.w);
283 					}
284 				}
285 
286 			}
287 			else
288 			{
289 			//
290 			// unpack ILBM
291 			//
292 				Error ("%s is an interlaced LBM, not packed", filename);
293 			}
294 			break;
295 		}
296 
297 		LBM_P += Align(chunklength);
298 	}
299 
300 	free (LBMbuffer);
301 
302 	*picture = picbuffer;
303 
304 	if (palette)
305 		*palette = cmapbuffer;
306 }
307 
308 
309 /*
310 ============================================================================
311 
312 							WRITE LBM
313 
314 ============================================================================
315 */
316 
317 /*
318 ==============
319 WriteLBMfile
320 ==============
321 */
WriteLBMfile(const char * filename,byte * data,int width,int height,byte * palette)322 void WriteLBMfile (const char *filename, byte *data,
323 				   int width, int height, byte *palette)
324 {
325 	byte    *lbm, *lbmptr;
326 	int    *formlength, *bmhdlength, *cmaplength, *bodylength;
327 	int    length;
328 	bmhd_t  basebmhd;
329 
330 	lbm = lbmptr = safe_malloc (width*height+1000);
331 
332 //
333 // start FORM
334 //
335 	*lbmptr++ = 'F';
336 	*lbmptr++ = 'O';
337 	*lbmptr++ = 'R';
338 	*lbmptr++ = 'M';
339 
340 	formlength = (int*)lbmptr;
341 	lbmptr+=4;                      // leave space for length
342 
343 	*lbmptr++ = 'P';
344 	*lbmptr++ = 'B';
345 	*lbmptr++ = 'M';
346 	*lbmptr++ = ' ';
347 
348 //
349 // write BMHD
350 //
351 	*lbmptr++ = 'B';
352 	*lbmptr++ = 'M';
353 	*lbmptr++ = 'H';
354 	*lbmptr++ = 'D';
355 
356 	bmhdlength = (int *)lbmptr;
357 	lbmptr+=4;                      // leave space for length
358 
359 	memset (&basebmhd,0,sizeof(basebmhd));
360 	basebmhd.w = BigShort((short)width);
361 	basebmhd.h = BigShort((short)height);
362 	basebmhd.nPlanes = BigShort(8);
363 	basebmhd.xAspect = BigShort(5);
364 	basebmhd.yAspect = BigShort(6);
365 	basebmhd.pageWidth = BigShort((short)width);
366 	basebmhd.pageHeight = BigShort((short)height);
367 
368 	memcpy (lbmptr,&basebmhd,sizeof(basebmhd));
369 	lbmptr += sizeof(basebmhd);
370 
371 	length = lbmptr-(byte *)bmhdlength-4;
372 	*bmhdlength = BigLong(length);
373 	if (length&1)
374 		*lbmptr++ = 0;          // pad chunk to even offset
375 
376 //
377 // write CMAP
378 //
379 	*lbmptr++ = 'C';
380 	*lbmptr++ = 'M';
381 	*lbmptr++ = 'A';
382 	*lbmptr++ = 'P';
383 
384 	cmaplength = (int *)lbmptr;
385 	lbmptr+=4;                      // leave space for length
386 
387 	memcpy (lbmptr,palette,768);
388 	lbmptr += 768;
389 
390 	length = lbmptr-(byte *)cmaplength-4;
391 	*cmaplength = BigLong(length);
392 	if (length&1)
393 		*lbmptr++ = 0;          // pad chunk to even offset
394 
395 //
396 // write BODY
397 //
398 	*lbmptr++ = 'B';
399 	*lbmptr++ = 'O';
400 	*lbmptr++ = 'D';
401 	*lbmptr++ = 'Y';
402 
403 	bodylength = (int *)lbmptr;
404 	lbmptr+=4;                      // leave space for length
405 
406 	memcpy (lbmptr,data,width*height);
407 	lbmptr += width*height;
408 
409 	length = lbmptr-(byte *)bodylength-4;
410 	*bodylength = BigLong(length);
411 	if (length&1)
412 		*lbmptr++ = 0;          // pad chunk to even offset
413 
414 //
415 // done
416 //
417 	length = lbmptr-(byte *)formlength-4;
418 	*formlength = BigLong(length);
419 	if (length&1)
420 		*lbmptr++ = 0;          // pad chunk to even offset
421 
422 //
423 // write output file
424 //
425 	SaveFile (filename, lbm, lbmptr-lbm);
426 	free (lbm);
427 }
428 
429 
430 /*
431 ============================================================================
432 
433 LOAD PCX
434 
435 ============================================================================
436 */
437 
438 typedef struct
439 {
440     char	manufacturer;
441     char	version;
442     char	encoding;
443     char	bits_per_pixel;
444     unsigned short	xmin,ymin,xmax,ymax;
445     unsigned short	hres,vres;
446     unsigned char	palette[48];
447     char	reserved;
448     char	color_planes;
449     unsigned short	bytes_per_line;
450     unsigned short	palette_type;
451     char	filler[58];
452     unsigned char	data;			// unbounded
453 } pcx_t;
454 
455 
456 /*
457 ==============
458 LoadPCX
459 ==============
460 */
461 
462 /* RR2DO2 */
463 #define DECODEPCX( b, d, r ) d=*b++;if((d&0xC0)==0xC0){r=d&0x3F;d=*b++;}else{r=1;}
464 
LoadPCX(const char * filename,byte ** pic,byte ** palette,int * width,int * height)465 void LoadPCX( const char *filename, byte **pic, byte **palette, int *width, int *height )
466 {
467 	byte	*raw;
468 	pcx_t	*pcx;
469 	int		x, y, lsize;
470 	int		len;
471 	int		dataByte, runLength;
472 	byte	*out, *pix;
473 
474 
475 	/* load the file */
476 	len = vfsLoadFile (filename, (void **)&raw, 0);
477     if( len == -1 )
478 		Error( "LoadPCX: Couldn't read %s", filename );
479 
480 
481 	/* parse the PCX file */
482 	pcx = (pcx_t *)raw;
483 	raw = &pcx->data;
484 
485 	pcx->xmin = LittleShort(pcx->xmin);
486 	pcx->ymin = LittleShort(pcx->ymin);
487 	pcx->xmax = LittleShort(pcx->xmax);
488 	pcx->ymax = LittleShort(pcx->ymax);
489 	pcx->hres = LittleShort(pcx->hres);
490 	pcx->vres = LittleShort(pcx->vres);
491 	pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
492 	pcx->palette_type = LittleShort(pcx->palette_type);
493 
494 	if (pcx->manufacturer != 0x0a
495 		|| pcx->version != 5
496 		|| pcx->encoding != 1
497 		|| pcx->bits_per_pixel != 8
498 		|| pcx->xmax >= 640
499 		|| pcx->ymax >= 480)
500 		Error ("Bad pcx file %s", filename);
501 
502 	if (palette)
503 	{
504 		*palette = safe_malloc(768);
505 		memcpy (*palette, (byte *)pcx + len - 768, 768);
506 	}
507 
508 	if (width)
509 		*width = pcx->xmax+1;
510 	if (height)
511 		*height = pcx->ymax+1;
512 
513 	if (!pic)
514 		return;
515 
516 	out = safe_malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
517 	if (!out)
518 		Error( "LoadPCX: couldn't allocate");
519 
520 	*pic = out;
521 	pix = out;
522 
523 	/* RR2DO2: pcx fix  */
524 	lsize = pcx->color_planes * pcx->bytes_per_line;
525 
526 	/* go scanline by scanline */
527 	for( y = 0; y <= pcx->ymax; y++, pix += pcx->xmax + 1 )
528 	{
529 		/* do a scanline */
530 		for( x=0; x <= pcx->xmax; )
531 		{
532 			/* RR2DO2 */
533 			DECODEPCX( raw, dataByte, runLength );
534 			while( runLength-- > 0 )
535 				pix[ x++ ] = dataByte;
536 		}
537 
538 		/* RR2DO2: discard any other data */
539 		while( x < lsize )
540 		{
541 			DECODEPCX( raw, dataByte, runLength );
542 			x++;
543 		}
544 		while( runLength-- > 0 )
545 			x++;
546 	}
547 
548 	/* validity check */
549 	if( raw - (byte *) pcx > len)
550 		Error( "PCX file %s was malformed", filename );
551 	free( pcx );
552 }
553 
554 
555 
556 /*
557 ==============
558 WritePCXfile
559 ==============
560 */
WritePCXfile(const char * filename,byte * data,int width,int height,byte * palette)561 void WritePCXfile (const char *filename, byte *data,
562 				   int width, int height, byte *palette)
563 {
564 	int		i, j, length;
565 	pcx_t	*pcx;
566 	byte		*pack;
567 
568 	pcx = safe_malloc (width*height*2+1000);
569 	memset (pcx, 0, sizeof(*pcx));
570 
571 	pcx->manufacturer = 0x0a;	// PCX id
572 	pcx->version = 5;			// 256 color
573  	pcx->encoding = 1;		// uncompressed
574 	pcx->bits_per_pixel = 8;		// 256 color
575 	pcx->xmin = 0;
576 	pcx->ymin = 0;
577 	pcx->xmax = LittleShort((short)(width-1));
578 	pcx->ymax = LittleShort((short)(height-1));
579 	pcx->hres = LittleShort((short)width);
580 	pcx->vres = LittleShort((short)height);
581 	pcx->color_planes = 1;		// chunky image
582 	pcx->bytes_per_line = LittleShort((short)width);
583 	pcx->palette_type = LittleShort(1);		// not a grey scale
584 
585 	// pack the image
586 	pack = &pcx->data;
587 
588 	for (i=0 ; i<height ; i++)
589 	{
590 		for (j=0 ; j<width ; j++)
591 		{
592 			if ( (*data & 0xc0) != 0xc0)
593 				*pack++ = *data++;
594 			else
595 			{
596 				*pack++ = 0xc1;
597 				*pack++ = *data++;
598 			}
599 		}
600 	}
601 
602 	// write the palette
603 	*pack++ = 0x0c;	// palette ID byte
604 	for (i=0 ; i<768 ; i++)
605 		*pack++ = *palette++;
606 
607 // write output file
608 	length = pack - (byte *)pcx;
609 	SaveFile (filename, pcx, length);
610 
611 	free (pcx);
612 }
613 
614 /*
615 ============================================================================
616 
617 LOAD BMP
618 
619 ============================================================================
620 */
621 
622 
623 /*
624 
625 // we can't just use these structures, because
626 // compiler structure alignment will not be portable
627 // on this unaligned stuff
628 
629 typedef struct tagBITMAPFILEHEADER { // bmfh
630         WORD    bfType;				// BM
631         DWORD   bfSize;
632         WORD    bfReserved1;
633         WORD    bfReserved2;
634         DWORD   bfOffBits;
635 } BITMAPFILEHEADER;
636 
637 typedef struct tagBITMAPINFOHEADER{ // bmih
638    DWORD  biSize;
639    LONG   biWidth;
640    LONG   biHeight;
641    WORD   biPlanes;
642    WORD   biBitCount
643    DWORD  biCompression;
644    DWORD  biSizeImage;
645    LONG   biXPelsPerMeter;
646    LONG   biYPelsPerMeter;
647    DWORD  biClrUsed;
648    DWORD  biClrImportant;
649 } BITMAPINFOHEADER;
650 
651 typedef struct tagBITMAPINFO { // bmi
652    BITMAPINFOHEADER bmiHeader;
653    RGBQUAD          bmiColors[1];
654 } BITMAPINFO;
655 
656 typedef struct tagBITMAPCOREHEADER { // bmch
657         DWORD   bcSize;
658         WORD    bcWidth;
659         WORD    bcHeight;
660         WORD    bcPlanes;
661         WORD    bcBitCount;
662 } BITMAPCOREHEADER;
663 
664 typedef struct _BITMAPCOREINFO {    // bmci
665         BITMAPCOREHEADER  bmciHeader;
666         RGBTRIPLE         bmciColors[1];
667 } BITMAPCOREINFO;
668 
669 */
670 
671 /*
672 ==============
673 LoadBMP
674 ==============
675 */
LoadBMP(const char * filename,byte ** pic,byte ** palette,int * width,int * height)676 void LoadBMP (const char *filename, byte **pic, byte **palette, int *width, int *height)
677 {
678   byte	*out;
679   int		i;
680   int		bfSize;
681   int		bfOffBits;
682   int		structSize;
683   int		bcWidth;
684   int     bcHeight;
685   int	    bcPlanes;
686   int		bcBitCount;
687   byte	bcPalette[1024];
688   qboolean	flipped;
689   byte *in;
690   int len, pos = 0;
691 
692   len = vfsLoadFile (filename, (void **)&in, 0);
693   if (len == -1)
694   {
695     Error ("Couldn't read %s", filename);
696   }
697 
698   i = bufLittleShort (in, len, &pos);
699   if (i != 'B' + ('M'<<8) ) {
700     Error ("%s is not a bmp file", filename);
701   }
702 
703   bfSize = bufLittleLong (in, len, &pos);
704   bufLittleShort(in, len, &pos);
705   bufLittleShort(in, len, &pos);
706   bfOffBits = bufLittleLong (in, len, &pos);
707 
708   // the size will tell us if it is a
709   // bitmapinfo or a bitmapcore
710   structSize = bufLittleLong (in, len, &pos);
711   if (structSize == 40)
712   {
713     // bitmapinfo
714     bcWidth = bufLittleLong(in, len, &pos);
715     bcHeight= bufLittleLong(in, len, &pos);
716     bcPlanes = bufLittleShort(in, len, &pos);
717     bcBitCount = bufLittleShort(in, len, &pos);
718 
719     pos += 24;
720 
721     if (palette)
722     {
723       memcpy (bcPalette, in+pos, 1024);
724       pos += 1024;
725       *palette = safe_malloc(768);
726 
727       for (i = 0 ; i < 256 ; i++)
728       {
729         (*palette)[i * 3 + 0] = bcPalette[i * 4 + 2];
730         (*palette)[i * 3 + 1] = bcPalette[i * 4 + 1];
731         (*palette)[i * 3 + 2] = bcPalette[i * 4 + 0];
732       }
733     }
734   }
735   else if (structSize == 12)
736   {
737     // bitmapcore
738     bcWidth = bufLittleShort(in, len, &pos);
739     bcHeight= bufLittleShort(in, len, &pos);
740     bcPlanes = bufLittleShort(in, len, &pos);
741     bcBitCount = bufLittleShort(in, len, &pos);
742 
743     if (palette)
744     {
745       memcpy (bcPalette, in+pos, 768);
746       pos += 768;
747       *palette = safe_malloc(768);
748 
749       for (i = 0 ; i < 256 ; i++) {
750         (*palette)[i * 3 + 0] = bcPalette[i * 3 + 2];
751         (*palette)[i * 3 + 1] = bcPalette[i * 3 + 1];
752         (*palette)[i * 3 + 2] = bcPalette[i * 3 + 0];
753       }
754     }
755   } else {
756     Error ("%s had strange struct size", filename);
757   }
758 
759   if (bcPlanes != 1) {
760     Error ("%s was not a single plane image", filename);
761   }
762 
763   if (bcBitCount != 8) {
764     Error ("%s was not an 8 bit image", filename);
765   }
766 
767   if (bcHeight < 0) {
768     bcHeight = -bcHeight;
769     flipped = qtrue;
770   } else {
771     flipped = qfalse;
772   }
773 
774   if (width)
775     *width = bcWidth;
776   if (height)
777     *height = bcHeight;
778 
779   if (!pic) {
780     free (in);
781     return;
782   }
783 
784   out = safe_malloc ( bcWidth * bcHeight );
785   *pic = out;
786   pos = bfOffBits;
787 
788   if (flipped) {
789     for (i = 0 ; i < bcHeight ; i++) {
790       memcpy (out + bcWidth * (bcHeight - 1 - i), in+pos, bcWidth);
791       pos += bcWidth;
792     }
793   } else {
794     memcpy (out, in+pos, bcWidth*bcHeight);
795     pos += bcWidth*bcHeight;
796   }
797 
798   free (in);
799 }
800 
801 
802 /*
803 ============================================================================
804 
805 LOAD IMAGE
806 
807 ============================================================================
808 */
809 
810 /*
811 ==============
812 Load256Image
813 
814 Will load either an lbm or pcx, depending on extension.
815 Any of the return pointers can be NULL if you don't want them.
816 ==============
817 */
Load256Image(const char * name,byte ** pixels,byte ** palette,int * width,int * height)818 void Load256Image (const char *name, byte **pixels, byte **palette, int *width, int *height)
819 {
820   char ext[128];
821 
822   ExtractFileExtension (name, ext);
823   if (!Q_stricmp (ext, "lbm"))
824   {
825     LoadLBM (name, pixels, palette);
826     if (width)
827       *width = bmhd.w;
828     if (height)
829       *height = bmhd.h;
830   }
831   else if (!Q_stricmp (ext, "pcx"))
832   {
833     LoadPCX (name, pixels, palette, width, height);
834   }
835   else if (!Q_stricmp (ext, "bmp"))
836   {
837     LoadBMP (name, pixels, palette, width, height);
838   }
839   else
840     Error ("%s doesn't have a known image extension", name);
841 }
842 
843 
844 /*
845 ==============
846 Save256Image
847 
848 Will save either an lbm or pcx, depending on extension.
849 ==============
850 */
Save256Image(const char * name,byte * pixels,byte * palette,int width,int height)851 void Save256Image (const char *name, byte *pixels, byte *palette,
852 				   int width, int height)
853 {
854 	char	ext[128];
855 
856 	ExtractFileExtension (name, ext);
857 	if (!Q_stricmp (ext, "lbm"))
858 	{
859 		WriteLBMfile (name, pixels, width, height, palette);
860 	}
861 	else if (!Q_stricmp (ext, "pcx"))
862 	{
863 		WritePCXfile (name, pixels, width, height, palette);
864 	}
865 	else
866 		Error ("%s doesn't have a known image extension", name);
867 }
868 
869 
870 
871 
872 /*
873 ============================================================================
874 
875 TARGA IMAGE
876 
877 ============================================================================
878 */
879 
880 typedef struct _TargaHeader {
881 	unsigned char 	id_length, colormap_type, image_type;
882 	unsigned short	colormap_index, colormap_length;
883 	unsigned char	colormap_size;
884 	unsigned short	x_origin, y_origin, width, height;
885 	unsigned char	pixel_size, attributes;
886 } TargaHeader;
887 
TargaError(TargaHeader * t,const char * message)888 void TargaError(TargaHeader *t, const char *message)
889 {
890 	Sys_Printf("%s\n:TargaHeader:\nuint8 id_length = %i;\nuint8 colormap_type = %i;\nuint8 image_type = %i;\nuint16 colormap_index = %i;\nuint16 colormap_length = %i;\nuint8 colormap_size = %i;\nuint16 x_origin = %i;\nuint16 y_origin = %i;\nuint16 width = %i;\nuint16 height = %i;\nuint8 pixel_size = %i;\nuint8 attributes = %i;\n", message, t->id_length, t->colormap_type, t->image_type, t->colormap_index, t->colormap_length, t->colormap_size, t->x_origin, t->y_origin, t->width, t->height, t->pixel_size, t->attributes);
891 }
892 
893 /*
894 =============
895 LoadTGABuffer
896 =============
897 */
LoadTGABuffer(const byte * f,const byte * enddata,byte ** pic,int * width,int * height)898 void LoadTGABuffer (const byte *f, const byte *enddata, byte **pic, int *width, int *height)
899 {
900 	int x, y, row_inc, compressed, readpixelcount, red, green, blue, alpha, runlen, pindex, alphabits, image_width, image_height;
901 	byte *pixbuf, *image_rgba;
902 	const byte *fin;
903 	unsigned char *p;
904 	TargaHeader targa_header;
905 	unsigned char palette[256*4];
906 
907 	*pic = NULL;
908 
909 	// abort if it is too small to parse
910 	if (enddata - f < 19)
911 		return;
912 
913 	targa_header.id_length = f[0];
914 	targa_header.colormap_type = f[1];
915 	targa_header.image_type = f[2];
916 
917 	targa_header.colormap_index = f[3] + f[4] * 256;
918 	targa_header.colormap_length = f[5] + f[6] * 256;
919 	targa_header.colormap_size = f[7];
920 	targa_header.x_origin = f[8] + f[9] * 256;
921 	targa_header.y_origin = f[10] + f[11] * 256;
922 	targa_header.width = image_width = f[12] + f[13] * 256;
923 	targa_header.height = image_height = f[14] + f[15] * 256;
924 
925 	targa_header.pixel_size = f[16];
926 	targa_header.attributes = f[17];
927 
928 	// advance to end of header
929 	fin = f + 18;
930 
931 	// skip TARGA image comment (usually 0 bytes)
932 	fin += targa_header.id_length;
933 
934 	// read/skip the colormap if present (note: according to the TARGA spec it
935 	// can be present even on truecolor or greyscale images, just not used by
936 	// the image data)
937 	if (targa_header.colormap_type)
938 	{
939 		if (targa_header.colormap_length > 256)
940 		{
941 			TargaError(&targa_header, "LoadTGA: only up to 256 colormap_length supported\n");
942 			return;
943 		}
944 		if (targa_header.colormap_index)
945 		{
946 			TargaError(&targa_header, "LoadTGA: colormap_index not supported\n");
947 			return;
948 		}
949 		if (targa_header.colormap_size == 24)
950 		{
951 			for (x = 0;x < targa_header.colormap_length;x++)
952 			{
953 				palette[x*4+2] = *fin++;
954 				palette[x*4+1] = *fin++;
955 				palette[x*4+0] = *fin++;
956 				palette[x*4+3] = 255;
957 			}
958 		}
959 		else if (targa_header.colormap_size == 32)
960 		{
961 			for (x = 0;x < targa_header.colormap_length;x++)
962 			{
963 				palette[x*4+2] = *fin++;
964 				palette[x*4+1] = *fin++;
965 				palette[x*4+0] = *fin++;
966 				palette[x*4+3] = *fin++;
967 			}
968 		}
969 		else
970 		{
971 			TargaError(&targa_header, "LoadTGA: Only 32 and 24 bit colormap_size supported\n");
972 			return;
973 		}
974 	}
975 
976 	// check our pixel_size restrictions according to image_type
977 	if (targa_header.image_type == 2 || targa_header.image_type == 10)
978 	{
979 		if (targa_header.pixel_size != 24 && targa_header.pixel_size != 32)
980 		{
981 			TargaError(&targa_header, "LoadTGA: only 24bit and 32bit pixel sizes supported for type 2 and type 10 images\n");
982 			return;
983 		}
984 	}
985 	else if (targa_header.image_type == 1 || targa_header.image_type == 9)
986 	{
987 		if (targa_header.pixel_size != 8)
988 		{
989 			TargaError(&targa_header, "LoadTGA: only 8bit pixel size for type 1, 3, 9, and 11 images supported\n");
990 			return;
991 		}
992 	}
993 	else if (targa_header.image_type == 3 || targa_header.image_type == 11)
994 	{
995 		if (targa_header.pixel_size != 8)
996 		{
997 			TargaError(&targa_header, "LoadTGA: only 8bit pixel size for type 1, 3, 9, and 11 images supported\n");
998 			return;
999 		}
1000 	}
1001 	else
1002 	{
1003 		TargaError(&targa_header, "LoadTGA: Only type 1, 2, 3, 9, 10, and 11 targa RGB images supported");
1004 		return;
1005 	}
1006 
1007 	if (targa_header.attributes & 0x10)
1008 	{
1009 		TargaError(&targa_header, "LoadTGA: origin must be in top left or bottom left, top right and bottom right are not supported\n");
1010 		return;
1011 	}
1012 
1013 	// number of attribute bits per pixel, we only support 0 or 8
1014 	alphabits = targa_header.attributes & 0x0F;
1015 	if (alphabits != 8 && alphabits != 0)
1016 	{
1017 		TargaError(&targa_header, "LoadTGA: only 0 or 8 attribute (alpha) bits supported\n");
1018 		return;
1019 	}
1020 
1021 	image_rgba = safe_malloc(image_width * image_height * 4);
1022 	if (!image_rgba)
1023 	{
1024 		Sys_Printf("LoadTGA: not enough memory for %i by %i image\n", image_width, image_height);
1025 		return;
1026 	}
1027 
1028 	// If bit 5 of attributes isn't set, the image has been stored from bottom to top
1029 	if ((targa_header.attributes & 0x20) == 0)
1030 	{
1031 		pixbuf = image_rgba + (image_height - 1)*image_width*4;
1032 		row_inc = -image_width*4*2;
1033 	}
1034 	else
1035 	{
1036 		pixbuf = image_rgba;
1037 		row_inc = 0;
1038 	}
1039 
1040 	compressed = targa_header.image_type == 9 || targa_header.image_type == 10 || targa_header.image_type == 11;
1041 	x = 0;
1042 	y = 0;
1043 	red = green = blue = alpha = 255;
1044 	while (y < image_height)
1045 	{
1046 		// decoder is mostly the same whether it's compressed or not
1047 		readpixelcount = 1000000;
1048 		runlen = 1000000;
1049 		if (compressed && fin < enddata)
1050 		{
1051 			runlen = *fin++;
1052 			// high bit indicates this is an RLE compressed run
1053 			if (runlen & 0x80)
1054 				readpixelcount = 1;
1055 			runlen = 1 + (runlen & 0x7f);
1056 		}
1057 
1058 		while((runlen--) && y < image_height)
1059 		{
1060 			if (readpixelcount > 0)
1061 			{
1062 				readpixelcount--;
1063 				red = green = blue = alpha = 255;
1064 				if (fin < enddata)
1065 				{
1066 					switch(targa_header.image_type)
1067 					{
1068 					case 1:
1069 					case 9:
1070 						// colormapped
1071 						pindex = *fin++;
1072 						if (pindex >= targa_header.colormap_length)
1073 							pindex = 0; // error
1074 						p = palette + pindex * 4;
1075 						red = p[0];
1076 						green = p[1];
1077 						blue = p[2];
1078 						alpha = p[3];
1079 						break;
1080 					case 2:
1081 					case 10:
1082 						// BGR or BGRA
1083 						blue = *fin++;
1084 						if (fin < enddata)
1085 							green = *fin++;
1086 						if (fin < enddata)
1087 							red = *fin++;
1088 						if (targa_header.pixel_size == 32 && fin < enddata)
1089 							alpha = *fin++;
1090 						break;
1091 					case 3:
1092 					case 11:
1093 						// greyscale
1094 						red = green = blue = *fin++;
1095 						break;
1096 					}
1097 					if (!alphabits)
1098 						alpha = 255;
1099 				}
1100 			}
1101 			*pixbuf++ = red;
1102 			*pixbuf++ = green;
1103 			*pixbuf++ = blue;
1104 			*pixbuf++ = alpha;
1105 			x++;
1106 			if (x == image_width)
1107 			{
1108 				// end of line, advance to next
1109 				x = 0;
1110 				y++;
1111 				pixbuf += row_inc;
1112 			}
1113 		}
1114 	}
1115 
1116 	*pic = image_rgba;
1117 	if (width)
1118 		*width = image_width;
1119 	if (height)
1120 		*height = image_height;
1121 }
1122 
1123 
1124 /*
1125 =============
1126 LoadTGA
1127 =============
1128 */
LoadTGA(const char * name,byte ** pixels,int * width,int * height)1129 void LoadTGA (const char *name, byte **pixels, int *width, int *height)
1130 {
1131 	byte			*buffer;
1132 	int nLen;
1133 	//
1134 	// load the file
1135 	//
1136 	nLen = vfsLoadFile ( ( char * ) name, (void **)&buffer, 0);
1137 	if (nLen == -1)
1138 	{
1139 		Error ("Couldn't read %s", name);
1140 	}
1141 
1142 	LoadTGABuffer(buffer, buffer + nLen, pixels, width, height);
1143 
1144 }
1145 
1146 
1147 /*
1148 ================
1149 WriteTGA
1150 ================
1151 */
WriteTGA(const char * filename,byte * data,int width,int height)1152 void WriteTGA (const char *filename, byte *data, int width, int height) {
1153 	byte	*buffer;
1154 	int		i;
1155 	int		c;
1156 	FILE	*f;
1157 
1158 	buffer = safe_malloc(width*height*4 + 18);
1159 	memset (buffer, 0, 18);
1160 	buffer[2] = 2;		// uncompressed type
1161 	buffer[12] = width&255;
1162 	buffer[13] = width>>8;
1163 	buffer[14] = height&255;
1164 	buffer[15] = height>>8;
1165 	buffer[16] = 32;	// pixel size
1166 
1167 	// swap rgb to bgr
1168 	c = 18 + width * height * 4;
1169 	for (i=18 ; i<c ; i+=4)
1170 	{
1171 		buffer[i] = data[i-18+2];		// blue
1172 		buffer[i+1] = data[i-18+1];		// green
1173 		buffer[i+2] = data[i-18+0];		// red
1174 		buffer[i+3] = data[i-18+3];		// alpha
1175 	}
1176 
1177 	f = fopen (filename, "wb");
1178 	fwrite (buffer, 1, c, f);
1179 	fclose (f);
1180 
1181 	free (buffer);
1182 }
1183 
1184 /*
1185 ============================================================================
1186 
1187 LOAD32BITIMAGE
1188 
1189 ============================================================================
1190 */
1191 
1192 /*
1193 ==============
1194 Load32BitImage
1195 
1196 Any of the return pointers can be NULL if you don't want them.
1197 ==============
1198 */
Load32BitImage(const char * name,unsigned ** pixels,int * width,int * height)1199 void Load32BitImage (const char *name, unsigned **pixels,  int *width, int *height)
1200 {
1201 	char	ext[128];
1202 	byte	*palette;
1203 	byte	*pixels8;
1204 	byte	*pixels32;
1205 	int		size;
1206 	int		i;
1207 	int		v;
1208 
1209 	ExtractFileExtension (name, ext);
1210 	if (!Q_stricmp (ext, "tga")) {
1211 		LoadTGA (name, (byte **)pixels, width, height);
1212 	} else {
1213 		Load256Image (name, &pixels8, &palette, width, height);
1214 		if (!pixels) {
1215 			return;
1216 		}
1217 		size = *width * *height;
1218 		pixels32 = safe_malloc(size * 4);
1219 		*pixels = (unsigned *)pixels32;
1220 		for (i = 0 ; i < size ; i++) {
1221 			v = pixels8[i];
1222 			pixels32[i*4 + 0] = palette[ v * 3 + 0 ];
1223 			pixels32[i*4 + 1] = palette[ v * 3 + 1 ];
1224 			pixels32[i*4 + 2] = palette[ v * 3 + 2 ];
1225 			pixels32[i*4 + 3] = 0xff;
1226 		}
1227 	}
1228 }
1229 
1230 
1231