]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_textures.c
upload NULL textures as NULL textures, rather than creating a big array
[xonotic/darkplaces.git] / gl_textures.c
1
2 #include "quakedef.h"
3 #ifdef SUPPORTD3D
4 #include <d3d9.h>
5 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
6 #endif
7 #include "image.h"
8 #include "jpeg.h"
9 #include "image_png.h"
10 #include "intoverflow.h"
11 #include "dpsoftrast.h"
12
13 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)"};
14 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)"};
15 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%"};
16 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)"};
17 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)"};
18 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)"};
19 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)"};
20 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)"};
21 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)"};
22 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"};
23 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"};
24 cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
25 cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
26 cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
27 cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
28 cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
29 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
30 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)"};
31 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
32 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
33 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)"};
34 cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "0", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"};
35 cvar_t r_texture_dds_load_alphamode = {0, "r_texture_dds_load_alphamode", "1", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambiguous, 2: texture format only"};
36 cvar_t r_texture_dds_load_logfailure = {0, "r_texture_dds_load_logfailure", "1", "log missing DDS textures to ddstexturefailures.log"};
37 cvar_t r_texture_dds_swdecode = {0, "r_texture_dds_swdecode", "0", "0: don't software decode DDS, 1: software decode DDS if unsupported, 2: always software decode DDS"};
38
39 qboolean        gl_filter_force = false;
40 int             gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
41 int             gl_filter_mag = GL_LINEAR;
42 DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_mipmap = DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE;
43 DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_nomipmap = DPSOFTRAST_TEXTURE_FILTER_LINEAR;
44
45 #ifdef SUPPORTD3D
46 int d3d_filter_flatmin = D3DTEXF_LINEAR;
47 int d3d_filter_flatmag = D3DTEXF_LINEAR;
48 int d3d_filter_flatmix = D3DTEXF_POINT;
49 int d3d_filter_mipmin = D3DTEXF_LINEAR;
50 int d3d_filter_mipmag = D3DTEXF_LINEAR;
51 int d3d_filter_mipmix = D3DTEXF_LINEAR;
52 int d3d_filter_nomip = false;
53 #endif
54
55
56 static mempool_t *texturemempool;
57 static memexpandablearray_t texturearray;
58
59 // note: this must not conflict with TEXF_ flags in r_textures.h
60 // bitmask for mismatch checking
61 #define GLTEXF_IMPORTANTBITS (0)
62 // dynamic texture (treat texnum == 0 differently)
63 #define GLTEXF_DYNAMIC          0x00080000
64
65 typedef struct textypeinfo_s
66 {
67         textype_t textype;
68         int inputbytesperpixel;
69         int internalbytesperpixel;
70         float glinternalbytesperpixel;
71         int glinternalformat;
72         int glformat;
73         int gltype;
74 }
75 textypeinfo_t;
76
77
78 static textypeinfo_t textype_palette                = {TEXTYPE_PALETTE    , 1, 4, 4.0f, GL_RGBA                         , GL_BGRA           , GL_UNSIGNED_BYTE };
79 static textypeinfo_t textype_palette_alpha          = {TEXTYPE_PALETTE    , 1, 4, 4.0f, GL_RGBA                         , GL_BGRA           , GL_UNSIGNED_BYTE };
80 static textypeinfo_t textype_rgba                   = {TEXTYPE_RGBA       , 4, 4, 4.0f, GL_RGBA                         , GL_RGBA           , GL_UNSIGNED_BYTE };
81 static textypeinfo_t textype_rgba_alpha             = {TEXTYPE_RGBA       , 4, 4, 4.0f, GL_RGBA                         , GL_RGBA           , GL_UNSIGNED_BYTE };
82 static textypeinfo_t textype_rgba_compress          = {TEXTYPE_RGBA       , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA           , GL_UNSIGNED_BYTE };
83 static textypeinfo_t textype_rgba_alpha_compress    = {TEXTYPE_RGBA       , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA           , GL_UNSIGNED_BYTE };
84 static textypeinfo_t textype_bgra                   = {TEXTYPE_BGRA       , 4, 4, 4.0f, GL_RGBA                         , GL_BGRA           , GL_UNSIGNED_BYTE };
85 static textypeinfo_t textype_bgra_alpha             = {TEXTYPE_BGRA       , 4, 4, 4.0f, GL_RGBA                         , GL_BGRA           , GL_UNSIGNED_BYTE };
86 static textypeinfo_t textype_bgra_compress          = {TEXTYPE_BGRA       , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA           , GL_UNSIGNED_BYTE };
87 static textypeinfo_t textype_bgra_alpha_compress    = {TEXTYPE_BGRA       , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_BGRA           , GL_UNSIGNED_BYTE };
88 static textypeinfo_t textype_shadowmap16            = {TEXTYPE_SHADOWMAP  , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB        , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
89 static textypeinfo_t textype_shadowmap24            = {TEXTYPE_SHADOWMAP  , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB        , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
90 static textypeinfo_t textype_alpha                  = {TEXTYPE_ALPHA      , 1, 4, 4.0f, GL_ALPHA                        , GL_ALPHA          , GL_UNSIGNED_BYTE };
91 static textypeinfo_t textype_dxt1                   = {TEXTYPE_DXT1       , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0                 , 0                };
92 static textypeinfo_t textype_dxt1a                  = {TEXTYPE_DXT1A      , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0                 , 0                };
93 static textypeinfo_t textype_dxt3                   = {TEXTYPE_DXT3       , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0                 , 0                };
94 static textypeinfo_t textype_dxt5                   = {TEXTYPE_DXT5       , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0                 , 0                };
95 static textypeinfo_t textype_colorbuffer            = {TEXTYPE_COLORBUFFER, 4, 4, 4.0f, GL_RGBA                         , GL_BGRA           , GL_UNSIGNED_BYTE };
96 static textypeinfo_t textype_colorbuffer16f         = {TEXTYPE_COLORBUFFER16F,8,8,8.0f, GL_RGBA16F_ARB                  , GL_RGBA           , GL_FLOAT         };
97 static textypeinfo_t textype_colorbuffer32f         = {TEXTYPE_COLORBUFFER32F,16,16,16.0f,GL_RGBA32F_ARB                , GL_RGBA           , GL_FLOAT         };
98
99
100 typedef enum gltexturetype_e
101 {
102         GLTEXTURETYPE_2D,
103         GLTEXTURETYPE_3D,
104         GLTEXTURETYPE_CUBEMAP,
105         GLTEXTURETYPE_TOTAL
106 }
107 gltexturetype_t;
108
109 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB};
110 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
111 static int cubemapside[6] =
112 {
113         GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
114         GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
115         GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
116         GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
117         GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
118         GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
119 };
120
121 typedef struct gltexture_s
122 {
123         // this portion of the struct is exposed to the R_GetTexture macro for
124         // speed reasons, must be identical in rtexture_t!
125         int texnum; // GL texture slot number
126         qboolean dirty; // indicates that R_RealGetTexture should be called
127         int gltexturetypeenum; // used by R_Mesh_TexBind
128         // d3d stuff the backend needs
129         void *d3dtexture;
130 #ifdef SUPPORTD3D
131         qboolean d3disdepthsurface; // for depth/stencil surfaces
132         int d3dformat;
133         int d3dusage;
134         int d3dpool;
135         int d3daddressu;
136         int d3daddressv;
137         int d3daddressw;
138         int d3dmagfilter;
139         int d3dminfilter;
140         int d3dmipfilter;
141         int d3dmaxmiplevelfilter;
142         int d3dmipmaplodbias;
143         int d3dmaxmiplevel;
144 #endif
145
146         // dynamic texture stuff [11/22/2007 Black]
147         updatecallback_t updatecallback;
148         void *updatacallback_data;
149         // --- [11/22/2007 Black]
150
151         // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
152         unsigned char *bufferpixels;
153         qboolean buffermodified;
154
155         // pointer to texturepool (check this to see if the texture is allocated)
156         struct gltexturepool_s *pool;
157         // pointer to next texture in texturepool chain
158         struct gltexture_s *chain;
159         // name of the texture (this might be removed someday), no duplicates
160         char identifier[MAX_QPATH + 32];
161         // original data size in *inputtexels
162         int inputwidth, inputheight, inputdepth;
163         // copy of the original texture(s) supplied to the upload function, for
164         // delayed uploads (non-precached)
165         unsigned char *inputtexels;
166         // original data size in *inputtexels
167         int inputdatasize;
168         // flags supplied to the LoadTexture function
169         // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
170         int flags;
171         // picmip level
172         int miplevel;
173         // pointer to one of the textype_ structs
174         textypeinfo_t *textype;
175         // one of the GLTEXTURETYPE_ values
176         int texturetype;
177         // palette if the texture is TEXTYPE_PALETTE
178         const unsigned int *palette;
179         // actual stored texture size after gl_picmip and gl_max_size are applied
180         // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
181         int tilewidth, tileheight, tiledepth;
182         // 1 or 6 depending on texturetype
183         int sides;
184         // how many mipmap levels in this texture
185         int miplevels;
186         // bytes per pixel
187         int bytesperpixel;
188         // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
189         int glformat;
190         // 3 or 4
191         int glinternalformat;
192         // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
193         int gltype;
194 }
195 gltexture_t;
196
197 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
198
199 typedef struct gltexturepool_s
200 {
201         unsigned int sentinel;
202         struct gltexture_s *gltchain;
203         struct gltexturepool_s *next;
204 }
205 gltexturepool_t;
206
207 static gltexturepool_t *gltexturepoolchain = NULL;
208
209 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
210 static int resizebuffersize = 0;
211 static const unsigned char *texturebuffer;
212
213 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
214 {
215         switch(textype)
216         {
217         case TEXTYPE_DXT1:
218                 return &textype_dxt1;
219         case TEXTYPE_DXT1A:
220                 return &textype_dxt1a;
221         case TEXTYPE_DXT3:
222                 return &textype_dxt3;
223         case TEXTYPE_DXT5:
224                 return &textype_dxt5;
225         case TEXTYPE_PALETTE:
226                 return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
227         case TEXTYPE_RGBA:
228                 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
229                         return (flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress;
230                 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba;
231         case TEXTYPE_BGRA:
232                 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
233                         return (flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress;
234                 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra;
235         case TEXTYPE_ALPHA:
236                 return &textype_alpha;
237         case TEXTYPE_SHADOWMAP:
238                 return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
239         case TEXTYPE_COLORBUFFER:
240                 return &textype_colorbuffer;
241         case TEXTYPE_COLORBUFFER16F:
242                 return &textype_colorbuffer16f;
243         case TEXTYPE_COLORBUFFER32F:
244                 return &textype_colorbuffer32f;
245         default:
246                 Host_Error("R_GetTexTypeInfo: unknown texture format");
247                 break;
248         }
249         return NULL;
250 }
251
252 // dynamic texture code [11/22/2007 Black]
253 void R_MarkDirtyTexture(rtexture_t *rt) {
254         gltexture_t *glt = (gltexture_t*) rt;
255         if( !glt ) {
256                 return;
257         }
258
259         // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
260         if (glt->flags & GLTEXF_DYNAMIC)
261         {
262                 // mark it as dirty, so R_RealGetTexture gets called
263                 glt->dirty = true;
264         }
265 }
266
267 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
268         gltexture_t *glt = (gltexture_t*) rt;
269         if( !glt ) {
270                 return;
271         }
272
273         glt->flags |= GLTEXF_DYNAMIC;
274         glt->updatecallback = updatecallback;
275         glt->updatacallback_data = data;
276 }
277
278 static void R_UpdateDynamicTexture(gltexture_t *glt) {
279         glt->dirty = false;
280         if( glt->updatecallback ) {
281                 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
282         }
283 }
284
285 void R_PurgeTexture(rtexture_t *rt)
286 {
287         if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
288                 R_FreeTexture(rt);
289         }
290 }
291
292 void R_FreeTexture(rtexture_t *rt)
293 {
294         gltexture_t *glt, **gltpointer;
295
296         glt = (gltexture_t *)rt;
297         if (glt == NULL)
298                 Host_Error("R_FreeTexture: texture == NULL");
299
300         for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
301         if (*gltpointer == glt)
302                 *gltpointer = glt->chain;
303         else
304                 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
305
306         R_Mesh_ClearBindingsForTexture(glt->texnum);
307
308         switch(vid.renderpath)
309         {
310         case RENDERPATH_GL11:
311         case RENDERPATH_GL13:
312         case RENDERPATH_GL20:
313         case RENDERPATH_GLES2:
314                 if (glt->texnum)
315                 {
316                         CHECKGLERROR
317                         qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
318                 }
319                 break;
320         case RENDERPATH_D3D9:
321 #ifdef SUPPORTD3D
322                 if (glt->d3disdepthsurface)
323                         IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
324                 else if (glt->tiledepth > 1)
325                         IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
326                 else if (glt->sides == 6)
327                         IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
328                 else
329                         IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
330                 glt->d3dtexture = NULL;
331 #endif
332                 break;
333         case RENDERPATH_D3D10:
334                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
335                 break;
336         case RENDERPATH_D3D11:
337                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
338                 break;
339         case RENDERPATH_SOFT:
340                 if (glt->texnum)
341                         DPSOFTRAST_Texture_Free(glt->texnum);
342                 break;
343         }
344
345         if (glt->inputtexels)
346                 Mem_Free(glt->inputtexels);
347         Mem_ExpandableArray_FreeRecord(&texturearray, glt);
348 }
349
350 rtexturepool_t *R_AllocTexturePool(void)
351 {
352         gltexturepool_t *pool;
353         if (texturemempool == NULL)
354                 return NULL;
355         pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
356         if (pool == NULL)
357                 return NULL;
358         pool->next = gltexturepoolchain;
359         gltexturepoolchain = pool;
360         pool->sentinel = TEXTUREPOOL_SENTINEL;
361         return (rtexturepool_t *)pool;
362 }
363
364 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
365 {
366         gltexturepool_t *pool, **poolpointer;
367         if (rtexturepool == NULL)
368                 return;
369         if (*rtexturepool == NULL)
370                 return;
371         pool = (gltexturepool_t *)(*rtexturepool);
372         *rtexturepool = NULL;
373         if (pool->sentinel != TEXTUREPOOL_SENTINEL)
374                 Host_Error("R_FreeTexturePool: pool already freed");
375         for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
376         if (*poolpointer == pool)
377                 *poolpointer = pool->next;
378         else
379                 Host_Error("R_FreeTexturePool: pool not linked");
380         while (pool->gltchain)
381                 R_FreeTexture((rtexture_t *)pool->gltchain);
382         Mem_Free(pool);
383 }
384
385
386 typedef struct glmode_s
387 {
388         const char *name;
389         int minification, magnification;
390         DPSOFTRAST_TEXTURE_FILTER dpsoftrastfilter_mipmap, dpsoftrastfilter_nomipmap;
391 }
392 glmode_t;
393
394 static glmode_t modes[6] =
395 {
396         {"GL_NEAREST", GL_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
397         {"GL_LINEAR", GL_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
398         {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
399         {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
400         {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
401         {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR}
402 };
403
404 #ifdef SUPPORTD3D
405 typedef struct d3dmode_s
406 {
407         const char *name;
408         int m1, m2;
409 }
410 d3dmode_t;
411
412 static d3dmode_t d3dmodes[6] =
413 {
414         {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
415         {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
416         {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
417         {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
418         {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
419         {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
420 };
421 #endif
422
423 static void GL_TextureMode_f (void)
424 {
425         int i;
426         GLint oldbindtexnum;
427         gltexture_t *glt;
428         gltexturepool_t *pool;
429
430         if (Cmd_Argc() == 1)
431         {
432                 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
433                 for (i = 0;i < 6;i++)
434                 {
435                         if (gl_filter_min == modes[i].minification)
436                         {
437                                 Con_Printf("%s\n", modes[i].name);
438                                 return;
439                         }
440                 }
441                 Con_Print("current filter is unknown???\n");
442                 return;
443         }
444
445         for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
446                 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
447                         break;
448         if (i == 6)
449         {
450                 Con_Print("bad filter name\n");
451                 return;
452         }
453
454         gl_filter_min = modes[i].minification;
455         gl_filter_mag = modes[i].magnification;
456         gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
457
458         dpsoftrast_filter_mipmap = modes[i].dpsoftrastfilter_mipmap;
459         dpsoftrast_filter_nomipmap = modes[i].dpsoftrastfilter_nomipmap;
460
461         switch(vid.renderpath)
462         {
463         case RENDERPATH_GL11:
464         case RENDERPATH_GL13:
465         case RENDERPATH_GL20:
466         case RENDERPATH_GLES2:
467                 // change all the existing mipmap texture objects
468                 // FIXME: force renderer(/client/something?) restart instead?
469                 CHECKGLERROR
470                 GL_ActiveTexture(0);
471                 for (pool = gltexturepoolchain;pool;pool = pool->next)
472                 {
473                         for (glt = pool->gltchain;glt;glt = glt->chain)
474                         {
475                                 // only update already uploaded images
476                                 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
477                                 {
478                                         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
479                                         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
480                                         if (glt->flags & TEXF_MIPMAP)
481                                         {
482                                                 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
483                                         }
484                                         else
485                                         {
486                                                 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
487                                         }
488                                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
489                                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
490                                 }
491                         }
492                 }
493                 break;
494         case RENDERPATH_D3D9:
495 #ifdef SUPPORTD3D
496                 d3d_filter_flatmin = d3dmodes[i].m1;
497                 d3d_filter_flatmag = d3dmodes[i].m1;
498                 d3d_filter_flatmix = D3DTEXF_POINT;
499                 d3d_filter_mipmin = d3dmodes[i].m1;
500                 d3d_filter_mipmag = d3dmodes[i].m1;
501                 d3d_filter_mipmix = d3dmodes[i].m2;
502                 d3d_filter_nomip = i < 2;
503                 if (gl_texture_anisotropy.integer > 1 && i == 5)
504                         d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
505                 for (pool = gltexturepoolchain;pool;pool = pool->next)
506                 {
507                         for (glt = pool->gltchain;glt;glt = glt->chain)
508                         {
509                                 // only update already uploaded images
510                                 if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
511                                 {
512                                         if (glt->flags & TEXF_MIPMAP)
513                                         {
514                                                 glt->d3dminfilter = d3d_filter_mipmin;
515                                                 glt->d3dmagfilter = d3d_filter_mipmag;
516                                                 glt->d3dmipfilter = d3d_filter_mipmix;
517                                                 glt->d3dmaxmiplevelfilter = 0;
518                                         }
519                                         else
520                                         {
521                                                 glt->d3dminfilter = d3d_filter_flatmin;
522                                                 glt->d3dmagfilter = d3d_filter_flatmag;
523                                                 glt->d3dmipfilter = d3d_filter_flatmix;
524                                                 glt->d3dmaxmiplevelfilter = 0;
525                                         }
526                                 }
527                         }
528                 }
529 #endif
530                 break;
531         case RENDERPATH_D3D10:
532                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
533                 break;
534         case RENDERPATH_D3D11:
535                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
536                 break;
537         case RENDERPATH_SOFT:
538                 // change all the existing texture objects
539                 for (pool = gltexturepoolchain;pool;pool = pool->next)
540                         for (glt = pool->gltchain;glt;glt = glt->chain)
541                                 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
542                                         DPSOFTRAST_Texture_Filter(glt->texnum, (glt->flags & TEXF_MIPMAP) ? dpsoftrast_filter_mipmap : dpsoftrast_filter_nomipmap);
543                 break;
544         }
545 }
546
547 static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, int inwidth, int inheight, int indepth, int *outwidth, int *outheight, int *outdepth, int *outmiplevels)
548 {
549         int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
550
551         switch (texturetype)
552         {
553         default:
554         case GLTEXTURETYPE_2D:
555                 maxsize = vid.maxtexturesize_2d;
556                 if (flags & TEXF_PICMIP)
557                 {
558                         maxsize = bound(1, gl_max_size.integer, maxsize);
559                         picmip = miplevel;
560                 }
561                 break;
562         case GLTEXTURETYPE_3D:
563                 maxsize = vid.maxtexturesize_3d;
564                 break;
565         case GLTEXTURETYPE_CUBEMAP:
566                 maxsize = vid.maxtexturesize_cubemap;
567                 break;
568         }
569
570         if (vid.support.arb_texture_non_power_of_two)
571         {
572                 width2 = min(inwidth >> picmip, maxsize);
573                 height2 = min(inheight >> picmip, maxsize);
574                 depth2 = min(indepth >> picmip, maxsize);
575         }
576         else
577         {
578                 for (width2 = 1;width2 < inwidth;width2 <<= 1);
579                 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
580                 for (height2 = 1;height2 < inheight;height2 <<= 1);
581                 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
582                 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
583                 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
584         }
585
586         switch(vid.renderpath)
587         {
588         case RENDERPATH_GL11:
589         case RENDERPATH_GL13:
590         case RENDERPATH_GL20:
591         case RENDERPATH_D3D10:
592         case RENDERPATH_D3D11:
593         case RENDERPATH_SOFT:
594         case RENDERPATH_GLES2:
595                 break;
596         case RENDERPATH_D3D9:
597 #if 0
598                 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
599                 if (texturetype == GLTEXTURETYPE_2D)
600                 {
601                         width2 = max(width2, 2);
602                         height2 = max(height2, 2);
603                 }
604 #endif
605                 break;
606         }
607
608         miplevels = 1;
609         if (flags & TEXF_MIPMAP)
610         {
611                 int extent = max(width2, max(height2, depth2));
612                 while(extent >>= 1)
613                         miplevels++;
614         }
615
616         if (outwidth)
617                 *outwidth = max(1, width2);
618         if (outheight)
619                 *outheight = max(1, height2);
620         if (outdepth)
621                 *outdepth = max(1, depth2);
622         if (outmiplevels)
623                 *outmiplevels = miplevels;
624 }
625
626
627 static int R_CalcTexelDataSize (gltexture_t *glt)
628 {
629         int width2, height2, depth2, size;
630
631         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
632
633         size = width2 * height2 * depth2;
634
635         if (glt->flags & TEXF_MIPMAP)
636         {
637                 while (width2 > 1 || height2 > 1 || depth2 > 1)
638                 {
639                         if (width2 > 1)
640                                 width2 >>= 1;
641                         if (height2 > 1)
642                                 height2 >>= 1;
643                         if (depth2 > 1)
644                                 depth2 >>= 1;
645                         size += width2 * height2 * depth2;
646                 }
647         }
648
649         return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
650 }
651
652 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
653 {
654         int glsize;
655         int isloaded;
656         int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
657         int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
658         gltexture_t *glt;
659         gltexturepool_t *pool;
660         if (printeach)
661                 Con_Print("glsize input loaded mip alpha name\n");
662         for (pool = gltexturepoolchain;pool;pool = pool->next)
663         {
664                 pooltotal = 0;
665                 pooltotalt = 0;
666                 pooltotalp = 0;
667                 poolloaded = 0;
668                 poolloadedt = 0;
669                 poolloadedp = 0;
670                 for (glt = pool->gltchain;glt;glt = glt->chain)
671                 {
672                         glsize = R_CalcTexelDataSize(glt);
673                         isloaded = glt->texnum != 0;
674                         pooltotal++;
675                         pooltotalt += glsize;
676                         pooltotalp += glt->inputdatasize;
677                         if (isloaded)
678                         {
679                                 poolloaded++;
680                                 poolloadedt += glsize;
681                                 poolloadedp += glt->inputdatasize;
682                         }
683                         if (printeach)
684                                 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);
685                 }
686                 if (printpool)
687                         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);
688                 sumtotal += pooltotal;
689                 sumtotalt += pooltotalt;
690                 sumtotalp += pooltotalp;
691                 sumloaded += poolloaded;
692                 sumloadedt += poolloadedt;
693                 sumloadedp += poolloadedp;
694         }
695         if (printtotal)
696                 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);
697 }
698
699 static void R_TextureStats_f(void)
700 {
701         R_TextureStats_Print(true, true, true);
702 }
703
704 static void r_textures_start(void)
705 {
706         switch(vid.renderpath)
707         {
708         case RENDERPATH_GL11:
709         case RENDERPATH_GL13:
710         case RENDERPATH_GL20:
711         case RENDERPATH_GLES2:
712                 // LordHavoc: allow any alignment
713                 CHECKGLERROR
714                 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
715                 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
716                 break;
717         case RENDERPATH_D3D9:
718                 break;
719         case RENDERPATH_D3D10:
720                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
721                 break;
722         case RENDERPATH_D3D11:
723                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
724                 break;
725         case RENDERPATH_SOFT:
726                 break;
727         }
728
729         texturemempool = Mem_AllocPool("texture management", 0, NULL);
730         Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
731
732         // Disable JPEG screenshots if the DLL isn't loaded
733         if (! JPEG_OpenLibrary ())
734                 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
735         if (! PNG_OpenLibrary ())
736                 Cvar_SetValueQuick (&scr_screenshot_png, 0);
737 }
738
739 static void r_textures_shutdown(void)
740 {
741         rtexturepool_t *temp;
742
743         JPEG_CloseLibrary ();
744
745         while(gltexturepoolchain)
746         {
747                 temp = (rtexturepool_t *) gltexturepoolchain;
748                 R_FreeTexturePool(&temp);
749         }
750
751         resizebuffersize = 0;
752         resizebuffer = NULL;
753         colorconvertbuffer = NULL;
754         texturebuffer = NULL;
755         Mem_ExpandableArray_FreeArray(&texturearray);
756         Mem_FreePool(&texturemempool);
757 }
758
759 static void r_textures_newmap(void)
760 {
761 }
762
763 static void r_textures_devicelost(void)
764 {
765         int i, endindex;
766         gltexture_t *glt;
767         endindex = Mem_ExpandableArray_IndexRange(&texturearray);
768         for (i = 0;i < endindex;i++)
769         {
770                 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
771                 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
772                         continue;
773                 switch(vid.renderpath)
774                 {
775                 case RENDERPATH_GL11:
776                 case RENDERPATH_GL13:
777                 case RENDERPATH_GL20:
778                 case RENDERPATH_GLES2:
779                         break;
780                 case RENDERPATH_D3D9:
781 #ifdef SUPPORTD3D
782                         if (glt->d3disdepthsurface)
783                                 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
784                         else if (glt->tiledepth > 1)
785                                 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
786                         else if (glt->sides == 6)
787                                 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
788                         else
789                                 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
790                         glt->d3dtexture = NULL;
791 #endif
792                         break;
793                 case RENDERPATH_D3D10:
794                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
795                         break;
796                 case RENDERPATH_D3D11:
797                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
798                         break;
799                 case RENDERPATH_SOFT:
800                         break;
801                 }
802         }
803 }
804
805 static void r_textures_devicerestored(void)
806 {
807         int i, endindex;
808         gltexture_t *glt;
809         endindex = Mem_ExpandableArray_IndexRange(&texturearray);
810         for (i = 0;i < endindex;i++)
811         {
812                 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
813                 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
814                         continue;
815                 switch(vid.renderpath)
816                 {
817                 case RENDERPATH_GL11:
818                 case RENDERPATH_GL13:
819                 case RENDERPATH_GL20:
820                 case RENDERPATH_GLES2:
821                         break;
822                 case RENDERPATH_D3D9:
823 #ifdef SUPPORTD3D
824                         {
825                                 HRESULT d3dresult;
826                                 if (glt->d3disdepthsurface)
827                                 {
828                                         if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
829                                                 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
830                                 }
831                                 else if (glt->tiledepth > 1)
832                                 {
833                                         if (FAILED(d3dresult = IDirect3DDevice9_CreateVolumeTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->tiledepth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DVolumeTexture9 **)&glt->d3dtexture, NULL)))
834                                                 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
835                                 }
836                                 else if (glt->sides == 6)
837                                 {
838                                         if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
839                                                 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
840                                 }
841                                 else
842                                 {
843                                         if (FAILED(d3dresult = IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL)))
844                                                 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
845                                 }
846                         }
847 #endif
848                         break;
849                 case RENDERPATH_D3D10:
850                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
851                         break;
852                 case RENDERPATH_D3D11:
853                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
854                         break;
855                 case RENDERPATH_SOFT:
856                         break;
857                 }
858         }
859 }
860
861
862 void R_Textures_Init (void)
863 {
864         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");
865         Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
866         Cvar_RegisterVariable (&gl_max_size);
867         Cvar_RegisterVariable (&gl_picmip);
868         Cvar_RegisterVariable (&gl_picmip_world);
869         Cvar_RegisterVariable (&r_picmipworld);
870         Cvar_RegisterVariable (&gl_picmip_sprites);
871         Cvar_RegisterVariable (&r_picmipsprites);
872         Cvar_RegisterVariable (&gl_picmip_other);
873         Cvar_RegisterVariable (&gl_max_lightmapsize);
874         Cvar_RegisterVariable (&r_lerpimages);
875         Cvar_RegisterVariable (&gl_texture_anisotropy);
876         Cvar_RegisterVariable (&gl_texturecompression);
877         Cvar_RegisterVariable (&gl_texturecompression_color);
878         Cvar_RegisterVariable (&gl_texturecompression_normal);
879         Cvar_RegisterVariable (&gl_texturecompression_gloss);
880         Cvar_RegisterVariable (&gl_texturecompression_glow);
881         Cvar_RegisterVariable (&gl_texturecompression_2d);
882         Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
883         Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
884         Cvar_RegisterVariable (&gl_texturecompression_sky);
885         Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
886         Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
887         Cvar_RegisterVariable (&gl_nopartialtextureupdates);
888         Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
889         Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
890         Cvar_RegisterVariable (&r_texture_dds_swdecode);
891
892         R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
893 }
894
895 void R_Textures_Frame (void)
896 {
897         static int old_aniso = 0;
898
899         // could do procedural texture animation here, if we keep track of which
900         // textures were accessed this frame...
901
902         // free the resize buffers
903         resizebuffersize = 0;
904         if (resizebuffer)
905         {
906                 Mem_Free(resizebuffer);
907                 resizebuffer = NULL;
908         }
909         if (colorconvertbuffer)
910         {
911                 Mem_Free(colorconvertbuffer);
912                 colorconvertbuffer = NULL;
913         }
914
915         if (old_aniso != gl_texture_anisotropy.integer)
916         {
917                 gltexture_t *glt;
918                 gltexturepool_t *pool;
919                 GLint oldbindtexnum;
920
921                 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
922
923                 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
924
925                 switch(vid.renderpath)
926                 {
927                 case RENDERPATH_GL11:
928                 case RENDERPATH_GL13:
929                 case RENDERPATH_GL20:
930                 case RENDERPATH_GLES2:
931                         CHECKGLERROR
932                         GL_ActiveTexture(0);
933                         for (pool = gltexturepoolchain;pool;pool = pool->next)
934                         {
935                                 for (glt = pool->gltchain;glt;glt = glt->chain)
936                                 {
937                                         // only update already uploaded images
938                                         if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
939                                         {
940                                                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
941
942                                                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
943                                                 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
944
945                                                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
946                                         }
947                                 }
948                         }
949                         break;
950                 case RENDERPATH_D3D9:
951                 case RENDERPATH_D3D10:
952                 case RENDERPATH_D3D11:
953                 case RENDERPATH_SOFT:
954                         break;
955                 }
956         }
957 }
958
959 void R_MakeResizeBufferBigger(int size)
960 {
961         if (resizebuffersize < size)
962         {
963                 resizebuffersize = size;
964                 if (resizebuffer)
965                         Mem_Free(resizebuffer);
966                 if (colorconvertbuffer)
967                         Mem_Free(colorconvertbuffer);
968                 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
969                 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
970                 if (!resizebuffer || !colorconvertbuffer)
971                         Host_Error("R_Upload: out of memory");
972         }
973 }
974
975 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
976 {
977         int textureenum = gltexturetypeenums[texturetype];
978         int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
979
980         CHECKGLERROR
981
982         if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
983         {
984                 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
985                 if (gl_texture_anisotropy.integer != aniso)
986                         Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
987                 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
988         }
989         qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
990         qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
991         if (gltexturetypedimensions[texturetype] >= 3)
992         {
993                 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
994         }
995
996         CHECKGLERROR
997         if (!gl_filter_force && flags & TEXF_FORCENEAREST)
998         {
999                 if (flags & TEXF_MIPMAP)
1000                 {
1001                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
1002                 }
1003                 else
1004                 {
1005                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
1006                 }
1007                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
1008         }
1009         else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
1010         {
1011                 if (flags & TEXF_MIPMAP)
1012                 {
1013                         if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
1014                         {
1015                                 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
1016                         }
1017                         else
1018                         {
1019                                 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
1020                         }
1021                 }
1022                 else
1023                 {
1024                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
1025                 }
1026                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
1027         }
1028         else
1029         {
1030                 if (flags & TEXF_MIPMAP)
1031                 {
1032                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1033                 }
1034                 else
1035                 {
1036                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1037                 }
1038                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1039         }
1040
1041         if (textype == TEXTYPE_SHADOWMAP)
1042         {
1043                 if (vid.support.arb_shadow)
1044                 {
1045                         if (flags & TEXF_COMPARE)
1046                         {
1047                                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1048                         }
1049                         else
1050                         {
1051                                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1052                         }
1053                         qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1054                 }
1055                 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1056         }
1057
1058         CHECKGLERROR
1059 }
1060
1061 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1062 {
1063         if (data == NULL)
1064                 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1065
1066         if (glt->texturetype != GLTEXTURETYPE_2D)
1067                 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1068
1069         if (glt->textype->textype == TEXTYPE_PALETTE)
1070                 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1071
1072         if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1073                 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1074
1075         if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1076                 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1077
1078         // update a portion of the image
1079
1080         switch(vid.renderpath)
1081         {
1082         case RENDERPATH_GL11:
1083         case RENDERPATH_GL13:
1084         case RENDERPATH_GL20:
1085         case RENDERPATH_GLES2:
1086                 {
1087                         int oldbindtexnum;
1088                         CHECKGLERROR
1089                         // we need to restore the texture binding after finishing the upload
1090                         GL_ActiveTexture(0);
1091                         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1092                         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1093                         qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1094                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1095                 }
1096                 break;
1097         case RENDERPATH_D3D9:
1098 #ifdef SUPPORTD3D
1099                 {
1100                         RECT d3drect;
1101                         D3DLOCKED_RECT d3dlockedrect;
1102                         int y;
1103                         memset(&d3drect, 0, sizeof(d3drect));
1104                         d3drect.left = fragx;
1105                         d3drect.top = fragy;
1106                         d3drect.right = fragx+fragwidth;
1107                         d3drect.bottom = fragy+fragheight;
1108                         if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1109                         {
1110                                 for (y = 0;y < fragheight;y++)
1111                                         memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1112                                 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1113                         }
1114                 }
1115 #endif
1116                 break;
1117         case RENDERPATH_D3D10:
1118                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1119                 break;
1120         case RENDERPATH_D3D11:
1121                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1122                 break;
1123         case RENDERPATH_SOFT:
1124                 DPSOFTRAST_Texture_UpdatePartial(glt->texnum, 0, data, fragx, fragy, fragwidth, fragheight);
1125                 break;
1126         }
1127 }
1128
1129 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1130 {
1131         int i, mip = 0, width, height, depth;
1132         GLint oldbindtexnum = 0;
1133         const unsigned char *prevbuffer;
1134         prevbuffer = data;
1135
1136         // error out if a stretch is needed on special texture types
1137         if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1138                 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1139
1140         // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1141         // of the target size and then use the mipmap reduction function to get
1142         // high quality supersampled results
1143         for (width  = glt->tilewidth;width  < glt->inputwidth ;width  <<= 1);
1144         for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1145         for (depth  = glt->tiledepth;depth  < glt->inputdepth ;depth  <<= 1);
1146         R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1147
1148         if (prevbuffer == NULL)
1149         {
1150                 width = glt->tilewidth;
1151                 height = glt->tileheight;
1152                 depth = glt->tiledepth;
1153 //              memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1154 //              prevbuffer = resizebuffer;
1155         }
1156         else
1157         {
1158                 if (glt->textype->textype == TEXTYPE_PALETTE)
1159                 {
1160                         // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1161                         Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1162                         prevbuffer = colorconvertbuffer;
1163                 }
1164                 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1165                 {
1166                         // multiply RGB channels by A channel before uploading
1167                         int alpha;
1168                         for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1169                         {
1170                                 alpha = prevbuffer[i+3];
1171                                 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1172                                 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1173                                 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1174                                 colorconvertbuffer[i+3] = alpha;
1175                         }
1176                         prevbuffer = colorconvertbuffer;
1177                 }
1178                 // scale up to a power of 2 size (if appropriate)
1179                 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1180                 {
1181                         Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1182                         prevbuffer = resizebuffer;
1183                 }
1184                 // apply mipmap reduction algorithm to get down to picmip/max_size
1185                 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1186                 {
1187                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1188                         prevbuffer = resizebuffer;
1189                 }
1190         }
1191
1192         // do the appropriate upload type...
1193         switch(vid.renderpath)
1194         {
1195         case RENDERPATH_GL11:
1196         case RENDERPATH_GL13:
1197         case RENDERPATH_GL20:
1198         case RENDERPATH_GLES2:
1199                 CHECKGLERROR
1200
1201                 // we need to restore the texture binding after finishing the upload
1202                 GL_ActiveTexture(0);
1203                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1204                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1205
1206                 if (qglGetCompressedTexImageARB)
1207                 {
1208                         if (gl_texturecompression.integer >= 2)
1209                                 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1210                         else
1211                                 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1212                         CHECKGLERROR
1213                 }
1214                 switch(glt->texturetype)
1215                 {
1216                 case GLTEXTURETYPE_2D:
1217                         qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1218                         if (glt->flags & TEXF_MIPMAP)
1219                         {
1220                                 while (width > 1 || height > 1 || depth > 1)
1221                                 {
1222                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1223                                         prevbuffer = resizebuffer;
1224                                         qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1225                                 }
1226                         }
1227                         break;
1228                 case GLTEXTURETYPE_3D:
1229                         qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1230                         if (glt->flags & TEXF_MIPMAP)
1231                         {
1232                                 while (width > 1 || height > 1 || depth > 1)
1233                                 {
1234                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1235                                         prevbuffer = resizebuffer;
1236                                         qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1237                                 }
1238                         }
1239                         break;
1240                 case GLTEXTURETYPE_CUBEMAP:
1241                         // convert and upload each side in turn,
1242                         // from a continuous block of input texels
1243                         texturebuffer = (unsigned char *)prevbuffer;
1244                         for (i = 0;i < 6;i++)
1245                         {
1246                                 prevbuffer = texturebuffer;
1247                                 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1248                                 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1249                                 {
1250                                         Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1251                                         prevbuffer = resizebuffer;
1252                                 }
1253                                 // picmip/max_size
1254                                 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1255                                 {
1256                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1257                                         prevbuffer = resizebuffer;
1258                                 }
1259                                 mip = 0;
1260                                 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1261                                 if (glt->flags & TEXF_MIPMAP)
1262                                 {
1263                                         while (width > 1 || height > 1 || depth > 1)
1264                                         {
1265                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1266                                                 prevbuffer = resizebuffer;
1267                                                 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1268                                         }
1269                                 }
1270                         }
1271                         break;
1272                 }
1273                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1274                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1275                 break;
1276         case RENDERPATH_D3D9:
1277 #ifdef SUPPORTD3D
1278                 if (!(glt->flags & TEXF_RENDERTARGET))
1279                 {
1280                         D3DLOCKED_RECT d3dlockedrect;
1281                         D3DLOCKED_BOX d3dlockedbox;
1282                         switch(glt->texturetype)
1283                         {
1284                         case GLTEXTURETYPE_2D:
1285                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1286                                 {
1287                                         if (prevbuffer)
1288                                                 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1289                                         else
1290                                                 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1291                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1292                                 }
1293                                 mip++;
1294                                 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1295                                 {
1296                                         while (width > 1 || height > 1 || depth > 1)
1297                                         {
1298                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1299                                                 prevbuffer = resizebuffer;
1300                                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1301                                                 {
1302                                                         memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1303                                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1304                                                 }
1305                                                 mip++;
1306                                         }
1307                                 }
1308                                 break;
1309                         case GLTEXTURETYPE_3D:
1310                                 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1311                                 {
1312                                         // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1313                                         memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1314                                         IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1315                                 }
1316                                 mip++;
1317                                 if (glt->flags & TEXF_MIPMAP)
1318                                 {
1319                                         while (width > 1 || height > 1 || depth > 1)
1320                                         {
1321                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1322                                                 prevbuffer = resizebuffer;
1323                                                 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1324                                                 {
1325                                                         // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1326                                                         memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1327                                                         IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1328                                                 }
1329                                                 mip++;
1330                                         }
1331                                 }
1332                                 break;
1333                         case GLTEXTURETYPE_CUBEMAP:
1334                                 // convert and upload each side in turn,
1335                                 // from a continuous block of input texels
1336                                 texturebuffer = (unsigned char *)prevbuffer;
1337                                 for (i = 0;i < 6;i++)
1338                                 {
1339                                         prevbuffer = texturebuffer;
1340                                         texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1341                                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1342                                         {
1343                                                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1344                                                 prevbuffer = resizebuffer;
1345                                         }
1346                                         // picmip/max_size
1347                                         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1348                                         {
1349                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1350                                                 prevbuffer = resizebuffer;
1351                                         }
1352                                         mip = 0;
1353                                         if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1354                                         {
1355                                                 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1356                                                 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1357                                         }
1358                                         mip++;
1359                                         if (glt->flags & TEXF_MIPMAP)
1360                                         {
1361                                                 while (width > 1 || height > 1 || depth > 1)
1362                                                 {
1363                                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1364                                                         prevbuffer = resizebuffer;
1365                                                         if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1366                                                         {
1367                                                                 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1368                                                                 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1369                                                         }
1370                                                         mip++;
1371                                                 }
1372                                         }
1373                                 }
1374                                 break;
1375                         }
1376                 }
1377                 glt->d3daddressw = 0;
1378                 if (glt->flags & TEXF_CLAMP)
1379                 {
1380                         glt->d3daddressu = D3DTADDRESS_CLAMP;
1381                         glt->d3daddressv = D3DTADDRESS_CLAMP;
1382                         if (glt->tiledepth > 1)
1383                                 glt->d3daddressw = D3DTADDRESS_CLAMP;
1384                 }
1385                 else
1386                 {
1387                         glt->d3daddressu = D3DTADDRESS_WRAP;
1388                         glt->d3daddressv = D3DTADDRESS_WRAP;
1389                         if (glt->tiledepth > 1)
1390                                 glt->d3daddressw = D3DTADDRESS_WRAP;
1391                 }
1392                 glt->d3dmipmaplodbias = 0;
1393                 glt->d3dmaxmiplevel = 0;
1394                 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1395                 if (glt->flags & TEXF_FORCELINEAR)
1396                 {
1397                         glt->d3dminfilter = D3DTEXF_LINEAR;
1398                         glt->d3dmagfilter = D3DTEXF_LINEAR;
1399                         glt->d3dmipfilter = D3DTEXF_POINT;
1400                 }
1401                 else if (glt->flags & TEXF_FORCENEAREST)
1402                 {
1403                         glt->d3dminfilter = D3DTEXF_POINT;
1404                         glt->d3dmagfilter = D3DTEXF_POINT;
1405                         glt->d3dmipfilter = D3DTEXF_POINT;
1406                 }
1407                 else if (glt->flags & TEXF_MIPMAP)
1408                 {
1409                         glt->d3dminfilter = d3d_filter_mipmin;
1410                         glt->d3dmagfilter = d3d_filter_mipmag;
1411                         glt->d3dmipfilter = d3d_filter_mipmix;
1412                 }
1413                 else
1414                 {
1415                         glt->d3dminfilter = d3d_filter_flatmin;
1416                         glt->d3dmagfilter = d3d_filter_flatmag;
1417                         glt->d3dmipfilter = d3d_filter_flatmix;
1418                 }
1419 #endif
1420                 break;
1421         case RENDERPATH_D3D10:
1422                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1423                 break;
1424         case RENDERPATH_D3D11:
1425                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1426                 break;
1427         case RENDERPATH_SOFT:
1428                 switch(glt->texturetype)
1429                 {
1430                 case GLTEXTURETYPE_2D:
1431                         DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1432                         break;
1433                 case GLTEXTURETYPE_3D:
1434                         DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1435                         break;
1436                 case GLTEXTURETYPE_CUBEMAP:
1437                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1438                         {
1439                                 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1440                                 // convert and upload each side in turn,
1441                                 // from a continuous block of input texels
1442                                 // copy the results into combinedbuffer
1443                                 texturebuffer = (unsigned char *)prevbuffer;
1444                                 for (i = 0;i < 6;i++)
1445                                 {
1446                                         prevbuffer = texturebuffer;
1447                                         texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1448                                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1449                                         {
1450                                                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1451                                                 prevbuffer = resizebuffer;
1452                                         }
1453                                         // picmip/max_size
1454                                         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1455                                         {
1456                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1457                                                 prevbuffer = resizebuffer;
1458                                         }
1459                                         memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1460                                 }
1461                                 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1462                                 Mem_Free(combinedbuffer);
1463                         }
1464                         else
1465                                 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1466                         break;
1467                 }
1468                 if (glt->flags & TEXF_FORCELINEAR)
1469                         DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1470                 else if (glt->flags & TEXF_FORCENEAREST)
1471                         DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1472                 else if (glt->flags & TEXF_MIPMAP)
1473                         DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1474                 else
1475                         DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1476                 break;
1477         }
1478 }
1479
1480 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)
1481 {
1482         int i, size;
1483         gltexture_t *glt;
1484         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1485         textypeinfo_t *texinfo, *texinfo2;
1486         unsigned char *temppixels = NULL;
1487
1488         if (cls.state == ca_dedicated)
1489                 return NULL;
1490
1491         if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1492         {
1493                 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1494                 return NULL;
1495         }
1496         if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1497         {
1498                 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1499                 return NULL;
1500         }
1501
1502         texinfo = R_GetTexTypeInfo(textype, flags);
1503         size = width * height * depth * sides * texinfo->inputbytesperpixel;
1504         if (size < 1)
1505         {
1506                 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1507                 return NULL;
1508         }
1509
1510         if (textype == TEXTYPE_RGBA)
1511         {
1512                 // swap bytes
1513                 static int rgbaswapindices[4] = {2, 1, 0, 3};
1514                 textype = TEXTYPE_BGRA;
1515                 texinfo = R_GetTexTypeInfo(textype, flags);
1516                 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1517                 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1518                 data = temppixels;
1519         }
1520
1521         // clear the alpha flag if the texture has no transparent pixels
1522         switch(textype)
1523         {
1524         case TEXTYPE_PALETTE:
1525                 if (flags & TEXF_ALPHA)
1526                 {
1527                         flags &= ~TEXF_ALPHA;
1528                         if (data)
1529                         {
1530                                 for (i = 0;i < size;i++)
1531                                 {
1532                                         if (((unsigned char *)&palette[data[i]])[3] < 255)
1533                                         {
1534                                                 flags |= TEXF_ALPHA;
1535                                                 break;
1536                                         }
1537                                 }
1538                         }
1539                 }
1540                 break;
1541         case TEXTYPE_RGBA:
1542         case TEXTYPE_BGRA:
1543                 if (flags & TEXF_ALPHA)
1544                 {
1545                         flags &= ~TEXF_ALPHA;
1546                         if (data)
1547                         {
1548                                 for (i = 3;i < size;i += 4)
1549                                 {
1550                                         if (data[i] < 255)
1551                                         {
1552                                                 flags |= TEXF_ALPHA;
1553                                                 break;
1554                                         }
1555                                 }
1556                         }
1557                 }
1558                 break;
1559         case TEXTYPE_SHADOWMAP:
1560                 break;
1561         case TEXTYPE_DXT1:
1562                 break;
1563         case TEXTYPE_DXT1A:
1564         case TEXTYPE_DXT3:
1565         case TEXTYPE_DXT5:
1566                 flags |= TEXF_ALPHA;
1567                 break;
1568         case TEXTYPE_ALPHA:
1569                 flags |= TEXF_ALPHA;
1570                 break;
1571         case TEXTYPE_COLORBUFFER:
1572         case TEXTYPE_COLORBUFFER16F:
1573         case TEXTYPE_COLORBUFFER32F:
1574                 flags |= TEXF_ALPHA;
1575                 break;
1576         default:
1577                 Sys_Error("R_LoadTexture: unknown texture type");
1578         }
1579
1580         texinfo2 = R_GetTexTypeInfo(textype, flags);
1581         if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1582                 texinfo = texinfo2;
1583         else
1584                 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1585
1586         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1587         if (identifier)
1588                 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1589         glt->pool = pool;
1590         glt->chain = pool->gltchain;
1591         pool->gltchain = glt;
1592         glt->inputwidth = width;
1593         glt->inputheight = height;
1594         glt->inputdepth = depth;
1595         glt->flags = flags;
1596         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
1597         glt->textype = texinfo;
1598         glt->texturetype = texturetype;
1599         glt->inputdatasize = size;
1600         glt->palette = palette;
1601         glt->glinternalformat = texinfo->glinternalformat;
1602         glt->glformat = texinfo->glformat;
1603         glt->gltype = texinfo->gltype;
1604         glt->bytesperpixel = texinfo->internalbytesperpixel;
1605         glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1606         glt->texnum = 0;
1607         glt->dirty = false;
1608         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1609         // init the dynamic texture attributes, too [11/22/2007 Black]
1610         glt->updatecallback = NULL;
1611         glt->updatacallback_data = NULL;
1612
1613         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1614
1615         // upload the texture
1616         // data may be NULL (blank texture for dynamic rendering)
1617         switch(vid.renderpath)
1618         {
1619         case RENDERPATH_GL11:
1620         case RENDERPATH_GL13:
1621         case RENDERPATH_GL20:
1622         case RENDERPATH_GLES2:
1623                 CHECKGLERROR
1624                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1625                 break;
1626         case RENDERPATH_D3D9:
1627 #ifdef SUPPORTD3D
1628                 {
1629                         D3DFORMAT d3dformat;
1630                         D3DPOOL d3dpool;
1631                         DWORD d3dusage;
1632                         HRESULT d3dresult;
1633                         d3dusage = 0;
1634                         d3dpool = D3DPOOL_MANAGED;
1635                         if (flags & TEXF_RENDERTARGET)
1636                         {
1637                                 d3dusage |= D3DUSAGE_RENDERTARGET;
1638                                 d3dpool = D3DPOOL_DEFAULT;
1639                         }
1640                         switch(textype)
1641                         {
1642                         case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1643                         case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1644                         case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1645                         case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
1646                         case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
1647                         case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
1648                         case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1649                         case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1650                         default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1651                         }
1652                         glt->d3dformat = d3dformat;
1653                         glt->d3dusage = d3dusage;
1654                         glt->d3dpool = d3dpool;
1655                         glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1656                         if (glt->d3disdepthsurface)
1657                         {
1658                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1659                                         Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1660                         }
1661                         else if (glt->tiledepth > 1)
1662                         {
1663                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateVolumeTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->tiledepth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DVolumeTexture9 **)&glt->d3dtexture, NULL)))
1664                                         Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1665                         }
1666                         else if (glt->sides == 6)
1667                         {
1668                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1669                                         Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1670                         }
1671                         else
1672                         {
1673                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL)))
1674                                         Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1675                         }
1676                 }
1677 #endif
1678                 break;
1679         case RENDERPATH_D3D10:
1680                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1681                 break;
1682         case RENDERPATH_D3D11:
1683                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1684                 break;
1685         case RENDERPATH_SOFT:
1686                 {
1687                         int tflags = 0;
1688                         switch(textype)
1689                         {
1690                         case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1691                         case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1692                         case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1693                         case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1694                         case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
1695                         case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
1696                         case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1697                         case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1698                         default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1699                         }
1700                         if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1701                         if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1702                         if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1703                         if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1704                         glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1705                 }
1706                 break;
1707         }
1708
1709         R_UploadFullTexture(glt, data);
1710         if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1711                 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1712
1713         // free any temporary processing buffer we allocated...
1714         if (temppixels)
1715                 Mem_Free(temppixels);
1716
1717         // texture converting and uploading can take a while, so make sure we're sending keepalives
1718         // FIXME: this causes rendering during R_Shadow_DrawLights
1719 //      CL_KeepaliveMessage(false);
1720
1721         return (rtexture_t *)glt;
1722 }
1723
1724 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)
1725 {
1726         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1727 }
1728
1729 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)
1730 {
1731         return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1732 }
1733
1734 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)
1735 {
1736         return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1737 }
1738
1739 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1740 {
1741         int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1742         if (filter)
1743                 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1744         else
1745                 flags |= TEXF_FORCENEAREST;
1746         if (precision <= 16)
1747                 flags |= TEXF_LOWPRECISION;
1748         return flags;
1749 }
1750
1751 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1752 {
1753         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1754 }
1755
1756 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1757 {
1758         gltexture_t *glt = (gltexture_t *)rt;
1759         unsigned char *dds;
1760         int oldbindtexnum;
1761         int bytesperpixel = 0;
1762         int bytesperblock = 0;
1763         int dds_flags;
1764         int dds_format_flags;
1765         int dds_caps1;
1766         int dds_caps2;
1767         int ret;
1768         int mip;
1769         int mipmaps;
1770         int mipinfo[16][4];
1771         int ddssize = 128;
1772         GLint internalformat;
1773         const char *ddsfourcc;
1774         if (!rt)
1775                 return -1; // NULL pointer
1776         if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1777                 return -2; // broken driver - crashes on reading internal format
1778         if (!qglGetTexLevelParameteriv)
1779                 return -2;
1780         GL_ActiveTexture(0);
1781         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1782         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1783         qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1784         switch(internalformat)
1785         {
1786         default: ddsfourcc = NULL;bytesperpixel = 4;break;
1787         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1788         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1789         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1790         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1791         }
1792         // if premultiplied alpha, say so in the DDS file
1793         if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1794         {
1795                 switch(internalformat)
1796                 {
1797                         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1798                         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1799                 }
1800         }
1801         if (!bytesperblock && skipuncompressed)
1802                 return -3; // skipped
1803         memset(mipinfo, 0, sizeof(mipinfo));
1804         mipinfo[0][0] = glt->tilewidth;
1805         mipinfo[0][1] = glt->tileheight;
1806         mipmaps = 1;
1807         if (glt->flags & TEXF_MIPMAP)
1808         {
1809                 for (mip = 1;mip < 16;mip++)
1810                 {
1811                         mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1812                         mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1813                         if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1814                         {
1815                                 mip++;
1816                                 break;
1817                         }
1818                 }
1819                 mipmaps = mip;
1820         }
1821         for (mip = 0;mip < mipmaps;mip++)
1822         {
1823                 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1824                 mipinfo[mip][3] = ddssize;
1825                 ddssize += mipinfo[mip][2];
1826         }
1827         dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1828         if (!dds)
1829                 return -4;
1830         dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1831         dds_caps2 = 0;
1832         if (bytesperblock)
1833         {
1834                 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1835                 dds_format_flags = 0x4; // DDPF_FOURCC
1836         }
1837         else
1838         {
1839                 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1840                 dds_format_flags = 0x40; // DDPF_RGB
1841         }
1842         if (mipmaps)
1843         {
1844                 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1845                 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1846         }
1847         if(hasalpha)
1848                 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1849         memcpy(dds, "DDS ", 4);
1850         StoreLittleLong(dds+4, ddssize);
1851         StoreLittleLong(dds+8, dds_flags);
1852         StoreLittleLong(dds+12, mipinfo[0][1]); // height
1853         StoreLittleLong(dds+16, mipinfo[0][0]); // width
1854         StoreLittleLong(dds+24, 1); // depth
1855         StoreLittleLong(dds+28, mipmaps); // mipmaps
1856         StoreLittleLong(dds+76, 32); // format size
1857         StoreLittleLong(dds+80, dds_format_flags);
1858         StoreLittleLong(dds+108, dds_caps1);
1859         StoreLittleLong(dds+112, dds_caps2);
1860         if (bytesperblock)
1861         {
1862                 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1863                 memcpy(dds+84, ddsfourcc, 4);
1864                 for (mip = 0;mip < mipmaps;mip++)
1865                 {
1866                         qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1867                 }
1868         }
1869         else
1870         {
1871                 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1872                 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1873                 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1874                 for (mip = 0;mip < mipmaps;mip++)
1875                 {
1876                         qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1877                 }
1878         }
1879         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1880         ret = FS_WriteFile(filename, dds, ddssize);
1881         Mem_Free(dds);
1882         return ret ? ddssize : -5;
1883 }
1884
1885 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
1886 {
1887         int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1888         //int dds_flags;
1889         textype_t textype;
1890         int bytesperblock, bytesperpixel;
1891         int mipcomplete;
1892         gltexture_t *glt;
1893         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1894         textypeinfo_t *texinfo;
1895         int mip, mipwidth, mipheight, mipsize, mipsize_total;
1896         unsigned int c;
1897         GLint oldbindtexnum = 0;
1898         const unsigned char *mippixels, *ddspixels, *mippixels_start;
1899         unsigned char *dds;
1900         fs_offset_t ddsfilesize;
1901         unsigned int ddssize;
1902         qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
1903
1904         if (cls.state == ca_dedicated)
1905                 return NULL;
1906
1907         dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1908         ddssize = ddsfilesize;
1909
1910         if (!dds)
1911         {
1912                 if(r_texture_dds_load_logfailure.integer)
1913                         Log_Printf("ddstexturefailures.log", "%s\n", filename);
1914                 return NULL; // not found
1915         }
1916
1917         if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1918         {
1919                 Mem_Free(dds);
1920                 Con_Printf("^1%s: not a DDS image\n", filename);
1921                 return NULL;
1922         }
1923
1924         //dds_flags = BuffLittleLong(dds+8);
1925         dds_format_flags = BuffLittleLong(dds+80);
1926         dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1927         dds_width = BuffLittleLong(dds+16);
1928         dds_height = BuffLittleLong(dds+12);
1929         ddspixels = dds + 128;
1930
1931         if(r_texture_dds_load_alphamode.integer == 0)
1932                 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1933                         flags &= ~TEXF_ALPHA;
1934
1935         //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1936         if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1937         {
1938                 // very sloppy BGRA 32bit identification
1939                 textype = TEXTYPE_BGRA;
1940                 bytesperblock = 0;
1941                 bytesperpixel = 4;
1942                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1943                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1944                 {
1945                         Mem_Free(dds);
1946                         Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1947                         return NULL;
1948                 }
1949                 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1950                 {
1951                         // check alpha
1952                         for (i = 3;i < size;i += 4)
1953                                 if (ddspixels[i] < 255)
1954                                         break;
1955                         if (i >= size)
1956                                 flags &= ~TEXF_ALPHA;
1957                 }
1958         }
1959         else if (!memcmp(dds+84, "DXT1", 4))
1960         {
1961                 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1962                 // LordHavoc: it is my belief that this does not infringe on the
1963                 // patent because it is not decoding pixels...
1964                 textype = TEXTYPE_DXT1;
1965                 bytesperblock = 8;
1966                 bytesperpixel = 0;
1967                 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1968                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1969                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1970                 {
1971                         Mem_Free(dds);
1972                         Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1973                         return NULL;
1974                 }
1975                 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1976                 {
1977                         if(r_texture_dds_load_alphamode.integer == 1)
1978                         {
1979                                 // check alpha
1980                                 for (i = 0;i < size;i += bytesperblock)
1981                                         if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1982                                         {
1983                                                 // NOTE: this assumes sizeof(unsigned int) == 4
1984                                                 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1985                                                 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1986                                                 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1987                                                         break;
1988                                         }
1989                                 if (i < size)
1990                                         textype = TEXTYPE_DXT1A;
1991                                 else
1992                                         flags &= ~TEXF_ALPHA;
1993                         }
1994                         else
1995                         {
1996                                 flags &= ~TEXF_ALPHA;
1997                         }
1998                 }
1999         }
2000         else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2001         {
2002                 if(!memcmp(dds+84, "DXT2", 4))
2003                 {
2004                         if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2005                         {
2006                                 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2007                         }
2008                 }
2009                 else
2010                 {
2011                         if(flags & TEXF_RGBMULTIPLYBYALPHA)
2012                         {
2013                                 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2014                         }
2015                 }
2016                 textype = TEXTYPE_DXT3;
2017                 bytesperblock = 16;
2018                 bytesperpixel = 0;
2019                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2020                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2021                 {
2022                         Mem_Free(dds);
2023                         Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2024                         return NULL;
2025                 }
2026                 // we currently always assume alpha
2027         }
2028         else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2029         {
2030                 if(!memcmp(dds+84, "DXT4", 4))
2031                 {
2032                         if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2033                         {
2034                                 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2035                         }
2036                 }
2037                 else
2038                 {
2039                         if(flags & TEXF_RGBMULTIPLYBYALPHA)
2040                         {
2041                                 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2042                         }
2043                 }
2044                 textype = TEXTYPE_DXT5;
2045                 bytesperblock = 16;
2046                 bytesperpixel = 0;
2047                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2048                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2049                 {
2050                         Mem_Free(dds);
2051                         Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2052                         return NULL;
2053                 }
2054                 // we currently always assume alpha
2055         }
2056         else
2057         {
2058                 Mem_Free(dds);
2059                 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2060                 return NULL;
2061         }
2062
2063         force_swdecode = false;
2064         if(bytesperblock)
2065         {
2066                 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
2067                 {
2068                         if(r_texture_dds_swdecode.integer > 1)
2069                                 force_swdecode = true;
2070                 }
2071                 else
2072                 {
2073                         if(r_texture_dds_swdecode.integer < 1)
2074                         {
2075                                 // unsupported
2076                                 Mem_Free(dds);
2077                                 return NULL;
2078                         }
2079                         force_swdecode = true;
2080                 }
2081         }
2082
2083         // return whether this texture is transparent
2084         if (hasalphaflag)
2085                 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2086
2087         // if we SW decode, choose 2 sizes bigger
2088         if(force_swdecode)
2089         {
2090                 // this is quarter res, so do not scale down more than we have to
2091                 miplevel -= 2;
2092
2093                 if(miplevel < 0)
2094                         Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2095         }
2096
2097         // this is where we apply gl_picmip
2098         mippixels_start = ddspixels;
2099         mipwidth = dds_width;
2100         mipheight = dds_height;
2101         while(miplevel >= 1 && dds_miplevels >= 1)
2102         {
2103                 if (mipwidth <= 1 && mipheight <= 1)
2104                         break;
2105                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2106                 mippixels_start += mipsize; // just skip
2107                 --dds_miplevels;
2108                 --miplevel;
2109                 if (mipwidth > 1)
2110                         mipwidth >>= 1;
2111                 if (mipheight > 1)
2112                         mipheight >>= 1;
2113         }
2114         mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2115         mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2116
2117         // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2118
2119         // fake decode S3TC if needed
2120         if(force_swdecode)
2121         {
2122                 int mipsize_new = mipsize_total / bytesperblock * 4;
2123                 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2124                 unsigned char *p = mipnewpixels;
2125                 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2126                 {
2127                         c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2128                         p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2129                         p[1] = (((c >>  5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2130                         p[0] = (((c      ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2131                         if(textype == TEXTYPE_DXT5)
2132                                 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2133                         else if(textype == TEXTYPE_DXT3)
2134                                 p[3] = (
2135                                           (mippixels_start[i-8] & 0x0F)
2136                                         + (mippixels_start[i-8] >> 4)
2137                                         + (mippixels_start[i-7] & 0x0F)
2138                                         + (mippixels_start[i-7] >> 4)
2139                                         + (mippixels_start[i-6] & 0x0F)
2140                                         + (mippixels_start[i-6] >> 4)
2141                                         + (mippixels_start[i-5] & 0x0F)
2142                                         + (mippixels_start[i-5] >> 4)
2143                                        ) * (0.125f / 15.0f * 255.0f);
2144                         else
2145                                 p[3] = 255;
2146                 }
2147
2148                 textype = TEXTYPE_BGRA;
2149                 bytesperblock = 0;
2150                 bytesperpixel = 4;
2151
2152                 // as each block becomes a pixel, we must use pixel count for this
2153                 mipwidth = (mipwidth + 3) / 4;
2154                 mipheight = (mipheight + 3) / 4;
2155                 mipsize = bytesperpixel * mipwidth * mipheight;
2156                 mippixels_start = mipnewpixels;
2157                 mipsize_total = mipsize_new;
2158         }
2159
2160         // start mip counting
2161         mippixels = mippixels_start;
2162
2163         // calculate average color if requested
2164         if (avgcolor)
2165         {
2166                 float f;
2167                 Vector4Clear(avgcolor);
2168                 if (bytesperblock)
2169                 {
2170                         for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2171                         {
2172                                 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2173                                 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2174                                 avgcolor[1] += ((c >>  5) & 0x3F) + ((c >> 21) & 0x3F);
2175                                 avgcolor[2] += ((c      ) & 0x1F) + ((c >> 16) & 0x1F);
2176                                 if(textype == TEXTYPE_DXT5)
2177                                         avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2178                                 else if(textype == TEXTYPE_DXT3)
2179                                         avgcolor[3] += (
2180                                                   (mippixels_start[i-8] & 0x0F)
2181                                                 + (mippixels_start[i-8] >> 4)
2182                                                 + (mippixels_start[i-7] & 0x0F)
2183                                                 + (mippixels_start[i-7] >> 4)
2184                                                 + (mippixels_start[i-6] & 0x0F)
2185                                                 + (mippixels_start[i-6] >> 4)
2186                                                 + (mippixels_start[i-5] & 0x0F)
2187                                                 + (mippixels_start[i-5] >> 4)
2188                                                ) * (0.125f / 15.0f * 255.0f);
2189                                 else
2190                                         avgcolor[3] += 255;
2191                         }
2192                         f = (float)bytesperblock / size;
2193                         avgcolor[0] *= (0.5f / 31.0f) * f;
2194                         avgcolor[1] *= (0.5f / 63.0f) * f;
2195                         avgcolor[2] *= (0.5f / 31.0f) * f;
2196                         avgcolor[3] *= f;
2197                 }
2198                 else
2199                 {
2200                         for (i = 0;i < mipsize;i += 4)
2201                         {
2202                                 avgcolor[0] += mippixels[i+2];
2203                                 avgcolor[1] += mippixels[i+1];
2204                                 avgcolor[2] += mippixels[i];
2205                                 avgcolor[3] += mippixels[i+3];
2206                         }
2207                         f = (1.0f / 255.0f) * bytesperpixel / size;
2208                         avgcolor[0] *= f;
2209                         avgcolor[1] *= f;
2210                         avgcolor[2] *= f;
2211                         avgcolor[3] *= f;
2212                 }
2213         }
2214
2215         // when not requesting mipmaps, do not load them
2216         if(!(flags & TEXF_MIPMAP))
2217                 dds_miplevels = 0;
2218
2219         if (dds_miplevels >= 1)
2220                 flags |= TEXF_MIPMAP;
2221         else
2222                 flags &= ~TEXF_MIPMAP;
2223
2224         texinfo = R_GetTexTypeInfo(textype, flags);
2225
2226         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2227         strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2228         glt->pool = pool;
2229         glt->chain = pool->gltchain;
2230         pool->gltchain = glt;
2231         glt->inputwidth = mipwidth;
2232         glt->inputheight = mipheight;
2233         glt->inputdepth = 1;
2234         glt->flags = flags;
2235         glt->textype = texinfo;
2236         glt->texturetype = GLTEXTURETYPE_2D;
2237         glt->inputdatasize = ddssize;
2238         glt->glinternalformat = texinfo->glinternalformat;
2239         glt->glformat = texinfo->glformat;
2240         glt->gltype = texinfo->gltype;
2241         glt->bytesperpixel = texinfo->internalbytesperpixel;
2242         glt->sides = 1;
2243         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2244         glt->tilewidth = mipwidth;
2245         glt->tileheight = mipheight;
2246         glt->tiledepth = 1;
2247         glt->miplevels = dds_miplevels;
2248
2249         // texture uploading can take a while, so make sure we're sending keepalives
2250         CL_KeepaliveMessage(false);
2251
2252         // create the texture object
2253         switch(vid.renderpath)
2254         {
2255         case RENDERPATH_GL11:
2256         case RENDERPATH_GL13:
2257         case RENDERPATH_GL20:
2258         case RENDERPATH_GLES2:
2259                 CHECKGLERROR
2260                 GL_ActiveTexture(0);
2261                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2262                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2263                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2264                 break;
2265         case RENDERPATH_D3D9:
2266 #ifdef SUPPORTD3D
2267                 {
2268                         D3DFORMAT d3dformat;
2269                         D3DPOOL d3dpool;
2270                         DWORD d3dusage;
2271                         switch(textype)
2272                         {
2273                         case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2274                         case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2275                         case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2276                         case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2277                         default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2278                         }
2279                         d3dusage = 0;
2280                         d3dpool = D3DPOOL_MANAGED;
2281                         IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2282                 }
2283 #endif
2284                 break;
2285         case RENDERPATH_D3D10:
2286                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2287                 break;
2288         case RENDERPATH_D3D11:
2289                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2290                 break;
2291         case RENDERPATH_SOFT:
2292                 glt->texnum = DPSOFTRAST_Texture_New(((glt->flags & TEXF_CLAMP) ? DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE : 0) | (dds_miplevels > 1 ? DPSOFTRAST_TEXTURE_FLAG_MIPMAP : 0), glt->tilewidth, glt->tileheight, glt->tiledepth);
2293                 break;
2294         }
2295
2296         // upload the texture
2297         // we need to restore the texture binding after finishing the upload
2298         mipcomplete = false;
2299
2300         for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2301         {
2302                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2303                 if (mippixels + mipsize > mippixels_start + mipsize_total)
2304                         break;
2305                 switch(vid.renderpath)
2306                 {
2307                 case RENDERPATH_GL11:
2308                 case RENDERPATH_GL13:
2309                 case RENDERPATH_GL20:
2310                 case RENDERPATH_GLES2:
2311                         if (bytesperblock)
2312                         {
2313                                 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2314                         }
2315                         else
2316                         {
2317                                 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2318                         }
2319                         break;
2320                 case RENDERPATH_D3D9:
2321 #ifdef SUPPORTD3D
2322                         {
2323                                 D3DLOCKED_RECT d3dlockedrect;
2324                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2325                                 {
2326                                         memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2327                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2328                                 }
2329                                 break;
2330                         }
2331 #endif
2332                         break;
2333                 case RENDERPATH_D3D10:
2334                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2335                         break;
2336                 case RENDERPATH_D3D11:
2337                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2338                         break;
2339                 case RENDERPATH_SOFT:
2340                         if (bytesperblock)
2341                                 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2342                         else
2343                                 DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
2344                         // DPSOFTRAST calculates its own mipmaps
2345                         mip = dds_miplevels;
2346                         break;
2347                 }
2348                 mippixels += mipsize;
2349                 if (mipwidth <= 1 && mipheight <= 1)
2350                 {
2351                         mipcomplete = true;
2352                         break;
2353                 }
2354                 if (mipwidth > 1)
2355                         mipwidth >>= 1;
2356                 if (mipheight > 1)
2357                         mipheight >>= 1;
2358         }
2359
2360         // after upload we have to set some parameters...
2361         switch(vid.renderpath)
2362         {
2363         case RENDERPATH_GL11:
2364         case RENDERPATH_GL13:
2365         case RENDERPATH_GL20:
2366         case RENDERPATH_GLES2:
2367                 if (dds_miplevels >= 1 && !mipcomplete)
2368                 {
2369                         // need to set GL_TEXTURE_MAX_LEVEL
2370                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2371                 }
2372                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2373                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2374                 break;
2375         case RENDERPATH_D3D9:
2376 #ifdef SUPPORTD3D
2377                 glt->d3daddressw = 0;
2378                 if (glt->flags & TEXF_CLAMP)
2379                 {
2380                         glt->d3daddressu = D3DTADDRESS_CLAMP;
2381                         glt->d3daddressv = D3DTADDRESS_CLAMP;
2382                         if (glt->tiledepth > 1)
2383                                 glt->d3daddressw = D3DTADDRESS_CLAMP;
2384                 }
2385                 else
2386                 {
2387                         glt->d3daddressu = D3DTADDRESS_WRAP;
2388                         glt->d3daddressv = D3DTADDRESS_WRAP;
2389                         if (glt->tiledepth > 1)
2390                                 glt->d3daddressw = D3DTADDRESS_WRAP;
2391                 }
2392                 glt->d3dmipmaplodbias = 0;
2393                 glt->d3dmaxmiplevel = 0;
2394                 glt->d3dmaxmiplevelfilter = 0;
2395                 if (glt->flags & TEXF_MIPMAP)
2396                 {
2397                         glt->d3dminfilter = d3d_filter_mipmin;
2398                         glt->d3dmagfilter = d3d_filter_mipmag;
2399                         glt->d3dmipfilter = d3d_filter_mipmix;
2400                 }
2401                 else
2402                 {
2403                         glt->d3dminfilter = d3d_filter_flatmin;
2404                         glt->d3dmagfilter = d3d_filter_flatmag;
2405                         glt->d3dmipfilter = d3d_filter_flatmix;
2406                 }
2407 #endif
2408                 break;
2409         case RENDERPATH_D3D10:
2410                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2411                 break;
2412         case RENDERPATH_D3D11:
2413                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2414                 break;
2415         case RENDERPATH_SOFT:
2416                 if (glt->flags & TEXF_FORCELINEAR)
2417                         DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2418                 else if (glt->flags & TEXF_FORCENEAREST)
2419                         DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2420                 else if (glt->flags & TEXF_MIPMAP)
2421                         DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2422                 else
2423                         DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2424                 break;
2425         }
2426
2427         Mem_Free(dds);
2428         if(force_swdecode)
2429                 Mem_Free((unsigned char *) mippixels_start);
2430         return (rtexture_t *)glt;
2431 }
2432
2433 int R_TextureWidth(rtexture_t *rt)
2434 {
2435         return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2436 }
2437
2438 int R_TextureHeight(rtexture_t *rt)
2439 {
2440         return rt ? ((gltexture_t *)rt)->inputheight : 0;
2441 }
2442
2443 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2444 {
2445         gltexture_t *glt = (gltexture_t *)rt;
2446         if (data == NULL)
2447                 Host_Error("R_UpdateTexture: no data supplied");
2448         if (glt == NULL)
2449                 Host_Error("R_UpdateTexture: no texture supplied");
2450         if (!glt->texnum && !glt->d3dtexture)
2451         {
2452                 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2453                 return;
2454         }
2455         // update part of the texture
2456         if (glt->bufferpixels)
2457         {
2458                 int j;
2459                 int bpp = glt->bytesperpixel;
2460                 int inputskip = width*bpp;
2461                 int outputskip = glt->tilewidth*bpp;
2462                 const unsigned char *input = data;
2463                 unsigned char *output = glt->bufferpixels;
2464                 if (glt->inputdepth != 1 || glt->sides != 1)
2465                         Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2466                 if (x < 0)
2467                 {
2468                         width += x;
2469                         input -= x*bpp;
2470                         x = 0;
2471                 }
2472                 if (y < 0)
2473                 {
2474                         height += y;
2475                         input -= y*inputskip;
2476                         y = 0;
2477                 }
2478                 if (width > glt->tilewidth - x)
2479                         width = glt->tilewidth - x;
2480                 if (height > glt->tileheight - y)
2481                         height = glt->tileheight - y;
2482                 if (width < 1 || height < 1)
2483                         return;
2484                 glt->dirty = true;
2485                 glt->buffermodified = true;
2486                 output += y*outputskip + x*bpp;
2487                 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2488                         memcpy(output, input, width*bpp);
2489         }
2490         else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2491                 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2492         else
2493                 R_UploadFullTexture(glt, data);
2494 }
2495
2496 int R_RealGetTexture(rtexture_t *rt)
2497 {
2498         if (rt)
2499         {
2500                 gltexture_t *glt;
2501                 glt = (gltexture_t *)rt;
2502                 if (glt->flags & GLTEXF_DYNAMIC)
2503                         R_UpdateDynamicTexture(glt);
2504                 if (glt->buffermodified && glt->bufferpixels)
2505                 {
2506                         glt->buffermodified = false;
2507                         R_UploadFullTexture(glt, glt->bufferpixels);
2508                 }
2509                 glt->dirty = false;
2510                 return glt->texnum;
2511         }
2512         else
2513                 return 0;
2514 }
2515
2516 void R_ClearTexture (rtexture_t *rt)
2517 {
2518         gltexture_t *glt = (gltexture_t *)rt;
2519
2520         R_UploadFullTexture(glt, NULL);
2521 }
2522
2523 int R_PicmipForFlags(int flags)
2524 {
2525         int miplevel = 0;
2526         if(flags & TEXF_PICMIP)
2527         {
2528                 miplevel += gl_picmip.integer;
2529                 if (flags & TEXF_ISWORLD)
2530                 {
2531                         if (r_picmipworld.integer)
2532                                 miplevel += gl_picmip_world.integer;
2533                         else
2534                                 miplevel = 0;
2535                 }
2536                 else if (flags & TEXF_ISSPRITE)
2537                 {
2538                         if (r_picmipsprites.integer)
2539                                 miplevel += gl_picmip_sprites.integer;
2540                         else
2541                                 miplevel = 0;
2542                 }
2543                 else
2544                         miplevel += gl_picmip_other.integer;
2545         }
2546         return max(0, miplevel);
2547 }