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