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