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