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