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