]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_textures.c
R_CompleteLightPoint: more correct sampling
[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         // scale up to a power of 2 size (if appropriate)
1123         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1124         {
1125                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1126                 prevbuffer = resizebuffer;
1127         }
1128         // apply mipmap reduction algorithm to get down to picmip/max_size
1129         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1130         {
1131                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1132                 prevbuffer = resizebuffer;
1133         }
1134
1135         // do the appropriate upload type...
1136         switch(vid.renderpath)
1137         {
1138         case RENDERPATH_GL11:
1139         case RENDERPATH_GL13:
1140         case RENDERPATH_GL20:
1141         case RENDERPATH_CGGL:
1142                 CHECKGLERROR
1143
1144                 // we need to restore the texture binding after finishing the upload
1145                 GL_ActiveTexture(0);
1146                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1147                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1148
1149                 if (qglGetCompressedTexImageARB)
1150                 {
1151                         if (gl_texturecompression.integer >= 2)
1152                                 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1153                         else
1154                                 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1155                         CHECKGLERROR
1156                 }
1157                 switch(glt->texturetype)
1158                 {
1159                 case GLTEXTURETYPE_2D:
1160                         qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1161                         if (glt->flags & TEXF_MIPMAP)
1162                         {
1163                                 while (width > 1 || height > 1 || depth > 1)
1164                                 {
1165                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1166                                         prevbuffer = resizebuffer;
1167                                         qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1168                                 }
1169                         }
1170                         break;
1171                 case GLTEXTURETYPE_3D:
1172                         qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1173                         if (glt->flags & TEXF_MIPMAP)
1174                         {
1175                                 while (width > 1 || height > 1 || depth > 1)
1176                                 {
1177                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1178                                         prevbuffer = resizebuffer;
1179                                         qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1180                                 }
1181                         }
1182                         break;
1183                 case GLTEXTURETYPE_CUBEMAP:
1184                         // convert and upload each side in turn,
1185                         // from a continuous block of input texels
1186                         texturebuffer = (unsigned char *)prevbuffer;
1187                         for (i = 0;i < 6;i++)
1188                         {
1189                                 prevbuffer = texturebuffer;
1190                                 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1191                                 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1192                                 {
1193                                         Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1194                                         prevbuffer = resizebuffer;
1195                                 }
1196                                 // picmip/max_size
1197                                 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1198                                 {
1199                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1200                                         prevbuffer = resizebuffer;
1201                                 }
1202                                 mip = 0;
1203                                 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1204                                 if (glt->flags & TEXF_MIPMAP)
1205                                 {
1206                                         while (width > 1 || height > 1 || depth > 1)
1207                                         {
1208                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1209                                                 prevbuffer = resizebuffer;
1210                                                 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1211                                         }
1212                                 }
1213                         }
1214                         break;
1215                 }
1216                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1217                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1218                 break;
1219         case RENDERPATH_D3D9:
1220 #ifdef SUPPORTD3D
1221                 if (!(glt->flags & TEXF_RENDERTARGET))
1222                 {
1223                         D3DLOCKED_RECT d3dlockedrect;
1224                         D3DLOCKED_BOX d3dlockedbox;
1225                         switch(glt->texturetype)
1226                         {
1227                         case GLTEXTURETYPE_2D:
1228                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1229                                 {
1230                                         if (prevbuffer)
1231                                                 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1232                                         else
1233                                                 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1234                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1235                                 }
1236                                 mip++;
1237                                 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1238                                 {
1239                                         while (width > 1 || height > 1 || depth > 1)
1240                                         {
1241                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1242                                                 prevbuffer = resizebuffer;
1243                                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1244                                                 {
1245                                                         memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1246                                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1247                                                 }
1248                                                 mip++;
1249                                         }
1250                                 }
1251                                 break;
1252                         case GLTEXTURETYPE_3D:
1253                                 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1254                                 {
1255                                         // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1256                                         memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1257                                         IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1258                                 }
1259                                 mip++;
1260                                 if (glt->flags & TEXF_MIPMAP)
1261                                 {
1262                                         while (width > 1 || height > 1 || depth > 1)
1263                                         {
1264                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1265                                                 prevbuffer = resizebuffer;
1266                                                 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1267                                                 {
1268                                                         // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1269                                                         memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1270                                                         IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1271                                                 }
1272                                                 mip++;
1273                                         }
1274                                 }
1275                                 break;
1276                         case GLTEXTURETYPE_CUBEMAP:
1277                                 // convert and upload each side in turn,
1278                                 // from a continuous block of input texels
1279                                 texturebuffer = (unsigned char *)prevbuffer;
1280                                 for (i = 0;i < 6;i++)
1281                                 {
1282                                         prevbuffer = texturebuffer;
1283                                         texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1284                                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1285                                         {
1286                                                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1287                                                 prevbuffer = resizebuffer;
1288                                         }
1289                                         // picmip/max_size
1290                                         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1291                                         {
1292                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1293                                                 prevbuffer = resizebuffer;
1294                                         }
1295                                         mip = 0;
1296                                         if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1297                                         {
1298                                                 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1299                                                 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1300                                         }
1301                                         mip++;
1302                                         if (glt->flags & TEXF_MIPMAP)
1303                                         {
1304                                                 while (width > 1 || height > 1 || depth > 1)
1305                                                 {
1306                                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1307                                                         prevbuffer = resizebuffer;
1308                                                         if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1309                                                         {
1310                                                                 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1311                                                                 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1312                                                         }
1313                                                         mip++;
1314                                                 }
1315                                         }
1316                                 }
1317                                 break;
1318                         }
1319                 }
1320                 glt->d3daddressw = 0;
1321                 if (glt->flags & TEXF_CLAMP)
1322                 {
1323                         glt->d3daddressu = D3DTADDRESS_CLAMP;
1324                         glt->d3daddressv = D3DTADDRESS_CLAMP;
1325                         if (glt->tiledepth > 1)
1326                                 glt->d3daddressw = D3DTADDRESS_CLAMP;
1327                 }
1328                 else
1329                 {
1330                         glt->d3daddressu = D3DTADDRESS_WRAP;
1331                         glt->d3daddressv = D3DTADDRESS_WRAP;
1332                         if (glt->tiledepth > 1)
1333                                 glt->d3daddressw = D3DTADDRESS_WRAP;
1334                 }
1335                 glt->d3dmipmaplodbias = 0;
1336                 glt->d3dmaxmiplevel = 0;
1337                 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1338                 if (glt->flags & TEXF_FORCELINEAR)
1339                 {
1340                         glt->d3dminfilter = D3DTEXF_LINEAR;
1341                         glt->d3dmagfilter = D3DTEXF_LINEAR;
1342                         glt->d3dmipfilter = D3DTEXF_POINT;
1343                 }
1344                 else if (glt->flags & TEXF_FORCENEAREST)
1345                 {
1346                         glt->d3dminfilter = D3DTEXF_POINT;
1347                         glt->d3dmagfilter = D3DTEXF_POINT;
1348                         glt->d3dmipfilter = D3DTEXF_POINT;
1349                 }
1350                 else if (glt->flags & TEXF_MIPMAP)
1351                 {
1352                         glt->d3dminfilter = d3d_filter_mipmin;
1353                         glt->d3dmagfilter = d3d_filter_mipmag;
1354                         glt->d3dmipfilter = d3d_filter_mipmix;
1355                 }
1356                 else
1357                 {
1358                         glt->d3dminfilter = d3d_filter_flatmin;
1359                         glt->d3dmagfilter = d3d_filter_flatmag;
1360                         glt->d3dmipfilter = d3d_filter_flatmix;
1361                 }
1362 #endif
1363                 break;
1364         case RENDERPATH_D3D10:
1365                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1366                 break;
1367         case RENDERPATH_D3D11:
1368                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1369                 break;
1370         }
1371 }
1372
1373 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)
1374 {
1375         int i, size;
1376         gltexture_t *glt;
1377         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1378         textypeinfo_t *texinfo, *texinfo2;
1379         unsigned char *temppixels = NULL;
1380
1381         if (cls.state == ca_dedicated)
1382                 return NULL;
1383
1384         if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1385         {
1386                 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1387                 return NULL;
1388         }
1389         if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1390         {
1391                 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1392                 return NULL;
1393         }
1394
1395         texinfo = R_GetTexTypeInfo(textype, flags);
1396         size = width * height * depth * sides * texinfo->inputbytesperpixel;
1397         if (size < 1)
1398         {
1399                 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1400                 return NULL;
1401         }
1402
1403         if (textype == TEXTYPE_RGBA)
1404         {
1405                 // swap bytes
1406                 static int rgbaswapindices[4] = {2, 1, 0, 3};
1407                 textype = TEXTYPE_BGRA;
1408                 texinfo = R_GetTexTypeInfo(textype, flags);
1409                 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1410                 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1411                 data = temppixels;
1412         }
1413
1414         // clear the alpha flag if the texture has no transparent pixels
1415         switch(textype)
1416         {
1417         case TEXTYPE_PALETTE:
1418                 if (flags & TEXF_ALPHA)
1419                 {
1420                         flags &= ~TEXF_ALPHA;
1421                         if (data)
1422                         {
1423                                 for (i = 0;i < size;i++)
1424                                 {
1425                                         if (((unsigned char *)&palette[data[i]])[3] < 255)
1426                                         {
1427                                                 flags |= TEXF_ALPHA;
1428                                                 break;
1429                                         }
1430                                 }
1431                         }
1432                 }
1433                 break;
1434         case TEXTYPE_RGBA:
1435         case TEXTYPE_BGRA:
1436                 if (flags & TEXF_ALPHA)
1437                 {
1438                         flags &= ~TEXF_ALPHA;
1439                         if (data)
1440                         {
1441                                 for (i = 3;i < size;i += 4)
1442                                 {
1443                                         if (data[i] < 255)
1444                                         {
1445                                                 flags |= TEXF_ALPHA;
1446                                                 break;
1447                                         }
1448                                 }
1449                         }
1450                 }
1451                 break;
1452         case TEXTYPE_SHADOWMAP:
1453                 break;
1454         case TEXTYPE_DXT1:
1455                 break;
1456         case TEXTYPE_DXT1A:
1457         case TEXTYPE_DXT3:
1458         case TEXTYPE_DXT5:
1459                 flags |= TEXF_ALPHA;
1460                 break;
1461         case TEXTYPE_ALPHA:
1462                 flags |= TEXF_ALPHA;
1463                 break;
1464         case TEXTYPE_COLORBUFFER:
1465                 flags |= TEXF_ALPHA;
1466                 break;
1467         default:
1468                 Sys_Error("R_LoadTexture: unknown texture type");
1469         }
1470
1471         texinfo2 = R_GetTexTypeInfo(textype, flags);
1472         if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1473                 texinfo = texinfo2;
1474         else
1475                 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1476
1477         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1478         if (identifier)
1479                 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1480         glt->pool = pool;
1481         glt->chain = pool->gltchain;
1482         pool->gltchain = glt;
1483         glt->inputwidth = width;
1484         glt->inputheight = height;
1485         glt->inputdepth = depth;
1486         glt->flags = flags;
1487         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
1488         glt->textype = texinfo;
1489         glt->texturetype = texturetype;
1490         glt->inputdatasize = size;
1491         glt->palette = palette;
1492         glt->glinternalformat = texinfo->glinternalformat;
1493         glt->glformat = texinfo->glformat;
1494         glt->gltype = texinfo->gltype;
1495         glt->bytesperpixel = texinfo->internalbytesperpixel;
1496         glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1497         glt->texnum = 0;
1498         glt->dirty = false;
1499         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1500         // init the dynamic texture attributes, too [11/22/2007 Black]
1501         glt->updatecallback = NULL;
1502         glt->updatacallback_data = NULL;
1503
1504         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1505
1506         // upload the texture
1507         // data may be NULL (blank texture for dynamic rendering)
1508         switch(vid.renderpath)
1509         {
1510         case RENDERPATH_GL11:
1511         case RENDERPATH_GL13:
1512         case RENDERPATH_GL20:
1513         case RENDERPATH_CGGL:
1514                 CHECKGLERROR
1515                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1516                 break;
1517         case RENDERPATH_D3D9:
1518 #ifdef SUPPORTD3D
1519                 {
1520                         D3DFORMAT d3dformat;
1521                         D3DPOOL d3dpool;
1522                         DWORD d3dusage;
1523                         HRESULT d3dresult;
1524                         d3dusage = 0;
1525                         d3dpool = D3DPOOL_MANAGED;
1526                         if (flags & TEXF_RENDERTARGET)
1527                         {
1528                                 d3dusage |= D3DUSAGE_RENDERTARGET;
1529                                 d3dpool = D3DPOOL_DEFAULT;
1530                         }
1531                         switch(textype)
1532                         {
1533                         case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1534                         case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1535                         case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1536                         case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1537                         case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1538                         case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1539                         default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1540                         }
1541                         glt->d3dformat = d3dformat;
1542                         glt->d3dusage = d3dusage;
1543                         glt->d3dpool = d3dpool;
1544                         glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1545                         if (glt->d3disdepthsurface)
1546                         {
1547                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1548                                         Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1549                         }
1550                         else if (glt->tiledepth > 1)
1551                         {
1552                                 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)))
1553                                         Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1554                         }
1555                         else if (glt->sides == 6)
1556                         {
1557                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1558                                         Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1559                         }
1560                         else
1561                         {
1562                                 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)))
1563                                         Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1564                         }
1565                 }
1566 #endif
1567                 break;
1568         case RENDERPATH_D3D10:
1569                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1570                 break;
1571         case RENDERPATH_D3D11:
1572                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1573                 break;
1574         }
1575
1576         R_UploadFullTexture(glt, data);
1577         if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1578                 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1579
1580         // free any temporary processing buffer we allocated...
1581         if (temppixels)
1582                 Mem_Free(temppixels);
1583
1584         // texture converting and uploading can take a while, so make sure we're sending keepalives
1585         // FIXME: this causes rendering during R_Shadow_DrawLights
1586 //      CL_KeepaliveMessage(false);
1587
1588         return (rtexture_t *)glt;
1589 }
1590
1591 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)
1592 {
1593         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1594 }
1595
1596 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)
1597 {
1598         return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1599 }
1600
1601 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)
1602 {
1603         return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1604 }
1605
1606 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1607 {
1608         int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1609         if (filter)
1610                 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1611         else
1612                 flags |= TEXF_FORCENEAREST;
1613         if (precision <= 16)
1614                 flags |= TEXF_LOWPRECISION;
1615         return flags;
1616 }
1617
1618 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1619 {
1620         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1621 }
1622
1623 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1624 {
1625         gltexture_t *glt = (gltexture_t *)rt;
1626         unsigned char *dds;
1627         int oldbindtexnum;
1628         int bytesperpixel = 0;
1629         int bytesperblock = 0;
1630         int dds_flags;
1631         int dds_format_flags;
1632         int dds_caps1;
1633         int dds_caps2;
1634         int ret;
1635         int mip;
1636         int mipmaps;
1637         int mipinfo[16][4];
1638         int ddssize = 128;
1639         GLint internalformat;
1640         const char *ddsfourcc;
1641         if (!rt)
1642                 return -1; // NULL pointer
1643         if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1644                 return -2; // broken driver - crashes on reading internal format
1645         if (!qglGetTexLevelParameteriv)
1646                 return -2;
1647         GL_ActiveTexture(0);
1648         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1649         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1650         qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1651         switch(internalformat)
1652         {
1653         default: ddsfourcc = NULL;bytesperpixel = 4;break;
1654         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1655         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1656         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1657         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1658         }
1659         if (!bytesperblock && skipuncompressed)
1660                 return -3; // skipped
1661         memset(mipinfo, 0, sizeof(mipinfo));
1662         mipinfo[0][0] = glt->tilewidth;
1663         mipinfo[0][1] = glt->tileheight;
1664         mipmaps = 1;
1665         if (glt->flags & TEXF_MIPMAP)
1666         {
1667                 for (mip = 1;mip < 16;mip++)
1668                 {
1669                         mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1670                         mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1671                         if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1672                         {
1673                                 mip++;
1674                                 break;
1675                         }
1676                 }
1677                 mipmaps = mip;
1678         }
1679         for (mip = 0;mip < mipmaps;mip++)
1680         {
1681                 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1682                 mipinfo[mip][3] = ddssize;
1683                 ddssize += mipinfo[mip][2];
1684         }
1685         dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1686         if (!dds)
1687                 return -4;
1688         dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1689         dds_caps2 = 0;
1690         if (bytesperblock)
1691         {
1692                 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1693                 dds_format_flags = 0x4; // DDPF_FOURCC
1694         }
1695         else
1696         {
1697                 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1698                 dds_format_flags = 0x40; // DDPF_RGB
1699         }
1700         if (mipmaps)
1701         {
1702                 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1703                 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1704         }
1705         if(hasalpha)
1706                 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1707         memcpy(dds, "DDS ", 4);
1708         StoreLittleLong(dds+4, ddssize);
1709         StoreLittleLong(dds+8, dds_flags);
1710         StoreLittleLong(dds+12, mipinfo[0][1]); // height
1711         StoreLittleLong(dds+16, mipinfo[0][0]); // width
1712         StoreLittleLong(dds+24, 1); // depth
1713         StoreLittleLong(dds+28, mipmaps); // mipmaps
1714         StoreLittleLong(dds+76, 32); // format size
1715         StoreLittleLong(dds+80, dds_format_flags);
1716         StoreLittleLong(dds+108, dds_caps1);
1717         StoreLittleLong(dds+112, dds_caps2);
1718         if (bytesperblock)
1719         {
1720                 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1721                 memcpy(dds+84, ddsfourcc, 4);
1722                 for (mip = 0;mip < mipmaps;mip++)
1723                 {
1724                         qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1725                 }
1726         }
1727         else
1728         {
1729                 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1730                 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1731                 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1732                 for (mip = 0;mip < mipmaps;mip++)
1733                 {
1734                         qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1735                 }
1736         }
1737         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1738         ret = FS_WriteFile(filename, dds, ddssize);
1739         Mem_Free(dds);
1740         return ret ? ddssize : -5;
1741 }
1742
1743 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
1744 {
1745         int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1746         //int dds_flags;
1747         textype_t textype;
1748         int bytesperblock, bytesperpixel;
1749         int mipcomplete;
1750         gltexture_t *glt;
1751         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1752         textypeinfo_t *texinfo;
1753         int mip, mipwidth, mipheight, mipsize;
1754         unsigned int c;
1755         GLint oldbindtexnum = 0;
1756         const unsigned char *mippixels, *ddspixels;
1757         unsigned char *dds;
1758         fs_offset_t ddsfilesize;
1759         unsigned int ddssize;
1760
1761         if (cls.state == ca_dedicated)
1762                 return NULL;
1763
1764         dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1765         ddssize = ddsfilesize;
1766
1767         if (!dds)
1768         {
1769                 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1770                 return NULL; // not found
1771         }
1772
1773         if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1774         {
1775                 Mem_Free(dds);
1776                 Con_Printf("^1%s: not a DDS image\n", filename);
1777                 return NULL;
1778         }
1779
1780         //dds_flags = BuffLittleLong(dds+8);
1781         dds_format_flags = BuffLittleLong(dds+80);
1782         dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1783         dds_width = BuffLittleLong(dds+16);
1784         dds_height = BuffLittleLong(dds+12);
1785         ddspixels = dds + 128;
1786
1787         if(r_texture_dds_load_alphamode.integer == 0)
1788                 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1789                         flags &= ~TEXF_ALPHA;
1790
1791         //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1792         if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1793         {
1794                 // very sloppy BGRA 32bit identification
1795                 textype = TEXTYPE_BGRA;
1796                 bytesperblock = 0;
1797                 bytesperpixel = 4;
1798                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1799                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1800                 {
1801                         Mem_Free(dds);
1802                         Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1803                         return NULL;
1804                 }
1805                 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1806                 {
1807                         // check alpha
1808                         for (i = 3;i < size;i += 4)
1809                                 if (ddspixels[i] < 255)
1810                                         break;
1811                         if (i >= size)
1812                                 flags &= ~TEXF_ALPHA;
1813                 }
1814         }
1815         else if (!memcmp(dds+84, "DXT1", 4))
1816         {
1817                 if(!vid.support.ext_texture_compression_s3tc)
1818                 {
1819                         Mem_Free(dds);
1820                         return NULL;
1821                 }
1822                 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1823                 // LordHavoc: it is my belief that this does not infringe on the
1824                 // patent because it is not decoding pixels...
1825                 textype = TEXTYPE_DXT1;
1826                 bytesperblock = 8;
1827                 bytesperpixel = 0;
1828                 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1829                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1830                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1831                 {
1832                         Mem_Free(dds);
1833                         Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1834                         return NULL;
1835                 }
1836                 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1837                 {
1838                         if(r_texture_dds_load_alphamode.integer == 1)
1839                         {
1840                                 // check alpha
1841                                 for (i = 0;i < size;i += bytesperblock)
1842                                         if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1843                                         {
1844                                                 // NOTE: this assumes sizeof(unsigned int) == 4
1845                                                 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1846                                                 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1847                                                 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1848                                                         break;
1849                                         }
1850                                 if (i < size)
1851                                         textype = TEXTYPE_DXT1A;
1852                                 else
1853                                         flags &= ~TEXF_ALPHA;
1854                         }
1855                         else
1856                         {
1857                                 flags &= ~TEXF_ALPHA;
1858                         }
1859                 }
1860         }
1861         else if (!memcmp(dds+84, "DXT3", 4))
1862         {
1863                 if(!vid.support.ext_texture_compression_s3tc)
1864                 {
1865                         Mem_Free(dds);
1866                         return NULL;
1867                 }
1868                 textype = TEXTYPE_DXT3;
1869                 bytesperblock = 16;
1870                 bytesperpixel = 0;
1871                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1872                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1873                 {
1874                         Mem_Free(dds);
1875                         Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1876                         return NULL;
1877                 }
1878                 // we currently always assume alpha
1879         }
1880         else if (!memcmp(dds+84, "DXT5", 4))
1881         {
1882                 if(!vid.support.ext_texture_compression_s3tc)
1883                 {
1884                         Mem_Free(dds);
1885                         return NULL;
1886                 }
1887                 textype = TEXTYPE_DXT5;
1888                 bytesperblock = 16;
1889                 bytesperpixel = 0;
1890                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1891                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1892                 {
1893                         Mem_Free(dds);
1894                         Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1895                         return NULL;
1896                 }
1897                 // we currently always assume alpha
1898         }
1899         else
1900         {
1901                 Mem_Free(dds);
1902                 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1903                 return NULL;
1904         }
1905
1906         // return whether this texture is transparent
1907         if (hasalphaflag)
1908                 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1909
1910         // calculate average color if requested
1911         if (avgcolor)
1912         {
1913                 float f;
1914                 Vector4Clear(avgcolor);
1915                 if (bytesperblock)
1916                 {
1917                         for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
1918                         {
1919                                 c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
1920                                 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1921                                 avgcolor[1] += ((c >>  5) & 0x3F) + ((c >> 21) & 0x3F);
1922                                 avgcolor[2] += ((c      ) & 0x1F) + ((c >> 16) & 0x1F);
1923                         }
1924                         f = (float)bytesperblock / size;
1925                         avgcolor[0] *= (0.5f / 31.0f) * f;
1926                         avgcolor[1] *= (0.5f / 63.0f) * f;
1927                         avgcolor[2] *= (0.5f / 31.0f) * f;
1928                         avgcolor[3] = 1; // too hard to calculate
1929                 }
1930                 else
1931                 {
1932                         for (i = 0;i < size;i += 4)
1933                         {
1934                                 avgcolor[0] += ddspixels[i+2];
1935                                 avgcolor[1] += ddspixels[i+1];
1936                                 avgcolor[2] += ddspixels[i];
1937                                 avgcolor[3] += ddspixels[i+3];
1938                         }
1939                         f = (1.0f / 255.0f) * bytesperpixel / size;
1940                         avgcolor[0] *= f;
1941                         avgcolor[1] *= f;
1942                         avgcolor[2] *= f;
1943                         avgcolor[3] *= f;
1944                 }
1945         }
1946
1947         // this is where we apply gl_picmip
1948         mippixels = ddspixels;
1949         mipwidth = dds_width;
1950         mipheight = dds_height;
1951         while(miplevel >= 1 && dds_miplevels >= 1)
1952         {
1953                 if (mipwidth <= 1 && mipheight <= 1)
1954                         break;
1955                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1956                 mippixels += mipsize; // just skip
1957                 --dds_miplevels;
1958                 --miplevel;
1959                 if (mipwidth > 1)
1960                         mipwidth >>= 1;
1961                 if (mipheight > 1)
1962                         mipheight >>= 1;
1963         }
1964
1965         // when not requesting mipmaps, do not load them
1966         if(!(flags & TEXF_MIPMAP))
1967                 dds_miplevels = 0;
1968
1969         if (dds_miplevels >= 1)
1970                 flags |= TEXF_MIPMAP;
1971         else
1972                 flags &= ~TEXF_MIPMAP;
1973
1974         // if S3TC is not supported, there's very little we can do about it
1975         if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
1976         {
1977                 Mem_Free(dds);
1978                 Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
1979                 return NULL;
1980         }
1981
1982         texinfo = R_GetTexTypeInfo(textype, flags);
1983
1984         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1985         strlcpy (glt->identifier, filename, sizeof(glt->identifier));
1986         glt->pool = pool;
1987         glt->chain = pool->gltchain;
1988         pool->gltchain = glt;
1989         glt->inputwidth = mipwidth;
1990         glt->inputheight = mipheight;
1991         glt->inputdepth = 1;
1992         glt->flags = flags;
1993         glt->textype = texinfo;
1994         glt->texturetype = GLTEXTURETYPE_2D;
1995         glt->inputdatasize = ddssize;
1996         glt->glinternalformat = texinfo->glinternalformat;
1997         glt->glformat = texinfo->glformat;
1998         glt->gltype = texinfo->gltype;
1999         glt->bytesperpixel = texinfo->internalbytesperpixel;
2000         glt->sides = 1;
2001         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2002         glt->tilewidth = mipwidth;
2003         glt->tileheight = mipheight;
2004         glt->tiledepth = 1;
2005         glt->miplevels = dds_miplevels;
2006
2007         // texture uploading can take a while, so make sure we're sending keepalives
2008         CL_KeepaliveMessage(false);
2009
2010         // create the texture object
2011         switch(vid.renderpath)
2012         {
2013         case RENDERPATH_GL11:
2014         case RENDERPATH_GL13:
2015         case RENDERPATH_GL20:
2016         case RENDERPATH_CGGL:
2017                 CHECKGLERROR
2018                 GL_ActiveTexture(0);
2019                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2020                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2021                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2022                 break;
2023         case RENDERPATH_D3D9:
2024 #ifdef SUPPORTD3D
2025                 {
2026                         D3DFORMAT d3dformat;
2027                         D3DPOOL d3dpool;
2028                         DWORD d3dusage;
2029                         switch(textype)
2030                         {
2031                         case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2032                         case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2033                         case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2034                         case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2035                         default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2036                         }
2037                         d3dusage = 0;
2038                         d3dpool = D3DPOOL_MANAGED;
2039                         IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2040                 }
2041 #endif
2042                 break;
2043         case RENDERPATH_D3D10:
2044                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2045                 break;
2046         case RENDERPATH_D3D11:
2047                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2048                 break;
2049         }
2050
2051         // upload the texture
2052         // we need to restore the texture binding after finishing the upload
2053         mipcomplete = false;
2054
2055         for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2056         {
2057                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2058                 if (mippixels + mipsize > dds + ddssize)
2059                         break;
2060                 switch(vid.renderpath)
2061                 {
2062                 case RENDERPATH_GL11:
2063                 case RENDERPATH_GL13:
2064                 case RENDERPATH_GL20:
2065                 case RENDERPATH_CGGL:
2066                         if (bytesperblock)
2067                         {
2068                                 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2069                         }
2070                         else
2071                         {
2072                                 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2073                         }
2074                         break;
2075                 case RENDERPATH_D3D9:
2076 #ifdef SUPPORTD3D
2077                         {
2078                                 D3DLOCKED_RECT d3dlockedrect;
2079                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2080                                 {
2081                                         memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2082                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2083                                 }
2084                                 break;
2085                         }
2086 #endif
2087                         break;
2088                 case RENDERPATH_D3D10:
2089                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2090                         break;
2091                 case RENDERPATH_D3D11:
2092                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2093                         break;
2094                 }
2095                 mippixels += mipsize;
2096                 if (mipwidth <= 1 && mipheight <= 1)
2097                 {
2098                         mipcomplete = true;
2099                         break;
2100                 }
2101                 if (mipwidth > 1)
2102                         mipwidth >>= 1;
2103                 if (mipheight > 1)
2104                         mipheight >>= 1;
2105         }
2106
2107         // after upload we have to set some parameters...
2108         switch(vid.renderpath)
2109         {
2110         case RENDERPATH_GL11:
2111         case RENDERPATH_GL13:
2112         case RENDERPATH_GL20:
2113         case RENDERPATH_CGGL:
2114                 if (dds_miplevels >= 1 && !mipcomplete)
2115                 {
2116                         // need to set GL_TEXTURE_MAX_LEVEL
2117                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2118                 }
2119                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2120                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2121                 break;
2122         case RENDERPATH_D3D9:
2123 #ifdef SUPPORTD3D
2124                 glt->d3daddressw = 0;
2125                 if (glt->flags & TEXF_CLAMP)
2126                 {
2127                         glt->d3daddressu = D3DTADDRESS_CLAMP;
2128                         glt->d3daddressv = D3DTADDRESS_CLAMP;
2129                         if (glt->tiledepth > 1)
2130                                 glt->d3daddressw = D3DTADDRESS_CLAMP;
2131                 }
2132                 else
2133                 {
2134                         glt->d3daddressu = D3DTADDRESS_WRAP;
2135                         glt->d3daddressv = D3DTADDRESS_WRAP;
2136                         if (glt->tiledepth > 1)
2137                                 glt->d3daddressw = D3DTADDRESS_WRAP;
2138                 }
2139                 glt->d3dmipmaplodbias = 0;
2140                 glt->d3dmaxmiplevel = 0;
2141                 glt->d3dmaxmiplevelfilter = 0;
2142                 if (glt->flags & TEXF_MIPMAP)
2143                 {
2144                         glt->d3dminfilter = d3d_filter_mipmin;
2145                         glt->d3dmagfilter = d3d_filter_mipmag;
2146                         glt->d3dmipfilter = d3d_filter_mipmix;
2147                 }
2148                 else
2149                 {
2150                         glt->d3dminfilter = d3d_filter_flatmin;
2151                         glt->d3dmagfilter = d3d_filter_flatmag;
2152                         glt->d3dmipfilter = d3d_filter_flatmix;
2153                 }
2154 #endif
2155                 break;
2156         case RENDERPATH_D3D10:
2157                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2158                 break;
2159         case RENDERPATH_D3D11:
2160                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2161                 break;
2162         }
2163
2164         Mem_Free(dds);
2165         return (rtexture_t *)glt;
2166 }
2167
2168 int R_TextureWidth(rtexture_t *rt)
2169 {
2170         return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2171 }
2172
2173 int R_TextureHeight(rtexture_t *rt)
2174 {
2175         return rt ? ((gltexture_t *)rt)->inputheight : 0;
2176 }
2177
2178 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
2179 {
2180         gltexture_t *glt = (gltexture_t *)rt;
2181         if (data == NULL)
2182                 Host_Error("R_UpdateTexture: no data supplied");
2183         if (glt == NULL)
2184                 Host_Error("R_UpdateTexture: no texture supplied");
2185         if (!glt->texnum && !glt->d3dtexture)
2186         {
2187                 Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", (void *)glt, glt->identifier, (void *)glt->pool);
2188                 return;
2189         }
2190         // update part of the texture
2191         if (glt->bufferpixels)
2192         {
2193                 int j;
2194                 int bpp = glt->bytesperpixel;
2195                 int inputskip = width*bpp;
2196                 int outputskip = glt->tilewidth*bpp;
2197                 const unsigned char *input = data;
2198                 unsigned char *output = glt->bufferpixels;
2199                 if (x < 0)
2200                 {
2201                         width += x;
2202                         input -= x*bpp;
2203                         x = 0;
2204                 }
2205                 if (y < 0)
2206                 {
2207                         height += y;
2208                         input -= y*inputskip;
2209                         y = 0;
2210                 }
2211                 if (width > glt->tilewidth - x)
2212                         width = glt->tilewidth - x;
2213                 if (height > glt->tileheight - y)
2214                         height = glt->tileheight - y;
2215                 if (width < 1 || height < 1)
2216                         return;
2217                 glt->dirty = true;
2218                 glt->buffermodified = true;
2219                 output += y*outputskip + x*bpp;
2220                 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2221                         memcpy(output, input, width*bpp);
2222         }
2223         else if (x || y || width != glt->inputwidth || height != glt->inputheight)
2224                 R_UploadPartialTexture(glt, data, x, y, 0, width, height, 1);
2225         else
2226                 R_UploadFullTexture(glt, data);
2227 }
2228
2229 int R_RealGetTexture(rtexture_t *rt)
2230 {
2231         if (rt)
2232         {
2233                 gltexture_t *glt;
2234                 glt = (gltexture_t *)rt;
2235                 if (glt->flags & GLTEXF_DYNAMIC)
2236                         R_UpdateDynamicTexture(glt);
2237                 if (glt->buffermodified && glt->bufferpixels)
2238                 {
2239                         glt->buffermodified = false;
2240                         R_UploadFullTexture(glt, glt->bufferpixels);
2241                 }
2242                 glt->dirty = false;
2243                 return glt->texnum;
2244         }
2245         else
2246                 return 0;
2247 }
2248
2249 void R_ClearTexture (rtexture_t *rt)
2250 {
2251         gltexture_t *glt = (gltexture_t *)rt;
2252
2253         R_UploadFullTexture(glt, NULL);
2254 }
2255
2256 int R_PicmipForFlags(int flags)
2257 {
2258         int miplevel = 0;
2259         if(flags & TEXF_PICMIP)
2260         {
2261                 miplevel += gl_picmip.integer;
2262                 if (flags & TEXF_ISWORLD)
2263                 {
2264                         if (r_picmipworld.integer)
2265                                 miplevel += gl_picmip_world.integer;
2266                         else
2267                                 miplevel = 0;
2268                 }
2269                 else if (flags & TEXF_ISSPRITE)
2270                 {
2271                         if (r_picmipsprites.integer)
2272                                 miplevel += gl_picmip_sprites.integer;
2273                         else
2274                                 miplevel = 0;
2275                 }
2276                 else
2277                         miplevel += gl_picmip_other.integer;
2278         }
2279         return max(0, miplevel);
2280 }