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