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