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