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