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