]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_textures.c
upload NULL textures as NULL textures, rather than creating a big array
[xonotic/darkplaces.git] / gl_textures.c
1
2 #include "quakedef.h"
3 #ifdef SUPPORTD3D
4 #include <d3d9.h>
5 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
6 #endif
7 #include "image.h"
8 #include "jpeg.h"
9 #include "image_png.h"
10 #include "intoverflow.h"
11 #include "dpsoftrast.h"
12
13 cvar_t gl_max_size = {CVAR_SAVE, "gl_max_size", "2048", "maximum allowed texture size, can be used to reduce video memory usage, limited by hardware capabilities (typically 2048, 4096, or 8192)"};
14 cvar_t gl_max_lightmapsize = {CVAR_SAVE, "gl_max_lightmapsize", "1024", "maximum allowed texture size for lightmap textures, use larger values to improve rendering speed, as long as there is enough video memory available (setting it too high for the hardware will cause very bad performance)"};
15 cvar_t gl_picmip = {CVAR_SAVE, "gl_picmip", "0", "reduces resolution of textures by powers of 2, for example 1 will halve width/height, reducing texture memory usage by 75%"};
16 cvar_t gl_picmip_world = {CVAR_SAVE, "gl_picmip_world", "0", "extra picmip level for world textures (may be negative, which will then reduce gl_picmip for these)"};
17 cvar_t r_picmipworld = {CVAR_SAVE, "r_picmipworld", "1", "whether gl_picmip shall apply to world textures too (setting this to 0 is a shorthand for gl_picmip_world -9999999)"};
18 cvar_t gl_picmip_sprites = {CVAR_SAVE, "gl_picmip_sprites", "0", "extra picmip level for sprite textures (may be negative, which will then reduce gl_picmip for these)"};
19 cvar_t r_picmipsprites = {CVAR_SAVE, "r_picmipsprites", "1", "make gl_picmip affect sprites too (saves some graphics memory in sprite heavy games) (setting this to 0 is a shorthand for gl_picmip_sprites -9999999)"};
20 cvar_t gl_picmip_other = {CVAR_SAVE, "gl_picmip_other", "0", "extra picmip level for other textures (may be negative, which will then reduce gl_picmip for these)"};
21 cvar_t r_lerpimages = {CVAR_SAVE, "r_lerpimages", "1", "bilinear filters images when scaling them up to power of 2 size (mode 1), looks better than glquake (mode 0)"};
22 cvar_t gl_texture_anisotropy = {CVAR_SAVE, "gl_texture_anisotropy", "1", "anisotropic filtering quality (if supported by hardware), 1 sample (no anisotropy) and 8 sample (8 tap anisotropy) are recommended values"};
23 cvar_t gl_texturecompression = {CVAR_SAVE, "gl_texturecompression", "0", "whether to compress textures, a value of 0 disables compression (even if the individual cvars are 1), 1 enables fast (low quality) compression at startup, 2 enables slow (high quality) compression at startup"};
24 cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
25 cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
26 cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
27 cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
28 cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
29 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
30 cvar_t gl_texturecompression_q3bspdeluxemaps = {CVAR_SAVE, "gl_texturecompression_q3bspdeluxemaps", "0", "whether to compress deluxemaps in q3bsp format levels (only levels compiled with q3map2 -deluxe have these)"};
31 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
32 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
33 cvar_t gl_texturecompression_reflectmask = {CVAR_SAVE, "gl_texturecompression_reflectmask", "1", "whether to compress reflection cubemap masks (mask of which areas of the texture should reflect the generic shiny cubemap)"};
34 cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "0", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"};
35 cvar_t r_texture_dds_load_alphamode = {0, "r_texture_dds_load_alphamode", "1", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambiguous, 2: texture format only"};
36 cvar_t r_texture_dds_load_logfailure = {0, "r_texture_dds_load_logfailure", "1", "log missing DDS textures to ddstexturefailures.log"};
37 cvar_t r_texture_dds_swdecode = {0, "r_texture_dds_swdecode", "0", "0: don't software decode DDS, 1: software decode DDS if unsupported, 2: always software decode DDS"};
38
39 qboolean        gl_filter_force = false;
40 int             gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
41 int             gl_filter_mag = GL_LINEAR;
42 DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_mipmap = DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE;
43 DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_nomipmap = DPSOFTRAST_TEXTURE_FILTER_LINEAR;
44
45 #ifdef SUPPORTD3D
46 int d3d_filter_flatmin = D3DTEXF_LINEAR;
47 int d3d_filter_flatmag = D3DTEXF_LINEAR;
48 int d3d_filter_flatmix = D3DTEXF_POINT;
49 int d3d_filter_mipmin = D3DTEXF_LINEAR;
50 int d3d_filter_mipmag = D3DTEXF_LINEAR;
51 int d3d_filter_mipmix = D3DTEXF_LINEAR;
52 int d3d_filter_nomip = false;
53 #endif
54
55
56 static mempool_t *texturemempool;
57 static memexpandablearray_t texturearray;
58
59 // note: this must not conflict with TEXF_ flags in r_textures.h
60 // bitmask for mismatch checking
61 #define GLTEXF_IMPORTANTBITS (0)
62 // dynamic texture (treat texnum == 0 differently)
63 #define GLTEXF_DYNAMIC          0x00080000
64
65 typedef struct textypeinfo_s
66 {
67         textype_t textype;
68         int inputbytesperpixel;
69         int internalbytesperpixel;
70         float glinternalbytesperpixel;
71         int glinternalformat;
72         int glformat;
73         int gltype;
74 }
75 textypeinfo_t;
76
77
78 static textypeinfo_t textype_palette                = {TEXTYPE_PALETTE    , 1, 4, 4.0f, GL_RGBA                         , GL_BGRA           , GL_UNSIGNED_BYTE };
79 static textypeinfo_t textype_palette_alpha          = {TEXTYPE_PALETTE    , 1, 4, 4.0f, GL_RGBA                         , GL_BGRA           , GL_UNSIGNED_BYTE };
80 static textypeinfo_t textype_rgba                   = {TEXTYPE_RGBA       , 4, 4, 4.0f, GL_RGBA                         , GL_RGBA           , GL_UNSIGNED_BYTE };
81 static textypeinfo_t textype_rgba_alpha             = {TEXTYPE_RGBA       , 4, 4, 4.0f, GL_RGBA                         , GL_RGBA           , GL_UNSIGNED_BYTE };
82 static textypeinfo_t textype_rgba_compress          = {TEXTYPE_RGBA       , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA           , GL_UNSIGNED_BYTE };
83 static textypeinfo_t textype_rgba_alpha_compress    = {TEXTYPE_RGBA       , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA           , GL_UNSIGNED_BYTE };
84 static textypeinfo_t textype_bgra                   = {TEXTYPE_BGRA       , 4, 4, 4.0f, GL_RGBA                         , GL_BGRA           , GL_UNSIGNED_BYTE };
85 static textypeinfo_t textype_bgra_alpha             = {TEXTYPE_BGRA       , 4, 4, 4.0f, GL_RGBA                         , GL_BGRA           , GL_UNSIGNED_BYTE };
86 static textypeinfo_t textype_bgra_compress          = {TEXTYPE_BGRA       , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA           , GL_UNSIGNED_BYTE };
87 static textypeinfo_t textype_bgra_alpha_compress    = {TEXTYPE_BGRA       , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_BGRA           , GL_UNSIGNED_BYTE };
88 static textypeinfo_t textype_shadowmap16            = {TEXTYPE_SHADOWMAP  , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB        , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
89 static textypeinfo_t textype_shadowmap24            = {TEXTYPE_SHADOWMAP  , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB        , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
90 static textypeinfo_t textype_alpha                  = {TEXTYPE_ALPHA      , 1, 4, 4.0f, GL_ALPHA                        , GL_ALPHA          , GL_UNSIGNED_BYTE };
91 static textypeinfo_t textype_dxt1                   = {TEXTYPE_DXT1       , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0                 , 0                };
92 static textypeinfo_t textype_dxt1a                  = {TEXTYPE_DXT1A      , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0                 , 0                };
93 static textypeinfo_t textype_dxt3                   = {TEXTYPE_DXT3       , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0                 , 0                };
94 static textypeinfo_t textype_dxt5                   = {TEXTYPE_DXT5       , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0                 , 0                };
95 static textypeinfo_t textype_colorbuffer            = {TEXTYPE_COLORBUFFER, 4, 4, 4.0f, GL_RGBA                         , GL_BGRA           , GL_UNSIGNED_BYTE };
96
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
1151         {
1152                 if (glt->textype->textype == TEXTYPE_PALETTE)
1153                 {
1154                         // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1155                         Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1156                         prevbuffer = colorconvertbuffer;
1157                 }
1158                 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1159                 {
1160                         // multiply RGB channels by A channel before uploading
1161                         int alpha;
1162                         for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1163                         {
1164                                 alpha = prevbuffer[i+3];
1165                                 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1166                                 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1167                                 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1168                                 colorconvertbuffer[i+3] = alpha;
1169                         }
1170                         prevbuffer = colorconvertbuffer;
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
1186         // do the appropriate upload type...
1187         switch(vid.renderpath)
1188         {
1189         case RENDERPATH_GL11:
1190         case RENDERPATH_GL13:
1191         case RENDERPATH_GL20:
1192         case RENDERPATH_GLES2:
1193                 CHECKGLERROR
1194
1195                 // we need to restore the texture binding after finishing the upload
1196                 GL_ActiveTexture(0);
1197                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1198                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1199
1200                 if (qglGetCompressedTexImageARB)
1201                 {
1202                         if (gl_texturecompression.integer >= 2)
1203                                 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1204                         else
1205                                 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1206                         CHECKGLERROR
1207                 }
1208                 switch(glt->texturetype)
1209                 {
1210                 case GLTEXTURETYPE_2D:
1211                         qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1212                         if (glt->flags & TEXF_MIPMAP)
1213                         {
1214                                 while (width > 1 || height > 1 || depth > 1)
1215                                 {
1216                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1217                                         prevbuffer = resizebuffer;
1218                                         qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1219                                 }
1220                         }
1221                         break;
1222                 case GLTEXTURETYPE_3D:
1223                         qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1224                         if (glt->flags & TEXF_MIPMAP)
1225                         {
1226                                 while (width > 1 || height > 1 || depth > 1)
1227                                 {
1228                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1229                                         prevbuffer = resizebuffer;
1230                                         qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1231                                 }
1232                         }
1233                         break;
1234                 case GLTEXTURETYPE_CUBEMAP:
1235                         // convert and upload each side in turn,
1236                         // from a continuous block of input texels
1237                         texturebuffer = (unsigned char *)prevbuffer;
1238                         for (i = 0;i < 6;i++)
1239                         {
1240                                 prevbuffer = texturebuffer;
1241                                 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1242                                 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1243                                 {
1244                                         Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1245                                         prevbuffer = resizebuffer;
1246                                 }
1247                                 // picmip/max_size
1248                                 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1249                                 {
1250                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1251                                         prevbuffer = resizebuffer;
1252                                 }
1253                                 mip = 0;
1254                                 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1255                                 if (glt->flags & TEXF_MIPMAP)
1256                                 {
1257                                         while (width > 1 || height > 1 || depth > 1)
1258                                         {
1259                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1260                                                 prevbuffer = resizebuffer;
1261                                                 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1262                                         }
1263                                 }
1264                         }
1265                         break;
1266                 }
1267                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1268                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1269                 break;
1270         case RENDERPATH_D3D9:
1271 #ifdef SUPPORTD3D
1272                 if (!(glt->flags & TEXF_RENDERTARGET))
1273                 {
1274                         D3DLOCKED_RECT d3dlockedrect;
1275                         D3DLOCKED_BOX d3dlockedbox;
1276                         switch(glt->texturetype)
1277                         {
1278                         case GLTEXTURETYPE_2D:
1279                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1280                                 {
1281                                         if (prevbuffer)
1282                                                 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1283                                         else
1284                                                 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1285                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1286                                 }
1287                                 mip++;
1288                                 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1289                                 {
1290                                         while (width > 1 || height > 1 || depth > 1)
1291                                         {
1292                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1293                                                 prevbuffer = resizebuffer;
1294                                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1295                                                 {
1296                                                         memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1297                                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1298                                                 }
1299                                                 mip++;
1300                                         }
1301                                 }
1302                                 break;
1303                         case GLTEXTURETYPE_3D:
1304                                 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1305                                 {
1306                                         // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1307                                         memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1308                                         IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1309                                 }
1310                                 mip++;
1311                                 if (glt->flags & TEXF_MIPMAP)
1312                                 {
1313                                         while (width > 1 || height > 1 || depth > 1)
1314                                         {
1315                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1316                                                 prevbuffer = resizebuffer;
1317                                                 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1318                                                 {
1319                                                         // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1320                                                         memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1321                                                         IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1322                                                 }
1323                                                 mip++;
1324                                         }
1325                                 }
1326                                 break;
1327                         case GLTEXTURETYPE_CUBEMAP:
1328                                 // convert and upload each side in turn,
1329                                 // from a continuous block of input texels
1330                                 texturebuffer = (unsigned char *)prevbuffer;
1331                                 for (i = 0;i < 6;i++)
1332                                 {
1333                                         prevbuffer = texturebuffer;
1334                                         texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1335                                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1336                                         {
1337                                                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1338                                                 prevbuffer = resizebuffer;
1339                                         }
1340                                         // picmip/max_size
1341                                         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1342                                         {
1343                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1344                                                 prevbuffer = resizebuffer;
1345                                         }
1346                                         mip = 0;
1347                                         if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1348                                         {
1349                                                 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1350                                                 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1351                                         }
1352                                         mip++;
1353                                         if (glt->flags & TEXF_MIPMAP)
1354                                         {
1355                                                 while (width > 1 || height > 1 || depth > 1)
1356                                                 {
1357                                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1358                                                         prevbuffer = resizebuffer;
1359                                                         if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1360                                                         {
1361                                                                 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1362                                                                 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1363                                                         }
1364                                                         mip++;
1365                                                 }
1366                                         }
1367                                 }
1368                                 break;
1369                         }
1370                 }
1371                 glt->d3daddressw = 0;
1372                 if (glt->flags & TEXF_CLAMP)
1373                 {
1374                         glt->d3daddressu = D3DTADDRESS_CLAMP;
1375                         glt->d3daddressv = D3DTADDRESS_CLAMP;
1376                         if (glt->tiledepth > 1)
1377                                 glt->d3daddressw = D3DTADDRESS_CLAMP;
1378                 }
1379                 else
1380                 {
1381                         glt->d3daddressu = D3DTADDRESS_WRAP;
1382                         glt->d3daddressv = D3DTADDRESS_WRAP;
1383                         if (glt->tiledepth > 1)
1384                                 glt->d3daddressw = D3DTADDRESS_WRAP;
1385                 }
1386                 glt->d3dmipmaplodbias = 0;
1387                 glt->d3dmaxmiplevel = 0;
1388                 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1389                 if (glt->flags & TEXF_FORCELINEAR)
1390                 {
1391                         glt->d3dminfilter = D3DTEXF_LINEAR;
1392                         glt->d3dmagfilter = D3DTEXF_LINEAR;
1393                         glt->d3dmipfilter = D3DTEXF_POINT;
1394                 }
1395                 else if (glt->flags & TEXF_FORCENEAREST)
1396                 {
1397                         glt->d3dminfilter = D3DTEXF_POINT;
1398                         glt->d3dmagfilter = D3DTEXF_POINT;
1399                         glt->d3dmipfilter = D3DTEXF_POINT;
1400                 }
1401                 else if (glt->flags & TEXF_MIPMAP)
1402                 {
1403                         glt->d3dminfilter = d3d_filter_mipmin;
1404                         glt->d3dmagfilter = d3d_filter_mipmag;
1405                         glt->d3dmipfilter = d3d_filter_mipmix;
1406                 }
1407                 else
1408                 {
1409                         glt->d3dminfilter = d3d_filter_flatmin;
1410                         glt->d3dmagfilter = d3d_filter_flatmag;
1411                         glt->d3dmipfilter = d3d_filter_flatmix;
1412                 }
1413 #endif
1414                 break;
1415         case RENDERPATH_D3D10:
1416                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1417                 break;
1418         case RENDERPATH_D3D11:
1419                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1420                 break;
1421         case RENDERPATH_SOFT:
1422                 switch(glt->texturetype)
1423                 {
1424                 case GLTEXTURETYPE_2D:
1425                         DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1426                         break;
1427                 case GLTEXTURETYPE_3D:
1428                         DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1429                         break;
1430                 case GLTEXTURETYPE_CUBEMAP:
1431                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1432                         {
1433                                 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1434                                 // convert and upload each side in turn,
1435                                 // from a continuous block of input texels
1436                                 // copy the results into combinedbuffer
1437                                 texturebuffer = (unsigned char *)prevbuffer;
1438                                 for (i = 0;i < 6;i++)
1439                                 {
1440                                         prevbuffer = texturebuffer;
1441                                         texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1442                                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1443                                         {
1444                                                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1445                                                 prevbuffer = resizebuffer;
1446                                         }
1447                                         // picmip/max_size
1448                                         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1449                                         {
1450                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1451                                                 prevbuffer = resizebuffer;
1452                                         }
1453                                         memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1454                                 }
1455                                 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1456                                 Mem_Free(combinedbuffer);
1457                         }
1458                         else
1459                                 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1460                         break;
1461                 }
1462                 if (glt->flags & TEXF_FORCELINEAR)
1463                         DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1464                 else if (glt->flags & TEXF_FORCENEAREST)
1465                         DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1466                 else if (glt->flags & TEXF_MIPMAP)
1467                         DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1468                 else
1469                         DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1470                 break;
1471         }
1472 }
1473
1474 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)
1475 {
1476         int i, size;
1477         gltexture_t *glt;
1478         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1479         textypeinfo_t *texinfo, *texinfo2;
1480         unsigned char *temppixels = NULL;
1481
1482         if (cls.state == ca_dedicated)
1483                 return NULL;
1484
1485         if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1486         {
1487                 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1488                 return NULL;
1489         }
1490         if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1491         {
1492                 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1493                 return NULL;
1494         }
1495
1496         texinfo = R_GetTexTypeInfo(textype, flags);
1497         size = width * height * depth * sides * texinfo->inputbytesperpixel;
1498         if (size < 1)
1499         {
1500                 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1501                 return NULL;
1502         }
1503
1504         if (textype == TEXTYPE_RGBA)
1505         {
1506                 // swap bytes
1507                 static int rgbaswapindices[4] = {2, 1, 0, 3};
1508                 textype = TEXTYPE_BGRA;
1509                 texinfo = R_GetTexTypeInfo(textype, flags);
1510                 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1511                 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1512                 data = temppixels;
1513         }
1514
1515         // clear the alpha flag if the texture has no transparent pixels
1516         switch(textype)
1517         {
1518         case TEXTYPE_PALETTE:
1519                 if (flags & TEXF_ALPHA)
1520                 {
1521                         flags &= ~TEXF_ALPHA;
1522                         if (data)
1523                         {
1524                                 for (i = 0;i < size;i++)
1525                                 {
1526                                         if (((unsigned char *)&palette[data[i]])[3] < 255)
1527                                         {
1528                                                 flags |= TEXF_ALPHA;
1529                                                 break;
1530                                         }
1531                                 }
1532                         }
1533                 }
1534                 break;
1535         case TEXTYPE_RGBA:
1536         case TEXTYPE_BGRA:
1537                 if (flags & TEXF_ALPHA)
1538                 {
1539                         flags &= ~TEXF_ALPHA;
1540                         if (data)
1541                         {
1542                                 for (i = 3;i < size;i += 4)
1543                                 {
1544                                         if (data[i] < 255)
1545                                         {
1546                                                 flags |= TEXF_ALPHA;
1547                                                 break;
1548                                         }
1549                                 }
1550                         }
1551                 }
1552                 break;
1553         case TEXTYPE_SHADOWMAP:
1554                 break;
1555         case TEXTYPE_DXT1:
1556                 break;
1557         case TEXTYPE_DXT1A:
1558         case TEXTYPE_DXT3:
1559         case TEXTYPE_DXT5:
1560                 flags |= TEXF_ALPHA;
1561                 break;
1562         case TEXTYPE_ALPHA:
1563                 flags |= TEXF_ALPHA;
1564                 break;
1565         case TEXTYPE_COLORBUFFER:
1566                 flags |= TEXF_ALPHA;
1567                 break;
1568         default:
1569                 Sys_Error("R_LoadTexture: unknown texture type");
1570         }
1571
1572         texinfo2 = R_GetTexTypeInfo(textype, flags);
1573         if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1574                 texinfo = texinfo2;
1575         else
1576                 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1577
1578         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1579         if (identifier)
1580                 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1581         glt->pool = pool;
1582         glt->chain = pool->gltchain;
1583         pool->gltchain = glt;
1584         glt->inputwidth = width;
1585         glt->inputheight = height;
1586         glt->inputdepth = depth;
1587         glt->flags = flags;
1588         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
1589         glt->textype = texinfo;
1590         glt->texturetype = texturetype;
1591         glt->inputdatasize = size;
1592         glt->palette = palette;
1593         glt->glinternalformat = texinfo->glinternalformat;
1594         glt->glformat = texinfo->glformat;
1595         glt->gltype = texinfo->gltype;
1596         glt->bytesperpixel = texinfo->internalbytesperpixel;
1597         glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1598         glt->texnum = 0;
1599         glt->dirty = false;
1600         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1601         // init the dynamic texture attributes, too [11/22/2007 Black]
1602         glt->updatecallback = NULL;
1603         glt->updatacallback_data = NULL;
1604
1605         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1606
1607         // upload the texture
1608         // data may be NULL (blank texture for dynamic rendering)
1609         switch(vid.renderpath)
1610         {
1611         case RENDERPATH_GL11:
1612         case RENDERPATH_GL13:
1613         case RENDERPATH_GL20:
1614         case RENDERPATH_GLES2:
1615                 CHECKGLERROR
1616                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1617                 break;
1618         case RENDERPATH_D3D9:
1619 #ifdef SUPPORTD3D
1620                 {
1621                         D3DFORMAT d3dformat;
1622                         D3DPOOL d3dpool;
1623                         DWORD d3dusage;
1624                         HRESULT d3dresult;
1625                         d3dusage = 0;
1626                         d3dpool = D3DPOOL_MANAGED;
1627                         if (flags & TEXF_RENDERTARGET)
1628                         {
1629                                 d3dusage |= D3DUSAGE_RENDERTARGET;
1630                                 d3dpool = D3DPOOL_DEFAULT;
1631                         }
1632                         switch(textype)
1633                         {
1634                         case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1635                         case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1636                         case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1637                         case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1638                         case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1639                         case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1640                         default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1641                         }
1642                         glt->d3dformat = d3dformat;
1643                         glt->d3dusage = d3dusage;
1644                         glt->d3dpool = d3dpool;
1645                         glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1646                         if (glt->d3disdepthsurface)
1647                         {
1648                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1649                                         Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1650                         }
1651                         else if (glt->tiledepth > 1)
1652                         {
1653                                 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)))
1654                                         Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1655                         }
1656                         else if (glt->sides == 6)
1657                         {
1658                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1659                                         Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1660                         }
1661                         else
1662                         {
1663                                 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)))
1664                                         Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1665                         }
1666                 }
1667 #endif
1668                 break;
1669         case RENDERPATH_D3D10:
1670                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1671                 break;
1672         case RENDERPATH_D3D11:
1673                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1674                 break;
1675         case RENDERPATH_SOFT:
1676                 {
1677                         int tflags = 0;
1678                         switch(textype)
1679                         {
1680                         case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1681                         case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1682                         case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1683                         case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1684                         case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1685                         case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1686                         default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1687                         }
1688                         if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1689                         if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1690                         if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1691                         if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1692                         glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1693                 }
1694                 break;
1695         }
1696
1697         R_UploadFullTexture(glt, data);
1698         if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1699                 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1700
1701         // free any temporary processing buffer we allocated...
1702         if (temppixels)
1703                 Mem_Free(temppixels);
1704
1705         // texture converting and uploading can take a while, so make sure we're sending keepalives
1706         // FIXME: this causes rendering during R_Shadow_DrawLights
1707 //      CL_KeepaliveMessage(false);
1708
1709         return (rtexture_t *)glt;
1710 }
1711
1712 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)
1713 {
1714         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1715 }
1716
1717 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)
1718 {
1719         return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1720 }
1721
1722 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)
1723 {
1724         return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1725 }
1726
1727 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1728 {
1729         int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1730         if (filter)
1731                 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1732         else
1733                 flags |= TEXF_FORCENEAREST;
1734         if (precision <= 16)
1735                 flags |= TEXF_LOWPRECISION;
1736         return flags;
1737 }
1738
1739 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1740 {
1741         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1742 }
1743
1744 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1745 {
1746         gltexture_t *glt = (gltexture_t *)rt;
1747         unsigned char *dds;
1748         int oldbindtexnum;
1749         int bytesperpixel = 0;
1750         int bytesperblock = 0;
1751         int dds_flags;
1752         int dds_format_flags;
1753         int dds_caps1;
1754         int dds_caps2;
1755         int ret;
1756         int mip;
1757         int mipmaps;
1758         int mipinfo[16][4];
1759         int ddssize = 128;
1760         GLint internalformat;
1761         const char *ddsfourcc;
1762         if (!rt)
1763                 return -1; // NULL pointer
1764         if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1765                 return -2; // broken driver - crashes on reading internal format
1766         if (!qglGetTexLevelParameteriv)
1767                 return -2;
1768         GL_ActiveTexture(0);
1769         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1770         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1771         qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1772         switch(internalformat)
1773         {
1774         default: ddsfourcc = NULL;bytesperpixel = 4;break;
1775         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1776         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1777         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1778         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1779         }
1780         // if premultiplied alpha, say so in the DDS file
1781         if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1782         {
1783                 switch(internalformat)
1784                 {
1785                         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1786                         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1787                 }
1788         }
1789         if (!bytesperblock && skipuncompressed)
1790                 return -3; // skipped
1791         memset(mipinfo, 0, sizeof(mipinfo));
1792         mipinfo[0][0] = glt->tilewidth;
1793         mipinfo[0][1] = glt->tileheight;
1794         mipmaps = 1;
1795         if (glt->flags & TEXF_MIPMAP)
1796         {
1797                 for (mip = 1;mip < 16;mip++)
1798                 {
1799                         mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1800                         mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1801                         if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1802                         {
1803                                 mip++;
1804                                 break;
1805                         }
1806                 }
1807                 mipmaps = mip;
1808         }
1809         for (mip = 0;mip < mipmaps;mip++)
1810         {
1811                 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1812                 mipinfo[mip][3] = ddssize;
1813                 ddssize += mipinfo[mip][2];
1814         }
1815         dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1816         if (!dds)
1817                 return -4;
1818         dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1819         dds_caps2 = 0;
1820         if (bytesperblock)
1821         {
1822                 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1823                 dds_format_flags = 0x4; // DDPF_FOURCC
1824         }
1825         else
1826         {
1827                 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1828                 dds_format_flags = 0x40; // DDPF_RGB
1829         }
1830         if (mipmaps)
1831         {
1832                 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1833                 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1834         }
1835         if(hasalpha)
1836                 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1837         memcpy(dds, "DDS ", 4);
1838         StoreLittleLong(dds+4, ddssize);
1839         StoreLittleLong(dds+8, dds_flags);
1840         StoreLittleLong(dds+12, mipinfo[0][1]); // height
1841         StoreLittleLong(dds+16, mipinfo[0][0]); // width
1842         StoreLittleLong(dds+24, 1); // depth
1843         StoreLittleLong(dds+28, mipmaps); // mipmaps
1844         StoreLittleLong(dds+76, 32); // format size
1845         StoreLittleLong(dds+80, dds_format_flags);
1846         StoreLittleLong(dds+108, dds_caps1);
1847         StoreLittleLong(dds+112, dds_caps2);
1848         if (bytesperblock)
1849         {
1850                 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1851                 memcpy(dds+84, ddsfourcc, 4);
1852                 for (mip = 0;mip < mipmaps;mip++)
1853                 {
1854                         qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1855                 }
1856         }
1857         else
1858         {
1859                 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1860                 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1861                 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1862                 for (mip = 0;mip < mipmaps;mip++)
1863                 {
1864                         qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1865                 }
1866         }
1867         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1868         ret = FS_WriteFile(filename, dds, ddssize);
1869         Mem_Free(dds);
1870         return ret ? ddssize : -5;
1871 }
1872
1873 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
1874 {
1875         int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1876         //int dds_flags;
1877         textype_t textype;
1878         int bytesperblock, bytesperpixel;
1879         int mipcomplete;
1880         gltexture_t *glt;
1881         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1882         textypeinfo_t *texinfo;
1883         int mip, mipwidth, mipheight, mipsize, mipsize_total;
1884         unsigned int c;
1885         GLint oldbindtexnum = 0;
1886         const unsigned char *mippixels, *ddspixels, *mippixels_start;
1887         unsigned char *dds;
1888         fs_offset_t ddsfilesize;
1889         unsigned int ddssize;
1890         qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
1891
1892         if (cls.state == ca_dedicated)
1893                 return NULL;
1894
1895         dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1896         ddssize = ddsfilesize;
1897
1898         if (!dds)
1899         {
1900                 if(r_texture_dds_load_logfailure.integer)
1901                         Log_Printf("ddstexturefailures.log", "%s\n", filename);
1902                 return NULL; // not found
1903         }
1904
1905         if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1906         {
1907                 Mem_Free(dds);
1908                 Con_Printf("^1%s: not a DDS image\n", filename);
1909                 return NULL;
1910         }
1911
1912         //dds_flags = BuffLittleLong(dds+8);
1913         dds_format_flags = BuffLittleLong(dds+80);
1914         dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1915         dds_width = BuffLittleLong(dds+16);
1916         dds_height = BuffLittleLong(dds+12);
1917         ddspixels = dds + 128;
1918
1919         if(r_texture_dds_load_alphamode.integer == 0)
1920                 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1921                         flags &= ~TEXF_ALPHA;
1922
1923         //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1924         if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1925         {
1926                 // very sloppy BGRA 32bit identification
1927                 textype = TEXTYPE_BGRA;
1928                 bytesperblock = 0;
1929                 bytesperpixel = 4;
1930                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1931                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1932                 {
1933                         Mem_Free(dds);
1934                         Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1935                         return NULL;
1936                 }
1937                 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1938                 {
1939                         // check alpha
1940                         for (i = 3;i < size;i += 4)
1941                                 if (ddspixels[i] < 255)
1942                                         break;
1943                         if (i >= size)
1944                                 flags &= ~TEXF_ALPHA;
1945                 }
1946         }
1947         else if (!memcmp(dds+84, "DXT1", 4))
1948         {
1949                 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1950                 // LordHavoc: it is my belief that this does not infringe on the
1951                 // patent because it is not decoding pixels...
1952                 textype = TEXTYPE_DXT1;
1953                 bytesperblock = 8;
1954                 bytesperpixel = 0;
1955                 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1956                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1957                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1958                 {
1959                         Mem_Free(dds);
1960                         Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1961                         return NULL;
1962                 }
1963                 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1964                 {
1965                         if(r_texture_dds_load_alphamode.integer == 1)
1966                         {
1967                                 // check alpha
1968                                 for (i = 0;i < size;i += bytesperblock)
1969                                         if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1970                                         {
1971                                                 // NOTE: this assumes sizeof(unsigned int) == 4
1972                                                 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1973                                                 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1974                                                 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1975                                                         break;
1976                                         }
1977                                 if (i < size)
1978                                         textype = TEXTYPE_DXT1A;
1979                                 else
1980                                         flags &= ~TEXF_ALPHA;
1981                         }
1982                         else
1983                         {
1984                                 flags &= ~TEXF_ALPHA;
1985                         }
1986                 }
1987         }
1988         else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
1989         {
1990                 if(!memcmp(dds+84, "DXT2", 4))
1991                 {
1992                         if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1993                         {
1994                                 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
1995                         }
1996                 }
1997                 else
1998                 {
1999                         if(flags & TEXF_RGBMULTIPLYBYALPHA)
2000                         {
2001                                 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2002                         }
2003                 }
2004                 textype = TEXTYPE_DXT3;
2005                 bytesperblock = 16;
2006                 bytesperpixel = 0;
2007                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2008                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2009                 {
2010                         Mem_Free(dds);
2011                         Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2012                         return NULL;
2013                 }
2014                 // we currently always assume alpha
2015         }
2016         else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2017         {
2018                 if(!memcmp(dds+84, "DXT4", 4))
2019                 {
2020                         if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2021                         {
2022                                 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2023                         }
2024                 }
2025                 else
2026                 {
2027                         if(flags & TEXF_RGBMULTIPLYBYALPHA)
2028                         {
2029                                 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2030                         }
2031                 }
2032                 textype = TEXTYPE_DXT5;
2033                 bytesperblock = 16;
2034                 bytesperpixel = 0;
2035                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2036                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2037                 {
2038                         Mem_Free(dds);
2039                         Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2040                         return NULL;
2041                 }
2042                 // we currently always assume alpha
2043         }
2044         else
2045         {
2046                 Mem_Free(dds);
2047                 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2048                 return NULL;
2049         }
2050
2051         force_swdecode = false;
2052         if(bytesperblock)
2053         {
2054                 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
2055                 {
2056                         if(r_texture_dds_swdecode.integer > 1)
2057                                 force_swdecode = true;
2058                 }
2059                 else
2060                 {
2061                         if(r_texture_dds_swdecode.integer < 1)
2062                         {
2063                                 // unsupported
2064                                 Mem_Free(dds);
2065                                 return NULL;
2066                         }
2067                         force_swdecode = true;
2068                 }
2069         }
2070
2071         // return whether this texture is transparent
2072         if (hasalphaflag)
2073                 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2074
2075         // if we SW decode, choose 2 sizes bigger
2076         if(force_swdecode)
2077         {
2078                 // this is quarter res, so do not scale down more than we have to
2079                 miplevel -= 2;
2080
2081                 if(miplevel < 0)
2082                         Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2083         }
2084
2085         // this is where we apply gl_picmip
2086         mippixels_start = ddspixels;
2087         mipwidth = dds_width;
2088         mipheight = dds_height;
2089         while(miplevel >= 1 && dds_miplevels >= 1)
2090         {
2091                 if (mipwidth <= 1 && mipheight <= 1)
2092                         break;
2093                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2094                 mippixels_start += mipsize; // just skip
2095                 --dds_miplevels;
2096                 --miplevel;
2097                 if (mipwidth > 1)
2098                         mipwidth >>= 1;
2099                 if (mipheight > 1)
2100                         mipheight >>= 1;
2101         }
2102         mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2103         mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2104
2105         // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2106
2107         // fake decode S3TC if needed
2108         if(force_swdecode)
2109         {
2110                 int mipsize_new = mipsize_total / bytesperblock * 4;
2111                 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2112                 unsigned char *p = mipnewpixels;
2113                 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2114                 {
2115                         c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2116                         p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2117                         p[1] = (((c >>  5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2118                         p[0] = (((c      ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2119                         if(textype == TEXTYPE_DXT5)
2120                                 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2121                         else if(textype == TEXTYPE_DXT3)
2122                                 p[3] = (
2123                                           (mippixels_start[i-8] & 0x0F)
2124                                         + (mippixels_start[i-8] >> 4)
2125                                         + (mippixels_start[i-7] & 0x0F)
2126                                         + (mippixels_start[i-7] >> 4)
2127                                         + (mippixels_start[i-6] & 0x0F)
2128                                         + (mippixels_start[i-6] >> 4)
2129                                         + (mippixels_start[i-5] & 0x0F)
2130                                         + (mippixels_start[i-5] >> 4)
2131                                        ) * (0.125f / 15.0f * 255.0f);
2132                         else
2133                                 p[3] = 255;
2134                 }
2135
2136                 textype = TEXTYPE_BGRA;
2137                 bytesperblock = 0;
2138                 bytesperpixel = 4;
2139
2140                 // as each block becomes a pixel, we must use pixel count for this
2141                 mipwidth = (mipwidth + 3) / 4;
2142                 mipheight = (mipheight + 3) / 4;
2143                 mipsize = bytesperpixel * mipwidth * mipheight;
2144                 mippixels_start = mipnewpixels;
2145                 mipsize_total = mipsize_new;
2146         }
2147
2148         // start mip counting
2149         mippixels = mippixels_start;
2150
2151         // calculate average color if requested
2152         if (avgcolor)
2153         {
2154                 float f;
2155                 Vector4Clear(avgcolor);
2156                 if (bytesperblock)
2157                 {
2158                         for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2159                         {
2160                                 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2161                                 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2162                                 avgcolor[1] += ((c >>  5) & 0x3F) + ((c >> 21) & 0x3F);
2163                                 avgcolor[2] += ((c      ) & 0x1F) + ((c >> 16) & 0x1F);
2164                                 if(textype == TEXTYPE_DXT5)
2165                                         avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2166                                 else if(textype == TEXTYPE_DXT3)
2167                                         avgcolor[3] += (
2168                                                   (mippixels_start[i-8] & 0x0F)
2169                                                 + (mippixels_start[i-8] >> 4)
2170                                                 + (mippixels_start[i-7] & 0x0F)
2171                                                 + (mippixels_start[i-7] >> 4)
2172                                                 + (mippixels_start[i-6] & 0x0F)
2173                                                 + (mippixels_start[i-6] >> 4)
2174                                                 + (mippixels_start[i-5] & 0x0F)
2175                                                 + (mippixels_start[i-5] >> 4)
2176                                                ) * (0.125f / 15.0f * 255.0f);
2177                                 else
2178                                         avgcolor[3] += 255;
2179                         }
2180                         f = (float)bytesperblock / size;
2181                         avgcolor[0] *= (0.5f / 31.0f) * f;
2182                         avgcolor[1] *= (0.5f / 63.0f) * f;
2183                         avgcolor[2] *= (0.5f / 31.0f) * f;
2184                         avgcolor[3] *= f;
2185                 }
2186                 else
2187                 {
2188                         for (i = 0;i < mipsize;i += 4)
2189                         {
2190                                 avgcolor[0] += mippixels[i+2];
2191                                 avgcolor[1] += mippixels[i+1];
2192                                 avgcolor[2] += mippixels[i];
2193                                 avgcolor[3] += mippixels[i+3];
2194                         }
2195                         f = (1.0f / 255.0f) * bytesperpixel / size;
2196                         avgcolor[0] *= f;
2197                         avgcolor[1] *= f;
2198                         avgcolor[2] *= f;
2199                         avgcolor[3] *= f;
2200                 }
2201         }
2202
2203         // when not requesting mipmaps, do not load them
2204         if(!(flags & TEXF_MIPMAP))
2205                 dds_miplevels = 0;
2206
2207         if (dds_miplevels >= 1)
2208                 flags |= TEXF_MIPMAP;
2209         else
2210                 flags &= ~TEXF_MIPMAP;
2211
2212         texinfo = R_GetTexTypeInfo(textype, flags);
2213
2214         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2215         strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2216         glt->pool = pool;
2217         glt->chain = pool->gltchain;
2218         pool->gltchain = glt;
2219         glt->inputwidth = mipwidth;
2220         glt->inputheight = mipheight;
2221         glt->inputdepth = 1;
2222         glt->flags = flags;
2223         glt->textype = texinfo;
2224         glt->texturetype = GLTEXTURETYPE_2D;
2225         glt->inputdatasize = ddssize;
2226         glt->glinternalformat = texinfo->glinternalformat;
2227         glt->glformat = texinfo->glformat;
2228         glt->gltype = texinfo->gltype;
2229         glt->bytesperpixel = texinfo->internalbytesperpixel;
2230         glt->sides = 1;
2231         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2232         glt->tilewidth = mipwidth;
2233         glt->tileheight = mipheight;
2234         glt->tiledepth = 1;
2235         glt->miplevels = dds_miplevels;
2236
2237         // texture uploading can take a while, so make sure we're sending keepalives
2238         CL_KeepaliveMessage(false);
2239
2240         // create the texture object
2241         switch(vid.renderpath)
2242         {
2243         case RENDERPATH_GL11:
2244         case RENDERPATH_GL13:
2245         case RENDERPATH_GL20:
2246         case RENDERPATH_GLES2:
2247                 CHECKGLERROR
2248                 GL_ActiveTexture(0);
2249                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2250                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2251                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2252                 break;
2253         case RENDERPATH_D3D9:
2254 #ifdef SUPPORTD3D
2255                 {
2256                         D3DFORMAT d3dformat;
2257                         D3DPOOL d3dpool;
2258                         DWORD d3dusage;
2259                         switch(textype)
2260                         {
2261                         case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2262                         case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2263                         case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2264                         case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2265                         default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2266                         }
2267                         d3dusage = 0;
2268                         d3dpool = D3DPOOL_MANAGED;
2269                         IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2270                 }
2271 #endif
2272                 break;
2273         case RENDERPATH_D3D10:
2274                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2275                 break;
2276         case RENDERPATH_D3D11:
2277                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2278                 break;
2279         case RENDERPATH_SOFT:
2280                 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);
2281                 break;
2282         }
2283
2284         // upload the texture
2285         // we need to restore the texture binding after finishing the upload
2286         mipcomplete = false;
2287
2288         for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2289         {
2290                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2291                 if (mippixels + mipsize > mippixels_start + mipsize_total)
2292                         break;
2293                 switch(vid.renderpath)
2294                 {
2295                 case RENDERPATH_GL11:
2296                 case RENDERPATH_GL13:
2297                 case RENDERPATH_GL20:
2298                 case RENDERPATH_GLES2:
2299                         if (bytesperblock)
2300                         {
2301                                 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2302                         }
2303                         else
2304                         {
2305                                 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2306                         }
2307                         break;
2308                 case RENDERPATH_D3D9:
2309 #ifdef SUPPORTD3D
2310                         {
2311                                 D3DLOCKED_RECT d3dlockedrect;
2312                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2313                                 {
2314                                         memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2315                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2316                                 }
2317                                 break;
2318                         }
2319 #endif
2320                         break;
2321                 case RENDERPATH_D3D10:
2322                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2323                         break;
2324                 case RENDERPATH_D3D11:
2325                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2326                         break;
2327                 case RENDERPATH_SOFT:
2328                         if (bytesperblock)
2329                                 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2330                         else
2331                                 DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
2332                         // DPSOFTRAST calculates its own mipmaps
2333                         mip = dds_miplevels;
2334                         break;
2335                 }
2336                 mippixels += mipsize;
2337                 if (mipwidth <= 1 && mipheight <= 1)
2338                 {
2339                         mipcomplete = true;
2340                         break;
2341                 }
2342                 if (mipwidth > 1)
2343                         mipwidth >>= 1;
2344                 if (mipheight > 1)
2345                         mipheight >>= 1;
2346         }
2347
2348         // after upload we have to set some parameters...
2349         switch(vid.renderpath)
2350         {
2351         case RENDERPATH_GL11:
2352         case RENDERPATH_GL13:
2353         case RENDERPATH_GL20:
2354         case RENDERPATH_GLES2:
2355                 if (dds_miplevels >= 1 && !mipcomplete)
2356                 {
2357                         // need to set GL_TEXTURE_MAX_LEVEL
2358                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2359                 }
2360                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2361                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2362                 break;
2363         case RENDERPATH_D3D9:
2364 #ifdef SUPPORTD3D
2365                 glt->d3daddressw = 0;
2366                 if (glt->flags & TEXF_CLAMP)
2367                 {
2368                         glt->d3daddressu = D3DTADDRESS_CLAMP;
2369                         glt->d3daddressv = D3DTADDRESS_CLAMP;
2370                         if (glt->tiledepth > 1)
2371                                 glt->d3daddressw = D3DTADDRESS_CLAMP;
2372                 }
2373                 else
2374                 {
2375                         glt->d3daddressu = D3DTADDRESS_WRAP;
2376                         glt->d3daddressv = D3DTADDRESS_WRAP;
2377                         if (glt->tiledepth > 1)
2378                                 glt->d3daddressw = D3DTADDRESS_WRAP;
2379                 }
2380                 glt->d3dmipmaplodbias = 0;
2381                 glt->d3dmaxmiplevel = 0;
2382                 glt->d3dmaxmiplevelfilter = 0;
2383                 if (glt->flags & TEXF_MIPMAP)
2384                 {
2385                         glt->d3dminfilter = d3d_filter_mipmin;
2386                         glt->d3dmagfilter = d3d_filter_mipmag;
2387                         glt->d3dmipfilter = d3d_filter_mipmix;
2388                 }
2389                 else
2390                 {
2391                         glt->d3dminfilter = d3d_filter_flatmin;
2392                         glt->d3dmagfilter = d3d_filter_flatmag;
2393                         glt->d3dmipfilter = d3d_filter_flatmix;
2394                 }
2395 #endif
2396                 break;
2397         case RENDERPATH_D3D10:
2398                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2399                 break;
2400         case RENDERPATH_D3D11:
2401                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2402                 break;
2403         case RENDERPATH_SOFT:
2404                 if (glt->flags & TEXF_FORCELINEAR)
2405                         DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2406                 else if (glt->flags & TEXF_FORCENEAREST)
2407                         DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2408                 else if (glt->flags & TEXF_MIPMAP)
2409                         DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2410                 else
2411                         DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2412                 break;
2413         }
2414
2415         Mem_Free(dds);
2416         if(force_swdecode)
2417                 Mem_Free((unsigned char *) mippixels_start);
2418         return (rtexture_t *)glt;
2419 }
2420
2421 int R_TextureWidth(rtexture_t *rt)
2422 {
2423         return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2424 }
2425
2426 int R_TextureHeight(rtexture_t *rt)
2427 {
2428         return rt ? ((gltexture_t *)rt)->inputheight : 0;
2429 }
2430
2431 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2432 {
2433         gltexture_t *glt = (gltexture_t *)rt;
2434         if (data == NULL)
2435                 Host_Error("R_UpdateTexture: no data supplied");
2436         if (glt == NULL)
2437                 Host_Error("R_UpdateTexture: no texture supplied");
2438         if (!glt->texnum && !glt->d3dtexture)
2439         {
2440                 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2441                 return;
2442         }
2443         // update part of the texture
2444         if (glt->bufferpixels)
2445         {
2446                 int j;
2447                 int bpp = glt->bytesperpixel;
2448                 int inputskip = width*bpp;
2449                 int outputskip = glt->tilewidth*bpp;
2450                 const unsigned char *input = data;
2451                 unsigned char *output = glt->bufferpixels;
2452                 if (glt->inputdepth != 1 || glt->sides != 1)
2453                         Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2454                 if (x < 0)
2455                 {
2456                         width += x;
2457                         input -= x*bpp;
2458                         x = 0;
2459                 }
2460                 if (y < 0)
2461                 {
2462                         height += y;
2463                         input -= y*inputskip;
2464                         y = 0;
2465                 }
2466                 if (width > glt->tilewidth - x)
2467                         width = glt->tilewidth - x;
2468                 if (height > glt->tileheight - y)
2469                         height = glt->tileheight - y;
2470                 if (width < 1 || height < 1)
2471                         return;
2472                 glt->dirty = true;
2473                 glt->buffermodified = true;
2474                 output += y*outputskip + x*bpp;
2475                 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2476                         memcpy(output, input, width*bpp);
2477         }
2478         else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2479                 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2480         else
2481                 R_UploadFullTexture(glt, data);
2482 }
2483
2484 int R_RealGetTexture(rtexture_t *rt)
2485 {
2486         if (rt)
2487         {
2488                 gltexture_t *glt;
2489                 glt = (gltexture_t *)rt;
2490                 if (glt->flags & GLTEXF_DYNAMIC)
2491                         R_UpdateDynamicTexture(glt);
2492                 if (glt->buffermodified && glt->bufferpixels)
2493                 {
2494                         glt->buffermodified = false;
2495                         R_UploadFullTexture(glt, glt->bufferpixels);
2496                 }
2497                 glt->dirty = false;
2498                 return glt->texnum;
2499         }
2500         else
2501                 return 0;
2502 }
2503
2504 void R_ClearTexture (rtexture_t *rt)
2505 {
2506         gltexture_t *glt = (gltexture_t *)rt;
2507
2508         R_UploadFullTexture(glt, NULL);
2509 }
2510
2511 int R_PicmipForFlags(int flags)
2512 {
2513         int miplevel = 0;
2514         if(flags & TEXF_PICMIP)
2515         {
2516                 miplevel += gl_picmip.integer;
2517                 if (flags & TEXF_ISWORLD)
2518                 {
2519                         if (r_picmipworld.integer)
2520                                 miplevel += gl_picmip_world.integer;
2521                         else
2522                                 miplevel = 0;
2523                 }
2524                 else if (flags & TEXF_ISSPRITE)
2525                 {
2526                         if (r_picmipsprites.integer)
2527                                 miplevel += gl_picmip_sprites.integer;
2528                         else
2529                                 miplevel = 0;
2530                 }
2531                 else
2532                         miplevel += gl_picmip_other.integer;
2533         }
2534         return max(0, miplevel);
2535 }