1 /*
2 Copyright (C) 2003-2006 Andrey Nazarov
3 Copyright (C) 1997-2001 Id Software, Inc.
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
14 See the GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 */
21
22 //
23 // images.c -- image reading and writing functions
24 //
25
26 #ifdef USE_LIBPNG
27 #include <png.h>
28 #endif
29
30 #ifdef USE_LIBJPEG
31 #ifndef USE_LIBPNG
32 #include <setjmp.h>
33 #endif
34 #include <jpeglib.h>
35 #endif
36
37 #include "q_shared.h"
38 #include "com_public.h"
39 #include "qfiles.h"
40 #include "q_list.h"
41 #include "r_shared.h"
42
43 /*
44 =================================================================
45
46 PCX LOADING
47
48 =================================================================
49 */
50
51
52 /*
53 ==============
54 Image_LoadPCX
55 ==============
56 */
57
Image_LoadPCX(const char * filename,byte ** pic,byte * palette,int * width,int * height)58 void Image_LoadPCX( const char *filename, byte **pic, byte *palette, int *width, int *height ) {
59 byte *raw, *end;
60 pcx_t *pcx;
61 uint32 x, y, w, h;
62 int len;
63 int dataByte, runLength;
64 byte *out, *pix;
65
66 if( !filename || !pic ) {
67 Com_Error( ERR_FATAL, "LoadPCX: NULL" );
68 }
69
70 *pic = NULL;
71
72 //
73 // load the file
74 //
75 len = fs.LoadFile( filename, (void **)&raw );
76 if( !raw ) {
77 return;
78 }
79
80 //
81 // parse the PCX file
82 //
83 pcx = (pcx_t *)raw;
84
85 w = LittleShort( pcx->xmax ) + 1;
86 h = LittleShort( pcx->ymax ) + 1;
87
88 if( pcx->manufacturer != 0x0a
89 || pcx->version != 5
90 || pcx->encoding != 1
91 || pcx->bits_per_pixel != 8
92 || w > 640
93 || h > 480 )
94 {
95 Com_WPrintf( "LoadPCX: %s: unsupported format\n", filename );
96 return;
97 }
98
99 pix = out = R_Malloc ( w * h );
100
101 if( palette ) {
102 if( len < 768 ) {
103 goto malformed;
104 }
105 memcpy( palette, ( byte * )pcx + len - 768, 768 );
106 }
107
108 raw = &pcx->data;
109 end = ( byte * )pcx + len;
110
111 for( y = 0; y < h; y++, pix += w ) {
112 for( x = 0; x < w; ) {
113 if( raw == end ) {
114 goto malformed;
115 }
116 dataByte = *raw++;
117
118 if( ( dataByte & 0xC0 ) == 0xC0 ) {
119 runLength = dataByte & 0x3F;
120 if( x + runLength > w ) {
121 goto malformed;
122 }
123 if( raw == end ) {
124 goto malformed;
125 }
126 dataByte = *raw++;
127 while( runLength-- ) {
128 pix[x++] = dataByte;
129 }
130 } else {
131 pix[x++] = dataByte;
132 }
133
134 }
135
136 }
137
138 if( width )
139 *width = w;
140 if( height )
141 *height = h;
142
143 *pic = out;
144
145 fs.FreeFile( pcx );
146 return;
147
148 malformed:
149 Com_WPrintf( "LoadPCX: %s: file was malformed\n", filename );
150 com.Free( out );
151 fs.FreeFile( pcx );
152 }
153
154 #ifdef TRUECOLOR_RENDERER
155
156 /*
157 =========================================================
158
159 TARGA LOADING
160
161 =========================================================
162 */
163
164 #pragma pack(push,1)
165
166 typedef struct _TargaHeader {
167 uint8 id_length, colormap_type, image_type;
168 uint16 colormap_index, colormap_length;
169 uint8 colormap_size;
170 uint16 x_origin, y_origin, width, height;
171 uint8 pixel_size, attributes;
172 } TargaHeader;
173
174 #pragma pack(pop)
175
tga_decode_bgr(byte * data,byte * pixels,int columns,int rows,byte * maxp)176 static qboolean tga_decode_bgr( byte *data, byte *pixels,
177 int columns, int rows, byte *maxp )
178 {
179 int col, row;
180 uint32 *pixbuf;
181
182 for( row = rows - 1; row >= 0; row-- ) {
183 pixbuf = ( uint32 * )pixels + row * columns;
184
185 for( col = 0; col < columns; col++ ) {
186 *pixbuf++ = MakeColor( data[2], data[1], data[0], 255 );
187 data += 3;
188 }
189 }
190
191 return qtrue;
192 }
193
tga_decode_bgra(byte * data,byte * pixels,int columns,int rows,byte * maxp)194 static qboolean tga_decode_bgra( byte *data, byte *pixels,
195 int columns, int rows, byte *maxp )
196 {
197 int col, row;
198 uint32 *pixbuf;
199
200 for( row = rows - 1; row >= 0; row-- ) {
201 pixbuf = ( uint32 * )pixels + row * columns;
202
203 for( col = 0; col < columns; col++ ) {
204 *pixbuf++ = MakeColor( data[2], data[1], data[0], data[3] );
205 data += 4;
206 }
207 }
208
209 return qtrue;
210 }
211
tga_decode_bgr_flip(byte * data,byte * pixels,int columns,int rows,byte * maxp)212 static qboolean tga_decode_bgr_flip( byte *data, byte *pixels,
213 int columns, int rows, byte *maxp )
214 {
215 int count;
216 uint32 *pixbuf;
217
218 pixbuf = ( uint32 * )pixels;
219 count = rows * columns;
220 do {
221 *pixbuf++ = MakeColor( data[2], data[1], data[0], 255 );
222 data += 3;
223 } while( --count );
224
225 return qtrue;
226 }
227
tga_decode_bgra_flip(byte * data,byte * pixels,int columns,int rows,byte * maxp)228 static qboolean tga_decode_bgra_flip( byte *data, byte *pixels,
229 int columns, int rows, byte *maxp )
230 {
231 int count;
232 uint32 *pixbuf;
233
234 pixbuf = ( uint32 * )pixels;
235 count = rows * columns;
236 do {
237 *pixbuf++ = MakeColor( data[2], data[1], data[0], data[3] );
238 data += 4;
239 } while( --count );
240
241 return qtrue;
242 }
243
tga_decode_bgr_rle(byte * data,byte * pixels,int columns,int rows,byte * maxp)244 static qboolean tga_decode_bgr_rle( byte *data, byte *pixels,
245 int columns, int rows, byte *maxp )
246 {
247 int col, row;
248 uint32 *pixbuf, color;
249 byte packetHeader, packetSize;
250 int j;
251
252 for( row = rows - 1; row >= 0; row-- ) {
253 pixbuf = ( uint32 * )pixels + row * columns;
254
255 for( col = 0; col < columns; ) {
256 packetHeader = *data++;
257 packetSize = 1 + ( packetHeader & 0x7f );
258
259 if( packetHeader & 0x80 ) {
260 /* run-length packet */
261 if( data + 3 > maxp ) {
262 return qfalse;
263 }
264 color = MakeColor(
265 data[2],
266 data[1],
267 data[0],
268 255 );
269 data += 3;
270 for( j = 0; j < packetSize; j++ ) {
271 *pixbuf++ = color;
272
273 col++;
274 if( col == columns ) {
275 /* run spans across rows */
276 col = 0;
277
278 if( row > 0 )
279 row--;
280 else
281 goto breakOut;
282
283 pixbuf = ( uint32 * )pixels + row * columns;
284 }
285 }
286 } else {
287 /* non run-length packet */
288 if( data + 3 * packetSize > maxp ) {
289 return qfalse;
290 }
291 for( j = 0; j < packetSize; j++ ) {
292 *pixbuf++ = MakeColor(
293 data[2],
294 data[1],
295 data[0],
296 255 );
297 data += 3;
298
299 col++;
300 if( col == columns ) {
301 /* run spans across rows */
302 col = 0;
303 if( row > 0 )
304 row--;
305 else
306 goto breakOut;
307 pixbuf = ( uint32 * )pixels + row * columns;
308 }
309 }
310 }
311 }
312 breakOut: ;
313
314 }
315
316 return qtrue;
317
318 }
319
tga_decode_bgra_rle(byte * data,byte * pixels,int columns,int rows,byte * maxp)320 static qboolean tga_decode_bgra_rle( byte *data, byte *pixels,
321 int columns, int rows, byte *maxp )
322 {
323 int col, row;
324 uint32 *pixbuf, color;
325 byte packetHeader, packetSize;
326 int j;
327
328 for( row = rows - 1; row >= 0; row-- ) {
329 pixbuf = ( uint32 * )pixels + row * columns;
330
331 for( col = 0; col < columns; ) {
332 packetHeader = *data++;
333 packetSize = 1 + ( packetHeader & 0x7f );
334
335 if( packetHeader & 0x80 ) {
336 /* run-length packet */
337 if( data + 4 > maxp ) {
338 return qfalse;
339 }
340 color = MakeColor(
341 data[2],
342 data[1],
343 data[0],
344 data[3] );
345 data += 4;
346 for( j = 0; j < packetSize; j++ ) {
347 *pixbuf++ = color;
348
349 col++;
350 if( col == columns ) {
351 /* run spans across rows */
352 col = 0;
353
354 if( row > 0 )
355 row--;
356 else
357 goto breakOut;
358
359 pixbuf = ( uint32 * )pixels + row * columns;
360 }
361 }
362 } else {
363 /* non run-length packet */
364 if( data + 4 * packetSize > maxp ) {
365 return qfalse;
366 }
367 for( j = 0; j < packetSize; j++ ) {
368 *pixbuf++ = MakeColor(
369 data[2],
370 data[1],
371 data[0],
372 data[3] );
373 data += 4;
374
375 col++;
376 if( col == columns ) {
377 /* run spans across rows */
378 col = 0;
379 if( row > 0 )
380 row--;
381 else
382 goto breakOut;
383 pixbuf = ( uint32 * )pixels + row * columns;
384 }
385 }
386 }
387 }
388 breakOut: ;
389
390 }
391
392 return qtrue;
393
394 }
395
396 /*
397 =============
398 LoadTGA
399 =============
400 */
Image_LoadTGA(const char * filename,byte ** pic,int * width,int * height)401 void Image_LoadTGA( const char *filename, byte **pic,
402 int *width, int *height )
403 {
404 byte *buffer;
405 int length;
406 TargaHeader *targa_header;
407 byte *pixels;
408 int offset, w, h;
409 qboolean (*decode)( byte *, byte *, int, int, byte * );
410 int imageType, pixelSize, bytesPerPixel;
411
412 if( !filename || !pic ) {
413 Com_Error( ERR_FATAL, "LoadTGA: NULL" );
414 }
415
416 *pic = NULL;
417
418 //
419 // load the file
420 //
421 length = fs.LoadFile( filename, ( void ** )&buffer );
422 if( !buffer ) {
423 return;
424 }
425
426 if( length < sizeof( *targa_header ) ) {
427 Com_WPrintf( "LoadTGA: %s: invalid targa header\n",
428 filename );
429 goto finish;
430 }
431
432 targa_header = ( TargaHeader * )buffer;
433
434 /* skip TARGA image comment */
435 offset = sizeof( *targa_header ) + targa_header->id_length;
436 if( offset + 4 > length ) {
437 Com_WPrintf( "LoadTGA: %s: malformed targa image\n",
438 filename );
439 goto finish;
440 }
441
442 imageType = targa_header->image_type;
443 pixelSize = targa_header->pixel_size;
444
445 if( pixelSize == 32 ) {
446 bytesPerPixel = 4;
447 } else if( pixelSize == 24 ) {
448 bytesPerPixel = 3;
449 } else {
450 Com_WPrintf(
451 "LoadTGA: %s: only 32 and 24 bit targa RGB "
452 "images supported, this one is %d bit\n",
453 filename, pixelSize );
454 goto finish;
455 }
456
457 w = LittleShort( targa_header->width );
458 h = LittleShort( targa_header->height );
459 if( !w || !h || w > MAX_TEXTURE_SIZE || h > MAX_TEXTURE_SIZE ) {
460 Com_WPrintf(
461 "LoadTGA: %s: has invalid dimensions: %dx%d\n",
462 filename, w, h );
463 goto finish;
464 }
465
466 if( imageType == 2 ) {
467 if( offset + w * h * bytesPerPixel > length ) {
468 Com_WPrintf(
469 "LoadTGA: %s: malformed targa image\n", filename );
470 goto finish;
471 }
472 if( targa_header->attributes & 32 ) {
473 if( pixelSize == 32 ) {
474 decode = tga_decode_bgra_flip;
475 } else {
476 decode = tga_decode_bgr_flip;
477 }
478 } else {
479 if( pixelSize == 32 ) {
480 decode = tga_decode_bgra;
481 } else {
482 decode = tga_decode_bgr;
483 }
484 }
485 } else if( imageType == 10 ) {
486 if( targa_header->attributes & 32 ) {
487 Com_WPrintf(
488 "LoadTGA: %s: vertically flipped, RLE encoded "
489 "images are not supported\n",
490 filename );
491 goto finish;
492 }
493 if( pixelSize == 32 ) {
494 decode = tga_decode_bgra_rle;
495 } else {
496 decode = tga_decode_bgr_rle;
497 }
498 } else {
499 Com_WPrintf(
500 "LoadTGA: %s: only type 2 and 10 targa RGB "
501 "images supported, this one is %d\n",
502 filename, imageType );
503 goto finish;
504 }
505
506 pixels = R_Malloc( w * h * 4 );
507
508 if( (*decode)( buffer + offset, pixels, w, h, buffer + length ) == qfalse ) {
509 com.Free( pixels );
510 goto finish;
511 }
512
513 *pic = pixels;
514 *width = w;
515 *height = h;
516
517 finish:
518 fs.FreeFile( buffer );
519 }
520
521 /*
522 =========================================================
523
524 TARGA WRITING
525
526 =========================================================
527 */
528
529 /*
530 =================
531 Image_WriteTGA
532 =================
533 */
Image_WriteTGA(const char * filename,const byte * bgr,int width,int height)534 qboolean Image_WriteTGA( const char *filename, const byte *bgr,
535 int width, int height )
536 {
537 int length;
538 fileHandle_t f;
539 TargaHeader header;
540
541 fs.FOpenFile( filename, &f, FS_MODE_WRITE );
542 if( !f ) {
543 return qfalse;
544 }
545
546 memset( &header, 0, sizeof( header ) );
547 header.image_type = 2; /* uncompressed type */
548 header.width = LittleShort( width );
549 header.height = LittleShort( height );
550 header.pixel_size = 24; /* pixel size */
551 if( fs.Write( &header, sizeof( header ), f ) != sizeof( header ) ) {
552 goto fail;
553 }
554
555 length = width * height * 3;
556 if( fs.Write( bgr, length, f ) != length ) {
557 goto fail;
558 }
559
560 fs.FCloseFile( f );
561 return qtrue;
562
563 fail:
564 fs.FCloseFile( f );
565 return qfalse;
566 }
567
568
569 /*
570 =========================================================
571
572 JPEG LOADING
573
574 =========================================================
575 */
576
577 #ifdef USE_LIBJPEG
578
579 typedef struct my_error_mgr {
580 struct jpeg_error_mgr pub;
581 jmp_buf setjmp_buffer;
582 } *my_error_ptr;
583
my_error_exit(j_common_ptr cinfo)584 METHODDEF( void )my_error_exit( j_common_ptr cinfo ) {
585 my_error_ptr myerr = ( my_error_ptr )cinfo->err;
586
587 (*cinfo->err->output_message)( cinfo );
588
589 longjmp( myerr->setjmp_buffer, 1 );
590 }
591
592
mem_init_source(j_decompress_ptr cinfo)593 METHODDEF( void ) mem_init_source( j_decompress_ptr cinfo ) { }
594
mem_fill_input_buffer(j_decompress_ptr cinfo)595 METHODDEF( boolean ) mem_fill_input_buffer( j_decompress_ptr cinfo ) {
596 my_error_ptr jerr = ( my_error_ptr )cinfo->err;
597
598 longjmp( jerr->setjmp_buffer, 1 );
599 return TRUE;
600 }
601
602
mem_skip_input_data(j_decompress_ptr cinfo,long num_bytes)603 METHODDEF( void ) mem_skip_input_data( j_decompress_ptr cinfo, long num_bytes ) {
604 struct jpeg_source_mgr *src = cinfo->src;
605 my_error_ptr jerr = ( my_error_ptr )cinfo->err;
606
607 if( src->bytes_in_buffer < num_bytes ) {
608 longjmp( jerr->setjmp_buffer, 1 );
609 }
610
611 src->next_input_byte += ( size_t )num_bytes;
612 src->bytes_in_buffer -= ( size_t )num_bytes;
613 }
614
mem_term_source(j_decompress_ptr cinfo)615 METHODDEF( void ) mem_term_source( j_decompress_ptr cinfo ) { }
616
617
local_jpeg_mem_src(j_decompress_ptr cinfo,byte * memory,int size)618 METHODDEF( void ) local_jpeg_mem_src( j_decompress_ptr cinfo, byte *memory, int size ) {
619 cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small)( ( j_common_ptr )cinfo, JPOOL_PERMANENT, sizeof( struct jpeg_source_mgr ) );
620
621 cinfo->src->init_source = mem_init_source;
622 cinfo->src->fill_input_buffer = mem_fill_input_buffer;
623 cinfo->src->skip_input_data = mem_skip_input_data;
624 cinfo->src->resync_to_restart = jpeg_resync_to_restart;
625 cinfo->src->term_source = mem_term_source;
626 cinfo->src->bytes_in_buffer = size;
627 cinfo->src->next_input_byte = memory;
628 }
629
630 /*
631 =================
632 LoadJPG
633 =================
634 */
Image_LoadJPG(const char * filename,byte ** pic,int * width,int * height)635 void Image_LoadJPG( const char *filename, byte **pic, int *width, int *height ) {
636 struct jpeg_decompress_struct cinfo;
637 struct my_error_mgr jerr;
638 JSAMPARRAY buffer;
639 int row_stride;
640 byte *rawdata;
641 int rawlength;
642 byte *pixels;
643 byte *src, *dest;
644 int i;
645
646 if( !filename || !pic ) {
647 Com_Error( ERR_FATAL, "LoadJPG: NULL" );
648 }
649
650 *pic = NULL;
651 pixels = NULL;
652
653 rawlength = fs.LoadFile( filename, ( void ** )&rawdata );
654 if( !rawdata ) {
655 return;
656 }
657
658 if( rawlength < 10 || *( uint32 * )( rawdata + 6 ) != MakeLittleLong( 'J', 'F', 'I', 'F' ) ) {
659 Com_WPrintf( "LoadJPG: %s: not a valid JPEG file\n", filename );
660 fs.FreeFile( rawdata );
661 return;
662 }
663
664 cinfo.err = jpeg_std_error( &jerr.pub );
665 jerr.pub.error_exit = my_error_exit;
666
667 jpeg_create_decompress( &cinfo );
668
669 if( setjmp( jerr.setjmp_buffer ) ) {
670 Com_WPrintf( "LoadJPG: %s: JPEGLIB signaled an error\n", filename );
671 jpeg_destroy_decompress( &cinfo );
672 if( pixels ) {
673 com.Free( pixels );
674 pixels = NULL;
675 }
676 fs.FreeFile( rawdata );
677 return;
678 }
679
680 local_jpeg_mem_src( &cinfo, rawdata, rawlength );
681 jpeg_read_header( &cinfo, TRUE );
682 jpeg_start_decompress( &cinfo );
683
684 if( cinfo.output_components != 3 /*&& cinfo.output_components != 4*/ ) {
685 Com_WPrintf( "LoadJPG: %s: unsupported number of color components: %i\n",
686 filename, cinfo.output_components );
687 jpeg_destroy_decompress( &cinfo );
688 fs.FreeFile( rawdata );
689 return;
690 }
691
692 *width = cinfo.output_width;
693 *height = cinfo.output_height;
694
695 pixels = R_Malloc( cinfo.output_width * cinfo.output_height * 4 );
696
697 row_stride = cinfo.output_width * cinfo.output_components;
698
699 buffer = (*cinfo.mem->alloc_sarray)( ( j_common_ptr )&cinfo, JPOOL_IMAGE, row_stride, 1 );
700
701 dest = pixels;
702 while( cinfo.output_scanline < cinfo.output_height ) {
703 jpeg_read_scanlines( &cinfo, buffer, 1 );
704
705 src = ( byte * )buffer[0];
706 for( i = 0; i < cinfo.output_width; i++ ) {
707 *( uint32 * )dest = MakeColor( src[0], src[1], src[2], 255 );
708 src += 3;
709 dest += 4;
710 }
711 }
712
713 jpeg_finish_decompress( &cinfo );
714 jpeg_destroy_decompress( &cinfo );
715
716 fs.FreeFile( rawdata );
717
718 *pic = pixels;
719
720 }
721
722 /*
723 =========================================================
724
725 JPEG WRITING
726
727 =========================================================
728 */
729
730 #define OUTPUT_BUF_SIZE 4096
731
732 typedef struct my_destination_mgr {
733 struct jpeg_destination_mgr pub; /* public fields */
734
735 fileHandle_t hFile; /* target stream */
736 JOCTET *buffer; /* start of buffer */
737 } *my_dest_ptr;
738
739
vfs_init_destination(j_compress_ptr cinfo)740 METHODDEF( void ) vfs_init_destination( j_compress_ptr cinfo ) {
741 my_dest_ptr dest = ( my_dest_ptr )cinfo->dest;
742
743 /* Allocate the output buffer --- it will be released when done with image */
744 dest->buffer = ( JOCTET * )(*cinfo->mem->alloc_small)( ( j_common_ptr )cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE * sizeof( JOCTET ) );
745
746 dest->pub.next_output_byte = dest->buffer;
747 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
748 }
749
vfs_empty_output_buffer(j_compress_ptr cinfo)750 METHODDEF( boolean ) vfs_empty_output_buffer( j_compress_ptr cinfo ) {
751 my_dest_ptr dest = ( my_dest_ptr )cinfo->dest;
752 my_error_ptr jerr = ( my_error_ptr )cinfo->err;
753
754 if( fs.Write( dest->buffer, OUTPUT_BUF_SIZE, dest->hFile ) != OUTPUT_BUF_SIZE ) {
755 longjmp( jerr->setjmp_buffer, 1 );
756 }
757
758 dest->pub.next_output_byte = dest->buffer;
759 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
760
761 return TRUE;
762
763 }
764
vfs_term_destination(j_compress_ptr cinfo)765 METHODDEF( void ) vfs_term_destination( j_compress_ptr cinfo ) {
766 my_dest_ptr dest = ( my_dest_ptr )cinfo->dest;
767 my_error_ptr jerr = ( my_error_ptr )cinfo->err;
768 int remaining = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
769
770 /* Write any data remaining in the buffer */
771 if( remaining > 0 ) {
772 if( fs.Write( dest->buffer, remaining, dest->hFile ) != remaining ) {
773 longjmp( jerr->setjmp_buffer, 1 );
774 }
775 }
776
777 }
778
779
jpeg_vfs_dst(j_compress_ptr cinfo,fileHandle_t hFile)780 METHODDEF( void ) jpeg_vfs_dst( j_compress_ptr cinfo, fileHandle_t hFile ) {
781 my_dest_ptr dest;
782
783 dest = ( my_dest_ptr )(*cinfo->mem->alloc_small)( ( j_common_ptr )cinfo, JPOOL_PERMANENT, sizeof( struct my_destination_mgr ) );
784 cinfo->dest = &dest->pub;
785
786 dest->pub.init_destination = vfs_init_destination;
787 dest->pub.empty_output_buffer = vfs_empty_output_buffer;
788 dest->pub.term_destination = vfs_term_destination;
789 dest->hFile = hFile;
790
791 }
792
793 /*
794 =================
795 Image_WriteJPG
796 =================
797 */
Image_WriteJPG(const char * filename,const byte * rgb,int width,int height,int quality)798 qboolean Image_WriteJPG( const char *filename, const byte *rgb, int width, int height, int quality ) {
799 struct jpeg_compress_struct cinfo;
800 struct my_error_mgr jerr;
801 fileHandle_t hFile;
802 JSAMPROW row_pointer[1];
803 int row_stride;
804
805 fs.FOpenFile( filename, &hFile, FS_MODE_WRITE );
806 if( !hFile ) {
807 Com_DPrintf( "WriteJPG: %s: couldn't create file\n", filename );
808 return qfalse;
809 }
810
811 cinfo.err = jpeg_std_error( &jerr.pub );
812 jerr.pub.error_exit = my_error_exit;
813
814 if( _setjmp( jerr.setjmp_buffer ) ) {
815 Com_DPrintf( "WriteJPG: %s: JPEGLIB signaled an error\n", filename );
816 jpeg_destroy_compress( &cinfo );
817 fs.FCloseFile( hFile );
818 return qfalse;
819 }
820
821 jpeg_create_compress( &cinfo );
822
823 jpeg_vfs_dst( &cinfo, hFile );
824
825 cinfo.image_width = width; // image width and height, in pixels
826 cinfo.image_height = height;
827 cinfo.input_components = 3; // # of color components per pixel
828 cinfo.in_color_space = JCS_RGB; // colorspace of input image
829
830 clamp( quality, 0, 100 );
831
832 jpeg_set_defaults( &cinfo );
833 jpeg_set_quality( &cinfo, quality, TRUE );
834
835 jpeg_start_compress( &cinfo, TRUE );
836
837 row_stride = width * 3; // JSAMPLEs per row in image_buffer
838
839 while( cinfo.next_scanline < cinfo.image_height ) {
840 row_pointer[0] = ( byte * )( &rgb[( cinfo.image_height - cinfo.next_scanline - 1 ) * row_stride] );
841 jpeg_write_scanlines( &cinfo, row_pointer, 1 );
842 }
843
844 jpeg_finish_compress( &cinfo );
845 fs.FCloseFile( hFile );
846
847 jpeg_destroy_compress( &cinfo );
848
849 return qtrue;
850 }
851
852 #endif /* USE_LIBJPEG */
853
854
855 #ifdef USE_LIBPNG
856
857 /*
858 =========================================================
859
860 PNG LOADING
861
862 =========================================================
863 */
864
865 typedef struct {
866 byte *data;
867 byte *maxp;
868 } pngReadStruct;
869
png_vfs_read_fn(png_structp png_ptr,png_bytep buf,png_size_t size)870 static void png_vfs_read_fn( png_structp png_ptr, png_bytep buf, png_size_t size ) {
871 pngReadStruct *r = png_get_io_ptr( png_ptr );
872
873 if( r->data + size > r->maxp ) {
874 size = r->maxp - r->data;
875 }
876 memcpy( buf, r->data, size );
877 r->data += size;
878 }
879
png_console_error_fn(png_structp png_ptr,png_const_charp error_msg)880 static void png_console_error_fn( png_structp png_ptr, png_const_charp error_msg ) {
881 char *f = png_get_error_ptr( png_ptr );
882
883 Com_EPrintf( "LoadPNG: %s: %s\n", f, error_msg );
884 longjmp( png_jmpbuf( png_ptr ), -1 );
885 }
886
png_console_warning_fn(png_structp png_ptr,png_const_charp warning_msg)887 static void png_console_warning_fn( png_structp png_ptr, png_const_charp warning_msg ) {
888 char *f = png_get_error_ptr( png_ptr );
889
890 Com_WPrintf( "LoadPNG: %s: %s\n", f, warning_msg );
891 }
892
893 /*
894 =================
895 LoadPNG
896 =================
897 */
Image_LoadPNG(const char * filename,byte ** pic,int * width,int * height)898 void Image_LoadPNG( const char *filename, byte **pic, int *width, int *height ) {
899 byte *rawdata;
900 int rawlength;
901 byte *pixels;
902 byte *row_pointers[MAX_TEXTURE_SIZE];
903 png_uint_32 w, h, rowbytes, row;
904 int bitdepth, colortype;
905 png_structp png_ptr;
906 png_infop info_ptr;
907 pngReadStruct r;
908
909 if( !filename || !pic ) {
910 Com_Error( ERR_FATAL, "LoadPNG: NULL" );
911 }
912
913 *pic = NULL;
914 pixels = NULL;
915
916 rawlength = fs.LoadFile( filename, ( void ** )&rawdata );
917 if( !rawdata ) {
918 return;
919 }
920
921 png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING,
922 ( png_voidp )filename, png_console_error_fn, png_console_warning_fn );
923 if( !png_ptr ) {
924 goto fail;
925 }
926
927 info_ptr = png_create_info_struct( png_ptr );
928 if( !info_ptr ) {
929 png_destroy_read_struct( &png_ptr, NULL, NULL );
930 goto fail;
931 }
932
933 if( setjmp( png_jmpbuf( png_ptr ) ) ) {
934 png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
935 goto fail;
936 }
937
938 r.data = rawdata;
939 r.maxp = rawdata + rawlength;
940 png_set_read_fn( png_ptr, ( png_voidp )&r, png_vfs_read_fn );
941
942 png_read_info( png_ptr, info_ptr );
943
944 if( !png_get_IHDR( png_ptr, info_ptr, &w, &h, &bitdepth, &colortype,
945 NULL, NULL, NULL ) )
946 {
947 png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
948 goto fail;
949 }
950
951 if( w > MAX_TEXTURE_SIZE || h > MAX_TEXTURE_SIZE ) {
952 Com_EPrintf( "LoadPNG: %s: oversize image dimensions: %lux%lu\n",
953 filename, w, h );
954 png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
955 goto fail;
956 }
957
958 switch( colortype ) {
959 case PNG_COLOR_TYPE_PALETTE:
960 png_set_palette_to_rgb( png_ptr );
961 break;
962 case PNG_COLOR_TYPE_GRAY:
963 if( bitdepth < 8 ) {
964 png_set_expand_gray_1_2_4_to_8( png_ptr );
965 }
966 // fall through
967 case PNG_COLOR_TYPE_GRAY_ALPHA:
968 png_set_gray_to_rgb( png_ptr );
969 break;
970 }
971
972 if( bitdepth < 8 ) {
973 png_set_packing( png_ptr );
974 } else if( bitdepth == 16 ) {
975 png_set_strip_16( png_ptr );
976 }
977
978 if( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) ) {
979 png_set_tRNS_to_alpha( png_ptr );
980 }
981
982 png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER );
983
984 png_read_update_info( png_ptr, info_ptr );
985
986 rowbytes = png_get_rowbytes( png_ptr, info_ptr );
987 pixels = R_Malloc( h * rowbytes );
988
989 for( row = 0; row < h; row++ ) {
990 row_pointers[row] = pixels + row * rowbytes;
991 }
992
993 png_read_image( png_ptr, row_pointers );
994
995 png_read_end( png_ptr, info_ptr );
996
997 png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
998
999 *pic = pixels;
1000 *width = w;
1001 *height = h;
1002
1003 fail:
1004 fs.FreeFile( rawdata );
1005 }
1006
1007 #endif /* USE_LIBPNG */
1008
1009 #endif /* TRUECOLOR_RENDERER */
1010
1011 /*
1012 =========================================================
1013
1014 IMAGE MANAGER
1015
1016 =========================================================
1017 */
1018
1019 image_t r_images[MAX_RIMAGES];
1020 list_t r_imageHash[RIMAGES_HASH];
1021 int r_numImages;
1022
1023 uint32 d_8to24table[256];
1024
1025 #ifdef TRUECOLOR_RENDERER
1026
1027 static cvar_t *r_override_textures;
1028
1029 /*
1030 ================
1031 R_ResampleTexture
1032 ================
1033 */
R_ResampleTexture(const byte * in,int inwidth,int inheight,byte * out,int outwidth,int outheight)1034 void R_ResampleTexture( const byte *in, int inwidth, int inheight, byte *out, int outwidth, int outheight ) {
1035 int i, j;
1036 const byte *inrow1, *inrow2;
1037 uint32 frac, fracstep;
1038 uint32 p1[MAX_TEXTURE_SIZE], p2[MAX_TEXTURE_SIZE];
1039 const byte *pix1, *pix2, *pix3, *pix4;
1040 float heightScale;
1041
1042 if( outwidth > MAX_TEXTURE_SIZE ) {
1043 Com_Error( ERR_FATAL, "ResampleTexture: outwidth > %d",
1044 MAX_TEXTURE_SIZE );
1045 }
1046
1047 fracstep = inwidth * 0x10000 / outwidth;
1048
1049 frac = fracstep >> 2;
1050 for( i = 0; i < outwidth; i++ ) {
1051 p1[i] = 4 * ( frac >> 16 );
1052 frac += fracstep;
1053 }
1054 frac = 3 * ( fracstep >> 2 );
1055 for( i = 0; i < outwidth; i++ ) {
1056 p2[i] = 4 * ( frac >> 16 );
1057 frac += fracstep;
1058 }
1059
1060 heightScale = ( float )inheight / outheight;
1061 inwidth <<= 2;
1062 for( i = 0; i < outheight; i++ ) {
1063 inrow1 = in + inwidth * ( int )( ( i + 0.25f ) * heightScale );
1064 inrow2 = in + inwidth * ( int )( ( i + 0.75f ) * heightScale );
1065 for( j = 0; j < outwidth; j++ ) {
1066 pix1 = inrow1 + p1[j];
1067 pix2 = inrow1 + p2[j];
1068 pix3 = inrow2 + p1[j];
1069 pix4 = inrow2 + p2[j];
1070 out[0] = ( pix1[0] + pix2[0] + pix3[0] + pix4[0] ) >> 2;
1071 out[1] = ( pix1[1] + pix2[1] + pix3[1] + pix4[1] ) >> 2;
1072 out[2] = ( pix1[2] + pix2[2] + pix3[2] + pix4[2] ) >> 2;
1073 out[3] = ( pix1[3] + pix2[3] + pix3[3] + pix4[3] ) >> 2;
1074 out += 4;
1075 }
1076 }
1077 }
1078
1079 #endif /* TRUECOLOR_RENDERER */
1080
1081 /*
1082 ===============
1083 R_ImageList_f
1084 ===============
1085 */
R_ImageList_f(void)1086 static void R_ImageList_f( void ) {
1087 int i;
1088 image_t *image;
1089 int texels;
1090
1091 Com_Printf( "------------------\n");
1092 texels = 0;
1093
1094 for( i = 0, image = r_images; i < r_numImages; i++, image++ ) {
1095 if( !image->registration_sequence )
1096 continue;
1097 texels += image->upload_width * image->upload_height;
1098 switch( image->type ) {
1099 case it_skin:
1100 Com_Printf( "M" );
1101 break;
1102 case it_sprite:
1103 Com_Printf( "S" );
1104 break;
1105 case it_wall:
1106 Com_Printf( "W" );
1107 break;
1108 case it_pic:
1109 Com_Printf( "P" );
1110 break;
1111 case it_sky:
1112 Com_Printf( "Y" );
1113 break;
1114 case it_lightmap:
1115 Com_Printf( "L" );
1116 break;
1117 case it_charset:
1118 Com_Printf( "C" );
1119 break;
1120 default:
1121 Com_Printf( " " );
1122 break;
1123 }
1124
1125 Com_Printf( " %4i %4i %s: %s\n", image->upload_width,
1126 image->upload_height, ( image->flags & if_paletted ) ? "PAL" : "RGB",
1127 image->name );
1128 }
1129 Com_Printf( "Total texel count (not counting mipmaps): %i\n", texels );
1130 }
1131
R_AllocImageInternal(const char * name,uint32 hash)1132 static image_t *R_AllocImageInternal( const char *name, uint32 hash ) {
1133 int i;
1134 image_t *image;
1135
1136 // find a free image_t slot
1137 for( i = 0, image = r_images; i < r_numImages; i++, image++ ) {
1138 if( !image->registration_sequence )
1139 break;
1140 }
1141
1142 if( i == r_numImages ) {
1143 if( r_numImages == MAX_RIMAGES )
1144 Com_Error( ERR_FATAL, "R_AllocImage: MAX_IMAGES" );
1145 r_numImages++;
1146 }
1147
1148 strcpy( image->name, name );
1149 List_Append( &r_imageHash[hash], image );
1150
1151 image->registration_sequence = registration_sequence;
1152
1153 return image;
1154 }
1155
1156 /*
1157 ===============
1158 R_LookupImage
1159
1160 Finds the given image
1161 ===============
1162 */
R_LookupImage(const char * name,imagetype_t type,uint32 hash,int baselength)1163 static image_t *R_LookupImage( const char *name, imagetype_t type,
1164 uint32 hash, int baselength )
1165 {
1166 listElem_t *elem;
1167 image_t *image;
1168
1169 // look for it
1170 for( elem = r_imageHash[hash].first; elem; elem = elem->next ) {
1171 image = ( image_t * )elem;
1172 if( image->type != type ) {
1173 continue;
1174 }
1175 if( !strncmp( image->name, name, baselength ) ) {
1176 return image;
1177 }
1178 }
1179
1180 return NULL;
1181 }
1182
R_AllocImage(const char * name)1183 image_t *R_AllocImage( const char *name ) {
1184 char buffer[MAX_QPATH];
1185 char *ext;
1186 uint32 hash;
1187 image_t *image;
1188 int length;
1189
1190 if( !name || !name[0] ) {
1191 Com_Error( ERR_FATAL, "R_AllocImage: NULL" );
1192 }
1193
1194 length = strlen( name );
1195 if( length >= MAX_QPATH ) {
1196 Com_Error( ERR_FATAL, "R_AllocImage: oversize name: %d chars", length );
1197 }
1198
1199 strcpy( buffer, name );
1200 Q_strlwr( buffer );
1201
1202 ext = COM_FileExtension( buffer );
1203 if( *ext == '.' ) {
1204 *ext = 0;
1205 } else {
1206 ext = NULL;
1207 }
1208 hash = Com_HashPath( buffer, RIMAGES_HASH );
1209 if( ext ) {
1210 *ext = '.';
1211 }
1212
1213 image = R_AllocImageInternal( buffer, hash );
1214
1215 return image;
1216 }
1217
1218
R_CreateImage(const char * name,byte * pic,int width,int height,imagetype_t type,imageflags_t flags)1219 image_t *R_CreateImage( const char *name, byte *pic, int width, int height,
1220 imagetype_t type, imageflags_t flags )
1221 {
1222 image_t *image;
1223
1224 image = R_AllocImage( name );
1225 R_LoadImage( image, pic, width, height, type, flags );
1226
1227 return image;
1228 }
1229
1230
1231 #ifdef TRUECOLOR_RENDERER
1232
1233 /*
1234 ===============
1235 R_FindImage
1236
1237 Finds or loads the given image (8 or 32 bit)
1238 ===============
1239 */
R_FindImage(const char * name,imagetype_t type)1240 image_t *R_FindImage( const char *name, imagetype_t type ) {
1241 image_t *image;
1242 byte *pic;
1243 int width, height;
1244 char buffer[MAX_QPATH];
1245 char *ext;
1246 int length;
1247 uint32 hash, extHash;
1248 imageflags_t flags;
1249
1250 if( !name || !name[0] ) {
1251 Com_Error( ERR_FATAL, "R_FindImage: NULL" );
1252 }
1253
1254 length = strlen( name );
1255 if( length >= MAX_QPATH ) {
1256 Com_Error( ERR_FATAL, "R_FindImage: oversize name: %d chars", length );
1257 }
1258
1259 if( length <= 4 ) {
1260 /* must have at least 1 char of basename
1261 * and 4 chars of extension part */
1262 return NULL;
1263 }
1264
1265 length -= 4;
1266 if( name[length] != '.' ) {
1267 return NULL;
1268 }
1269
1270 strcpy( buffer, name );
1271 Q_strlwr( buffer );
1272 buffer[length] = 0;
1273
1274 hash = Com_HashPath( buffer, RIMAGES_HASH );
1275
1276 if( ( image = R_LookupImage( buffer, type, hash, length ) ) != NULL ) {
1277 image->registration_sequence = registration_sequence;
1278 return image;
1279 }
1280
1281 ext = buffer + length;
1282 extHash = MakeLittleLong( '.', ext[1], ext[2], ext[3] );
1283
1284 //
1285 // load the pic from disk
1286 //
1287 pic = NULL;
1288 image = NULL;
1289 flags = 0;
1290
1291 if( r_override_textures->integer ) {
1292 #ifdef USE_LIBPNG
1293 // try *.png
1294 strcpy( ext, ".png" );
1295 Image_LoadPNG( buffer, &pic, &width, &height );
1296
1297 if( !pic )
1298 #endif
1299 {
1300 // try *.tga
1301 strcpy( ext, ".tga" );
1302 Image_LoadTGA( buffer, &pic, &width, &height );
1303
1304 #ifdef USE_LIBJPEG
1305 if( !pic ) {
1306 // try *.jpg
1307 strcpy( ext, ".jpg" );
1308 Image_LoadJPG( buffer, &pic, &width, &height );
1309 }
1310 #endif
1311 }
1312
1313 if( pic ) {
1314 /* replacing 8 bit texture with 32 bit texture */
1315 if( extHash == EXTENSION_WAL ) {
1316 flags |= if_replace_wal;
1317 } else if( extHash == EXTENSION_PCX ) {
1318 flags |= if_replace_pcx;
1319 }
1320 goto loadImage;
1321 }
1322
1323 if( extHash == EXTENSION_PCX ) {
1324 strcpy( ext, ".pcx" );
1325 Image_LoadPCX( buffer, &pic, NULL, &width, &height );
1326 if( pic ) {
1327 flags |= if_paletted;
1328 goto loadImage;
1329 }
1330
1331 return NULL;
1332 }
1333
1334 if( extHash == EXTENSION_WAL ) {
1335 strcpy( ext, ".wal" );
1336 image = R_LoadWal( buffer );
1337 return image;
1338 }
1339
1340 return NULL;
1341 }
1342
1343 switch( extHash ) {
1344 case EXTENSION_PNG:
1345 #ifdef USE_LIBPNG
1346 // try *.png
1347 strcpy( ext, ".png" );
1348 Image_LoadPNG( buffer, &pic, &width, &height );
1349 if( pic ) {
1350 goto loadImage;
1351 }
1352 #endif
1353
1354 // try *.tga
1355 strcpy( ext, ".tga" );
1356 Image_LoadTGA( buffer, &pic, &width, &height );
1357 if( pic ) {
1358 goto loadImage;
1359 }
1360
1361 #ifdef USE_LIBJPEG
1362 // try *.jpg
1363 strcpy( ext, ".jpg" );
1364 Image_LoadJPG( buffer, &pic, &width, &height );
1365 if( pic ) {
1366 goto loadImage;
1367 }
1368 #endif
1369
1370 // try *.pcx
1371 strcpy( ext, ".pcx" );
1372 Image_LoadPCX( buffer, &pic, NULL, &width, &height );
1373 if( pic ) {
1374 flags |= if_paletted;
1375 goto loadImage;
1376 }
1377 return NULL;
1378
1379 case EXTENSION_TGA:
1380 strcpy( ext, ".tga" );
1381 Image_LoadTGA( buffer, &pic, &width, &height );
1382 if( pic ) {
1383 goto loadImage;
1384 }
1385
1386 #ifdef USE_LIBPNG
1387 // try *.png
1388 strcpy( ext, ".png" );
1389 Image_LoadPNG( buffer, &pic, &width, &height );
1390 if( pic ) {
1391 goto loadImage;
1392 }
1393 #endif
1394
1395 #ifdef USE_LIBJPEG
1396 // try *.jpg
1397 strcpy( ext, ".jpg" );
1398 Image_LoadJPG( buffer, &pic, &width, &height );
1399 if( pic ) {
1400 goto loadImage;
1401 }
1402 #endif
1403
1404 // try *.pcx
1405 strcpy( ext, ".pcx" );
1406 Image_LoadPCX( buffer, &pic, NULL, &width, &height );
1407 if( pic ) {
1408 flags |= if_paletted;
1409 goto loadImage;
1410 }
1411 return NULL;
1412
1413 case EXTENSION_JPG:
1414 #ifdef USE_LIBJPEG
1415 strcpy( ext, ".jpg" );
1416 Image_LoadJPG( buffer, &pic, &width, &height );
1417 if( pic ) {
1418 goto loadImage;
1419 }
1420 #endif
1421
1422 #ifdef USE_LIBPNG
1423 // try *.png
1424 strcpy( ext, ".png" );
1425 Image_LoadPNG( buffer, &pic, &width, &height );
1426 if( pic ) {
1427 goto loadImage;
1428 }
1429 #endif
1430
1431 // try *.tga
1432 strcpy( ext, ".tga" );
1433 Image_LoadTGA( buffer, &pic, &width, &height );
1434 if( pic ) {
1435 goto loadImage;
1436 }
1437
1438 // try *.pcx
1439 strcpy( ext, ".pcx" );
1440 Image_LoadPCX( buffer, &pic, NULL, &width, &height );
1441 if( pic ) {
1442 flags |= if_paletted;
1443 goto loadImage;
1444 }
1445 return NULL;
1446
1447
1448 case EXTENSION_PCX:
1449 strcpy( ext, ".pcx" );
1450 Image_LoadPCX( buffer, &pic, NULL, &width, &height );
1451 if( pic ) {
1452 flags |= if_paletted;
1453 goto loadImage;
1454 }
1455
1456 #ifdef USE_LIBPNG
1457 // try *.png
1458 strcpy( ext, ".png" );
1459 Image_LoadPNG( buffer, &pic, &width, &height );
1460 if( pic ) {
1461 goto loadImage;
1462 }
1463 #endif
1464
1465 // try *.tga
1466 strcpy( ext, ".tga" );
1467 Image_LoadTGA( buffer, &pic, &width, &height );
1468 if( pic ) {
1469 goto loadImage;
1470 }
1471
1472 #ifdef USE_LIBJPEG
1473 // try *.jpg
1474 strcpy( ext, ".jpg" );
1475 Image_LoadJPG( buffer, &pic, &width, &height );
1476 if( pic ) {
1477 goto loadImage;
1478 }
1479 #endif
1480
1481 return NULL;
1482
1483 case EXTENSION_WAL:
1484 strcpy( ext, ".wal" );
1485 image = R_LoadWal( buffer );
1486 if( image ) {
1487 return image;
1488 }
1489
1490 /* FIXME: no way to figure correct texture dimensions here */
1491
1492 #ifdef USE_LIBPNG
1493 // try *.png
1494 strcpy( ext, ".png" );
1495 Image_LoadPNG( buffer, &pic, &width, &height );
1496 if( pic ) {
1497 goto loadImage;
1498 }
1499 #endif
1500
1501 // try *.tga
1502 strcpy( ext, ".tga" );
1503 Image_LoadTGA( buffer, &pic, &width, &height );
1504 if( pic ) {
1505 goto loadImage;
1506 }
1507
1508 #ifdef USE_LIBJPEG
1509 // try *.jpg
1510 strcpy( ext, ".jpg" );
1511 Image_LoadJPG( buffer, &pic, &width, &height );
1512 if( pic ) {
1513 goto loadImage;
1514 }
1515 #endif
1516
1517 return NULL;
1518
1519 default:
1520 return NULL;
1521
1522 }
1523
1524 loadImage:
1525 image = R_AllocImageInternal( buffer, hash );
1526 R_LoadImage( image, pic, width, height, type, flags );
1527 return image;
1528 }
1529
1530 #else /* TRUECOLOR_RENDERER */
1531
1532 /*
1533 ===============
1534 R_FindImage
1535
1536 Finds or loads the given image (8 bit)
1537 ===============
1538 */
R_FindImage(const char * name,imagetype_t type)1539 image_t *R_FindImage( const char *name, imagetype_t type ) {
1540 image_t *image;
1541 byte *pic;
1542 int width, height;
1543 char buffer[MAX_QPATH];
1544 char *ext;
1545 int length;
1546 uint32 hash, extHash;
1547
1548 if( !name || !name[0] ) {
1549 Com_Error( ERR_FATAL, "R_FindImage: NULL" );
1550 }
1551
1552 length = strlen( name );
1553 if( length >= MAX_QPATH ) {
1554 Com_Error( ERR_FATAL, "R_FindImage: oversize name: %d chars", length );
1555 }
1556
1557 if( length <= 4 ) {
1558 /* must have at least 1 char of basename
1559 * and 4 chars of extension part */
1560 return NULL;
1561 }
1562
1563 length -= 4;
1564 if( name[length] != '.' ) {
1565 return NULL;
1566 }
1567
1568 strcpy( buffer, name );
1569 Q_strlwr( buffer );
1570 buffer[length] = 0;
1571
1572 hash = Com_HashPath( buffer, RIMAGES_HASH );
1573
1574 if( ( image = R_LookupImage( buffer, type, hash, length ) ) != NULL ) {
1575 image->registration_sequence = registration_sequence;
1576 return image;
1577 }
1578
1579 ext = buffer + length;
1580 extHash = MakeLittleLong( '.', ext[1], ext[2], ext[3] );
1581
1582 *ext = '.';
1583
1584 //
1585 // load the pic from disk
1586 //
1587 if( extHash == EXTENSION_JPG || extHash == EXTENSION_TGA || extHash == EXTENSION_PNG ) {
1588 strcpy( ext, ".pcx" );
1589 extHash = EXTENSION_PCX;
1590 }
1591 if( extHash == EXTENSION_PCX ) {
1592 Image_LoadPCX( buffer, &pic, NULL, &width, &height );
1593 if( !pic ) {
1594 return NULL;
1595 }
1596 image = R_AllocImageInternal( buffer, hash );
1597 R_LoadImage( image, pic, width, height, type, if_paletted );
1598 return image;
1599 }
1600
1601 if( extHash == EXTENSION_WAL ) {
1602 image = R_LoadWal( buffer );
1603 return image;
1604 }
1605
1606 return NULL;
1607 }
1608
1609 #endif /* !TRUECOLOR_RENDERER */
1610
1611 /*
1612 ================
1613 R_FreeUnusedImages
1614
1615 Any image that was not touched on this registration sequence
1616 will be freed.
1617 ================
1618 */
R_FreeUnusedImages(void)1619 void R_FreeUnusedImages( void ) {
1620 image_t *image, *last;
1621
1622 last = r_images + r_numImages;
1623 for( image = r_images; image != last; image++ ) {
1624 if( image->registration_sequence == registration_sequence ) {
1625 #ifdef SOFTWARE_RENDERER
1626 Com_PageInMemory( image->pixels[0], image->width * image->height * VID_BYTES );
1627 #endif
1628 continue; // used this sequence
1629 }
1630 if( !image->registration_sequence )
1631 continue; // free image_t slot
1632 if( image->type == it_pic || image->type == it_charset )
1633 continue; // don't free pics
1634 if( image->flags & if_auto ) {
1635 if( image->type != it_lightmap ) {
1636 continue; // never free r_notexture or particle texture
1637 // always free lightmaps
1638 }
1639 }
1640
1641 // delete it from hash table
1642 List_DeleteElem( image );
1643
1644 // free it
1645 R_FreeImage( image );
1646
1647 memset( image, 0, sizeof( *image ) );
1648 }
1649 }
1650
R_FreeAllImages(void)1651 void R_FreeAllImages( void ) {
1652 image_t *image, *last;
1653
1654 last = r_images + r_numImages;
1655 for( image = r_images; image != last; image++ ) {
1656 if( !image->registration_sequence )
1657 continue; // free image_t slot
1658 // free it
1659 R_FreeImage( image );
1660
1661 memset( image, 0, sizeof( *image ) );
1662 }
1663
1664 Com_DPrintf( "R_FreeAllImages: %i images freed\n", r_numImages );
1665
1666 r_numImages = 0;
1667 memset( r_imageHash, 0, sizeof( r_imageHash ) );
1668 }
1669
1670 /*
1671 ===============
1672 R_GetPalette
1673 ===============
1674 */
R_GetPalette(byte ** dest)1675 void R_GetPalette( byte **dest ) {
1676 int i;
1677 byte *pic, *src;
1678 byte palette[768];
1679 int width, height;
1680
1681 /* get the palette */
1682 Image_LoadPCX( "pics/colormap.pcx", &pic, palette, &width, &height );
1683 if( !pic ) {
1684 Com_Error( ERR_FATAL, "Couldn't load pics/colormap.pcx" );
1685 }
1686
1687 src = palette;
1688 for( i = 0; i < 255; i++ ) {
1689 d_8to24table[i] = MakeColor( src[0], src[1], src[2], 255 );
1690 src += 3;
1691 }
1692
1693 /* 255 is transparent*/
1694 d_8to24table[i] = MakeColor( src[0], src[1], src[2], 0 );
1695
1696 if( dest ) {
1697 *dest = pic;
1698 } else {
1699 com.Free( pic );
1700 }
1701
1702 }
1703
R_InitImageManager(void)1704 void R_InitImageManager( void ) {
1705 #ifdef TRUECOLOR_RENDERER
1706 if( sizeof( TargaHeader ) != 18 ) {
1707 Com_Error( ERR_FATAL, "TargaHeader structure has invalid size %i, check your compiler settings", sizeof( TargaHeader ) );
1708 }
1709
1710 r_override_textures = cvar.Get( "r_override_textures", "0", CVAR_ARCHIVE|CVAR_LATCHED );
1711 #endif
1712 cmd.AddCommand( "imagelist", R_ImageList_f );
1713 }
1714
R_ShutdownImageManager(void)1715 void R_ShutdownImageManager( void ) {
1716 cmd.RemoveCommand( "imagelist" );
1717 }
1718
1719