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