]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_textures.c
change sv_cullentities_trace_samples from 1 to 2 - 1 is completely
[divverent/darkplaces.git] / gl_textures.c
1
2 #include "quakedef.h"
3 #include "image.h"
4 #include "jpeg.h"
5 #include "image_png.h"
6
7 cvar_t gl_max_size = {CVAR_SAVE, "gl_max_size", "2048", "maximum allowed texture size, can be used to reduce video memory usage, limited by hardware capabilities (typically 2048, 4096, or 8192)"};
8 cvar_t gl_max_lightmapsize = {CVAR_SAVE, "gl_max_lightmapsize", "1024", "maximum allowed texture size for lightmap textures, use larger values to improve rendering speed, as long as there is enough video memory available (setting it too high for the hardware will cause very bad performance)"};
9 cvar_t gl_picmip = {CVAR_SAVE, "gl_picmip", "0", "reduces resolution of textures by powers of 2, for example 1 will halve width/height, reducing texture memory usage by 75%"};
10 cvar_t r_lerpimages = {CVAR_SAVE, "r_lerpimages", "1", "bilinear filters images when scaling them up to power of 2 size (mode 1), looks better than glquake (mode 0)"};
11 cvar_t r_precachetextures = {CVAR_SAVE, "r_precachetextures", "1", "0 = never upload textures until used, 1 = upload most textures before use (exceptions: rarely used skin colormap layers), 2 = upload all textures before use (can increase texture memory usage significantly)"};
12 cvar_t gl_texture_anisotropy = {CVAR_SAVE, "gl_texture_anisotropy", "1", "anisotropic filtering quality (if supported by hardware), 1 sample (no anisotropy) and 8 sample (8 tap anisotropy) are recommended values"};
13 cvar_t gl_texturecompression = {CVAR_SAVE, "gl_texturecompression", "0", "whether to compress textures, a value of 0 disables compression (even if the individual cvars are 1), 1 enables fast (low quality) compression at startup, 2 enables slow (high quality) compression at startup"};
14 cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
15 cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
16 cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
17 cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
18 cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
19 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
20 cvar_t gl_texturecompression_q3bspdeluxemaps = {CVAR_SAVE, "gl_texturecompression_q3bspdeluxemaps", "0", "whether to compress deluxemaps in q3bsp format levels (only levels compiled with q3map2 -deluxe have these)"};
21 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
22 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
23
24 int             gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
25 int             gl_filter_mag = GL_LINEAR;
26
27
28 static mempool_t *texturemempool;
29
30 // note: this must not conflict with TEXF_ flags in r_textures.h
31 // cleared when a texture is uploaded
32 #define GLTEXF_UPLOAD           0x00010000
33 // bitmask for mismatch checking
34 #define GLTEXF_IMPORTANTBITS (0)
35 // set when image is uploaded and freed
36 #define GLTEXF_DESTROYED        0x00040000
37 // dynamic texture (treat texnum == 0 differently)
38 #define GLTEXF_DYNAMIC          0x00080000
39
40 typedef struct textypeinfo_s
41 {
42         textype_t textype;
43         int inputbytesperpixel;
44         int internalbytesperpixel;
45         float glinternalbytesperpixel;
46         int glformat;
47         int glinternalformat;
48         int gltype;
49 }
50 textypeinfo_t;
51
52 static textypeinfo_t textype_palette                = {TEXTYPE_PALETTE, 1, 4, 4.0f, GL_BGRA   , 3, GL_UNSIGNED_BYTE};
53 static textypeinfo_t textype_palette_alpha          = {TEXTYPE_PALETTE, 1, 4, 4.0f, GL_BGRA   , 4, GL_UNSIGNED_BYTE};
54 static textypeinfo_t textype_palette_compress       = {TEXTYPE_PALETTE, 1, 4, 0.5f, GL_BGRA   , GL_COMPRESSED_RGB_ARB, GL_UNSIGNED_BYTE};
55 static textypeinfo_t textype_palette_alpha_compress = {TEXTYPE_PALETTE, 1, 4, 1.0f, GL_BGRA   , GL_COMPRESSED_RGBA_ARB, GL_UNSIGNED_BYTE};
56 static textypeinfo_t textype_rgba                   = {TEXTYPE_RGBA   , 4, 4, 4.0f, GL_RGBA   , 3, GL_UNSIGNED_BYTE};
57 static textypeinfo_t textype_rgba_alpha             = {TEXTYPE_RGBA   , 4, 4, 4.0f, GL_RGBA   , 4, GL_UNSIGNED_BYTE};
58 static textypeinfo_t textype_rgba_compress          = {TEXTYPE_RGBA   , 4, 4, 0.5f, GL_RGBA   , GL_COMPRESSED_RGB_ARB, GL_UNSIGNED_BYTE};
59 static textypeinfo_t textype_rgba_alpha_compress    = {TEXTYPE_RGBA   , 4, 4, 1.0f, GL_RGBA   , GL_COMPRESSED_RGBA_ARB, GL_UNSIGNED_BYTE};
60 static textypeinfo_t textype_bgra                   = {TEXTYPE_BGRA   , 4, 4, 4.0f, GL_BGRA   , 3, GL_UNSIGNED_BYTE};
61 static textypeinfo_t textype_bgra_alpha             = {TEXTYPE_BGRA   , 4, 4, 4.0f, GL_BGRA   , 4, GL_UNSIGNED_BYTE};
62 static textypeinfo_t textype_bgra_compress          = {TEXTYPE_BGRA   , 4, 4, 0.5f, GL_BGRA   , GL_COMPRESSED_RGB_ARB, GL_UNSIGNED_BYTE};
63 static textypeinfo_t textype_bgra_alpha_compress    = {TEXTYPE_BGRA   , 4, 4, 1.0f, GL_BGRA   , GL_COMPRESSED_RGBA_ARB, GL_UNSIGNED_BYTE};
64 static textypeinfo_t textype_shadowmap16            = {TEXTYPE_SHADOWMAP,2,2, 2.0f, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT16_ARB, GL_UNSIGNED_SHORT};
65 static textypeinfo_t textype_shadowmap24            = {TEXTYPE_SHADOWMAP,4,4, 4.0f, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT24_ARB, GL_UNSIGNED_INT};
66
67 typedef enum gltexturetype_e
68 {
69         GLTEXTURETYPE_2D,
70         GLTEXTURETYPE_3D,
71         GLTEXTURETYPE_CUBEMAP,
72         GLTEXTURETYPE_RECTANGLE,
73         GLTEXTURETYPE_TOTAL
74 }
75 gltexturetype_t;
76
77 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_RECTANGLE_ARB};
78 static int gltexturetypebindingenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_BINDING_2D, GL_TEXTURE_BINDING_3D, GL_TEXTURE_BINDING_CUBE_MAP_ARB, GL_TEXTURE_BINDING_RECTANGLE_ARB};
79 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2, 2};
80 static int cubemapside[6] =
81 {
82         GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
83         GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
84         GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
85         GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
86         GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
87         GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
88 };
89
90 typedef struct gltexture_s
91 {
92         // this field is exposed to the R_GetTexture macro, for speed reasons
93         // (must be identical in rtexture_t)
94         int texnum; // GL texture slot number
95
96         // dynamic texture stuff [11/22/2007 Black]
97         // used to hold the texture number of dirty textures   
98         int dirtytexnum;
99         updatecallback_t updatecallback;
100         void *updatacallback_data;
101         // --- [11/22/2007 Black]
102
103         // pointer to texturepool (check this to see if the texture is allocated)
104         struct gltexturepool_s *pool;
105         // pointer to next texture in texturepool chain
106         struct gltexture_s *chain;
107         // name of the texture (this might be removed someday), no duplicates
108         char identifier[MAX_QPATH + 32];
109         // original data size in *inputtexels
110         int inputwidth, inputheight, inputdepth;
111         // copy of the original texture(s) supplied to the upload function, for
112         // delayed uploads (non-precached)
113         unsigned char *inputtexels;
114         // original data size in *inputtexels
115         int inputdatasize;
116         // flags supplied to the LoadTexture function
117         // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
118         int flags;
119         // pointer to one of the textype_ structs
120         textypeinfo_t *textype;
121         // one of the GLTEXTURETYPE_ values
122         int texturetype;
123         // palette if the texture is TEXTYPE_PALETTE
124         const unsigned int *palette;
125         // actual stored texture size after gl_picmip and gl_max_size are applied
126         // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
127         int tilewidth, tileheight, tiledepth;
128         // 1 or 6 depending on texturetype
129         int sides;
130         // bytes per pixel
131         int bytesperpixel;
132         // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
133         int glformat;
134         // 3 or 4
135         int glinternalformat;
136         // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
137         int gltype;
138 }
139 gltexture_t;
140
141 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
142
143 typedef struct gltexturepool_s
144 {
145         unsigned int sentinel;
146         struct gltexture_s *gltchain;
147         struct gltexturepool_s *next;
148 }
149 gltexturepool_t;
150
151 static gltexturepool_t *gltexturepoolchain = NULL;
152
153 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
154 static int resizebuffersize = 0;
155 static const unsigned char *texturebuffer;
156 static int texturebuffersize = 0;
157
158 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
159 {
160         if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.arb_texture_compression)
161         {
162                 if (flags & TEXF_ALPHA)
163                 {
164                         switch(textype)
165                         {
166                         case TEXTYPE_PALETTE:
167                                 return &textype_palette_alpha_compress;
168                         case TEXTYPE_RGBA:
169                                 return &textype_rgba_alpha_compress;
170                         case TEXTYPE_BGRA:
171                                 return &textype_bgra_alpha_compress;
172                         default:
173                                 Host_Error("R_GetTexTypeInfo: unknown texture format");
174                                 return NULL;
175                         }
176                 }
177                 else
178                 {
179                         switch(textype)
180                         {
181                         case TEXTYPE_PALETTE:
182                                 return &textype_palette_compress;
183                         case TEXTYPE_RGBA:
184                                 return &textype_rgba_compress;
185                         case TEXTYPE_BGRA:
186                                 return &textype_bgra_compress;
187                         default:
188                                 Host_Error("R_GetTexTypeInfo: unknown texture format");
189                                 return NULL;
190                         }
191                 }
192         }
193         else
194         {
195                 if (flags & TEXF_ALPHA)
196                 {
197                         switch(textype)
198                         {
199                         case TEXTYPE_PALETTE:
200                                 return &textype_palette_alpha;
201                         case TEXTYPE_RGBA:
202                                 return &textype_rgba_alpha;
203                         case TEXTYPE_BGRA:
204                                 return &textype_bgra_alpha;
205                         default:
206                                 Host_Error("R_GetTexTypeInfo: unknown texture format");
207                                 return NULL;
208                         }
209                 }
210                 else
211                 {
212                         switch(textype)
213                         {
214                         case TEXTYPE_PALETTE:
215                                 return &textype_palette;
216                         case TEXTYPE_RGBA:
217                                 return &textype_rgba;
218                         case TEXTYPE_BGRA:
219                                 return &textype_bgra;
220                         case TEXTYPE_SHADOWMAP:
221                                 return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
222                         default:
223                                 Host_Error("R_GetTexTypeInfo: unknown texture format");
224                                 return NULL;
225                         }
226                 }
227         }
228         return NULL; // this line only to hush compiler warnings
229 }
230
231 // dynamic texture code [11/22/2007 Black]
232 void R_MarkDirtyTexture(rtexture_t *rt) {
233         gltexture_t *glt = (gltexture_t*) rt;
234         if( !glt ) {
235                 return;
236         }
237
238         // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
239         if( !glt->dirtytexnum && glt->flags & GLTEXF_DYNAMIC ) {
240                 glt->dirtytexnum = glt->texnum;
241                 // mark it as dirty, so R_RealGetTexture gets called
242                 glt->texnum = 0;
243         }
244 }
245
246 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
247         gltexture_t *glt = (gltexture_t*) rt;
248         if( !glt ) {
249                 return;
250         }
251
252         glt->flags |= GLTEXF_DYNAMIC;
253         glt->updatecallback = updatecallback;
254         glt->updatacallback_data = data;
255         glt->dirtytexnum = 0;
256 }
257
258 static void R_UpdateDynamicTexture(gltexture_t *glt) {
259         glt->texnum = glt->dirtytexnum;
260         // reset dirtytexnum again (not dirty anymore)
261         glt->dirtytexnum = 0;
262         // TODO: now assert that t->texnum != 0 ?
263         if( glt->updatecallback ) {
264                 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
265         }
266 }
267
268 void R_PurgeTexture(rtexture_t *rt)
269 {
270         if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
271                 R_FreeTexture(rt);
272         }
273 }
274
275 void R_FreeTexture(rtexture_t *rt)
276 {
277         gltexture_t *glt, **gltpointer;
278
279         glt = (gltexture_t *)rt;
280         if (glt == NULL)
281                 Host_Error("R_FreeTexture: texture == NULL");
282
283         for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
284         if (*gltpointer == glt)
285                 *gltpointer = glt->chain;
286         else
287                 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
288
289         if (!(glt->flags & GLTEXF_UPLOAD))
290         {
291                 CHECKGLERROR
292                 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
293         }
294
295         if (glt->inputtexels)
296                 Mem_Free(glt->inputtexels);
297         Mem_Free(glt);
298 }
299
300 rtexturepool_t *R_AllocTexturePool(void)
301 {
302         gltexturepool_t *pool;
303         if (texturemempool == NULL)
304                 return NULL;
305         pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
306         if (pool == NULL)
307                 return NULL;
308         pool->next = gltexturepoolchain;
309         gltexturepoolchain = pool;
310         pool->sentinel = TEXTUREPOOL_SENTINEL;
311         return (rtexturepool_t *)pool;
312 }
313
314 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
315 {
316         gltexturepool_t *pool, **poolpointer;
317         if (rtexturepool == NULL)
318                 return;
319         if (*rtexturepool == NULL)
320                 return;
321         pool = (gltexturepool_t *)(*rtexturepool);
322         *rtexturepool = NULL;
323         if (pool->sentinel != TEXTUREPOOL_SENTINEL)
324                 Host_Error("R_FreeTexturePool: pool already freed");
325         for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
326         if (*poolpointer == pool)
327                 *poolpointer = pool->next;
328         else
329                 Host_Error("R_FreeTexturePool: pool not linked");
330         while (pool->gltchain)
331                 R_FreeTexture((rtexture_t *)pool->gltchain);
332         Mem_Free(pool);
333 }
334
335
336 typedef struct glmode_s
337 {
338         char *name;
339         int minification, magnification;
340 }
341 glmode_t;
342
343 static glmode_t modes[6] =
344 {
345         {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
346         {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
347         {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
348         {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
349         {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
350         {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
351 };
352
353 static void GL_TextureMode_f (void)
354 {
355         int i;
356         GLint oldbindtexnum;
357         gltexture_t *glt;
358         gltexturepool_t *pool;
359
360         if (Cmd_Argc() == 1)
361         {
362                 for (i = 0;i < 6;i++)
363                 {
364                         if (gl_filter_min == modes[i].minification)
365                         {
366                                 Con_Printf("%s\n", modes[i].name);
367                                 return;
368                         }
369                 }
370                 Con_Print("current filter is unknown???\n");
371                 return;
372         }
373
374         for (i = 0;i < 6;i++)
375                 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
376                         break;
377         if (i == 6)
378         {
379                 Con_Print("bad filter name\n");
380                 return;
381         }
382
383         gl_filter_min = modes[i].minification;
384         gl_filter_mag = modes[i].magnification;
385
386         // change all the existing mipmap texture objects
387         // FIXME: force renderer(/client/something?) restart instead?
388         CHECKGLERROR
389         for (pool = gltexturepoolchain;pool;pool = pool->next)
390         {
391                 for (glt = pool->gltchain;glt;glt = glt->chain)
392                 {
393                         // only update already uploaded images
394                         if (!(glt->flags & (GLTEXF_UPLOAD | TEXF_FORCENEAREST | TEXF_FORCELINEAR)))
395                         {
396                                 qglGetIntegerv(gltexturetypebindingenums[glt->texturetype], &oldbindtexnum);CHECKGLERROR
397                                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
398                                 if (glt->flags & TEXF_MIPMAP)
399                                 {
400                                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
401                                 }
402                                 else
403                                 {
404                                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
405                                 }
406                                 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
407                                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
408                         }
409                 }
410         }
411 }
412
413 static void GL_Texture_CalcImageSize(int texturetype, int flags, int inwidth, int inheight, int indepth, int *outwidth, int *outheight, int *outdepth)
414 {
415         int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1;
416
417         switch (texturetype)
418         {
419         default:
420         case GLTEXTURETYPE_2D:
421                 maxsize = vid.maxtexturesize_2d;
422                 if (flags & TEXF_PICMIP)
423                 {
424                         maxsize = bound(1, gl_max_size.integer, maxsize);
425                         picmip = gl_picmip.integer;
426                 }
427                 break;
428         case GLTEXTURETYPE_3D:
429                 maxsize = vid.maxtexturesize_3d;
430                 break;
431         case GLTEXTURETYPE_CUBEMAP:
432                 maxsize = vid.maxtexturesize_cubemap;
433                 break;
434         }
435
436         if (outwidth)
437         {
438                 if (vid.support.arb_texture_non_power_of_two)
439                         width2 = min(inwidth >> picmip, maxsize);
440                 else
441                 {
442                         for (width2 = 1;width2 < inwidth;width2 <<= 1);
443                         for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
444                 }
445                 *outwidth = max(1, width2);
446         }
447         if (outheight)
448         {
449                 if (vid.support.arb_texture_non_power_of_two)
450                         height2 = min(inheight >> picmip, maxsize);
451                 else
452                 {
453                         for (height2 = 1;height2 < inheight;height2 <<= 1);
454                         for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
455                 }
456                 *outheight = max(1, height2);
457         }
458         if (outdepth)
459         {
460                 if (vid.support.arb_texture_non_power_of_two)
461                         depth2 = min(indepth >> picmip, maxsize);
462                 else
463                 {
464                         for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
465                         for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
466                 }
467                 *outdepth = max(1, depth2);
468         }
469 }
470
471
472 static int R_CalcTexelDataSize (gltexture_t *glt)
473 {
474         int width2, height2, depth2, size;
475
476         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2);
477
478         size = width2 * height2 * depth2;
479
480         if (glt->flags & TEXF_MIPMAP)
481         {
482                 while (width2 > 1 || height2 > 1 || depth2 > 1)
483                 {
484                         if (width2 > 1)
485                                 width2 >>= 1;
486                         if (height2 > 1)
487                                 height2 >>= 1;
488                         if (depth2 > 1)
489                                 depth2 >>= 1;
490                         size += width2 * height2 * depth2;
491                 }
492         }
493
494         return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
495 }
496
497 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
498 {
499         int glsize;
500         int isloaded;
501         int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
502         int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
503         gltexture_t *glt;
504         gltexturepool_t *pool;
505         if (printeach)
506                 Con_Print("glsize input loaded mip alpha name\n");
507         for (pool = gltexturepoolchain;pool;pool = pool->next)
508         {
509                 pooltotal = 0;
510                 pooltotalt = 0;
511                 pooltotalp = 0;
512                 poolloaded = 0;
513                 poolloadedt = 0;
514                 poolloadedp = 0;
515                 for (glt = pool->gltchain;glt;glt = glt->chain)
516                 {
517                         glsize = R_CalcTexelDataSize(glt);
518                         isloaded = !(glt->flags & GLTEXF_UPLOAD);
519                         pooltotal++;
520                         pooltotalt += glsize;
521                         pooltotalp += glt->inputdatasize;
522                         if (isloaded)
523                         {
524                                 poolloaded++;
525                                 poolloadedt += glsize;
526                                 poolloadedp += glt->inputdatasize;
527                         }
528                         if (printeach)
529                                 Con_Printf("%c%4i%c%c%4i%c %s %s %s %s\n", isloaded ? '[' : ' ', (glsize + 1023) / 1024, isloaded ? ']' : ' ', glt->inputtexels ? '[' : ' ', (glt->inputdatasize + 1023) / 1024, glt->inputtexels ? ']' : ' ', isloaded ? "loaded" : "      ", (glt->flags & TEXF_MIPMAP) ? "mip" : "   ", (glt->flags & TEXF_ALPHA) ? "alpha" : "     ", glt->identifier);
530                 }
531                 if (printpool)
532                         Con_Printf("texturepool %10p total: %i (%.3fMB, %.3fMB original), uploaded %i (%.3fMB, %.3fMB original), upload on demand %i (%.3fMB, %.3fMB original)\n", (void *)pool, pooltotal, pooltotalt / 1048576.0, pooltotalp / 1048576.0, poolloaded, poolloadedt / 1048576.0, poolloadedp / 1048576.0, pooltotal - poolloaded, (pooltotalt - poolloadedt) / 1048576.0, (pooltotalp - poolloadedp) / 1048576.0);
533                 sumtotal += pooltotal;
534                 sumtotalt += pooltotalt;
535                 sumtotalp += pooltotalp;
536                 sumloaded += poolloaded;
537                 sumloadedt += poolloadedt;
538                 sumloadedp += poolloadedp;
539         }
540         if (printtotal)
541                 Con_Printf("textures total: %i (%.3fMB, %.3fMB original), uploaded %i (%.3fMB, %.3fMB original), upload on demand %i (%.3fMB, %.3fMB original)\n", sumtotal, sumtotalt / 1048576.0, sumtotalp / 1048576.0, sumloaded, sumloadedt / 1048576.0, sumloadedp / 1048576.0, sumtotal - sumloaded, (sumtotalt - sumloadedt) / 1048576.0, (sumtotalp - sumloadedp) / 1048576.0);
542 }
543
544 static void R_TextureStats_f(void)
545 {
546         R_TextureStats_Print(true, true, true);
547 }
548
549 static void r_textures_start(void)
550 {
551         // LordHavoc: allow any alignment
552         CHECKGLERROR
553         qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
554         qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
555
556         texturemempool = Mem_AllocPool("texture management", 0, NULL);
557
558         // Disable JPEG screenshots if the DLL isn't loaded
559         if (! JPEG_OpenLibrary ())
560                 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
561         // TODO: support png screenshots?
562         PNG_OpenLibrary ();
563 }
564
565 static void r_textures_shutdown(void)
566 {
567         rtexturepool_t *temp;
568
569         JPEG_CloseLibrary ();
570
571         while(gltexturepoolchain)
572         {
573                 temp = (rtexturepool_t *) gltexturepoolchain;
574                 R_FreeTexturePool(&temp);
575         }
576
577         resizebuffersize = 0;
578         texturebuffersize = 0;
579         resizebuffer = NULL;
580         colorconvertbuffer = NULL;
581         texturebuffer = NULL;
582         Mem_FreePool(&texturemempool);
583 }
584
585 static void r_textures_newmap(void)
586 {
587 }
588
589 void R_Textures_Init (void)
590 {
591         Cmd_AddCommand("gl_texturemode", &GL_TextureMode_f, "set texture filtering mode (GL_NEAREST, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, etc)");
592         Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
593         Cvar_RegisterVariable (&gl_max_size);
594         Cvar_RegisterVariable (&gl_picmip);
595         Cvar_RegisterVariable (&gl_max_lightmapsize);
596         Cvar_RegisterVariable (&r_lerpimages);
597         Cvar_RegisterVariable (&r_precachetextures);
598         Cvar_RegisterVariable (&gl_texture_anisotropy);
599         Cvar_RegisterVariable (&gl_texturecompression);
600         Cvar_RegisterVariable (&gl_texturecompression_color);
601         Cvar_RegisterVariable (&gl_texturecompression_normal);
602         Cvar_RegisterVariable (&gl_texturecompression_gloss);
603         Cvar_RegisterVariable (&gl_texturecompression_glow);
604         Cvar_RegisterVariable (&gl_texturecompression_2d);
605         Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
606         Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
607         Cvar_RegisterVariable (&gl_texturecompression_sky);
608         Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
609
610         R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap);
611 }
612
613 void R_Textures_Frame (void)
614 {
615         static int old_aniso = 0;
616
617         // could do procedural texture animation here, if we keep track of which
618         // textures were accessed this frame...
619
620         // free the resize buffers
621         resizebuffersize = 0;
622         if (resizebuffer)
623         {
624                 Mem_Free(resizebuffer);
625                 resizebuffer = NULL;
626         }
627         if (colorconvertbuffer)
628         {
629                 Mem_Free(colorconvertbuffer);
630                 colorconvertbuffer = NULL;
631         }
632
633         if (old_aniso != gl_texture_anisotropy.integer)
634         {
635                 gltexture_t *glt;
636                 gltexturepool_t *pool;
637                 GLint oldbindtexnum;
638
639                 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
640
641                 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
642
643                 CHECKGLERROR
644                 for (pool = gltexturepoolchain;pool;pool = pool->next)
645                 {
646                         for (glt = pool->gltchain;glt;glt = glt->chain)
647                         {
648                                 // only update already uploaded images
649                                 if ((glt->flags & (GLTEXF_UPLOAD | TEXF_MIPMAP)) == TEXF_MIPMAP)
650                                 {
651                                         qglGetIntegerv(gltexturetypebindingenums[glt->texturetype], &oldbindtexnum);CHECKGLERROR
652
653                                         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
654                                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
655
656                                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
657                                 }
658                         }
659                 }
660         }
661 }
662
663 void R_MakeResizeBufferBigger(int size)
664 {
665         if (resizebuffersize < size)
666         {
667                 resizebuffersize = size;
668                 if (resizebuffer)
669                         Mem_Free(resizebuffer);
670                 if (colorconvertbuffer)
671                         Mem_Free(colorconvertbuffer);
672                 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
673                 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
674                 if (!resizebuffer || !colorconvertbuffer)
675                         Host_Error("R_Upload: out of memory");
676         }
677 }
678
679 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
680 {
681         int textureenum = gltexturetypeenums[texturetype];
682         int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
683
684         CHECKGLERROR
685
686         if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
687         {
688                 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
689                 if (gl_texture_anisotropy.integer != aniso)
690                         Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
691                 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
692         }
693         qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
694         qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
695         if (gltexturetypedimensions[texturetype] >= 3)
696         {
697                 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
698         }
699
700         CHECKGLERROR
701         if (flags & TEXF_FORCENEAREST)
702         {
703                 if (flags & TEXF_MIPMAP)
704                 {
705                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
706                 }
707                 else
708                 {
709                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
710                 }
711                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
712         }
713         else if (flags & TEXF_FORCELINEAR)
714         {
715                 if (flags & TEXF_MIPMAP)
716                 {
717                         if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
718                         {
719                                 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
720                         }
721                         else
722                         {
723                                 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
724                         }
725                 }
726                 else
727                 {
728                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
729                 }
730                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
731         }
732         else
733         {
734                 if (flags & TEXF_MIPMAP)
735                 {
736                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
737                 }
738                 else
739                 {
740                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
741                 }
742                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
743         }
744
745         if (textype == TEXTYPE_SHADOWMAP)
746         {
747                 if (vid.support.arb_shadow)
748                 {
749                         if (flags & TEXF_COMPARE)
750                         {
751                                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
752                         }
753                         else
754                         {
755                                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
756                         }
757                         qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
758                 }
759                 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
760         }
761
762         CHECKGLERROR
763 }
764
765 static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
766 {
767         int i, mip, width, height, depth;
768         GLint oldbindtexnum;
769         const unsigned char *prevbuffer;
770         prevbuffer = data;
771
772         CHECKGLERROR
773
774         // we need to restore the texture binding after finishing the upload
775         qglGetIntegerv(gltexturetypebindingenums[glt->texturetype], &oldbindtexnum);CHECKGLERROR
776         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
777
778         // these are rounded up versions of the size to do better resampling
779         if (vid.support.arb_texture_non_power_of_two || glt->texturetype == GLTEXTURETYPE_RECTANGLE)
780         {
781                 width = glt->inputwidth;
782                 height = glt->inputheight;
783                 depth = glt->inputdepth;
784         }
785         else
786         {
787                 for (width  = 1;width  < glt->inputwidth ;width  <<= 1);
788                 for (height = 1;height < glt->inputheight;height <<= 1);
789                 for (depth  = 1;depth  < glt->inputdepth ;depth  <<= 1);
790         }
791
792         R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
793         R_MakeResizeBufferBigger(fragwidth * fragheight * fragdepth * glt->sides * glt->bytesperpixel);
794
795         if (prevbuffer == NULL)
796         {
797                 memset(resizebuffer, 0, fragwidth * fragheight * fragdepth * glt->bytesperpixel);
798                 prevbuffer = resizebuffer;
799         }
800         else if (glt->textype->textype == TEXTYPE_PALETTE)
801         {
802                 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
803                 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, fragwidth * fragheight * fragdepth * glt->sides, glt->palette);
804                 prevbuffer = colorconvertbuffer;
805         }
806
807         if ((glt->flags & (TEXF_MIPMAP | TEXF_PICMIP | GLTEXF_UPLOAD)) == 0 && glt->inputwidth == glt->tilewidth && glt->inputheight == glt->tileheight && glt->inputdepth == glt->tiledepth)
808         {
809                 // update a portion of the image
810                 switch(glt->texturetype)
811                 {
812                 case GLTEXTURETYPE_2D:
813                         qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
814                         break;
815                 case GLTEXTURETYPE_3D:
816                         qglTexSubImage3D(GL_TEXTURE_3D, 0, fragx, fragy, fragz, fragwidth, fragheight, fragdepth, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
817                         break;
818                 default:
819                         Host_Error("R_Upload: partial update of type other than 2D");
820                         break;
821                 }
822         }
823         else
824         {
825                 if (fragx || fragy || fragz || glt->inputwidth != fragwidth || glt->inputheight != fragheight || glt->inputdepth != fragdepth)
826                         Host_Error("R_Upload: partial update not allowed on initial upload or in combination with PICMIP or MIPMAP\n");
827
828                 // upload the image for the first time
829                 glt->flags &= ~GLTEXF_UPLOAD;
830
831                 // cubemaps contain multiple images and thus get processed a bit differently
832                 if (glt->texturetype != GLTEXTURETYPE_CUBEMAP)
833                 {
834                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
835                         {
836                                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
837                                 prevbuffer = resizebuffer;
838                         }
839                         // picmip/max_size
840                         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
841                         {
842                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
843                                 prevbuffer = resizebuffer;
844                         }
845                 }
846                 mip = 0;
847                 if (vid.support.arb_texture_compression)
848                 {
849                         if (gl_texturecompression.integer >= 2)
850                                 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
851                         else
852                                 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
853                         CHECKGLERROR
854                 }
855                 switch(glt->texturetype)
856                 {
857                 case GLTEXTURETYPE_2D:
858                         qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
859                         if (glt->flags & TEXF_MIPMAP)
860                         {
861                                 while (width > 1 || height > 1 || depth > 1)
862                                 {
863                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
864                                         prevbuffer = resizebuffer;
865                                         qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
866                                 }
867                         }
868                         break;
869                 case GLTEXTURETYPE_3D:
870                         qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
871                         if (glt->flags & TEXF_MIPMAP)
872                         {
873                                 while (width > 1 || height > 1 || depth > 1)
874                                 {
875                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
876                                         prevbuffer = resizebuffer;
877                                         qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
878                                 }
879                         }
880                         break;
881                 case GLTEXTURETYPE_CUBEMAP:
882                         // convert and upload each side in turn,
883                         // from a continuous block of input texels
884                         texturebuffer = (unsigned char *)prevbuffer;
885                         for (i = 0;i < 6;i++)
886                         {
887                                 prevbuffer = texturebuffer;
888                                 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
889                                 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
890                                 {
891                                         Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
892                                         prevbuffer = resizebuffer;
893                                 }
894                                 // picmip/max_size
895                                 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
896                                 {
897                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
898                                         prevbuffer = resizebuffer;
899                                 }
900                                 mip = 0;
901                                 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
902                                 if (glt->flags & TEXF_MIPMAP)
903                                 {
904                                         while (width > 1 || height > 1 || depth > 1)
905                                         {
906                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
907                                                 prevbuffer = resizebuffer;
908                                                 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
909                                         }
910                                 }
911                         }
912                         break;
913                 case GLTEXTURETYPE_RECTANGLE:
914                         qglTexImage2D(GL_TEXTURE_RECTANGLE_ARB, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, NULL);CHECKGLERROR
915                         break;
916                 }
917                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
918         }
919         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
920 }
921
922 int R_RealGetTexture(rtexture_t *rt)
923 {
924         if (rt)
925         {
926                 gltexture_t *glt;
927                 glt = (gltexture_t *)rt;
928                 if (glt->flags & GLTEXF_DYNAMIC)
929                         R_UpdateDynamicTexture(glt);
930                 if (glt->flags & GLTEXF_UPLOAD)
931                 {
932                         CHECKGLERROR
933                         qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
934                         R_Upload(glt, glt->inputtexels, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
935                         if (glt->inputtexels)
936                         {
937                                 Mem_Free(glt->inputtexels);
938                                 glt->inputtexels = NULL;
939                                 glt->flags |= GLTEXF_DESTROYED;
940                         }
941                         else if (glt->flags & GLTEXF_DESTROYED)
942                                 Con_Printf("R_GetTexture: Texture %s already uploaded and destroyed.  Can not upload original image again.  Uploaded blank texture.\n", glt->identifier);
943                 }
944
945                 return glt->texnum;
946         }
947         else
948                 return 0;
949 }
950
951 static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int depth, int sides, int flags, textype_t textype, int texturetype, const unsigned char *data, const unsigned int *palette)
952 {
953         int i, size;
954         gltexture_t *glt;
955         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
956         textypeinfo_t *texinfo;
957         int precache;
958
959         if (cls.state == ca_dedicated)
960                 return NULL;
961
962         if (texturetype == GLTEXTURETYPE_RECTANGLE && !vid.support.arb_texture_rectangle)
963         {
964                 Con_Printf ("R_LoadTexture: rectangle texture not supported by driver\n");
965                 return NULL;
966         }
967         if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
968         {
969                 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
970                 return NULL;
971         }
972         if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
973         {
974                 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
975                 return NULL;
976         }
977
978         texinfo = R_GetTexTypeInfo(textype, flags);
979         size = width * height * depth * sides * texinfo->inputbytesperpixel;
980         if (size < 1)
981         {
982                 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
983                 return NULL;
984         }
985
986         // clear the alpha flag if the texture has no transparent pixels
987         switch(textype)
988         {
989         case TEXTYPE_PALETTE:
990                 if (flags & TEXF_ALPHA)
991                 {
992                         flags &= ~TEXF_ALPHA;
993                         if (data)
994                         {
995                                 for (i = 0;i < size;i++)
996                                 {
997                                         if (((unsigned char *)&palette[data[i]])[3] < 255)
998                                         {
999                                                 flags |= TEXF_ALPHA;
1000                                                 break;
1001                                         }
1002                                 }
1003                         }
1004                 }
1005                 break;
1006         case TEXTYPE_RGBA:
1007         case TEXTYPE_BGRA:
1008                 if (flags & TEXF_ALPHA)
1009                 {
1010                         flags &= ~TEXF_ALPHA;
1011                         if (data)
1012                         {
1013                                 for (i = 3;i < size;i += 4)
1014                                 {
1015                                         if (data[i] < 255)
1016                                         {
1017                                                 flags |= TEXF_ALPHA;
1018                                                 break;
1019                                         }
1020                                 }
1021                         }
1022                 }
1023                 break;
1024         case TEXTYPE_SHADOWMAP:
1025                 break;
1026         default:
1027                 Host_Error("R_LoadTexture: unknown texture type");
1028         }
1029
1030         glt = (gltexture_t *)Mem_Alloc(texturemempool, sizeof(gltexture_t));
1031         if (identifier)
1032                 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1033         glt->pool = pool;
1034         glt->chain = pool->gltchain;
1035         pool->gltchain = glt;
1036         glt->inputwidth = width;
1037         glt->inputheight = height;
1038         glt->inputdepth = depth;
1039         glt->flags = flags | GLTEXF_UPLOAD;
1040         glt->textype = texinfo;
1041         glt->texturetype = texturetype;
1042         glt->inputdatasize = size;
1043         glt->palette = palette;
1044         glt->glinternalformat = texinfo->glinternalformat;
1045         glt->glformat = texinfo->glformat;
1046         glt->gltype = texinfo->gltype;
1047         glt->bytesperpixel = texinfo->internalbytesperpixel;
1048         glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1049         glt->texnum = 0;
1050         // init the dynamic texture attributes, too [11/22/2007 Black]
1051         glt->dirtytexnum = 0;
1052         glt->updatecallback = NULL;
1053         glt->updatacallback_data = NULL;
1054
1055         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth);
1056
1057         precache = false;
1058         if (glt->flags & TEXF_ALWAYSPRECACHE)
1059                 precache = true;
1060         else if (r_precachetextures.integer >= 2)
1061                 precache = true;
1062         else if (r_precachetextures.integer >= 1)
1063                 if (glt->flags & TEXF_PRECACHE)
1064                         precache = true;
1065
1066         if (precache)
1067         {
1068                 // immediate upload (most common case)
1069                 // data may be NULL (blank texture for dynamic rendering)
1070                 CHECKGLERROR
1071                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1072                 R_Upload(glt, data, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
1073         }
1074         else if (data)
1075         {
1076                 // deferred texture upload (menu graphics)
1077                 // optimize first if possible
1078                 if ((textype == TEXTYPE_BGRA || textype == TEXTYPE_RGBA) && glt->inputwidth * glt->inputheight * glt->inputdepth > glt->tilewidth * glt->tileheight * glt->tiledepth)
1079                 {
1080                         glt->inputtexels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1081                         Image_Resample32(data, glt->inputwidth, glt->inputheight, glt->inputdepth, glt->inputtexels, glt->tilewidth, glt->tileheight, glt->tiledepth, r_lerpimages.integer);
1082                         // change texture size accordingly
1083                         glt->inputwidth = glt->tilewidth;
1084                         glt->inputheight = glt->tileheight;
1085                         glt->inputdepth = glt->tiledepth;
1086                         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth);
1087                 }
1088                 else
1089                 {
1090                         glt->inputtexels = (unsigned char *)Mem_Alloc(texturemempool, size);
1091                         memcpy(glt->inputtexels, data, size);
1092                 }
1093         }
1094
1095         // texture converting and uploading can take a while, so make sure we're sending keepalives
1096         CL_KeepaliveMessage(false);
1097
1098         return (rtexture_t *)glt;
1099 }
1100
1101 rtexture_t *R_LoadTexture2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, const unsigned char *data, textype_t textype, int flags, const unsigned int *palette)
1102 {
1103         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, textype, GLTEXTURETYPE_2D, data, palette);
1104 }
1105
1106 rtexture_t *R_LoadTexture3D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int depth, const unsigned char *data, textype_t textype, int flags, const unsigned int *palette)
1107 {
1108         return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, textype, GLTEXTURETYPE_3D, data, palette);
1109 }
1110
1111 rtexture_t *R_LoadTextureCubeMap(rtexturepool_t *rtexturepool, const char *identifier, int width, const unsigned char *data, textype_t textype, int flags, const unsigned int *palette)
1112 {
1113         return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1114 }
1115
1116 rtexture_t *R_LoadTextureRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, const unsigned char *data, textype_t textype, int flags, const unsigned int *palette)
1117 {
1118         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, textype, GLTEXTURETYPE_RECTANGLE, data, palette);
1119 }
1120
1121 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1122 {
1123         int flags = TEXF_ALWAYSPRECACHE | TEXF_CLAMP;
1124         if (filter)
1125                 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1126         else
1127                 flags |= TEXF_FORCENEAREST;
1128         if (precision <= 16)
1129                 flags |= TEXF_LOWPRECISION;
1130         return flags;
1131 }
1132
1133 rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1134 {
1135         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
1136 }
1137
1138 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1139 {
1140         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1141 }
1142
1143 rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter)
1144 {
1145     return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
1146 }
1147
1148 int R_TextureWidth(rtexture_t *rt)
1149 {
1150         return rt ? ((gltexture_t *)rt)->inputwidth : 0;
1151 }
1152
1153 int R_TextureHeight(rtexture_t *rt)
1154 {
1155         return rt ? ((gltexture_t *)rt)->inputheight : 0;
1156 }
1157
1158 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
1159 {
1160         gltexture_t *glt = (gltexture_t *)rt;
1161         if (data == NULL)
1162                 Host_Error("R_UpdateTexture: no data supplied");
1163         if (glt == NULL)
1164                 Host_Error("R_UpdateTexture: no texture supplied");
1165         if (!glt->texnum)
1166                 Host_Error("R_UpdateTexture: texture has not been uploaded yet");
1167         // update part of the texture
1168         R_Upload(glt, data, x, y, 0, width, height, 1);
1169 }
1170
1171 void R_ClearTexture (rtexture_t *rt)
1172 {
1173         gltexture_t *glt = (gltexture_t *)rt;
1174
1175         R_Upload( glt, NULL, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth );
1176 }