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