1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19 
20 //
21 // rf_image.c
22 // Loads and uploads images to the video card
23 // The image loading functions MUST remain local to this file, since memory allocations
24 // and released are "batched" as to relieve possible fragmentation.
25 //
26 
27 #include "rf_local.h"
28 
29 #ifdef WIN32
30 # include "../include/jpeg/jpeglib.h"
31 # include "../include/zlibpng/png.h"
32 #else
33 # include <jpeglib.h>
34 # include <png.h>
35 # include <zlib.h>
36 #endif
37 
38 #define MAX_IMAGE_HASH			(MAX_IMAGES/4)
39 #define MAX_IMAGE_SCRATCHSIZE	512	// 512*512*4 = 1MB
40 
41 static byte		*r_palScratch;
42 static uint32	*r_imageScaleScratch;
43 static uint32	*r_imageResampleScratch;
44 
45 image_t			*r_lmTextures[R_MAX_LIGHTMAPS];
46 static image_t	r_imageList[MAX_IMAGES];
47 static image_t	*r_imageHashTree[MAX_IMAGE_HASH];
48 uint32	r_numImages;
49 
50 static byte		r_intensityTable[256];
51 static byte		r_gammaTable[256];
52 static uint32	r_paletteTable[256];
53 
54 const char		*r_cubeMapSuffix[6] = { "px", "nx", "py", "ny", "pz", "nz" };
55 const char		*r_skyNameSuffix[6] = { "rt", "bk", "lf", "ft", "up", "dn" };
56 
57 static const GLenum r_cubeTargets[] = {
58 	GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
59 	GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
60 	GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
61 	GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
62 	GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
63 	GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
64 };
65 
66 static byte r_defaultImagePal[] = {
67 	#include "rf_defpal.h"
68 };
69 
70 enum {
71 	IMGTAG_DEFAULT,
72 	IMGTAG_BATCH,	// Used to release in groups
73 	IMGTAG_REG,		// Released when registration finishes
74 };
75 
76 static int	r_imageAllocTag;
77 
78 /*
79 ==============================================================================
80 
81 	TEXTURE STATE
82 
83 ==============================================================================
84 */
85 
86 /*
87 ==================
88 GL_TextureBits
89 ==================
90 */
GL_TextureBits(qBool verbose,qBool verboseOnly)91 void GL_TextureBits (qBool verbose, qBool verboseOnly)
92 {
93 	// Print to the console if desired
94 	if (verbose) {
95 		switch (r_textureBits->intVal) {
96 		case 32:
97 			Com_Printf (0, "Texture bits: 32\n");
98 			break;
99 
100 		case 16:
101 			Com_Printf (0, "Texture bits: 16\n");
102 			break;
103 
104 		default:
105 			Com_Printf (0, "Texture bits: default\n");
106 			break;
107 		}
108 
109 		// Only print (don't set)
110 		if (verboseOnly)
111 			return;
112 	}
113 
114 	// Set
115 	switch (r_textureBits->intVal) {
116 	case 32:
117 		ri.rgbFormat = GL_RGB8;
118 		ri.rgbaFormat = GL_RGBA8;
119 		break;
120 
121 	case 16:
122 		ri.rgbFormat = GL_RGB5;
123 		ri.rgbaFormat = GL_RGBA4;
124 		break;
125 
126 	default:
127 		ri.rgbFormat = GL_RGB;
128 		ri.rgbaFormat = GL_RGBA;
129 		break;
130 	}
131 }
132 
133 
134 /*
135 ===============
136 GL_TextureMode
137 ===============
138 */
139 typedef struct glTexMode_s {
140 	char	*name;
141 
142 	GLint	minimize;
143 	GLint	maximize;
144 } glTexMode_t;
145 
146 static const glTexMode_t modes[] = {
147 	{"GL_NEAREST",					GL_NEAREST,					GL_NEAREST},
148 	{"GL_LINEAR",					GL_LINEAR,					GL_LINEAR},
149 	{"GL_NEAREST_MIPMAP_NEAREST",	GL_NEAREST_MIPMAP_NEAREST,	GL_NEAREST},
150 	{"GL_NEAREST_MIPMAP_LINEAR",	GL_NEAREST_MIPMAP_LINEAR,	GL_NEAREST},
151 	{"GL_LINEAR_MIPMAP_NEAREST",	GL_LINEAR_MIPMAP_NEAREST,	GL_LINEAR},		// Bilinear
152 	{"GL_LINEAR_MIPMAP_LINEAR",		GL_LINEAR_MIPMAP_LINEAR,	GL_LINEAR}		// Trilinear
153 };
154 
155 #define NUM_GL_MODES (sizeof (modes) / sizeof (glTexMode_t))
156 
GL_TextureMode(qBool verbose,qBool verboseOnly)157 void GL_TextureMode (qBool verbose, qBool verboseOnly)
158 {
159 	uint32	i;
160 	image_t	*image;
161 	char	*string = gl_texturemode->string;
162 
163 	// Find a matching mode
164 	for (i=0 ; i<NUM_GL_MODES ; i++) {
165 		if (!Q_stricmp (modes[i].name, string))
166 			break;
167 	}
168 
169 	if (i == NUM_GL_MODES) {
170 		// Not found
171 		Com_Printf (PRNT_WARNING, "bad filter name -- falling back to GL_LINEAR_MIPMAP_NEAREST\n");
172 		Cvar_VariableSet (gl_texturemode, "GL_LINEAR_MIPMAP_NEAREST", qTrue);
173 
174 		ri.texMinFilter = GL_LINEAR_MIPMAP_NEAREST;
175 		ri.texMagFilter = GL_LINEAR;
176 	}
177 	else {
178 		// Found
179 		ri.texMinFilter = modes[i].minimize;
180 		ri.texMagFilter = modes[i].maximize;
181 	}
182 
183 	gl_texturemode->modified = qFalse;
184 	if (verbose) {
185 		Com_Printf (0, "Texture mode: %s\n", modes[i].name);
186 		if (verboseOnly)
187 			return;
188 	}
189 
190 	// Change all the existing mipmap texture objects
191 	for (i=0, image=r_imageList ; i<r_numImages ; i++, image++) {
192 		if (!image->touchFrame)
193 			continue;	// Free r_imageList slot
194 		if (image->flags & (IF_NOMIPMAP_LINEAR|IF_NOMIPMAP_NEAREST))
195 			continue;
196 
197 		RB_BindTexture (image);
198 		qglTexParameteri (image->target, GL_TEXTURE_MIN_FILTER, ri.texMinFilter);
199 		qglTexParameteri (image->target, GL_TEXTURE_MAG_FILTER, ri.texMagFilter);
200 	}
201 }
202 
203 
204 /*
205 ===============
206 GL_ResetAnisotropy
207 ===============
208 */
GL_ResetAnisotropy(void)209 void GL_ResetAnisotropy (void)
210 {
211 	uint32	i;
212 	image_t	*image;
213 	int		set;
214 
215 	r_ext_maxAnisotropy->modified = qFalse;
216 	if (!ri.config.extTexFilterAniso)
217 		return;
218 
219 	// Change all the existing mipmap texture objects
220 	set = clamp (r_ext_maxAnisotropy->intVal, 1, ri.config.maxAniso);
221 	for (i=0, image=r_imageList ; i<r_numImages ; i++, image++) {
222 		if (!image->touchFrame)
223 			continue;	// Free r_imageList slot
224 		if (image->flags & (IF_NOMIPMAP_LINEAR|IF_NOMIPMAP_NEAREST))
225 			continue;	// Skip non-mipmapped imagery
226 
227 		RB_BindTexture (image);
228 		qglTexParameteri (image->target, GL_TEXTURE_MAX_ANISOTROPY_EXT, set);
229 	}
230 }
231 
232 /*
233 ==============================================================================
234 
235 	JPG
236 
237 ==============================================================================
238 */
239 
jpg_noop(j_decompress_ptr cinfo)240 static void jpg_noop(j_decompress_ptr cinfo)
241 {
242 }
243 
jpeg_d_error_exit(j_common_ptr cinfo)244 static void jpeg_d_error_exit (j_common_ptr cinfo)
245 {
246 	char msg[1024];
247 
248 	(cinfo->err->format_message)(cinfo, msg);
249 	Com_Error (ERR_FATAL, "R_LoadJPG: JPEG Lib Error: '%s'", msg);
250 }
251 
jpg_fill_input_buffer(j_decompress_ptr cinfo)252 static boolean jpg_fill_input_buffer (j_decompress_ptr cinfo)
253 {
254     Com_DevPrintf (PRNT_WARNING, "R_LoadJPG: Premeture end of jpeg file\n");
255 
256     return 1;
257 }
258 
jpg_skip_input_data(j_decompress_ptr cinfo,long num_bytes)259 static void jpg_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
260 {
261     cinfo->src->next_input_byte += (size_t) num_bytes;
262     cinfo->src->bytes_in_buffer -= (size_t) num_bytes;
263 }
264 
265 /*
266 =============
267 R_LoadJPG
268 
269 ala Vic
270 =============
271 */
R_LoadJPG(char * name,byte ** pic,int * width,int * height)272 static void R_LoadJPG (char *name, byte **pic, int *width, int *height)
273 {
274     int		fileLen, components;
275     byte	*img, *scan, *buffer, *dummy;
276     struct	jpeg_error_mgr			jerr;
277     struct	jpeg_decompress_struct	cinfo;
278 	uint32	i;
279 
280 	if (pic)
281 		*pic = NULL;
282 
283 	// Load the file
284 	fileLen = FS_LoadFile (name, (void **)&buffer, NULL);
285 	if (!buffer || fileLen <= 0)
286 		return;
287 
288 	// Parse the file
289 	cinfo.err = jpeg_std_error (&jerr);
290 	jerr.error_exit = jpeg_d_error_exit;
291 
292 	jpeg_create_decompress (&cinfo);
293 
294 	jpeg_mem_src (&cinfo, buffer, fileLen);
295 	jpeg_read_header (&cinfo, TRUE);
296 
297 	jpeg_start_decompress (&cinfo);
298 
299 	components = cinfo.output_components;
300     if (components != 3 && components != 1) {
301 		Com_DevPrintf (PRNT_WARNING, "R_LoadJPG: Bad jpeg components '%s' (%d)\n", name, components);
302 		jpeg_destroy_decompress (&cinfo);
303 		FS_FreeFile (buffer);
304 		return;
305 	}
306 
307 	if (cinfo.output_width <= 0 || cinfo.output_height <= 0) {
308 		Com_DevPrintf (PRNT_WARNING, "R_LoadJPG: Bad jpeg dimensions on '%s' (%d x %d)\n", name, cinfo.output_width, cinfo.output_height);
309 		jpeg_destroy_decompress (&cinfo);
310 		FS_FreeFile (buffer);
311 		return;
312 	}
313 
314 	if (width)
315 		*width = cinfo.output_width;
316 	if (height)
317 		*height = cinfo.output_height;
318 
319 	img = Mem_PoolAllocExt (cinfo.output_width * cinfo.output_height * 4, qFalse, ri.imageSysPool, r_imageAllocTag);
320 	dummy = Mem_PoolAllocExt (cinfo.output_width * components, qFalse, ri.imageSysPool, r_imageAllocTag);
321 
322 	if (pic)
323 		*pic = img;
324 
325 	while (cinfo.output_scanline < cinfo.output_height) {
326 		scan = dummy;
327 		if (!jpeg_read_scanlines (&cinfo, &scan, 1)) {
328 			Com_Printf (PRNT_WARNING, "Bad jpeg file %s\n", name);
329 			jpeg_destroy_decompress (&cinfo);
330 			Mem_Free (dummy);
331 			FS_FreeFile (buffer);
332 			return;
333 		}
334 
335 		if (components == 1) {
336 			for (i=0 ; i<cinfo.output_width ; i++, img+=4)
337 				img[0] = img[1] = img[2] = *scan++;
338 		}
339 		else {
340 			for (i=0 ; i<cinfo.output_width ; i++, img+=4, scan += 3)
341 				img[0] = scan[0], img[1] = scan[1], img[2] = scan[2];
342 		}
343 	}
344 
345     jpeg_finish_decompress (&cinfo);
346     jpeg_destroy_decompress (&cinfo);
347 
348     Mem_Free (dummy);
349 	FS_FreeFile (buffer);
350 }
351 
352 
353 /*
354 ==================
355 R_WriteJPG
356 ==================
357 */
358 
R_WriteJPG(FILE * f,byte * buffer,int width,int height,int quality)359 static void R_WriteJPG (FILE *f, byte *buffer, int width, int height, int quality)
360 {
361 	int			offset, w3;
362 	struct		jpeg_compress_struct	cinfo;
363 	struct		jpeg_error_mgr			jerr;
364 	byte		*s;
365 
366 	// Initialise the jpeg compression object
367 	cinfo.err = jpeg_std_error (&jerr);
368 	jpeg_create_compress (&cinfo);
369 	jpeg_stdio_dest (&cinfo, f);
370 
371 	// Setup jpeg parameters
372 	cinfo.image_width = width;
373 	cinfo.image_height = height;
374 	cinfo.in_color_space = JCS_RGB;
375 	cinfo.input_components = 3;
376 	cinfo.progressive_mode = TRUE;
377 
378 	jpeg_set_defaults (&cinfo);
379 	jpeg_set_quality (&cinfo, quality, TRUE);
380 	jpeg_start_compress (&cinfo, qTrue);	// start compression
381 	jpeg_write_marker (&cinfo, JPEG_COM, (byte *) "EGL v" EGL_VERSTR, (uint32) strlen ("EGL v" EGL_VERSTR));
382 
383 	// Feed scanline data
384 	w3 = cinfo.image_width * 3;
385 	offset = w3 * cinfo.image_height - w3;
386 	while (cinfo.next_scanline < cinfo.image_height) {
387 		s = &buffer[offset - (cinfo.next_scanline * w3)];
388 		jpeg_write_scanlines (&cinfo, &s, 1);
389 	}
390 
391 	// Finish compression
392 	jpeg_finish_compress (&cinfo);
393 	jpeg_destroy_compress (&cinfo);
394 }
395 
396 /*
397 ==============================================================================
398 
399 	PCX
400 
401 ==============================================================================
402 */
403 
404 /*
405 =============
406 R_LoadPCX
407 =============
408 */
R_LoadPCX(char * name,byte ** pic,byte ** palette,int * width,int * height)409 static void R_LoadPCX (char *name, byte **pic, byte **palette, int *width, int *height)
410 {
411 	byte		*raw;
412 	pcxHeader_t	*pcx;
413 	int			x, y, fileLen;
414 	int			dataByte, runLength;
415 	byte		*out, *pix;
416 
417 	if (pic)
418 		*pic = NULL;
419 	if (palette)
420 		*palette = NULL;
421 
422 	// Load the file
423 	fileLen = FS_LoadFile (name, (void **)&raw, NULL);
424 	if (!raw || fileLen <= 0)
425 		return;
426 
427 	// Parse the PCX file
428 	pcx = (pcxHeader_t *)raw;
429 
430 	pcx->xMin = LittleShort (pcx->xMin);
431 	pcx->yMin = LittleShort (pcx->yMin);
432 	pcx->xMax = LittleShort (pcx->xMax);
433 	pcx->yMax = LittleShort (pcx->yMax);
434 	pcx->hRes = LittleShort (pcx->hRes);
435 	pcx->vRes = LittleShort (pcx->vRes);
436 	pcx->bytesPerLine = LittleShort (pcx->bytesPerLine);
437 	pcx->paletteType = LittleShort (pcx->paletteType);
438 
439 	raw = &pcx->data;
440 
441 	// Sanity checks
442 	if (pcx->manufacturer != 0x0a || pcx->version != 5 || pcx->encoding != 1) {
443 		Com_DevPrintf (PRNT_WARNING, "R_LoadPCX: %s: Invalid PCX header\n", name);
444 		return;
445 	}
446 
447 	if (pcx->bitsPerPixel != 8 || pcx->colorPlanes != 1) {
448 		Com_DevPrintf (PRNT_WARNING, "R_LoadPCX: %s: Only 8-bit PCX images are supported\n", name);
449 		return;
450 	}
451 
452 	if (pcx->xMax >= 640 || pcx->xMax <= 0 || pcx->yMax >= 480 || pcx->yMax <= 0) {
453 		Com_DevPrintf (PRNT_WARNING, "R_LoadPCX: %s: Bad PCX file dimensions: %i x %i\n", name, pcx->xMax, pcx->yMax);
454 		return;
455 	}
456 
457 	// FIXME: Some images with weird dimensions will crash if I don't do this...
458 	x = max (pcx->yMax+1, pcx->xMax+1);
459 	pix = out = Mem_PoolAllocExt (x * x, qFalse, ri.imageSysPool, r_imageAllocTag);
460 	if (pic)
461 		*pic = out;
462 
463 	if (palette) {
464 		*palette = Mem_PoolAllocExt (768, qFalse, ri.imageSysPool, r_imageAllocTag);
465 		memcpy (*palette, (byte *)pcx + fileLen - 768, 768);
466 	}
467 
468 	if (width)
469 		*width = pcx->xMax+1;
470 	if (height)
471 		*height = pcx->yMax+1;
472 
473 	for (y=0 ; y<=pcx->yMax ; y++, pix+=pcx->xMax+1) {
474 		for (x=0 ; x<=pcx->xMax ; ) {
475 			dataByte = *raw++;
476 
477 			if ((dataByte & 0xC0) == 0xC0) {
478 				runLength = dataByte & 0x3F;
479 				dataByte = *raw++;
480 			}
481 			else
482 				runLength = 1;
483 
484 			while (runLength-- > 0)
485 				pix[x++] = dataByte;
486 		}
487 	}
488 
489 	if (raw - (byte *)pcx > fileLen) {
490 		Com_DevPrintf (PRNT_WARNING, "R_LoadPCX: %s: PCX file was malformed", name);
491 		Mem_Free (out);
492 		out = NULL;
493 		pix = NULL;
494 
495 		if (pic)
496 			*pic = NULL;
497 		if (palette) {
498 			Mem_Free (palette);
499 			*palette = NULL;
500 		}
501 	}
502 
503 	if (!pic)
504 		Mem_Free (out);
505 	FS_FreeFile (pcx);
506 }
507 
508 /*
509 ==============================================================================
510 
511 	PNG
512 
513 ==============================================================================
514 */
515 
516 typedef struct pngBuf_s {
517 	byte	*buffer;
518 	int		pos;
519 } pngBuf_t;
520 
PngReadFunc(png_struct * Png,png_bytep buf,png_size_t size)521 void __cdecl PngReadFunc (png_struct *Png, png_bytep buf, png_size_t size)
522 {
523 	pngBuf_t *PngFileBuffer = (pngBuf_t*)png_get_io_ptr(Png);
524 	memcpy (buf,PngFileBuffer->buffer + PngFileBuffer->pos, size);
525 	PngFileBuffer->pos += size;
526 }
527 
528 /*
529 =============
530 R_LoadPNG
531 =============
532 */
R_LoadPNG(char * name,byte ** pic,int * width,int * height,int * samples)533 static void R_LoadPNG (char *name, byte **pic, int *width, int *height, int *samples)
534 {
535 	int				rowbytes;
536 	png_structp		png_ptr;
537 	png_infop		info_ptr;
538 	png_infop		end_info;
539 	png_bytepp		row_pointers;
540 	png_bytep		pic_ptr;
541 	int				fileLen;
542 	uint32			i;
543 	pngBuf_t		PngFileBuffer = { NULL, 0 };
544 
545 	if (pic)
546 		*pic = NULL;
547 
548 	// Load the file
549 	fileLen = FS_LoadFile (name, (void **)&PngFileBuffer.buffer, NULL);
550 	if (!PngFileBuffer.buffer || fileLen <= 0)
551 		return;
552 
553 	// Parse the PNG file
554 	if ((png_check_sig (PngFileBuffer.buffer, 8)) == 0) {
555 		Com_Printf (PRNT_WARNING, "R_LoadPNG: Not a PNG file: %s\n", name);
556 		FS_FreeFile (PngFileBuffer.buffer);
557 		return;
558 	}
559 
560 	PngFileBuffer.pos = 0;
561 
562 	png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,  NULL, NULL);
563 	if (!png_ptr) {
564 		Com_Printf (PRNT_WARNING, "R_LoadPNG: Bad PNG file: %s\n", name);
565 		FS_FreeFile (PngFileBuffer.buffer);
566 		return;
567 	}
568 
569 	info_ptr = png_create_info_struct (png_ptr);
570 	if (!info_ptr) {
571 		png_destroy_read_struct (&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
572 		Com_Printf (PRNT_WARNING, "R_LoadPNG: Bad PNG file: %s\n", name);
573 		FS_FreeFile (PngFileBuffer.buffer);
574 		return;
575 	}
576 
577 	end_info = png_create_info_struct (png_ptr);
578 	if (!end_info) {
579 		png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
580 		Com_Printf (PRNT_WARNING, "R_LoadPNG: Bad PNG file: %s\n", name);
581 		FS_FreeFile (PngFileBuffer.buffer);
582 		return;
583 	}
584 
585 	png_set_read_fn (png_ptr, (png_voidp)&PngFileBuffer, (png_rw_ptr)PngReadFunc);
586 
587 	png_read_info (png_ptr, info_ptr);
588 
589 	// Color
590 	if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) {
591 		png_set_palette_to_rgb (png_ptr);
592 		png_read_update_info (png_ptr, info_ptr);
593 	}
594 
595 	if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB)
596 		png_set_filler (png_ptr, 0xFF, PNG_FILLER_AFTER);
597 
598 	if (png_get_color_type(png_ptr, info_ptr)  == PNG_COLOR_TYPE_GRAY && png_get_bit_depth(png_ptr, info_ptr) < 8)
599 		png_set_expand_gray_1_2_4_to_8 (png_ptr);
600 
601 	if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
602 		png_set_tRNS_to_alpha (png_ptr);
603 
604 	if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY || png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY_ALPHA)
605 		png_set_gray_to_rgb (png_ptr);
606 
607 	if (png_get_bit_depth(png_ptr, info_ptr) == 16)
608 		png_set_strip_16 (png_ptr);
609 
610 	if (png_get_bit_depth(png_ptr, info_ptr) < 8)
611         png_set_packing (png_ptr);
612 
613 	png_read_update_info (png_ptr, info_ptr);
614 
615 	rowbytes = png_get_rowbytes (png_ptr, info_ptr);
616 
617 	if (!png_get_channels(png_ptr, info_ptr)) {
618 		png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
619 		Com_Printf (PRNT_WARNING, "R_LoadPNG: Bad PNG file: %s\n", name);
620 		FS_FreeFile (PngFileBuffer.buffer);
621 	}
622 
623 	pic_ptr = Mem_PoolAllocExt (png_get_image_height(png_ptr, info_ptr) * rowbytes, qFalse, ri.imageSysPool, r_imageAllocTag);
624 	if (pic)
625 		*pic = pic_ptr;
626 
627 	row_pointers = Mem_PoolAllocExt (sizeof (png_bytep) * png_get_image_height(png_ptr, info_ptr), qFalse, ri.imageSysPool, r_imageAllocTag);
628 
629 	for (i=0 ; i<png_get_image_height(png_ptr, info_ptr) ; i++) {
630 		row_pointers[i] = pic_ptr;
631 		pic_ptr += rowbytes;
632 	}
633 
634 	png_read_image (png_ptr, row_pointers);
635 
636 	if (width)
637 		*width = png_get_image_width(png_ptr, info_ptr);
638 	if (height)
639 		*height = png_get_image_height(png_ptr, info_ptr);
640 	if (samples)
641 		*samples = png_get_channels(png_ptr, info_ptr);
642 
643 	png_read_end (png_ptr, end_info);
644 	png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
645 
646 	Mem_Free (row_pointers);
647 	FS_FreeFile (PngFileBuffer.buffer);
648 }
649 
650 
651 /*
652 ==================
653 R_PNGScreenShot
654 ==================
655 */
R_WritePNG(FILE * f,byte * buffer,int width,int height)656 static void R_WritePNG (FILE *f, byte *buffer, int width, int height)
657 {
658 	int			i;
659 	png_structp	png_ptr;
660 	png_infop	info_ptr;
661 	png_bytep	*row_pointers;
662 
663 	png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
664 	if (!png_ptr) {
665 		Com_Printf (PRNT_WARNING, "R_WritePNG: LibPNG Error!\n");
666 		return;
667 	}
668 
669 	info_ptr = png_create_info_struct(png_ptr);
670 	if (!info_ptr) {
671 		png_destroy_write_struct (&png_ptr, (png_infopp)NULL);
672 		Com_Printf (PRNT_WARNING, "R_WritePNG: LibPNG Error!\n");
673 		return;
674 	}
675 
676 	png_init_io (png_ptr, f);
677 
678 	png_set_IHDR (png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB,
679 				PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
680 
681 	png_set_compression_level (png_ptr, Z_DEFAULT_COMPRESSION);
682 	png_set_compression_mem_level (png_ptr, 9);
683 
684 	png_write_info (png_ptr, info_ptr);
685 
686 	row_pointers = Mem_PoolAllocExt (height * sizeof (png_bytep), qFalse, ri.imageSysPool, IMGTAG_DEFAULT);
687 	for (i=0 ; i<height ; i++)
688 		row_pointers[i] = buffer + (height - 1 - i) * 3 * width;
689 
690 	png_write_image (png_ptr, row_pointers);
691 	png_write_end (png_ptr, info_ptr);
692 
693 	png_destroy_write_struct (&png_ptr, &info_ptr);
694 
695 	Mem_Free (row_pointers);
696 }
697 
698 /*
699 ==============================================================================
700 
701 	TGA
702 
703 ==============================================================================
704 */
705 
706 /*
707 =============
708 R_LoadTGA
709 
710 Loads type 1, 2, 3, 9, 10, 11 TARGA images.
711 Type 32 and 33 are unsupported.
712 =============
713 */
R_LoadTGA(char * name,byte ** pic,int * width,int * height,int * samples)714 static void R_LoadTGA (char *name, byte **pic, int *width, int *height, int *samples)
715 {
716 	int			i, columns, rows, rowInc, row, col;
717 	byte		*buf_p, *buffer, *pixbuf, *targaRGBA;
718 	int			fileLen, components, readPixelCount, pixelCount;
719 	byte		palette[256][4], red, green, blue, alpha;
720 	qBool		compressed;
721 	tgaHeader_t	tga;
722 
723 	*pic = NULL;
724 
725 	// Load the file
726 	fileLen = FS_LoadFile (name, (void **)&buffer, NULL);
727 	if (!buffer || fileLen <= 0)
728 		return;
729 
730 	// Parse the header
731 	buf_p = buffer;
732 	tga.idLength = *buf_p++;
733 	tga.colorMapType = *buf_p++;
734 	tga.imageType = *buf_p++;
735 
736 	tga.colorMapIndex = buf_p[0] + buf_p[1] * 256; buf_p+=2;
737 	tga.colorMapLength = buf_p[0] + buf_p[1] * 256; buf_p+=2;
738 	tga.colorMapSize = *buf_p++;
739 	tga.xOrigin = LittleShort (*((int16 *)buf_p)); buf_p+=2;
740 	tga.yOrigin = LittleShort (*((int16 *)buf_p)); buf_p+=2;
741 	tga.width = LittleShort (*((int16 *)buf_p)); buf_p+=2;
742 	tga.height = LittleShort (*((int16 *)buf_p)); buf_p+=2;
743 	tga.pixelSize = *buf_p++;
744 	tga.attributes = *buf_p++;
745 
746 	// Check header values
747 	if (tga.width == 0 || tga.height == 0 || tga.width > 4096 || tga.height > 4096) {
748 		Com_DevPrintf (PRNT_WARNING, "R_LoadTGA: %s: Bad TGA file (%i x %i)\n", name, tga.width, tga.height);
749 		FS_FreeFile (buffer);
750 		return;
751 	}
752 
753 	// Skip TARGA image comment
754 	if (tga.idLength != 0)
755 		buf_p += tga.idLength;
756 
757 	compressed = qFalse;
758 	switch (tga.imageType) {
759 	case 9:
760 		compressed = qTrue;
761 	case 1:
762 		// Uncompressed colormapped image
763 		if (tga.pixelSize != 8) {
764 			Com_DevPrintf (PRNT_WARNING, "R_LoadTGA: %s: Only 8 bit images supported for type 1 and 9\n", name);
765 			FS_FreeFile (buffer);
766 			return;
767 		}
768 		if (tga.colorMapLength != 256) {
769 			Com_DevPrintf (PRNT_WARNING, "R_LoadTGA: %s: Only 8 bit colormaps are supported for type 1 and 9\n", name);
770 			FS_FreeFile (buffer);
771 			return;
772 		}
773 		if (tga.colorMapIndex) {
774 			Com_DevPrintf (PRNT_WARNING, "R_LoadTGA: %s: colorMapIndex is not supported for type 1 and 9\n", name);
775 			FS_FreeFile (buffer);
776 			return;
777 		}
778 
779 		switch (tga.colorMapSize) {
780 		case 32:
781 			for (i=0 ; i<tga.colorMapLength ; i++) {
782 				palette[i][2] = *buf_p++;
783 				palette[i][1] = *buf_p++;
784 				palette[i][0] = *buf_p++;
785 				palette[i][3] = *buf_p++;
786 			}
787 			break;
788 
789 		case 24:
790 			for (i=0 ; i<tga.colorMapLength ; i++) {
791 				palette[i][2] = *buf_p++;
792 				palette[i][1] = *buf_p++;
793 				palette[i][0] = *buf_p++;
794 				palette[i][3] = 255;
795 			}
796 			break;
797 
798 		default:
799 			Com_DevPrintf (PRNT_WARNING, "R_LoadTGA: %s: Only 24 and 32 bit colormaps are supported for type 1 and 9\n", name);
800 			FS_FreeFile (buffer);
801 			return;
802 		}
803 		break;
804 
805 	case 10:
806 		compressed = qTrue;
807 	case 2:
808 		// Uncompressed or RLE compressed RGB
809 		if (tga.pixelSize != 32 && tga.pixelSize != 24) {
810 			Com_DevPrintf (PRNT_WARNING, "R_LoadTGA: %s: Only 32 or 24 bit images supported for type 2 and 10\n", name);
811 			FS_FreeFile (buffer);
812 			return;
813 		}
814 		break;
815 
816 	case 11:
817 		compressed = qTrue;
818 	case 3:
819 		// Uncompressed greyscale
820 		if (tga.pixelSize != 8) {
821 			Com_DevPrintf (PRNT_WARNING, "R_LoadTGA: %s: Only 8 bit images supported for type 3 and 11", name);
822 			FS_FreeFile (buffer);
823 			return;
824 		}
825 		break;
826 
827 	default:
828 		Com_DevPrintf (PRNT_WARNING, "R_LoadTGA: %s: Only type 1, 2, 3, 9, 10, and 11 TGA images are supported (%i)", name, tga.imageType);
829 		FS_FreeFile (buffer);
830 		return;
831 	}
832 
833 	columns = tga.width;
834 	if (width)
835 		*width = columns;
836 
837 	rows = tga.height;
838 	if (height)
839 		*height = rows;
840 
841 	targaRGBA = Mem_PoolAllocExt (columns * rows * 4, qFalse, ri.imageSysPool, r_imageAllocTag);
842 	*pic = targaRGBA;
843 
844 	// If bit 5 of attributes isn't set, the image has been stored from bottom to top
845 	if (tga.attributes & 0x20) {
846 		pixbuf = targaRGBA;
847 		rowInc = 0;
848 	}
849 	else {
850 		pixbuf = targaRGBA + (rows - 1) * columns * 4;
851 		rowInc = -columns * 4 * 2;
852 	}
853 
854 	for (row=col=0, components=3 ; row<rows ; ) {
855 		pixelCount = 0x10000;
856 		readPixelCount = 0x10000;
857 
858 		if (compressed) {
859 			pixelCount = *buf_p++;
860 			if (pixelCount & 0x80)	// Run-length packet
861 				readPixelCount = 1;
862 			pixelCount = 1 + (pixelCount & 0x7f);
863 		}
864 
865 		while (pixelCount-- && row < rows) {
866 			if (readPixelCount-- > 0) {
867 				switch (tga.imageType) {
868 				case 1:
869 				case 9:
870 					// Colormapped image
871 					blue = *buf_p++;
872 					red = palette[blue][0];
873 					green = palette[blue][1];
874 					blue = palette[blue][2];
875 					alpha = palette[blue][3];
876 					if (alpha != 255)
877 						components = 4;
878 					break;
879 				case 2:
880 				case 10:
881 					// 24 or 32 bit image
882 					blue = *buf_p++;
883 					green = *buf_p++;
884 					red = *buf_p++;
885 					if (tga.pixelSize == 32) {
886 						alpha = *buf_p++;
887 						if (alpha != 255)
888 							components = 4;
889 					}
890 					else
891 						alpha = 255;
892 					break;
893 				case 3:
894 				case 11:
895 					// Greyscale image
896 					blue = green = red = *buf_p++;
897 					alpha = 255;
898 					break;
899 				}
900 			}
901 
902 			*pixbuf++ = red;
903 			*pixbuf++ = green;
904 			*pixbuf++ = blue;
905 			*pixbuf++ = alpha;
906 			if (++col == columns) {
907 				// Run spans across rows
908 				row++;
909 				col = 0;
910 				pixbuf += rowInc;
911 			}
912 		}
913 	}
914 
915 	FS_FreeFile (buffer);
916 
917 	if (samples)
918 		*samples = components;
919 }
920 
921 
922 /*
923 ==================
924 R_WriteTGA
925 ==================
926 */
R_WriteTGA(FILE * f,byte * buffer,int width,int height,qBool rgb)927 static void R_WriteTGA (FILE *f, byte *buffer, int width, int height, qBool rgb)
928 {
929 	int		i, size, temp;
930 	byte	*out;
931 
932 	// Allocate an output buffer
933 	size = (width * height * 3) + 18;
934 	out = Mem_PoolAllocExt (size, qTrue, ri.imageSysPool, IMGTAG_DEFAULT);
935 
936 	// Fill in header
937 	out[2] = 2;		// Uncompressed type
938 	out[12] = width & 255;
939 	out[13] = width >> 8;
940 	out[14] = height & 255;
941 	out[15] = height >> 8;
942 	out[16] = 24;	// Pixel size
943 
944 	// Copy to temporary buffer
945 	memcpy (out + 18, buffer, width * height * 3);
946 
947 	// Swap rgb to bgr
948 	if (rgb) {
949 		for (i=18 ; i<size ; i+=3) {
950 			temp = out[i];
951 			out[i] = out[i+2];
952 			out[i+2] = temp;
953 		}
954 	}
955 
956 	fwrite (out, 1, size, f);
957 
958 	Mem_Free (out);
959 }
960 
961 /*
962 ==============================================================================
963 
964 	WAL
965 
966 ==============================================================================
967 */
968 
969 /*
970 ================
971 R_LoadWal
972 ================
973 */
R_LoadWal(char * name,byte ** pic,int * width,int * height)974 static void R_LoadWal (char *name, byte **pic, int *width, int *height)
975 {
976 	walTex_t	*mt;
977 	byte		*buffer, *out;
978 	int			fileLen;
979 	uint32		i;
980 
981 	// Load the file
982 	fileLen = FS_LoadFile (name, (void **)&buffer, NULL);
983 	if (!buffer || fileLen <= 0)
984 		return;
985 
986 	// Parse the WAL file
987 	mt = (walTex_t *)buffer;
988 
989 	mt->width = LittleLong (mt->width);
990 	mt->height = LittleLong (mt->height);
991 	mt->offsets[0] = LittleLong (mt->offsets[0]);
992 
993 	// Sanity check
994 	if (mt->width <= 0 || mt->height <= 0) {
995 		Com_DevPrintf (0, "R_LoadWal: bad WAL file 's' (%i x %i)\n", name, mt->width, mt->height);
996 		FS_FreeFile ((void *)buffer);
997 		return;
998 	}
999 
1000 	// Store values
1001 	if (width)
1002 		*width = mt->width;
1003 	if (height)
1004 		*height = mt->height;
1005 
1006 	// Copy data
1007 	*pic = out = Mem_PoolAllocExt (mt->width*mt->height, qFalse, ri.imageSysPool, r_imageAllocTag);
1008 	for (i=0 ; i<mt->width*mt->height ; i++)
1009 		*out++ = *(buffer + mt->offsets[0] + i);
1010 
1011 	// Done
1012 	FS_FreeFile ((void *)buffer);
1013 }
1014 
1015 /*
1016 ==============================================================================
1017 
1018 	PRE-UPLOAD HANDLING
1019 
1020 ==============================================================================
1021 */
1022 
1023 /*
1024 ===============
1025 R_ColorMipLevel
1026 ===============
1027 */
R_ColorMipLevel(byte * image,int size,int level)1028 static void R_ColorMipLevel (byte *image, int size, int level)
1029 {
1030 	int		i;
1031 
1032 	if (level == 0)
1033 		return;
1034 
1035 	switch ((level+2) % 3) {
1036 	case 0:
1037 		for (i=0 ; i<size ; i++) {
1038 			image[0] = 255;
1039 			image[1] *= 0.5f;
1040 			image[2] *= 0.5f;
1041 
1042 			image += 4;
1043 		}
1044 		break;
1045 
1046 	case 1:
1047 		for (i=0 ; i<size ; i++) {
1048 			image[0] *= 0.5f;
1049 			image[1] = 255;
1050 			image[2] *= 0.5f;
1051 
1052 			image += 4;
1053 		}
1054 		break;
1055 
1056 	case 2:
1057 		for (i=0 ; i<size ; i++) {
1058 			image[0] *= 0.5f;
1059 			image[1] *= 0.5f;
1060 			image[2] = 255;
1061 
1062 			image += 4;
1063 		}
1064 		break;
1065 	}
1066 }
1067 
1068 
1069 /*
1070 ===============
1071 R_ImageFormat
1072 ===============
1073 */
R_ImageFormat(char * name,int flags,int * samples)1074 static inline int R_ImageFormat (char *name, int flags, int *samples)
1075 {
1076 	GLint		format;
1077 
1078 	if (flags & IF_NOALPHA && *samples == 4)
1079 		*samples = 3;
1080 
1081 	switch (*samples) {
1082 	case 3:
1083 		if (!ri.config.extTexCompression || flags & IF_NOCOMPRESS)
1084 			format = ri.rgbFormat;
1085 		else
1086 			format = ri.rgbFormatCompressed;
1087 		break;
1088 
1089 	default:
1090 		Com_Printf (PRNT_WARNING, "WARNING: Invalid image sample count '%d' on '%s', assuming '4'\n", samples, name);
1091 		*samples = 4;
1092 	case 4:
1093 		if (!ri.config.extTexCompression || flags & IF_NOCOMPRESS)
1094 			format = ri.rgbaFormat;
1095 		else
1096 			format = ri.rgbaFormatCompressed;
1097 		break;
1098 	}
1099 
1100 	return format;
1101 }
1102 
1103 
1104 /*
1105 ================
1106 R_LightScaleImage
1107 
1108 Scale up the pixel values in a texture to increase the lighting range
1109 ================
1110 */
R_LightScaleImage(uint32 * in,int inWidth,int inHeight,qBool useGamma,qBool useIntensity)1111 static void R_LightScaleImage (uint32 *in, int inWidth, int inHeight, qBool useGamma, qBool useIntensity)
1112 {
1113 	int		i, c;
1114 	byte	*out;
1115 
1116 	out = (byte *)in;
1117 	c = inWidth * inHeight;
1118 
1119 	if (useGamma) {
1120 		if (useIntensity) {
1121 			for (i=0 ; i<c ; i++, out+=4) {
1122 				out[0] = r_gammaTable[r_intensityTable[out[0]]];
1123 				out[1] = r_gammaTable[r_intensityTable[out[1]]];
1124 				out[2] = r_gammaTable[r_intensityTable[out[2]]];
1125 			}
1126 		}
1127 		else {
1128 			for (i=0 ; i<c ; i++, out+=4) {
1129 				out[0] = r_gammaTable[out[0]];
1130 				out[1] = r_gammaTable[out[1]];
1131 				out[2] = r_gammaTable[out[2]];
1132 			}
1133 		}
1134 	}
1135 	else if (useIntensity) {
1136 		for (i=0 ; i<c ; i++, out+=4) {
1137 			out[0] = r_intensityTable[out[0]];
1138 			out[1] = r_intensityTable[out[1]];
1139 			out[2] = r_intensityTable[out[2]];
1140 		}
1141 	}
1142 }
1143 
1144 
1145 /*
1146 ================
1147 R_MipmapImage
1148 
1149 Operates in place, quartering the size of the texture
1150 ================
1151 */
R_MipmapImage(byte * in,int inWidth,int inHeight)1152 static void R_MipmapImage (byte *in, int inWidth, int inHeight)
1153 {
1154 	int		i, j;
1155 	byte	*out;
1156 
1157 	inWidth <<= 2;
1158 	inHeight >>= 1;
1159 
1160 	out = in;
1161 	for (i=0 ; i<inHeight ; i++, in+=inWidth) {
1162 		for (j=0 ; j<inWidth ; j+=8, out+=4, in+=8) {
1163 			out[0] = (in[0] + in[4] + in[inWidth+0] + in[inWidth+4])>>2;
1164 			out[1] = (in[1] + in[5] + in[inWidth+1] + in[inWidth+5])>>2;
1165 			out[2] = (in[2] + in[6] + in[inWidth+2] + in[inWidth+6])>>2;
1166 			out[3] = (in[3] + in[7] + in[inWidth+3] + in[inWidth+7])>>2;
1167 		}
1168 	}
1169 }
1170 
1171 
1172 /*
1173 ================
1174 R_ResampleImage
1175 ================
1176 */
R_ResampleImage(uint32 * in,int inWidth,int inHeight,uint32 * out,int outWidth,int outHeight)1177 static void R_ResampleImage (uint32 *in, int inWidth, int inHeight, uint32 *out, int outWidth, int outHeight)
1178 {
1179 	int		i, j;
1180 	uint32	*inrow, *inrow2;
1181 	uint32	frac, fracstep;
1182 	uint32	*p1, *p2;
1183 	byte	*pix1, *pix2, *pix3, *pix4;
1184 	uint32	*resampleBuffer;
1185 	qBool	noFree;
1186 
1187 	if (inWidth == outWidth && inHeight == outHeight) {
1188 		for (i=0 ; i<inWidth*inHeight ; i++)
1189 			*out++ = *in++;
1190 		return;
1191 	}
1192 
1193 	if (ri.reg.inSequence && outWidth*outHeight < MAX_IMAGE_SCRATCHSIZE*MAX_IMAGE_SCRATCHSIZE) {
1194 		resampleBuffer = r_imageResampleScratch;
1195 		noFree = qTrue;
1196 	}
1197 	else {
1198 		resampleBuffer = Mem_PoolAllocExt (outWidth * outHeight * sizeof (uint32), qFalse, ri.imageSysPool, r_imageAllocTag);
1199 		noFree = qFalse;
1200 	}
1201 
1202 	p1 = resampleBuffer;
1203 	p2 = resampleBuffer + outWidth;
1204 
1205 	// Resample
1206 	fracstep = inWidth * 0x10000 / outWidth;
1207 
1208 	frac = fracstep >> 2;
1209 	for (i=0 ; i<outWidth ; i++) {
1210 		p1[i] = 4 * (frac >> 16);
1211 		frac += fracstep;
1212 	}
1213 
1214 	frac = 3 * (fracstep >> 2);
1215 	for (i=0 ; i<outWidth ; i++) {
1216 		p2[i] = 4 * (frac >> 16);
1217 		frac += fracstep;
1218 	}
1219 
1220 	for (i=0 ; i<outHeight ; i++, out += outWidth) {
1221 		inrow = in + inWidth * (int)((i + 0.25f) * inHeight / outHeight);
1222 		inrow2 = in + inWidth * (int)((i + 0.75f) * inHeight / outHeight);
1223 		frac = fracstep >> 1;
1224 
1225 		for (j=0 ; j<outWidth ; j++) {
1226 			pix1 = (byte *)inrow + p1[j];
1227 			pix2 = (byte *)inrow + p2[j];
1228 			pix3 = (byte *)inrow2 + p1[j];
1229 			pix4 = (byte *)inrow2 + p2[j];
1230 
1231 			((byte *)(out + j))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0]) >> 2;
1232 			((byte *)(out + j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1]) >> 2;
1233 			((byte *)(out + j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2]) >> 2;
1234 			((byte *)(out + j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3]) >> 2;
1235 		}
1236 	}
1237 
1238 	if (!noFree)
1239 		Mem_Free (resampleBuffer);
1240 
1241 	ri.reg.imagesResampled++;
1242 }
1243 
1244 /*
1245 ==============================================================================
1246 
1247 	IMAGE UPLOADING
1248 
1249 ==============================================================================
1250 */
1251 
1252 /*
1253 ===============
1254 R_UploadCMImage
1255 ===============
1256 */
R_UploadCMImage(char * name,byte ** data,int width,int height,int flags,int samples,int * upWidth,int * upHeight,int * upFormat)1257 static void R_UploadCMImage (char *name, byte **data, int width, int height, int flags, int samples, int *upWidth, int *upHeight, int *upFormat)
1258 {
1259 	GLsizei		scaledWidth, scaledHeight;
1260 	uint32		*scaledData;
1261 	qBool		mipMap;
1262 	GLint		format;
1263 	qBool		noFree;
1264 	int			i, c;
1265 
1266 	// Find next highest power of two
1267 	for (scaledWidth=1 ; scaledWidth<width ; scaledWidth<<=1) ;
1268 	for (scaledHeight=1 ; scaledHeight<height ; scaledHeight<<=1) ;
1269 	if (r_roundImagesDown->intVal) {
1270 		if (scaledWidth > width)
1271 			scaledWidth >>= 1;
1272 		if (scaledHeight > height)
1273 			scaledHeight >>= 1;
1274 	}
1275 
1276 	// Mipmap
1277 	mipMap = (flags & (IF_NOMIPMAP_LINEAR|IF_NOMIPMAP_NEAREST)) ? qFalse : qTrue;
1278 
1279 	// Let people sample down the world textures for speed
1280 	if (mipMap && !(flags & IF_NOPICMIP)) {
1281 		if (gl_picmip->intVal > 0) {
1282 			scaledWidth >>= gl_picmip->intVal;
1283 			scaledHeight >>= gl_picmip->intVal;
1284 		}
1285 	}
1286 
1287 	// Clamp dimensions
1288 	scaledWidth = clamp (scaledWidth, 1, ri.config.maxCMTexSize);
1289 	scaledHeight = clamp (scaledHeight, 1, ri.config.maxCMTexSize);
1290 
1291 	// Get the image format
1292 	format = R_ImageFormat (name, flags, &samples);
1293 
1294 	// Set base upload values
1295 	if (upWidth)
1296 		*upWidth = scaledWidth;
1297 	if (upHeight)
1298 		*upHeight = scaledHeight;
1299 	if (upFormat)
1300 		*upFormat = format;
1301 
1302 	// Texture params
1303 	if (mipMap) {
1304 		if (ri.config.extSGISGenMipmap)
1305 			qglTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
1306 
1307 		if (ri.config.extTexFilterAniso)
1308 			qglTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAX_ANISOTROPY_EXT, clamp (r_ext_maxAnisotropy->intVal, 1, ri.config.maxAniso));
1309 
1310 		qglTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, ri.texMinFilter);
1311 		qglTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, ri.texMagFilter);
1312 	}
1313 	else {
1314 		if (ri.config.extSGISGenMipmap)
1315 			qglTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
1316 
1317 		if (ri.config.extTexFilterAniso)
1318 			qglTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1);
1319 
1320 		if (flags & IF_NOMIPMAP_LINEAR) {
1321 			qglTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1322 			qglTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1323 		}
1324 		else {
1325 			qglTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1326 			qglTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1327 		}
1328 	}
1329 
1330 	// Cubemaps use edge clamping
1331 	if (ri.config.extTexEdgeClamp) {
1332 		qglTexParameterf (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1333 		qglTexParameterf (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1334 		qglTexParameterf (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
1335 	}
1336 	else {
1337 		qglTexParameterf (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
1338 		qglTexParameterf (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
1339 		qglTexParameterf (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, GL_CLAMP);
1340 	}
1341 
1342 	// Allocate a buffer
1343 	if (ri.reg.inSequence && scaledWidth*scaledHeight < MAX_IMAGE_SCRATCHSIZE*MAX_IMAGE_SCRATCHSIZE) {
1344 		scaledData = r_imageScaleScratch;
1345 		noFree = qTrue;
1346 	}
1347 	else {
1348 		scaledData = Mem_PoolAllocExt (scaledWidth * scaledHeight * 4, qFalse, ri.imageSysPool, r_imageAllocTag);
1349 		noFree = qFalse;
1350 	}
1351 
1352 	// Upload
1353 	for (i=0 ; i<6 ; i++) {
1354 		// Resample
1355 		R_ResampleImage ((uint32 *)(data[i]), width, height, scaledData, scaledWidth, scaledHeight);
1356 
1357 		// Scan and replace channels if desired
1358 		if (flags & (IF_NORGB|IF_NOALPHA)) {
1359 			byte	*scan;
1360 
1361 			if (flags & IF_NORGB) {
1362 				scan = (byte *)scaledData;
1363 				for (c=scaledWidth*scaledHeight ; c>0 ; c--, scan+=4)
1364 					scan[0] = scan[1] = scan[2] = 255;
1365 			}
1366 			else {
1367 				scan = (byte *)scaledData + 3;
1368 				for (c=scaledWidth*scaledHeight ; c>0 ; c--, scan+=4)
1369 					*scan = 255;
1370 			}
1371 		}
1372 
1373 		// Apply image gamma/intensity
1374 		R_LightScaleImage (scaledData, scaledWidth, scaledHeight, (!(flags & IF_NOGAMMA)) && !ri.config.hwGammaInUse, mipMap && !(flags & IF_NOINTENS));
1375 
1376 		// Upload the base image
1377 		qglTexImage2D (r_cubeTargets[i], 0, format, scaledWidth, scaledHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledData);
1378 
1379 		// Upload mipmap levels
1380 		if (mipMap && !ri.config.extSGISGenMipmap) {
1381 			int		mipWidth, mipHeight;
1382 			int		mipLevel;
1383 
1384 			mipLevel = 0;
1385 			mipWidth = scaledWidth;
1386 			mipHeight = scaledHeight;
1387 			while (mipWidth > 1 || mipHeight > 1) {
1388 				R_MipmapImage ((byte *)scaledData, mipWidth, mipHeight);
1389 
1390 				mipWidth >>= 1;
1391 				if (mipWidth < 1)
1392 					mipWidth = 1;
1393 
1394 				mipHeight >>= 1;
1395 				if (mipHeight < 1)
1396 					mipHeight = 1;
1397 
1398 				mipLevel++;
1399 
1400 				if (r_colorMipLevels->intVal)
1401 					R_ColorMipLevel ((byte *)scaledData, mipWidth * mipHeight, mipLevel);
1402 
1403 				qglTexImage2D (r_cubeTargets[i], mipLevel, format, mipWidth, mipHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledData);
1404 			}
1405 		}
1406 	}
1407 
1408 	// Done
1409 	if (!noFree)
1410 		Mem_Free (scaledData);
1411 }
1412 
1413 
1414 /*
1415 ===============
1416 R_Upload2DImage
1417 ===============
1418 */
R_Upload2DImage(char * name,byte * data,int width,int height,int flags,int samples,int * upWidth,int * upHeight,int * upFormat)1419 static void R_Upload2DImage (char *name, byte *data, int width, int height, int flags, int samples, int *upWidth, int *upHeight, int *upFormat)
1420 {
1421 	GLsizei		scaledWidth, scaledHeight;
1422 	uint32		*scaledData;
1423 	qBool		mipMap;
1424 	GLint		format;
1425 	qBool		noFree;
1426 	int			c;
1427 
1428 	// Find next highest power of two
1429 	for (scaledWidth=1 ; scaledWidth<width ; scaledWidth<<=1) ;
1430 	for (scaledHeight=1 ; scaledHeight<height ; scaledHeight<<=1) ;
1431 	if (r_roundImagesDown->intVal) {
1432 		if (scaledWidth > width)
1433 			scaledWidth >>= 1;
1434 		if (scaledHeight > height)
1435 			scaledHeight >>= 1;
1436 	}
1437 
1438 	// Mipmap
1439 	mipMap = (flags & (IF_NOMIPMAP_LINEAR|IF_NOMIPMAP_NEAREST)) ? qFalse : qTrue;
1440 
1441 	// Let people sample down the world textures for speed
1442 	if (mipMap && !(flags & IF_NOPICMIP)) {
1443 		if (gl_picmip->intVal > 0) {
1444 			scaledWidth >>= gl_picmip->intVal;
1445 			scaledHeight >>= gl_picmip->intVal;
1446 		}
1447 	}
1448 
1449 	// Clamp dimensions
1450 	scaledWidth = clamp (scaledWidth, 1, ri.config.maxTexSize);
1451 	scaledHeight = clamp (scaledHeight, 1, ri.config.maxTexSize);
1452 
1453 	// Get the image format
1454 	format = R_ImageFormat (name, flags, &samples);
1455 
1456 	// Set base upload values
1457 	if (upWidth)
1458 		*upWidth = scaledWidth;
1459 	if (upHeight)
1460 		*upHeight = scaledHeight;
1461 	if (upFormat)
1462 		*upFormat = format;
1463 
1464 	// Texture params
1465 	if (mipMap) {
1466 		if (ri.config.extSGISGenMipmap)
1467 			qglTexParameteri (GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
1468 
1469 		if (ri.config.extTexFilterAniso)
1470 			qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, clamp (r_ext_maxAnisotropy->intVal, 1, ri.config.maxAniso));
1471 
1472 		qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, ri.texMinFilter);
1473 		qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, ri.texMagFilter);
1474 	}
1475 	else {
1476 		if (ri.config.extSGISGenMipmap)
1477 			qglTexParameteri (GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
1478 
1479 		if (ri.config.extTexFilterAniso)
1480 			qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1);
1481 
1482 		if (flags & IF_NOMIPMAP_LINEAR) {
1483 			qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1484 			qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1485 		}
1486 		else {
1487 			qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1488 			qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1489 		}
1490 	}
1491 
1492 	// Texture edge clamping
1493 	if (!(flags & IF_CLAMP)) {
1494 		qglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1495 		qglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1496 	}
1497 	else if (ri.config.extTexEdgeClamp) {
1498 		qglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1499 		qglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1500 	}
1501 	else {
1502 		qglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
1503 		qglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
1504 	}
1505 
1506 	// Allocate a buffer
1507 	if (ri.reg.inSequence && scaledWidth*scaledHeight < MAX_IMAGE_SCRATCHSIZE*MAX_IMAGE_SCRATCHSIZE) {
1508 		scaledData = r_imageScaleScratch;
1509 		noFree = qTrue;
1510 	}
1511 	else {
1512 		scaledData = Mem_PoolAllocExt (scaledWidth * scaledHeight * 4, qFalse, ri.imageSysPool, r_imageAllocTag);
1513 		noFree = qFalse;
1514 	}
1515 
1516 	// Resample
1517 	R_ResampleImage ((uint32 *)data, width, height, scaledData, scaledWidth, scaledHeight);
1518 
1519 	// Scan and replace channels if desired
1520 	if (flags & (IF_NORGB|IF_NOALPHA)) {
1521 		byte	*scan;
1522 
1523 		if (flags & IF_NORGB) {
1524 			scan = (byte *)scaledData;
1525 			for (c=scaledWidth*scaledHeight ; c>0 ; c--, scan+=4)
1526 				scan[0] = scan[1] = scan[2] = 255;
1527 		}
1528 		else {
1529 			scan = (byte *)scaledData + 3;
1530 			for (c=scaledWidth*scaledHeight ; c>0 ; c--, scan+=4)
1531 				*scan = 255;
1532 		}
1533 	}
1534 
1535 	// Apply image gamma/intensity
1536 	R_LightScaleImage (scaledData, scaledWidth, scaledHeight, (!(flags & IF_NOGAMMA)) && !ri.config.hwGammaInUse, mipMap && !(flags & IF_NOINTENS));
1537 
1538 	// Upload the base image
1539 	qglTexImage2D (GL_TEXTURE_2D, 0, format, scaledWidth, scaledHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledData);
1540 
1541 	// Upload mipmap levels
1542 	if (mipMap && !ri.config.extSGISGenMipmap) {
1543 		int		mipWidth, mipHeight;
1544 		int		mipLevel;
1545 
1546 		mipLevel = 0;
1547 		mipWidth = scaledWidth;
1548 		mipHeight = scaledHeight;
1549 		while (mipWidth > 1 || mipHeight > 1) {
1550 			R_MipmapImage ((byte *)scaledData, mipWidth, mipHeight);
1551 
1552 			mipWidth >>= 1;
1553 			if (mipWidth < 1)
1554 				mipWidth = 1;
1555 
1556 			mipHeight >>= 1;
1557 			if (mipHeight < 1)
1558 				mipHeight = 1;
1559 
1560 			mipLevel++;
1561 
1562 			if (r_colorMipLevels->intVal)
1563 				R_ColorMipLevel ((byte *)scaledData, mipWidth * mipHeight, mipLevel);
1564 
1565 			qglTexImage2D (GL_TEXTURE_2D, mipLevel, format, mipWidth, mipHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledData);
1566 		}
1567 	}
1568 
1569 	// Done
1570 	if (!noFree)
1571 		Mem_Free (scaledData);
1572 }
1573 
1574 
1575 /*
1576 ===============
1577 R_Upload3DImage
1578 
1579 FIXME:
1580 - Support mipmapping, light scaling, and size scaling
1581 - Test SGIS mipmap gen
1582 - r_roundImagesDown, r_colorMipLevels
1583 ===============
1584 */
R_Upload3DImage(char * name,byte ** data,int width,int height,int depth,int flags,int samples,int * upWidth,int * upHeight,int * upDepth,int * upFormat)1585 static void R_Upload3DImage (char *name, byte **data, int width, int height, int depth, int flags, int samples, int *upWidth, int *upHeight, int *upDepth, int *upFormat)
1586 {
1587 	GLsizei		scaledWidth, scaledHeight, scaledDepth;
1588 	GLint		format;
1589 	qBool		mipMap;
1590 	int			i, c;
1591 
1592 	// Find next highest power of two
1593 	for (scaledWidth=1 ; scaledWidth<width ; scaledWidth<<=1) ;
1594 	for (scaledHeight=1 ; scaledHeight<height ; scaledHeight<<=1) ;
1595 	for (scaledDepth=1 ; scaledDepth<depth ; scaledDepth<<=1) ;
1596 
1597 	// Mipmap
1598 	mipMap = (flags & (IF_NOMIPMAP_LINEAR|IF_NOMIPMAP_NEAREST)) ? qFalse : qTrue;
1599 
1600 	// Mipmapping not supported
1601 	if (mipMap && !ri.config.extSGISGenMipmap)
1602 		Com_Error (ERR_DROP, "R_Upload3DImage: mipmapping not yet supported");
1603 	if (width != scaledWidth || height != scaledHeight || depth != scaledDepth)
1604 		Com_Error (ERR_DROP, "R_Upload3DImage: scaling not supported, use power of two dimensions and depth");
1605 	if (scaledWidth > ri.config.max3DTexSize || scaledHeight > ri.config.max3DTexSize || scaledDepth > ri.config.max3DTexSize)
1606 		Com_Error (ERR_DROP, "R_Upload3DImage: dimensions too large, scaling not yet supported");
1607 
1608 	// Get the image format
1609 	format = R_ImageFormat (name, flags, &samples);
1610 
1611 	// Set base upload values
1612 	if (upWidth)
1613 		*upWidth = scaledWidth;
1614 	if (upHeight)
1615 		*upHeight = scaledHeight;
1616 	if (upDepth)
1617 		*upDepth = scaledDepth;
1618 	if (upFormat)
1619 		*upFormat = format;
1620 
1621 	// Texture params
1622 	if (mipMap) {
1623 		if (ri.config.extSGISGenMipmap)
1624 			qglTexParameteri (GL_TEXTURE_3D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
1625 
1626 		if (ri.config.extTexFilterAniso)
1627 			qglTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MAX_ANISOTROPY_EXT, clamp (r_ext_maxAnisotropy->intVal, 1, ri.config.maxAniso));
1628 
1629 		qglTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, ri.texMinFilter);
1630 		qglTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, ri.texMagFilter);
1631 	}
1632 	else {
1633 		if (ri.config.extSGISGenMipmap)
1634 			qglTexParameteri (GL_TEXTURE_3D, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
1635 
1636 		if (ri.config.extTexFilterAniso)
1637 			qglTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1);
1638 
1639 		if (flags & IF_NOMIPMAP_LINEAR) {
1640 			qglTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1641 			qglTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1642 		}
1643 		else {
1644 			qglTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1645 			qglTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1646 		}
1647 	}
1648 
1649 	// Texture edge clamping
1650 	if (!(flags & IF_CLAMP)) {
1651 		qglTexParameterf (GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1652 		qglTexParameterf (GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1653 		qglTexParameterf (GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
1654 	}
1655 	else if (ri.config.extTexEdgeClamp) {
1656 		qglTexParameterf (GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1657 		qglTexParameterf (GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1658 		qglTexParameterf (GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
1659 	}
1660 	else {
1661 		qglTexParameterf (GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
1662 		qglTexParameterf (GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
1663 		qglTexParameterf (GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
1664 	}
1665 
1666 	// Scan and replace channels if desired
1667 	if (flags & (IF_NORGB|IF_NOALPHA)) {
1668 		byte	*scan;
1669 
1670 		if (flags & IF_NORGB) {
1671 			for (i=0 ; i<depth ; i++) {
1672 				scan = (byte *)data[i];
1673 				for (c=scaledWidth*scaledHeight ; c>0 ; c--, scan+=4)
1674 					scan[0] = scan[1] = scan[2] = 255;
1675 			}
1676 		}
1677 		else {
1678 			for (i=0 ; i<depth ; i++) {
1679 				scan = (byte *)data[i] + 3;
1680 				for (c=scaledWidth*scaledHeight ; c>0 ; c--, scan+=4)
1681 					*scan = 255;
1682 			}
1683 		}
1684 	}
1685 
1686 	// Upload
1687 	qglTexImage3D (GL_TEXTURE_3D, 0, format, scaledWidth, scaledHeight, scaledDepth, 0, GL_RGBA, GL_UNSIGNED_BYTE, data[0]);
1688 }
1689 
1690 /*
1691 ==============================================================================
1692 
1693 	WAL/PCX PALETTE
1694 
1695 ==============================================================================
1696 */
1697 
1698 /*
1699 ===============
1700 R_PalToRGBA
1701 
1702 Converts a paletted image to standard RGB[A] before passing off for upload.
1703 Also finds out if it's RGB or RGBA.
1704 ===============
1705 */
1706 typedef struct floodFill_s {
1707 	int		x, y;
1708 } floodFill_t;
1709 
1710 // must be a power of 2
1711 #define FLOODFILL_FIFO_SIZE 0x1000
1712 #define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1)
1713 
1714 #define FLOODFILL_STEP( off, dx, dy ) \
1715 { \
1716 	if (pos[off] == fillColor) { \
1717 		pos[off] = 255; \
1718 		fifo[inpt].x = x + (dx), fifo[inpt].y = y + (dy); \
1719 		inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \
1720 	} \
1721 	else if (pos[off] != 255) fdc = pos[off]; \
1722 }
1723 
R_FloodFillSkin(byte * skin,int skinWidth,int skinHeight)1724 static void R_FloodFillSkin (byte *skin, int skinWidth, int skinHeight)
1725 {
1726 	byte		fillColor;
1727 	floodFill_t	fifo[FLOODFILL_FIFO_SIZE];
1728 	int			inpt = 0, outpt = 0;
1729 	int			filledColor;
1730 	int			i;
1731 
1732 	// Assume this is the pixel to fill
1733 	fillColor = *skin;
1734 	filledColor = -1;
1735 
1736 	if (filledColor == -1) {
1737 		filledColor = 0;
1738 		// Attempt to find opaque black
1739 		for (i=0 ; i<256 ; ++i) {
1740 			if (r_paletteTable[i] == (255 << 0)) {
1741 				// Alpha 1.0
1742 				filledColor = i;
1743 				break;
1744 			}
1745 		}
1746 	}
1747 
1748 	// Can't fill to filled color or to transparent color (used as visited marker)
1749 	if (fillColor == filledColor || fillColor == 255)
1750 		return;
1751 
1752 	fifo[inpt].x = 0, fifo[inpt].y = 0;
1753 	inpt = (inpt + 1) & FLOODFILL_FIFO_MASK;
1754 
1755 	while (outpt != inpt) {
1756 		int			x = fifo[outpt].x, y = fifo[outpt].y;
1757 		int			fdc = filledColor;
1758 		byte		*pos = &skin[x + skinWidth * y];
1759 
1760 		outpt = (outpt + 1) & FLOODFILL_FIFO_MASK;
1761 
1762 		if (x > 0)
1763 			FLOODFILL_STEP (-1, -1, 0);
1764 
1765 		if (x < skinWidth-1)
1766 			FLOODFILL_STEP (1, 1, 0);
1767 
1768 		if (y > 0)
1769 			FLOODFILL_STEP (-skinWidth, 0, -1);
1770 
1771 		if (y < skinHeight-1)
1772 			FLOODFILL_STEP (skinWidth, 0, 1);
1773 		skin[x + skinWidth * y] = fdc;
1774 	}
1775 }
R_PalToRGBA(char * name,byte * data,int width,int height,int flags,image_t * image,qBool isPCX)1776 static void R_PalToRGBA (char *name, byte *data, int width, int height, int flags, image_t *image, qBool isPCX)
1777 {
1778 	uint32	*trans;
1779 	int		i, s, pxl;
1780 	int		samples;
1781 	qBool	noFree;
1782 
1783 	s = width * height;
1784 	if (ri.reg.inSequence && s < MAX_IMAGE_SCRATCHSIZE*MAX_IMAGE_SCRATCHSIZE) {
1785 		trans = (uint32 *)r_palScratch;
1786 		noFree = qTrue;
1787 	}
1788 	else {
1789 		trans = Mem_PoolAllocExt (s * 4, qFalse, ri.imageSysPool, r_imageAllocTag);
1790 		noFree = qFalse;
1791 	}
1792 
1793 	// Map the palette to standard RGB
1794 	samples = 3;
1795 	for (i=0 ; i<s ; i++) {
1796 		pxl = data[i];
1797 		trans[i] = r_paletteTable[pxl];
1798 
1799 		if (pxl == 0xff) {
1800 			samples = 4;
1801 
1802 			// Transparent, so scan around for another color to avoid alpha fringes
1803 			if (i > width && data[i-width] != 255)
1804 				pxl = data[i-width];
1805 			else if (i < s-width && data[i+width] != 255)
1806 				pxl = data[i+width];
1807 			else if (i > 0 && data[i-1] != 255)
1808 				pxl = data[i-1];
1809 			else if (i < s-1 && data[i+1] != 255)
1810 				pxl = data[i+1];
1811 			else
1812 				pxl = 0;
1813 
1814 			// Copy rgb components
1815 			((byte *)&trans[i])[0] = ((byte *)&r_paletteTable[pxl])[0];
1816 			((byte *)&trans[i])[1] = ((byte *)&r_paletteTable[pxl])[1];
1817 			((byte *)&trans[i])[2] = ((byte *)&r_paletteTable[pxl])[2];
1818 		}
1819 	}
1820 
1821 	// Upload
1822 	if (isPCX)
1823 		R_FloodFillSkin ((byte *)trans, width, height);
1824 
1825 	R_Upload2DImage (name, (byte *)trans, width, height, flags, samples, &image->upWidth, &image->upHeight, &image->format);
1826 	if (!noFree)
1827 		Mem_Free (trans);
1828 }
1829 
1830 /*
1831 ==============================================================================
1832 
1833 	IMAGE LOADING
1834 
1835 ==============================================================================
1836 */
1837 
1838 /*
1839 ================
1840 R_BareImageName
1841 ================
1842 */
R_BareImageName(const char * name)1843 static const char *R_BareImageName (const char *name)
1844 {
1845 	static char	bareName[2][MAX_QPATH];
1846 	static int	bareIndex;
1847 
1848 	bareIndex ^= 1;
1849 
1850 	// Fix/strip barename
1851 	Com_NormalizePath (bareName[bareIndex], sizeof (bareName[bareIndex]), name);
1852 	Com_StripExtension (bareName[bareIndex], sizeof (bareName[bareIndex]), bareName[bareIndex]);
1853 	Q_strlwr (bareName[bareIndex]);
1854 
1855 	return bareName[bareIndex];
1856 }
1857 
1858 
1859 /*
1860 ================
1861 R_FindImage
1862 ================
1863 */
R_FindImage(const char * bareName,int flags)1864 static image_t *R_FindImage (const char *bareName, int flags)
1865 {
1866 	image_t	*image;
1867 	uint32	hash;
1868 
1869 	// Calculate hash
1870 	hash = Com_HashGeneric (bareName, MAX_IMAGE_HASH);
1871 
1872 	ri.reg.imagesSeaked++;
1873 
1874 	// Look for it
1875 	if (flags == 0) {
1876 		for (image=r_imageHashTree[hash] ; image ; image=image->hashNext) {
1877 			if (!image->touchFrame)
1878 				continue;	// Free r_imageList slot
1879 
1880 			// Check name
1881 			if (!strcmp (bareName, image->bareName))
1882 				return image;
1883 		}
1884 	}
1885 	else {
1886 		for (image=r_imageHashTree[hash] ; image ; image=image->hashNext) {
1887 			if (!image->touchFrame)
1888 				continue;	// Free r_imageList slot
1889 			if (image->flags != flags)
1890 				continue;
1891 
1892 			// Check name
1893 			if (!strcmp (bareName, image->bareName))
1894 				return image;
1895 		}
1896 	}
1897 
1898 	return NULL;
1899 }
1900 
1901 
1902 /*
1903 ================
1904 R_LoadImage
1905 
1906 This is also used as an entry point for the generated ri.noTexture
1907 ================
1908 */
R_LoadImage(char * name,const char * bareName,byte ** pic,int width,int height,int depth,texFlags_t flags,int samples,qBool upload8,qBool isPCX)1909 image_t *R_LoadImage (char *name, const char *bareName, byte **pic, int width, int height, int depth, texFlags_t flags, int samples, qBool upload8, qBool isPCX)
1910 {
1911 	image_t		*image;
1912 	uint32		i;
1913 
1914 	// Find a free r_imageList spot
1915 	for (i=0, image=r_imageList ; i<r_numImages ; i++, image++) {
1916 		if (image->touchFrame)
1917 			continue;	// Used r_imageList slot
1918 
1919 		image->texNum = i + 1;
1920 		break;
1921 	}
1922 
1923 	// None found, create a new spot
1924 	if (i == r_numImages) {
1925 		if (r_numImages+1 >= MAX_IMAGES)
1926 			Com_Error (ERR_DROP, "R_LoadImage: MAX_IMAGES");
1927 
1928 		image = &r_imageList[r_numImages++];
1929 		image->texNum = r_numImages;
1930 	}
1931 
1932 	// See if this texture is allowed
1933 	if (image->flags & IT_3D && depth > 1 && !ri.config.extTex3D)
1934 		Com_Error (ERR_DROP, "R_LoadImage: '%s' is 3D and 3D textures are disabled", name);
1935 
1936 	// Set the name
1937 	Q_strncpyz (image->name, name, sizeof (image->name));
1938 	if (!bareName)
1939 		bareName = R_BareImageName (name);
1940 	Q_strncpyz (image->bareName, bareName, sizeof (image->bareName));
1941 
1942 	// Set width, height, and depth
1943 	image->width = image->tcWidth = width;
1944 	image->height = image->tcHeight = height;
1945 	image->depth = depth;
1946 
1947 	// Texture scaling, hacky special case!
1948 	if (!upload8 && !(flags & (IF_NOMIPMAP_NEAREST|IF_NOMIPMAP_LINEAR))) {
1949 		char		newName[MAX_QPATH];
1950 		walTex_t	*mt;
1951 		int			fileLen;
1952 
1953 		Q_snprintfz (newName, sizeof (newName), "%s.wal", image->bareName);
1954 		fileLen = FS_LoadFile (newName, (void **)&mt, NULL);
1955 		if (mt && fileLen > 0) {
1956 			image->tcWidth = LittleLong (mt->width);
1957 			image->tcHeight = LittleLong (mt->height);
1958 
1959 			FS_FreeFile (mt);
1960 		}
1961 	}
1962 
1963 	// Set base values
1964 	image->flags = flags;
1965 	image->touchFrame = ri.reg.registerFrame;
1966 	image->hashValue = Com_HashGeneric (image->bareName, MAX_IMAGE_HASH);
1967 
1968 	if (!(image->flags & (IT_CUBEMAP|IT_3D)))
1969 		image->target = GL_TEXTURE_2D;
1970 	else if (image->flags & IT_CUBEMAP)
1971 		image->target = GL_TEXTURE_CUBE_MAP_ARB;
1972 	else if (image->depth > 1) {
1973 		image->target = GL_TEXTURE_3D;
1974 		assert (image->flags & IT_3D);
1975 	}
1976 
1977 	// Upload
1978 	RB_BindTexture (image);
1979 	switch (image->target) {
1980 	case GL_TEXTURE_2D:
1981 		if (upload8)
1982 			R_PalToRGBA (name, *pic, width, height, flags, image, isPCX);
1983 		else
1984 			R_Upload2DImage (name, *pic, width, height, flags, samples, &image->upWidth, &image->upHeight, &image->format);
1985 		break;
1986 
1987 	case GL_TEXTURE_3D:
1988 		R_Upload3DImage (name, pic, width, height, depth, flags, samples, &image->upWidth, &image->upHeight, &image->upDepth, &image->format);
1989 		break;
1990 
1991 	case GL_TEXTURE_CUBE_MAP_ARB:
1992 		R_UploadCMImage (name, pic, width, height, flags, samples, &image->upWidth, &image->upHeight, &image->format);
1993 		break;
1994 	}
1995 
1996 	// Link it in
1997 	image->hashNext = r_imageHashTree[image->hashValue];
1998 	r_imageHashTree[image->hashValue] = image;
1999 	return image;
2000 }
2001 
2002 
2003 /*
2004 ===============
2005 R_RegisterCubeMap
2006 
2007 Finds or loads the given cubemap image
2008 Static because R_RegisterImage uses it if it's passed the IT_CUBEMAP flag
2009 ===============
2010 */
R_RegisterCubeMap(char * name,texFlags_t flags)2011 static inline image_t *R_RegisterCubeMap (char *name, texFlags_t flags)
2012 {
2013 	image_t		*image;
2014 	int			i, len;
2015 	int			samples;
2016 	byte		*pic[6];
2017 	int			width, height;
2018 	int			firstSize, firstSamples;
2019 	char		loadName[MAX_QPATH];
2020 	const char	*bareName;
2021 
2022 	// Make sure we have this
2023 	flags |= (IT_CUBEMAP|IF_CLAMP);
2024 
2025 	// Generate the bare name
2026 	bareName = R_BareImageName (name);
2027 
2028 	// See if it's already loaded
2029 	image = R_FindImage (bareName, flags);
2030 	if (image) {
2031 		R_TouchImage (image);
2032 		return image;
2033 	}
2034 
2035 	// Not found -- load the pic from disk
2036 	for (i=0 ; i<6 ; i++) {
2037 		pic[i] = NULL;
2038 
2039 		Q_snprintfz (loadName, sizeof (loadName), "%s_%s.png", bareName, r_cubeMapSuffix[i]);
2040 		len = strlen(loadName);
2041 
2042 		// PNG
2043 		R_LoadPNG (loadName, &pic[i], &width, &height, &samples);
2044 		if (!pic[i]) {
2045 			// TGA
2046 			loadName[len-3] = 't'; loadName[len-2] = 'g'; loadName[len-1] = 'a';
2047 			R_LoadTGA (loadName, &pic[i], &width, &height, &samples);
2048 			if (!pic[i]) {
2049 				// JPG
2050 				samples = 3;
2051 				loadName[len-3] = 'j'; loadName[len-2] = 'p'; loadName[len-1] = 'g';
2052 				R_LoadJPG (loadName, &pic[i], &width, &height);
2053 
2054 				// Not found
2055 				if (!pic[i]) {
2056 					Com_Printf (PRNT_WARNING, "R_RegisterCubeMap: Unable to find all of the sides, aborting!\n");
2057 					break;
2058 				}
2059 			}
2060 		}
2061 
2062 		// Must be square
2063 		if (width != height) {
2064 			Com_Printf (PRNT_WARNING, "R_RegisterCubeMap: %s is not square, aborting!\n", loadName);
2065 			break;
2066 		}
2067 
2068 		// Must match previous
2069 		if (!i) {
2070 			firstSize = width;
2071 			firstSamples = samples;
2072 		}
2073 		else {
2074 			if (firstSize != width) {
2075 				Com_Printf (PRNT_WARNING, "R_RegisterCubeMap: Size mismatch with previous on %s, aborting!\n", loadName);
2076 				break;
2077 			}
2078 
2079 			if (firstSamples != samples) {
2080 				Com_Printf (PRNT_WARNING, "R_RegisterCubeMap: Sample mismatch with previous on %s, aborting!\n", loadName);
2081 				break;
2082 			}
2083 		}
2084 	}
2085 
2086 	// Load the cubemap
2087 	if (i == 6)
2088 		image = R_LoadImage (loadName, bareName, pic, width, height, 1, flags, samples, qFalse, qFalse);
2089 
2090 	// Finish
2091 	for (i=0 ; i<6 ; i++) {
2092 		if (pic[i])
2093 			Mem_Free (pic[i]);
2094 	}
2095 
2096 	return image;
2097 }
2098 
2099 
2100 /*
2101 ===============
2102 R_RegisterImage
2103 
2104 Finds or loads the given image
2105 ===============
2106 */
R_RegisterImage(char * name,texFlags_t flags)2107 image_t	*R_RegisterImage (char *name, texFlags_t flags)
2108 {
2109 	image_t		*image;
2110 	byte		*pic;
2111 	int			len, width, height, samples;
2112 	char		loadName[MAX_QPATH];
2113 	const char	*bareName;
2114 
2115 	// Check the name
2116 	if (!name)
2117 		return NULL;
2118 
2119 	// Check the length
2120 	len = strlen (name);
2121 	if (len < 5) {
2122 		Com_Printf (PRNT_ERROR, "R_RegisterImage: Image name too short! %s\n");
2123 		return NULL;
2124 	}
2125 	if (len+1 >= MAX_QPATH) {
2126 		Com_Printf (PRNT_ERROR, "R_RegisterImage: Image name too long! %s\n");
2127 		return NULL;
2128 	}
2129 
2130 	// Cubemap stuff
2131 	if (flags & IT_CUBEMAP) {
2132 		if (ri.config.extTexCubeMap)
2133 			return R_RegisterCubeMap (name, flags);
2134 		flags &= ~IT_CUBEMAP;
2135 	}
2136 
2137 	// Generate the bare name
2138 	bareName = R_BareImageName (name);
2139 
2140 	// See if it's already loaded
2141 	image = R_FindImage (bareName, flags);
2142 	if (image) {
2143 		R_TouchImage (image);
2144 		return image;
2145 	}
2146 
2147 	// Not found -- load the pic from disk
2148 	Q_snprintfz (loadName, sizeof (loadName), "%s.png", bareName);
2149 	len = strlen(loadName);
2150 
2151 	// PNG
2152 	R_LoadPNG (loadName, &pic, &width, &height, &samples);
2153 	if (!pic) {
2154 		// TGA
2155 		loadName[len-3] = 't'; loadName[len-2] = 'g'; loadName[len-1] = 'a';
2156 		R_LoadTGA (loadName, &pic, &width, &height, &samples);
2157 		if (!pic) {
2158 			// JPG
2159 			samples = 3;
2160 			loadName[len-3] = 'j'; loadName[len-2] = 'p'; loadName[len-1] = 'g';
2161 			R_LoadJPG (loadName, &pic, &width, &height);
2162 			if (!pic) {
2163 				// WAL
2164 				if (!(strcmp (name+len-4, ".wal"))) {
2165 					loadName[len-3] = 'w'; loadName[len-2] = 'a'; loadName[len-1] = 'l';
2166 					R_LoadWal (loadName, &pic, &width, &height);
2167 					if (pic) {
2168 						image = R_LoadImage (loadName, bareName, &pic, width, height, 1, flags, samples, qTrue, qFalse);
2169 						return image;
2170 					}
2171 					return NULL;
2172 				}
2173 
2174 				// PCX
2175 				loadName[len-3] = 'p'; loadName[len-2] = 'c'; loadName[len-1] = 'x';
2176 				R_LoadPCX (loadName, &pic, NULL, &width, &height);
2177 				if (pic) {
2178 					image = R_LoadImage (loadName, bareName, &pic, width, height, 1, flags, samples, qTrue, qTrue);
2179 					return image;
2180 				}
2181 				return NULL;
2182 			}
2183 		}
2184 	}
2185 
2186 	// Found it, upload it
2187 	image = R_LoadImage (loadName, bareName, &pic, width, height, 1, flags, samples, qFalse, qFalse);
2188 
2189 	// Finish
2190 	if (pic)
2191 		Mem_Free (pic);
2192 
2193 	return image;
2194 }
2195 
2196 
2197 /*
2198 ================
2199 R_FreeImage
2200 ================
2201 */
R_FreeImage(image_t * image)2202 static inline void R_FreeImage (image_t *image)
2203 {
2204 	image_t	*hashImg;
2205 	image_t	**prev;
2206 
2207 	assert (image);
2208 	if (!image)
2209 		return;
2210 
2211 	// De-link it from the hash tree
2212 	prev = &r_imageHashTree[image->hashValue];
2213 	for ( ; ; ) {
2214 		hashImg = *prev;
2215 		if (!hashImg)
2216 			break;
2217 
2218 		if (hashImg == image) {
2219 			*prev = hashImg->hashNext;
2220 			break;
2221 		}
2222 		prev = &hashImg->hashNext;
2223 	}
2224 
2225 	// Free it
2226 	if (image->texNum)
2227 		qglDeleteTextures (1, &image->texNum);
2228 	else
2229 		Com_DevPrintf (PRNT_WARNING, "R_FreeImage: attempted to release invalid texNum on image '%s'!\n", image->name);
2230 	image->touchFrame = 0;
2231 }
2232 
2233 
2234 /*
2235 ================
2236 R_BeginImageRegistration
2237 ================
2238 */
R_BeginImageRegistration(void)2239 void R_BeginImageRegistration (void)
2240 {
2241 	// Allocate a registration scratch space
2242 	r_palScratch = Mem_PoolAllocExt (MAX_IMAGE_SCRATCHSIZE*MAX_IMAGE_SCRATCHSIZE*4, qFalse, ri.imageSysPool, IMGTAG_REG);
2243 	r_imageScaleScratch = Mem_PoolAllocExt (MAX_IMAGE_SCRATCHSIZE*MAX_IMAGE_SCRATCHSIZE*sizeof(uint32), qFalse, ri.imageSysPool, IMGTAG_REG);
2244 	r_imageResampleScratch = Mem_PoolAllocExt (MAX_IMAGE_SCRATCHSIZE*MAX_IMAGE_SCRATCHSIZE*sizeof(uint32), qFalse, ri.imageSysPool, IMGTAG_REG);
2245 }
2246 
2247 
2248 /*
2249 ================
2250 R_EndImageRegistration
2251 
2252 Any image that was not touched on this registration sequence will be released
2253 ================
2254 */
R_EndImageRegistration(void)2255 void R_EndImageRegistration (void)
2256 {
2257 	image_t	*image;
2258 	uint32	i;
2259 
2260 	// Free the scratch
2261 	Mem_FreeTag (ri.imageSysPool, IMGTAG_REG);
2262 	r_palScratch = NULL;
2263 	r_imageScaleScratch = NULL;
2264 	r_imageResampleScratch = NULL;
2265 
2266 	// Free un-touched images
2267 	for (i=0, image=r_imageList ; i<r_numImages ; i++, image++) {
2268 		if (!image->touchFrame)
2269 			continue;	// Free r_imageList slot
2270 		if (image->touchFrame == ri.reg.registerFrame)
2271 			continue;	// Used this sequence
2272 		if (image->flags & IF_NOFLUSH) {
2273 			R_TouchImage (image);
2274 			continue;	// Don't free
2275 		}
2276 
2277 		R_FreeImage (image);
2278 		ri.reg.imagesReleased++;
2279 	}
2280 }
2281 
2282 
2283 /*
2284 ===============
2285 R_UpdateTexture
2286 ===============
2287 */
R_UpdateTexture(char * name,byte * data,int width,int height)2288 qBool R_UpdateTexture (char *name, byte *data, int width, int height)
2289 {
2290 	image_t		*image;
2291 	const char	*bareName;
2292 
2293 	// Check name
2294 	if (!name || !name[0])
2295 		Com_Error (ERR_DROP, "R_UpdateTexture: NULL texture name");
2296 
2297 	// Generate the bare name
2298 	bareName = R_BareImageName (name);
2299 
2300 	// Find the image
2301 	image = R_FindImage (bareName, 0);
2302 	if (!image) {
2303 		Com_DevPrintf (PRNT_WARNING, "R_UpdateTexture: %s: could not find!\n", name);
2304 		return qFalse;
2305 	}
2306 
2307 	// Can't be compressed
2308 	if (!(image->flags & IF_NOCOMPRESS)) {
2309 		Com_DevPrintf (PRNT_WARNING, "R_UpdateTexture: %s: can not update potentially compressed images!\n", name);
2310 		return qFalse;
2311 	}
2312 
2313 	// Can't be picmipped
2314 	if (!(image->flags & IF_NOPICMIP)) {
2315 		Com_DevPrintf (PRNT_WARNING, "R_UpdateTexture: %s: can not update potentionally picmipped images!\n", name);
2316 		return qFalse;
2317 	}
2318 
2319 	// Can't be mipmapped
2320 	if (!(image->flags & (IF_NOMIPMAP_LINEAR|IF_NOMIPMAP_NEAREST))) {
2321 		Com_DevPrintf (PRNT_WARNING, "R_UpdateTexture: %s: can not update mipmapped images!\n", name);
2322 		return qFalse;
2323 	}
2324 
2325 	// Must be 2D
2326 	if (image->target != GL_TEXTURE_2D) {
2327 		Com_DevPrintf (PRNT_WARNING, "R_UpdateTexture: %s: must be a 2D image!\n", name);
2328 		return qFalse;
2329 	}
2330 
2331 	// Check the size
2332 	if (width > ri.config.maxTexSize || height > ri.config.maxTexSize) {
2333 		Com_DevPrintf (PRNT_WARNING, "R_UpdateTexture: %s: size exceeds card maximum!\n", name);
2334 		return qFalse;
2335 	}
2336 
2337 	// Update
2338 	RB_BindTexture (image);
2339 	qglTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
2340 	return qTrue;
2341 }
2342 
2343 
2344 /*
2345 ===============
2346 R_GetImageSize
2347 ===============
2348 */
R_GetImageSize(shader_t * shader,int * width,int * height)2349 void R_GetImageSize (shader_t *shader, int *width, int *height)
2350 {
2351 	shaderPass_t	*pass;
2352 	image_t			*image;
2353 	int				i;
2354 
2355 	if (!shader || !shader->numPasses) {
2356 		if (width)
2357 			*width = 0;
2358 		if (height)
2359 			*height = 0;
2360 		return;
2361 	}
2362 
2363 	image = NULL;
2364 	for (i=0, pass=shader->passes ; i<shader->numPasses ; pass++, i++) {
2365 		if (i != shader->sizeBase)
2366 			continue;
2367 
2368 		image = pass->animImages[0];
2369 		break;
2370 	}
2371 
2372 	if (!image)
2373 		return;
2374 
2375 	if (width)
2376 		*width = image->width;
2377 	if (height)
2378 		*height = image->height;
2379 }
2380 
2381 /*
2382 ==============================================================================
2383 
2384 	CONSOLE FUNCTIONS
2385 
2386 ==============================================================================
2387 */
2388 
2389 /*
2390 ===============
2391 R_ImageList_f
2392 ===============
2393 */
R_ImageList_f(void)2394 static void R_ImageList_f (void)
2395 {
2396 	uint32		tempWidth, tempHeight;
2397 	uint32		i, totalImages, totalMips;
2398 	uint32		mipTexels, texels;
2399 	image_t		*image;
2400 
2401 	Com_Printf (0, "------------------------------------------------------\n");
2402 	Com_Printf (0, "Tex# Ta Format       LGIFC Width Height Name\n");
2403 	Com_Printf (0, "---- -- ------------ ----- ----- ------ --------------\n");
2404 
2405 	for (i=0, totalImages=0, totalMips=0, mipTexels=0, texels=0, image=r_imageList ; i<r_numImages ; i++, image++) {
2406 		if (!image->touchFrame)
2407 			continue;	// Free r_imageList slot
2408 
2409 		// Texnum
2410 		Com_Printf (0, "%4d ", image->texNum);
2411 
2412 		// Target
2413 		switch (image->target) {
2414 		case GL_TEXTURE_CUBE_MAP_ARB:			Com_Printf (0, "CM ");			break;
2415 		case GL_TEXTURE_1D:						Com_Printf (0, "1D ");			break;
2416 		case GL_TEXTURE_2D:						Com_Printf (0, "2D ");			break;
2417 		case GL_TEXTURE_3D:						Com_Printf (0, "3D ");			break;
2418 		}
2419 
2420 		// Format
2421 		switch (image->format) {
2422 		case GL_RGBA8:							Com_Printf (0, "RGBA8     ");	break;
2423 		case GL_RGBA4:							Com_Printf (0, "RGBA4     ");	break;
2424 		case GL_RGBA:							Com_Printf (0, "RGBA      ");	break;
2425 		case GL_RGB8:							Com_Printf (0, "RGB8      ");	break;
2426 		case GL_RGB5:							Com_Printf (0, "RGB5      ");	break;
2427 		case GL_RGB:							Com_Printf (0, "RGB       ");	break;
2428 
2429 		case GL_DSDT8_NV:						Com_Printf (0, "DSDT8     ");	break;
2430 
2431 		case GL_COMPRESSED_RGB_ARB:				Com_Printf (0, "RGB   ARB  ");	break;
2432 		case GL_COMPRESSED_RGBA_ARB:			Com_Printf (0, "RGBA  ARB  ");	break;
2433 
2434 		case GL_RGB_S3TC:						Com_Printf (0, "RGB   S3   ");	break;
2435 		case GL_RGB4_S3TC:						Com_Printf (0, "RGB4  S3   ");	break;
2436 		case GL_RGBA_S3TC:						Com_Printf (0, "RGBA  S3   ");	break;
2437 		case GL_RGBA4_S3TC:						Com_Printf (0, "RGBA4 S3   ");	break;
2438 
2439 		case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:	Com_Printf (0, "RGB   DXT1 ");	break;
2440 		case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:	Com_Printf (0, "RGBA  DXT1 ");	break;
2441 		case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:	Com_Printf (0, "RGBA  DXT3 ");	break;
2442 		case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:	Com_Printf (0, "RGBA  DXT5 ");	break;
2443 
2444 		default:								Com_Printf (0, "??????     ");	break;
2445 		}
2446 
2447 		// Flags
2448 		Com_Printf (0, "%s", (image->flags & IT_LIGHTMAP)	? "L" : "-");
2449 		Com_Printf (0, "%s", (image->flags & IF_NOGAMMA)	? "-" : "G");
2450 		Com_Printf (0, "%s", (image->flags & IF_NOINTENS)	? "-" : "I");
2451 		Com_Printf (0, "%s", (image->flags & IF_NOFLUSH)	? "F" : "-");
2452 		Com_Printf (0, "%s", (image->flags & IF_CLAMP)		? "C" : "-");
2453 
2454 		// Width/height name
2455 		Com_Printf (0, " %5i  %5i %s\n", image->upWidth, image->upHeight, image->name);
2456 
2457 		// Increment counters
2458 		totalImages++;
2459 		texels += image->upWidth * image->upHeight;
2460 		if (!(image->flags & (IF_NOMIPMAP_LINEAR|IF_NOMIPMAP_NEAREST))) {
2461 			tempWidth=image->upWidth, tempHeight=image->upHeight;
2462 			while (tempWidth > 1 || tempHeight > 1) {
2463 				tempWidth >>= 1;
2464 				if (tempWidth < 1)
2465 					tempWidth = 1;
2466 
2467 				tempHeight >>= 1;
2468 				if (tempHeight < 1)
2469 					tempHeight = 1;
2470 
2471 				mipTexels += tempWidth * tempHeight;
2472 				totalMips++;
2473 			}
2474 		}
2475 	}
2476 
2477 	Com_Printf (0, "------------------------------------------------------\n");
2478 	Com_Printf (0, "Total images: %d (with mips: %d)\n", totalImages, totalImages+totalMips);
2479 	Com_Printf (0, "Texel count: %d (w/o mips: %d)\n", texels+mipTexels, texels);
2480 	Com_Printf (0, "------------------------------------------------------\n");
2481 }
2482 
2483 
2484 /*
2485 ==================
2486 R_ScreenShot_f
2487 ==================
2488 */
2489 enum {
2490 	SSHOTTYPE_JPG,
2491 	SSHOTTYPE_PNG,
2492 	SSHOTTYPE_TGA,
2493 };
R_ScreenShot_f(void)2494 static void R_ScreenShot_f (void)
2495 {
2496 	char	checkName[MAX_OSPATH];
2497 	int		type, shotNum, quality;
2498 	char	*ext;
2499 	byte	*buffer;
2500 	FILE	*f;
2501 
2502 	// Find out what format to save in
2503 	if (Cmd_Argc () > 1)
2504 		ext = Cmd_Argv (1);
2505 	else
2506 		ext = gl_screenshot->string;
2507 
2508 	if (!Q_stricmp (ext, "png"))
2509 		type = SSHOTTYPE_PNG;
2510 	else if (!Q_stricmp (ext, "jpg"))
2511 		type = SSHOTTYPE_JPG;
2512 	else
2513 		type = SSHOTTYPE_TGA;
2514 
2515 	// Set necessary values
2516 	switch (type) {
2517 	case SSHOTTYPE_TGA:
2518 		Com_Printf (0, "Taking TGA screenshot...\n");
2519 		quality = 100;
2520 		ext = "tga";
2521 		break;
2522 
2523 	case SSHOTTYPE_PNG:
2524 		Com_Printf (0, "Taking PNG screenshot...\n");
2525 		quality = 100;
2526 		ext = "png";
2527 		break;
2528 
2529 	case SSHOTTYPE_JPG:
2530 		if (Cmd_Argc () == 3)
2531 			quality = atoi (Cmd_Argv (2));
2532 		else
2533 			quality = gl_jpgquality->intVal;
2534 		if (quality > 100 || quality <= 0)
2535 			quality = 100;
2536 
2537 		Com_Printf (0, "Taking JPG screenshot (at %i%% quality)...\n", quality);
2538 		ext = "jpg";
2539 		break;
2540 	}
2541 
2542 	// Create the scrnshots directory if it doesn't exist
2543 	Q_snprintfz (checkName, sizeof (checkName), "%s/scrnshot", FS_Gamedir ());
2544 	Sys_Mkdir (checkName);
2545 
2546 	// Find a file name to save it to
2547 	for (shotNum=0 ; shotNum<1000 ; shotNum++) {
2548 		Q_snprintfz (checkName, sizeof (checkName), "%s/scrnshot/egl%.3d.%s", FS_Gamedir (), shotNum, ext);
2549 		f = fopen (checkName, "rb");
2550 		if (!f)
2551 			break;
2552 		fclose (f);
2553 	}
2554 
2555 	// Open it
2556 	f = fopen (checkName, "wb");
2557 	if (shotNum == 1000 || !f) {
2558 		Com_Printf (PRNT_WARNING, "R_ScreenShot_f: Couldn't create a file\n");
2559 		fclose (f);
2560 		return;
2561 	}
2562 
2563 	// Allocate room for a copy of the framebuffer
2564 	buffer = Mem_PoolAllocExt (ri.config.vidWidth * ri.config.vidHeight * 3, qFalse, ri.imageSysPool, IMGTAG_DEFAULT);
2565 
2566 	// Read the framebuffer into our storage
2567 	if (ri.config.extBGRA && type == SSHOTTYPE_TGA) {
2568 		qglReadPixels (0, 0, ri.config.vidWidth, ri.config.vidHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, buffer);
2569 
2570 		// Apply hardware gamma
2571 		if (ri.config.hwGammaInUse) {
2572 			int		i, size;
2573 
2574 			size = ri.config.vidWidth * ri.config.vidHeight * 3;
2575 			for (i=0 ; i<size ; i+=3) {
2576 				buffer[i+2] = ri.gammaRamp[buffer[i+2]] >> 8;
2577 				buffer[i+1] = ri.gammaRamp[buffer[i+1] + 256] >> 8;
2578 				buffer[i+0] = ri.gammaRamp[buffer[i+0] + 512] >> 8;
2579 			}
2580 		}
2581 	}
2582 	else {
2583 		qglReadPixels (0, 0, ri.config.vidWidth, ri.config.vidHeight, GL_RGB, GL_UNSIGNED_BYTE, buffer);
2584 
2585 		// Apply hardware gamma
2586 		if (ri.config.hwGammaInUse) {
2587 			int		i, size;
2588 
2589 			size = ri.config.vidWidth * ri.config.vidHeight * 3;
2590 
2591 			for (i=0 ; i<size ; i+=3) {
2592 				buffer[i+0] = ri.gammaRamp[buffer[i+0]] >> 8;
2593 				buffer[i+1] = ri.gammaRamp[buffer[i+1] + 256] >> 8;
2594 				buffer[i+2] = ri.gammaRamp[buffer[i+2] + 512] >> 8;
2595 			}
2596 		}
2597 	}
2598 
2599 	// Write
2600 	switch (type) {
2601 	case SSHOTTYPE_TGA:
2602 		R_WriteTGA (f, buffer, ri.config.vidWidth, ri.config.vidHeight, !ri.config.extBGRA);
2603 		break;
2604 
2605 	case SSHOTTYPE_PNG:
2606 		R_WritePNG (f, buffer, ri.config.vidWidth, ri.config.vidHeight);
2607 		break;
2608 
2609 	case SSHOTTYPE_JPG:
2610 		R_WriteJPG (f, buffer, ri.config.vidWidth, ri.config.vidHeight, quality);
2611 		break;
2612 	}
2613 
2614 	// Finish
2615 	fclose (f);
2616 	Mem_Free (buffer);
2617 
2618 	Com_Printf (0, "Wrote egl%.3d.%s\n", shotNum, ext);
2619 }
2620 
2621 /*
2622 ==============================================================================
2623 
2624 	INIT / SHUTDOWN
2625 
2626 ==============================================================================
2627 */
2628 
2629 static void	*cmd_imageList;
2630 static void	*cmd_screenShot;
2631 
2632 /*
2633 ==================
2634 R_UpdateGammaRamp
2635 ==================
2636 */
R_UpdateGammaRamp(void)2637 void R_UpdateGammaRamp (void)
2638 {
2639 	int		i;
2640 	byte	gam;
2641 
2642 	vid_gamma->modified = qFalse;
2643 	if (!ri.config.hwGammaInUse)
2644 		return;
2645 
2646 	for (i=0 ; i<256 ; i++) {
2647 		gam = (byte)(clamp (255 * pow (( (i & 255) + 0.5f)*0.0039138943248532289628180039138943, vid_gamma->floatVal) + 0.5f, 0, 255));
2648 		ri.gammaRamp[i] = ri.gammaRamp[i + 256] = ri.gammaRamp[i + 512] = gam * 255;
2649 	}
2650 
2651 	GLimp_SetGammaRamp (ri.gammaRamp);
2652 }
2653 
2654 
2655 /*
2656 ==================
2657 R_InitSpecialTextures
2658 ==================
2659 */
2660 #define INTTEXSIZE	32
2661 #define INTTEXBYTES	4
R_InitSpecialTextures(void)2662 static void R_InitSpecialTextures (void)
2663 {
2664 	int		size;
2665 	int		x, y, z, d;
2666 	float	intensity;
2667 	double	tw, th, tx, ty, t;
2668 	byte	*data;
2669 	vec3_t	v;
2670 
2671 	/*
2672 	** ri.noTexture
2673 	*/
2674 	data = Mem_PoolAllocExt (INTTEXSIZE * INTTEXSIZE * INTTEXBYTES, qFalse, ri.imageSysPool, IMGTAG_BATCH);
2675 	for (x=0 ; x<INTTEXSIZE ; x++) {
2676 		for (y=0 ; y<INTTEXSIZE ; y++) {
2677 			data[(y*INTTEXSIZE + x)*4+3] = 255;
2678 
2679 			if ((x == 0 || x == INTTEXSIZE-1) || (y == 0 || y == INTTEXSIZE-1)) {
2680 				data[(y*INTTEXSIZE + x)*INTTEXBYTES+0] = 127;
2681 				data[(y*INTTEXSIZE + x)*INTTEXBYTES+1] = 127;
2682 				data[(y*INTTEXSIZE + x)*INTTEXBYTES+2] = 127;
2683 				continue;
2684 			}
2685 
2686 			data[(y*INTTEXSIZE + x)*INTTEXBYTES+0] = 31;
2687 			data[(y*INTTEXSIZE + x)*INTTEXBYTES+1] = 31;
2688 			data[(y*INTTEXSIZE + x)*INTTEXBYTES+2] = 31;
2689 		}
2690 	}
2691 
2692 	memset (&ri.noTexture, 0, sizeof (ri.noTexture));
2693 	ri.noTexture = R_Load2DImage ("***r_noTexture***", &data, INTTEXSIZE, INTTEXSIZE,
2694 		IF_NOFLUSH|IF_NOPICMIP|IF_NOGAMMA|IF_NOINTENS|IF_NOCOMPRESS, 3);
2695 
2696 	/*
2697 	** ri.whiteTexture
2698 	*/
2699 	memset (data, 255, INTTEXSIZE * INTTEXSIZE * INTTEXBYTES);
2700 	memset (&ri.whiteTexture, 0, sizeof (ri.whiteTexture));
2701 	ri.whiteTexture = R_Load2DImage ("***r_whiteTexture***", &data, INTTEXSIZE, INTTEXSIZE,
2702 		IF_NOFLUSH|IF_NOPICMIP|IF_NOGAMMA|IF_NOINTENS|IF_NOCOMPRESS, 3);
2703 
2704 	/*
2705 	** ri.blackTexture
2706 	*/
2707 	memset (data, 0, INTTEXSIZE * INTTEXSIZE * INTTEXBYTES);
2708 	memset (&ri.blackTexture, 0, sizeof (ri.blackTexture));
2709 	ri.blackTexture = R_Load2DImage ("***r_blackTexture***", &data, INTTEXSIZE, INTTEXSIZE,
2710 		IF_NOFLUSH|IF_NOPICMIP|IF_NOGAMMA|IF_NOINTENS|IF_NOCOMPRESS, 3);
2711 
2712 	/*
2713 	** ri.cinTexture
2714 	** Reserve a texNum for cinematics
2715 	*/
2716 	data = Mem_PoolAllocExt (256 * 256 * 4, qFalse, ri.imageSysPool, IMGTAG_BATCH);
2717 	memset (data, 0, 256 * 256 * 4);
2718 	memset (&ri.cinTexture, 0, sizeof (ri.cinTexture));
2719 	ri.cinTexture = R_Load2DImage ("***r_cinTexture***", &data, 256, 256,
2720 		IF_NOFLUSH|IF_NOPICMIP|IF_NOMIPMAP_LINEAR|IF_CLAMP|IF_NOINTENS|IF_NOGAMMA|IF_NOCOMPRESS, 3);
2721 
2722 	/*
2723 	** ri.dLightTexture
2724 	*/
2725 	if (ri.config.extTex3D) {
2726 		size = 32;
2727 		data = Mem_PoolAllocExt (size * size * size * 4, qFalse, ri.imageSysPool, IMGTAG_BATCH);
2728 	}
2729 	else {
2730 		size = 64;
2731 		data = Mem_PoolAllocExt (size * size * 4, qFalse, ri.imageSysPool, IMGTAG_BATCH);
2732 	}
2733 
2734 	for (x=0 ; x<size ; x++) {
2735 		for (y=0 ; y<size ; y++) {
2736 			for (z=0 ; z<size ; z++) {
2737 				v[0] = ((x + 0.5f) * (2.0f / (float)size) - 1.0f) * (1.0f / 0.9375);
2738 				v[1] = ((y + 0.5f) * (2.0f / (float)size) - 1.0f) * (1.0f / 0.9375);
2739 				if (ri.config.extTex3D)
2740 					v[2] = ((z + 0.5f) * (2.0f / (float)size) - 1.0f) * (1.0f / 0.9375);
2741 				else
2742 					v[2] = 0;
2743 
2744 				intensity = 1.0f - Vec3Length (v);
2745 				if (intensity > 0)
2746 					intensity *= 256.0f;
2747 				d = clamp (intensity, 0, 255);
2748 
2749 				data[((z*size+y)*size + x) * 4 + 0] = d;
2750 				data[((z*size+y)*size + x) * 4 + 1] = d;
2751 				data[((z*size+y)*size + x) * 4 + 2] = d;
2752 				data[((z*size+y)*size + x) * 4 + 3] = 255;
2753 
2754 				if (!ri.config.extTex3D)
2755 					break;
2756 			}
2757 		}
2758 	}
2759 
2760 	memset (&ri.dLightTexture, 0, sizeof (ri.dLightTexture));
2761 	if (ri.config.extTex3D)
2762 		ri.dLightTexture = R_Load3DImage ("***r_dLightTexture***", &data, size, size, size,
2763 			IF_NOFLUSH|IF_NOPICMIP|IF_NOMIPMAP_LINEAR|IF_NOINTENS|IF_NOGAMMA|IF_CLAMP|IT_3D, 4);
2764 	else
2765 		ri.dLightTexture = R_Load2DImage ("***r_dLightTexture***", &data, size, size,
2766 			IF_NOFLUSH|IF_NOPICMIP|IF_NOMIPMAP_LINEAR|IF_NOINTENS|IF_NOGAMMA|IF_CLAMP, 4);
2767 
2768 	/*
2769 	** ri.fogTexture
2770 	*/
2771 	tw = 1.0f / ((float)FOGTEX_WIDTH - 1.0f);
2772 	th = 1.0f / ((float)FOGTEX_HEIGHT - 1.0f);
2773 
2774 	data = Mem_PoolAllocExt (FOGTEX_WIDTH * FOGTEX_HEIGHT * 4, qFalse, ri.imageSysPool, IMGTAG_BATCH);
2775 	memset (data, 255, FOGTEX_WIDTH*FOGTEX_HEIGHT*4);
2776 
2777 	for (y=0, ty=0.0f ; y<FOGTEX_HEIGHT ; y++, ty+=th) {
2778 		for (x=0, tx=0.0f ; x<FOGTEX_WIDTH ; x++, tx+=tw) {
2779 			t = sqrt (tx) * 255.0;
2780 			data[(x+y*FOGTEX_WIDTH)*4+3] = (byte)(min (t, 255.0));
2781 		}
2782 
2783 		data[y*4+3] = 0;
2784 	}
2785 	memset (&ri.fogTexture, 0, sizeof (ri.fogTexture));
2786 	ri.fogTexture = R_Load2DImage ("***r_fogTexture***", &data, FOGTEX_WIDTH, FOGTEX_HEIGHT,
2787 		IF_NOFLUSH|IF_NOPICMIP|IF_NOMIPMAP_LINEAR|IF_NOINTENS|IF_NOGAMMA|IF_CLAMP, 4);
2788 
2789 	Mem_FreeTag (ri.imageSysPool, IMGTAG_BATCH);
2790 }
2791 
2792 
2793 /*
2794 ===============
2795 R_ImageInit
2796 ===============
2797 */
R_ImageInit(void)2798 void R_ImageInit (void)
2799 {
2800 	int		i, j;
2801 	float	gam;
2802 	int		red, green, blue;
2803 	uint32	v;
2804 	byte	*pal;
2805 	uint32	initTime;
2806 
2807 	initTime = Sys_UMilliseconds ();
2808 	Com_Printf (0, "\n--------- Image Initialization ---------\n");
2809 
2810 	// Registration
2811 	cmd_imageList	= Cmd_AddCommand ("imagelist",	R_ImageList_f,			"Prints out a list of the currently loaded textures");
2812 	cmd_screenShot	= Cmd_AddCommand ("screenshot",	R_ScreenShot_f,			"Takes a screenshot");
2813 
2814 	// Defaults
2815 	r_numImages = 0;
2816 
2817 	// Set the initial state
2818 	GL_TextureMode (qTrue, qFalse);
2819 	GL_TextureBits (qTrue, qFalse);
2820 
2821 	// Get the palette
2822 	Com_Printf (0, "Loading pallete table\n");
2823 	R_LoadPCX ("pics/colormap.pcx", NULL, &pal, NULL, NULL);
2824 	if (!pal) {
2825 		Com_Printf (0, "...not found, using internal default\n");
2826 		pal = r_defaultImagePal;
2827 	}
2828 
2829 	for (i=0 ; i<256 ; i++) {
2830 		red = pal[i*3+0];
2831 		green = pal[i*3+1];
2832 		blue = pal[i*3+2];
2833 
2834 		v = (255<<24) + (red<<0) + (green<<8) + (blue<<16);
2835 		r_paletteTable[i] = LittleLong (v);
2836 	}
2837 
2838 	r_paletteTable[255] &= LittleLong (0xffffff);	// 255 is transparent
2839 
2840 	if (pal != r_defaultImagePal)
2841 		Mem_Free (pal);
2842 
2843 	// Set up the gamma and intensity ramps
2844 	Com_Printf (0, "Creating software gamma and intensity ramps\n");
2845 	if (intensity->floatVal < 1)
2846 		Cvar_VariableSetValue (intensity, 1, qTrue);
2847 	ri.inverseIntensity = 1.0f / intensity->floatVal;
2848 
2849 	// Hack! because voodoo's are nasty bright
2850 	if (ri.renderClass == REND_CLASS_VOODOO)
2851 		gam = 1.0f;
2852 	else
2853 		gam = vid_gamma->floatVal;
2854 
2855 	// Gamma
2856 	if (gam == 1) {
2857 		for (i=0 ; i<256 ; i++)
2858 			r_gammaTable[i] = i;
2859 	}
2860 	else {
2861 		for (i=0 ; i<256 ; i++) {
2862 			j = (byte)(255 * pow ((i + 0.5f)*0.0039138943248532289628180039138943f, gam) + 0.5f);
2863 			if (j < 0)
2864 				j = 0;
2865 			else if (j > 255)
2866 				j = 255;
2867 
2868 			r_gammaTable[i] = j;
2869 		}
2870 	}
2871 
2872 	// Intensity (eww)
2873 	for (i=0 ; i<256 ; i++) {
2874 		j = i * intensity->intVal;
2875 		if (j > 255)
2876 			j = 255;
2877 		r_intensityTable[i] = j;
2878 	}
2879 
2880 	// Get gamma ramp
2881 	Com_Printf (0, "Downloading desktop gamma ramp\n");
2882 	ri.rampDownloaded = GLimp_GetGammaRamp (ri.originalRamp);
2883 	if (ri.rampDownloaded) {
2884 		Com_Printf (0, "...GLimp_GetGammaRamp succeeded\n");
2885 		ri.config.hwGammaAvail = qTrue;
2886 	}
2887 	else {
2888 		Com_Printf (PRNT_ERROR, "...GLimp_GetGammaRamp failed!\n");
2889 		ri.config.hwGammaAvail = qFalse;
2890 	}
2891 
2892 	// Use hardware gamma?
2893 	ri.config.hwGammaInUse = (ri.rampDownloaded && r_hwGamma->intVal);
2894 	if (ri.config.hwGammaInUse) {
2895 		Com_Printf (0, "...using hardware gamma\n");
2896 		R_UpdateGammaRamp ();
2897 	}
2898 	else
2899 		Com_Printf (0, "...using software gamma\n");
2900 
2901 	// Load up special textures
2902 	Com_Printf (0, "Generating internal textures\n");
2903 	R_InitSpecialTextures ();
2904 
2905 	Com_Printf (0, "----------------------------------------\n");
2906 
2907 	// Check memory integrity
2908 	Mem_CheckPoolIntegrity (ri.imageSysPool);
2909 
2910 	Com_Printf (0, "init time: %ums\n", Sys_UMilliseconds()-initTime);
2911 	Com_Printf (0, "----------------------------------------\n");
2912 }
2913 
2914 
2915 /*
2916 ===============
2917 R_ImageShutdown
2918 ===============
2919 */
R_ImageShutdown(void)2920 void R_ImageShutdown (void)
2921 {
2922 	image_t	*image;
2923 	uint32	size, i;
2924 
2925 	Com_Printf (0, "Image system shutdown:\n");
2926 
2927 	// Replace gamma ramp
2928 	if (ri.config.hwGammaInUse)
2929 		GLimp_SetGammaRamp (ri.originalRamp);
2930 
2931 	// Unregister commands
2932 	Cmd_RemoveCommand ("imagelist", cmd_imageList);
2933 	Cmd_RemoveCommand ("screenshot", cmd_screenShot);
2934 
2935 	// Free loaded textures
2936 	for (i=0, image=r_imageList ; i<r_numImages ; i++, image++) {
2937 		if (!image->touchFrame || !image->texNum)
2938 			continue;	// Free r_imageList slot
2939 
2940 		// Free it
2941 		qglDeleteTextures (1, &image->texNum);
2942 	}
2943 
2944 	// Clear everything
2945 	r_numImages = 0;
2946 	memset (r_imageList, 0, sizeof (image_t) * MAX_IMAGES);
2947 	memset (r_imageHashTree, 0, sizeof (image_t *) * MAX_IMAGE_HASH);
2948 	memset (r_lmTextures, 0, sizeof (image_t *) * R_MAX_LIGHTMAPS);
2949 
2950 	// Free memory
2951 	size = Mem_FreePool (ri.imageSysPool);
2952 	Com_Printf (0, "...releasing %u bytes...\n", size);
2953 }
2954