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