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