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