]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_textures.c
Rollback last change which was meant to be many smaller pieces.
[xonotic/darkplaces.git] / gl_textures.c
1
2 #include "quakedef.h"
3 #ifdef SUPPORTD3D
4 #include <d3d9.h>
5 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
6 #endif
7 #include "image.h"
8 #include "jpeg.h"
9 #include "image_png.h"
10 #include "intoverflow.h"
11 #include "dpsoftrast.h"
12
13 #ifndef GL_TEXTURE_3D
14 #define GL_TEXTURE_3D                           0x806F
15 #endif
16
17 cvar_t gl_max_size = {CVAR_SAVE, "gl_max_size", "2048", "maximum allowed texture size, can be used to reduce video memory usage, limited by hardware capabilities (typically 2048, 4096, or 8192)"};
18 cvar_t gl_max_lightmapsize = {CVAR_SAVE, "gl_max_lightmapsize", "1024", "maximum allowed texture size for lightmap textures, use larger values to improve rendering speed, as long as there is enough video memory available (setting it too high for the hardware will cause very bad performance)"};
19 cvar_t gl_picmip = {CVAR_SAVE, "gl_picmip", "0", "reduces resolution of textures by powers of 2, for example 1 will halve width/height, reducing texture memory usage by 75%"};
20 cvar_t gl_picmip_world = {CVAR_SAVE, "gl_picmip_world", "0", "extra picmip level for world textures (may be negative, which will then reduce gl_picmip for these)"};
21 cvar_t r_picmipworld = {CVAR_SAVE, "r_picmipworld", "1", "whether gl_picmip shall apply to world textures too (setting this to 0 is a shorthand for gl_picmip_world -9999999)"};
22 cvar_t gl_picmip_sprites = {CVAR_SAVE, "gl_picmip_sprites", "0", "extra picmip level for sprite textures (may be negative, which will then reduce gl_picmip for these)"};
23 cvar_t r_picmipsprites = {CVAR_SAVE, "r_picmipsprites", "1", "make gl_picmip affect sprites too (saves some graphics memory in sprite heavy games) (setting this to 0 is a shorthand for gl_picmip_sprites -9999999)"};
24 cvar_t gl_picmip_other = {CVAR_SAVE, "gl_picmip_other", "0", "extra picmip level for other textures (may be negative, which will then reduce gl_picmip for these)"};
25 cvar_t r_lerpimages = {CVAR_SAVE, "r_lerpimages", "1", "bilinear filters images when scaling them up to power of 2 size (mode 1), looks better than glquake (mode 0)"};
26 cvar_t gl_texture_anisotropy = {CVAR_SAVE, "gl_texture_anisotropy", "1", "anisotropic filtering quality (if supported by hardware), 1 sample (no anisotropy) and 8 sample (8 tap anisotropy) are recommended values"};
27 cvar_t gl_texturecompression = {CVAR_SAVE, "gl_texturecompression", "0", "whether to compress textures, a value of 0 disables compression (even if the individual cvars are 1), 1 enables fast (low quality) compression at startup, 2 enables slow (high quality) compression at startup"};
28 cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
29 cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
30 cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
31 cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
32 cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
33 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
34 cvar_t gl_texturecompression_q3bspdeluxemaps = {CVAR_SAVE, "gl_texturecompression_q3bspdeluxemaps", "0", "whether to compress deluxemaps in q3bsp format levels (only levels compiled with q3map2 -deluxe have these)"};
35 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
36 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
37 cvar_t gl_texturecompression_reflectmask = {CVAR_SAVE, "gl_texturecompression_reflectmask", "1", "whether to compress reflection cubemap masks (mask of which areas of the texture should reflect the generic shiny cubemap)"};
38 cvar_t gl_texturecompression_sprites = {CVAR_SAVE, "gl_texturecompression_sprites", "1", "whether to compress sprites"};
39 cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "0", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"};
40 cvar_t r_texture_dds_load_alphamode = {0, "r_texture_dds_load_alphamode", "1", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambiguous, 2: texture format only"};
41 cvar_t r_texture_dds_load_logfailure = {0, "r_texture_dds_load_logfailure", "0", "log missing DDS textures to ddstexturefailures.log, 0: done log, 1: log with no optional textures (_norm, glow etc.). 2: log all"};
42 cvar_t r_texture_dds_swdecode = {0, "r_texture_dds_swdecode", "0", "0: don't software decode DDS, 1: software decode DDS if unsupported, 2: always software decode DDS"};
43
44 qboolean        gl_filter_force = false;
45 int             gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
46 int             gl_filter_mag = GL_LINEAR;
47 DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_mipmap = DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE;
48 DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_nomipmap = DPSOFTRAST_TEXTURE_FILTER_LINEAR;
49
50 #ifdef SUPPORTD3D
51 int d3d_filter_flatmin = D3DTEXF_LINEAR;
52 int d3d_filter_flatmag = D3DTEXF_LINEAR;
53 int d3d_filter_flatmix = D3DTEXF_POINT;
54 int d3d_filter_mipmin = D3DTEXF_LINEAR;
55 int d3d_filter_mipmag = D3DTEXF_LINEAR;
56 int d3d_filter_mipmix = D3DTEXF_LINEAR;
57 int d3d_filter_nomip = false;
58 #endif
59
60
61 static mempool_t *texturemempool;
62 static memexpandablearray_t texturearray;
63
64 // note: this must not conflict with TEXF_ flags in r_textures.h
65 // bitmask for mismatch checking
66 #define GLTEXF_IMPORTANTBITS (0)
67 // dynamic texture (treat texnum == 0 differently)
68 #define GLTEXF_DYNAMIC          0x00080000
69
70 typedef struct textypeinfo_s
71 {
72         const char *name;
73         textype_t textype;
74         int inputbytesperpixel;
75         int internalbytesperpixel;
76         float glinternalbytesperpixel;
77         int glinternalformat;
78         int glformat;
79         int gltype;
80 }
81 textypeinfo_t;
82
83 #ifdef USE_GLES2
84
85 // we use these internally even if we never deliver such data to the driver
86 #define GL_BGR                                  0x80E0
87 #define GL_BGRA                                 0x80E1
88
89 // framebuffer texture formats
90 // GLES2 devices rarely support depth textures, so we actually use a renderbuffer there
91 static textypeinfo_t textype_shadowmap16_comp            = {"shadowmap16_comp",         TEXTYPE_SHADOWMAP16_COMP     ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
92 static textypeinfo_t textype_shadowmap16_raw             = {"shadowmap16_raw",          TEXTYPE_SHADOWMAP16_RAW      ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
93 static textypeinfo_t textype_shadowmap24_comp            = {"shadowmap24_comp",         TEXTYPE_SHADOWMAP24_COMP     ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
94 static textypeinfo_t textype_shadowmap24_raw             = {"shadowmap24_raw",          TEXTYPE_SHADOWMAP24_RAW      ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
95 static textypeinfo_t textype_depth16                     = {"depth16",                  TEXTYPE_DEPTHBUFFER16        ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
96 static textypeinfo_t textype_depth24                     = {"depth24",                  TEXTYPE_DEPTHBUFFER24        ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
97 static textypeinfo_t textype_depth24stencil8             = {"depth24stencil8",          TEXTYPE_DEPTHBUFFER24STENCIL8,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
98 static textypeinfo_t textype_colorbuffer                 = {"colorbuffer",              TEXTYPE_COLORBUFFER          ,  2,  2,  2.0f, GL_RGB565                         , GL_RGBA           , GL_UNSIGNED_SHORT_5_6_5};
99 static textypeinfo_t textype_colorbuffer16f              = {"colorbuffer16f",           TEXTYPE_COLORBUFFER16F       ,  2,  2,  2.0f, GL_RGBA16F                        , GL_RGBA           , GL_HALF_FLOAT_ARB};
100 static textypeinfo_t textype_colorbuffer32f              = {"colorbuffer32f",           TEXTYPE_COLORBUFFER32F       ,  2,  2,  2.0f, GL_RGBA32F                        , GL_RGBA           , GL_FLOAT};
101
102 // image formats:
103 static textypeinfo_t textype_alpha                       = {"alpha",                    TEXTYPE_ALPHA         ,  1,  4,  4.0f, GL_ALPHA                              , GL_ALPHA          , GL_UNSIGNED_BYTE };
104 static textypeinfo_t textype_palette                     = {"palette",                  TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
105 static textypeinfo_t textype_palette_alpha               = {"palette_alpha",            TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
106 static textypeinfo_t textype_rgba                        = {"rgba",                     TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_RGBA                               , GL_RGBA           , GL_UNSIGNED_BYTE };
107 static textypeinfo_t textype_rgba_alpha                  = {"rgba_alpha",               TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_RGBA                               , GL_RGBA           , GL_UNSIGNED_BYTE };
108 static textypeinfo_t textype_bgra                        = {"bgra",                     TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
109 static textypeinfo_t textype_bgra_alpha                  = {"bgra_alpha",               TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
110 #ifdef __ANDROID__
111 static textypeinfo_t textype_etc1                        = {"etc1",                     TEXTYPE_ETC1          ,  1,  3,  0.5f, GL_ETC1_RGB8_OES                         , 0                 , 0                };
112 #endif
113 #else
114 // framebuffer texture formats
115 static textypeinfo_t textype_shadowmap16_comp            = {"shadowmap16_comp",         TEXTYPE_SHADOWMAP16_COMP     ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16_ARB          , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
116 static textypeinfo_t textype_shadowmap16_raw             = {"shadowmap16_raw",          TEXTYPE_SHADOWMAP16_RAW      ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16_ARB          , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
117 static textypeinfo_t textype_shadowmap24_comp            = {"shadowmap24_comp",         TEXTYPE_SHADOWMAP24_COMP     ,  4,  4,  4.0f, GL_DEPTH_COMPONENT24_ARB          , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
118 static textypeinfo_t textype_shadowmap24_raw             = {"shadowmap24_raw",          TEXTYPE_SHADOWMAP24_RAW      ,  4,  4,  4.0f, GL_DEPTH_COMPONENT24_ARB          , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
119 static textypeinfo_t textype_depth16                     = {"depth16",                  TEXTYPE_DEPTHBUFFER16        ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16_ARB          , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
120 static textypeinfo_t textype_depth24                     = {"depth24",                  TEXTYPE_DEPTHBUFFER24        ,  4,  4,  4.0f, GL_DEPTH_COMPONENT24_ARB          , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
121 static textypeinfo_t textype_depth24stencil8             = {"depth24stencil8",          TEXTYPE_DEPTHBUFFER24STENCIL8,  4,  4,  4.0f, GL_DEPTH24_STENCIL8_EXT           , GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT};
122 static textypeinfo_t textype_colorbuffer                 = {"colorbuffer",              TEXTYPE_COLORBUFFER          ,  4,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
123 static textypeinfo_t textype_colorbuffer16f              = {"colorbuffer16f",           TEXTYPE_COLORBUFFER16F       ,  8,  8,  8.0f, GL_RGBA16F_ARB                        , GL_RGBA           , GL_HALF_FLOAT_ARB};
124 static textypeinfo_t textype_colorbuffer32f              = {"colorbuffer32f",           TEXTYPE_COLORBUFFER32F       , 16, 16, 16.0f, GL_RGBA32F_ARB                        , GL_RGBA           , GL_FLOAT         };
125
126 // image formats:
127 static textypeinfo_t textype_alpha                       = {"alpha",                    TEXTYPE_ALPHA         ,  1,  4,  4.0f, GL_ALPHA                              , GL_ALPHA          , GL_UNSIGNED_BYTE };
128 static textypeinfo_t textype_palette                     = {"palette",                  TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_RGB                                , GL_BGRA           , GL_UNSIGNED_BYTE };
129 static textypeinfo_t textype_palette_alpha               = {"palette_alpha",            TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
130 static textypeinfo_t textype_rgba                        = {"rgba",                     TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_RGB                                , GL_RGBA           , GL_UNSIGNED_BYTE };
131 static textypeinfo_t textype_rgba_alpha                  = {"rgba_alpha",               TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_RGBA                               , GL_RGBA           , GL_UNSIGNED_BYTE };
132 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 };
133 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 };
134 static textypeinfo_t textype_bgra                        = {"bgra",                     TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_RGB                                , GL_BGRA           , GL_UNSIGNED_BYTE };
135 static textypeinfo_t textype_bgra_alpha                  = {"bgra_alpha",               TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
136 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 };
137 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 };
138 static textypeinfo_t textype_dxt1                        = {"dxt1",                     TEXTYPE_DXT1          ,  4,  0,  0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT       , 0                 , 0                };
139 static textypeinfo_t textype_dxt1a                       = {"dxt1a",                    TEXTYPE_DXT1A         ,  4,  0,  0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT      , 0                 , 0                };
140 static textypeinfo_t textype_dxt3                        = {"dxt3",                     TEXTYPE_DXT3          ,  4,  0,  1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT      , 0                 , 0                };
141 static textypeinfo_t textype_dxt5                        = {"dxt5",                     TEXTYPE_DXT5          ,  4,  0,  1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT      , 0                 , 0                };
142 static textypeinfo_t textype_sRGB_palette                = {"sRGB_palette",             TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_SRGB_EXT                           , GL_BGRA           , GL_UNSIGNED_BYTE };
143 static textypeinfo_t textype_sRGB_palette_alpha          = {"sRGB_palette_alpha",       TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_SRGB_ALPHA_EXT                     , GL_BGRA           , GL_UNSIGNED_BYTE };
144 static textypeinfo_t textype_sRGB_rgba                   = {"sRGB_rgba",                TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_SRGB_EXT                           , GL_RGBA           , GL_UNSIGNED_BYTE };
145 static textypeinfo_t textype_sRGB_rgba_alpha             = {"sRGB_rgba_alpha",          TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_SRGB_ALPHA_EXT                     , GL_RGBA           , GL_UNSIGNED_BYTE };
146 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 };
147 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 };
148 static textypeinfo_t textype_sRGB_bgra                   = {"sRGB_bgra",                TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_SRGB_EXT                           , GL_BGRA           , GL_UNSIGNED_BYTE };
149 static textypeinfo_t textype_sRGB_bgra_alpha             = {"sRGB_bgra_alpha",          TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_SRGB_ALPHA_EXT                     , GL_BGRA           , GL_UNSIGNED_BYTE };
150 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 };
151 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 };
152 static textypeinfo_t textype_sRGB_dxt1                   = {"sRGB_dxt1",                TEXTYPE_DXT1          ,  4,  0,  0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT      , 0                 , 0                };
153 static textypeinfo_t textype_sRGB_dxt1a                  = {"sRGB_dxt1a",               TEXTYPE_DXT1A         ,  4,  0,  0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0                 , 0                };
154 static textypeinfo_t textype_sRGB_dxt3                   = {"sRGB_dxt3",                TEXTYPE_DXT3          ,  4,  0,  1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0                 , 0                };
155 static textypeinfo_t textype_sRGB_dxt5                   = {"sRGB_dxt5",                TEXTYPE_DXT5          ,  4,  0,  1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0                 , 0                };
156 #endif
157
158 typedef enum gltexturetype_e
159 {
160         GLTEXTURETYPE_2D,
161         GLTEXTURETYPE_3D,
162         GLTEXTURETYPE_CUBEMAP,
163         GLTEXTURETYPE_TOTAL
164 }
165 gltexturetype_t;
166
167 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP};
168 #ifdef GL_TEXTURE_WRAP_R
169 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
170 #endif
171 static int cubemapside[6] =
172 {
173         GL_TEXTURE_CUBE_MAP_POSITIVE_X,
174         GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
175         GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
176         GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
177         GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
178         GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
179 };
180
181 typedef struct gltexture_s
182 {
183         // this portion of the struct is exposed to the R_GetTexture macro for
184         // speed reasons, must be identical in rtexture_t!
185         int texnum; // GL texture slot number
186         int renderbuffernum; // GL renderbuffer slot number
187         qboolean dirty; // indicates that R_RealGetTexture should be called
188         qboolean glisdepthstencil; // indicates that FBO attachment has to be GL_DEPTH_STENCIL_ATTACHMENT
189         int gltexturetypeenum; // used by R_Mesh_TexBind
190         // d3d stuff the backend needs
191         void *d3dtexture;
192         void *d3dsurface;
193 #ifdef SUPPORTD3D
194         qboolean d3disrendertargetsurface;
195         qboolean d3disdepthstencilsurface;
196         int d3dformat;
197         int d3dusage;
198         int d3dpool;
199         int d3daddressu;
200         int d3daddressv;
201         int d3daddressw;
202         int d3dmagfilter;
203         int d3dminfilter;
204         int d3dmipfilter;
205         int d3dmaxmiplevelfilter;
206         int d3dmipmaplodbias;
207         int d3dmaxmiplevel;
208 #endif
209
210         // dynamic texture stuff [11/22/2007 Black]
211         updatecallback_t updatecallback;
212         void *updatecallback_data;
213         // --- [11/22/2007 Black]
214
215         // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
216         unsigned char *bufferpixels;
217         qboolean buffermodified;
218
219         // pointer to texturepool (check this to see if the texture is allocated)
220         struct gltexturepool_s *pool;
221         // pointer to next texture in texturepool chain
222         struct gltexture_s *chain;
223         // name of the texture (this might be removed someday), no duplicates
224         char identifier[MAX_QPATH + 32];
225         // original data size in *inputtexels
226         int inputwidth, inputheight, inputdepth;
227         // copy of the original texture(s) supplied to the upload function, for
228         // delayed uploads (non-precached)
229         unsigned char *inputtexels;
230         // original data size in *inputtexels
231         int inputdatasize;
232         // flags supplied to the LoadTexture function
233         // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
234         int flags;
235         // picmip level
236         int miplevel;
237         // pointer to one of the textype_ structs
238         textypeinfo_t *textype;
239         // one of the GLTEXTURETYPE_ values
240         int texturetype;
241         // palette if the texture is TEXTYPE_PALETTE
242         const unsigned int *palette;
243         // actual stored texture size after gl_picmip and gl_max_size are applied
244         // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
245         int tilewidth, tileheight, tiledepth;
246         // 1 or 6 depending on texturetype
247         int sides;
248         // how many mipmap levels in this texture
249         int miplevels;
250         // bytes per pixel
251         int bytesperpixel;
252         // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
253         int glformat;
254         // 3 or 4
255         int glinternalformat;
256         // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
257         int gltype;
258 }
259 gltexture_t;
260
261 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
262
263 typedef struct gltexturepool_s
264 {
265         unsigned int sentinel;
266         struct gltexture_s *gltchain;
267         struct gltexturepool_s *next;
268 }
269 gltexturepool_t;
270
271 static gltexturepool_t *gltexturepoolchain = NULL;
272
273 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
274 static int resizebuffersize = 0;
275 static const unsigned char *texturebuffer;
276
277 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
278 {
279         switch(textype)
280         {
281 #ifdef USE_GLES2
282         case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
283         case TEXTYPE_RGBA: return ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba);
284         case TEXTYPE_BGRA: return ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra);
285 #ifdef __ANDROID__
286         case TEXTYPE_ETC1: return &textype_etc1;
287 #endif
288         case TEXTYPE_ALPHA: return &textype_alpha;
289         case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
290         case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
291         case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
292         case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
293         case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
294         case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
295         case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
296         case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
297         case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
298         case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
299 #else
300         case TEXTYPE_DXT1: return &textype_dxt1;
301         case TEXTYPE_DXT1A: return &textype_dxt1a;
302         case TEXTYPE_DXT3: return &textype_dxt3;
303         case TEXTYPE_DXT5: return &textype_dxt5;
304         case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
305         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);
306         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);
307         case TEXTYPE_ALPHA: return &textype_alpha;
308         case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
309         case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
310         case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
311         case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
312         case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
313         case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
314         case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
315         case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
316         case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
317         case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
318         case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1;
319         case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a;
320         case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
321         case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
322         case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
323         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);
324         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);
325 #endif
326         default:
327                 Host_Error("R_GetTexTypeInfo: unknown texture format");
328                 break;
329         }
330         return NULL;
331 }
332
333 // dynamic texture code [11/22/2007 Black]
334 void R_MarkDirtyTexture(rtexture_t *rt) {
335         gltexture_t *glt = (gltexture_t*) rt;
336         if( !glt ) {
337                 return;
338         }
339
340         // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
341         if (glt->flags & GLTEXF_DYNAMIC)
342         {
343                 // mark it as dirty, so R_RealGetTexture gets called
344                 glt->dirty = true;
345         }
346 }
347
348 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
349         gltexture_t *glt = (gltexture_t*) rt;
350         if( !glt ) {
351                 return;
352         }
353
354         glt->flags |= GLTEXF_DYNAMIC;
355         glt->updatecallback = updatecallback;
356         glt->updatecallback_data = data;
357 }
358
359 static void R_UpdateDynamicTexture(gltexture_t *glt) {
360         glt->dirty = false;
361         if( glt->updatecallback ) {
362                 glt->updatecallback( (rtexture_t*) glt, glt->updatecallback_data );
363         }
364 }
365
366 void R_PurgeTexture(rtexture_t *rt)
367 {
368         if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
369                 R_FreeTexture(rt);
370         }
371 }
372
373 void R_FreeTexture(rtexture_t *rt)
374 {
375         gltexture_t *glt, **gltpointer;
376
377         glt = (gltexture_t *)rt;
378         if (glt == NULL)
379                 Host_Error("R_FreeTexture: texture == NULL");
380
381         for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
382         if (*gltpointer == glt)
383                 *gltpointer = glt->chain;
384         else
385                 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
386
387         R_Mesh_ClearBindingsForTexture(glt->texnum);
388
389         switch(vid.renderpath)
390         {
391         case RENDERPATH_GL11:
392         case RENDERPATH_GL13:
393         case RENDERPATH_GL20:
394         case RENDERPATH_GLES1:
395         case RENDERPATH_GLES2:
396                 if (glt->texnum)
397                 {
398                         CHECKGLERROR
399                         qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
400                 }
401                 if (glt->renderbuffernum)
402                 {
403                         CHECKGLERROR
404                         qglDeleteRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
405                 }
406                 break;
407         case RENDERPATH_D3D9:
408 #ifdef SUPPORTD3D
409                 if (glt->d3dsurface)
410                         IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dsurface);
411                 else if (glt->tiledepth > 1)
412                         IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
413                 else if (glt->sides == 6)
414                         IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
415                 else
416                         IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
417                 glt->d3dtexture = NULL;
418                 glt->d3dsurface = NULL;
419 #endif
420                 break;
421         case RENDERPATH_D3D10:
422                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
423                 break;
424         case RENDERPATH_D3D11:
425                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
426                 break;
427         case RENDERPATH_SOFT:
428                 if (glt->texnum)
429                         DPSOFTRAST_Texture_Free(glt->texnum);
430                 break;
431         }
432
433         if (glt->inputtexels)
434                 Mem_Free(glt->inputtexels);
435         Mem_ExpandableArray_FreeRecord(&texturearray, glt);
436 }
437
438 rtexturepool_t *R_AllocTexturePool(void)
439 {
440         gltexturepool_t *pool;
441         if (texturemempool == NULL)
442                 return NULL;
443         pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
444         if (pool == NULL)
445                 return NULL;
446         pool->next = gltexturepoolchain;
447         gltexturepoolchain = pool;
448         pool->sentinel = TEXTUREPOOL_SENTINEL;
449         return (rtexturepool_t *)pool;
450 }
451
452 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
453 {
454         gltexturepool_t *pool, **poolpointer;
455         if (rtexturepool == NULL)
456                 return;
457         if (*rtexturepool == NULL)
458                 return;
459         pool = (gltexturepool_t *)(*rtexturepool);
460         *rtexturepool = NULL;
461         if (pool->sentinel != TEXTUREPOOL_SENTINEL)
462                 Host_Error("R_FreeTexturePool: pool already freed");
463         for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
464         if (*poolpointer == pool)
465                 *poolpointer = pool->next;
466         else
467                 Host_Error("R_FreeTexturePool: pool not linked");
468         while (pool->gltchain)
469                 R_FreeTexture((rtexture_t *)pool->gltchain);
470         Mem_Free(pool);
471 }
472
473
474 typedef struct glmode_s
475 {
476         const char *name;
477         int minification, magnification;
478         DPSOFTRAST_TEXTURE_FILTER dpsoftrastfilter_mipmap, dpsoftrastfilter_nomipmap;
479 }
480 glmode_t;
481
482 static glmode_t modes[6] =
483 {
484         {"GL_NEAREST", GL_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
485         {"GL_LINEAR", GL_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
486         {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
487         {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
488         {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
489         {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR}
490 };
491
492 #ifdef SUPPORTD3D
493 typedef struct d3dmode_s
494 {
495         const char *name;
496         int m1, m2;
497 }
498 d3dmode_t;
499
500 static d3dmode_t d3dmodes[6] =
501 {
502         {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
503         {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
504         {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
505         {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
506         {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
507         {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
508 };
509 #endif
510
511 static void GL_TextureMode_f (void)
512 {
513         int i;
514         GLint oldbindtexnum;
515         gltexture_t *glt;
516         gltexturepool_t *pool;
517
518         if (Cmd_Argc() == 1)
519         {
520                 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
521                 for (i = 0;i < 6;i++)
522                 {
523                         if (gl_filter_min == modes[i].minification)
524                         {
525                                 Con_Printf("%s\n", modes[i].name);
526                                 return;
527                         }
528                 }
529                 Con_Print("current filter is unknown???\n");
530                 return;
531         }
532
533         for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
534                 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
535                         break;
536         if (i == 6)
537         {
538                 Con_Print("bad filter name\n");
539                 return;
540         }
541
542         gl_filter_min = modes[i].minification;
543         gl_filter_mag = modes[i].magnification;
544         gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
545
546         dpsoftrast_filter_mipmap = modes[i].dpsoftrastfilter_mipmap;
547         dpsoftrast_filter_nomipmap = modes[i].dpsoftrastfilter_nomipmap;
548
549         switch(vid.renderpath)
550         {
551         case RENDERPATH_GL11:
552         case RENDERPATH_GL13:
553         case RENDERPATH_GL20:
554         case RENDERPATH_GLES1:
555         case RENDERPATH_GLES2:
556                 // change all the existing mipmap texture objects
557                 // FIXME: force renderer(/client/something?) restart instead?
558                 CHECKGLERROR
559                 GL_ActiveTexture(0);
560                 for (pool = gltexturepoolchain;pool;pool = pool->next)
561                 {
562                         for (glt = pool->gltchain;glt;glt = glt->chain)
563                         {
564                                 // only update already uploaded images
565                                 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
566                                 {
567                                         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
568                                         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
569                                         if (glt->flags & TEXF_MIPMAP)
570                                         {
571                                                 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
572                                         }
573                                         else
574                                         {
575                                                 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
576                                         }
577                                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
578                                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
579                                 }
580                         }
581                 }
582                 break;
583         case RENDERPATH_D3D9:
584 #ifdef SUPPORTD3D
585                 d3d_filter_flatmin = d3dmodes[i].m1;
586                 d3d_filter_flatmag = d3dmodes[i].m1;
587                 d3d_filter_flatmix = D3DTEXF_POINT;
588                 d3d_filter_mipmin = d3dmodes[i].m1;
589                 d3d_filter_mipmag = d3dmodes[i].m1;
590                 d3d_filter_mipmix = d3dmodes[i].m2;
591                 d3d_filter_nomip = i < 2;
592                 if (gl_texture_anisotropy.integer > 1 && i == 5)
593                         d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
594                 for (pool = gltexturepoolchain;pool;pool = pool->next)
595                 {
596                         for (glt = pool->gltchain;glt;glt = glt->chain)
597                         {
598                                 // only update already uploaded images
599                                 if (glt->d3dtexture && !glt->d3dsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
600                                 {
601                                         if (glt->flags & TEXF_MIPMAP)
602                                         {
603                                                 glt->d3dminfilter = d3d_filter_mipmin;
604                                                 glt->d3dmagfilter = d3d_filter_mipmag;
605                                                 glt->d3dmipfilter = d3d_filter_mipmix;
606                                                 glt->d3dmaxmiplevelfilter = 0;
607                                         }
608                                         else
609                                         {
610                                                 glt->d3dminfilter = d3d_filter_flatmin;
611                                                 glt->d3dmagfilter = d3d_filter_flatmag;
612                                                 glt->d3dmipfilter = d3d_filter_flatmix;
613                                                 glt->d3dmaxmiplevelfilter = 0;
614                                         }
615                                 }
616                         }
617                 }
618 #endif
619                 break;
620         case RENDERPATH_D3D10:
621                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
622                 break;
623         case RENDERPATH_D3D11:
624                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
625                 break;
626         case RENDERPATH_SOFT:
627                 // change all the existing texture objects
628                 for (pool = gltexturepoolchain;pool;pool = pool->next)
629                         for (glt = pool->gltchain;glt;glt = glt->chain)
630                                 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
631                                         DPSOFTRAST_Texture_Filter(glt->texnum, (glt->flags & TEXF_MIPMAP) ? dpsoftrast_filter_mipmap : dpsoftrast_filter_nomipmap);
632                 break;
633         }
634 }
635
636 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)
637 {
638         int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
639
640         switch (texturetype)
641         {
642         default:
643         case GLTEXTURETYPE_2D:
644                 maxsize = vid.maxtexturesize_2d;
645                 if (flags & TEXF_PICMIP)
646                 {
647                         maxsize = bound(1, gl_max_size.integer, maxsize);
648                         picmip = miplevel;
649                 }
650                 break;
651         case GLTEXTURETYPE_3D:
652                 maxsize = vid.maxtexturesize_3d;
653                 break;
654         case GLTEXTURETYPE_CUBEMAP:
655                 maxsize = vid.maxtexturesize_cubemap;
656                 break;
657         }
658
659         if (vid.support.arb_texture_non_power_of_two)
660         {
661                 width2 = min(inwidth >> picmip, maxsize);
662                 height2 = min(inheight >> picmip, maxsize);
663                 depth2 = min(indepth >> picmip, maxsize);
664         }
665         else
666         {
667                 for (width2 = 1;width2 < inwidth;width2 <<= 1);
668                 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
669                 for (height2 = 1;height2 < inheight;height2 <<= 1);
670                 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
671                 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
672                 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
673         }
674
675         switch(vid.renderpath)
676         {
677         case RENDERPATH_GL11:
678         case RENDERPATH_GL13:
679         case RENDERPATH_GL20:
680         case RENDERPATH_D3D10:
681         case RENDERPATH_D3D11:
682         case RENDERPATH_SOFT:
683         case RENDERPATH_GLES1:
684         case RENDERPATH_GLES2:
685                 break;
686         case RENDERPATH_D3D9:
687 #if 0
688                 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
689                 if (texturetype == GLTEXTURETYPE_2D)
690                 {
691                         width2 = max(width2, 2);
692                         height2 = max(height2, 2);
693                 }
694 #endif
695                 break;
696         }
697
698         miplevels = 1;
699         if (flags & TEXF_MIPMAP)
700         {
701                 int extent = max(width2, max(height2, depth2));
702                 while(extent >>= 1)
703                         miplevels++;
704         }
705
706         if (outwidth)
707                 *outwidth = max(1, width2);
708         if (outheight)
709                 *outheight = max(1, height2);
710         if (outdepth)
711                 *outdepth = max(1, depth2);
712         if (outmiplevels)
713                 *outmiplevels = miplevels;
714 }
715
716
717 static int R_CalcTexelDataSize (gltexture_t *glt)
718 {
719         int width2, height2, depth2, size;
720
721         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
722
723         size = width2 * height2 * depth2;
724
725         if (glt->flags & TEXF_MIPMAP)
726         {
727                 while (width2 > 1 || height2 > 1 || depth2 > 1)
728                 {
729                         if (width2 > 1)
730                                 width2 >>= 1;
731                         if (height2 > 1)
732                                 height2 >>= 1;
733                         if (depth2 > 1)
734                                 depth2 >>= 1;
735                         size += width2 * height2 * depth2;
736                 }
737         }
738
739         return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
740 }
741
742 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
743 {
744         int glsize;
745         int isloaded;
746         int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
747         int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
748         gltexture_t *glt;
749         gltexturepool_t *pool;
750         if (printeach)
751                 Con_Print("glsize input loaded mip alpha name\n");
752         for (pool = gltexturepoolchain;pool;pool = pool->next)
753         {
754                 pooltotal = 0;
755                 pooltotalt = 0;
756                 pooltotalp = 0;
757                 poolloaded = 0;
758                 poolloadedt = 0;
759                 poolloadedp = 0;
760                 for (glt = pool->gltchain;glt;glt = glt->chain)
761                 {
762                         glsize = R_CalcTexelDataSize(glt);
763                         isloaded = glt->texnum != 0 || glt->renderbuffernum != 0 || glt->d3dtexture || glt->d3dsurface;
764                         pooltotal++;
765                         pooltotalt += glsize;
766                         pooltotalp += glt->inputdatasize;
767                         if (isloaded)
768                         {
769                                 poolloaded++;
770                                 poolloadedt += glsize;
771                                 poolloadedp += glt->inputdatasize;
772                         }
773                         if (printeach)
774                                 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);
775                 }
776                 if (printpool)
777                         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);
778                 sumtotal += pooltotal;
779                 sumtotalt += pooltotalt;
780                 sumtotalp += pooltotalp;
781                 sumloaded += poolloaded;
782                 sumloadedt += poolloadedt;
783                 sumloadedp += poolloadedp;
784         }
785         if (printtotal)
786                 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);
787 }
788
789 static void R_TextureStats_f(void)
790 {
791         R_TextureStats_Print(true, true, true);
792 }
793
794 static void r_textures_start(void)
795 {
796         switch(vid.renderpath)
797         {
798         case RENDERPATH_GL11:
799         case RENDERPATH_GL13:
800         case RENDERPATH_GL20:
801         case RENDERPATH_GLES1:
802         case RENDERPATH_GLES2:
803                 // LordHavoc: allow any alignment
804                 CHECKGLERROR
805                 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
806                 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
807                 break;
808         case RENDERPATH_D3D9:
809                 break;
810         case RENDERPATH_D3D10:
811                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
812                 break;
813         case RENDERPATH_D3D11:
814                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
815                 break;
816         case RENDERPATH_SOFT:
817                 break;
818         }
819
820         texturemempool = Mem_AllocPool("texture management", 0, NULL);
821         Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
822
823         // Disable JPEG screenshots if the DLL isn't loaded
824         if (! JPEG_OpenLibrary ())
825                 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
826         if (! PNG_OpenLibrary ())
827                 Cvar_SetValueQuick (&scr_screenshot_png, 0);
828 }
829
830 static void r_textures_shutdown(void)
831 {
832         rtexturepool_t *temp;
833
834         JPEG_CloseLibrary ();
835
836         while(gltexturepoolchain)
837         {
838                 temp = (rtexturepool_t *) gltexturepoolchain;
839                 R_FreeTexturePool(&temp);
840         }
841
842         resizebuffersize = 0;
843         resizebuffer = NULL;
844         colorconvertbuffer = NULL;
845         texturebuffer = NULL;
846         Mem_ExpandableArray_FreeArray(&texturearray);
847         Mem_FreePool(&texturemempool);
848 }
849
850 static void r_textures_newmap(void)
851 {
852 }
853
854 static void r_textures_devicelost(void)
855 {
856         int i, endindex;
857         gltexture_t *glt;
858         endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
859         for (i = 0;i < endindex;i++)
860         {
861                 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
862                 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
863                         continue;
864                 switch(vid.renderpath)
865                 {
866                 case RENDERPATH_GL11:
867                 case RENDERPATH_GL13:
868                 case RENDERPATH_GL20:
869                 case RENDERPATH_GLES1:
870                 case RENDERPATH_GLES2:
871                         break;
872                 case RENDERPATH_D3D9:
873 #ifdef SUPPORTD3D
874                         if (glt->d3dsurface)
875                                 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dsurface);
876                         else if (glt->tiledepth > 1)
877                                 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
878                         else if (glt->sides == 6)
879                                 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
880                         else
881                                 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
882                         glt->d3dtexture = NULL;
883                         glt->d3dsurface = NULL;
884 #endif
885                         break;
886                 case RENDERPATH_D3D10:
887                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
888                         break;
889                 case RENDERPATH_D3D11:
890                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
891                         break;
892                 case RENDERPATH_SOFT:
893                         break;
894                 }
895         }
896 }
897
898 static void r_textures_devicerestored(void)
899 {
900         int i, endindex;
901         gltexture_t *glt;
902         endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
903         for (i = 0;i < endindex;i++)
904         {
905                 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
906                 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
907                         continue;
908                 switch(vid.renderpath)
909                 {
910                 case RENDERPATH_GL11:
911                 case RENDERPATH_GL13:
912                 case RENDERPATH_GL20:
913                 case RENDERPATH_GLES1:
914                 case RENDERPATH_GLES2:
915                         break;
916                 case RENDERPATH_D3D9:
917 #ifdef SUPPORTD3D
918                         {
919                                 HRESULT d3dresult;
920                                 if (glt->d3disrendertargetsurface)
921                                 {
922                                         if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
923                                                 Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!");
924                                 }
925                                 else if (glt->d3disdepthstencilsurface)
926                                 {
927                                         if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
928                                                 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
929                                 }
930                                 else if (glt->tiledepth > 1)
931                                 {
932                                         if (FAILED(d3dresult = IDirect3DDevice9_CreateVolumeTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->tiledepth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DVolumeTexture9 **)&glt->d3dtexture, NULL)))
933                                                 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
934                                 }
935                                 else if (glt->sides == 6)
936                                 {
937                                         if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
938                                                 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
939                                 }
940                                 else
941                                 {
942                                         if (FAILED(d3dresult = IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL)))
943                                                 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
944                                 }
945                         }
946 #endif
947                         break;
948                 case RENDERPATH_D3D10:
949                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
950                         break;
951                 case RENDERPATH_D3D11:
952                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
953                         break;
954                 case RENDERPATH_SOFT:
955                         break;
956                 }
957         }
958 }
959
960
961 void R_Textures_Init (void)
962 {
963         Cmd_AddCommand("gl_texturemode", &GL_TextureMode_f, "set texture filtering mode (GL_NEAREST, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, etc); an additional argument 'force' forces the texture mode even in cases where it may not be appropriate");
964         Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
965         Cvar_RegisterVariable (&gl_max_size);
966         Cvar_RegisterVariable (&gl_picmip);
967         Cvar_RegisterVariable (&gl_picmip_world);
968         Cvar_RegisterVariable (&r_picmipworld);
969         Cvar_RegisterVariable (&gl_picmip_sprites);
970         Cvar_RegisterVariable (&r_picmipsprites);
971         Cvar_RegisterVariable (&gl_picmip_other);
972         Cvar_RegisterVariable (&gl_max_lightmapsize);
973         Cvar_RegisterVariable (&r_lerpimages);
974         Cvar_RegisterVariable (&gl_texture_anisotropy);
975         Cvar_RegisterVariable (&gl_texturecompression);
976         Cvar_RegisterVariable (&gl_texturecompression_color);
977         Cvar_RegisterVariable (&gl_texturecompression_normal);
978         Cvar_RegisterVariable (&gl_texturecompression_gloss);
979         Cvar_RegisterVariable (&gl_texturecompression_glow);
980         Cvar_RegisterVariable (&gl_texturecompression_2d);
981         Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
982         Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
983         Cvar_RegisterVariable (&gl_texturecompression_sky);
984         Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
985         Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
986         Cvar_RegisterVariable (&gl_texturecompression_sprites);
987         Cvar_RegisterVariable (&gl_nopartialtextureupdates);
988         Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
989         Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
990         Cvar_RegisterVariable (&r_texture_dds_swdecode);
991
992         R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
993 }
994
995 void R_Textures_Frame (void)
996 {
997 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
998         static int old_aniso = 0;
999 #endif
1000
1001         // could do procedural texture animation here, if we keep track of which
1002         // textures were accessed this frame...
1003
1004         // free the resize buffers
1005         resizebuffersize = 0;
1006         if (resizebuffer)
1007         {
1008                 Mem_Free(resizebuffer);
1009                 resizebuffer = NULL;
1010         }
1011         if (colorconvertbuffer)
1012         {
1013                 Mem_Free(colorconvertbuffer);
1014                 colorconvertbuffer = NULL;
1015         }
1016
1017 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
1018         if (old_aniso != gl_texture_anisotropy.integer)
1019         {
1020                 gltexture_t *glt;
1021                 gltexturepool_t *pool;
1022                 GLint oldbindtexnum;
1023
1024                 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
1025
1026                 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
1027
1028                 switch(vid.renderpath)
1029                 {
1030                 case RENDERPATH_GL11:
1031                 case RENDERPATH_GL13:
1032                 case RENDERPATH_GL20:
1033                 case RENDERPATH_GLES1:
1034                 case RENDERPATH_GLES2:
1035                         CHECKGLERROR
1036                         GL_ActiveTexture(0);
1037                         for (pool = gltexturepoolchain;pool;pool = pool->next)
1038                         {
1039                                 for (glt = pool->gltchain;glt;glt = glt->chain)
1040                                 {
1041                                         // only update already uploaded images
1042                                         if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
1043                                         {
1044                                                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1045
1046                                                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1047                                                 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
1048
1049                                                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1050                                         }
1051                                 }
1052                         }
1053                         break;
1054                 case RENDERPATH_D3D9:
1055                 case RENDERPATH_D3D10:
1056                 case RENDERPATH_D3D11:
1057                 case RENDERPATH_SOFT:
1058                         break;
1059                 }
1060         }
1061 #endif
1062 }
1063
1064 static void R_MakeResizeBufferBigger(int size)
1065 {
1066         if (resizebuffersize < size)
1067         {
1068                 resizebuffersize = size;
1069                 if (resizebuffer)
1070                         Mem_Free(resizebuffer);
1071                 if (colorconvertbuffer)
1072                         Mem_Free(colorconvertbuffer);
1073                 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
1074                 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
1075                 if (!resizebuffer || !colorconvertbuffer)
1076                         Host_Error("R_Upload: out of memory");
1077         }
1078 }
1079
1080 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
1081 {
1082         int textureenum = gltexturetypeenums[texturetype];
1083         int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
1084
1085         CHECKGLERROR
1086
1087 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
1088         if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
1089         {
1090                 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
1091                 if (gl_texture_anisotropy.integer != aniso)
1092                         Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
1093                 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
1094         }
1095 #endif
1096         qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
1097         qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
1098 #ifdef GL_TEXTURE_WRAP_R
1099         if (gltexturetypedimensions[texturetype] >= 3)
1100         {
1101                 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
1102         }
1103 #endif
1104
1105         CHECKGLERROR
1106         if (!gl_filter_force && flags & TEXF_FORCENEAREST)
1107         {
1108                 if (flags & TEXF_MIPMAP)
1109                 {
1110                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
1111                 }
1112                 else
1113                 {
1114                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
1115                 }
1116                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
1117         }
1118         else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
1119         {
1120                 if (flags & TEXF_MIPMAP)
1121                 {
1122                         if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
1123                         {
1124                                 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
1125                         }
1126                         else
1127                         {
1128                                 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
1129                         }
1130                 }
1131                 else
1132                 {
1133                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
1134                 }
1135                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
1136         }
1137         else
1138         {
1139                 if (flags & TEXF_MIPMAP)
1140                 {
1141                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1142                 }
1143                 else
1144                 {
1145                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1146                 }
1147                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1148         }
1149
1150 #ifdef GL_TEXTURE_COMPARE_MODE_ARB
1151         switch(textype)
1152         {
1153         case TEXTYPE_SHADOWMAP16_COMP:
1154         case TEXTYPE_SHADOWMAP24_COMP:
1155                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1156                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1157                 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1158                 break;
1159         case TEXTYPE_SHADOWMAP16_RAW:
1160         case TEXTYPE_SHADOWMAP24_RAW:
1161                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1162                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1163                 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1164                 break;
1165         default:
1166                 break;
1167         }
1168 #endif
1169
1170         CHECKGLERROR
1171 }
1172
1173 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1174 {
1175         if (data == NULL)
1176                 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1177
1178         if (glt->texturetype != GLTEXTURETYPE_2D)
1179                 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1180
1181         if (glt->textype->textype == TEXTYPE_PALETTE)
1182                 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1183
1184         if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1185                 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1186
1187         if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1188                 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1189
1190         // update a portion of the image
1191
1192         switch(vid.renderpath)
1193         {
1194         case RENDERPATH_GL11:
1195         case RENDERPATH_GL13:
1196         case RENDERPATH_GL20:
1197         case RENDERPATH_GLES1:
1198         case RENDERPATH_GLES2:
1199                 {
1200                         int oldbindtexnum;
1201                         CHECKGLERROR
1202                         // we need to restore the texture binding after finishing the upload
1203                         GL_ActiveTexture(0);
1204                         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1205                         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1206                         qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1207                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1208                 }
1209                 break;
1210         case RENDERPATH_D3D9:
1211 #ifdef SUPPORTD3D
1212                 {
1213                         RECT d3drect;
1214                         D3DLOCKED_RECT d3dlockedrect;
1215                         int y;
1216                         memset(&d3drect, 0, sizeof(d3drect));
1217                         d3drect.left = fragx;
1218                         d3drect.top = fragy;
1219                         d3drect.right = fragx+fragwidth;
1220                         d3drect.bottom = fragy+fragheight;
1221                         if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1222                         {
1223                                 for (y = 0;y < fragheight;y++)
1224                                         memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1225                                 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1226                         }
1227                 }
1228 #endif
1229                 break;
1230         case RENDERPATH_D3D10:
1231                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1232                 break;
1233         case RENDERPATH_D3D11:
1234                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1235                 break;
1236         case RENDERPATH_SOFT:
1237                 DPSOFTRAST_Texture_UpdatePartial(glt->texnum, 0, data, fragx, fragy, fragwidth, fragheight);
1238                 break;
1239         }
1240 }
1241
1242 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1243 {
1244         int i, mip = 0, width, height, depth;
1245         GLint oldbindtexnum = 0;
1246         const unsigned char *prevbuffer;
1247         prevbuffer = data;
1248
1249         // error out if a stretch is needed on special texture types
1250         if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1251                 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1252
1253         // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1254         // of the target size and then use the mipmap reduction function to get
1255         // high quality supersampled results
1256         for (width  = glt->tilewidth;width  < glt->inputwidth ;width  <<= 1);
1257         for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1258         for (depth  = glt->tiledepth;depth  < glt->inputdepth ;depth  <<= 1);
1259         R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1260
1261         if (prevbuffer == NULL)
1262         {
1263                 width = glt->tilewidth;
1264                 height = glt->tileheight;
1265                 depth = glt->tiledepth;
1266 //              memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1267 //              prevbuffer = resizebuffer;
1268         }
1269         else
1270         {
1271                 if (glt->textype->textype == TEXTYPE_PALETTE)
1272                 {
1273                         // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1274                         Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1275                         prevbuffer = colorconvertbuffer;
1276                 }
1277                 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1278                 {
1279                         // multiply RGB channels by A channel before uploading
1280                         int alpha;
1281                         for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1282                         {
1283                                 alpha = prevbuffer[i+3];
1284                                 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1285                                 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1286                                 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1287                                 colorconvertbuffer[i+3] = alpha;
1288                         }
1289                         prevbuffer = colorconvertbuffer;
1290                 }
1291                 // scale up to a power of 2 size (if appropriate)
1292                 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1293                 {
1294                         Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1295                         prevbuffer = resizebuffer;
1296                 }
1297                 // apply mipmap reduction algorithm to get down to picmip/max_size
1298                 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1299                 {
1300                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1301                         prevbuffer = resizebuffer;
1302                 }
1303         }
1304
1305         // do the appropriate upload type...
1306         switch(vid.renderpath)
1307         {
1308         case RENDERPATH_GL11:
1309         case RENDERPATH_GL13:
1310         case RENDERPATH_GL20:
1311         case RENDERPATH_GLES1:
1312         case RENDERPATH_GLES2:
1313                 if (glt->texnum) // not renderbuffers
1314                 {
1315                         CHECKGLERROR
1316
1317                         // we need to restore the texture binding after finishing the upload
1318                         GL_ActiveTexture(0);
1319                         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1320                         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1321
1322 #ifndef USE_GLES2
1323 #ifdef GL_TEXTURE_COMPRESSION_HINT_ARB
1324                         if (qglGetCompressedTexImageARB)
1325                         {
1326                                 if (gl_texturecompression.integer >= 2)
1327                                         qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1328                                 else
1329                                         qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1330                                 CHECKGLERROR
1331                         }
1332 #endif
1333 #endif
1334                         switch(glt->texturetype)
1335                         {
1336                         case GLTEXTURETYPE_2D:
1337                                 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1338                                 if (glt->flags & TEXF_MIPMAP)
1339                                 {
1340                                         while (width > 1 || height > 1 || depth > 1)
1341                                         {
1342                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1343                                                 prevbuffer = resizebuffer;
1344                                                 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1345                                         }
1346                                 }
1347                                 break;
1348                         case GLTEXTURETYPE_3D:
1349 #ifndef USE_GLES2
1350                                 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1351                                 if (glt->flags & TEXF_MIPMAP)
1352                                 {
1353                                         while (width > 1 || height > 1 || depth > 1)
1354                                         {
1355                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1356                                                 prevbuffer = resizebuffer;
1357                                                 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1358                                         }
1359                                 }
1360 #endif
1361                                 break;
1362                         case GLTEXTURETYPE_CUBEMAP:
1363                                 // convert and upload each side in turn,
1364                                 // from a continuous block of input texels
1365                                 texturebuffer = (unsigned char *)prevbuffer;
1366                                 for (i = 0;i < 6;i++)
1367                                 {
1368                                         prevbuffer = texturebuffer;
1369                                         texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1370                                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1371                                         {
1372                                                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1373                                                 prevbuffer = resizebuffer;
1374                                         }
1375                                         // picmip/max_size
1376                                         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1377                                         {
1378                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1379                                                 prevbuffer = resizebuffer;
1380                                         }
1381                                         mip = 0;
1382                                         qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1383                                         if (glt->flags & TEXF_MIPMAP)
1384                                         {
1385                                                 while (width > 1 || height > 1 || depth > 1)
1386                                                 {
1387                                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1388                                                         prevbuffer = resizebuffer;
1389                                                         qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1390                                                 }
1391                                         }
1392                                 }
1393                                 break;
1394                         }
1395                         GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1396                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1397                 }
1398                 break;
1399         case RENDERPATH_D3D9:
1400 #ifdef SUPPORTD3D
1401                 if (!(glt->flags & TEXF_RENDERTARGET) && glt->d3dtexture && !glt->d3dsurface)
1402                 {
1403                         D3DLOCKED_RECT d3dlockedrect;
1404                         D3DLOCKED_BOX d3dlockedbox;
1405                         switch(glt->texturetype)
1406                         {
1407                         case GLTEXTURETYPE_2D:
1408                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1409                                 {
1410                                         if (prevbuffer)
1411                                                 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1412                                         else
1413                                                 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1414                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1415                                 }
1416                                 mip++;
1417                                 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1418                                 {
1419                                         while (width > 1 || height > 1 || depth > 1)
1420                                         {
1421                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1422                                                 prevbuffer = resizebuffer;
1423                                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1424                                                 {
1425                                                         memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1426                                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1427                                                 }
1428                                                 mip++;
1429                                         }
1430                                 }
1431                                 break;
1432                         case GLTEXTURETYPE_3D:
1433                                 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1434                                 {
1435                                         // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1436                                         memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1437                                         IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1438                                 }
1439                                 mip++;
1440                                 if (glt->flags & TEXF_MIPMAP)
1441                                 {
1442                                         while (width > 1 || height > 1 || depth > 1)
1443                                         {
1444                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1445                                                 prevbuffer = resizebuffer;
1446                                                 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1447                                                 {
1448                                                         // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1449                                                         memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1450                                                         IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1451                                                 }
1452                                                 mip++;
1453                                         }
1454                                 }
1455                                 break;
1456                         case GLTEXTURETYPE_CUBEMAP:
1457                                 // convert and upload each side in turn,
1458                                 // from a continuous block of input texels
1459                                 texturebuffer = (unsigned char *)prevbuffer;
1460                                 for (i = 0;i < 6;i++)
1461                                 {
1462                                         prevbuffer = texturebuffer;
1463                                         texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1464                                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1465                                         {
1466                                                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1467                                                 prevbuffer = resizebuffer;
1468                                         }
1469                                         // picmip/max_size
1470                                         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1471                                         {
1472                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1473                                                 prevbuffer = resizebuffer;
1474                                         }
1475                                         mip = 0;
1476                                         if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1477                                         {
1478                                                 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1479                                                 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1480                                         }
1481                                         mip++;
1482                                         if (glt->flags & TEXF_MIPMAP)
1483                                         {
1484                                                 while (width > 1 || height > 1 || depth > 1)
1485                                                 {
1486                                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1487                                                         prevbuffer = resizebuffer;
1488                                                         if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1489                                                         {
1490                                                                 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1491                                                                 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1492                                                         }
1493                                                         mip++;
1494                                                 }
1495                                         }
1496                                 }
1497                                 break;
1498                         }
1499                 }
1500                 glt->d3daddressw = 0;
1501                 if (glt->flags & TEXF_CLAMP)
1502                 {
1503                         glt->d3daddressu = D3DTADDRESS_CLAMP;
1504                         glt->d3daddressv = D3DTADDRESS_CLAMP;
1505                         if (glt->tiledepth > 1)
1506                                 glt->d3daddressw = D3DTADDRESS_CLAMP;
1507                 }
1508                 else
1509                 {
1510                         glt->d3daddressu = D3DTADDRESS_WRAP;
1511                         glt->d3daddressv = D3DTADDRESS_WRAP;
1512                         if (glt->tiledepth > 1)
1513                                 glt->d3daddressw = D3DTADDRESS_WRAP;
1514                 }
1515                 glt->d3dmipmaplodbias = 0;
1516                 glt->d3dmaxmiplevel = 0;
1517                 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1518                 if (glt->flags & TEXF_FORCELINEAR)
1519                 {
1520                         glt->d3dminfilter = D3DTEXF_LINEAR;
1521                         glt->d3dmagfilter = D3DTEXF_LINEAR;
1522                         glt->d3dmipfilter = D3DTEXF_POINT;
1523                 }
1524                 else if (glt->flags & TEXF_FORCENEAREST)
1525                 {
1526                         glt->d3dminfilter = D3DTEXF_POINT;
1527                         glt->d3dmagfilter = D3DTEXF_POINT;
1528                         glt->d3dmipfilter = D3DTEXF_POINT;
1529                 }
1530                 else if (glt->flags & TEXF_MIPMAP)
1531                 {
1532                         glt->d3dminfilter = d3d_filter_mipmin;
1533                         glt->d3dmagfilter = d3d_filter_mipmag;
1534                         glt->d3dmipfilter = d3d_filter_mipmix;
1535                 }
1536                 else
1537                 {
1538                         glt->d3dminfilter = d3d_filter_flatmin;
1539                         glt->d3dmagfilter = d3d_filter_flatmag;
1540                         glt->d3dmipfilter = d3d_filter_flatmix;
1541                 }
1542 #endif
1543                 break;
1544         case RENDERPATH_D3D10:
1545                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1546                 break;
1547         case RENDERPATH_D3D11:
1548                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1549                 break;
1550         case RENDERPATH_SOFT:
1551                 switch(glt->texturetype)
1552                 {
1553                 case GLTEXTURETYPE_2D:
1554                         DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1555                         break;
1556                 case GLTEXTURETYPE_3D:
1557                         DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1558                         break;
1559                 case GLTEXTURETYPE_CUBEMAP:
1560                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1561                         {
1562                                 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1563                                 // convert and upload each side in turn,
1564                                 // from a continuous block of input texels
1565                                 // copy the results into combinedbuffer
1566                                 texturebuffer = (unsigned char *)prevbuffer;
1567                                 for (i = 0;i < 6;i++)
1568                                 {
1569                                         prevbuffer = texturebuffer;
1570                                         texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1571                                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1572                                         {
1573                                                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1574                                                 prevbuffer = resizebuffer;
1575                                         }
1576                                         // picmip/max_size
1577                                         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1578                                         {
1579                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1580                                                 prevbuffer = resizebuffer;
1581                                         }
1582                                         memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1583                                 }
1584                                 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1585                                 Mem_Free(combinedbuffer);
1586                         }
1587                         else
1588                                 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1589                         break;
1590                 }
1591                 if (glt->flags & TEXF_FORCELINEAR)
1592                         DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1593                 else if (glt->flags & TEXF_FORCENEAREST)
1594                         DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1595                 else if (glt->flags & TEXF_MIPMAP)
1596                         DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1597                 else
1598                         DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1599                 break;
1600         }
1601 }
1602
1603 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)
1604 {
1605         int i, size;
1606         gltexture_t *glt;
1607         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1608         textypeinfo_t *texinfo, *texinfo2;
1609         unsigned char *temppixels = NULL;
1610         qboolean swaprb;
1611
1612         if (cls.state == ca_dedicated)
1613                 return NULL;
1614
1615         // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1616         if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1617         {
1618                 int numpixels = width * height * depth * sides;
1619                 size = numpixels * 4;
1620                 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1621                 if (data)
1622                 {
1623                         const unsigned char *p;
1624                         unsigned char *o = temppixels;
1625                         for (i = 0;i < numpixels;i++, o += 4)
1626                         {
1627                                 p = (const unsigned char *)palette + 4*data[i];
1628                                 o[0] = p[2];
1629                                 o[1] = p[1];
1630                                 o[2] = p[0];
1631                                 o[3] = p[3];
1632                         }
1633                 }
1634                 data = temppixels;
1635                 textype = TEXTYPE_RGBA;
1636         }
1637         swaprb = false;
1638         switch(textype)
1639         {
1640         case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1641         case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1642         case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1643         case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1644         default: break;
1645         }
1646         if (swaprb)
1647         {
1648                 // swap bytes
1649                 static int rgbaswapindices[4] = {2, 1, 0, 3};
1650                 size = width * height * depth * sides * 4;
1651                 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1652                 if (data)
1653                         Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1654                 data = temppixels;
1655         }
1656
1657         // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1658         if (!vid.support.ext_texture_srgb)
1659         {
1660                 qboolean convertsRGB = false;
1661                 switch(textype)
1662                 {
1663                 case TEXTYPE_SRGB_DXT1:    textype = TEXTYPE_DXT1   ;convertsRGB = true;break;
1664                 case TEXTYPE_SRGB_DXT1A:   textype = TEXTYPE_DXT1A  ;convertsRGB = true;break;
1665                 case TEXTYPE_SRGB_DXT3:    textype = TEXTYPE_DXT3   ;convertsRGB = true;break;
1666                 case TEXTYPE_SRGB_DXT5:    textype = TEXTYPE_DXT5   ;convertsRGB = true;break;
1667                 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;/*convertsRGB = true;*/break;
1668                 case TEXTYPE_SRGB_RGBA:    textype = TEXTYPE_RGBA   ;convertsRGB = true;break;
1669                 case TEXTYPE_SRGB_BGRA:    textype = TEXTYPE_BGRA   ;convertsRGB = true;break;
1670                 default:
1671                         break;
1672                 }
1673                 if (convertsRGB && data)
1674                 {
1675                         size = width * height * depth * sides * 4;
1676                         if (!temppixels)
1677                         {
1678                                 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1679                                 memcpy(temppixels, data, size);
1680                                 data = temppixels;
1681                         }
1682                         Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1683                 }
1684         }
1685
1686         if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1687         {
1688                 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1689                 return NULL;
1690         }
1691         if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1692         {
1693                 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1694                 return NULL;
1695         }
1696
1697         texinfo = R_GetTexTypeInfo(textype, flags);
1698         size = width * height * depth * sides * texinfo->inputbytesperpixel;
1699         if (size < 1)
1700         {
1701                 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1702                 return NULL;
1703         }
1704
1705         // clear the alpha flag if the texture has no transparent pixels
1706         switch(textype)
1707         {
1708         case TEXTYPE_PALETTE:
1709         case TEXTYPE_SRGB_PALETTE:
1710                 if (flags & TEXF_ALPHA)
1711                 {
1712                         flags &= ~TEXF_ALPHA;
1713                         if (data)
1714                         {
1715                                 for (i = 0;i < size;i++)
1716                                 {
1717                                         if (((unsigned char *)&palette[data[i]])[3] < 255)
1718                                         {
1719                                                 flags |= TEXF_ALPHA;
1720                                                 break;
1721                                         }
1722                                 }
1723                         }
1724                 }
1725                 break;
1726         case TEXTYPE_RGBA:
1727         case TEXTYPE_BGRA:
1728         case TEXTYPE_SRGB_RGBA:
1729         case TEXTYPE_SRGB_BGRA:
1730                 if (flags & TEXF_ALPHA)
1731                 {
1732                         flags &= ~TEXF_ALPHA;
1733                         if (data)
1734                         {
1735                                 for (i = 3;i < size;i += 4)
1736                                 {
1737                                         if (data[i] < 255)
1738                                         {
1739                                                 flags |= TEXF_ALPHA;
1740                                                 break;
1741                                         }
1742                                 }
1743                         }
1744                 }
1745                 break;
1746         case TEXTYPE_SHADOWMAP16_COMP:
1747         case TEXTYPE_SHADOWMAP16_RAW:
1748         case TEXTYPE_SHADOWMAP24_COMP:
1749         case TEXTYPE_SHADOWMAP24_RAW:
1750                 break;
1751         case TEXTYPE_DXT1:
1752         case TEXTYPE_SRGB_DXT1:
1753                 break;
1754         case TEXTYPE_DXT1A:
1755         case TEXTYPE_SRGB_DXT1A:
1756         case TEXTYPE_DXT3:
1757         case TEXTYPE_SRGB_DXT3:
1758         case TEXTYPE_DXT5:
1759         case TEXTYPE_SRGB_DXT5:
1760                 flags |= TEXF_ALPHA;
1761                 break;
1762         case TEXTYPE_ALPHA:
1763                 flags |= TEXF_ALPHA;
1764                 break;
1765         case TEXTYPE_COLORBUFFER:
1766         case TEXTYPE_COLORBUFFER16F:
1767         case TEXTYPE_COLORBUFFER32F:
1768                 flags |= TEXF_ALPHA;
1769                 break;
1770         default:
1771                 Sys_Error("R_LoadTexture: unknown texture type");
1772         }
1773
1774         texinfo2 = R_GetTexTypeInfo(textype, flags);
1775         if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1776                 texinfo = texinfo2;
1777         else
1778                 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1779
1780         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1781         if (identifier)
1782                 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1783         glt->pool = pool;
1784         glt->chain = pool->gltchain;
1785         pool->gltchain = glt;
1786         glt->inputwidth = width;
1787         glt->inputheight = height;
1788         glt->inputdepth = depth;
1789         glt->flags = flags;
1790         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
1791         glt->textype = texinfo;
1792         glt->texturetype = texturetype;
1793         glt->inputdatasize = size;
1794         glt->palette = palette;
1795         glt->glinternalformat = texinfo->glinternalformat;
1796         glt->glformat = texinfo->glformat;
1797         glt->gltype = texinfo->gltype;
1798         glt->bytesperpixel = texinfo->internalbytesperpixel;
1799         glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1800         glt->texnum = 0;
1801         glt->dirty = false;
1802         glt->glisdepthstencil = false;
1803         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1804         // init the dynamic texture attributes, too [11/22/2007 Black]
1805         glt->updatecallback = NULL;
1806         glt->updatecallback_data = NULL;
1807
1808         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1809
1810         // upload the texture
1811         // data may be NULL (blank texture for dynamic rendering)
1812         switch(vid.renderpath)
1813         {
1814         case RENDERPATH_GL11:
1815         case RENDERPATH_GL13:
1816         case RENDERPATH_GL20:
1817         case RENDERPATH_GLES1:
1818         case RENDERPATH_GLES2:
1819                 CHECKGLERROR
1820                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1821                 break;
1822         case RENDERPATH_D3D9:
1823 #ifdef SUPPORTD3D
1824                 {
1825                         D3DFORMAT d3dformat;
1826                         D3DPOOL d3dpool;
1827                         DWORD d3dusage;
1828                         HRESULT d3dresult;
1829                         d3dusage = 0;
1830                         d3dpool = D3DPOOL_MANAGED;
1831                         if (flags & TEXF_RENDERTARGET)
1832                         {
1833                                 d3dusage |= D3DUSAGE_RENDERTARGET;
1834                                 d3dpool = D3DPOOL_DEFAULT;
1835                         }
1836                         switch(textype)
1837                         {
1838                         case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1839                         case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1840                         case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1841                         case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
1842                         case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
1843                         case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
1844                         case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1845                         default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1846                         }
1847                         glt->d3dformat = d3dformat;
1848                         glt->d3dusage = d3dusage;
1849                         glt->d3dpool = d3dpool;
1850                         glt->d3disrendertargetsurface = false;
1851                         glt->d3disdepthstencilsurface = false;
1852                         if (glt->tiledepth > 1)
1853                         {
1854                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateVolumeTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->tiledepth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DVolumeTexture9 **)&glt->d3dtexture, NULL)))
1855                                         Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1856                         }
1857                         else if (glt->sides == 6)
1858                         {
1859                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1860                                         Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1861                         }
1862                         else
1863                         {
1864                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL)))
1865                                         Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1866                         }
1867                 }
1868 #endif
1869                 break;
1870         case RENDERPATH_D3D10:
1871                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1872                 break;
1873         case RENDERPATH_D3D11:
1874                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1875                 break;
1876         case RENDERPATH_SOFT:
1877                 {
1878                         int tflags = 0;
1879                         switch(textype)
1880                         {
1881                         case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1882                         case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1883                         case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1884                         case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1885                         case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
1886                         case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
1887                         case TEXTYPE_SHADOWMAP16_COMP:
1888                         case TEXTYPE_SHADOWMAP16_RAW:
1889                         case TEXTYPE_SHADOWMAP24_COMP:
1890                         case TEXTYPE_SHADOWMAP24_RAW: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1891                         case TEXTYPE_DEPTHBUFFER16:
1892                         case TEXTYPE_DEPTHBUFFER24:
1893                         case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1894                         case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1895                         default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1896                         }
1897                         if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1898                         if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1899                         if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1900                         if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1901                         glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1902                 }
1903                 break;
1904         }
1905
1906         R_UploadFullTexture(glt, data);
1907         if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1908                 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1909
1910         // free any temporary processing buffer we allocated...
1911         if (temppixels)
1912                 Mem_Free(temppixels);
1913
1914         // texture converting and uploading can take a while, so make sure we're sending keepalives
1915         // FIXME: this causes rendering during R_Shadow_DrawLights
1916 //      CL_KeepaliveMessage(false);
1917
1918         return (rtexture_t *)glt;
1919 }
1920
1921 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)
1922 {
1923         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1924 }
1925
1926 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)
1927 {
1928         return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1929 }
1930
1931 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)
1932 {
1933         return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1934 }
1935
1936 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter)
1937 {
1938         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL);
1939 }
1940
1941 rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
1942 {
1943         gltexture_t *glt;
1944         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1945         textypeinfo_t *texinfo;
1946
1947         if (cls.state == ca_dedicated)
1948                 return NULL;
1949
1950         texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP);
1951
1952         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1953         if (identifier)
1954                 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1955         glt->pool = pool;
1956         glt->chain = pool->gltchain;
1957         pool->gltchain = glt;
1958         glt->inputwidth = width;
1959         glt->inputheight = height;
1960         glt->inputdepth = 1;
1961         glt->flags = TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_FORCENEAREST;
1962         glt->miplevel = 0;
1963         glt->textype = texinfo;
1964         glt->texturetype = textype;
1965         glt->inputdatasize = width*height*texinfo->internalbytesperpixel;
1966         glt->palette = NULL;
1967         glt->glinternalformat = texinfo->glinternalformat;
1968         glt->glformat = texinfo->glformat;
1969         glt->gltype = texinfo->gltype;
1970         glt->bytesperpixel = texinfo->internalbytesperpixel;
1971         glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1972         glt->texnum = 0;
1973         glt->dirty = false;
1974         glt->glisdepthstencil = textype == TEXTYPE_DEPTHBUFFER24STENCIL8;
1975         glt->gltexturetypeenum = GL_TEXTURE_2D;
1976         // init the dynamic texture attributes, too [11/22/2007 Black]
1977         glt->updatecallback = NULL;
1978         glt->updatecallback_data = NULL;
1979
1980         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1981
1982         // upload the texture
1983         // data may be NULL (blank texture for dynamic rendering)
1984         switch(vid.renderpath)
1985         {
1986         case RENDERPATH_GL11:
1987         case RENDERPATH_GL13:
1988         case RENDERPATH_GL20:
1989         case RENDERPATH_GLES1:
1990         case RENDERPATH_GLES2:
1991                 CHECKGLERROR
1992                 qglGenRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
1993                 qglBindRenderbuffer(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR
1994                 qglRenderbufferStorage(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR
1995                 // 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
1996                 qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR
1997                 break;
1998         case RENDERPATH_D3D9:
1999 #ifdef SUPPORTD3D
2000                 {
2001                         D3DFORMAT d3dformat;
2002                         HRESULT d3dresult;
2003                         glt->d3disrendertargetsurface = false;
2004                         glt->d3disdepthstencilsurface = false;
2005                         switch(textype)
2006                         {
2007                         case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;glt->d3disrendertargetsurface = true;break;
2008                         case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;glt->d3disrendertargetsurface = true;break;
2009                         case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;glt->d3disrendertargetsurface = true;break;
2010                         case TEXTYPE_DEPTHBUFFER16: d3dformat = D3DFMT_D16;glt->d3disdepthstencilsurface = true;break;
2011                         case TEXTYPE_DEPTHBUFFER24: d3dformat = D3DFMT_D24X8;glt->d3disdepthstencilsurface = true;break;
2012                         case TEXTYPE_DEPTHBUFFER24STENCIL8: d3dformat = D3DFMT_D24S8;glt->d3disdepthstencilsurface = true;break;
2013                         default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2014                         }
2015                         glt->d3dformat = d3dformat;
2016                         glt->d3dusage = 0;
2017                         glt->d3dpool = 0;
2018                         if (glt->d3disrendertargetsurface)
2019                         {
2020                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
2021                                         Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!");
2022                         }
2023                         else if (glt->d3disdepthstencilsurface)
2024                         {
2025                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
2026                                         Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
2027                         }
2028                 }
2029 #endif
2030                 break;
2031         case RENDERPATH_D3D10:
2032                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2033                 break;
2034         case RENDERPATH_D3D11:
2035                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2036                 break;
2037         case RENDERPATH_SOFT:
2038                 {
2039                         int tflags = 0;
2040                         switch(textype)
2041                         {
2042                         case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8 | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2043                         case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2044                         case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2045                         case TEXTYPE_DEPTHBUFFER16:
2046                         case TEXTYPE_DEPTHBUFFER24:
2047                         case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2048                         default: Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
2049                         }
2050                         glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
2051                 }
2052                 break;
2053         }
2054
2055         return (rtexture_t *)glt;
2056 }
2057
2058 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
2059 {
2060 #ifdef USE_GLES2
2061         return -1; // unsupported on this platform
2062 #else
2063         gltexture_t *glt = (gltexture_t *)rt;
2064         unsigned char *dds;
2065         int oldbindtexnum;
2066         int bytesperpixel = 0;
2067         int bytesperblock = 0;
2068         int dds_flags;
2069         int dds_format_flags;
2070         int dds_caps1;
2071         int dds_caps2;
2072         int ret;
2073         int mip;
2074         int mipmaps;
2075         int mipinfo[16][4];
2076         int ddssize = 128;
2077         GLint internalformat;
2078         const char *ddsfourcc;
2079         if (!rt)
2080                 return -1; // NULL pointer
2081         if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
2082                 return -2; // broken driver - crashes on reading internal format
2083         if (!qglGetTexLevelParameteriv)
2084                 return -2;
2085         GL_ActiveTexture(0);
2086         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2087         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2088         qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
2089         switch(internalformat)
2090         {
2091         default: ddsfourcc = NULL;bytesperpixel = 4;break;
2092         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
2093         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
2094         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
2095         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
2096         }
2097         // if premultiplied alpha, say so in the DDS file
2098         if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
2099         {
2100                 switch(internalformat)
2101                 {
2102                         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
2103                         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
2104                 }
2105         }
2106         if (!bytesperblock && skipuncompressed)
2107                 return -3; // skipped
2108         memset(mipinfo, 0, sizeof(mipinfo));
2109         mipinfo[0][0] = glt->tilewidth;
2110         mipinfo[0][1] = glt->tileheight;
2111         mipmaps = 1;
2112         if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1))
2113         {
2114                 for (mip = 1;mip < 16;mip++)
2115                 {
2116                         mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
2117                         mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
2118                         if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
2119                         {
2120                                 mip++;
2121                                 break;
2122                         }
2123                 }
2124                 mipmaps = mip;
2125         }
2126         for (mip = 0;mip < mipmaps;mip++)
2127         {
2128                 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
2129                 mipinfo[mip][3] = ddssize;
2130                 ddssize += mipinfo[mip][2];
2131         }
2132         dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
2133         if (!dds)
2134                 return -4;
2135         dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
2136         dds_caps2 = 0;
2137         if (bytesperblock)
2138         {
2139                 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
2140                 dds_format_flags = 0x4; // DDPF_FOURCC
2141         }
2142         else
2143         {
2144                 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
2145                 dds_format_flags = 0x40; // DDPF_RGB
2146         }
2147         if (mipmaps)
2148         {
2149                 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
2150                 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
2151         }
2152         if(hasalpha)
2153                 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
2154         memcpy(dds, "DDS ", 4);
2155         StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
2156         StoreLittleLong(dds+8, dds_flags);
2157         StoreLittleLong(dds+12, mipinfo[0][1]); // height
2158         StoreLittleLong(dds+16, mipinfo[0][0]); // width
2159         StoreLittleLong(dds+24, 0); // depth
2160         StoreLittleLong(dds+28, mipmaps); // mipmaps
2161         StoreLittleLong(dds+76, 32); // format size
2162         StoreLittleLong(dds+80, dds_format_flags);
2163         StoreLittleLong(dds+108, dds_caps1);
2164         StoreLittleLong(dds+112, dds_caps2);
2165         if (bytesperblock)
2166         {
2167                 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
2168                 memcpy(dds+84, ddsfourcc, 4);
2169                 for (mip = 0;mip < mipmaps;mip++)
2170                 {
2171                         qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
2172                 }
2173         }
2174         else
2175         {
2176                 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
2177                 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
2178                 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
2179                 for (mip = 0;mip < mipmaps;mip++)
2180                 {
2181                         qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
2182                 }
2183         }
2184         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2185         ret = FS_WriteFile(filename, dds, ddssize);
2186         Mem_Free(dds);
2187         return ret ? ddssize : -5;
2188 #endif
2189 }
2190
2191 #ifdef __ANDROID__
2192 // ELUAN: FIXME: separate this code
2193 #include "ktx10/include/ktx.h"
2194 #endif
2195
2196 rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qboolean srgb, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel, qboolean optionaltexture) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint
2197 {
2198         int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
2199         //int dds_flags;
2200         textype_t textype;
2201         int bytesperblock, bytesperpixel;
2202         int mipcomplete;
2203         gltexture_t *glt;
2204         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
2205         textypeinfo_t *texinfo;
2206         int mip, mipwidth, mipheight, mipsize, mipsize_total;
2207         unsigned int c, r, g, b;
2208         GLint oldbindtexnum = 0;
2209         unsigned char *mippixels;
2210         unsigned char *mippixels_start;
2211         unsigned char *ddspixels;
2212         unsigned char *dds;
2213         fs_offset_t ddsfilesize;
2214         unsigned int ddssize;
2215         qboolean force_swdecode, npothack;
2216 #ifdef __ANDROID__
2217         // ELUAN: FIXME: separate this code
2218         char vabuf[1024];
2219         char vabuf2[1024];
2220         int strsize;
2221         KTX_dimensions sizes;
2222 #endif
2223
2224         if (cls.state == ca_dedicated)
2225                 return NULL;
2226
2227 #ifdef __ANDROID__
2228         // ELUAN: FIXME: separate this code
2229         if (vid.renderpath != RENDERPATH_GLES2)
2230         {
2231                 Con_DPrintf("KTX texture format is only supported on the GLES2 renderpath\n");
2232                 return NULL;
2233         }
2234
2235         // some textures are specified with extensions, so it becomes .tga.dds
2236         FS_StripExtension (filename, vabuf2, sizeof(vabuf2));
2237         FS_StripExtension (vabuf2, vabuf, sizeof(vabuf));
2238         FS_DefaultExtension (vabuf, ".ktx", sizeof(vabuf));
2239         strsize = strlen(vabuf);
2240         if (strsize > 5)
2241         for (i = 0; i <= strsize - 4; i++) // copy null termination
2242                 vabuf[i] = vabuf[i + 4];
2243
2244         Con_DPrintf("Loading %s...\n", vabuf);
2245         dds = FS_LoadFile(vabuf, tempmempool, true, &ddsfilesize);
2246         ddssize = ddsfilesize;
2247
2248         if (!dds)
2249         {
2250                 Con_DPrintf("Not found!\n");
2251                 return NULL; // not found
2252         }
2253         Con_DPrintf("Found!\n");
2254
2255         if (flags & TEXF_ALPHA)
2256         {
2257                 Con_DPrintf("KTX texture with alpha not supported yet, disabling\n");
2258                 flags &= ~TEXF_ALPHA;
2259         }
2260
2261         {
2262                 GLenum target;
2263                 GLenum glerror;
2264                 GLboolean isMipmapped;
2265                 KTX_error_code ktxerror;
2266
2267                 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2268
2269                 // texture uploading can take a while, so make sure we're sending keepalives
2270                 CL_KeepaliveMessage(false);
2271
2272                 // create the texture object
2273                 CHECKGLERROR
2274                 GL_ActiveTexture(0);
2275                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[GLTEXTURETYPE_2D]);
2276                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2277                 qglBindTexture(gltexturetypeenums[GLTEXTURETYPE_2D], glt->texnum);CHECKGLERROR
2278
2279                 // upload the texture
2280                 // we need to restore the texture binding after finishing the upload
2281
2282                 // NOTE: some drivers fail with ETC1 NPOT (only PowerVR?). This may make the driver crash later.
2283                 ktxerror = ktxLoadTextureM(dds, ddssize, &glt->texnum, &target, &sizes, &isMipmapped, &glerror,
2284                                                                 0, NULL);// can't CHECKGLERROR, the lib catches it
2285
2286                 // FIXME: delete texture if we fail here
2287                 if (target != GL_TEXTURE_2D)
2288                 {
2289                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2290                         Mem_Free(dds);
2291                         Con_DPrintf("%s target != GL_TEXTURE_2D, target == %x\n", vabuf, target);
2292                         return NULL; // FIXME: delete the texture from memory
2293                 }
2294
2295                 if (KTX_SUCCESS == ktxerror)
2296                 {
2297                         textype = TEXTYPE_ETC1;
2298                         flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2299
2300                         // return whether this texture is transparent
2301                         if (hasalphaflag)
2302                                 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2303
2304                         // TODO: apply gl_picmip
2305                         // TODO: avgcolor
2306                         // TODO: srgb
2307                         // TODO: only load mipmaps if requested
2308
2309                         if (isMipmapped)
2310                                 flags |= TEXF_MIPMAP;
2311                         else
2312                                 flags &= ~TEXF_MIPMAP;
2313
2314                         texinfo = R_GetTexTypeInfo(textype, flags);
2315
2316                         strlcpy (glt->identifier, vabuf, sizeof(glt->identifier));
2317                         glt->pool = pool;
2318                         glt->chain = pool->gltchain;
2319                         pool->gltchain = glt;
2320                         glt->inputwidth = sizes.width;
2321                         glt->inputheight = sizes.height;
2322                         glt->inputdepth = 1;
2323                         glt->flags = flags;
2324                         glt->textype = texinfo;
2325                         glt->texturetype = GLTEXTURETYPE_2D;
2326                         glt->inputdatasize = ddssize;
2327                         glt->glinternalformat = texinfo->glinternalformat;
2328                         glt->glformat = texinfo->glformat;
2329                         glt->gltype = texinfo->gltype;
2330                         glt->bytesperpixel = texinfo->internalbytesperpixel;
2331                         glt->sides = 1;
2332                         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2333                         glt->tilewidth = sizes.width;
2334                         glt->tileheight = sizes.height;
2335                         glt->tiledepth = 1;
2336                         glt->miplevels = isMipmapped ? 1 : 0; // FIXME
2337
2338                                 // after upload we have to set some parameters...
2339 #ifdef GL_TEXTURE_MAX_LEVEL
2340                         /* FIXME
2341                                 if (dds_miplevels >= 1 && !mipcomplete)
2342                                 {
2343                                         // need to set GL_TEXTURE_MAX_LEVEL
2344                                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2345                                 }
2346                         */
2347 #endif
2348                                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2349
2350                                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2351                                 Mem_Free(dds);
2352                                 return (rtexture_t *)glt;
2353                 }
2354                 else
2355                 {
2356                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2357                         Mem_Free(dds);
2358                         Con_DPrintf("KTX texture %s failed to load: %x\n", vabuf, ktxerror);
2359                         return NULL;
2360                 }
2361         }
2362 #endif // __ANDROID__
2363
2364         dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
2365         ddssize = ddsfilesize;
2366
2367         if (!dds)
2368         {
2369                 if (r_texture_dds_load_logfailure.integer && (r_texture_dds_load_logfailure.integer >= 2 || !optionaltexture))
2370                         Log_Printf("ddstexturefailures.log", "%s\n", filename);
2371                 return NULL; // not found
2372         }
2373
2374         if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
2375         {
2376                 Mem_Free(dds);
2377                 Con_Printf("^1%s: not a DDS image\n", filename);
2378                 return NULL;
2379         }
2380
2381         //dds_flags = BuffLittleLong(dds+8);
2382         dds_format_flags = BuffLittleLong(dds+80);
2383         dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
2384         dds_width = BuffLittleLong(dds+16);
2385         dds_height = BuffLittleLong(dds+12);
2386         ddspixels = dds + 128;
2387
2388         if(r_texture_dds_load_alphamode.integer == 0)
2389                 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
2390                         flags &= ~TEXF_ALPHA;
2391
2392         //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
2393         if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
2394         {
2395                 // very sloppy BGRA 32bit identification
2396                 textype = TEXTYPE_BGRA;
2397                 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2398                 bytesperblock = 0;
2399                 bytesperpixel = 4;
2400                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
2401                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2402                 {
2403                         Mem_Free(dds);
2404                         Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
2405                         return NULL;
2406                 }
2407                 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
2408                 {
2409                         // check alpha
2410                         for (i = 3;i < size;i += 4)
2411                                 if (ddspixels[i] < 255)
2412                                         break;
2413                         if (i >= size)
2414                                 flags &= ~TEXF_ALPHA;
2415                 }
2416         }
2417         else if (!memcmp(dds+84, "DXT1", 4))
2418         {
2419                 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
2420                 // LordHavoc: it is my belief that this does not infringe on the
2421                 // patent because it is not decoding pixels...
2422                 textype = TEXTYPE_DXT1;
2423                 bytesperblock = 8;
2424                 bytesperpixel = 0;
2425                 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
2426                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2427                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2428                 {
2429                         Mem_Free(dds);
2430                         Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
2431                         return NULL;
2432                 }
2433                 if (flags & TEXF_ALPHA)
2434                 {
2435                         if (r_texture_dds_load_alphamode.integer == 1)
2436                         {
2437                                 // check alpha
2438                                 for (i = 0;i < size;i += bytesperblock)
2439                                         if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
2440                                         {
2441                                                 // NOTE: this assumes sizeof(unsigned int) == 4
2442                                                 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
2443                                                 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
2444                                                 if(data & (data<<1) & 0xAAAAAAAA)//rgh
2445                                                         break;
2446                                         }
2447                                 if (i < size)
2448                                         textype = TEXTYPE_DXT1A;
2449                                 else
2450                                         flags &= ~TEXF_ALPHA;
2451                         }
2452                         else if (r_texture_dds_load_alphamode.integer == 0)
2453                                 textype = TEXTYPE_DXT1A;
2454                         else
2455                         {
2456                                 flags &= ~TEXF_ALPHA;
2457                         }
2458                 }
2459         }
2460         else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2461         {
2462                 if(!memcmp(dds+84, "DXT2", 4))
2463                 {
2464                         if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2465                         {
2466                                 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2467                         }
2468                 }
2469                 else
2470                 {
2471                         if(flags & TEXF_RGBMULTIPLYBYALPHA)
2472                         {
2473                                 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2474                         }
2475                 }
2476                 textype = TEXTYPE_DXT3;
2477                 bytesperblock = 16;
2478                 bytesperpixel = 0;
2479                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2480                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2481                 {
2482                         Mem_Free(dds);
2483                         Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2484                         return NULL;
2485                 }
2486                 // we currently always assume alpha
2487         }
2488         else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2489         {
2490                 if(!memcmp(dds+84, "DXT4", 4))
2491                 {
2492                         if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2493                         {
2494                                 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2495                         }
2496                 }
2497                 else
2498                 {
2499                         if(flags & TEXF_RGBMULTIPLYBYALPHA)
2500                         {
2501                                 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2502                         }
2503                 }
2504                 textype = TEXTYPE_DXT5;
2505                 bytesperblock = 16;
2506                 bytesperpixel = 0;
2507                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2508                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2509                 {
2510                         Mem_Free(dds);
2511                         Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2512                         return NULL;
2513                 }
2514                 // we currently always assume alpha
2515         }
2516         else
2517         {
2518                 Mem_Free(dds);
2519                 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2520                 return NULL;
2521         }
2522
2523         // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
2524         if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
2525         {
2526                 textype = TEXTYPE_DXT1;
2527                 bytesperblock = 8;
2528                 ddssize -= 128;
2529                 ddssize /= 2;
2530                 for (i = 0;i < (int)ddssize;i += bytesperblock)
2531                         memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
2532                 ddssize += 128;
2533         }
2534
2535         force_swdecode = false;
2536         npothack = 
2537                 (!vid.support.arb_texture_non_power_of_two &&
2538                         (
2539                                 (dds_width & (dds_width - 1))
2540                                 ||
2541                                 (dds_height & (dds_height - 1))
2542                         )
2543                 );
2544         if(bytesperblock)
2545         {
2546                 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && !npothack)
2547                 {
2548                         if(r_texture_dds_swdecode.integer > 1)
2549                                 force_swdecode = true;
2550                 }
2551                 else
2552                 {
2553                         if(r_texture_dds_swdecode.integer < 1)
2554                         {
2555                                 // unsupported
2556                                 Mem_Free(dds);
2557                                 return NULL;
2558                         }
2559                         force_swdecode = true;
2560                 }
2561         }
2562
2563         // return whether this texture is transparent
2564         if (hasalphaflag)
2565                 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2566
2567         // if we SW decode, choose 2 sizes bigger
2568         if(force_swdecode)
2569         {
2570                 // this is quarter res, so do not scale down more than we have to
2571                 miplevel -= 2;
2572
2573                 if(miplevel < 0)
2574                         Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2575         }
2576
2577         // this is where we apply gl_picmip
2578         mippixels_start = ddspixels;
2579         mipwidth = dds_width;
2580         mipheight = dds_height;
2581         while(miplevel >= 1 && dds_miplevels >= 1)
2582         {
2583                 if (mipwidth <= 1 && mipheight <= 1)
2584                         break;
2585                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2586                 mippixels_start += mipsize; // just skip
2587                 --dds_miplevels;
2588                 --miplevel;
2589                 if (mipwidth > 1)
2590                         mipwidth >>= 1;
2591                 if (mipheight > 1)
2592                         mipheight >>= 1;
2593         }
2594         mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2595         mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2596
2597         // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2598
2599         // fake decode S3TC if needed
2600         if(force_swdecode)
2601         {
2602                 int mipsize_new = mipsize_total / bytesperblock * 4;
2603                 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2604                 unsigned char *p = mipnewpixels;
2605                 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2606                 {
2607                         c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2608                         p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2609                         p[1] = (((c >>  5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2610                         p[0] = (((c      ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2611                         if(textype == TEXTYPE_DXT5)
2612                                 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2613                         else if(textype == TEXTYPE_DXT3)
2614                                 p[3] = (
2615                                           (mippixels_start[i-8] & 0x0F)
2616                                         + (mippixels_start[i-8] >> 4)
2617                                         + (mippixels_start[i-7] & 0x0F)
2618                                         + (mippixels_start[i-7] >> 4)
2619                                         + (mippixels_start[i-6] & 0x0F)
2620                                         + (mippixels_start[i-6] >> 4)
2621                                         + (mippixels_start[i-5] & 0x0F)
2622                                         + (mippixels_start[i-5] >> 4)
2623                                        ) * (0.125f / 15.0f * 255.0f);
2624                         else
2625                                 p[3] = 255;
2626                 }
2627
2628                 textype = TEXTYPE_BGRA;
2629                 bytesperblock = 0;
2630                 bytesperpixel = 4;
2631
2632                 // as each block becomes a pixel, we must use pixel count for this
2633                 mipwidth = (mipwidth + 3) / 4;
2634                 mipheight = (mipheight + 3) / 4;
2635                 mipsize = bytesperpixel * mipwidth * mipheight;
2636                 mippixels_start = mipnewpixels;
2637                 mipsize_total = mipsize_new;
2638         }
2639
2640         // start mip counting
2641         mippixels = mippixels_start;
2642
2643         // calculate average color if requested
2644         if (avgcolor)
2645         {
2646                 float f;
2647                 Vector4Clear(avgcolor);
2648                 if (bytesperblock)
2649                 {
2650                         for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2651                         {
2652                                 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2653                                 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2654                                 avgcolor[1] += ((c >>  5) & 0x3F) + ((c >> 21) & 0x3F);
2655                                 avgcolor[2] += ((c      ) & 0x1F) + ((c >> 16) & 0x1F);
2656                                 if(textype == TEXTYPE_DXT5)
2657                                         avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f);
2658                                 else if(textype == TEXTYPE_DXT3)
2659                                         avgcolor[3] += (
2660                                                   (mippixels_start[i-8] & 0x0F)
2661                                                 + (mippixels_start[i-8] >> 4)
2662                                                 + (mippixels_start[i-7] & 0x0F)
2663                                                 + (mippixels_start[i-7] >> 4)
2664                                                 + (mippixels_start[i-6] & 0x0F)
2665                                                 + (mippixels_start[i-6] >> 4)
2666                                                 + (mippixels_start[i-5] & 0x0F)
2667                                                 + (mippixels_start[i-5] >> 4)
2668                                                ) * (0.125f / 15.0f);
2669                                 else
2670                                         avgcolor[3] += 1.0f;
2671                         }
2672                         f = (float)bytesperblock / mipsize;
2673                         avgcolor[0] *= (0.5f / 31.0f) * f;
2674                         avgcolor[1] *= (0.5f / 63.0f) * f;
2675                         avgcolor[2] *= (0.5f / 31.0f) * f;
2676                         avgcolor[3] *= f;
2677                 }
2678                 else
2679                 {
2680                         for (i = 0;i < mipsize;i += 4)
2681                         {
2682                                 avgcolor[0] += mippixels[i+2];
2683                                 avgcolor[1] += mippixels[i+1];
2684                                 avgcolor[2] += mippixels[i];
2685                                 avgcolor[3] += mippixels[i+3];
2686                         }
2687                         f = (1.0f / 255.0f) * bytesperpixel / mipsize;
2688                         avgcolor[0] *= f;
2689                         avgcolor[1] *= f;
2690                         avgcolor[2] *= f;
2691                         avgcolor[3] *= f;
2692                 }
2693         }
2694
2695         // if we want sRGB, convert now
2696         if(srgb)
2697         {
2698                 if (vid.support.ext_texture_srgb)
2699                 {
2700                         switch(textype)
2701                         {
2702                         case TEXTYPE_DXT1:    textype = TEXTYPE_SRGB_DXT1   ;break;
2703                         case TEXTYPE_DXT1A:   textype = TEXTYPE_SRGB_DXT1A  ;break;
2704                         case TEXTYPE_DXT3:    textype = TEXTYPE_SRGB_DXT3   ;break;
2705                         case TEXTYPE_DXT5:    textype = TEXTYPE_SRGB_DXT5   ;break;
2706                         case TEXTYPE_RGBA:    textype = TEXTYPE_SRGB_RGBA   ;break;
2707                         default:
2708                                 break;
2709                         }
2710                 }
2711                 else
2712                 {
2713                         switch(textype)
2714                         {
2715                         case TEXTYPE_DXT1:
2716                         case TEXTYPE_DXT1A:
2717                         case TEXTYPE_DXT3:
2718                         case TEXTYPE_DXT5:
2719                                 {
2720                                         for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2721                                         {
2722                                                 int c0, c1, c0new, c1new;
2723                                                 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2724                                                 r = ((c0 >> 11) & 0x1F);
2725                                                 g = ((c0 >>  5) & 0x3F);
2726                                                 b = ((c0      ) & 0x1F);
2727                                                 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2728                                                 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2729                                                 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2730                                                 c0new = (r << 11) | (g << 5) | b;
2731                                                 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2732                                                 r = ((c1 >> 11) & 0x1F);
2733                                                 g = ((c1 >>  5) & 0x3F);
2734                                                 b = ((c1      ) & 0x1F);
2735                                                 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2736                                                 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2737                                                 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2738                                                 c1new = (r << 11) | (g << 5) | b;
2739                                                 // swap the colors if needed to fix order
2740                                                 if(c0 > c1) // thirds
2741                                                 {
2742                                                         if(c0new < c1new)
2743                                                         {
2744                                                                 c = c0new;
2745                                                                 c0new = c1new;
2746                                                                 c1new = c;
2747                                                                 if(c0new == c1new)
2748                                                                 mippixels_start[i+4] ^= 0x55;
2749                                                                 mippixels_start[i+5] ^= 0x55;
2750                                                                 mippixels_start[i+6] ^= 0x55;
2751                                                                 mippixels_start[i+7] ^= 0x55;
2752                                                         }
2753                                                         else if(c0new == c1new)
2754                                                         {
2755                                                                 mippixels_start[i+4] = 0x00;
2756                                                                 mippixels_start[i+5] = 0x00;
2757                                                                 mippixels_start[i+6] = 0x00;
2758                                                                 mippixels_start[i+7] = 0x00;
2759                                                         }
2760                                                 }
2761                                                 else // half + transparent
2762                                                 {
2763                                                         if(c0new > c1new)
2764                                                         {
2765                                                                 c = c0new;
2766                                                                 c0new = c1new;
2767                                                                 c1new = c;
2768                                                                 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2769                                                                 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2770                                                                 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2771                                                                 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2772                                                         }
2773                                                 }
2774                                                 mippixels_start[i] = c0new & 255;
2775                                                 mippixels_start[i+1] = c0new >> 8;
2776                                                 mippixels_start[i+2] = c1new & 255;
2777                                                 mippixels_start[i+3] = c1new >> 8;
2778                                         }
2779                                 }
2780                                 break;
2781                         case TEXTYPE_RGBA:
2782                                 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2783                                 break;
2784                         default:
2785                                 break;
2786                         }
2787                 }
2788         }
2789
2790         // when not requesting mipmaps, do not load them
2791         if(!(flags & TEXF_MIPMAP))
2792                 dds_miplevels = 0;
2793
2794         if (dds_miplevels >= 1)
2795                 flags |= TEXF_MIPMAP;
2796         else
2797                 flags &= ~TEXF_MIPMAP;
2798
2799         texinfo = R_GetTexTypeInfo(textype, flags);
2800
2801         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2802         strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2803         glt->pool = pool;
2804         glt->chain = pool->gltchain;
2805         pool->gltchain = glt;
2806         glt->inputwidth = mipwidth;
2807         glt->inputheight = mipheight;
2808         glt->inputdepth = 1;
2809         glt->flags = flags;
2810         glt->textype = texinfo;
2811         glt->texturetype = GLTEXTURETYPE_2D;
2812         glt->inputdatasize = ddssize;
2813         glt->glinternalformat = texinfo->glinternalformat;
2814         glt->glformat = texinfo->glformat;
2815         glt->gltype = texinfo->gltype;
2816         glt->bytesperpixel = texinfo->internalbytesperpixel;
2817         glt->sides = 1;
2818         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2819         glt->tilewidth = mipwidth;
2820         glt->tileheight = mipheight;
2821         glt->tiledepth = 1;
2822         glt->miplevels = dds_miplevels;
2823
2824         if(npothack)
2825         {
2826                 for (glt->tilewidth = 1;glt->tilewidth < mipwidth;glt->tilewidth <<= 1);
2827                 for (glt->tileheight = 1;glt->tileheight < mipheight;glt->tileheight <<= 1);
2828         }
2829
2830         // texture uploading can take a while, so make sure we're sending keepalives
2831         CL_KeepaliveMessage(false);
2832
2833         // create the texture object
2834         switch(vid.renderpath)
2835         {
2836         case RENDERPATH_GL11:
2837         case RENDERPATH_GL13:
2838         case RENDERPATH_GL20:
2839         case RENDERPATH_GLES1:
2840         case RENDERPATH_GLES2:
2841                 CHECKGLERROR
2842                 GL_ActiveTexture(0);
2843                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2844                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2845                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2846                 break;
2847         case RENDERPATH_D3D9:
2848 #ifdef SUPPORTD3D
2849                 {
2850                         D3DFORMAT d3dformat;
2851                         D3DPOOL d3dpool;
2852                         DWORD d3dusage;
2853                         switch(textype)
2854                         {
2855                         case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2856                         case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2857                         case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2858                         case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2859                         default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2860                         }
2861                         d3dusage = 0;
2862                         d3dpool = D3DPOOL_MANAGED;
2863                         IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2864                 }
2865 #endif
2866                 break;
2867         case RENDERPATH_D3D10:
2868                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2869                 break;
2870         case RENDERPATH_D3D11:
2871                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2872                 break;
2873         case RENDERPATH_SOFT:
2874                 glt->texnum = DPSOFTRAST_Texture_New(((glt->flags & TEXF_CLAMP) ? DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE : 0) | (dds_miplevels > 1 ? DPSOFTRAST_TEXTURE_FLAG_MIPMAP : 0), glt->tilewidth, glt->tileheight, glt->tiledepth);
2875                 break;
2876         }
2877
2878         // upload the texture
2879         // we need to restore the texture binding after finishing the upload
2880         mipcomplete = false;
2881
2882         for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2883         {
2884                 unsigned char *upload_mippixels = mippixels;
2885                 int upload_mipwidth = mipwidth;
2886                 int upload_mipheight = mipheight;
2887                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2888                 if (mippixels + mipsize > mippixels_start + mipsize_total)
2889                         break;
2890                 if(npothack)
2891                 {
2892                         upload_mipwidth = (glt->tilewidth >> mip);
2893                         upload_mipheight = (glt->tileheight >> mip);
2894                         if(upload_mipwidth != mipwidth || upload_mipheight != mipheight)
2895                         // I _think_ they always mismatch, but I was too lazy
2896                         // to properly check, and this test here is really
2897                         // harmless
2898                         {
2899                                 upload_mippixels = (unsigned char *) Mem_Alloc(tempmempool, 4 * upload_mipwidth * upload_mipheight);
2900                                 Image_Resample32(mippixels, mipwidth, mipheight, 1, upload_mippixels, upload_mipwidth, upload_mipheight, 1, r_lerpimages.integer);
2901                         }
2902                 }
2903                 switch(vid.renderpath)
2904                 {
2905                 case RENDERPATH_GL11:
2906                 case RENDERPATH_GL13:
2907                 case RENDERPATH_GL20:
2908                 case RENDERPATH_GLES1:
2909                 case RENDERPATH_GLES2:
2910                         if (bytesperblock)
2911                         {
2912                                 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR
2913                         }
2914                         else
2915                         {
2916                                 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR
2917                         }
2918                         break;
2919                 case RENDERPATH_D3D9:
2920 #ifdef SUPPORTD3D
2921                         {
2922                                 D3DLOCKED_RECT d3dlockedrect;
2923                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2924                                 {
2925                                         memcpy(d3dlockedrect.pBits, upload_mippixels, mipsize);
2926                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2927                                 }
2928                                 break;
2929                         }
2930 #endif
2931                         break;
2932                 case RENDERPATH_D3D10:
2933                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2934                         break;
2935                 case RENDERPATH_D3D11:
2936                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2937                         break;
2938                 case RENDERPATH_SOFT:
2939                         if (bytesperblock)
2940                                 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2941                         else
2942                                 DPSOFTRAST_Texture_UpdateFull(glt->texnum, upload_mippixels);
2943                         // DPSOFTRAST calculates its own mipmaps
2944                         mip = dds_miplevels;
2945                         break;
2946                 }
2947                 if(upload_mippixels != mippixels)
2948                         Mem_Free(upload_mippixels);
2949                 mippixels += mipsize;
2950                 if (mipwidth <= 1 && mipheight <= 1)
2951                 {
2952                         mipcomplete = true;
2953                         break;
2954                 }
2955                 if (mipwidth > 1)
2956                         mipwidth >>= 1;
2957                 if (mipheight > 1)
2958                         mipheight >>= 1;
2959         }
2960
2961         // after upload we have to set some parameters...
2962         switch(vid.renderpath)
2963         {
2964         case RENDERPATH_GL11:
2965         case RENDERPATH_GL13:
2966         case RENDERPATH_GL20:
2967         case RENDERPATH_GLES1:
2968         case RENDERPATH_GLES2:
2969 #ifdef GL_TEXTURE_MAX_LEVEL
2970                 if (dds_miplevels >= 1 && !mipcomplete)
2971                 {
2972                         // need to set GL_TEXTURE_MAX_LEVEL
2973                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2974                 }
2975 #endif
2976                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2977                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2978                 break;
2979         case RENDERPATH_D3D9:
2980 #ifdef SUPPORTD3D
2981                 glt->d3daddressw = 0;
2982                 if (glt->flags & TEXF_CLAMP)
2983                 {
2984                         glt->d3daddressu = D3DTADDRESS_CLAMP;
2985                         glt->d3daddressv = D3DTADDRESS_CLAMP;
2986                         if (glt->tiledepth > 1)
2987                                 glt->d3daddressw = D3DTADDRESS_CLAMP;
2988                 }
2989                 else
2990                 {
2991                         glt->d3daddressu = D3DTADDRESS_WRAP;
2992                         glt->d3daddressv = D3DTADDRESS_WRAP;
2993                         if (glt->tiledepth > 1)
2994                                 glt->d3daddressw = D3DTADDRESS_WRAP;
2995                 }
2996                 glt->d3dmipmaplodbias = 0;
2997                 glt->d3dmaxmiplevel = 0;
2998                 glt->d3dmaxmiplevelfilter = 0;
2999                 if (glt->flags & TEXF_MIPMAP)
3000                 {
3001                         glt->d3dminfilter = d3d_filter_mipmin;
3002                         glt->d3dmagfilter = d3d_filter_mipmag;
3003                         glt->d3dmipfilter = d3d_filter_mipmix;
3004                 }
3005                 else
3006                 {
3007                         glt->d3dminfilter = d3d_filter_flatmin;
3008                         glt->d3dmagfilter = d3d_filter_flatmag;
3009                         glt->d3dmipfilter = d3d_filter_flatmix;
3010                 }
3011 #endif
3012                 break;
3013         case RENDERPATH_D3D10:
3014                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3015                 break;
3016         case RENDERPATH_D3D11:
3017                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3018                 break;
3019         case RENDERPATH_SOFT:
3020                 if (glt->flags & TEXF_FORCELINEAR)
3021                         DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
3022                 else if (glt->flags & TEXF_FORCENEAREST)
3023                         DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
3024                 else if (glt->flags & TEXF_MIPMAP)
3025                         DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
3026                 else
3027                         DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
3028                 break;
3029         }
3030
3031         Mem_Free(dds);
3032         if(force_swdecode)
3033                 Mem_Free((unsigned char *) mippixels_start);
3034         return (rtexture_t *)glt;
3035 }
3036
3037 int R_TextureWidth(rtexture_t *rt)
3038 {
3039         return rt ? ((gltexture_t *)rt)->inputwidth : 0;
3040 }
3041
3042 int R_TextureHeight(rtexture_t *rt)
3043 {
3044         return rt ? ((gltexture_t *)rt)->inputheight : 0;
3045 }
3046
3047 int R_TextureFlags(rtexture_t *rt)
3048 {
3049         return rt ? ((gltexture_t *)rt)->flags : 0;
3050 }
3051
3052 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
3053 {
3054         gltexture_t *glt = (gltexture_t *)rt;
3055         if (data == NULL)
3056                 Host_Error("R_UpdateTexture: no data supplied");
3057         if (glt == NULL)
3058                 Host_Error("R_UpdateTexture: no texture supplied");
3059         if (!glt->texnum && !glt->d3dtexture)
3060         {
3061                 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
3062                 return;
3063         }
3064         // update part of the texture
3065         if (glt->bufferpixels)
3066         {
3067                 int j;
3068                 int bpp = glt->bytesperpixel;
3069                 int inputskip = width*bpp;
3070                 int outputskip = glt->tilewidth*bpp;
3071                 const unsigned char *input = data;
3072                 unsigned char *output = glt->bufferpixels;
3073                 if (glt->inputdepth != 1 || glt->sides != 1)
3074                         Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
3075                 if (x < 0)
3076                 {
3077                         width += x;
3078                         input -= x*bpp;
3079                         x = 0;
3080                 }
3081                 if (y < 0)
3082                 {
3083                         height += y;
3084                         input -= y*inputskip;
3085                         y = 0;
3086                 }
3087                 if (width > glt->tilewidth - x)
3088                         width = glt->tilewidth - x;
3089                 if (height > glt->tileheight - y)
3090                         height = glt->tileheight - y;
3091                 if (width < 1 || height < 1)
3092                         return;
3093                 glt->dirty = true;
3094                 glt->buffermodified = true;
3095                 output += y*outputskip + x*bpp;
3096                 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
3097                         memcpy(output, input, width*bpp);
3098         }
3099         else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
3100                 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
3101         else
3102                 R_UploadFullTexture(glt, data);
3103 }
3104
3105 int R_RealGetTexture(rtexture_t *rt)
3106 {
3107         if (rt)
3108         {
3109                 gltexture_t *glt;
3110                 glt = (gltexture_t *)rt;
3111                 if (glt->flags & GLTEXF_DYNAMIC)
3112                         R_UpdateDynamicTexture(glt);
3113                 if (glt->buffermodified && glt->bufferpixels)
3114                 {
3115                         glt->buffermodified = false;
3116                         R_UploadFullTexture(glt, glt->bufferpixels);
3117                 }
3118                 glt->dirty = false;
3119                 return glt->texnum;
3120         }
3121         else
3122                 return 0;
3123 }
3124
3125 void R_ClearTexture (rtexture_t *rt)
3126 {
3127         gltexture_t *glt = (gltexture_t *)rt;
3128
3129         R_UploadFullTexture(glt, NULL);
3130 }
3131
3132 int R_PicmipForFlags(int flags)
3133 {
3134         int miplevel = 0;
3135         if(flags & TEXF_PICMIP)
3136         {
3137                 miplevel += gl_picmip.integer;
3138                 if (flags & TEXF_ISWORLD)
3139                 {
3140                         if (r_picmipworld.integer)
3141                                 miplevel += gl_picmip_world.integer;
3142                         else
3143                                 miplevel = 0;
3144                 }
3145                 else if (flags & TEXF_ISSPRITE)
3146                 {
3147                         if (r_picmipsprites.integer)
3148                                 miplevel += gl_picmip_sprites.integer;
3149                         else
3150                                 miplevel = 0;
3151                 }
3152                 else
3153                         miplevel += gl_picmip_other.integer;
3154         }
3155         return max(0, miplevel);
3156 }