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