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