]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_textures.c
00a9c33d7e9355257bf27ca78e1df05669a5e3b0
[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                         }
1624                         Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1625                 }
1626         }
1627
1628         if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1629         {
1630                 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1631                 return NULL;
1632         }
1633         if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1634         {
1635                 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1636                 return NULL;
1637         }
1638
1639         texinfo = R_GetTexTypeInfo(textype, flags);
1640         size = width * height * depth * sides * texinfo->inputbytesperpixel;
1641         if (size < 1)
1642         {
1643                 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1644                 return NULL;
1645         }
1646
1647         // clear the alpha flag if the texture has no transparent pixels
1648         switch(textype)
1649         {
1650         case TEXTYPE_PALETTE:
1651         case TEXTYPE_SRGB_PALETTE:
1652                 if (flags & TEXF_ALPHA)
1653                 {
1654                         flags &= ~TEXF_ALPHA;
1655                         if (data)
1656                         {
1657                                 for (i = 0;i < size;i++)
1658                                 {
1659                                         if (((unsigned char *)&palette[data[i]])[3] < 255)
1660                                         {
1661                                                 flags |= TEXF_ALPHA;
1662                                                 break;
1663                                         }
1664                                 }
1665                         }
1666                 }
1667                 break;
1668         case TEXTYPE_RGBA:
1669         case TEXTYPE_BGRA:
1670         case TEXTYPE_SRGB_RGBA:
1671         case TEXTYPE_SRGB_BGRA:
1672                 if (flags & TEXF_ALPHA)
1673                 {
1674                         flags &= ~TEXF_ALPHA;
1675                         if (data)
1676                         {
1677                                 for (i = 3;i < size;i += 4)
1678                                 {
1679                                         if (data[i] < 255)
1680                                         {
1681                                                 flags |= TEXF_ALPHA;
1682                                                 break;
1683                                         }
1684                                 }
1685                         }
1686                 }
1687                 break;
1688         case TEXTYPE_SHADOWMAP:
1689                 break;
1690         case TEXTYPE_DXT1:
1691         case TEXTYPE_SRGB_DXT1:
1692                 break;
1693         case TEXTYPE_DXT1A:
1694         case TEXTYPE_SRGB_DXT1A:
1695         case TEXTYPE_DXT3:
1696         case TEXTYPE_SRGB_DXT3:
1697         case TEXTYPE_DXT5:
1698         case TEXTYPE_SRGB_DXT5:
1699                 flags |= TEXF_ALPHA;
1700                 break;
1701         case TEXTYPE_ALPHA:
1702                 flags |= TEXF_ALPHA;
1703                 break;
1704         case TEXTYPE_COLORBUFFER:
1705         case TEXTYPE_COLORBUFFER16F:
1706         case TEXTYPE_COLORBUFFER32F:
1707                 flags |= TEXF_ALPHA;
1708                 break;
1709         default:
1710                 Sys_Error("R_LoadTexture: unknown texture type");
1711         }
1712
1713         texinfo2 = R_GetTexTypeInfo(textype, flags);
1714         if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1715                 texinfo = texinfo2;
1716         else
1717                 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1718
1719         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1720         if (identifier)
1721                 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1722         glt->pool = pool;
1723         glt->chain = pool->gltchain;
1724         pool->gltchain = glt;
1725         glt->inputwidth = width;
1726         glt->inputheight = height;
1727         glt->inputdepth = depth;
1728         glt->flags = flags;
1729         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
1730         glt->textype = texinfo;
1731         glt->texturetype = texturetype;
1732         glt->inputdatasize = size;
1733         glt->palette = palette;
1734         glt->glinternalformat = texinfo->glinternalformat;
1735         glt->glformat = texinfo->glformat;
1736         glt->gltype = texinfo->gltype;
1737         glt->bytesperpixel = texinfo->internalbytesperpixel;
1738         glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1739         glt->texnum = 0;
1740         glt->dirty = false;
1741         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1742         // init the dynamic texture attributes, too [11/22/2007 Black]
1743         glt->updatecallback = NULL;
1744         glt->updatacallback_data = NULL;
1745
1746         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1747
1748         // upload the texture
1749         // data may be NULL (blank texture for dynamic rendering)
1750         switch(vid.renderpath)
1751         {
1752         case RENDERPATH_GL11:
1753         case RENDERPATH_GL13:
1754         case RENDERPATH_GL20:
1755         case RENDERPATH_GLES1:
1756         case RENDERPATH_GLES2:
1757                 CHECKGLERROR
1758                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1759                 break;
1760         case RENDERPATH_D3D9:
1761 #ifdef SUPPORTD3D
1762                 {
1763                         D3DFORMAT d3dformat;
1764                         D3DPOOL d3dpool;
1765                         DWORD d3dusage;
1766                         HRESULT d3dresult;
1767                         d3dusage = 0;
1768                         d3dpool = D3DPOOL_MANAGED;
1769                         if (flags & TEXF_RENDERTARGET)
1770                         {
1771                                 d3dusage |= D3DUSAGE_RENDERTARGET;
1772                                 d3dpool = D3DPOOL_DEFAULT;
1773                         }
1774                         switch(textype)
1775                         {
1776                         case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1777                         case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1778                         case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1779                         case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
1780                         case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
1781                         case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
1782                         case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1783                         case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1784                         default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1785                         }
1786                         glt->d3dformat = d3dformat;
1787                         glt->d3dusage = d3dusage;
1788                         glt->d3dpool = d3dpool;
1789                         glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1790                         if (glt->d3disdepthsurface)
1791                         {
1792                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1793                                         Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1794                         }
1795                         else if (glt->tiledepth > 1)
1796                         {
1797                                 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)))
1798                                         Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1799                         }
1800                         else if (glt->sides == 6)
1801                         {
1802                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1803                                         Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1804                         }
1805                         else
1806                         {
1807                                 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)))
1808                                         Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1809                         }
1810                 }
1811 #endif
1812                 break;
1813         case RENDERPATH_D3D10:
1814                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1815                 break;
1816         case RENDERPATH_D3D11:
1817                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1818                 break;
1819         case RENDERPATH_SOFT:
1820                 {
1821                         int tflags = 0;
1822                         switch(textype)
1823                         {
1824                         case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1825                         case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1826                         case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1827                         case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1828                         case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
1829                         case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
1830                         case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1831                         case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1832                         default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1833                         }
1834                         if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1835                         if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1836                         if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1837                         if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1838                         glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1839                 }
1840                 break;
1841         }
1842
1843         R_UploadFullTexture(glt, data);
1844         if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1845                 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1846
1847         // free any temporary processing buffer we allocated...
1848         if (temppixels)
1849                 Mem_Free(temppixels);
1850
1851         // texture converting and uploading can take a while, so make sure we're sending keepalives
1852         // FIXME: this causes rendering during R_Shadow_DrawLights
1853 //      CL_KeepaliveMessage(false);
1854
1855         return (rtexture_t *)glt;
1856 }
1857
1858 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)
1859 {
1860         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1861 }
1862
1863 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)
1864 {
1865         return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1866 }
1867
1868 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)
1869 {
1870         return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1871 }
1872
1873 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1874 {
1875         int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1876         if (filter)
1877                 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1878         else
1879                 flags |= TEXF_FORCENEAREST;
1880         if (precision <= 16)
1881                 flags |= TEXF_LOWPRECISION;
1882         return flags;
1883 }
1884
1885 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1886 {
1887         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1888 }
1889
1890 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1891 {
1892 #ifdef USE_GLES2
1893         return -1; // unsupported on this platform
1894 #else
1895         gltexture_t *glt = (gltexture_t *)rt;
1896         unsigned char *dds;
1897         int oldbindtexnum;
1898         int bytesperpixel = 0;
1899         int bytesperblock = 0;
1900         int dds_flags;
1901         int dds_format_flags;
1902         int dds_caps1;
1903         int dds_caps2;
1904         int ret;
1905         int mip;
1906         int mipmaps;
1907         int mipinfo[16][4];
1908         int ddssize = 128;
1909         GLint internalformat;
1910         const char *ddsfourcc;
1911         if (!rt)
1912                 return -1; // NULL pointer
1913         if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1914                 return -2; // broken driver - crashes on reading internal format
1915         if (!qglGetTexLevelParameteriv)
1916                 return -2;
1917         GL_ActiveTexture(0);
1918         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1919         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1920         qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1921         switch(internalformat)
1922         {
1923         default: ddsfourcc = NULL;bytesperpixel = 4;break;
1924         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1925         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1926         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1927         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1928         }
1929         // if premultiplied alpha, say so in the DDS file
1930         if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1931         {
1932                 switch(internalformat)
1933                 {
1934                         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1935                         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1936                 }
1937         }
1938         if (!bytesperblock && skipuncompressed)
1939                 return -3; // skipped
1940         memset(mipinfo, 0, sizeof(mipinfo));
1941         mipinfo[0][0] = glt->tilewidth;
1942         mipinfo[0][1] = glt->tileheight;
1943         mipmaps = 1;
1944         if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tilewidth == 1))
1945         {
1946                 for (mip = 1;mip < 16;mip++)
1947                 {
1948                         mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1949                         mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1950                         if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1951                         {
1952                                 mip++;
1953                                 break;
1954                         }
1955                 }
1956                 mipmaps = mip;
1957         }
1958         for (mip = 0;mip < mipmaps;mip++)
1959         {
1960                 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1961                 mipinfo[mip][3] = ddssize;
1962                 ddssize += mipinfo[mip][2];
1963         }
1964         dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1965         if (!dds)
1966                 return -4;
1967         dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1968         dds_caps2 = 0;
1969         if (bytesperblock)
1970         {
1971                 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1972                 dds_format_flags = 0x4; // DDPF_FOURCC
1973         }
1974         else
1975         {
1976                 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1977                 dds_format_flags = 0x40; // DDPF_RGB
1978         }
1979         if (mipmaps)
1980         {
1981                 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1982                 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1983         }
1984         if(hasalpha)
1985                 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1986         memcpy(dds, "DDS ", 4);
1987         StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
1988         StoreLittleLong(dds+8, dds_flags);
1989         StoreLittleLong(dds+12, mipinfo[0][1]); // height
1990         StoreLittleLong(dds+16, mipinfo[0][0]); // width
1991         StoreLittleLong(dds+24, 0); // depth
1992         StoreLittleLong(dds+28, mipmaps); // mipmaps
1993         StoreLittleLong(dds+76, 32); // format size
1994         StoreLittleLong(dds+80, dds_format_flags);
1995         StoreLittleLong(dds+108, dds_caps1);
1996         StoreLittleLong(dds+112, dds_caps2);
1997         if (bytesperblock)
1998         {
1999                 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
2000                 memcpy(dds+84, ddsfourcc, 4);
2001                 for (mip = 0;mip < mipmaps;mip++)
2002                 {
2003                         qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
2004                 }
2005         }
2006         else
2007         {
2008                 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
2009                 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
2010                 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
2011                 for (mip = 0;mip < mipmaps;mip++)
2012                 {
2013                         qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
2014                 }
2015         }
2016         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2017         ret = FS_WriteFile(filename, dds, ddssize);
2018         Mem_Free(dds);
2019         return ret ? ddssize : -5;
2020 #endif
2021 }
2022
2023 rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint
2024 {
2025         int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
2026         //int dds_flags;
2027         textype_t textype;
2028         int bytesperblock, bytesperpixel;
2029         int mipcomplete;
2030         gltexture_t *glt;
2031         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
2032         textypeinfo_t *texinfo;
2033         int mip, mipwidth, mipheight, mipsize, mipsize_total;
2034         unsigned int c;
2035         GLint oldbindtexnum = 0;
2036         const unsigned char *mippixels;
2037         const unsigned char *mippixels_start;
2038         unsigned char *ddspixels;
2039         unsigned char *dds;
2040         fs_offset_t ddsfilesize;
2041         unsigned int ddssize;
2042         qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
2043
2044         if (cls.state == ca_dedicated)
2045                 return NULL;
2046
2047         dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
2048         ddssize = ddsfilesize;
2049
2050         if (!dds)
2051         {
2052                 if(r_texture_dds_load_logfailure.integer)
2053                         Log_Printf("ddstexturefailures.log", "%s\n", filename);
2054                 return NULL; // not found
2055         }
2056
2057         if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
2058         {
2059                 Mem_Free(dds);
2060                 Con_Printf("^1%s: not a DDS image\n", filename);
2061                 return NULL;
2062         }
2063
2064         //dds_flags = BuffLittleLong(dds+8);
2065         dds_format_flags = BuffLittleLong(dds+80);
2066         dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
2067         dds_width = BuffLittleLong(dds+16);
2068         dds_height = BuffLittleLong(dds+12);
2069         ddspixels = dds + 128;
2070
2071         if(r_texture_dds_load_alphamode.integer == 0)
2072                 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
2073                         flags &= ~TEXF_ALPHA;
2074
2075         //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
2076         if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
2077         {
2078                 // very sloppy BGRA 32bit identification
2079                 textype = TEXTYPE_BGRA;
2080                 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2081                 bytesperblock = 0;
2082                 bytesperpixel = 4;
2083                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
2084                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2085                 {
2086                         Mem_Free(dds);
2087                         Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
2088                         return NULL;
2089                 }
2090                 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
2091                 {
2092                         // check alpha
2093                         for (i = 3;i < size;i += 4)
2094                                 if (ddspixels[i] < 255)
2095                                         break;
2096                         if (i >= size)
2097                                 flags &= ~TEXF_ALPHA;
2098                 }
2099         }
2100         else if (!memcmp(dds+84, "DXT1", 4))
2101         {
2102                 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
2103                 // LordHavoc: it is my belief that this does not infringe on the
2104                 // patent because it is not decoding pixels...
2105                 textype = TEXTYPE_DXT1;
2106                 bytesperblock = 8;
2107                 bytesperpixel = 0;
2108                 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
2109                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2110                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2111                 {
2112                         Mem_Free(dds);
2113                         Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
2114                         return NULL;
2115                 }
2116                 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
2117                 {
2118                         if(r_texture_dds_load_alphamode.integer == 1)
2119                         {
2120                                 // check alpha
2121                                 for (i = 0;i < size;i += bytesperblock)
2122                                         if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
2123                                         {
2124                                                 // NOTE: this assumes sizeof(unsigned int) == 4
2125                                                 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
2126                                                 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
2127                                                 if(data & (data<<1) & 0xAAAAAAAA)//rgh
2128                                                         break;
2129                                         }
2130                                 if (i < size)
2131                                         textype = TEXTYPE_DXT1A;
2132                                 else
2133                                         flags &= ~TEXF_ALPHA;
2134                         }
2135                         else
2136                         {
2137                                 flags &= ~TEXF_ALPHA;
2138                         }
2139                 }
2140         }
2141         else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2142         {
2143                 if(!memcmp(dds+84, "DXT2", 4))
2144                 {
2145                         if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2146                         {
2147                                 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2148                         }
2149                 }
2150                 else
2151                 {
2152                         if(flags & TEXF_RGBMULTIPLYBYALPHA)
2153                         {
2154                                 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2155                         }
2156                 }
2157                 textype = TEXTYPE_DXT3;
2158                 bytesperblock = 16;
2159                 bytesperpixel = 0;
2160                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2161                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2162                 {
2163                         Mem_Free(dds);
2164                         Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2165                         return NULL;
2166                 }
2167                 // we currently always assume alpha
2168         }
2169         else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2170         {
2171                 if(!memcmp(dds+84, "DXT4", 4))
2172                 {
2173                         if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2174                         {
2175                                 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2176                         }
2177                 }
2178                 else
2179                 {
2180                         if(flags & TEXF_RGBMULTIPLYBYALPHA)
2181                         {
2182                                 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2183                         }
2184                 }
2185                 textype = TEXTYPE_DXT5;
2186                 bytesperblock = 16;
2187                 bytesperpixel = 0;
2188                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2189                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2190                 {
2191                         Mem_Free(dds);
2192                         Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2193                         return NULL;
2194                 }
2195                 // we currently always assume alpha
2196         }
2197         else
2198         {
2199                 Mem_Free(dds);
2200                 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2201                 return NULL;
2202         }
2203
2204         // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
2205         if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
2206         {
2207                 textype = TEXTYPE_DXT1;
2208                 bytesperblock = 8;
2209                 ddssize -= 128;
2210                 ddssize /= 2;
2211                 for (i = 0;i < (int)ddssize;i += bytesperblock)
2212                         memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
2213                 ddssize += 128;
2214         }
2215
2216         force_swdecode = false;
2217         if(bytesperblock)
2218         {
2219                 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
2220                 {
2221                         if(r_texture_dds_swdecode.integer > 1)
2222                                 force_swdecode = true;
2223                 }
2224                 else
2225                 {
2226                         if(r_texture_dds_swdecode.integer < 1)
2227                         {
2228                                 // unsupported
2229                                 Mem_Free(dds);
2230                                 return NULL;
2231                         }
2232                         force_swdecode = true;
2233                 }
2234         }
2235
2236         // return whether this texture is transparent
2237         if (hasalphaflag)
2238                 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2239
2240         // if we SW decode, choose 2 sizes bigger
2241         if(force_swdecode)
2242         {
2243                 // this is quarter res, so do not scale down more than we have to
2244                 miplevel -= 2;
2245
2246                 if(miplevel < 0)
2247                         Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2248         }
2249
2250         // this is where we apply gl_picmip
2251         mippixels_start = ddspixels;
2252         mipwidth = dds_width;
2253         mipheight = dds_height;
2254         while(miplevel >= 1 && dds_miplevels >= 1)
2255         {
2256                 if (mipwidth <= 1 && mipheight <= 1)
2257                         break;
2258                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2259                 mippixels_start += mipsize; // just skip
2260                 --dds_miplevels;
2261                 --miplevel;
2262                 if (mipwidth > 1)
2263                         mipwidth >>= 1;
2264                 if (mipheight > 1)
2265                         mipheight >>= 1;
2266         }
2267         mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2268         mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2269
2270         // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2271
2272         // fake decode S3TC if needed
2273         if(force_swdecode)
2274         {
2275                 int mipsize_new = mipsize_total / bytesperblock * 4;
2276                 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2277                 unsigned char *p = mipnewpixels;
2278                 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2279                 {
2280                         c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2281                         p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2282                         p[1] = (((c >>  5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2283                         p[0] = (((c      ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2284                         if(textype == TEXTYPE_DXT5)
2285                                 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2286                         else if(textype == TEXTYPE_DXT3)
2287                                 p[3] = (
2288                                           (mippixels_start[i-8] & 0x0F)
2289                                         + (mippixels_start[i-8] >> 4)
2290                                         + (mippixels_start[i-7] & 0x0F)
2291                                         + (mippixels_start[i-7] >> 4)
2292                                         + (mippixels_start[i-6] & 0x0F)
2293                                         + (mippixels_start[i-6] >> 4)
2294                                         + (mippixels_start[i-5] & 0x0F)
2295                                         + (mippixels_start[i-5] >> 4)
2296                                        ) * (0.125f / 15.0f * 255.0f);
2297                         else
2298                                 p[3] = 255;
2299                 }
2300
2301                 textype = TEXTYPE_BGRA;
2302                 bytesperblock = 0;
2303                 bytesperpixel = 4;
2304
2305                 // as each block becomes a pixel, we must use pixel count for this
2306                 mipwidth = (mipwidth + 3) / 4;
2307                 mipheight = (mipheight + 3) / 4;
2308                 mipsize = bytesperpixel * mipwidth * mipheight;
2309                 mippixels_start = mipnewpixels;
2310                 mipsize_total = mipsize_new;
2311         }
2312
2313         // start mip counting
2314         mippixels = mippixels_start;
2315
2316         // calculate average color if requested
2317         if (avgcolor)
2318         {
2319                 float f;
2320                 Vector4Clear(avgcolor);
2321                 if (bytesperblock)
2322                 {
2323                         for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2324                         {
2325                                 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2326                                 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2327                                 avgcolor[1] += ((c >>  5) & 0x3F) + ((c >> 21) & 0x3F);
2328                                 avgcolor[2] += ((c      ) & 0x1F) + ((c >> 16) & 0x1F);
2329                                 if(textype == TEXTYPE_DXT5)
2330                                         avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2331                                 else if(textype == TEXTYPE_DXT3)
2332                                         avgcolor[3] += (
2333                                                   (mippixels_start[i-8] & 0x0F)
2334                                                 + (mippixels_start[i-8] >> 4)
2335                                                 + (mippixels_start[i-7] & 0x0F)
2336                                                 + (mippixels_start[i-7] >> 4)
2337                                                 + (mippixels_start[i-6] & 0x0F)
2338                                                 + (mippixels_start[i-6] >> 4)
2339                                                 + (mippixels_start[i-5] & 0x0F)
2340                                                 + (mippixels_start[i-5] >> 4)
2341                                                ) * (0.125f / 15.0f * 255.0f);
2342                                 else
2343                                         avgcolor[3] += 255;
2344                         }
2345                         f = (float)bytesperblock / size;
2346                         avgcolor[0] *= (0.5f / 31.0f) * f;
2347                         avgcolor[1] *= (0.5f / 63.0f) * f;
2348                         avgcolor[2] *= (0.5f / 31.0f) * f;
2349                         avgcolor[3] *= f;
2350                 }
2351                 else
2352                 {
2353                         for (i = 0;i < mipsize;i += 4)
2354                         {
2355                                 avgcolor[0] += mippixels[i+2];
2356                                 avgcolor[1] += mippixels[i+1];
2357                                 avgcolor[2] += mippixels[i];
2358                                 avgcolor[3] += mippixels[i+3];
2359                         }
2360                         f = (1.0f / 255.0f) * bytesperpixel / size;
2361                         avgcolor[0] *= f;
2362                         avgcolor[1] *= f;
2363                         avgcolor[2] *= f;
2364                         avgcolor[3] *= f;
2365                 }
2366         }
2367
2368         // when not requesting mipmaps, do not load them
2369         if(!(flags & TEXF_MIPMAP))
2370                 dds_miplevels = 0;
2371
2372         if (dds_miplevels >= 1)
2373                 flags |= TEXF_MIPMAP;
2374         else
2375                 flags &= ~TEXF_MIPMAP;
2376
2377         texinfo = R_GetTexTypeInfo(textype, flags);
2378
2379         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2380         strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2381         glt->pool = pool;
2382         glt->chain = pool->gltchain;
2383         pool->gltchain = glt;
2384         glt->inputwidth = mipwidth;
2385         glt->inputheight = mipheight;
2386         glt->inputdepth = 1;
2387         glt->flags = flags;
2388         glt->textype = texinfo;
2389         glt->texturetype = GLTEXTURETYPE_2D;
2390         glt->inputdatasize = ddssize;
2391         glt->glinternalformat = texinfo->glinternalformat;
2392         glt->glformat = texinfo->glformat;
2393         glt->gltype = texinfo->gltype;
2394         glt->bytesperpixel = texinfo->internalbytesperpixel;
2395         glt->sides = 1;
2396         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2397         glt->tilewidth = mipwidth;
2398         glt->tileheight = mipheight;
2399         glt->tiledepth = 1;
2400         glt->miplevels = dds_miplevels;
2401
2402         // texture uploading can take a while, so make sure we're sending keepalives
2403         CL_KeepaliveMessage(false);
2404
2405         // create the texture object
2406         switch(vid.renderpath)
2407         {
2408         case RENDERPATH_GL11:
2409         case RENDERPATH_GL13:
2410         case RENDERPATH_GL20:
2411         case RENDERPATH_GLES1:
2412         case RENDERPATH_GLES2:
2413                 CHECKGLERROR
2414                 GL_ActiveTexture(0);
2415                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2416                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2417                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2418                 break;
2419         case RENDERPATH_D3D9:
2420 #ifdef SUPPORTD3D
2421                 {
2422                         D3DFORMAT d3dformat;
2423                         D3DPOOL d3dpool;
2424                         DWORD d3dusage;
2425                         switch(textype)
2426                         {
2427                         case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2428                         case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2429                         case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2430                         case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2431                         default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2432                         }
2433                         d3dusage = 0;
2434                         d3dpool = D3DPOOL_MANAGED;
2435                         IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2436                 }
2437 #endif
2438                 break;
2439         case RENDERPATH_D3D10:
2440                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2441                 break;
2442         case RENDERPATH_D3D11:
2443                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2444                 break;
2445         case RENDERPATH_SOFT:
2446                 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);
2447                 break;
2448         }
2449
2450         // upload the texture
2451         // we need to restore the texture binding after finishing the upload
2452         mipcomplete = false;
2453
2454         for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2455         {
2456                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2457                 if (mippixels + mipsize > mippixels_start + mipsize_total)
2458                         break;
2459                 switch(vid.renderpath)
2460                 {
2461                 case RENDERPATH_GL11:
2462                 case RENDERPATH_GL13:
2463                 case RENDERPATH_GL20:
2464                 case RENDERPATH_GLES1:
2465                 case RENDERPATH_GLES2:
2466                         if (bytesperblock)
2467                         {
2468                                 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2469                         }
2470                         else
2471                         {
2472                                 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2473                         }
2474                         break;
2475                 case RENDERPATH_D3D9:
2476 #ifdef SUPPORTD3D
2477                         {
2478                                 D3DLOCKED_RECT d3dlockedrect;
2479                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2480                                 {
2481                                         memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2482                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2483                                 }
2484                                 break;
2485                         }
2486 #endif
2487                         break;
2488                 case RENDERPATH_D3D10:
2489                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2490                         break;
2491                 case RENDERPATH_D3D11:
2492                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2493                         break;
2494                 case RENDERPATH_SOFT:
2495                         if (bytesperblock)
2496                                 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2497                         else
2498                                 DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
2499                         // DPSOFTRAST calculates its own mipmaps
2500                         mip = dds_miplevels;
2501                         break;
2502                 }
2503                 mippixels += mipsize;
2504                 if (mipwidth <= 1 && mipheight <= 1)
2505                 {
2506                         mipcomplete = true;
2507                         break;
2508                 }
2509                 if (mipwidth > 1)
2510                         mipwidth >>= 1;
2511                 if (mipheight > 1)
2512                         mipheight >>= 1;
2513         }
2514
2515         // after upload we have to set some parameters...
2516         switch(vid.renderpath)
2517         {
2518         case RENDERPATH_GL11:
2519         case RENDERPATH_GL13:
2520         case RENDERPATH_GL20:
2521         case RENDERPATH_GLES1:
2522         case RENDERPATH_GLES2:
2523 #ifdef GL_TEXTURE_MAX_LEVEL
2524                 if (dds_miplevels >= 1 && !mipcomplete)
2525                 {
2526                         // need to set GL_TEXTURE_MAX_LEVEL
2527                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2528                 }
2529 #endif
2530                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2531                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2532                 break;
2533         case RENDERPATH_D3D9:
2534 #ifdef SUPPORTD3D
2535                 glt->d3daddressw = 0;
2536                 if (glt->flags & TEXF_CLAMP)
2537                 {
2538                         glt->d3daddressu = D3DTADDRESS_CLAMP;
2539                         glt->d3daddressv = D3DTADDRESS_CLAMP;
2540                         if (glt->tiledepth > 1)
2541                                 glt->d3daddressw = D3DTADDRESS_CLAMP;
2542                 }
2543                 else
2544                 {
2545                         glt->d3daddressu = D3DTADDRESS_WRAP;
2546                         glt->d3daddressv = D3DTADDRESS_WRAP;
2547                         if (glt->tiledepth > 1)
2548                                 glt->d3daddressw = D3DTADDRESS_WRAP;
2549                 }
2550                 glt->d3dmipmaplodbias = 0;
2551                 glt->d3dmaxmiplevel = 0;
2552                 glt->d3dmaxmiplevelfilter = 0;
2553                 if (glt->flags & TEXF_MIPMAP)
2554                 {
2555                         glt->d3dminfilter = d3d_filter_mipmin;
2556                         glt->d3dmagfilter = d3d_filter_mipmag;
2557                         glt->d3dmipfilter = d3d_filter_mipmix;
2558                 }
2559                 else
2560                 {
2561                         glt->d3dminfilter = d3d_filter_flatmin;
2562                         glt->d3dmagfilter = d3d_filter_flatmag;
2563                         glt->d3dmipfilter = d3d_filter_flatmix;
2564                 }
2565 #endif
2566                 break;
2567         case RENDERPATH_D3D10:
2568                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2569                 break;
2570         case RENDERPATH_D3D11:
2571                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2572                 break;
2573         case RENDERPATH_SOFT:
2574                 if (glt->flags & TEXF_FORCELINEAR)
2575                         DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2576                 else if (glt->flags & TEXF_FORCENEAREST)
2577                         DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2578                 else if (glt->flags & TEXF_MIPMAP)
2579                         DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2580                 else
2581                         DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2582                 break;
2583         }
2584
2585         Mem_Free(dds);
2586         if(force_swdecode)
2587                 Mem_Free((unsigned char *) mippixels_start);
2588         return (rtexture_t *)glt;
2589 }
2590
2591 int R_TextureWidth(rtexture_t *rt)
2592 {
2593         return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2594 }
2595
2596 int R_TextureHeight(rtexture_t *rt)
2597 {
2598         return rt ? ((gltexture_t *)rt)->inputheight : 0;
2599 }
2600
2601 int R_TextureFlags(rtexture_t *rt)
2602 {
2603         return rt ? ((gltexture_t *)rt)->flags : 0;
2604 }
2605
2606 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2607 {
2608         gltexture_t *glt = (gltexture_t *)rt;
2609         if (data == NULL)
2610                 Host_Error("R_UpdateTexture: no data supplied");
2611         if (glt == NULL)
2612                 Host_Error("R_UpdateTexture: no texture supplied");
2613         if (!glt->texnum && !glt->d3dtexture)
2614         {
2615                 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2616                 return;
2617         }
2618         // update part of the texture
2619         if (glt->bufferpixels)
2620         {
2621                 int j;
2622                 int bpp = glt->bytesperpixel;
2623                 int inputskip = width*bpp;
2624                 int outputskip = glt->tilewidth*bpp;
2625                 const unsigned char *input = data;
2626                 unsigned char *output = glt->bufferpixels;
2627                 if (glt->inputdepth != 1 || glt->sides != 1)
2628                         Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2629                 if (x < 0)
2630                 {
2631                         width += x;
2632                         input -= x*bpp;
2633                         x = 0;
2634                 }
2635                 if (y < 0)
2636                 {
2637                         height += y;
2638                         input -= y*inputskip;
2639                         y = 0;
2640                 }
2641                 if (width > glt->tilewidth - x)
2642                         width = glt->tilewidth - x;
2643                 if (height > glt->tileheight - y)
2644                         height = glt->tileheight - y;
2645                 if (width < 1 || height < 1)
2646                         return;
2647                 glt->dirty = true;
2648                 glt->buffermodified = true;
2649                 output += y*outputskip + x*bpp;
2650                 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2651                         memcpy(output, input, width*bpp);
2652         }
2653         else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2654                 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2655         else
2656                 R_UploadFullTexture(glt, data);
2657 }
2658
2659 int R_RealGetTexture(rtexture_t *rt)
2660 {
2661         if (rt)
2662         {
2663                 gltexture_t *glt;
2664                 glt = (gltexture_t *)rt;
2665                 if (glt->flags & GLTEXF_DYNAMIC)
2666                         R_UpdateDynamicTexture(glt);
2667                 if (glt->buffermodified && glt->bufferpixels)
2668                 {
2669                         glt->buffermodified = false;
2670                         R_UploadFullTexture(glt, glt->bufferpixels);
2671                 }
2672                 glt->dirty = false;
2673                 return glt->texnum;
2674         }
2675         else
2676                 return 0;
2677 }
2678
2679 void R_ClearTexture (rtexture_t *rt)
2680 {
2681         gltexture_t *glt = (gltexture_t *)rt;
2682
2683         R_UploadFullTexture(glt, NULL);
2684 }
2685
2686 int R_PicmipForFlags(int flags)
2687 {
2688         int miplevel = 0;
2689         if(flags & TEXF_PICMIP)
2690         {
2691                 miplevel += gl_picmip.integer;
2692                 if (flags & TEXF_ISWORLD)
2693                 {
2694                         if (r_picmipworld.integer)
2695                                 miplevel += gl_picmip_world.integer;
2696                         else
2697                                 miplevel = 0;
2698                 }
2699                 else if (flags & TEXF_ISSPRITE)
2700                 {
2701                         if (r_picmipsprites.integer)
2702                                 miplevel += gl_picmip_sprites.integer;
2703                         else
2704                                 miplevel = 0;
2705                 }
2706                 else
2707                         miplevel += gl_picmip_other.integer;
2708         }
2709         return max(0, miplevel);
2710 }