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