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