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