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