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