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