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