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