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