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