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