]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_textures.c
7503d6527770c03d05816c04b8eba92c0191ff8b
[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};
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              , 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              , 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              , 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              , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
102 static textypeinfo_t textype_depth16                     = {"depth16",                  TEXTYPE_DEPTHBUFFER16        ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
103 static textypeinfo_t textype_depth24                     = {"depth24",                  TEXTYPE_DEPTHBUFFER24        ,  4,  4,  4.0f, GL_DEPTH_COMPONENT24              , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
104 static textypeinfo_t textype_depth24stencil8             = {"depth24stencil8",          TEXTYPE_DEPTHBUFFER24STENCIL8,  4,  4,  4.0f, GL_DEPTH24_STENCIL8               , GL_DEPTH_STENCIL  , GL_UNSIGNED_INT_24_8};
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                        , GL_RGBA           , GL_HALF_FLOAT    };
107 static textypeinfo_t textype_colorbuffer32f              = {"colorbuffer32f",           TEXTYPE_COLORBUFFER32F       , 16, 16, 16.0f, GL_RGBA32F                        , 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                               , 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                         , GL_BGRA           , GL_UNSIGNED_BYTE };
127 static textypeinfo_t textype_sRGB_rgba                   = {"sRGB_rgba",                TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_SRGB                               , 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                         , 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                               , 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                         , 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 #ifndef USE_GLES2
894         switch(textype)
895         {
896         case TEXTYPE_SHADOWMAP16_COMP:
897         case TEXTYPE_SHADOWMAP24_COMP:
898                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);CHECKGLERROR
899                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);CHECKGLERROR
900                 break;
901         case TEXTYPE_SHADOWMAP16_RAW:
902         case TEXTYPE_SHADOWMAP24_RAW:
903                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE, GL_NONE);CHECKGLERROR
904                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);CHECKGLERROR
905                 break;
906         default:
907                 break;
908         }
909 #endif
910
911         CHECKGLERROR
912 }
913
914 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
915 {
916         if (data == NULL)
917                 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
918
919         if (glt->texturetype != GLTEXTURETYPE_2D)
920                 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
921
922         if (glt->textype->textype == TEXTYPE_PALETTE)
923                 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
924
925         if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
926                 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
927
928         if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
929                 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
930
931         // update a portion of the image
932
933         switch(vid.renderpath)
934         {
935         case RENDERPATH_GL32:
936         case RENDERPATH_GLES2:
937                 {
938                         int oldbindtexnum;
939                         CHECKGLERROR
940                         // we need to restore the texture binding after finishing the upload
941                         GL_ActiveTexture(0);
942                         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
943                         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
944                         qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
945                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
946                 }
947                 break;
948         }
949 }
950
951 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
952 {
953         int i, mip = 0, width, height, depth;
954         GLint oldbindtexnum = 0;
955         const unsigned char *prevbuffer;
956         prevbuffer = data;
957
958         // error out if a stretch is needed on special texture types
959         if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
960                 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
961
962         // when picmip or maxsize is applied, we scale up to a power of 2 multiple
963         // of the target size and then use the mipmap reduction function to get
964         // high quality supersampled results
965         for (width  = glt->tilewidth;width  < glt->inputwidth ;width  <<= 1);
966         for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
967         for (depth  = glt->tiledepth;depth  < glt->inputdepth ;depth  <<= 1);
968
969         if (prevbuffer == NULL)
970         {
971                 width = glt->tilewidth;
972                 height = glt->tileheight;
973                 depth = glt->tiledepth;
974 //              R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
975 //              memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
976 //              prevbuffer = resizebuffer;
977         }
978         else
979         {
980                 if (glt->textype->textype == TEXTYPE_PALETTE)
981                 {
982                         // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
983                         R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
984                         Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
985                         prevbuffer = colorconvertbuffer;
986                 }
987                 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
988                 {
989                         // multiply RGB channels by A channel before uploading
990                         int alpha;
991                         R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
992                         for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
993                         {
994                                 alpha = prevbuffer[i+3];
995                                 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
996                                 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
997                                 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
998                                 colorconvertbuffer[i+3] = alpha;
999                         }
1000                         prevbuffer = colorconvertbuffer;
1001                 }
1002                 // scale up to a power of 2 size (if appropriate)
1003                 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1004                 {
1005                         R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1006                         Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1007                         prevbuffer = resizebuffer;
1008                 }
1009                 // apply mipmap reduction algorithm to get down to picmip/max_size
1010                 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1011                 {
1012                         R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1013                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1014                         prevbuffer = resizebuffer;
1015                 }
1016         }
1017
1018         // do the appropriate upload type...
1019         switch(vid.renderpath)
1020         {
1021         case RENDERPATH_GL32:
1022         case RENDERPATH_GLES2:
1023                 if (glt->texnum) // not renderbuffers
1024                 {
1025                         CHECKGLERROR
1026
1027                         // we need to restore the texture binding after finishing the upload
1028                         GL_ActiveTexture(0);
1029                         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1030                         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1031
1032 #ifndef USE_GLES2
1033                         if (gl_texturecompression.integer >= 2)
1034                                 qglHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
1035                         else
1036                                 qglHint(GL_TEXTURE_COMPRESSION_HINT, GL_FASTEST);
1037                         CHECKGLERROR
1038 #endif
1039                         switch(glt->texturetype)
1040                         {
1041                         case GLTEXTURETYPE_2D:
1042                                 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1043                                 if (glt->flags & TEXF_MIPMAP)
1044                                 {
1045                                         while (width > 1 || height > 1 || depth > 1)
1046                                         {
1047                                                 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1048                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1049                                                 prevbuffer = resizebuffer;
1050                                                 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1051                                         }
1052                                 }
1053                                 break;
1054                         case GLTEXTURETYPE_3D:
1055 #ifndef USE_GLES2
1056                                 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1057                                 if (glt->flags & TEXF_MIPMAP)
1058                                 {
1059                                         while (width > 1 || height > 1 || depth > 1)
1060                                         {
1061                                                 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1062                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1063                                                 prevbuffer = resizebuffer;
1064                                                 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1065                                         }
1066                                 }
1067 #endif
1068                                 break;
1069                         case GLTEXTURETYPE_CUBEMAP:
1070                                 // convert and upload each side in turn,
1071                                 // from a continuous block of input texels
1072                                 texturebuffer = (unsigned char *)prevbuffer;
1073                                 for (i = 0;i < 6;i++)
1074                                 {
1075                                         prevbuffer = texturebuffer;
1076                                         texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1077                                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1078                                         {
1079                                                 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1080                                                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1081                                                 prevbuffer = resizebuffer;
1082                                         }
1083                                         // picmip/max_size
1084                                         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1085                                         {
1086                                                 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1087                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1088                                                 prevbuffer = resizebuffer;
1089                                         }
1090                                         mip = 0;
1091                                         qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1092                                         if (glt->flags & TEXF_MIPMAP)
1093                                         {
1094                                                 while (width > 1 || height > 1 || depth > 1)
1095                                                 {
1096                                                         R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1097                                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1098                                                         prevbuffer = resizebuffer;
1099                                                         qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1100                                                 }
1101                                         }
1102                                 }
1103                                 break;
1104                         }
1105                         GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1106                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1107                 }
1108                 break;
1109         }
1110 }
1111
1112 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)
1113 {
1114         int i, size;
1115         gltexture_t *glt;
1116         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1117         textypeinfo_t *texinfo, *texinfo2;
1118         unsigned char *temppixels = NULL;
1119         qboolean swaprb;
1120
1121         if (cls.state == ca_dedicated)
1122                 return NULL;
1123
1124         // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1125         if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1126         {
1127                 int numpixels = width * height * depth * sides;
1128                 size = numpixels * 4;
1129                 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1130                 if (data)
1131                 {
1132                         const unsigned char *p;
1133                         unsigned char *o = temppixels;
1134                         for (i = 0;i < numpixels;i++, o += 4)
1135                         {
1136                                 p = (const unsigned char *)palette + 4*data[i];
1137                                 o[0] = p[2];
1138                                 o[1] = p[1];
1139                                 o[2] = p[0];
1140                                 o[3] = p[3];
1141                         }
1142                 }
1143                 data = temppixels;
1144                 textype = TEXTYPE_RGBA;
1145         }
1146         swaprb = false;
1147         switch(textype)
1148         {
1149         case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1150         case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1151         case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1152         case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1153         default: break;
1154         }
1155         if (swaprb)
1156         {
1157                 // swap bytes
1158                 static int rgbaswapindices[4] = {2, 1, 0, 3};
1159                 size = width * height * depth * sides * 4;
1160                 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1161                 if (data)
1162                         Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1163                 data = temppixels;
1164         }
1165
1166         // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1167         if (!vid.support.ext_texture_srgb)
1168         {
1169                 qboolean convertsRGB = false;
1170                 switch(textype)
1171                 {
1172                 case TEXTYPE_SRGB_DXT1:    textype = TEXTYPE_DXT1   ;convertsRGB = true;break;
1173                 case TEXTYPE_SRGB_DXT1A:   textype = TEXTYPE_DXT1A  ;convertsRGB = true;break;
1174                 case TEXTYPE_SRGB_DXT3:    textype = TEXTYPE_DXT3   ;convertsRGB = true;break;
1175                 case TEXTYPE_SRGB_DXT5:    textype = TEXTYPE_DXT5   ;convertsRGB = true;break;
1176                 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;/*convertsRGB = true;*/break;
1177                 case TEXTYPE_SRGB_RGBA:    textype = TEXTYPE_RGBA   ;convertsRGB = true;break;
1178                 case TEXTYPE_SRGB_BGRA:    textype = TEXTYPE_BGRA   ;convertsRGB = true;break;
1179                 default:
1180                         break;
1181                 }
1182                 if (convertsRGB && data)
1183                 {
1184                         size = width * height * depth * sides * 4;
1185                         if (!temppixels)
1186                         {
1187                                 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1188                                 memcpy(temppixels, data, size);
1189                                 data = temppixels;
1190                         }
1191                         Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1192                 }
1193         }
1194
1195         texinfo = R_GetTexTypeInfo(textype, flags);
1196         size = width * height * depth * sides * texinfo->inputbytesperpixel;
1197         if (size < 1)
1198         {
1199                 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1200                 return NULL;
1201         }
1202
1203         // clear the alpha flag if the texture has no transparent pixels
1204         switch(textype)
1205         {
1206         case TEXTYPE_PALETTE:
1207         case TEXTYPE_SRGB_PALETTE:
1208                 if (flags & TEXF_ALPHA)
1209                 {
1210                         flags &= ~TEXF_ALPHA;
1211                         if (data)
1212                         {
1213                                 for (i = 0;i < size;i++)
1214                                 {
1215                                         if (((unsigned char *)&palette[data[i]])[3] < 255)
1216                                         {
1217                                                 flags |= TEXF_ALPHA;
1218                                                 break;
1219                                         }
1220                                 }
1221                         }
1222                 }
1223                 break;
1224         case TEXTYPE_RGBA:
1225         case TEXTYPE_BGRA:
1226         case TEXTYPE_SRGB_RGBA:
1227         case TEXTYPE_SRGB_BGRA:
1228                 if (flags & TEXF_ALPHA)
1229                 {
1230                         flags &= ~TEXF_ALPHA;
1231                         if (data)
1232                         {
1233                                 for (i = 3;i < size;i += 4)
1234                                 {
1235                                         if (data[i] < 255)
1236                                         {
1237                                                 flags |= TEXF_ALPHA;
1238                                                 break;
1239                                         }
1240                                 }
1241                         }
1242                 }
1243                 break;
1244         case TEXTYPE_SHADOWMAP16_COMP:
1245         case TEXTYPE_SHADOWMAP16_RAW:
1246         case TEXTYPE_SHADOWMAP24_COMP:
1247         case TEXTYPE_SHADOWMAP24_RAW:
1248                 break;
1249         case TEXTYPE_DXT1:
1250         case TEXTYPE_SRGB_DXT1:
1251                 break;
1252         case TEXTYPE_DXT1A:
1253         case TEXTYPE_SRGB_DXT1A:
1254         case TEXTYPE_DXT3:
1255         case TEXTYPE_SRGB_DXT3:
1256         case TEXTYPE_DXT5:
1257         case TEXTYPE_SRGB_DXT5:
1258                 flags |= TEXF_ALPHA;
1259                 break;
1260         case TEXTYPE_ALPHA:
1261                 flags |= TEXF_ALPHA;
1262                 break;
1263         case TEXTYPE_COLORBUFFER:
1264         case TEXTYPE_COLORBUFFER16F:
1265         case TEXTYPE_COLORBUFFER32F:
1266                 flags |= TEXF_ALPHA;
1267                 break;
1268         default:
1269                 Sys_Error("R_LoadTexture: unknown texture type");
1270         }
1271
1272         texinfo2 = R_GetTexTypeInfo(textype, flags);
1273         if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1274                 texinfo = texinfo2;
1275         else
1276                 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1277
1278         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1279         if (identifier)
1280                 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1281         glt->pool = pool;
1282         glt->chain = pool->gltchain;
1283         pool->gltchain = glt;
1284         glt->inputwidth = width;
1285         glt->inputheight = height;
1286         glt->inputdepth = depth;
1287         glt->flags = flags;
1288         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
1289         glt->textype = texinfo;
1290         glt->texturetype = texturetype;
1291         glt->inputdatasize = size;
1292         glt->palette = palette;
1293         glt->glinternalformat = texinfo->glinternalformat;
1294         glt->glformat = texinfo->glformat;
1295         glt->gltype = texinfo->gltype;
1296         glt->bytesperpixel = texinfo->internalbytesperpixel;
1297         glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1298         glt->texnum = 0;
1299         glt->dirty = false;
1300         glt->glisdepthstencil = false;
1301         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1302         // init the dynamic texture attributes, too [11/22/2007 Black]
1303         glt->updatecallback = NULL;
1304         glt->updatecallback_data = NULL;
1305
1306         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1307
1308         // upload the texture
1309         // data may be NULL (blank texture for dynamic rendering)
1310         switch(vid.renderpath)
1311         {
1312         case RENDERPATH_GL32:
1313         case RENDERPATH_GLES2:
1314                 CHECKGLERROR
1315                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1316                 break;
1317         }
1318
1319         R_UploadFullTexture(glt, data);
1320         if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1321                 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1322
1323         // free any temporary processing buffer we allocated...
1324         if (temppixels)
1325                 Mem_Free(temppixels);
1326
1327         // texture converting and uploading can take a while, so make sure we're sending keepalives
1328         // FIXME: this causes rendering during R_Shadow_DrawLights
1329 //      CL_KeepaliveMessage(false);
1330
1331         return (rtexture_t *)glt;
1332 }
1333
1334 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)
1335 {
1336         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1337 }
1338
1339 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)
1340 {
1341         return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1342 }
1343
1344 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)
1345 {
1346         return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1347 }
1348
1349 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter)
1350 {
1351         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL);
1352 }
1353
1354 rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
1355 {
1356         gltexture_t *glt;
1357         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1358         textypeinfo_t *texinfo;
1359
1360         if (cls.state == ca_dedicated)
1361                 return NULL;
1362
1363         texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP);
1364
1365         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1366         if (identifier)
1367                 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1368         glt->pool = pool;
1369         glt->chain = pool->gltchain;
1370         pool->gltchain = glt;
1371         glt->inputwidth = width;
1372         glt->inputheight = height;
1373         glt->inputdepth = 1;
1374         glt->flags = TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_FORCENEAREST;
1375         glt->miplevel = 0;
1376         glt->textype = texinfo;
1377         glt->texturetype = textype;
1378         glt->inputdatasize = width*height*texinfo->internalbytesperpixel;
1379         glt->palette = NULL;
1380         glt->glinternalformat = texinfo->glinternalformat;
1381         glt->glformat = texinfo->glformat;
1382         glt->gltype = texinfo->gltype;
1383         glt->bytesperpixel = texinfo->internalbytesperpixel;
1384         glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1385         glt->texnum = 0;
1386         glt->dirty = false;
1387         glt->glisdepthstencil = textype == TEXTYPE_DEPTHBUFFER24STENCIL8;
1388         glt->gltexturetypeenum = GL_TEXTURE_2D;
1389         // init the dynamic texture attributes, too [11/22/2007 Black]
1390         glt->updatecallback = NULL;
1391         glt->updatecallback_data = NULL;
1392
1393         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1394
1395         // upload the texture
1396         // data may be NULL (blank texture for dynamic rendering)
1397         switch(vid.renderpath)
1398         {
1399         case RENDERPATH_GL32:
1400         case RENDERPATH_GLES2:
1401                 CHECKGLERROR
1402                 qglGenRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
1403                 qglBindRenderbuffer(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR
1404                 qglRenderbufferStorage(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR
1405                 // 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
1406                 qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR
1407                 break;
1408         }
1409
1410         return (rtexture_t *)glt;
1411 }
1412
1413 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1414 {
1415 #ifdef USE_GLES2
1416         return -1; // unsupported on this platform
1417 #else
1418         gltexture_t *glt = (gltexture_t *)rt;
1419         unsigned char *dds;
1420         int oldbindtexnum;
1421         int bytesperpixel = 0;
1422         int bytesperblock = 0;
1423         int dds_flags;
1424         int dds_format_flags;
1425         int dds_caps1;
1426         int dds_caps2;
1427         int ret;
1428         int mip;
1429         int mipmaps;
1430         int mipinfo[16][4];
1431         int ddssize = 128;
1432         GLint internalformat;
1433         const char *ddsfourcc;
1434         if (!rt)
1435                 return -1; // NULL pointer
1436         if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1437                 return -2; // broken driver - crashes on reading internal format
1438         if (!qglGetTexLevelParameteriv)
1439                 return -2;
1440         GL_ActiveTexture(0);
1441         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1442         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1443         qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1444         switch(internalformat)
1445         {
1446         default: ddsfourcc = NULL;bytesperpixel = 4;break;
1447         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1448         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1449         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1450         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1451         }
1452         // if premultiplied alpha, say so in the DDS file
1453         if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1454         {
1455                 switch(internalformat)
1456                 {
1457                         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1458                         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1459                 }
1460         }
1461         if (!bytesperblock && skipuncompressed)
1462                 return -3; // skipped
1463         memset(mipinfo, 0, sizeof(mipinfo));
1464         mipinfo[0][0] = glt->tilewidth;
1465         mipinfo[0][1] = glt->tileheight;
1466         mipmaps = 1;
1467         if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1))
1468         {
1469                 for (mip = 1;mip < 16;mip++)
1470                 {
1471                         mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1472                         mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1473                         if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1474                         {
1475                                 mip++;
1476                                 break;
1477                         }
1478                 }
1479                 mipmaps = mip;
1480         }
1481         for (mip = 0;mip < mipmaps;mip++)
1482         {
1483                 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1484                 mipinfo[mip][3] = ddssize;
1485                 ddssize += mipinfo[mip][2];
1486         }
1487         dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1488         if (!dds)
1489                 return -4;
1490         dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1491         dds_caps2 = 0;
1492         if (bytesperblock)
1493         {
1494                 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1495                 dds_format_flags = 0x4; // DDPF_FOURCC
1496         }
1497         else
1498         {
1499                 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1500                 dds_format_flags = 0x40; // DDPF_RGB
1501         }
1502         if (mipmaps)
1503         {
1504                 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1505                 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1506         }
1507         if(hasalpha)
1508                 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1509         memcpy(dds, "DDS ", 4);
1510         StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
1511         StoreLittleLong(dds+8, dds_flags);
1512         StoreLittleLong(dds+12, mipinfo[0][1]); // height
1513         StoreLittleLong(dds+16, mipinfo[0][0]); // width
1514         StoreLittleLong(dds+24, 0); // depth
1515         StoreLittleLong(dds+28, mipmaps); // mipmaps
1516         StoreLittleLong(dds+76, 32); // format size
1517         StoreLittleLong(dds+80, dds_format_flags);
1518         StoreLittleLong(dds+108, dds_caps1);
1519         StoreLittleLong(dds+112, dds_caps2);
1520         if (bytesperblock)
1521         {
1522                 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1523                 memcpy(dds+84, ddsfourcc, 4);
1524                 for (mip = 0;mip < mipmaps;mip++)
1525                 {
1526                         qglGetCompressedTexImage(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1527                 }
1528         }
1529         else
1530         {
1531                 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1532                 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1533                 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1534                 for (mip = 0;mip < mipmaps;mip++)
1535                 {
1536                         qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1537                 }
1538         }
1539         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1540         ret = FS_WriteFile(filename, dds, ddssize);
1541         Mem_Free(dds);
1542         return ret ? ddssize : -5;
1543 #endif
1544 }
1545
1546 #ifdef __ANDROID__
1547 // ELUAN: FIXME: separate this code
1548 #include "ktx10/include/ktx.h"
1549 #endif
1550
1551 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
1552 {
1553         int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1554         //int dds_flags;
1555         textype_t textype;
1556         int bytesperblock, bytesperpixel;
1557         int mipcomplete;
1558         gltexture_t *glt;
1559         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1560         textypeinfo_t *texinfo;
1561         int mip, mipwidth, mipheight, mipsize, mipsize_total;
1562         unsigned int c, r, g, b;
1563         GLint oldbindtexnum = 0;
1564         unsigned char *mippixels;
1565         unsigned char *mippixels_start;
1566         unsigned char *ddspixels;
1567         unsigned char *dds;
1568         fs_offset_t ddsfilesize;
1569         unsigned int ddssize;
1570         qboolean force_swdecode;
1571 #ifdef __ANDROID__
1572         // ELUAN: FIXME: separate this code
1573         char vabuf[1024];
1574         char vabuf2[1024];
1575         int strsize;
1576         KTX_dimensions sizes;
1577 #endif
1578
1579         if (cls.state == ca_dedicated)
1580                 return NULL;
1581
1582 #ifdef __ANDROID__
1583         // ELUAN: FIXME: separate this code
1584         if (vid.renderpath != RENDERPATH_GLES2)
1585         {
1586                 Con_DPrintf("KTX texture format is only supported on the GLES2 renderpath\n");
1587                 return NULL;
1588         }
1589
1590         // some textures are specified with extensions, so it becomes .tga.dds
1591         FS_StripExtension (filename, vabuf2, sizeof(vabuf2));
1592         FS_StripExtension (vabuf2, vabuf, sizeof(vabuf));
1593         FS_DefaultExtension (vabuf, ".ktx", sizeof(vabuf));
1594         strsize = strlen(vabuf);
1595         if (strsize > 5)
1596         for (i = 0; i <= strsize - 4; i++) // copy null termination
1597                 vabuf[i] = vabuf[i + 4];
1598
1599         Con_DPrintf("Loading %s...\n", vabuf);
1600         dds = FS_LoadFile(vabuf, tempmempool, true, &ddsfilesize);
1601         ddssize = ddsfilesize;
1602
1603         if (!dds)
1604         {
1605                 Con_DPrintf("Not found!\n");
1606                 return NULL; // not found
1607         }
1608         Con_DPrintf("Found!\n");
1609
1610         if (flags & TEXF_ALPHA)
1611         {
1612                 Con_DPrintf("KTX texture with alpha not supported yet, disabling\n");
1613                 flags &= ~TEXF_ALPHA;
1614         }
1615
1616         {
1617                 GLenum target;
1618                 GLenum glerror;
1619                 GLboolean isMipmapped;
1620                 KTX_error_code ktxerror;
1621
1622                 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1623
1624                 // texture uploading can take a while, so make sure we're sending keepalives
1625                 CL_KeepaliveMessage(false);
1626
1627                 // create the texture object
1628                 CHECKGLERROR
1629                 GL_ActiveTexture(0);
1630                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[GLTEXTURETYPE_2D]);
1631                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1632                 qglBindTexture(gltexturetypeenums[GLTEXTURETYPE_2D], glt->texnum);CHECKGLERROR
1633
1634                 // upload the texture
1635                 // we need to restore the texture binding after finishing the upload
1636
1637                 // NOTE: some drivers fail with ETC1 NPOT (only PowerVR?). This may make the driver crash later.
1638                 ktxerror = ktxLoadTextureM(dds, ddssize, &glt->texnum, &target, &sizes, &isMipmapped, &glerror,
1639                                                                 0, NULL);// can't CHECKGLERROR, the lib catches it
1640
1641                 // FIXME: delete texture if we fail here
1642                 if (target != GL_TEXTURE_2D)
1643                 {
1644                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1645                         Mem_Free(dds);
1646                         Con_DPrintf("%s target != GL_TEXTURE_2D, target == %x\n", vabuf, target);
1647                         return NULL; // FIXME: delete the texture from memory
1648                 }
1649
1650                 if (KTX_SUCCESS == ktxerror)
1651                 {
1652                         textype = TEXTYPE_ETC1;
1653                         flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
1654
1655                         // return whether this texture is transparent
1656                         if (hasalphaflag)
1657                                 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1658
1659                         // TODO: apply gl_picmip
1660                         // TODO: avgcolor
1661                         // TODO: srgb
1662                         // TODO: only load mipmaps if requested
1663
1664                         if (isMipmapped)
1665                                 flags |= TEXF_MIPMAP;
1666                         else
1667                                 flags &= ~TEXF_MIPMAP;
1668
1669                         texinfo = R_GetTexTypeInfo(textype, flags);
1670
1671                         strlcpy (glt->identifier, vabuf, sizeof(glt->identifier));
1672                         glt->pool = pool;
1673                         glt->chain = pool->gltchain;
1674                         pool->gltchain = glt;
1675                         glt->inputwidth = sizes.width;
1676                         glt->inputheight = sizes.height;
1677                         glt->inputdepth = 1;
1678                         glt->flags = flags;
1679                         glt->textype = texinfo;
1680                         glt->texturetype = GLTEXTURETYPE_2D;
1681                         glt->inputdatasize = ddssize;
1682                         glt->glinternalformat = texinfo->glinternalformat;
1683                         glt->glformat = texinfo->glformat;
1684                         glt->gltype = texinfo->gltype;
1685                         glt->bytesperpixel = texinfo->internalbytesperpixel;
1686                         glt->sides = 1;
1687                         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1688                         glt->tilewidth = sizes.width;
1689                         glt->tileheight = sizes.height;
1690                         glt->tiledepth = 1;
1691                         glt->miplevels = isMipmapped ? 1 : 0; // FIXME
1692
1693                                 // after upload we have to set some parameters...
1694 #ifdef GL_TEXTURE_MAX_LEVEL
1695                         /* FIXME
1696                                 if (dds_miplevels >= 1 && !mipcomplete)
1697                                 {
1698                                         // need to set GL_TEXTURE_MAX_LEVEL
1699                                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
1700                                 }
1701                         */
1702 #endif
1703                                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1704
1705                                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1706                                 Mem_Free(dds);
1707                                 return (rtexture_t *)glt;
1708                 }
1709                 else
1710                 {
1711                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1712                         Mem_Free(dds);
1713                         Con_DPrintf("KTX texture %s failed to load: %x\n", vabuf, ktxerror);
1714                         return NULL;
1715                 }
1716         }
1717 #endif // __ANDROID__
1718
1719         dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1720         ddssize = ddsfilesize;
1721
1722         if (!dds)
1723         {
1724                 if (r_texture_dds_load_logfailure.integer && (r_texture_dds_load_logfailure.integer >= 2 || !optionaltexture))
1725                         Log_Printf("ddstexturefailures.log", "%s\n", filename);
1726                 return NULL; // not found
1727         }
1728
1729         if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1730         {
1731                 Mem_Free(dds);
1732                 Con_Printf("^1%s: not a DDS image\n", filename);
1733                 return NULL;
1734         }
1735
1736         //dds_flags = BuffLittleLong(dds+8);
1737         dds_format_flags = BuffLittleLong(dds+80);
1738         dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1739         dds_width = BuffLittleLong(dds+16);
1740         dds_height = BuffLittleLong(dds+12);
1741         ddspixels = dds + 128;
1742
1743         if(r_texture_dds_load_alphamode.integer == 0)
1744                 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1745                         flags &= ~TEXF_ALPHA;
1746
1747         //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1748         if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1749         {
1750                 // very sloppy BGRA 32bit identification
1751                 textype = TEXTYPE_BGRA;
1752                 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
1753                 bytesperblock = 0;
1754                 bytesperpixel = 4;
1755                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1756                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1757                 {
1758                         Mem_Free(dds);
1759                         Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1760                         return NULL;
1761                 }
1762                 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1763                 {
1764                         // check alpha
1765                         for (i = 3;i < size;i += 4)
1766                                 if (ddspixels[i] < 255)
1767                                         break;
1768                         if (i >= size)
1769                                 flags &= ~TEXF_ALPHA;
1770                 }
1771         }
1772         else if (!memcmp(dds+84, "DXT1", 4))
1773         {
1774                 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1775                 // LordHavoc: it is my belief that this does not infringe on the
1776                 // patent because it is not decoding pixels...
1777                 textype = TEXTYPE_DXT1;
1778                 bytesperblock = 8;
1779                 bytesperpixel = 0;
1780                 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1781                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1782                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1783                 {
1784                         Mem_Free(dds);
1785                         Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1786                         return NULL;
1787                 }
1788                 if (flags & TEXF_ALPHA)
1789                 {
1790                         if (r_texture_dds_load_alphamode.integer == 1)
1791                         {
1792                                 // check alpha
1793                                 for (i = 0;i < size;i += bytesperblock)
1794                                         if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1795                                         {
1796                                                 // NOTE: this assumes sizeof(unsigned int) == 4
1797                                                 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1798                                                 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1799                                                 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1800                                                         break;
1801                                         }
1802                                 if (i < size)
1803                                         textype = TEXTYPE_DXT1A;
1804                                 else
1805                                         flags &= ~TEXF_ALPHA;
1806                         }
1807                         else if (r_texture_dds_load_alphamode.integer == 0)
1808                                 textype = TEXTYPE_DXT1A;
1809                         else
1810                         {
1811                                 flags &= ~TEXF_ALPHA;
1812                         }
1813                 }
1814         }
1815         else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
1816         {
1817                 if(!memcmp(dds+84, "DXT2", 4))
1818                 {
1819                         if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1820                         {
1821                                 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
1822                         }
1823                 }
1824                 else
1825                 {
1826                         if(flags & TEXF_RGBMULTIPLYBYALPHA)
1827                         {
1828                                 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
1829                         }
1830                 }
1831                 textype = TEXTYPE_DXT3;
1832                 bytesperblock = 16;
1833                 bytesperpixel = 0;
1834                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1835                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1836                 {
1837                         Mem_Free(dds);
1838                         Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1839                         return NULL;
1840                 }
1841                 // we currently always assume alpha
1842         }
1843         else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
1844         {
1845                 if(!memcmp(dds+84, "DXT4", 4))
1846                 {
1847                         if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1848                         {
1849                                 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
1850                         }
1851                 }
1852                 else
1853                 {
1854                         if(flags & TEXF_RGBMULTIPLYBYALPHA)
1855                         {
1856                                 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
1857                         }
1858                 }
1859                 textype = TEXTYPE_DXT5;
1860                 bytesperblock = 16;
1861                 bytesperpixel = 0;
1862                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1863                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1864                 {
1865                         Mem_Free(dds);
1866                         Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1867                         return NULL;
1868                 }
1869                 // we currently always assume alpha
1870         }
1871         else
1872         {
1873                 Mem_Free(dds);
1874                 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1875                 return NULL;
1876         }
1877
1878         // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
1879         if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
1880         {
1881                 textype = TEXTYPE_DXT1;
1882                 bytesperblock = 8;
1883                 ddssize -= 128;
1884                 ddssize /= 2;
1885                 for (i = 0;i < (int)ddssize;i += bytesperblock)
1886                         memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
1887                 ddssize += 128;
1888         }
1889
1890         force_swdecode = false;
1891         if(bytesperblock)
1892         {
1893                 if(vid.support.ext_texture_compression_s3tc)
1894                 {
1895                         if(r_texture_dds_swdecode.integer > 1)
1896                                 force_swdecode = true;
1897                 }
1898                 else
1899                 {
1900                         if(r_texture_dds_swdecode.integer < 1)
1901                         {
1902                                 // unsupported
1903                                 Mem_Free(dds);
1904                                 return NULL;
1905                         }
1906                         force_swdecode = true;
1907                 }
1908         }
1909
1910         // return whether this texture is transparent
1911         if (hasalphaflag)
1912                 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1913
1914         // if we SW decode, choose 2 sizes bigger
1915         if(force_swdecode)
1916         {
1917                 // this is quarter res, so do not scale down more than we have to
1918                 miplevel -= 2;
1919
1920                 if(miplevel < 0)
1921                         Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
1922         }
1923
1924         // this is where we apply gl_picmip
1925         mippixels_start = ddspixels;
1926         mipwidth = dds_width;
1927         mipheight = dds_height;
1928         while(miplevel >= 1 && dds_miplevels >= 1)
1929         {
1930                 if (mipwidth <= 1 && mipheight <= 1)
1931                         break;
1932                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1933                 mippixels_start += mipsize; // just skip
1934                 --dds_miplevels;
1935                 --miplevel;
1936                 if (mipwidth > 1)
1937                         mipwidth >>= 1;
1938                 if (mipheight > 1)
1939                         mipheight >>= 1;
1940         }
1941         mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
1942         mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1943
1944         // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
1945
1946         // fake decode S3TC if needed
1947         if(force_swdecode)
1948         {
1949                 int mipsize_new = mipsize_total / bytesperblock * 4;
1950                 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
1951                 unsigned char *p = mipnewpixels;
1952                 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
1953                 {
1954                         c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
1955                         p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
1956                         p[1] = (((c >>  5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
1957                         p[0] = (((c      ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
1958                         if(textype == TEXTYPE_DXT5)
1959                                 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
1960                         else if(textype == TEXTYPE_DXT3)
1961                                 p[3] = (
1962                                           (mippixels_start[i-8] & 0x0F)
1963                                         + (mippixels_start[i-8] >> 4)
1964                                         + (mippixels_start[i-7] & 0x0F)
1965                                         + (mippixels_start[i-7] >> 4)
1966                                         + (mippixels_start[i-6] & 0x0F)
1967                                         + (mippixels_start[i-6] >> 4)
1968                                         + (mippixels_start[i-5] & 0x0F)
1969                                         + (mippixels_start[i-5] >> 4)
1970                                        ) * (0.125f / 15.0f * 255.0f);
1971                         else
1972                                 p[3] = 255;
1973                 }
1974
1975                 textype = TEXTYPE_BGRA;
1976                 bytesperblock = 0;
1977                 bytesperpixel = 4;
1978
1979                 // as each block becomes a pixel, we must use pixel count for this
1980                 mipwidth = (mipwidth + 3) / 4;
1981                 mipheight = (mipheight + 3) / 4;
1982                 mipsize = bytesperpixel * mipwidth * mipheight;
1983                 mippixels_start = mipnewpixels;
1984                 mipsize_total = mipsize_new;
1985         }
1986
1987         // start mip counting
1988         mippixels = mippixels_start;
1989
1990         // calculate average color if requested
1991         if (avgcolor)
1992         {
1993                 float f;
1994                 Vector4Clear(avgcolor);
1995                 if (bytesperblock)
1996                 {
1997                         for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
1998                         {
1999                                 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2000                                 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2001                                 avgcolor[1] += ((c >>  5) & 0x3F) + ((c >> 21) & 0x3F);
2002                                 avgcolor[2] += ((c      ) & 0x1F) + ((c >> 16) & 0x1F);
2003                                 if(textype == TEXTYPE_DXT5)
2004                                         avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f);
2005                                 else if(textype == TEXTYPE_DXT3)
2006                                         avgcolor[3] += (
2007                                                   (mippixels_start[i-8] & 0x0F)
2008                                                 + (mippixels_start[i-8] >> 4)
2009                                                 + (mippixels_start[i-7] & 0x0F)
2010                                                 + (mippixels_start[i-7] >> 4)
2011                                                 + (mippixels_start[i-6] & 0x0F)
2012                                                 + (mippixels_start[i-6] >> 4)
2013                                                 + (mippixels_start[i-5] & 0x0F)
2014                                                 + (mippixels_start[i-5] >> 4)
2015                                                ) * (0.125f / 15.0f);
2016                                 else
2017                                         avgcolor[3] += 1.0f;
2018                         }
2019                         f = (float)bytesperblock / mipsize;
2020                         avgcolor[0] *= (0.5f / 31.0f) * f;
2021                         avgcolor[1] *= (0.5f / 63.0f) * f;
2022                         avgcolor[2] *= (0.5f / 31.0f) * f;
2023                         avgcolor[3] *= f;
2024                 }
2025                 else
2026                 {
2027                         for (i = 0;i < mipsize;i += 4)
2028                         {
2029                                 avgcolor[0] += mippixels[i+2];
2030                                 avgcolor[1] += mippixels[i+1];
2031                                 avgcolor[2] += mippixels[i];
2032                                 avgcolor[3] += mippixels[i+3];
2033                         }
2034                         f = (1.0f / 255.0f) * bytesperpixel / mipsize;
2035                         avgcolor[0] *= f;
2036                         avgcolor[1] *= f;
2037                         avgcolor[2] *= f;
2038                         avgcolor[3] *= f;
2039                 }
2040         }
2041
2042         // if we want sRGB, convert now
2043         if(srgb)
2044         {
2045                 if (vid.support.ext_texture_srgb)
2046                 {
2047                         switch(textype)
2048                         {
2049                         case TEXTYPE_DXT1:    textype = TEXTYPE_SRGB_DXT1   ;break;
2050                         case TEXTYPE_DXT1A:   textype = TEXTYPE_SRGB_DXT1A  ;break;
2051                         case TEXTYPE_DXT3:    textype = TEXTYPE_SRGB_DXT3   ;break;
2052                         case TEXTYPE_DXT5:    textype = TEXTYPE_SRGB_DXT5   ;break;
2053                         case TEXTYPE_RGBA:    textype = TEXTYPE_SRGB_RGBA   ;break;
2054                         default:
2055                                 break;
2056                         }
2057                 }
2058                 else
2059                 {
2060                         switch(textype)
2061                         {
2062                         case TEXTYPE_DXT1:
2063                         case TEXTYPE_DXT1A:
2064                         case TEXTYPE_DXT3:
2065                         case TEXTYPE_DXT5:
2066                                 {
2067                                         for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2068                                         {
2069                                                 int c0, c1, c0new, c1new;
2070                                                 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2071                                                 r = ((c0 >> 11) & 0x1F);
2072                                                 g = ((c0 >>  5) & 0x3F);
2073                                                 b = ((c0      ) & 0x1F);
2074                                                 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2075                                                 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2076                                                 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2077                                                 c0new = (r << 11) | (g << 5) | b;
2078                                                 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2079                                                 r = ((c1 >> 11) & 0x1F);
2080                                                 g = ((c1 >>  5) & 0x3F);
2081                                                 b = ((c1      ) & 0x1F);
2082                                                 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2083                                                 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2084                                                 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2085                                                 c1new = (r << 11) | (g << 5) | b;
2086                                                 // swap the colors if needed to fix order
2087                                                 if(c0 > c1) // thirds
2088                                                 {
2089                                                         if(c0new < c1new)
2090                                                         {
2091                                                                 c = c0new;
2092                                                                 c0new = c1new;
2093                                                                 c1new = c;
2094                                                                 if(c0new == c1new)
2095                                                                 mippixels_start[i+4] ^= 0x55;
2096                                                                 mippixels_start[i+5] ^= 0x55;
2097                                                                 mippixels_start[i+6] ^= 0x55;
2098                                                                 mippixels_start[i+7] ^= 0x55;
2099                                                         }
2100                                                         else if(c0new == c1new)
2101                                                         {
2102                                                                 mippixels_start[i+4] = 0x00;
2103                                                                 mippixels_start[i+5] = 0x00;
2104                                                                 mippixels_start[i+6] = 0x00;
2105                                                                 mippixels_start[i+7] = 0x00;
2106                                                         }
2107                                                 }
2108                                                 else // half + transparent
2109                                                 {
2110                                                         if(c0new > c1new)
2111                                                         {
2112                                                                 c = c0new;
2113                                                                 c0new = c1new;
2114                                                                 c1new = c;
2115                                                                 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2116                                                                 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2117                                                                 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2118                                                                 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2119                                                         }
2120                                                 }
2121                                                 mippixels_start[i] = c0new & 255;
2122                                                 mippixels_start[i+1] = c0new >> 8;
2123                                                 mippixels_start[i+2] = c1new & 255;
2124                                                 mippixels_start[i+3] = c1new >> 8;
2125                                         }
2126                                 }
2127                                 break;
2128                         case TEXTYPE_RGBA:
2129                                 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2130                                 break;
2131                         default:
2132                                 break;
2133                         }
2134                 }
2135         }
2136
2137         // when not requesting mipmaps, do not load them
2138         if(!(flags & TEXF_MIPMAP))
2139                 dds_miplevels = 0;
2140
2141         if (dds_miplevels >= 1)
2142                 flags |= TEXF_MIPMAP;
2143         else
2144                 flags &= ~TEXF_MIPMAP;
2145
2146         texinfo = R_GetTexTypeInfo(textype, flags);
2147
2148         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2149         strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2150         glt->pool = pool;
2151         glt->chain = pool->gltchain;
2152         pool->gltchain = glt;
2153         glt->inputwidth = mipwidth;
2154         glt->inputheight = mipheight;
2155         glt->inputdepth = 1;
2156         glt->flags = flags;
2157         glt->textype = texinfo;
2158         glt->texturetype = GLTEXTURETYPE_2D;
2159         glt->inputdatasize = ddssize;
2160         glt->glinternalformat = texinfo->glinternalformat;
2161         glt->glformat = texinfo->glformat;
2162         glt->gltype = texinfo->gltype;
2163         glt->bytesperpixel = texinfo->internalbytesperpixel;
2164         glt->sides = 1;
2165         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2166         glt->tilewidth = mipwidth;
2167         glt->tileheight = mipheight;
2168         glt->tiledepth = 1;
2169         glt->miplevels = dds_miplevels;
2170
2171         // texture uploading can take a while, so make sure we're sending keepalives
2172         CL_KeepaliveMessage(false);
2173
2174         // create the texture object
2175         switch(vid.renderpath)
2176         {
2177         case RENDERPATH_GL32:
2178         case RENDERPATH_GLES2:
2179                 CHECKGLERROR
2180                 GL_ActiveTexture(0);
2181                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2182                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2183                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2184                 break;
2185         }
2186
2187         // upload the texture
2188         // we need to restore the texture binding after finishing the upload
2189         mipcomplete = false;
2190
2191         for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2192         {
2193                 unsigned char *upload_mippixels = mippixels;
2194                 int upload_mipwidth = mipwidth;
2195                 int upload_mipheight = mipheight;
2196                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2197                 if (mippixels + mipsize > mippixels_start + mipsize_total)
2198                         break;
2199                 switch(vid.renderpath)
2200                 {
2201                 case RENDERPATH_GL32:
2202                 case RENDERPATH_GLES2:
2203                         if (bytesperblock)
2204                         {
2205                                 qglCompressedTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR
2206                         }
2207                         else
2208                         {
2209                                 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR
2210                         }
2211                         break;
2212                 }
2213                 if(upload_mippixels != mippixels)
2214                         Mem_Free(upload_mippixels);
2215                 mippixels += mipsize;
2216                 if (mipwidth <= 1 && mipheight <= 1)
2217                 {
2218                         mipcomplete = true;
2219                         break;
2220                 }
2221                 if (mipwidth > 1)
2222                         mipwidth >>= 1;
2223                 if (mipheight > 1)
2224                         mipheight >>= 1;
2225         }
2226
2227         // after upload we have to set some parameters...
2228         switch(vid.renderpath)
2229         {
2230         case RENDERPATH_GL32:
2231         case RENDERPATH_GLES2:
2232 #ifdef GL_TEXTURE_MAX_LEVEL
2233                 if (dds_miplevels >= 1 && !mipcomplete)
2234                 {
2235                         // need to set GL_TEXTURE_MAX_LEVEL
2236                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2237                 }
2238 #endif
2239                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2240                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2241                 break;
2242         }
2243
2244         Mem_Free(dds);
2245         if(force_swdecode)
2246                 Mem_Free((unsigned char *) mippixels_start);
2247         return (rtexture_t *)glt;
2248 }
2249
2250 int R_TextureWidth(rtexture_t *rt)
2251 {
2252         return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2253 }
2254
2255 int R_TextureHeight(rtexture_t *rt)
2256 {
2257         return rt ? ((gltexture_t *)rt)->inputheight : 0;
2258 }
2259
2260 int R_TextureFlags(rtexture_t *rt)
2261 {
2262         return rt ? ((gltexture_t *)rt)->flags : 0;
2263 }
2264
2265 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2266 {
2267         gltexture_t *glt = (gltexture_t *)rt;
2268         if (data == NULL)
2269                 Host_Error("R_UpdateTexture: no data supplied");
2270         if (glt == NULL)
2271                 Host_Error("R_UpdateTexture: no texture supplied");
2272         if (!glt->texnum)
2273         {
2274                 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2275                 return;
2276         }
2277         // update part of the texture
2278         if (glt->bufferpixels)
2279         {
2280                 int j;
2281                 int bpp = glt->bytesperpixel;
2282                 int inputskip = width*bpp;
2283                 int outputskip = glt->tilewidth*bpp;
2284                 const unsigned char *input = data;
2285                 unsigned char *output = glt->bufferpixels;
2286                 if (glt->inputdepth != 1 || glt->sides != 1)
2287                         Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2288                 if (x < 0)
2289                 {
2290                         width += x;
2291                         input -= x*bpp;
2292                         x = 0;
2293                 }
2294                 if (y < 0)
2295                 {
2296                         height += y;
2297                         input -= y*inputskip;
2298                         y = 0;
2299                 }
2300                 if (width > glt->tilewidth - x)
2301                         width = glt->tilewidth - x;
2302                 if (height > glt->tileheight - y)
2303                         height = glt->tileheight - y;
2304                 if (width < 1 || height < 1)
2305                         return;
2306                 glt->dirty = true;
2307                 glt->buffermodified = true;
2308                 output += y*outputskip + x*bpp;
2309                 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2310                         memcpy(output, input, width*bpp);
2311         }
2312         else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2313                 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2314         else
2315                 R_UploadFullTexture(glt, data);
2316 }
2317
2318 int R_RealGetTexture(rtexture_t *rt)
2319 {
2320         if (rt)
2321         {
2322                 gltexture_t *glt;
2323                 glt = (gltexture_t *)rt;
2324                 if (glt->flags & GLTEXF_DYNAMIC)
2325                         R_UpdateDynamicTexture(glt);
2326                 if (glt->buffermodified && glt->bufferpixels)
2327                 {
2328                         glt->buffermodified = false;
2329                         R_UploadFullTexture(glt, glt->bufferpixels);
2330                 }
2331                 glt->dirty = false;
2332                 return glt->texnum;
2333         }
2334         else
2335                 return r_texture_white->texnum;
2336 }
2337
2338 void R_ClearTexture (rtexture_t *rt)
2339 {
2340         gltexture_t *glt = (gltexture_t *)rt;
2341
2342         R_UploadFullTexture(glt, NULL);
2343 }
2344
2345 int R_PicmipForFlags(int flags)
2346 {
2347         int miplevel = 0;
2348         if(flags & TEXF_PICMIP)
2349         {
2350                 miplevel += gl_picmip.integer;
2351                 if (flags & TEXF_ISWORLD)
2352                 {
2353                         if (r_picmipworld.integer)
2354                                 miplevel += gl_picmip_world.integer;
2355                         else
2356                                 miplevel = 0;
2357                 }
2358                 else if (flags & TEXF_ISSPRITE)
2359                 {
2360                         if (r_picmipsprites.integer)
2361                                 miplevel += gl_picmip_sprites.integer;
2362                         else
2363                                 miplevel = 0;
2364                 }
2365                 else
2366                         miplevel += gl_picmip_other.integer;
2367         }
2368         return max(0, miplevel);
2369 }