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