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