Quake II RTX doxygen  1.0 dev
images.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 Copyright (C) 2003-2006 Andrey Nazarov
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 
20 #include "gl.h"
21 #include "common/prompt.h"
22 
23 static int gl_filter_min;
24 static int gl_filter_max;
25 static float gl_filter_anisotropy;
28 
29 static int upload_width;
30 static int upload_height;
31 static qboolean upload_alpha;
32 
33 static cvar_t *gl_noscrap;
34 static cvar_t *gl_round_down;
35 static cvar_t *gl_picmip;
36 static cvar_t *gl_downsample_skins;
37 static cvar_t *gl_gamma_scale_pics;
38 static cvar_t *gl_bilerp_chars;
39 static cvar_t *gl_bilerp_pics;
40 static cvar_t *gl_upscale_pcx;
41 static cvar_t *gl_texturemode;
42 static cvar_t *gl_texturebits;
44 static cvar_t *gl_anisotropy;
45 static cvar_t *gl_saturation;
46 static cvar_t *gl_intensity;
47 static cvar_t *gl_gamma;
48 static cvar_t *gl_invert;
49 
50 static int GL_UpscaleLevel(int width, int height, imagetype_t type, imageflags_t flags);
51 static void GL_Upload32(byte *data, int width, int height, int baselevel, imagetype_t type, imageflags_t flags);
52 static void GL_Upscale32(byte *data, int width, int height, int maxlevel, imagetype_t type, imageflags_t flags);
53 static void GL_SetFilterAndRepeat(imagetype_t type, imageflags_t flags);
54 
55 typedef struct {
56  const char *name;
57  int minimize, maximize;
58 } glmode_t;
59 
60 static const glmode_t filterModes[] = {
61  { "GL_NEAREST", GL_NEAREST, GL_NEAREST },
62  { "GL_LINEAR", GL_LINEAR, GL_LINEAR },
63  { "GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST },
64  { "GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR },
65  { "GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST },
66  { "GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR }
67 };
68 
69 static const int numFilterModes = q_countof(filterModes);
70 
71 static void gl_texturemode_changed(cvar_t *self)
72 {
73  int i;
74  image_t *image;
75 
76  for (i = 0; i < numFilterModes; i++) {
77  if (!Q_stricmp(filterModes[i].name, self->string))
78  break;
79  }
80 
81  if (i == numFilterModes) {
82  Com_WPrintf("Bad texture mode: %s\n", self->string);
83  Cvar_Reset(self);
84  gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
85  gl_filter_max = GL_LINEAR;
86  } else {
89  }
90 
91  // change all the existing mipmap texture objects
92  for (i = 0, image = r_images; i < r_numImages; i++, image++) {
93  if (image->type == IT_WALL || image->type == IT_SKIN) {
94  GL_ForceTexture(0, image->texnum);
95  GL_SetFilterAndRepeat(image->type, image->flags);
96  }
97  }
98 }
99 
100 static void gl_texturemode_g(genctx_t *ctx)
101 {
102  int i;
103 
104  for (i = 0; i < numFilterModes; i++) {
105  if (!Prompt_AddMatch(ctx, filterModes[i].name)) {
106  break;
107  }
108  }
109 }
110 
111 static void gl_anisotropy_changed(cvar_t *self)
112 {
113  int i;
114  image_t *image;
115 
117  return;
118 
119  gl_filter_anisotropy = self->value;
121 
122  // change all the existing mipmap texture objects
123  for (i = 0, image = r_images; i < r_numImages; i++, image++) {
124  if (image->type == IT_WALL || image->type == IT_SKIN) {
125  GL_ForceTexture(0, image->texnum);
126  GL_SetFilterAndRepeat(image->type, image->flags);
127  }
128  }
129 }
130 
131 static void gl_bilerp_chars_changed(cvar_t *self)
132 {
133  int i;
134  image_t *image;
135 
136  // change all the existing charset texture objects
137  for (i = 0, image = r_images; i < r_numImages; i++, image++) {
138  if (image->type == IT_FONT) {
139  GL_ForceTexture(0, image->texnum);
140  GL_SetFilterAndRepeat(image->type, image->flags);
141  }
142  }
143 }
144 
145 static void gl_bilerp_pics_changed(cvar_t *self)
146 {
147  int i;
148  image_t *image;
149 
150  // change all the existing pic texture objects
151  for (i = 0, image = r_images; i < r_numImages; i++, image++) {
152  if (image->type == IT_PIC) {
153  GL_ForceTexture(0, image->texnum);
154  GL_SetFilterAndRepeat(image->type, image->flags);
155  }
156  }
157 }
158 
159 static void gl_texturebits_changed(cvar_t *self)
160 {
161  // ES doesn't support internal format != external
162  if (AT_LEAST_OPENGL_ES(1, 0)) {
163  gl_tex_alpha_format = GL_RGBA;
164  gl_tex_solid_format = GL_RGBA;
165 #ifdef GL_VERSION_1_1
166  } else if (self->integer > 16) {
167  gl_tex_alpha_format = GL_RGBA8;
168  gl_tex_solid_format = GL_RGB8;
169  } else if (self->integer > 8) {
170  gl_tex_alpha_format = GL_RGBA4;
171  gl_tex_solid_format = GL_RGB5;
172  } else if (self->integer > 0) {
173  gl_tex_alpha_format = GL_RGBA2;
174  gl_tex_solid_format = GL_R3_G3_B2;
175 #endif
176  } else {
177  gl_tex_alpha_format = GL_RGBA;
178  gl_tex_solid_format = GL_RGB;
179  }
180 }
181 
182 /*
183 =============================================================================
184 
185  SCRAP ALLOCATION
186 
187  Allocate all the little status bar objects into a single texture
188  to crutch up inefficient hardware / drivers
189 
190 =============================================================================
191 */
192 
193 #define SCRAP_BLOCK_WIDTH 256
194 #define SCRAP_BLOCK_HEIGHT 256
195 
198 static qboolean scrap_dirty;
199 
200 #define Scrap_AllocBlock(w, h, s, t) \
201  GL_AllocBlock(SCRAP_BLOCK_WIDTH, SCRAP_BLOCK_HEIGHT, scrap_inuse, w, h, s, t)
202 
203 static void Scrap_Init(void)
204 {
205  // make scrap texture initially transparent
206  memset(scrap_data, 0, sizeof(scrap_data));
207 }
208 
209 static void Scrap_Shutdown(void)
210 {
211  int i;
212 
213  for (i = 0; i < SCRAP_BLOCK_WIDTH; i++) {
214  scrap_inuse[i] = 0;
215  }
216 
217  scrap_dirty = qfalse;
218 }
219 
220 void Scrap_Upload(void)
221 {
222  int maxlevel;
223 
224  if (!scrap_dirty) {
225  return;
226  }
227 
229 
230  maxlevel = GL_UpscaleLevel(SCRAP_BLOCK_WIDTH, SCRAP_BLOCK_HEIGHT, IT_PIC, IF_SCRAP);
231  if (maxlevel) {
232  GL_Upscale32(scrap_data, SCRAP_BLOCK_WIDTH, SCRAP_BLOCK_HEIGHT, maxlevel, IT_PIC, IF_SCRAP);
233  GL_SetFilterAndRepeat(IT_PIC, IF_SCRAP | IF_UPSCALED);
234  } else {
235  GL_Upload32(scrap_data, SCRAP_BLOCK_WIDTH, SCRAP_BLOCK_HEIGHT, maxlevel, IT_PIC, IF_SCRAP);
236  GL_SetFilterAndRepeat(IT_PIC, IF_SCRAP);
237  }
238 
239  scrap_dirty = qfalse;
240 }
241 
242 //=======================================================
243 
244 static byte gammatable[256];
245 static byte intensitytable[256];
246 static byte gammaintensitytable[256];
247 static float colorscale;
248 
249 /*
250 ================
251 GL_GrayScaleTexture
252 
253 Transform to grayscale by replacing color components with
254 overall pixel luminance computed from weighted color sum
255 ================
256 */
257 static int GL_GrayScaleTexture(byte *in, int inwidth, int inheight, imagetype_t type, imageflags_t flags)
258 {
259  int i, c;
260  byte *p;
261  float r, g, b, y;
262 
263  if (type != IT_WALL)
264  return gl_tex_solid_format; // only grayscale world textures
265  if (flags & IF_TURBULENT)
266  return gl_tex_solid_format; // don't grayscale turbulent surfaces
267  if (colorscale == 1)
268  return gl_tex_solid_format;
269 
270  p = in;
271  c = inwidth * inheight;
272 
273  for (i = 0; i < c; i++, p += 4) {
274  r = p[0];
275  g = p[1];
276  b = p[2];
277  y = LUMINANCE(r, g, b);
278  p[0] = y + (r - y) * colorscale;
279  p[1] = y + (g - y) * colorscale;
280  p[2] = y + (b - y) * colorscale;
281  }
282 
283  // ES doesn't support internal format != external
284  if (colorscale == 0 && !AT_LEAST_OPENGL_ES(1, 0))
285  return GL_LUMINANCE;
286 
287  return gl_tex_solid_format;
288 }
289 
290 /*
291 ================
292 GL_LightScaleTexture
293 
294 Scale up the pixel values in a texture to increase the
295 lighting range
296 ================
297 */
298 static void GL_LightScaleTexture(byte *in, int inwidth, int inheight, imagetype_t type, imageflags_t flags)
299 {
300  int i, c;
301  byte *p;
302 
303  if (r_config.flags & QVF_GAMMARAMP)
304  return;
305 
306  p = in;
307  c = inwidth * inheight;
308 
309  if (type == IT_WALL || type == IT_SKIN) {
310  for (i = 0; i < c; i++, p += 4) {
311  p[0] = gammaintensitytable[p[0]];
312  p[1] = gammaintensitytable[p[1]];
313  p[2] = gammaintensitytable[p[2]];
314  }
315  } else if (gl_gamma_scale_pics->integer) {
316  for (i = 0; i < c; i++, p += 4) {
317  p[0] = gammatable[p[0]];
318  p[1] = gammatable[p[1]];
319  p[2] = gammatable[p[2]];
320  }
321  }
322 }
323 
324 static void GL_ColorInvertTexture(byte *in, int inwidth, int inheight, imagetype_t type, imageflags_t flags)
325 {
326  int i, c;
327  byte *p;
328 
329  if (type != IT_WALL)
330  return; // only invert world textures
331  if (flags & IF_TURBULENT)
332  return; // don't invert turbulent surfaces
333  if (!gl_invert->integer)
334  return;
335 
336  p = in;
337  c = inwidth * inheight;
338 
339  for (i = 0; i < c; i++, p += 4) {
340  p[0] = 255 - p[0];
341  p[1] = 255 - p[1];
342  p[2] = 255 - p[2];
343  }
344 }
345 
346 static qboolean GL_TextureHasAlpha(byte *data, int width, int height)
347 {
348  int i, c;
349  byte *scan;
350 
351  c = width * height;
352  scan = data + 3;
353  for (i = 0; i < c; i++, scan += 4) {
354  if (*scan != 255) {
355  return qtrue;
356  }
357  }
358 
359  return qfalse;
360 }
361 
362 static qboolean GL_MakePowerOfTwo(int *width, int *height)
363 {
364  if (!(*width & (*width - 1)) && !(*height & (*height - 1)))
365  return qtrue; // already power of two
366 
367  if (AT_LEAST_OPENGL(3, 0) && gl_texture_non_power_of_two->integer)
368  return qfalse; // assume full NPOT texture support
369 
370  *width = npot32(*width);
371  *height = npot32(*height);
372  return qfalse;
373 }
374 
375 /*
376 ===============
377 GL_Upload32
378 ===============
379 */
380 static void GL_Upload32(byte *data, int width, int height, int baselevel, imagetype_t type, imageflags_t flags)
381 {
382  byte *scaled;
383  int scaled_width, scaled_height, comp;
384  qboolean power_of_two;
385 
386  scaled_width = width;
387  scaled_height = height;
388  power_of_two = GL_MakePowerOfTwo(&scaled_width, &scaled_height);
389 
390  if (type == IT_WALL || (type == IT_SKIN && gl_downsample_skins->integer)) {
391  // round world textures down, if requested
392  if (gl_round_down->integer) {
393  if (scaled_width > width)
394  scaled_width >>= 1;
395  if (scaled_height > height)
396  scaled_height >>= 1;
397  }
398 
399  // let people sample down the world textures for speed
400  scaled_width >>= gl_picmip->integer;
401  scaled_height >>= gl_picmip->integer;
402  }
403 
404  // don't ever bother with >256 textures
405  while (scaled_width > gl_config.maxTextureSize || scaled_height > gl_config.maxTextureSize) {
406  scaled_width >>= 1;
407  scaled_height >>= 1;
408  }
409 
410  if (scaled_width < 1)
411  scaled_width = 1;
412  if (scaled_height < 1)
413  scaled_height = 1;
414 
415  upload_width = scaled_width;
416  upload_height = scaled_height;
417 
418  // set colorscale and lightscale before mipmap
419  comp = GL_GrayScaleTexture(data, width, height, type, flags);
420  GL_LightScaleTexture(data, width, height, type, flags);
421  GL_ColorInvertTexture(data, width, height, type, flags);
422 
423  if (scaled_width == width && scaled_height == height) {
424  // optimized case, do nothing
425  scaled = data;
426  } else if (power_of_two) {
427  // optimized case, use faster mipmap operation
428  scaled = data;
429  while (width > scaled_width || height > scaled_height) {
430  IMG_MipMap(scaled, scaled, width, height);
431  width >>= 1;
432  height >>= 1;
433  }
434  } else {
435  scaled = FS_AllocTempMem(scaled_width * scaled_height * 4);
436  IMG_ResampleTexture(data, width, height, scaled,
437  scaled_width, scaled_height);
438  }
439 
440  if (flags & IF_TRANSPARENT) {
441  upload_alpha = qtrue;
442  } else if (flags & IF_OPAQUE) {
443  upload_alpha = qfalse;
444  } else {
445  // scan the texture for any non-255 alpha
446  upload_alpha = GL_TextureHasAlpha(scaled, scaled_width, scaled_height);
447  }
448 
449  if (upload_alpha) {
450  comp = gl_tex_alpha_format;
451  }
452 
453  qglTexImage2D(GL_TEXTURE_2D, baselevel, comp, scaled_width,
454  scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
455 
456  c.texUploads++;
457 
458  if (type == IT_WALL || type == IT_SKIN) {
459  if (qglGenerateMipmap) {
460  qglGenerateMipmap(GL_TEXTURE_2D);
461  } else {
462  int miplevel = 0;
463 
464  while (scaled_width > 1 || scaled_height > 1) {
465  IMG_MipMap(scaled, scaled, scaled_width, scaled_height);
466  scaled_width >>= 1;
467  scaled_height >>= 1;
468  if (scaled_width < 1)
469  scaled_width = 1;
470  if (scaled_height < 1)
471  scaled_height = 1;
472  miplevel++;
473  qglTexImage2D(GL_TEXTURE_2D, miplevel, comp, scaled_width,
474  scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
475  }
476  }
477  }
478 
479  if (scaled != data) {
480  FS_FreeTempMem(scaled);
481  }
482 }
483 
484 static int GL_UpscaleLevel(int width, int height, imagetype_t type, imageflags_t flags)
485 {
486  int maxlevel;
487 
488  // only upscale pics, fonts and sprites
489  if (type != IT_PIC && type != IT_FONT && type != IT_SPRITE)
490  return 0;
491 
492  // only upscale 8-bit and small 32-bit pics
493  if (!(flags & (IF_PALETTED | IF_SCRAP)))
494  return 0;
495 
497 
498  maxlevel = Cvar_ClampInteger(gl_upscale_pcx, 0, 2);
499  while (maxlevel) {
500  int maxsize = gl_config.maxTextureSize >> maxlevel;
501 
502  // don't bother upscaling larger than max texture size
503  if (width <= maxsize && height <= maxsize)
504  break;
505 
506  maxlevel--;
507  }
508 
509  return maxlevel;
510 }
511 
512 static void GL_Upscale32(byte *data, int width, int height, int maxlevel, imagetype_t type, imageflags_t flags)
513 {
514  byte *buffer;
515 
516  buffer = FS_AllocTempMem((width * height) << ((maxlevel + 1) * 2));
517 
518  if (maxlevel >= 2) {
519  HQ4x_Render((uint32_t *)buffer, (uint32_t *)data, width, height);
520  GL_Upload32(buffer, width * 4, height * 4, maxlevel - 2, type, flags);
521  }
522 
523  if (maxlevel >= 1) {
524  HQ2x_Render((uint32_t *)buffer, (uint32_t *)data, width, height);
525  GL_Upload32(buffer, width * 2, height * 2, maxlevel - 1, type, flags);
526  }
527 
528  FS_FreeTempMem(buffer);
529 
530  GL_Upload32(data, width, height, maxlevel, type, flags);
531 
532 #ifdef GL_TEXTURE_MAX_LEVEL
533  if (AT_LEAST_OPENGL(1, 2))
534  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, maxlevel);
535 #endif
536 
537 #ifdef GL_TEXTURE_LOD_BIAS
538  // adjust LOD for resampled textures
539  if (upload_width != width || upload_height != height) {
540  float du = upload_width / (float)width;
541  float dv = upload_height / (float)height;
542  float bias = -log(max(du, dv)) / M_LN2;
543 
544  if (AT_LEAST_OPENGL(1, 4))
545  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, bias);
546  }
547 #endif
548 }
549 
550 static void GL_SetFilterAndRepeat(imagetype_t type, imageflags_t flags)
551 {
552  if (type == IT_WALL || type == IT_SKIN) {
553  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
554  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
555  } else {
556  qboolean nearest;
557 
558  if (flags & IF_NEAREST) {
559  nearest = qtrue;
560  } else if (type == IT_FONT) {
561  nearest = (gl_bilerp_chars->integer == 0);
562  } else if (type == IT_PIC) {
563  if (flags & IF_SCRAP)
564  nearest = (gl_bilerp_pics->integer == 0 || gl_bilerp_pics->integer == 1);
565  else
566  nearest = (gl_bilerp_pics->integer == 0);
567  } else {
568  nearest = qfalse;
569  }
570 
571  if ((flags & IF_UPSCALED) && AT_LEAST_OPENGL(1, 2)) {
572  if (nearest) {
573  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
574  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
575  } else {
576  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
577  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
578  }
579  } else {
580  if (nearest) {
581  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
582  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
583  } else {
584  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
585  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
586  }
587  }
588  }
589 
591  if (type == IT_WALL || type == IT_SKIN)
592  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_filter_anisotropy);
593  else
594  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1);
595  }
596 
597  if (type == IT_WALL || type == IT_SKIN || (flags & IF_REPEAT)) {
598  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
599  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
600 #ifdef GL_CLAMP_TO_EDGE
601  } else if (AT_LEAST_OPENGL(1, 2) || AT_LEAST_OPENGL_ES(1, 0)) {
602  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
603  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
604 #endif
605 #ifdef GL_CLAMP
606  } else {
607  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
608  qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
609 #endif
610  }
611 }
612 
613 /*
614 ================
615 IMG_Load
616 ================
617 */
618 void IMG_Load_GL(image_t *image, byte *pic)
619 {
620  byte *src, *dst;
621  int i, s, t, maxlevel;
622  int width, height;
623 
624  width = image->upload_width;
625  height = image->upload_height;
626 
627  // load small pics onto the scrap
628  if (image->type == IT_PIC && width < 64 && height < 64 &&
629  gl_noscrap->integer == 0 && Scrap_AllocBlock(width, height, &s, &t)) {
630  src = pic;
631  dst = &scrap_data[(t * SCRAP_BLOCK_WIDTH + s) * 4];
632  for (i = 0; i < height; i++) {
633  memcpy(dst, src, width * 4);
634  src += width * 4;
635  dst += SCRAP_BLOCK_WIDTH * 4;
636  }
637 
638  image->texnum = TEXNUM_SCRAP;
639  image->flags |= IF_SCRAP | IF_TRANSPARENT;
640  image->sl = (s + 0.01f) / (float)SCRAP_BLOCK_WIDTH;
641  image->sh = (s + width - 0.01f) / (float)SCRAP_BLOCK_WIDTH;
642  image->tl = (t + 0.01f) / (float)SCRAP_BLOCK_HEIGHT;
643  image->th = (t + height - 0.01f) / (float)SCRAP_BLOCK_HEIGHT;
644 
645  maxlevel = GL_UpscaleLevel(SCRAP_BLOCK_WIDTH, SCRAP_BLOCK_HEIGHT, IT_PIC, IF_SCRAP);
646  if (maxlevel)
647  image->flags |= IF_UPSCALED;
648 
649  scrap_dirty = qtrue;
650  } else {
651  qglGenTextures(1, &image->texnum);
652  GL_ForceTexture(0, image->texnum);
653 
654  maxlevel = GL_UpscaleLevel(width, height, image->type, image->flags);
655  if (maxlevel) {
656  GL_Upscale32(pic, width, height, maxlevel, image->type, image->flags);
657  image->flags |= IF_UPSCALED;
658  } else {
659  GL_Upload32(pic, width, height, maxlevel, image->type, image->flags);
660  }
661 
662  GL_SetFilterAndRepeat(image->type, image->flags);
663 
664  if (upload_alpha) {
665  image->flags |= IF_TRANSPARENT;
666  }
667  image->upload_width = upload_width << maxlevel; // after power of 2 and scales
668  image->upload_height = upload_height << maxlevel;
669  image->sl = 0;
670  image->sh = 1;
671  image->tl = 0;
672  image->th = 1;
673  }
674 
675  // don't need pics in memory after GL upload
676  Z_Free(pic);
677 }
678 
679 void IMG_Unload_GL(image_t *image)
680 {
681  if (image->texnum && !(image->flags & IF_SCRAP)) {
682  if (gls.texnums[0] == image->texnum)
683  gls.texnums[0] = 0;
684  qglDeleteTextures(1, &image->texnum);
685  image->texnum = 0;
686  }
687 }
688 
689 static void GL_BuildIntensityTable(void)
690 {
691  int i, j;
692  float f;
693 
694  f = Cvar_ClampValue(gl_intensity, 1, 5);
695  for (i = 0; i < 256; i++) {
696  j = i * f;
697  if (j > 255) {
698  j = 255;
699  }
700  intensitytable[i] = j;
701  }
702 
703  j = 255.0f / f;
704  gl_static.inverse_intensity_33 = MakeColor(j, j, j, 85);
705  gl_static.inverse_intensity_66 = MakeColor(j, j, j, 170);
706  gl_static.inverse_intensity_100 = MakeColor(j, j, j, 255);
707 }
708 
709 static void GL_BuildGammaTables(void)
710 {
711  int i;
712  float inf, g = gl_gamma->value;
713 
714  if (g == 1.0f) {
715  for (i = 0; i < 256; i++) {
716  gammatable[i] = i;
718  }
719  } else {
720  for (i = 0; i < 256; i++) {
721  inf = 255 * pow(i / 255.0, g);
722  if (inf > 255) {
723  inf = 255;
724  }
725  gammatable[i] = inf;
727  }
728  }
729 }
730 
731 static void gl_gamma_changed(cvar_t *self)
732 {
735 }
736 
737 static const byte dottexture[8][8] = {
738  {0, 0, 0, 0, 0, 0, 0, 0},
739  {0, 0, 1, 1, 0, 0, 0, 0},
740  {0, 1, 1, 1, 1, 0, 0, 0},
741  {0, 1, 1, 1, 1, 0, 0, 0},
742  {0, 0, 1, 1, 0, 0, 0, 0},
743  {0, 0, 0, 0, 0, 0, 0, 0},
744  {0, 0, 0, 0, 0, 0, 0, 0},
745  {0, 0, 0, 0, 0, 0, 0, 0},
746 };
747 
748 static void GL_InitDefaultTexture(void)
749 {
750  int i, j;
751  byte pixels[8 * 8 * 4];
752  byte *dst;
753  image_t *ntx;
754 
755  dst = pixels;
756  for (i = 0; i < 8; i++) {
757  for (j = 0; j < 8; j++) {
758  dst[0] = dottexture[i & 3][j & 3] * 255;
759  dst[1] = 0;
760  dst[2] = 0;
761  dst[3] = 255;
762  dst += 4;
763  }
764  }
765 
767  GL_Upload32(pixels, 8, 8, 0, IT_WALL, IF_TURBULENT);
768  GL_SetFilterAndRepeat(IT_WALL, IF_TURBULENT);
769 
770  // fill in notexture image
771  ntx = R_NOTEXTURE;
772  ntx->width = ntx->upload_width = 8;
773  ntx->height = ntx->upload_height = 8;
774  ntx->type = IT_WALL;
775  ntx->flags = 0;
776  ntx->texnum = TEXNUM_DEFAULT;
777  ntx->sl = 0;
778  ntx->sh = 1;
779  ntx->tl = 0;
780  ntx->th = 1;
781 }
782 
783 static void GL_InitParticleTexture(void)
784 {
785  byte pixels[16 * 16 * 4];
786  byte *dst;
787  float x, y, f;
788  int i, j;
789 
790  dst = pixels;
791  for (i = 0; i < 16; i++) {
792  for (j = 0; j < 16; j++) {
793  x = j - 16 / 2 + 0.5f;
794  y = i - 16 / 2 + 0.5f;
795  f = sqrt(x * x + y * y);
796  f = 1.0f - f / (16 / 2 - 0.5f);
797  dst[0] = 255;
798  dst[1] = 255;
799  dst[2] = 255;
800  dst[3] = 255 * clamp(f, 0, 1);
801  dst += 4;
802  }
803  }
804 
806  GL_Upload32(pixels, 16, 16, 0, IT_SPRITE, IF_NONE);
807  GL_SetFilterAndRepeat(IT_SPRITE, IF_NONE);
808 }
809 
810 static void GL_InitWhiteImage(void)
811 {
812  uint32_t pixel;
813 
814  pixel = U32_WHITE;
816  GL_Upload32((byte *)&pixel, 1, 1, 0, IT_SPRITE, IF_REPEAT | IF_NEAREST);
817  GL_SetFilterAndRepeat(IT_SPRITE, IF_REPEAT | IF_NEAREST);
818 
819  pixel = U32_BLACK;
821  GL_Upload32((byte *)&pixel, 1, 1, 0, IT_SPRITE, IF_REPEAT | IF_NEAREST);
822  GL_SetFilterAndRepeat(IT_SPRITE, IF_REPEAT | IF_NEAREST);
823 }
824 
825 static void GL_InitBeamTexture(void)
826 {
827  byte pixels[16 * 16 * 4];
828  byte *dst;
829  float f;
830  int i, j;
831 
832  dst = pixels;
833  for (i = 0; i < 16; i++) {
834  for (j = 0; j < 16; j++) {
835  f = abs(j - 16 / 2) - 0.5f;
836  f = 1.0f - f / (16 / 2 - 2.5f);
837  dst[0] = 255;
838  dst[1] = 255;
839  dst[2] = 255;
840  dst[3] = 255 * clamp(f, 0, 1);
841  dst += 4;
842  }
843  }
844 
846  GL_Upload32(pixels, 16, 16, 0, IT_SPRITE, IF_NONE);
847  GL_SetFilterAndRepeat(IT_SPRITE, IF_NONE);
848 }
849 
850 /*
851 ===============
852 GL_InitImages
853 ===============
854 */
855 void GL_InitImages(void)
856 {
857  gl_bilerp_chars = Cvar_Get("gl_bilerp_chars", "0", 0);
859  gl_bilerp_pics = Cvar_Get("gl_bilerp_pics", "1", 0);
861  gl_texturemode = Cvar_Get("gl_texturemode",
862  "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE);
864  gl_texturemode->generator = gl_texturemode_g;
865  gl_texturebits = Cvar_Get("gl_texturebits", "0", CVAR_FILES);
866  gl_texture_non_power_of_two = Cvar_Get("gl_texture_non_power_of_two", "1", 0);
867  gl_anisotropy = Cvar_Get("gl_anisotropy", "8", 0);
869  gl_noscrap = Cvar_Get("gl_noscrap", "0", CVAR_FILES);
870  gl_round_down = Cvar_Get("gl_round_down", "0", CVAR_FILES);
871  gl_picmip = Cvar_Get("gl_picmip", "0", CVAR_FILES);
872  gl_downsample_skins = Cvar_Get("gl_downsample_skins", "1", CVAR_FILES);
873  gl_gamma_scale_pics = Cvar_Get("gl_gamma_scale_pics", "0", CVAR_FILES);
874  gl_upscale_pcx = Cvar_Get("gl_upscale_pcx", "0", CVAR_FILES);
875  gl_saturation = Cvar_Get("gl_saturation", "1", CVAR_FILES);
876  gl_intensity = Cvar_Get("intensity", "2", CVAR_FILES);
877  gl_invert = Cvar_Get("gl_invert", "0", CVAR_FILES);
878  gl_gamma = Cvar_Get("vid_gamma", "0.8", CVAR_ARCHIVE);
879 
880  if (r_config.flags & QVF_GAMMARAMP) {
881  gl_gamma->changed = gl_gamma_changed;
882  gl_gamma->flags &= ~CVAR_FILES;
883  } else {
884  gl_gamma->flags |= CVAR_FILES;
885  }
886 
887  if (AT_LEAST_OPENGL(3, 0)) {
888  gl_texture_non_power_of_two->flags |= CVAR_FILES;
889  } else {
890  gl_texture_non_power_of_two->flags &= ~CVAR_FILES;
891  }
892 
893  IMG_Init();
894 
895  IMG_GetPalette();
896 
897  if (gl_upscale_pcx->integer) {
898  HQ2x_Init();
899  }
900 
902 
903  if (r_config.flags & QVF_GAMMARAMP) {
905  } else {
907  }
908 
909  // FIXME: the name 'saturation' is misleading in this context
911 
917 
920 
921  Scrap_Init();
922 
927 
928  GL_ShowErrors(__func__);
929 }
930 
931 #ifdef _DEBUG
932 extern image_t *r_charset;
933 #endif
934 
935 /*
936 ===============
937 GL_ShutdownImages
938 ===============
939 */
941 {
942  gl_bilerp_chars->changed = NULL;
943  gl_bilerp_pics->changed = NULL;
944  gl_texturemode->changed = NULL;
945  gl_texturemode->generator = NULL;
946  gl_anisotropy->changed = NULL;
947  gl_gamma->changed = NULL;
948 
949  // delete auto textures
952 
953 #ifdef _DEBUG
954  r_charset = NULL;
955 #endif
956 
957  IMG_FreeAll();
958  IMG_Shutdown();
959 
960  Scrap_Shutdown();
961 }
962 
glmode_t::name
const char * name
Definition: images.c:56
TEXNUM_SCRAP
#define TEXNUM_SCRAP
Definition: gl.h:440
SCRAP_BLOCK_HEIGHT
#define SCRAP_BLOCK_HEIGHT
Definition: images.c:194
VID_UpdateGamma
void VID_UpdateGamma(const byte *table)
Definition: client.c:413
gammaintensitytable
static byte gammaintensitytable[256]
Definition: images.c:246
scrap_inuse
static int scrap_inuse[SCRAP_BLOCK_WIDTH]
Definition: images.c:196
qglTexParameterf
#define qglTexParameterf
Definition: fixed.h:108
gl_gamma_scale_pics
static cvar_t * gl_gamma_scale_pics
Definition: images.c:37
IMG_GetPalette
void IMG_GetPalette(void)
Definition: images.c:1376
IMG_FreeAll
void IMG_FreeAll(void)
Definition: images.c:1343
miplevel
static int miplevel
Definition: edge.c:61
lm
lightmap_builder_t lm
Definition: surf.c:25
Scrap_Init
static void Scrap_Init(void)
Definition: images.c:203
upload_height
static int upload_height
Definition: images.c:30
height
static int height
Definition: physical_sky.c:39
gl_texturemode
static cvar_t * gl_texturemode
Definition: images.c:41
filterModes
static const glmode_t filterModes[]
Definition: images.c:60
NUM_TEXNUMS
#define NUM_TEXNUMS
Definition: gl.h:57
Scrap_AllocBlock
#define Scrap_AllocBlock(w, h, s, t)
Definition: images.c:200
image_t
struct image_s image_t
Definition: material.h:27
scrap_data
static byte scrap_data[SCRAP_BLOCK_WIDTH *SCRAP_BLOCK_HEIGHT *4]
Definition: images.c:197
GL_InitParticleTexture
static void GL_InitParticleTexture(void)
Definition: images.c:783
glConfig_t::maxTextureSize
int maxTextureSize
Definition: gl.h:109
Cvar_Get
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags)
Definition: cvar.c:257
GL_TextureHasAlpha
static qboolean GL_TextureHasAlpha(byte *data, int width, int height)
Definition: images.c:346
qglGenerateMipmap
QGL_core_IMP QGL_ARB_fragment_program_IMP QGL_ARB_multitexture_IMP QGL_ARB_vertex_buffer_object_IMP QGL_EXT_compiled_vertex_array_IMP qglGenerateMipmap_t qglGenerateMipmap
Definition: dynamic.c:34
GL_UpscaleLevel
static int GL_UpscaleLevel(int width, int height, imagetype_t type, imageflags_t flags)
Definition: images.c:484
IMG_MipMap
void IMG_MipMap(byte *out, byte *in, int width, int height)
Definition: images.c:623
gl_noscrap
static cvar_t * gl_noscrap
Definition: images.c:33
GL_Upscale32
static void GL_Upscale32(byte *data, int width, int height, int maxlevel, imagetype_t type, imageflags_t flags)
Definition: images.c:512
GL_Upload32
static void GL_Upload32(byte *data, int width, int height, int baselevel, imagetype_t type, imageflags_t flags)
Definition: images.c:380
glState_t::texnums
GLuint texnums[MAX_TMUS]
Definition: gl.h:310
GL_MakePowerOfTwo
static qboolean GL_MakePowerOfTwo(int *width, int *height)
Definition: images.c:362
gammatable
static byte gammatable[256]
Definition: images.c:244
IMG_ResampleTexture
void IMG_ResampleTexture(const byte *in, int inwidth, int inheight, byte *out, int outwidth, int outheight)
Definition: images.c:577
TEXNUM_BEAM
#define TEXNUM_BEAM
Definition: gl.h:442
glmode_t::minimize
int minimize
Definition: images.c:57
gl_texturemode_g
static void gl_texturemode_g(genctx_t *ctx)
Definition: images.c:100
gl_saturation
static cvar_t * gl_saturation
Definition: images.c:45
gl_bilerp_chars_changed
static void gl_bilerp_chars_changed(cvar_t *self)
Definition: images.c:131
gl_round_down
static cvar_t * gl_round_down
Definition: images.c:34
gl_invert
static cvar_t * gl_invert
Definition: images.c:48
gl_texturebits_changed
static void gl_texturebits_changed(cvar_t *self)
Definition: images.c:159
glStatic_t::inverse_intensity_100
uint32_t inverse_intensity_100
Definition: gl.h:74
GL_InitBeamTexture
static void GL_InitBeamTexture(void)
Definition: images.c:825
upload_width
static int upload_width
Definition: images.c:29
IMG_Unload_GL
void IMG_Unload_GL(image_t *image)
Definition: images.c:679
qglGenTextures
#define qglGenTextures
Definition: fixed.h:66
gl_config
glConfig_t gl_config
Definition: main.c:29
Prompt_AddMatch
qboolean Prompt_AddMatch(genctx_t *ctx, const char *s)
Definition: prompt.c:149
gl_bilerp_pics_changed
static void gl_bilerp_pics_changed(cvar_t *self)
Definition: images.c:145
gl_anisotropy
static cvar_t * gl_anisotropy
Definition: images.c:44
IMG_Load_GL
void IMG_Load_GL(image_t *image, byte *pic)
Definition: images.c:618
gls
glState_t gls
Definition: state.c:22
width
static int width
Definition: physical_sky.c:38
GL_BuildGammaTables
static void GL_BuildGammaTables(void)
Definition: images.c:709
statCounters_t::texUploads
int texUploads
Definition: gl.h:141
HQ4x_Render
void HQ4x_Render(uint32_t *output, const uint32_t *input, int width, int height)
Definition: hq2x.c:405
Scrap_Shutdown
static void Scrap_Shutdown(void)
Definition: images.c:209
TEXNUM_BLACK
#define TEXNUM_BLACK
Definition: gl.h:444
GL_InitImages
void GL_InitImages(void)
Definition: images.c:855
gl_filter_min
static int gl_filter_min
Definition: images.c:23
AT_LEAST_OPENGL_ES
#define AT_LEAST_OPENGL_ES(major, minor)
Definition: gl.h:124
TEXNUM_DEFAULT
#define TEXNUM_DEFAULT
Definition: gl.h:439
gl_downsample_skins
static cvar_t * gl_downsample_skins
Definition: images.c:36
r_numImages
int r_numImages
Definition: images.c:652
qglTexImage2D
#define qglTexImage2D
Definition: fixed.h:107
AT_LEAST_OPENGL
#define AT_LEAST_OPENGL(major, minor)
Definition: gl.h:121
Cvar_ClampValue
float Cvar_ClampValue(cvar_t *var, float min, float max)
Definition: cvar.c:571
gl_anisotropy_changed
static void gl_anisotropy_changed(cvar_t *self)
Definition: images.c:111
Z_Free
void Z_Free(void *ptr)
Definition: zone.c:147
dottexture
static const byte dottexture[8][8]
Definition: images.c:737
TEXNUM_PARTICLE
#define TEXNUM_PARTICLE
Definition: gl.h:441
glmode_t::maximize
int maximize
Definition: images.c:57
IMG_Shutdown
void IMG_Shutdown(void)
Definition: images.c:1448
r_images
image_t r_images[MAX_RIMAGES]
Definition: images.c:651
GL_ColorInvertTexture
static void GL_ColorInvertTexture(byte *in, int inwidth, int inheight, imagetype_t type, imageflags_t flags)
Definition: images.c:324
gl_bilerp_pics
static cvar_t * gl_bilerp_pics
Definition: images.c:39
glStatic_t::texnums
GLuint texnums[NUM_TEXNUMS]
Definition: gl.h:69
upload_alpha
static qboolean upload_alpha
Definition: images.c:31
GL_ForceTexture
void GL_ForceTexture(GLuint tmu, GLuint texnum)
Definition: state.c:25
GL_LightScaleTexture
static void GL_LightScaleTexture(byte *in, int inwidth, int inheight, imagetype_t type, imageflags_t flags)
Definition: images.c:298
gl_static
glStatic_t gl_static
Definition: main.c:28
HQ2x_Render
void HQ2x_Render(uint32_t *output, const uint32_t *input, int width, int height)
Definition: hq2x.c:357
gl_upscale_pcx
static cvar_t * gl_upscale_pcx
Definition: images.c:40
GL_ShutdownImages
void GL_ShutdownImages(void)
Definition: images.c:940
c
statCounters_t c
Definition: main.c:30
gl_filter_max
static int gl_filter_max
Definition: images.c:24
gl_texturemode_changed
static void gl_texturemode_changed(cvar_t *self)
Definition: images.c:71
LM_MAX_LIGHTMAPS
#define LM_MAX_LIGHTMAPS
Definition: gl.h:254
gl_bilerp_chars
static cvar_t * gl_bilerp_chars
Definition: images.c:38
TEXNUM_WHITE
#define TEXNUM_WHITE
Definition: gl.h:443
gl_tex_solid_format
static int gl_tex_solid_format
Definition: images.c:27
GL_InitDefaultTexture
static void GL_InitDefaultTexture(void)
Definition: images.c:748
glConfig_t::ext_enabled
unsigned ext_enabled
Definition: gl.h:107
GL_BuildIntensityTable
static void GL_BuildIntensityTable(void)
Definition: images.c:689
Cvar_ClampInteger
int Cvar_ClampInteger(cvar_t *var, int min, int max)
Definition: cvar.c:549
gl_tex_alpha_format
static int gl_tex_alpha_format
Definition: images.c:26
GL_InitWhiteImage
static void GL_InitWhiteImage(void)
Definition: images.c:810
glmode_t
Definition: images.c:55
glStatic_t::inverse_intensity_33
uint32_t inverse_intensity_33
Definition: gl.h:72
gl_gamma
static cvar_t * gl_gamma
Definition: images.c:47
colorscale
static float colorscale
Definition: images.c:247
gl_texture_non_power_of_two
static cvar_t * gl_texture_non_power_of_two
Definition: images.c:43
Scrap_Upload
void Scrap_Upload(void)
Definition: images.c:220
lightmap_builder_t::texnums
GLuint texnums[LM_MAX_LIGHTMAPS]
Definition: gl.h:265
QGL_EXT_texture_filter_anisotropic
#define QGL_EXT_texture_filter_anisotropic
Definition: dynamic.h:159
intensitytable
static byte intensitytable[256]
Definition: images.c:245
gl.h
SCRAP_BLOCK_WIDTH
#define SCRAP_BLOCK_WIDTH
Definition: images.c:193
gl_gamma_changed
static void gl_gamma_changed(cvar_t *self)
Definition: images.c:731
gl_filter_anisotropy
static float gl_filter_anisotropy
Definition: images.c:25
gl_intensity
static cvar_t * gl_intensity
Definition: images.c:46
gl_texturebits
static cvar_t * gl_texturebits
Definition: images.c:42
glStatic_t::inverse_intensity_66
uint32_t inverse_intensity_66
Definition: gl.h:73
gl_picmip
static cvar_t * gl_picmip
Definition: images.c:35
IMG_Init
void IMG_Init(void)
Definition: images.c:1419
HQ2x_Init
void HQ2x_Init(void)
Definition: hq2x.c:459
GL_ShowErrors
qboolean GL_ShowErrors(const char *func)
Definition: main.c:539
numFilterModes
static const int numFilterModes
Definition: images.c:69
GL_SetFilterAndRepeat
static void GL_SetFilterAndRepeat(imagetype_t type, imageflags_t flags)
Definition: images.c:550
r_config
refcfg_t r_config
Definition: refresh.c:401
qglDeleteTextures
#define qglDeleteTextures
Definition: fixed.h:50
GL_GrayScaleTexture
static int GL_GrayScaleTexture(byte *in, int inwidth, int inheight, imagetype_t type, imageflags_t flags)
Definition: images.c:257
glConfig_t::maxAnisotropy
float maxAnisotropy
Definition: gl.h:111
scrap_dirty
static qboolean scrap_dirty
Definition: images.c:198