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