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