]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_textures.c
fix a display issue with warpzone decals I caused in my last change
[xonotic/darkplaces.git] / gl_textures.c
1
2 #include "quakedef.h"
3 #include "image.h"
4 #include "jpeg.h"
5 #include "image_png.h"
6 #include "intoverflow.h"
7
8 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)"};
9 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)"};
10 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%"};
11 cvar_t gl_picmip_world = {CVAR_SAVE, "gl_picmip_world", "0", "extra picmip level for world textures (may be negative, which will then reduce gl_picmip for these)"};
12 cvar_t r_picmipworld = {CVAR_SAVE, "r_picmipworld", "1", "whether gl_picmip shall apply to world textures too (setting this to 0 is a shorthand for gl_picmip_world -9999999)"};
13 cvar_t gl_picmip_sprites = {CVAR_SAVE, "gl_picmip_sprites", "0", "extra picmip level for sprite textures (may be negative, which will then reduce gl_picmip for these)"};
14 cvar_t r_picmipsprites = {CVAR_SAVE, "r_picmipsprites", "1", "make gl_picmip affect sprites too (saves some graphics memory in sprite heavy games) (setting this to 0 is a shorthand for gl_picmip_sprites -9999999)"};
15 cvar_t gl_picmip_other = {CVAR_SAVE, "gl_picmip_other", "0", "extra picmip level for other textures (may be negative, which will then reduce gl_picmip for these)"};
16 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)"};
17 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"};
18 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"};
19 cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
20 cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
21 cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
22 cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
23 cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
24 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
25 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)"};
26 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
27 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
28 cvar_t gl_texturecompression_reflectmask = {CVAR_SAVE, "gl_texturecompression_reflectmask", "1", "whether to compress reflection cubemap masks (mask of which areas of the texture should reflect the generic shiny cubemap)"};
29 cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "1", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"};
30 cvar_t r_texture_dds_load_alphamode = {0, "r_texture_dds_load_alphamode", "1", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambigous, 2: texture format only"};
31
32 qboolean        gl_filter_force = false;
33 int             gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
34 int             gl_filter_mag = GL_LINEAR;
35
36
37 static mempool_t *texturemempool;
38 static memexpandablearray_t texturearray;
39
40 // note: this must not conflict with TEXF_ flags in r_textures.h
41 // bitmask for mismatch checking
42 #define GLTEXF_IMPORTANTBITS (0)
43 // dynamic texture (treat texnum == 0 differently)
44 #define GLTEXF_DYNAMIC          0x00080000
45
46 typedef struct textypeinfo_s
47 {
48         textype_t textype;
49         int inputbytesperpixel;
50         int internalbytesperpixel;
51         float glinternalbytesperpixel;
52         int glinternalformat;
53         int glformat;
54         int gltype;
55 }
56 textypeinfo_t;
57
58
59 static textypeinfo_t textype_palette                = {TEXTYPE_PALETTE    , 1, 4, 4.0f, 3                               , GL_BGRA           , GL_UNSIGNED_BYTE };
60 static textypeinfo_t textype_palette_alpha          = {TEXTYPE_PALETTE    , 1, 4, 4.0f, 4                               , GL_BGRA           , GL_UNSIGNED_BYTE };
61 static textypeinfo_t textype_rgba                   = {TEXTYPE_RGBA       , 4, 4, 4.0f, 3                               , GL_RGBA           , GL_UNSIGNED_BYTE };
62 static textypeinfo_t textype_rgba_alpha             = {TEXTYPE_RGBA       , 4, 4, 4.0f, 4                               , GL_RGBA           , GL_UNSIGNED_BYTE };
63 static textypeinfo_t textype_rgba_compress          = {TEXTYPE_RGBA       , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA           , GL_UNSIGNED_BYTE };
64 static textypeinfo_t textype_rgba_alpha_compress    = {TEXTYPE_RGBA       , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA           , GL_UNSIGNED_BYTE };
65 static textypeinfo_t textype_bgra                   = {TEXTYPE_BGRA       , 4, 4, 4.0f, 3                               , GL_BGRA           , GL_UNSIGNED_BYTE };
66 static textypeinfo_t textype_bgra_alpha             = {TEXTYPE_BGRA       , 4, 4, 4.0f, 4                               , GL_BGRA           , GL_UNSIGNED_BYTE };
67 static textypeinfo_t textype_bgra_compress          = {TEXTYPE_BGRA       , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA           , GL_UNSIGNED_BYTE };
68 static textypeinfo_t textype_bgra_alpha_compress    = {TEXTYPE_BGRA       , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_BGRA           , GL_UNSIGNED_BYTE };
69 static textypeinfo_t textype_shadowmap16            = {TEXTYPE_SHADOWMAP  , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB        , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
70 static textypeinfo_t textype_shadowmap24            = {TEXTYPE_SHADOWMAP  , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB        , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
71 static textypeinfo_t textype_alpha                  = {TEXTYPE_ALPHA      , 1, 4, 4.0f, GL_ALPHA                        , GL_ALPHA          , GL_UNSIGNED_BYTE };
72 static textypeinfo_t textype_dxt1                   = {TEXTYPE_DXT1       , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0                 , 0                };
73 static textypeinfo_t textype_dxt1a                  = {TEXTYPE_DXT1A      , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0                 , 0                };
74 static textypeinfo_t textype_dxt3                   = {TEXTYPE_DXT3       , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0                 , 0                };
75 static textypeinfo_t textype_dxt5                   = {TEXTYPE_DXT5       , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0                 , 0                };
76 static textypeinfo_t textype_colorbuffer            = {TEXTYPE_COLORBUFFER, 4, 4, 4.0f, 4                               , GL_BGRA           , GL_UNSIGNED_BYTE };
77
78
79 typedef enum gltexturetype_e
80 {
81         GLTEXTURETYPE_2D,
82         GLTEXTURETYPE_3D,
83         GLTEXTURETYPE_CUBEMAP,
84         GLTEXTURETYPE_RECTANGLE,
85         GLTEXTURETYPE_TOTAL
86 }
87 gltexturetype_t;
88
89 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_RECTANGLE_ARB};
90 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2, 2};
91 static int cubemapside[6] =
92 {
93         GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
94         GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
95         GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
96         GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
97         GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
98         GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
99 };
100
101 typedef struct gltexture_s
102 {
103         // this portion of the struct is exposed to the R_GetTexture macro for
104         // speed reasons, must be identical in rtexture_t!
105         int texnum; // GL texture slot number
106         qboolean dirty; // indicates that R_RealGetTexture should be called
107         int gltexturetypeenum; // used by R_Mesh_TexBind
108
109         // dynamic texture stuff [11/22/2007 Black]
110         updatecallback_t updatecallback;
111         void *updatacallback_data;
112         // --- [11/22/2007 Black]
113
114         // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
115         unsigned char *bufferpixels;
116         qboolean buffermodified;
117
118         // pointer to texturepool (check this to see if the texture is allocated)
119         struct gltexturepool_s *pool;
120         // pointer to next texture in texturepool chain
121         struct gltexture_s *chain;
122         // name of the texture (this might be removed someday), no duplicates
123         char identifier[MAX_QPATH + 32];
124         // original data size in *inputtexels
125         int inputwidth, inputheight, inputdepth;
126         // copy of the original texture(s) supplied to the upload function, for
127         // delayed uploads (non-precached)
128         unsigned char *inputtexels;
129         // original data size in *inputtexels
130         int inputdatasize;
131         // flags supplied to the LoadTexture function
132         // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
133         int flags;
134         // picmip level
135         int miplevel;
136         // pointer to one of the textype_ structs
137         textypeinfo_t *textype;
138         // one of the GLTEXTURETYPE_ values
139         int texturetype;
140         // palette if the texture is TEXTYPE_PALETTE
141         const unsigned int *palette;
142         // actual stored texture size after gl_picmip and gl_max_size are applied
143         // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
144         int tilewidth, tileheight, tiledepth;
145         // 1 or 6 depending on texturetype
146         int sides;
147         // bytes per pixel
148         int bytesperpixel;
149         // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
150         int glformat;
151         // 3 or 4
152         int glinternalformat;
153         // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
154         int gltype;
155 }
156 gltexture_t;
157
158 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
159
160 typedef struct gltexturepool_s
161 {
162         unsigned int sentinel;
163         struct gltexture_s *gltchain;
164         struct gltexturepool_s *next;
165 }
166 gltexturepool_t;
167
168 static gltexturepool_t *gltexturepoolchain = NULL;
169
170 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
171 static int resizebuffersize = 0;
172 static const unsigned char *texturebuffer;
173
174 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
175 {
176         switch(textype)
177         {
178         case TEXTYPE_DXT1:
179                 return &textype_dxt1;
180         case TEXTYPE_DXT1A:
181                 return &textype_dxt1a;
182         case TEXTYPE_DXT3:
183                 return &textype_dxt3;
184         case TEXTYPE_DXT5:
185                 return &textype_dxt5;
186         case TEXTYPE_PALETTE:
187                 return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
188         case TEXTYPE_RGBA:
189                 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
190                         return (flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress;
191                 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba;
192         case TEXTYPE_BGRA:
193                 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
194                         return (flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress;
195                 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra;
196         case TEXTYPE_ALPHA:
197                 return &textype_alpha;
198         case TEXTYPE_SHADOWMAP:
199                 return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
200         case TEXTYPE_COLORBUFFER:
201                 return &textype_colorbuffer;
202         default:
203                 Host_Error("R_GetTexTypeInfo: unknown texture format");
204                 break;
205         }
206         return NULL;
207 }
208
209 // dynamic texture code [11/22/2007 Black]
210 void R_MarkDirtyTexture(rtexture_t *rt) {
211         gltexture_t *glt = (gltexture_t*) rt;
212         if( !glt ) {
213                 return;
214         }
215
216         // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
217         if (glt->flags & GLTEXF_DYNAMIC)
218         {
219                 // mark it as dirty, so R_RealGetTexture gets called
220                 glt->dirty = true;
221         }
222 }
223
224 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
225         gltexture_t *glt = (gltexture_t*) rt;
226         if( !glt ) {
227                 return;
228         }
229
230         glt->flags |= GLTEXF_DYNAMIC;
231         glt->updatecallback = updatecallback;
232         glt->updatacallback_data = data;
233 }
234
235 static void R_UpdateDynamicTexture(gltexture_t *glt) {
236         glt->dirty = false;
237         if( glt->updatecallback ) {
238                 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
239         }
240 }
241
242 void R_PurgeTexture(rtexture_t *rt)
243 {
244         if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
245                 R_FreeTexture(rt);
246         }
247 }
248
249 void R_FreeTexture(rtexture_t *rt)
250 {
251         gltexture_t *glt, **gltpointer;
252
253         glt = (gltexture_t *)rt;
254         if (glt == NULL)
255                 Host_Error("R_FreeTexture: texture == NULL");
256
257         for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
258         if (*gltpointer == glt)
259                 *gltpointer = glt->chain;
260         else
261                 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
262
263         if (glt->texnum)
264         {
265                 CHECKGLERROR
266                 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
267         }
268
269         if (glt->inputtexels)
270                 Mem_Free(glt->inputtexels);
271         Mem_ExpandableArray_FreeRecord(&texturearray, glt);
272 }
273
274 rtexturepool_t *R_AllocTexturePool(void)
275 {
276         gltexturepool_t *pool;
277         if (texturemempool == NULL)
278                 return NULL;
279         pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
280         if (pool == NULL)
281                 return NULL;
282         pool->next = gltexturepoolchain;
283         gltexturepoolchain = pool;
284         pool->sentinel = TEXTUREPOOL_SENTINEL;
285         return (rtexturepool_t *)pool;
286 }
287
288 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
289 {
290         gltexturepool_t *pool, **poolpointer;
291         if (rtexturepool == NULL)
292                 return;
293         if (*rtexturepool == NULL)
294                 return;
295         pool = (gltexturepool_t *)(*rtexturepool);
296         *rtexturepool = NULL;
297         if (pool->sentinel != TEXTUREPOOL_SENTINEL)
298                 Host_Error("R_FreeTexturePool: pool already freed");
299         for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
300         if (*poolpointer == pool)
301                 *poolpointer = pool->next;
302         else
303                 Host_Error("R_FreeTexturePool: pool not linked");
304         while (pool->gltchain)
305                 R_FreeTexture((rtexture_t *)pool->gltchain);
306         Mem_Free(pool);
307 }
308
309
310 typedef struct glmode_s
311 {
312         char *name;
313         int minification, magnification;
314 }
315 glmode_t;
316
317 static glmode_t modes[6] =
318 {
319         {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
320         {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
321         {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
322         {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
323         {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
324         {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
325 };
326
327 static void GL_TextureMode_f (void)
328 {
329         int i;
330         GLint oldbindtexnum;
331         gltexture_t *glt;
332         gltexturepool_t *pool;
333
334         if (Cmd_Argc() == 1)
335         {
336                 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
337                 for (i = 0;i < 6;i++)
338                 {
339                         if (gl_filter_min == modes[i].minification)
340                         {
341                                 Con_Printf("%s\n", modes[i].name);
342                                 return;
343                         }
344                 }
345                 Con_Print("current filter is unknown???\n");
346                 return;
347         }
348
349         for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
350                 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
351                         break;
352         if (i == 6)
353         {
354                 Con_Print("bad filter name\n");
355                 return;
356         }
357
358         gl_filter_min = modes[i].minification;
359         gl_filter_mag = modes[i].magnification;
360         gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
361
362         // change all the existing mipmap texture objects
363         // FIXME: force renderer(/client/something?) restart instead?
364         CHECKGLERROR
365         GL_ActiveTexture(0);
366         for (pool = gltexturepoolchain;pool;pool = pool->next)
367         {
368                 for (glt = pool->gltchain;glt;glt = glt->chain)
369                 {
370                         // only update already uploaded images
371                         if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
372                         {
373                                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
374                                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
375                                 if (glt->flags & TEXF_MIPMAP)
376                                 {
377                                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
378                                 }
379                                 else
380                                 {
381                                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
382                                 }
383                                 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
384                                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
385                         }
386                 }
387         }
388 }
389
390 static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, int inwidth, int inheight, int indepth, int *outwidth, int *outheight, int *outdepth)
391 {
392         int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1;
393
394         switch (texturetype)
395         {
396         default:
397         case GLTEXTURETYPE_2D:
398                 maxsize = vid.maxtexturesize_2d;
399                 if (flags & TEXF_PICMIP)
400                 {
401                         maxsize = bound(1, gl_max_size.integer, maxsize);
402                         picmip = miplevel;
403                 }
404                 break;
405         case GLTEXTURETYPE_3D:
406                 maxsize = vid.maxtexturesize_3d;
407                 break;
408         case GLTEXTURETYPE_CUBEMAP:
409                 maxsize = vid.maxtexturesize_cubemap;
410                 break;
411         }
412
413         if (outwidth)
414         {
415                 if (vid.support.arb_texture_non_power_of_two)
416                         width2 = min(inwidth >> picmip, maxsize);
417                 else
418                 {
419                         for (width2 = 1;width2 < inwidth;width2 <<= 1);
420                         for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
421                 }
422                 *outwidth = max(1, width2);
423         }
424         if (outheight)
425         {
426                 if (vid.support.arb_texture_non_power_of_two)
427                         height2 = min(inheight >> picmip, maxsize);
428                 else
429                 {
430                         for (height2 = 1;height2 < inheight;height2 <<= 1);
431                         for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
432                 }
433                 *outheight = max(1, height2);
434         }
435         if (outdepth)
436         {
437                 if (vid.support.arb_texture_non_power_of_two)
438                         depth2 = min(indepth >> picmip, maxsize);
439                 else
440                 {
441                         for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
442                         for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
443                 }
444                 *outdepth = max(1, depth2);
445         }
446 }
447
448
449 static int R_CalcTexelDataSize (gltexture_t *glt)
450 {
451         int width2, height2, depth2, size;
452
453         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2);
454
455         size = width2 * height2 * depth2;
456
457         if (glt->flags & TEXF_MIPMAP)
458         {
459                 while (width2 > 1 || height2 > 1 || depth2 > 1)
460                 {
461                         if (width2 > 1)
462                                 width2 >>= 1;
463                         if (height2 > 1)
464                                 height2 >>= 1;
465                         if (depth2 > 1)
466                                 depth2 >>= 1;
467                         size += width2 * height2 * depth2;
468                 }
469         }
470
471         return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
472 }
473
474 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
475 {
476         int glsize;
477         int isloaded;
478         int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
479         int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
480         gltexture_t *glt;
481         gltexturepool_t *pool;
482         if (printeach)
483                 Con_Print("glsize input loaded mip alpha name\n");
484         for (pool = gltexturepoolchain;pool;pool = pool->next)
485         {
486                 pooltotal = 0;
487                 pooltotalt = 0;
488                 pooltotalp = 0;
489                 poolloaded = 0;
490                 poolloadedt = 0;
491                 poolloadedp = 0;
492                 for (glt = pool->gltchain;glt;glt = glt->chain)
493                 {
494                         glsize = R_CalcTexelDataSize(glt);
495                         isloaded = glt->texnum != 0;
496                         pooltotal++;
497                         pooltotalt += glsize;
498                         pooltotalp += glt->inputdatasize;
499                         if (isloaded)
500                         {
501                                 poolloaded++;
502                                 poolloadedt += glsize;
503                                 poolloadedp += glt->inputdatasize;
504                         }
505                         if (printeach)
506                                 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);
507                 }
508                 if (printpool)
509                         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);
510                 sumtotal += pooltotal;
511                 sumtotalt += pooltotalt;
512                 sumtotalp += pooltotalp;
513                 sumloaded += poolloaded;
514                 sumloadedt += poolloadedt;
515                 sumloadedp += poolloadedp;
516         }
517         if (printtotal)
518                 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);
519 }
520
521 static void R_TextureStats_f(void)
522 {
523         R_TextureStats_Print(true, true, true);
524 }
525
526 static void r_textures_start(void)
527 {
528         // LordHavoc: allow any alignment
529         CHECKGLERROR
530         qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
531         qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
532
533         texturemempool = Mem_AllocPool("texture management", 0, NULL);
534         Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
535
536         // Disable JPEG screenshots if the DLL isn't loaded
537         if (! JPEG_OpenLibrary ())
538                 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
539         if (! PNG_OpenLibrary ())
540                 Cvar_SetValueQuick (&scr_screenshot_png, 0);
541 }
542
543 static void r_textures_shutdown(void)
544 {
545         rtexturepool_t *temp;
546
547         JPEG_CloseLibrary ();
548
549         while(gltexturepoolchain)
550         {
551                 temp = (rtexturepool_t *) gltexturepoolchain;
552                 R_FreeTexturePool(&temp);
553         }
554
555         resizebuffersize = 0;
556         resizebuffer = NULL;
557         colorconvertbuffer = NULL;
558         texturebuffer = NULL;
559         Mem_ExpandableArray_FreeArray(&texturearray);
560         Mem_FreePool(&texturemempool);
561 }
562
563 static void r_textures_newmap(void)
564 {
565 }
566
567 void R_Textures_Init (void)
568 {
569         Cmd_AddCommand("gl_texturemode", &GL_TextureMode_f, "set texture filtering mode (GL_NEAREST, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, etc); an additional argument 'force' forces the texture mode even in cases where it may not be appropriate");
570         Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
571         Cvar_RegisterVariable (&gl_max_size);
572         Cvar_RegisterVariable (&gl_picmip);
573         Cvar_RegisterVariable (&gl_picmip_world);
574         Cvar_RegisterVariable (&r_picmipworld);
575         Cvar_RegisterVariable (&gl_picmip_sprites);
576         Cvar_RegisterVariable (&r_picmipsprites);
577         Cvar_RegisterVariable (&gl_picmip_other);
578         Cvar_RegisterVariable (&gl_max_lightmapsize);
579         Cvar_RegisterVariable (&r_lerpimages);
580         Cvar_RegisterVariable (&gl_texture_anisotropy);
581         Cvar_RegisterVariable (&gl_texturecompression);
582         Cvar_RegisterVariable (&gl_texturecompression_color);
583         Cvar_RegisterVariable (&gl_texturecompression_normal);
584         Cvar_RegisterVariable (&gl_texturecompression_gloss);
585         Cvar_RegisterVariable (&gl_texturecompression_glow);
586         Cvar_RegisterVariable (&gl_texturecompression_2d);
587         Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
588         Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
589         Cvar_RegisterVariable (&gl_texturecompression_sky);
590         Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
591         Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
592         Cvar_RegisterVariable (&gl_nopartialtextureupdates);
593         Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
594
595         R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, NULL, NULL);
596 }
597
598 void R_Textures_Frame (void)
599 {
600         static int old_aniso = 0;
601
602         // could do procedural texture animation here, if we keep track of which
603         // textures were accessed this frame...
604
605         // free the resize buffers
606         resizebuffersize = 0;
607         if (resizebuffer)
608         {
609                 Mem_Free(resizebuffer);
610                 resizebuffer = NULL;
611         }
612         if (colorconvertbuffer)
613         {
614                 Mem_Free(colorconvertbuffer);
615                 colorconvertbuffer = NULL;
616         }
617
618         if (old_aniso != gl_texture_anisotropy.integer)
619         {
620                 gltexture_t *glt;
621                 gltexturepool_t *pool;
622                 GLint oldbindtexnum;
623
624                 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
625
626                 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
627
628                 CHECKGLERROR
629                 GL_ActiveTexture(0);
630                 for (pool = gltexturepoolchain;pool;pool = pool->next)
631                 {
632                         for (glt = pool->gltchain;glt;glt = glt->chain)
633                         {
634                                 // only update already uploaded images
635                                 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
636                                 {
637                                         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
638
639                                         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
640                                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
641
642                                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
643                                 }
644                         }
645                 }
646         }
647 }
648
649 void R_MakeResizeBufferBigger(int size)
650 {
651         if (resizebuffersize < size)
652         {
653                 resizebuffersize = size;
654                 if (resizebuffer)
655                         Mem_Free(resizebuffer);
656                 if (colorconvertbuffer)
657                         Mem_Free(colorconvertbuffer);
658                 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
659                 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
660                 if (!resizebuffer || !colorconvertbuffer)
661                         Host_Error("R_Upload: out of memory");
662         }
663 }
664
665 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
666 {
667         int textureenum = gltexturetypeenums[texturetype];
668         int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
669
670         CHECKGLERROR
671
672         if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
673         {
674                 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
675                 if (gl_texture_anisotropy.integer != aniso)
676                         Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
677                 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
678         }
679         qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
680         qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
681         if (gltexturetypedimensions[texturetype] >= 3)
682         {
683                 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
684         }
685
686         CHECKGLERROR
687         if (!gl_filter_force && flags & TEXF_FORCENEAREST)
688         {
689                 if (flags & TEXF_MIPMAP)
690                 {
691                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
692                 }
693                 else
694                 {
695                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
696                 }
697                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
698         }
699         else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
700         {
701                 if (flags & TEXF_MIPMAP)
702                 {
703                         if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
704                         {
705                                 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
706                         }
707                         else
708                         {
709                                 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
710                         }
711                 }
712                 else
713                 {
714                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
715                 }
716                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
717         }
718         else
719         {
720                 if (flags & TEXF_MIPMAP)
721                 {
722                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
723                 }
724                 else
725                 {
726                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
727                 }
728                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
729         }
730
731         if (textype == TEXTYPE_SHADOWMAP)
732         {
733                 if (vid.support.arb_shadow)
734                 {
735                         if (flags & TEXF_COMPARE)
736                         {
737                                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
738                         }
739                         else
740                         {
741                                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
742                         }
743                         qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
744                 }
745                 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
746         }
747
748         CHECKGLERROR
749 }
750
751 static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
752 {
753         int i, mip, width, height, depth;
754         GLint oldbindtexnum;
755         const unsigned char *prevbuffer;
756         prevbuffer = data;
757
758         CHECKGLERROR
759
760         // we need to restore the texture binding after finishing the upload
761         GL_ActiveTexture(0);
762         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
763         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
764
765         // these are rounded up versions of the size to do better resampling
766         if (vid.support.arb_texture_non_power_of_two || glt->texturetype == GLTEXTURETYPE_RECTANGLE)
767         {
768                 width = glt->inputwidth;
769                 height = glt->inputheight;
770                 depth = glt->inputdepth;
771         }
772         else
773         {
774                 for (width  = 1;width  < glt->inputwidth ;width  <<= 1);
775                 for (height = 1;height < glt->inputheight;height <<= 1);
776                 for (depth  = 1;depth  < glt->inputdepth ;depth  <<= 1);
777         }
778
779         R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
780         R_MakeResizeBufferBigger(fragwidth * fragheight * fragdepth * glt->sides * glt->bytesperpixel);
781
782         if (prevbuffer == NULL)
783         {
784                 memset(resizebuffer, 0, fragwidth * fragheight * fragdepth * glt->bytesperpixel);
785                 prevbuffer = resizebuffer;
786         }
787         else if (glt->textype->textype == TEXTYPE_PALETTE)
788         {
789                 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
790                 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, fragwidth * fragheight * fragdepth * glt->sides, glt->palette);
791                 prevbuffer = colorconvertbuffer;
792         }
793
794         // upload the image - preferring to do only complete uploads (drivers do not really like partial updates)
795
796         if ((glt->flags & (TEXF_MIPMAP | TEXF_PICMIP)) == 0 && glt->inputwidth == glt->tilewidth && glt->inputheight == glt->tileheight && glt->inputdepth == glt->tiledepth && (fragx != 0 || fragy != 0 || fragwidth != glt->tilewidth || fragheight != glt->tileheight))
797         {
798                 // update a portion of the image
799                 switch(glt->texturetype)
800                 {
801                 case GLTEXTURETYPE_2D:
802                         qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
803                         break;
804                 case GLTEXTURETYPE_3D:
805                         qglTexSubImage3D(GL_TEXTURE_3D, 0, fragx, fragy, fragz, fragwidth, fragheight, fragdepth, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
806                         break;
807                 default:
808                         Host_Error("R_Upload: partial update of type other than 2D");
809                         break;
810                 }
811         }
812         else
813         {
814                 if (fragx || fragy || fragz || glt->inputwidth != fragwidth || glt->inputheight != fragheight || glt->inputdepth != fragdepth)
815                         Sys_Error("R_Upload \"%s\": partial update not allowed on initial upload or in combination with PICMIP or MIPMAP\n", glt->identifier);
816
817                 // cubemaps contain multiple images and thus get processed a bit differently
818                 if (glt->texturetype != GLTEXTURETYPE_CUBEMAP)
819                 {
820                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
821                         {
822                                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
823                                 prevbuffer = resizebuffer;
824                         }
825                         // picmip/max_size
826                         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
827                         {
828                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
829                                 prevbuffer = resizebuffer;
830                         }
831                 }
832                 mip = 0;
833                 if (qglGetCompressedTexImageARB)
834                 {
835                         if (gl_texturecompression.integer >= 2)
836                                 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
837                         else
838                                 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
839                         CHECKGLERROR
840                 }
841                 switch(glt->texturetype)
842                 {
843                 case GLTEXTURETYPE_2D:
844                         qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
845                         if (glt->flags & TEXF_MIPMAP)
846                         {
847                                 while (width > 1 || height > 1 || depth > 1)
848                                 {
849                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
850                                         prevbuffer = resizebuffer;
851                                         qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
852                                 }
853                         }
854                         break;
855                 case GLTEXTURETYPE_3D:
856                         qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
857                         if (glt->flags & TEXF_MIPMAP)
858                         {
859                                 while (width > 1 || height > 1 || depth > 1)
860                                 {
861                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
862                                         prevbuffer = resizebuffer;
863                                         qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
864                                 }
865                         }
866                         break;
867                 case GLTEXTURETYPE_CUBEMAP:
868                         // convert and upload each side in turn,
869                         // from a continuous block of input texels
870                         texturebuffer = (unsigned char *)prevbuffer;
871                         for (i = 0;i < 6;i++)
872                         {
873                                 prevbuffer = texturebuffer;
874                                 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
875                                 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
876                                 {
877                                         Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
878                                         prevbuffer = resizebuffer;
879                                 }
880                                 // picmip/max_size
881                                 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
882                                 {
883                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
884                                         prevbuffer = resizebuffer;
885                                 }
886                                 mip = 0;
887                                 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
888                                 if (glt->flags & TEXF_MIPMAP)
889                                 {
890                                         while (width > 1 || height > 1 || depth > 1)
891                                         {
892                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
893                                                 prevbuffer = resizebuffer;
894                                                 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
895                                         }
896                                 }
897                         }
898                         break;
899                 case GLTEXTURETYPE_RECTANGLE:
900                         qglTexImage2D(GL_TEXTURE_RECTANGLE_ARB, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, NULL);CHECKGLERROR
901                         break;
902                 }
903                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
904         }
905         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
906 }
907
908 static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int depth, int sides, int flags, int miplevel, textype_t textype, int texturetype, const unsigned char *data, const unsigned int *palette)
909 {
910         int i, size;
911         gltexture_t *glt;
912         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
913         textypeinfo_t *texinfo, *texinfo2;
914
915         if (cls.state == ca_dedicated)
916                 return NULL;
917
918         if (texturetype == GLTEXTURETYPE_RECTANGLE && !vid.support.arb_texture_rectangle)
919         {
920                 Con_Printf ("R_LoadTexture: rectangle texture not supported by driver\n");
921                 return NULL;
922         }
923         if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
924         {
925                 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
926                 return NULL;
927         }
928         if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
929         {
930                 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
931                 return NULL;
932         }
933
934         texinfo = R_GetTexTypeInfo(textype, flags);
935         size = width * height * depth * sides * texinfo->inputbytesperpixel;
936         if (size < 1)
937         {
938                 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
939                 return NULL;
940         }
941
942         // clear the alpha flag if the texture has no transparent pixels
943         switch(textype)
944         {
945         case TEXTYPE_PALETTE:
946                 if (flags & TEXF_ALPHA)
947                 {
948                         flags &= ~TEXF_ALPHA;
949                         if (data)
950                         {
951                                 for (i = 0;i < size;i++)
952                                 {
953                                         if (((unsigned char *)&palette[data[i]])[3] < 255)
954                                         {
955                                                 flags |= TEXF_ALPHA;
956                                                 break;
957                                         }
958                                 }
959                         }
960                 }
961                 break;
962         case TEXTYPE_RGBA:
963         case TEXTYPE_BGRA:
964                 if (flags & TEXF_ALPHA)
965                 {
966                         flags &= ~TEXF_ALPHA;
967                         if (data)
968                         {
969                                 for (i = 3;i < size;i += 4)
970                                 {
971                                         if (data[i] < 255)
972                                         {
973                                                 flags |= TEXF_ALPHA;
974                                                 break;
975                                         }
976                                 }
977                         }
978                 }
979                 break;
980         case TEXTYPE_SHADOWMAP:
981                 break;
982         case TEXTYPE_DXT1:
983                 break;
984         case TEXTYPE_DXT1A:
985         case TEXTYPE_DXT3:
986         case TEXTYPE_DXT5:
987                 flags |= TEXF_ALPHA;
988                 break;
989         case TEXTYPE_ALPHA:
990                 flags |= TEXF_ALPHA;
991                 break;
992         case TEXTYPE_COLORBUFFER:
993                 flags |= TEXF_ALPHA;
994                 break;
995         default:
996                 Host_Error("R_LoadTexture: unknown texture type");
997         }
998
999         texinfo2 = R_GetTexTypeInfo(textype, flags);
1000         if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1001                 texinfo = texinfo2;
1002         else
1003                 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1004
1005         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1006         if (identifier)
1007                 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1008         glt->pool = pool;
1009         glt->chain = pool->gltchain;
1010         pool->gltchain = glt;
1011         glt->inputwidth = width;
1012         glt->inputheight = height;
1013         glt->inputdepth = depth;
1014         glt->flags = flags;
1015         glt->miplevel = (miplevel < 0) ? R_PicmipForFlags(flags) : miplevel; // note: if miplevel is -1, we know the texture is in original size and we can picmip it normally
1016         glt->textype = texinfo;
1017         glt->texturetype = texturetype;
1018         glt->inputdatasize = size;
1019         glt->palette = palette;
1020         glt->glinternalformat = texinfo->glinternalformat;
1021         glt->glformat = texinfo->glformat;
1022         glt->gltype = texinfo->gltype;
1023         glt->bytesperpixel = texinfo->internalbytesperpixel;
1024         glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1025         glt->texnum = 0;
1026         glt->dirty = false;
1027         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1028         // init the dynamic texture attributes, too [11/22/2007 Black]
1029         glt->updatecallback = NULL;
1030         glt->updatacallback_data = NULL;
1031
1032         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth);
1033
1034         // upload the texture
1035         // data may be NULL (blank texture for dynamic rendering)
1036         CHECKGLERROR
1037         qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1038         R_Upload(glt, data, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
1039         if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1040                 glt->bufferpixels = Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1041
1042         // texture converting and uploading can take a while, so make sure we're sending keepalives
1043         CL_KeepaliveMessage(false);
1044
1045         return (rtexture_t *)glt;
1046 }
1047
1048 rtexture_t *R_LoadTexture2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette)
1049 {
1050         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1051 }
1052
1053 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, int miplevel, const unsigned int *palette)
1054 {
1055         return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1056 }
1057
1058 rtexture_t *R_LoadTextureCubeMap(rtexturepool_t *rtexturepool, const char *identifier, int width, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette)
1059 {
1060         return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1061 }
1062
1063 rtexture_t *R_LoadTextureRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette)
1064 {
1065         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_RECTANGLE, data, palette);
1066 }
1067
1068 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1069 {
1070         int flags = TEXF_CLAMP;
1071         if (filter)
1072                 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1073         else
1074                 flags |= TEXF_FORCENEAREST;
1075         if (precision <= 16)
1076                 flags |= TEXF_LOWPRECISION;
1077         return flags;
1078 }
1079
1080 rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1081 {
1082         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
1083 }
1084
1085 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1086 {
1087         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1088 }
1089
1090 rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter)
1091 {
1092     return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
1093 }
1094
1095 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1096 {
1097         gltexture_t *glt = (gltexture_t *)rt;
1098         unsigned char *dds;
1099         int oldbindtexnum;
1100         int bytesperpixel = 0;
1101         int bytesperblock = 0;
1102         int dds_flags;
1103         int dds_format_flags;
1104         int dds_caps1;
1105         int dds_caps2;
1106         int ret;
1107         int mip;
1108         int mipmaps;
1109         int mipinfo[16][4];
1110         int ddssize = 128;
1111         GLint internalformat;
1112         const char *ddsfourcc;
1113         if (!rt)
1114                 return -1; // NULL pointer
1115         if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1116                 return -2; // broken driver - crashes on reading internal format
1117         if (!qglGetTexLevelParameteriv)
1118                 return -2;
1119         GL_ActiveTexture(0);
1120         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1121         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1122         qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1123         switch(internalformat)
1124         {
1125         default: ddsfourcc = NULL;bytesperpixel = 4;break;
1126         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1127         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1128         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1129         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1130         }
1131         if (!bytesperblock && skipuncompressed)
1132                 return -3; // skipped
1133         memset(mipinfo, 0, sizeof(mipinfo));
1134         mipinfo[0][0] = glt->tilewidth;
1135         mipinfo[0][1] = glt->tileheight;
1136         mipmaps = 1;
1137         if (glt->flags & TEXF_MIPMAP)
1138         {
1139                 for (mip = 1;mip < 16;mip++)
1140                 {
1141                         mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1142                         mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1143                         if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1144                         {
1145                                 mip++;
1146                                 break;
1147                         }
1148                 }
1149                 mipmaps = mip;
1150         }
1151         for (mip = 0;mip < mipmaps;mip++)
1152         {
1153                 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1154                 mipinfo[mip][3] = ddssize;
1155                 ddssize += mipinfo[mip][2];
1156         }
1157         dds = Mem_Alloc(tempmempool, ddssize);
1158         if (!dds)
1159                 return -4;
1160         dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1161         dds_caps2 = 0;
1162         if (bytesperblock)
1163         {
1164                 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1165                 dds_format_flags = 0x4; // DDPF_FOURCC
1166         }
1167         else
1168         {
1169                 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1170                 dds_format_flags = 0x40; // DDPF_RGB
1171         }
1172         if (mipmaps)
1173         {
1174                 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1175                 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1176         }
1177         if(hasalpha)
1178                 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1179         memcpy(dds, "DDS ", 4);
1180         StoreLittleLong(dds+4, ddssize);
1181         StoreLittleLong(dds+8, dds_flags);
1182         StoreLittleLong(dds+12, mipinfo[0][1]); // height
1183         StoreLittleLong(dds+16, mipinfo[0][0]); // width
1184         StoreLittleLong(dds+24, 1); // depth
1185         StoreLittleLong(dds+28, mipmaps); // mipmaps
1186         StoreLittleLong(dds+76, 32); // format size
1187         StoreLittleLong(dds+80, dds_format_flags);
1188         StoreLittleLong(dds+108, dds_caps1);
1189         StoreLittleLong(dds+112, dds_caps2);
1190         if (bytesperblock)
1191         {
1192                 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1193                 memcpy(dds+84, ddsfourcc, 4);
1194                 for (mip = 0;mip < mipmaps;mip++)
1195                 {
1196                         qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1197                 }
1198         }
1199         else
1200         {
1201                 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1202                 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1203                 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1204                 for (mip = 0;mip < mipmaps;mip++)
1205                 {
1206                         qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1207                 }
1208         }
1209         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1210         ret = FS_WriteFile(filename, dds, ddssize);
1211         Mem_Free(dds);
1212         return ret ? ddssize : -5;
1213 }
1214
1215 rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint
1216 {
1217         int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1218         //int dds_flags;
1219         textype_t textype;
1220         int bytesperblock, bytesperpixel;
1221         int mipcomplete;
1222         gltexture_t *glt;
1223         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1224         textypeinfo_t *texinfo;
1225         int mip, mipwidth, mipheight, mipsize;
1226         unsigned int c;
1227         GLint oldbindtexnum;
1228         const unsigned char *mippixels, *ddspixels;
1229         unsigned char *dds;
1230         fs_offset_t ddsfilesize;
1231         unsigned int ddssize;
1232
1233         if (cls.state == ca_dedicated)
1234                 return NULL;
1235
1236         dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1237         ddssize = ddsfilesize;
1238
1239         if (!dds)
1240         {
1241                 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1242                 return NULL; // not found
1243         }
1244
1245         if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1246         {
1247                 Mem_Free(dds);
1248                 Con_Printf("^1%s: not a DDS image\n", filename);
1249                 return NULL;
1250         }
1251
1252         //dds_flags = BuffLittleLong(dds+8);
1253         dds_format_flags = BuffLittleLong(dds+80);
1254         dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1255         dds_width = BuffLittleLong(dds+16);
1256         dds_height = BuffLittleLong(dds+12);
1257         ddspixels = dds + 128;
1258
1259         if(r_texture_dds_load_alphamode.integer == 0)
1260                 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1261                         flags &= ~TEXF_ALPHA;
1262
1263         //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1264         if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1265         {
1266                 // very sloppy BGRA 32bit identification
1267                 textype = TEXTYPE_BGRA;
1268                 bytesperblock = 0;
1269                 bytesperpixel = 4;
1270                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1271                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1272                 {
1273                         Mem_Free(dds);
1274                         Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1275                         return NULL;
1276                 }
1277                 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1278                 {
1279                         // check alpha
1280                         for (i = 3;i < size;i += 4)
1281                                 if (ddspixels[i] < 255)
1282                                         break;
1283                         if (i >= size)
1284                                 flags &= ~TEXF_ALPHA;
1285                 }
1286         }
1287         else if (!memcmp(dds+84, "DXT1", 4))
1288         {
1289                 if(!vid.support.ext_texture_compression_s3tc)
1290                 {
1291                         Mem_Free(dds);
1292                         return NULL;
1293                 }
1294                 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1295                 // LordHavoc: it is my belief that this does not infringe on the
1296                 // patent because it is not decoding pixels...
1297                 textype = TEXTYPE_DXT1;
1298                 bytesperblock = 8;
1299                 bytesperpixel = 0;
1300                 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1301                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1302                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1303                 {
1304                         Mem_Free(dds);
1305                         Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1306                         return NULL;
1307                 }
1308                 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1309                 {
1310                         if(r_texture_dds_load_alphamode.integer == 1)
1311                         {
1312                                 // check alpha
1313                                 for (i = 0;i < size;i += bytesperblock)
1314                                         if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1315                                         {
1316                                                 // NOTE: this assumes sizeof(unsigned int) == 4
1317                                                 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1318                                                 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1319                                                 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1320                                                         break;
1321                                         }
1322                                 if (i < size)
1323                                         textype = TEXTYPE_DXT1A;
1324                                 else
1325                                         flags &= ~TEXF_ALPHA;
1326                         }
1327                         else
1328                         {
1329                                 flags &= ~TEXF_ALPHA;
1330                         }
1331                 }
1332         }
1333         else if (!memcmp(dds+84, "DXT3", 4))
1334         {
1335                 if(!vid.support.ext_texture_compression_s3tc)
1336                 {
1337                         Mem_Free(dds);
1338                         return NULL;
1339                 }
1340                 textype = TEXTYPE_DXT3;
1341                 bytesperblock = 16;
1342                 bytesperpixel = 0;
1343                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1344                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1345                 {
1346                         Mem_Free(dds);
1347                         Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1348                         return NULL;
1349                 }
1350                 // we currently always assume alpha
1351         }
1352         else if (!memcmp(dds+84, "DXT5", 4))
1353         {
1354                 if(!vid.support.ext_texture_compression_s3tc)
1355                 {
1356                         Mem_Free(dds);
1357                         return NULL;
1358                 }
1359                 textype = TEXTYPE_DXT5;
1360                 bytesperblock = 16;
1361                 bytesperpixel = 0;
1362                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1363                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1364                 {
1365                         Mem_Free(dds);
1366                         Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1367                         return NULL;
1368                 }
1369                 // we currently always assume alpha
1370         }
1371         else
1372         {
1373                 Mem_Free(dds);
1374                 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1375                 return NULL;
1376         }
1377
1378         // return whether this texture is transparent
1379         if (hasalphaflag)
1380                 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1381
1382         // calculate average color if requested
1383         if (avgcolor)
1384         {
1385                 float f;
1386                 Vector4Clear(avgcolor);
1387                 if (bytesperblock)
1388                 {
1389                         for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
1390                         {
1391                                 c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
1392                                 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1393                                 avgcolor[1] += ((c >>  5) & 0x3F) + ((c >> 21) & 0x3F);
1394                                 avgcolor[2] += ((c      ) & 0x1F) + ((c >> 16) & 0x1F);
1395                         }
1396                         f = (float)bytesperblock / size;
1397                         avgcolor[0] *= (0.5f / 31.0f) * f;
1398                         avgcolor[1] *= (0.5f / 63.0f) * f;
1399                         avgcolor[2] *= (0.5f / 31.0f) * f;
1400                         avgcolor[3] = 1; // too hard to calculate
1401                 }
1402                 else
1403                 {
1404                         for (i = 0;i < size;i += 4)
1405                         {
1406                                 avgcolor[0] += ddspixels[i+2];
1407                                 avgcolor[1] += ddspixels[i+1];
1408                                 avgcolor[2] += ddspixels[i];
1409                                 avgcolor[3] += ddspixels[i+3];
1410                         }
1411                         f = (1.0f / 255.0f) * bytesperpixel / size;
1412                         avgcolor[0] *= f;
1413                         avgcolor[1] *= f;
1414                         avgcolor[2] *= f;
1415                         avgcolor[3] *= f;
1416                 }
1417         }
1418
1419         // this is where we apply gl_picmip
1420         mippixels = ddspixels;
1421         mipwidth = dds_width;
1422         mipheight = dds_height;
1423         while(miplevel >= 1 && dds_miplevels >= 1)
1424         {
1425                 if (mipwidth <= 1 && mipheight <= 1)
1426                         break;
1427                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1428                 mippixels += mipsize; // just skip
1429                 --dds_miplevels;
1430                 --miplevel;
1431                 if (mipwidth > 1)
1432                         mipwidth >>= 1;
1433                 if (mipheight > 1)
1434                         mipheight >>= 1;
1435         }
1436
1437         // when not requesting mipmaps, do not load them
1438         if(!(flags & TEXF_MIPMAP))
1439                 dds_miplevels = 0;
1440
1441         if (dds_miplevels >= 1)
1442                 flags |= TEXF_MIPMAP;
1443         else
1444                 flags &= ~TEXF_MIPMAP;
1445
1446         // if S3TC is not supported, there's very little we can do about it
1447         if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
1448         {
1449                 Mem_Free(dds);
1450                 Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
1451                 return NULL;
1452         }
1453
1454         texinfo = R_GetTexTypeInfo(textype, flags);
1455
1456         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1457         strlcpy (glt->identifier, filename, sizeof(glt->identifier));
1458         glt->pool = pool;
1459         glt->chain = pool->gltchain;
1460         pool->gltchain = glt;
1461         glt->inputwidth = mipwidth;
1462         glt->inputheight = mipheight;
1463         glt->inputdepth = 1;
1464         glt->flags = flags;
1465         glt->textype = texinfo;
1466         glt->texturetype = GLTEXTURETYPE_2D;
1467         glt->inputdatasize = ddssize;
1468         glt->glinternalformat = texinfo->glinternalformat;
1469         glt->glformat = texinfo->glformat;
1470         glt->gltype = texinfo->gltype;
1471         glt->bytesperpixel = texinfo->internalbytesperpixel;
1472         glt->sides = 1;
1473         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1474         glt->tilewidth = mipwidth;
1475         glt->tileheight = mipheight;
1476         glt->tiledepth = 1;
1477
1478         // texture uploading can take a while, so make sure we're sending keepalives
1479         CL_KeepaliveMessage(false);
1480
1481         // upload the texture
1482         // we need to restore the texture binding after finishing the upload
1483         CHECKGLERROR
1484         GL_ActiveTexture(0);
1485         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1486         qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1487         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1488         mipcomplete = false;
1489
1490         for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
1491         {
1492                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1493                 if (mippixels + mipsize > dds + ddssize)
1494                         break;
1495                 if (bytesperblock)
1496                 {
1497                         qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
1498                 }
1499                 else
1500                 {
1501                         qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
1502                 }
1503                 mippixels += mipsize;
1504                 if (mipwidth <= 1 && mipheight <= 1)
1505                 {
1506                         mipcomplete = true;
1507                         break;
1508                 }
1509                 if (mipwidth > 1)
1510                         mipwidth >>= 1;
1511                 if (mipheight > 1)
1512                         mipheight >>= 1;
1513         }
1514         if (dds_miplevels >= 1 && !mipcomplete)
1515         {
1516                 // need to set GL_TEXTURE_MAX_LEVEL
1517                 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
1518         }
1519         GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1520         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1521
1522         Mem_Free(dds);
1523         return (rtexture_t *)glt;
1524 }
1525
1526 int R_TextureWidth(rtexture_t *rt)
1527 {
1528         return rt ? ((gltexture_t *)rt)->inputwidth : 0;
1529 }
1530
1531 int R_TextureHeight(rtexture_t *rt)
1532 {
1533         return rt ? ((gltexture_t *)rt)->inputheight : 0;
1534 }
1535
1536 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
1537 {
1538         gltexture_t *glt = (gltexture_t *)rt;
1539         if (data == NULL)
1540                 Host_Error("R_UpdateTexture: no data supplied");
1541         if (glt == NULL)
1542                 Host_Error("R_UpdateTexture: no texture supplied");
1543         if (!glt->texnum)
1544                 Host_Error("R_UpdateTexture: texture has not been uploaded yet");
1545         // update part of the texture
1546         if (glt->bufferpixels)
1547         {
1548                 int j;
1549                 int bpp = glt->bytesperpixel;
1550                 int inputskip = width*bpp;
1551                 int outputskip = glt->tilewidth*bpp;
1552                 const unsigned char *input = data;
1553                 unsigned char *output = glt->bufferpixels;
1554                 if (x < 0)
1555                 {
1556                         width += x;
1557                         input -= x*bpp;
1558                         x = 0;
1559                 }
1560                 if (y < 0)
1561                 {
1562                         height += y;
1563                         input -= y*inputskip;
1564                         y = 0;
1565                 }
1566                 if (width > glt->tilewidth - x)
1567                         width = glt->tilewidth - x;
1568                 if (height > glt->tileheight - y)
1569                         height = glt->tileheight - y;
1570                 if (width < 1 || height < 1)
1571                         return;
1572                 glt->dirty = true;
1573                 glt->buffermodified = true;
1574                 output += y*outputskip + x*bpp;
1575                 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
1576                         memcpy(output, input, width*bpp);
1577         }
1578         else
1579                 R_Upload(glt, data, x, y, 0, width, height, 1);
1580 }
1581
1582 int R_RealGetTexture(rtexture_t *rt)
1583 {
1584         if (rt)
1585         {
1586                 gltexture_t *glt;
1587                 glt = (gltexture_t *)rt;
1588                 if (glt->flags & GLTEXF_DYNAMIC)
1589                         R_UpdateDynamicTexture(glt);
1590                 if (glt->buffermodified && glt->bufferpixels)
1591                 {
1592                         glt->buffermodified = false;
1593                         R_Upload(glt, glt->bufferpixels, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth);
1594                 }
1595                 glt->dirty = false;
1596                 return glt->texnum;
1597         }
1598         else
1599                 return 0;
1600 }
1601
1602 void R_ClearTexture (rtexture_t *rt)
1603 {
1604         gltexture_t *glt = (gltexture_t *)rt;
1605
1606         R_Upload( glt, NULL, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth );
1607 }
1608
1609 int R_PicmipForFlags(int flags)
1610 {
1611         int miplevel = 0;
1612         if(flags & TEXF_PICMIP)
1613         {
1614                 miplevel += gl_picmip.integer;
1615                 if (flags & TEXF_ISWORLD)
1616                 {
1617                         if (r_picmipworld.integer)
1618                                 miplevel += gl_picmip_world.integer;
1619                         else
1620                                 miplevel = 0;
1621                 }
1622                 else if (flags & TEXF_ISSPRITE)
1623                 {
1624                         if (r_picmipsprites.integer)
1625                                 miplevel += gl_picmip_sprites.integer;
1626                         else
1627                                 miplevel = 0;
1628                 }
1629                 else
1630                         miplevel += gl_picmip_other.integer;
1631         }
1632         return max(0, miplevel);
1633 }