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