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