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