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