]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_textures.c
added gl_max_lightmapsize
[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 (&r_lerpimages);
596         Cvar_RegisterVariable (&r_precachetextures);
597         Cvar_RegisterVariable (&gl_texture_anisotropy);
598         Cvar_RegisterVariable (&gl_texturecompression);
599         Cvar_RegisterVariable (&gl_texturecompression_color);
600         Cvar_RegisterVariable (&gl_texturecompression_normal);
601         Cvar_RegisterVariable (&gl_texturecompression_gloss);
602         Cvar_RegisterVariable (&gl_texturecompression_glow);
603         Cvar_RegisterVariable (&gl_texturecompression_2d);
604         Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
605         Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
606         Cvar_RegisterVariable (&gl_texturecompression_sky);
607         Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
608
609         R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap);
610 }
611
612 void R_Textures_Frame (void)
613 {
614         static int old_aniso = 0;
615
616         // could do procedural texture animation here, if we keep track of which
617         // textures were accessed this frame...
618
619         // free the resize buffers
620         resizebuffersize = 0;
621         if (resizebuffer)
622         {
623                 Mem_Free(resizebuffer);
624                 resizebuffer = NULL;
625         }
626         if (colorconvertbuffer)
627         {
628                 Mem_Free(colorconvertbuffer);
629                 colorconvertbuffer = NULL;
630         }
631
632         if (old_aniso != gl_texture_anisotropy.integer)
633         {
634                 gltexture_t *glt;
635                 gltexturepool_t *pool;
636                 GLint oldbindtexnum;
637
638                 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
639
640                 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
641
642                 CHECKGLERROR
643                 for (pool = gltexturepoolchain;pool;pool = pool->next)
644                 {
645                         for (glt = pool->gltchain;glt;glt = glt->chain)
646                         {
647                                 // only update already uploaded images
648                                 if ((glt->flags & (GLTEXF_UPLOAD | TEXF_MIPMAP)) == TEXF_MIPMAP)
649                                 {
650                                         qglGetIntegerv(gltexturetypebindingenums[glt->texturetype], &oldbindtexnum);CHECKGLERROR
651
652                                         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
653                                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
654
655                                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
656                                 }
657                         }
658                 }
659         }
660 }
661
662 void R_MakeResizeBufferBigger(int size)
663 {
664         if (resizebuffersize < size)
665         {
666                 resizebuffersize = size;
667                 if (resizebuffer)
668                         Mem_Free(resizebuffer);
669                 if (colorconvertbuffer)
670                         Mem_Free(colorconvertbuffer);
671                 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
672                 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
673                 if (!resizebuffer || !colorconvertbuffer)
674                         Host_Error("R_Upload: out of memory");
675         }
676 }
677
678 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
679 {
680         int textureenum = gltexturetypeenums[texturetype];
681         int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
682
683         CHECKGLERROR
684
685         if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
686         {
687                 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
688                 if (gl_texture_anisotropy.integer != aniso)
689                         Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
690                 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
691         }
692         qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
693         qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
694         if (gltexturetypedimensions[texturetype] >= 3)
695         {
696                 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
697         }
698
699         CHECKGLERROR
700         if (flags & TEXF_FORCENEAREST)
701         {
702                 if (flags & TEXF_MIPMAP)
703                 {
704                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
705                 }
706                 else
707                 {
708                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
709                 }
710                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
711         }
712         else if (flags & TEXF_FORCELINEAR)
713         {
714                 if (flags & TEXF_MIPMAP)
715                 {
716                         if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
717                         {
718                                 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
719                         }
720                         else
721                         {
722                                 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
723                         }
724                 }
725                 else
726                 {
727                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
728                 }
729                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
730         }
731         else
732         {
733                 if (flags & TEXF_MIPMAP)
734                 {
735                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
736                 }
737                 else
738                 {
739                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
740                 }
741                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
742         }
743
744         if (textype == TEXTYPE_SHADOWMAP)
745         {
746                 if (vid.support.arb_shadow)
747                 {
748                         if (flags & TEXF_COMPARE)
749                         {
750                                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
751                         }
752                         else
753                         {
754                                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
755                         }
756                         qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
757                 }
758                 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
759         }
760
761         CHECKGLERROR
762 }
763
764 static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
765 {
766         int i, mip, width, height, depth;
767         GLint oldbindtexnum;
768         const unsigned char *prevbuffer;
769         prevbuffer = data;
770
771         CHECKGLERROR
772
773         // we need to restore the texture binding after finishing the upload
774         qglGetIntegerv(gltexturetypebindingenums[glt->texturetype], &oldbindtexnum);CHECKGLERROR
775         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
776
777         // these are rounded up versions of the size to do better resampling
778         if (vid.support.arb_texture_non_power_of_two || glt->texturetype == GLTEXTURETYPE_RECTANGLE)
779         {
780                 width = glt->inputwidth;
781                 height = glt->inputheight;
782                 depth = glt->inputdepth;
783         }
784         else
785         {
786                 for (width  = 1;width  < glt->inputwidth ;width  <<= 1);
787                 for (height = 1;height < glt->inputheight;height <<= 1);
788                 for (depth  = 1;depth  < glt->inputdepth ;depth  <<= 1);
789         }
790
791         R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
792         R_MakeResizeBufferBigger(fragwidth * fragheight * fragdepth * glt->sides * glt->bytesperpixel);
793
794         if (prevbuffer == NULL)
795         {
796                 memset(resizebuffer, 0, fragwidth * fragheight * fragdepth * glt->bytesperpixel);
797                 prevbuffer = resizebuffer;
798         }
799         else if (glt->textype->textype == TEXTYPE_PALETTE)
800         {
801                 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
802                 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, fragwidth * fragheight * fragdepth * glt->sides, glt->palette);
803                 prevbuffer = colorconvertbuffer;
804         }
805
806         if ((glt->flags & (TEXF_MIPMAP | TEXF_PICMIP | GLTEXF_UPLOAD)) == 0 && glt->inputwidth == glt->tilewidth && glt->inputheight == glt->tileheight && glt->inputdepth == glt->tiledepth)
807         {
808                 // update a portion of the image
809                 switch(glt->texturetype)
810                 {
811                 case GLTEXTURETYPE_2D:
812                         qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
813                         break;
814                 case GLTEXTURETYPE_3D:
815                         qglTexSubImage3D(GL_TEXTURE_3D, 0, fragx, fragy, fragz, fragwidth, fragheight, fragdepth, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
816                         break;
817                 default:
818                         Host_Error("R_Upload: partial update of type other than 2D");
819                         break;
820                 }
821         }
822         else
823         {
824                 if (fragx || fragy || fragz || glt->inputwidth != fragwidth || glt->inputheight != fragheight || glt->inputdepth != fragdepth)
825                         Host_Error("R_Upload: partial update not allowed on initial upload or in combination with PICMIP or MIPMAP\n");
826
827                 // upload the image for the first time
828                 glt->flags &= ~GLTEXF_UPLOAD;
829
830                 // cubemaps contain multiple images and thus get processed a bit differently
831                 if (glt->texturetype != GLTEXTURETYPE_CUBEMAP)
832                 {
833                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
834                         {
835                                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
836                                 prevbuffer = resizebuffer;
837                         }
838                         // picmip/max_size
839                         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
840                         {
841                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
842                                 prevbuffer = resizebuffer;
843                         }
844                 }
845                 mip = 0;
846                 if (vid.support.arb_texture_compression)
847                 {
848                         if (gl_texturecompression.integer >= 2)
849                                 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
850                         else
851                                 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
852                         CHECKGLERROR
853                 }
854                 switch(glt->texturetype)
855                 {
856                 case GLTEXTURETYPE_2D:
857                         qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
858                         if (glt->flags & TEXF_MIPMAP)
859                         {
860                                 while (width > 1 || height > 1 || depth > 1)
861                                 {
862                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
863                                         prevbuffer = resizebuffer;
864                                         qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
865                                 }
866                         }
867                         break;
868                 case GLTEXTURETYPE_3D:
869                         qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
870                         if (glt->flags & TEXF_MIPMAP)
871                         {
872                                 while (width > 1 || height > 1 || depth > 1)
873                                 {
874                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
875                                         prevbuffer = resizebuffer;
876                                         qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
877                                 }
878                         }
879                         break;
880                 case GLTEXTURETYPE_CUBEMAP:
881                         // convert and upload each side in turn,
882                         // from a continuous block of input texels
883                         texturebuffer = (unsigned char *)prevbuffer;
884                         for (i = 0;i < 6;i++)
885                         {
886                                 prevbuffer = texturebuffer;
887                                 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
888                                 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
889                                 {
890                                         Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
891                                         prevbuffer = resizebuffer;
892                                 }
893                                 // picmip/max_size
894                                 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
895                                 {
896                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
897                                         prevbuffer = resizebuffer;
898                                 }
899                                 mip = 0;
900                                 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
901                                 if (glt->flags & TEXF_MIPMAP)
902                                 {
903                                         while (width > 1 || height > 1 || depth > 1)
904                                         {
905                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
906                                                 prevbuffer = resizebuffer;
907                                                 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
908                                         }
909                                 }
910                         }
911                         break;
912                 case GLTEXTURETYPE_RECTANGLE:
913                         qglTexImage2D(GL_TEXTURE_RECTANGLE_ARB, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, NULL);CHECKGLERROR
914                         break;
915                 }
916                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
917         }
918         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
919 }
920
921 int R_RealGetTexture(rtexture_t *rt)
922 {
923         if (rt)
924         {
925                 gltexture_t *glt;
926                 glt = (gltexture_t *)rt;
927                 if (glt->flags & GLTEXF_DYNAMIC)
928                         R_UpdateDynamicTexture(glt);
929                 if (glt->flags & GLTEXF_UPLOAD)
930                 {
931                         CHECKGLERROR
932                         qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
933                         R_Upload(glt, glt->inputtexels, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
934                         if (glt->inputtexels)
935                         {
936                                 Mem_Free(glt->inputtexels);
937                                 glt->inputtexels = NULL;
938                                 glt->flags |= GLTEXF_DESTROYED;
939                         }
940                         else if (glt->flags & GLTEXF_DESTROYED)
941                                 Con_Printf("R_GetTexture: Texture %s already uploaded and destroyed.  Can not upload original image again.  Uploaded blank texture.\n", glt->identifier);
942                 }
943
944                 return glt->texnum;
945         }
946         else
947                 return 0;
948 }
949
950 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)
951 {
952         int i, size;
953         gltexture_t *glt;
954         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
955         textypeinfo_t *texinfo;
956         int precache;
957
958         if (cls.state == ca_dedicated)
959                 return NULL;
960
961         if (texturetype == GLTEXTURETYPE_RECTANGLE && !vid.support.arb_texture_rectangle)
962         {
963                 Con_Printf ("R_LoadTexture: rectangle texture not supported by driver\n");
964                 return NULL;
965         }
966         if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
967         {
968                 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
969                 return NULL;
970         }
971         if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
972         {
973                 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
974                 return NULL;
975         }
976
977         texinfo = R_GetTexTypeInfo(textype, flags);
978         size = width * height * depth * sides * texinfo->inputbytesperpixel;
979         if (size < 1)
980         {
981                 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
982                 return NULL;
983         }
984
985         // clear the alpha flag if the texture has no transparent pixels
986         switch(textype)
987         {
988         case TEXTYPE_PALETTE:
989                 if (flags & TEXF_ALPHA)
990                 {
991                         flags &= ~TEXF_ALPHA;
992                         if (data)
993                         {
994                                 for (i = 0;i < size;i++)
995                                 {
996                                         if (((unsigned char *)&palette[data[i]])[3] < 255)
997                                         {
998                                                 flags |= TEXF_ALPHA;
999                                                 break;
1000                                         }
1001                                 }
1002                         }
1003                 }
1004                 break;
1005         case TEXTYPE_RGBA:
1006         case TEXTYPE_BGRA:
1007                 if (flags & TEXF_ALPHA)
1008                 {
1009                         flags &= ~TEXF_ALPHA;
1010                         if (data)
1011                         {
1012                                 for (i = 3;i < size;i += 4)
1013                                 {
1014                                         if (data[i] < 255)
1015                                         {
1016                                                 flags |= TEXF_ALPHA;
1017                                                 break;
1018                                         }
1019                                 }
1020                         }
1021                 }
1022                 break;
1023         case TEXTYPE_SHADOWMAP:
1024                 break;
1025         default:
1026                 Host_Error("R_LoadTexture: unknown texture type");
1027         }
1028
1029         glt = (gltexture_t *)Mem_Alloc(texturemempool, sizeof(gltexture_t));
1030         if (identifier)
1031                 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1032         glt->pool = pool;
1033         glt->chain = pool->gltchain;
1034         pool->gltchain = glt;
1035         glt->inputwidth = width;
1036         glt->inputheight = height;
1037         glt->inputdepth = depth;
1038         glt->flags = flags | GLTEXF_UPLOAD;
1039         glt->textype = texinfo;
1040         glt->texturetype = texturetype;
1041         glt->inputdatasize = size;
1042         glt->palette = palette;
1043         glt->glinternalformat = texinfo->glinternalformat;
1044         glt->glformat = texinfo->glformat;
1045         glt->gltype = texinfo->gltype;
1046         glt->bytesperpixel = texinfo->internalbytesperpixel;
1047         glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1048         glt->texnum = 0;
1049         // init the dynamic texture attributes, too [11/22/2007 Black]
1050         glt->dirtytexnum = 0;
1051         glt->updatecallback = NULL;
1052         glt->updatacallback_data = NULL;
1053
1054         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth);
1055
1056         precache = false;
1057         if (glt->flags & TEXF_ALWAYSPRECACHE)
1058                 precache = true;
1059         else if (r_precachetextures.integer >= 2)
1060                 precache = true;
1061         else if (r_precachetextures.integer >= 1)
1062                 if (glt->flags & TEXF_PRECACHE)
1063                         precache = true;
1064
1065         if (precache)
1066         {
1067                 // immediate upload (most common case)
1068                 // data may be NULL (blank texture for dynamic rendering)
1069                 CHECKGLERROR
1070                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1071                 R_Upload(glt, data, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
1072         }
1073         else if (data)
1074         {
1075                 // deferred texture upload (menu graphics)
1076                 // optimize first if possible
1077                 if ((textype == TEXTYPE_BGRA || textype == TEXTYPE_RGBA) && glt->inputwidth * glt->inputheight * glt->inputdepth > glt->tilewidth * glt->tileheight * glt->tiledepth)
1078                 {
1079                         glt->inputtexels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1080                         Image_Resample32(data, glt->inputwidth, glt->inputheight, glt->inputdepth, glt->inputtexels, glt->tilewidth, glt->tileheight, glt->tiledepth, r_lerpimages.integer);
1081                         // change texture size accordingly
1082                         glt->inputwidth = glt->tilewidth;
1083                         glt->inputheight = glt->tileheight;
1084                         glt->inputdepth = glt->tiledepth;
1085                         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth);
1086                 }
1087                 else
1088                 {
1089                         glt->inputtexels = (unsigned char *)Mem_Alloc(texturemempool, size);
1090                         memcpy(glt->inputtexels, data, size);
1091                 }
1092         }
1093
1094         // texture converting and uploading can take a while, so make sure we're sending keepalives
1095         CL_KeepaliveMessage(false);
1096
1097         return (rtexture_t *)glt;
1098 }
1099
1100 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)
1101 {
1102         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, textype, GLTEXTURETYPE_2D, data, palette);
1103 }
1104
1105 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)
1106 {
1107         return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, textype, GLTEXTURETYPE_3D, data, palette);
1108 }
1109
1110 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)
1111 {
1112         return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1113 }
1114
1115 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1116 {
1117         int flags = TEXF_ALWAYSPRECACHE | TEXF_CLAMP;
1118         if (filter)
1119                 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1120         else
1121                 flags |= TEXF_FORCENEAREST;
1122         if (precision <= 16)
1123                 flags |= TEXF_LOWPRECISION;
1124         return flags;
1125 }
1126
1127 rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1128 {
1129         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
1130 }
1131
1132 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1133 {
1134         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1135 }
1136
1137 rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter)
1138 {
1139     return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
1140 }
1141
1142 int R_TextureWidth(rtexture_t *rt)
1143 {
1144         return rt ? ((gltexture_t *)rt)->inputwidth : 0;
1145 }
1146
1147 int R_TextureHeight(rtexture_t *rt)
1148 {
1149         return rt ? ((gltexture_t *)rt)->inputheight : 0;
1150 }
1151
1152 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
1153 {
1154         gltexture_t *glt = (gltexture_t *)rt;
1155         if (data == NULL)
1156                 Host_Error("R_UpdateTexture: no data supplied");
1157         if (glt == NULL)
1158                 Host_Error("R_UpdateTexture: no texture supplied");
1159         if (!glt->texnum)
1160                 Host_Error("R_UpdateTexture: texture has not been uploaded yet");
1161         // update part of the texture
1162         R_Upload(glt, data, x, y, 0, width, height, 1);
1163 }
1164
1165 void R_ClearTexture (rtexture_t *rt)
1166 {
1167         gltexture_t *glt = (gltexture_t *)rt;
1168
1169         R_Upload( glt, NULL, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth );
1170 }