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