]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_textures.c
use the DDPF_ALPHAPIXELS flag for DDS reading, at least works for ATI Compressonator
[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", "0", "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.arb_texture_compression)
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.arb_texture_compression)
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                         Host_Error("R_Upload: partial update not allowed on initial upload or in combination with PICMIP or MIPMAP\n");
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                 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1290                 // LordHavoc: it is my belief that this does not infringe on the
1291                 // patent because it is not decoding pixels...
1292                 textype = TEXTYPE_DXT1;
1293                 bytesperblock = 8;
1294                 bytesperpixel = 0;
1295                 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1296                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1297                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1298                 {
1299                         Mem_Free(dds);
1300                         Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1301                         return NULL;
1302                 }
1303                 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1304                 {
1305                         if(r_texture_dds_load_alphamode.integer == 1)
1306                         {
1307                                 // check alpha
1308                                 for (i = 0;i < size;i += bytesperblock)
1309                                         if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1310                                                 break;
1311                                 if (i < size)
1312                                         textype = TEXTYPE_DXT1A;
1313                                 else
1314                                         flags &= ~TEXF_ALPHA;
1315                         }
1316                         else
1317                         {
1318                                 flags &= ~TEXF_ALPHA;
1319                         }
1320                 }
1321         }
1322         else if (!memcmp(dds+84, "DXT3", 4))
1323         {
1324                 textype = TEXTYPE_DXT3;
1325                 bytesperblock = 16;
1326                 bytesperpixel = 0;
1327                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1328                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1329                 {
1330                         Mem_Free(dds);
1331                         Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1332                         return NULL;
1333                 }
1334                 // we currently always assume alpha
1335         }
1336         else if (!memcmp(dds+84, "DXT5", 4))
1337         {
1338                 textype = TEXTYPE_DXT5;
1339                 bytesperblock = 16;
1340                 bytesperpixel = 0;
1341                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1342                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1343                 {
1344                         Mem_Free(dds);
1345                         Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1346                         return NULL;
1347                 }
1348                 // we currently always assume alpha
1349         }
1350         else
1351         {
1352                 Mem_Free(dds);
1353                 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1354                 return NULL;
1355         }
1356
1357         // return whether this texture is transparent
1358         if (hasalphaflag)
1359                 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1360
1361         // calculate average color if requested
1362         if (avgcolor)
1363         {
1364                 float f;
1365                 Vector4Clear(avgcolor);
1366                 if (bytesperblock)
1367                 {
1368                         for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
1369                         {
1370                                 c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
1371                                 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1372                                 avgcolor[1] += ((c >>  5) & 0x3F) + ((c >> 21) & 0x3F);
1373                                 avgcolor[2] += ((c      ) & 0x1F) + ((c >> 16) & 0x1F);
1374                         }
1375                         f = (float)bytesperblock / size;
1376                         avgcolor[0] *= (0.5f / 31.0f) * f;
1377                         avgcolor[1] *= (0.5f / 63.0f) * f;
1378                         avgcolor[2] *= (0.5f / 31.0f) * f;
1379                         avgcolor[3] = 1; // too hard to calculate
1380                 }
1381                 else
1382                 {
1383                         for (i = 0;i < size;i += 4)
1384                         {
1385                                 avgcolor[0] += ddspixels[i+2];
1386                                 avgcolor[1] += ddspixels[i+1];
1387                                 avgcolor[2] += ddspixels[i];
1388                                 avgcolor[3] += ddspixels[i+3];
1389                         }
1390                         f = (1.0f / 255.0f) * bytesperpixel / size;
1391                         avgcolor[0] *= f;
1392                         avgcolor[1] *= f;
1393                         avgcolor[2] *= f;
1394                         avgcolor[3] *= f;
1395                 }
1396         }
1397
1398         // this is where we apply gl_picmip
1399         mippixels = ddspixels;
1400         mipwidth = dds_width;
1401         mipheight = dds_height;
1402         while(miplevel >= 1 && dds_miplevels >= 1)
1403         {
1404                 if (mipwidth <= 1 && mipheight <= 1)
1405                         break;
1406                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1407                 mippixels += mipsize; // just skip
1408                 --dds_miplevels;
1409                 --miplevel;
1410                 if (mipwidth > 1)
1411                         mipwidth >>= 1;
1412                 if (mipheight > 1)
1413                         mipheight >>= 1;
1414         }
1415
1416         // when not requesting mipmaps, do not load them
1417         if(!(flags & TEXF_MIPMAP))
1418                 dds_miplevels = 0;
1419
1420         if (dds_miplevels >= 1)
1421                 flags |= TEXF_MIPMAP;
1422         else
1423                 flags &= ~TEXF_MIPMAP;
1424
1425         // if S3TC is not supported, there's very little we can do about it
1426         if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
1427         {
1428                 Mem_Free(dds);
1429                 Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
1430                 return NULL;
1431         }
1432
1433         texinfo = R_GetTexTypeInfo(textype, flags);
1434
1435         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1436         strlcpy (glt->identifier, filename, sizeof(glt->identifier));
1437         glt->pool = pool;
1438         glt->chain = pool->gltchain;
1439         pool->gltchain = glt;
1440         glt->inputwidth = mipwidth;
1441         glt->inputheight = mipheight;
1442         glt->inputdepth = 1;
1443         glt->flags = flags;
1444         glt->textype = texinfo;
1445         glt->texturetype = GLTEXTURETYPE_2D;
1446         glt->inputdatasize = ddssize;
1447         glt->glinternalformat = texinfo->glinternalformat;
1448         glt->glformat = texinfo->glformat;
1449         glt->gltype = texinfo->gltype;
1450         glt->bytesperpixel = texinfo->internalbytesperpixel;
1451         glt->sides = 1;
1452         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1453         glt->tilewidth = mipwidth;
1454         glt->tileheight = mipheight;
1455         glt->tiledepth = 1;
1456
1457         // texture uploading can take a while, so make sure we're sending keepalives
1458         CL_KeepaliveMessage(false);
1459
1460         // upload the texture
1461         // we need to restore the texture binding after finishing the upload
1462         CHECKGLERROR
1463         GL_ActiveTexture(0);
1464         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1465         qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1466         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1467         mipcomplete = false;
1468
1469         for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
1470         {
1471                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1472                 if (mippixels + mipsize > dds + ddssize)
1473                         break;
1474                 if (bytesperblock)
1475                 {
1476                         qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
1477                 }
1478                 else
1479                 {
1480                         qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
1481                 }
1482                 mippixels += mipsize;
1483                 if (mipwidth <= 1 && mipheight <= 1)
1484                 {
1485                         mipcomplete = true;
1486                         break;
1487                 }
1488                 if (mipwidth > 1)
1489                         mipwidth >>= 1;
1490                 if (mipheight > 1)
1491                         mipheight >>= 1;
1492         }
1493         if (dds_miplevels >= 1 && !mipcomplete)
1494         {
1495                 // need to set GL_TEXTURE_MAX_LEVEL
1496                 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
1497         }
1498         GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1499         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1500
1501         Mem_Free(dds);
1502         return (rtexture_t *)glt;
1503 }
1504
1505 int R_TextureWidth(rtexture_t *rt)
1506 {
1507         return rt ? ((gltexture_t *)rt)->inputwidth : 0;
1508 }
1509
1510 int R_TextureHeight(rtexture_t *rt)
1511 {
1512         return rt ? ((gltexture_t *)rt)->inputheight : 0;
1513 }
1514
1515 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
1516 {
1517         gltexture_t *glt = (gltexture_t *)rt;
1518         if (data == NULL)
1519                 Host_Error("R_UpdateTexture: no data supplied");
1520         if (glt == NULL)
1521                 Host_Error("R_UpdateTexture: no texture supplied");
1522         if (!glt->texnum)
1523                 Host_Error("R_UpdateTexture: texture has not been uploaded yet");
1524         // update part of the texture
1525         if (glt->bufferpixels)
1526         {
1527                 int j;
1528                 int bpp = glt->bytesperpixel;
1529                 int inputskip = width*bpp;
1530                 int outputskip = glt->tilewidth*bpp;
1531                 const unsigned char *input = data;
1532                 unsigned char *output = glt->bufferpixels;
1533                 if (x < 0)
1534                 {
1535                         width += x;
1536                         input -= x*bpp;
1537                         x = 0;
1538                 }
1539                 if (y < 0)
1540                 {
1541                         height += y;
1542                         input -= y*inputskip;
1543                         y = 0;
1544                 }
1545                 if (width > glt->tilewidth - x)
1546                         width = glt->tilewidth - x;
1547                 if (height > glt->tileheight - y)
1548                         height = glt->tileheight - y;
1549                 if (width < 1 || height < 1)
1550                         return;
1551                 glt->dirty = true;
1552                 glt->buffermodified = true;
1553                 output += y*outputskip + x*bpp;
1554                 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
1555                         memcpy(output, input, width*bpp);
1556         }
1557         else
1558                 R_Upload(glt, data, x, y, 0, width, height, 1);
1559 }
1560
1561 int R_RealGetTexture(rtexture_t *rt)
1562 {
1563         if (rt)
1564         {
1565                 gltexture_t *glt;
1566                 glt = (gltexture_t *)rt;
1567                 if (glt->flags & GLTEXF_DYNAMIC)
1568                         R_UpdateDynamicTexture(glt);
1569                 if (glt->buffermodified && glt->bufferpixels)
1570                 {
1571                         glt->buffermodified = false;
1572                         R_Upload(glt, glt->bufferpixels, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth);
1573                 }
1574                 glt->dirty = false;
1575                 return glt->texnum;
1576         }
1577         else
1578                 return 0;
1579 }
1580
1581 void R_ClearTexture (rtexture_t *rt)
1582 {
1583         gltexture_t *glt = (gltexture_t *)rt;
1584
1585         R_Upload( glt, NULL, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth );
1586 }
1587
1588 int R_PicmipForFlags(int flags)
1589 {
1590         int miplevel = 0;
1591         if(flags & TEXF_PICMIP)
1592         {
1593                 miplevel += gl_picmip.integer;
1594                 if (flags & TEXF_ISWORLD)
1595                 {
1596                         if (r_picmipworld.integer)
1597                                 miplevel += gl_picmip_world.integer;
1598                         else
1599                                 miplevel = 0;
1600                 }
1601                 else if (flags & TEXF_ISSPRITE)
1602                 {
1603                         if (r_picmipsprites.integer)
1604                                 miplevel += gl_picmip_sprites.integer;
1605                         else
1606                                 miplevel = 0;
1607                 }
1608                 else
1609                         miplevel += gl_picmip_other.integer;
1610         }
1611         return max(0, miplevel);
1612 }