]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_textures.c
cvar: r_texture_dds_load_dxt1_noalpha; if set, DXT1 alpha detection is disabled,...
[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_dxt1_noalpha = {0, "r_texture_dds_load_dxt1_noalpha", "0", "if set, alpha detection on DXT1 is turned off, and DXT1 textures are assumed to never have alpha"};
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_dxt1_noalpha);
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)
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 = 0x41; // DDPF_RGB | DDPF_ALPHAPIXELS
1171         }
1172         if (mipmaps)
1173         {
1174                 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1175                 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1176         }
1177         memcpy(dds, "DDS ", 4);
1178         StoreLittleLong(dds+4, ddssize);
1179         StoreLittleLong(dds+8, dds_flags);
1180         StoreLittleLong(dds+12, mipinfo[0][1]); // height
1181         StoreLittleLong(dds+16, mipinfo[0][0]); // width
1182         StoreLittleLong(dds+24, 1); // depth
1183         StoreLittleLong(dds+28, mipmaps); // mipmaps
1184         StoreLittleLong(dds+76, 32); // format size
1185         StoreLittleLong(dds+80, dds_format_flags);
1186         StoreLittleLong(dds+108, dds_caps1);
1187         StoreLittleLong(dds+112, dds_caps2);
1188         if (bytesperblock)
1189         {
1190                 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1191                 memcpy(dds+84, ddsfourcc, 4);
1192                 for (mip = 0;mip < mipmaps;mip++)
1193                 {
1194                         qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1195                 }
1196         }
1197         else
1198         {
1199                 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1200                 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1201                 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1202                 for (mip = 0;mip < mipmaps;mip++)
1203                 {
1204                         qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1205                 }
1206         }
1207         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1208         ret = FS_WriteFile(filename, dds, ddssize);
1209         Mem_Free(dds);
1210         return ret ? ddssize : -5;
1211 }
1212
1213 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
1214 {
1215         int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1216         //int dds_flags;
1217         textype_t textype;
1218         int bytesperblock, bytesperpixel;
1219         int mipcomplete;
1220         gltexture_t *glt;
1221         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1222         textypeinfo_t *texinfo;
1223         int mip, mipwidth, mipheight, mipsize;
1224         unsigned int c;
1225         GLint oldbindtexnum;
1226         const unsigned char *mippixels, *ddspixels;
1227         unsigned char *dds;
1228         fs_offset_t ddsfilesize;
1229         unsigned int ddssize;
1230
1231         if (cls.state == ca_dedicated)
1232                 return NULL;
1233
1234         dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1235         ddssize = ddsfilesize;
1236
1237         if (!dds)
1238         {
1239                 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1240                 return NULL; // not found
1241         }
1242
1243         if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1244         {
1245                 Mem_Free(dds);
1246                 Con_Printf("^1%s: not a DDS image\n", filename);
1247                 return NULL;
1248         }
1249
1250         //dds_flags = BuffLittleLong(dds+8);
1251         dds_format_flags = BuffLittleLong(dds+80);
1252         dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1253         dds_width = BuffLittleLong(dds+16);
1254         dds_height = BuffLittleLong(dds+12);
1255         ddspixels = dds + 128;
1256
1257         //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1258         if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1259         {
1260                 // very sloppy BGRA 32bit identification
1261                 textype = TEXTYPE_BGRA;
1262                 bytesperblock = 0;
1263                 bytesperpixel = 4;
1264                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1265                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1266                 {
1267                         Mem_Free(dds);
1268                         Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1269                         return NULL;
1270                 }
1271                 // check alpha
1272                 for (i = 3;i < size;i += 4)
1273                         if (ddspixels[i] < 255)
1274                                 break;
1275                 if (i >= size)
1276                         flags &= ~TEXF_ALPHA;
1277         }
1278         else if (!memcmp(dds+84, "DXT1", 4))
1279         {
1280                 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1281                 // LordHavoc: it is my belief that this does not infringe on the
1282                 // patent because it is not decoding pixels...
1283                 textype = TEXTYPE_DXT1;
1284                 bytesperblock = 8;
1285                 bytesperpixel = 0;
1286                 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1287                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1288                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1289                 {
1290                         Mem_Free(dds);
1291                         Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1292                         return NULL;
1293                 }
1294                 if(r_texture_dds_load_dxt1_noalpha.integer)
1295                 {
1296                         flags &= ~TEXF_ALPHA;
1297                 }
1298                 else
1299                 {
1300                         for (i = 0;i < size;i += bytesperblock)
1301                                 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1302                                         break;
1303                         if (i < size)
1304                                 textype = TEXTYPE_DXT1A;
1305                         else
1306                                 flags &= ~TEXF_ALPHA;
1307                 }
1308         }
1309         else if (!memcmp(dds+84, "DXT3", 4))
1310         {
1311                 textype = TEXTYPE_DXT3;
1312                 bytesperblock = 16;
1313                 bytesperpixel = 0;
1314                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1315                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1316                 {
1317                         Mem_Free(dds);
1318                         Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1319                         return NULL;
1320                 }
1321         }
1322         else if (!memcmp(dds+84, "DXT5", 4))
1323         {
1324                 textype = TEXTYPE_DXT5;
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 DXT5 DDS image\n", filename);
1332                         return NULL;
1333                 }
1334         }
1335         else
1336         {
1337                 Mem_Free(dds);
1338                 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1339                 return NULL;
1340         }
1341
1342         // return whether this texture is transparent
1343         if (hasalphaflag)
1344                 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1345
1346         // calculate average color if requested
1347         if (avgcolor)
1348         {
1349                 float f;
1350                 Vector4Clear(avgcolor);
1351                 if (bytesperblock)
1352                 {
1353                         for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
1354                         {
1355                                 c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
1356                                 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1357                                 avgcolor[1] += ((c >>  5) & 0x3F) + ((c >> 21) & 0x3F);
1358                                 avgcolor[2] += ((c      ) & 0x1F) + ((c >> 16) & 0x1F);
1359                         }
1360                         f = (float)bytesperblock / size;
1361                         avgcolor[0] *= (0.5f / 31.0f) * f;
1362                         avgcolor[1] *= (0.5f / 63.0f) * f;
1363                         avgcolor[2] *= (0.5f / 31.0f) * f;
1364                         avgcolor[3] = 1; // too hard to calculate
1365                 }
1366                 else
1367                 {
1368                         for (i = 0;i < size;i += 4)
1369                         {
1370                                 avgcolor[0] += ddspixels[i+2];
1371                                 avgcolor[1] += ddspixels[i+1];
1372                                 avgcolor[2] += ddspixels[i];
1373                                 avgcolor[3] += ddspixels[i+3];
1374                         }
1375                         f = (1.0f / 255.0f) * bytesperpixel / size;
1376                         avgcolor[0] *= f;
1377                         avgcolor[1] *= f;
1378                         avgcolor[2] *= f;
1379                         avgcolor[3] *= f;
1380                 }
1381         }
1382
1383         // this is where we apply gl_picmip
1384         mippixels = ddspixels;
1385         mipwidth = dds_width;
1386         mipheight = dds_height;
1387         while(miplevel >= 1 && dds_miplevels >= 1)
1388         {
1389                 if (mipwidth <= 1 && mipheight <= 1)
1390                         break;
1391                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1392                 mippixels += mipsize; // just skip
1393                 --dds_miplevels;
1394                 --miplevel;
1395                 if (mipwidth > 1)
1396                         mipwidth >>= 1;
1397                 if (mipheight > 1)
1398                         mipheight >>= 1;
1399         }
1400
1401         // when not requesting mipmaps, do not load them
1402         if(!(flags & TEXF_MIPMAP))
1403                 dds_miplevels = 0;
1404
1405         if (dds_miplevels >= 1)
1406                 flags |= TEXF_MIPMAP;
1407         else
1408                 flags &= ~TEXF_MIPMAP;
1409
1410         // if S3TC is not supported, there's very little we can do about it
1411         if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
1412         {
1413                 Mem_Free(dds);
1414                 Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
1415                 return NULL;
1416         }
1417
1418         texinfo = R_GetTexTypeInfo(textype, flags);
1419
1420         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1421         strlcpy (glt->identifier, filename, sizeof(glt->identifier));
1422         glt->pool = pool;
1423         glt->chain = pool->gltchain;
1424         pool->gltchain = glt;
1425         glt->inputwidth = mipwidth;
1426         glt->inputheight = mipheight;
1427         glt->inputdepth = 1;
1428         glt->flags = flags;
1429         glt->textype = texinfo;
1430         glt->texturetype = GLTEXTURETYPE_2D;
1431         glt->inputdatasize = ddssize;
1432         glt->glinternalformat = texinfo->glinternalformat;
1433         glt->glformat = texinfo->glformat;
1434         glt->gltype = texinfo->gltype;
1435         glt->bytesperpixel = texinfo->internalbytesperpixel;
1436         glt->sides = 1;
1437         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1438         glt->tilewidth = mipwidth;
1439         glt->tileheight = mipheight;
1440         glt->tiledepth = 1;
1441
1442         // texture uploading can take a while, so make sure we're sending keepalives
1443         CL_KeepaliveMessage(false);
1444
1445         // upload the texture
1446         // we need to restore the texture binding after finishing the upload
1447         CHECKGLERROR
1448         GL_ActiveTexture(0);
1449         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1450         qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1451         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1452         mipcomplete = false;
1453
1454         for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
1455         {
1456                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1457                 if (mippixels + mipsize > dds + ddssize)
1458                         break;
1459                 if (bytesperblock)
1460                 {
1461                         qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
1462                 }
1463                 else
1464                 {
1465                         qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
1466                 }
1467                 mippixels += mipsize;
1468                 if (mipwidth <= 1 && mipheight <= 1)
1469                 {
1470                         mipcomplete = true;
1471                         break;
1472                 }
1473                 if (mipwidth > 1)
1474                         mipwidth >>= 1;
1475                 if (mipheight > 1)
1476                         mipheight >>= 1;
1477         }
1478         if (dds_miplevels >= 1 && !mipcomplete)
1479         {
1480                 // need to set GL_TEXTURE_MAX_LEVEL
1481                 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
1482         }
1483         GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1484         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1485
1486         Mem_Free(dds);
1487         return (rtexture_t *)glt;
1488 }
1489
1490 int R_TextureWidth(rtexture_t *rt)
1491 {
1492         return rt ? ((gltexture_t *)rt)->inputwidth : 0;
1493 }
1494
1495 int R_TextureHeight(rtexture_t *rt)
1496 {
1497         return rt ? ((gltexture_t *)rt)->inputheight : 0;
1498 }
1499
1500 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
1501 {
1502         gltexture_t *glt = (gltexture_t *)rt;
1503         if (data == NULL)
1504                 Host_Error("R_UpdateTexture: no data supplied");
1505         if (glt == NULL)
1506                 Host_Error("R_UpdateTexture: no texture supplied");
1507         if (!glt->texnum)
1508                 Host_Error("R_UpdateTexture: texture has not been uploaded yet");
1509         // update part of the texture
1510         if (glt->bufferpixels)
1511         {
1512                 int j;
1513                 int bpp = glt->bytesperpixel;
1514                 int inputskip = width*bpp;
1515                 int outputskip = glt->tilewidth*bpp;
1516                 const unsigned char *input = data;
1517                 unsigned char *output = glt->bufferpixels;
1518                 if (x < 0)
1519                 {
1520                         width += x;
1521                         input -= x*bpp;
1522                         x = 0;
1523                 }
1524                 if (y < 0)
1525                 {
1526                         height += y;
1527                         input -= y*inputskip;
1528                         y = 0;
1529                 }
1530                 if (width > glt->tilewidth - x)
1531                         width = glt->tilewidth - x;
1532                 if (height > glt->tileheight - y)
1533                         height = glt->tileheight - y;
1534                 if (width < 1 || height < 1)
1535                         return;
1536                 glt->dirty = true;
1537                 glt->buffermodified = true;
1538                 output += y*outputskip + x*bpp;
1539                 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
1540                         memcpy(output, input, width*bpp);
1541         }
1542         else
1543                 R_Upload(glt, data, x, y, 0, width, height, 1);
1544 }
1545
1546 int R_RealGetTexture(rtexture_t *rt)
1547 {
1548         if (rt)
1549         {
1550                 gltexture_t *glt;
1551                 glt = (gltexture_t *)rt;
1552                 if (glt->flags & GLTEXF_DYNAMIC)
1553                         R_UpdateDynamicTexture(glt);
1554                 if (glt->buffermodified && glt->bufferpixels)
1555                 {
1556                         glt->buffermodified = false;
1557                         R_Upload(glt, glt->bufferpixels, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth);
1558                 }
1559                 glt->dirty = false;
1560                 return glt->texnum;
1561         }
1562         else
1563                 return 0;
1564 }
1565
1566 void R_ClearTexture (rtexture_t *rt)
1567 {
1568         gltexture_t *glt = (gltexture_t *)rt;
1569
1570         R_Upload( glt, NULL, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth );
1571 }
1572
1573 int R_PicmipForFlags(int flags)
1574 {
1575         int miplevel = 0;
1576         if(flags & TEXF_PICMIP)
1577         {
1578                 miplevel += gl_picmip.integer;
1579                 if (flags & TEXF_ISWORLD)
1580                 {
1581                         if (r_picmipworld.integer)
1582                                 miplevel += gl_picmip_world.integer;
1583                         else
1584                                 miplevel = 0;
1585                 }
1586                 else if (flags & TEXF_ISSPRITE)
1587                 {
1588                         if (r_picmipsprites.integer)
1589                                 miplevel += gl_picmip_sprites.integer;
1590                         else
1591                                 miplevel = 0;
1592                 }
1593                 else
1594                         miplevel += gl_picmip_other.integer;
1595         }
1596         return max(0, miplevel);
1597 }