]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_textures.c
Don't allocate resize buffer for texture upload if the texture does not need to be...
[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
1260         if (prevbuffer == NULL)
1261         {
1262                 width = glt->tilewidth;
1263                 height = glt->tileheight;
1264                 depth = glt->tiledepth;
1265 //              R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
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                         R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1275                         Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1276                         prevbuffer = colorconvertbuffer;
1277                 }
1278                 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1279                 {
1280                         // multiply RGB channels by A channel before uploading
1281                         int alpha;
1282                         R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1283                         for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1284                         {
1285                                 alpha = prevbuffer[i+3];
1286                                 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1287                                 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1288                                 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1289                                 colorconvertbuffer[i+3] = alpha;
1290                         }
1291                         prevbuffer = colorconvertbuffer;
1292                 }
1293                 // scale up to a power of 2 size (if appropriate)
1294                 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1295                 {
1296                         R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1297                         Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1298                         prevbuffer = resizebuffer;
1299                 }
1300                 // apply mipmap reduction algorithm to get down to picmip/max_size
1301                 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1302                 {
1303                         R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1304                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1305                         prevbuffer = resizebuffer;
1306                 }
1307         }
1308
1309         // do the appropriate upload type...
1310         switch(vid.renderpath)
1311         {
1312         case RENDERPATH_GL11:
1313         case RENDERPATH_GL13:
1314         case RENDERPATH_GL20:
1315         case RENDERPATH_GLES1:
1316         case RENDERPATH_GLES2:
1317                 if (glt->texnum) // not renderbuffers
1318                 {
1319                         CHECKGLERROR
1320
1321                         // we need to restore the texture binding after finishing the upload
1322                         GL_ActiveTexture(0);
1323                         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1324                         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1325
1326 #ifndef USE_GLES2
1327 #ifdef GL_TEXTURE_COMPRESSION_HINT_ARB
1328                         if (qglGetCompressedTexImageARB)
1329                         {
1330                                 if (gl_texturecompression.integer >= 2)
1331                                         qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1332                                 else
1333                                         qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1334                                 CHECKGLERROR
1335                         }
1336 #endif
1337 #endif
1338                         switch(glt->texturetype)
1339                         {
1340                         case GLTEXTURETYPE_2D:
1341                                 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1342                                 if (glt->flags & TEXF_MIPMAP)
1343                                 {
1344                                         while (width > 1 || height > 1 || depth > 1)
1345                                         {
1346                                                 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1347                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1348                                                 prevbuffer = resizebuffer;
1349                                                 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1350                                         }
1351                                 }
1352                                 break;
1353                         case GLTEXTURETYPE_3D:
1354 #ifndef USE_GLES2
1355                                 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1356                                 if (glt->flags & TEXF_MIPMAP)
1357                                 {
1358                                         while (width > 1 || height > 1 || depth > 1)
1359                                         {
1360                                                 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1361                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1362                                                 prevbuffer = resizebuffer;
1363                                                 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1364                                         }
1365                                 }
1366 #endif
1367                                 break;
1368                         case GLTEXTURETYPE_CUBEMAP:
1369                                 // convert and upload each side in turn,
1370                                 // from a continuous block of input texels
1371                                 texturebuffer = (unsigned char *)prevbuffer;
1372                                 for (i = 0;i < 6;i++)
1373                                 {
1374                                         prevbuffer = texturebuffer;
1375                                         texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1376                                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1377                                         {
1378                                                 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1379                                                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1380                                                 prevbuffer = resizebuffer;
1381                                         }
1382                                         // picmip/max_size
1383                                         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1384                                         {
1385                                                 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1386                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1387                                                 prevbuffer = resizebuffer;
1388                                         }
1389                                         mip = 0;
1390                                         qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1391                                         if (glt->flags & TEXF_MIPMAP)
1392                                         {
1393                                                 while (width > 1 || height > 1 || depth > 1)
1394                                                 {
1395                                                         R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1396                                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1397                                                         prevbuffer = resizebuffer;
1398                                                         qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1399                                                 }
1400                                         }
1401                                 }
1402                                 break;
1403                         }
1404                         GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1405                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1406                 }
1407                 break;
1408         case RENDERPATH_D3D9:
1409 #ifdef SUPPORTD3D
1410                 if (!(glt->flags & TEXF_RENDERTARGET) && glt->d3dtexture && !glt->d3dsurface)
1411                 {
1412                         D3DLOCKED_RECT d3dlockedrect;
1413                         D3DLOCKED_BOX d3dlockedbox;
1414                         switch(glt->texturetype)
1415                         {
1416                         case GLTEXTURETYPE_2D:
1417                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1418                                 {
1419                                         if (prevbuffer)
1420                                                 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1421                                         else
1422                                                 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1423                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1424                                 }
1425                                 mip++;
1426                                 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1427                                 {
1428                                         while (width > 1 || height > 1 || depth > 1)
1429                                         {
1430                                                 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1431                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1432                                                 prevbuffer = resizebuffer;
1433                                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1434                                                 {
1435                                                         memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1436                                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1437                                                 }
1438                                                 mip++;
1439                                         }
1440                                 }
1441                                 break;
1442                         case GLTEXTURETYPE_3D:
1443                                 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1444                                 {
1445                                         // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1446                                         memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1447                                         IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1448                                 }
1449                                 mip++;
1450                                 if (glt->flags & TEXF_MIPMAP)
1451                                 {
1452                                         while (width > 1 || height > 1 || depth > 1)
1453                                         {
1454                                                 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1455                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1456                                                 prevbuffer = resizebuffer;
1457                                                 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1458                                                 {
1459                                                         // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1460                                                         memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1461                                                         IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1462                                                 }
1463                                                 mip++;
1464                                         }
1465                                 }
1466                                 break;
1467                         case GLTEXTURETYPE_CUBEMAP:
1468                                 // convert and upload each side in turn,
1469                                 // from a continuous block of input texels
1470                                 texturebuffer = (unsigned char *)prevbuffer;
1471                                 for (i = 0;i < 6;i++)
1472                                 {
1473                                         prevbuffer = texturebuffer;
1474                                         texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1475                                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1476                                         {
1477                                                 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1478                                                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1479                                                 prevbuffer = resizebuffer;
1480                                         }
1481                                         // picmip/max_size
1482                                         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1483                                         {
1484                                                 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1485                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1486                                                 prevbuffer = resizebuffer;
1487                                         }
1488                                         mip = 0;
1489                                         if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1490                                         {
1491                                                 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1492                                                 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1493                                         }
1494                                         mip++;
1495                                         if (glt->flags & TEXF_MIPMAP)
1496                                         {
1497                                                 while (width > 1 || height > 1 || depth > 1)
1498                                                 {
1499                                                         R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1500                                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1501                                                         prevbuffer = resizebuffer;
1502                                                         if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1503                                                         {
1504                                                                 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1505                                                                 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1506                                                         }
1507                                                         mip++;
1508                                                 }
1509                                         }
1510                                 }
1511                                 break;
1512                         }
1513                 }
1514                 glt->d3daddressw = 0;
1515                 if (glt->flags & TEXF_CLAMP)
1516                 {
1517                         glt->d3daddressu = D3DTADDRESS_CLAMP;
1518                         glt->d3daddressv = D3DTADDRESS_CLAMP;
1519                         if (glt->tiledepth > 1)
1520                                 glt->d3daddressw = D3DTADDRESS_CLAMP;
1521                 }
1522                 else
1523                 {
1524                         glt->d3daddressu = D3DTADDRESS_WRAP;
1525                         glt->d3daddressv = D3DTADDRESS_WRAP;
1526                         if (glt->tiledepth > 1)
1527                                 glt->d3daddressw = D3DTADDRESS_WRAP;
1528                 }
1529                 glt->d3dmipmaplodbias = 0;
1530                 glt->d3dmaxmiplevel = 0;
1531                 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1532                 if (glt->flags & TEXF_FORCELINEAR)
1533                 {
1534                         glt->d3dminfilter = D3DTEXF_LINEAR;
1535                         glt->d3dmagfilter = D3DTEXF_LINEAR;
1536                         glt->d3dmipfilter = D3DTEXF_POINT;
1537                 }
1538                 else if (glt->flags & TEXF_FORCENEAREST)
1539                 {
1540                         glt->d3dminfilter = D3DTEXF_POINT;
1541                         glt->d3dmagfilter = D3DTEXF_POINT;
1542                         glt->d3dmipfilter = D3DTEXF_POINT;
1543                 }
1544                 else if (glt->flags & TEXF_MIPMAP)
1545                 {
1546                         glt->d3dminfilter = d3d_filter_mipmin;
1547                         glt->d3dmagfilter = d3d_filter_mipmag;
1548                         glt->d3dmipfilter = d3d_filter_mipmix;
1549                 }
1550                 else
1551                 {
1552                         glt->d3dminfilter = d3d_filter_flatmin;
1553                         glt->d3dmagfilter = d3d_filter_flatmag;
1554                         glt->d3dmipfilter = d3d_filter_flatmix;
1555                 }
1556 #endif
1557                 break;
1558         case RENDERPATH_D3D10:
1559                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1560                 break;
1561         case RENDERPATH_D3D11:
1562                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1563                 break;
1564         case RENDERPATH_SOFT:
1565                 switch(glt->texturetype)
1566                 {
1567                 case GLTEXTURETYPE_2D:
1568                         DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1569                         break;
1570                 case GLTEXTURETYPE_3D:
1571                         DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1572                         break;
1573                 case GLTEXTURETYPE_CUBEMAP:
1574                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1575                         {
1576                                 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1577                                 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1578                                 // convert and upload each side in turn,
1579                                 // from a continuous block of input texels
1580                                 // copy the results into combinedbuffer
1581                                 texturebuffer = (unsigned char *)prevbuffer;
1582                                 for (i = 0;i < 6;i++)
1583                                 {
1584                                         prevbuffer = texturebuffer;
1585                                         texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1586                                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1587                                         {
1588                                                 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1589                                                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1590                                                 prevbuffer = resizebuffer;
1591                                         }
1592                                         // picmip/max_size
1593                                         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1594                                         {
1595                                                 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1596                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1597                                                 prevbuffer = resizebuffer;
1598                                         }
1599                                         memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1600                                 }
1601                                 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1602                                 Mem_Free(combinedbuffer);
1603                         }
1604                         else
1605                                 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1606                         break;
1607                 }
1608                 if (glt->flags & TEXF_FORCELINEAR)
1609                         DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1610                 else if (glt->flags & TEXF_FORCENEAREST)
1611                         DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1612                 else if (glt->flags & TEXF_MIPMAP)
1613                         DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1614                 else
1615                         DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1616                 break;
1617         }
1618 }
1619
1620 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)
1621 {
1622         int i, size;
1623         gltexture_t *glt;
1624         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1625         textypeinfo_t *texinfo, *texinfo2;
1626         unsigned char *temppixels = NULL;
1627         qboolean swaprb;
1628
1629         if (cls.state == ca_dedicated)
1630                 return NULL;
1631
1632         // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1633         if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1634         {
1635                 int numpixels = width * height * depth * sides;
1636                 size = numpixels * 4;
1637                 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1638                 if (data)
1639                 {
1640                         const unsigned char *p;
1641                         unsigned char *o = temppixels;
1642                         for (i = 0;i < numpixels;i++, o += 4)
1643                         {
1644                                 p = (const unsigned char *)palette + 4*data[i];
1645                                 o[0] = p[2];
1646                                 o[1] = p[1];
1647                                 o[2] = p[0];
1648                                 o[3] = p[3];
1649                         }
1650                 }
1651                 data = temppixels;
1652                 textype = TEXTYPE_RGBA;
1653         }
1654         swaprb = false;
1655         switch(textype)
1656         {
1657         case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1658         case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1659         case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1660         case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1661         default: break;
1662         }
1663         if (swaprb)
1664         {
1665                 // swap bytes
1666                 static int rgbaswapindices[4] = {2, 1, 0, 3};
1667                 size = width * height * depth * sides * 4;
1668                 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1669                 if (data)
1670                         Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1671                 data = temppixels;
1672         }
1673
1674         // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1675         if (!vid.support.ext_texture_srgb)
1676         {
1677                 qboolean convertsRGB = false;
1678                 switch(textype)
1679                 {
1680                 case TEXTYPE_SRGB_DXT1:    textype = TEXTYPE_DXT1   ;convertsRGB = true;break;
1681                 case TEXTYPE_SRGB_DXT1A:   textype = TEXTYPE_DXT1A  ;convertsRGB = true;break;
1682                 case TEXTYPE_SRGB_DXT3:    textype = TEXTYPE_DXT3   ;convertsRGB = true;break;
1683                 case TEXTYPE_SRGB_DXT5:    textype = TEXTYPE_DXT5   ;convertsRGB = true;break;
1684                 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;/*convertsRGB = true;*/break;
1685                 case TEXTYPE_SRGB_RGBA:    textype = TEXTYPE_RGBA   ;convertsRGB = true;break;
1686                 case TEXTYPE_SRGB_BGRA:    textype = TEXTYPE_BGRA   ;convertsRGB = true;break;
1687                 default:
1688                         break;
1689                 }
1690                 if (convertsRGB && data)
1691                 {
1692                         size = width * height * depth * sides * 4;
1693                         if (!temppixels)
1694                         {
1695                                 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1696                                 memcpy(temppixels, data, size);
1697                                 data = temppixels;
1698                         }
1699                         Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1700                 }
1701         }
1702
1703         if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1704         {
1705                 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1706                 return NULL;
1707         }
1708         if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1709         {
1710                 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1711                 return NULL;
1712         }
1713
1714         texinfo = R_GetTexTypeInfo(textype, flags);
1715         size = width * height * depth * sides * texinfo->inputbytesperpixel;
1716         if (size < 1)
1717         {
1718                 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1719                 return NULL;
1720         }
1721
1722         // clear the alpha flag if the texture has no transparent pixels
1723         switch(textype)
1724         {
1725         case TEXTYPE_PALETTE:
1726         case TEXTYPE_SRGB_PALETTE:
1727                 if (flags & TEXF_ALPHA)
1728                 {
1729                         flags &= ~TEXF_ALPHA;
1730                         if (data)
1731                         {
1732                                 for (i = 0;i < size;i++)
1733                                 {
1734                                         if (((unsigned char *)&palette[data[i]])[3] < 255)
1735                                         {
1736                                                 flags |= TEXF_ALPHA;
1737                                                 break;
1738                                         }
1739                                 }
1740                         }
1741                 }
1742                 break;
1743         case TEXTYPE_RGBA:
1744         case TEXTYPE_BGRA:
1745         case TEXTYPE_SRGB_RGBA:
1746         case TEXTYPE_SRGB_BGRA:
1747                 if (flags & TEXF_ALPHA)
1748                 {
1749                         flags &= ~TEXF_ALPHA;
1750                         if (data)
1751                         {
1752                                 for (i = 3;i < size;i += 4)
1753                                 {
1754                                         if (data[i] < 255)
1755                                         {
1756                                                 flags |= TEXF_ALPHA;
1757                                                 break;
1758                                         }
1759                                 }
1760                         }
1761                 }
1762                 break;
1763         case TEXTYPE_SHADOWMAP16_COMP:
1764         case TEXTYPE_SHADOWMAP16_RAW:
1765         case TEXTYPE_SHADOWMAP24_COMP:
1766         case TEXTYPE_SHADOWMAP24_RAW:
1767                 break;
1768         case TEXTYPE_DXT1:
1769         case TEXTYPE_SRGB_DXT1:
1770                 break;
1771         case TEXTYPE_DXT1A:
1772         case TEXTYPE_SRGB_DXT1A:
1773         case TEXTYPE_DXT3:
1774         case TEXTYPE_SRGB_DXT3:
1775         case TEXTYPE_DXT5:
1776         case TEXTYPE_SRGB_DXT5:
1777                 flags |= TEXF_ALPHA;
1778                 break;
1779         case TEXTYPE_ALPHA:
1780                 flags |= TEXF_ALPHA;
1781                 break;
1782         case TEXTYPE_COLORBUFFER:
1783         case TEXTYPE_COLORBUFFER16F:
1784         case TEXTYPE_COLORBUFFER32F:
1785                 flags |= TEXF_ALPHA;
1786                 break;
1787         default:
1788                 Sys_Error("R_LoadTexture: unknown texture type");
1789         }
1790
1791         texinfo2 = R_GetTexTypeInfo(textype, flags);
1792         if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1793                 texinfo = texinfo2;
1794         else
1795                 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1796
1797         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1798         if (identifier)
1799                 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1800         glt->pool = pool;
1801         glt->chain = pool->gltchain;
1802         pool->gltchain = glt;
1803         glt->inputwidth = width;
1804         glt->inputheight = height;
1805         glt->inputdepth = depth;
1806         glt->flags = flags;
1807         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
1808         glt->textype = texinfo;
1809         glt->texturetype = texturetype;
1810         glt->inputdatasize = size;
1811         glt->palette = palette;
1812         glt->glinternalformat = texinfo->glinternalformat;
1813         glt->glformat = texinfo->glformat;
1814         glt->gltype = texinfo->gltype;
1815         glt->bytesperpixel = texinfo->internalbytesperpixel;
1816         glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1817         glt->texnum = 0;
1818         glt->dirty = false;
1819         glt->glisdepthstencil = false;
1820         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1821         // init the dynamic texture attributes, too [11/22/2007 Black]
1822         glt->updatecallback = NULL;
1823         glt->updatecallback_data = NULL;
1824
1825         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1826
1827         // upload the texture
1828         // data may be NULL (blank texture for dynamic rendering)
1829         switch(vid.renderpath)
1830         {
1831         case RENDERPATH_GL11:
1832         case RENDERPATH_GL13:
1833         case RENDERPATH_GL20:
1834         case RENDERPATH_GLES1:
1835         case RENDERPATH_GLES2:
1836                 CHECKGLERROR
1837                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1838                 break;
1839         case RENDERPATH_D3D9:
1840 #ifdef SUPPORTD3D
1841                 {
1842                         D3DFORMAT d3dformat;
1843                         D3DPOOL d3dpool;
1844                         DWORD d3dusage;
1845                         HRESULT d3dresult;
1846                         d3dusage = 0;
1847                         d3dpool = D3DPOOL_MANAGED;
1848                         if (flags & TEXF_RENDERTARGET)
1849                         {
1850                                 d3dusage |= D3DUSAGE_RENDERTARGET;
1851                                 d3dpool = D3DPOOL_DEFAULT;
1852                         }
1853                         switch(textype)
1854                         {
1855                         case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1856                         case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1857                         case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1858                         case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
1859                         case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
1860                         case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
1861                         case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1862                         default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1863                         }
1864                         glt->d3dformat = d3dformat;
1865                         glt->d3dusage = d3dusage;
1866                         glt->d3dpool = d3dpool;
1867                         glt->d3disrendertargetsurface = false;
1868                         glt->d3disdepthstencilsurface = false;
1869                         if (glt->tiledepth > 1)
1870                         {
1871                                 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)))
1872                                         Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1873                         }
1874                         else if (glt->sides == 6)
1875                         {
1876                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1877                                         Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1878                         }
1879                         else
1880                         {
1881                                 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)))
1882                                         Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1883                         }
1884                 }
1885 #endif
1886                 break;
1887         case RENDERPATH_D3D10:
1888                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1889                 break;
1890         case RENDERPATH_D3D11:
1891                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1892                 break;
1893         case RENDERPATH_SOFT:
1894                 {
1895                         int tflags = 0;
1896                         switch(textype)
1897                         {
1898                         case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1899                         case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1900                         case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1901                         case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1902                         case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
1903                         case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
1904                         case TEXTYPE_SHADOWMAP16_COMP:
1905                         case TEXTYPE_SHADOWMAP16_RAW:
1906                         case TEXTYPE_SHADOWMAP24_COMP:
1907                         case TEXTYPE_SHADOWMAP24_RAW: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1908                         case TEXTYPE_DEPTHBUFFER16:
1909                         case TEXTYPE_DEPTHBUFFER24:
1910                         case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1911                         case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1912                         default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1913                         }
1914                         if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1915                         if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1916                         if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1917                         if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1918                         glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1919                 }
1920                 break;
1921         }
1922
1923         R_UploadFullTexture(glt, data);
1924         if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1925                 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1926
1927         // free any temporary processing buffer we allocated...
1928         if (temppixels)
1929                 Mem_Free(temppixels);
1930
1931         // texture converting and uploading can take a while, so make sure we're sending keepalives
1932         // FIXME: this causes rendering during R_Shadow_DrawLights
1933 //      CL_KeepaliveMessage(false);
1934
1935         return (rtexture_t *)glt;
1936 }
1937
1938 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)
1939 {
1940         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1941 }
1942
1943 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)
1944 {
1945         return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1946 }
1947
1948 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)
1949 {
1950         return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1951 }
1952
1953 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter)
1954 {
1955         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL);
1956 }
1957
1958 rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
1959 {
1960         gltexture_t *glt;
1961         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1962         textypeinfo_t *texinfo;
1963
1964         if (cls.state == ca_dedicated)
1965                 return NULL;
1966
1967         texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP);
1968
1969         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1970         if (identifier)
1971                 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1972         glt->pool = pool;
1973         glt->chain = pool->gltchain;
1974         pool->gltchain = glt;
1975         glt->inputwidth = width;
1976         glt->inputheight = height;
1977         glt->inputdepth = 1;
1978         glt->flags = TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_FORCENEAREST;
1979         glt->miplevel = 0;
1980         glt->textype = texinfo;
1981         glt->texturetype = textype;
1982         glt->inputdatasize = width*height*texinfo->internalbytesperpixel;
1983         glt->palette = NULL;
1984         glt->glinternalformat = texinfo->glinternalformat;
1985         glt->glformat = texinfo->glformat;
1986         glt->gltype = texinfo->gltype;
1987         glt->bytesperpixel = texinfo->internalbytesperpixel;
1988         glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1989         glt->texnum = 0;
1990         glt->dirty = false;
1991         glt->glisdepthstencil = textype == TEXTYPE_DEPTHBUFFER24STENCIL8;
1992         glt->gltexturetypeenum = GL_TEXTURE_2D;
1993         // init the dynamic texture attributes, too [11/22/2007 Black]
1994         glt->updatecallback = NULL;
1995         glt->updatecallback_data = NULL;
1996
1997         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1998
1999         // upload the texture
2000         // data may be NULL (blank texture for dynamic rendering)
2001         switch(vid.renderpath)
2002         {
2003         case RENDERPATH_GL11:
2004         case RENDERPATH_GL13:
2005         case RENDERPATH_GL20:
2006         case RENDERPATH_GLES1:
2007         case RENDERPATH_GLES2:
2008                 CHECKGLERROR
2009                 qglGenRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
2010                 qglBindRenderbuffer(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR
2011                 qglRenderbufferStorage(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR
2012                 // 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
2013                 qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR
2014                 break;
2015         case RENDERPATH_D3D9:
2016 #ifdef SUPPORTD3D
2017                 {
2018                         D3DFORMAT d3dformat;
2019                         HRESULT d3dresult;
2020                         glt->d3disrendertargetsurface = false;
2021                         glt->d3disdepthstencilsurface = false;
2022                         switch(textype)
2023                         {
2024                         case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;glt->d3disrendertargetsurface = true;break;
2025                         case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;glt->d3disrendertargetsurface = true;break;
2026                         case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;glt->d3disrendertargetsurface = true;break;
2027                         case TEXTYPE_DEPTHBUFFER16: d3dformat = D3DFMT_D16;glt->d3disdepthstencilsurface = true;break;
2028                         case TEXTYPE_DEPTHBUFFER24: d3dformat = D3DFMT_D24X8;glt->d3disdepthstencilsurface = true;break;
2029                         case TEXTYPE_DEPTHBUFFER24STENCIL8: d3dformat = D3DFMT_D24S8;glt->d3disdepthstencilsurface = true;break;
2030                         default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2031                         }
2032                         glt->d3dformat = d3dformat;
2033                         glt->d3dusage = 0;
2034                         glt->d3dpool = 0;
2035                         if (glt->d3disrendertargetsurface)
2036                         {
2037                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
2038                                         Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!");
2039                         }
2040                         else if (glt->d3disdepthstencilsurface)
2041                         {
2042                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
2043                                         Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
2044                         }
2045                 }
2046 #endif
2047                 break;
2048         case RENDERPATH_D3D10:
2049                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2050                 break;
2051         case RENDERPATH_D3D11:
2052                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2053                 break;
2054         case RENDERPATH_SOFT:
2055                 {
2056                         int tflags = 0;
2057                         switch(textype)
2058                         {
2059                         case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8 | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2060                         case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2061                         case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2062                         case TEXTYPE_DEPTHBUFFER16:
2063                         case TEXTYPE_DEPTHBUFFER24:
2064                         case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2065                         default: Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
2066                         }
2067                         glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
2068                 }
2069                 break;
2070         }
2071
2072         return (rtexture_t *)glt;
2073 }
2074
2075 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
2076 {
2077 #ifdef USE_GLES2
2078         return -1; // unsupported on this platform
2079 #else
2080         gltexture_t *glt = (gltexture_t *)rt;
2081         unsigned char *dds;
2082         int oldbindtexnum;
2083         int bytesperpixel = 0;
2084         int bytesperblock = 0;
2085         int dds_flags;
2086         int dds_format_flags;
2087         int dds_caps1;
2088         int dds_caps2;
2089         int ret;
2090         int mip;
2091         int mipmaps;
2092         int mipinfo[16][4];
2093         int ddssize = 128;
2094         GLint internalformat;
2095         const char *ddsfourcc;
2096         if (!rt)
2097                 return -1; // NULL pointer
2098         if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
2099                 return -2; // broken driver - crashes on reading internal format
2100         if (!qglGetTexLevelParameteriv)
2101                 return -2;
2102         GL_ActiveTexture(0);
2103         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2104         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2105         qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
2106         switch(internalformat)
2107         {
2108         default: ddsfourcc = NULL;bytesperpixel = 4;break;
2109         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
2110         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
2111         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
2112         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
2113         }
2114         // if premultiplied alpha, say so in the DDS file
2115         if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
2116         {
2117                 switch(internalformat)
2118                 {
2119                         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
2120                         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
2121                 }
2122         }
2123         if (!bytesperblock && skipuncompressed)
2124                 return -3; // skipped
2125         memset(mipinfo, 0, sizeof(mipinfo));
2126         mipinfo[0][0] = glt->tilewidth;
2127         mipinfo[0][1] = glt->tileheight;
2128         mipmaps = 1;
2129         if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1))
2130         {
2131                 for (mip = 1;mip < 16;mip++)
2132                 {
2133                         mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
2134                         mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
2135                         if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
2136                         {
2137                                 mip++;
2138                                 break;
2139                         }
2140                 }
2141                 mipmaps = mip;
2142         }
2143         for (mip = 0;mip < mipmaps;mip++)
2144         {
2145                 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
2146                 mipinfo[mip][3] = ddssize;
2147                 ddssize += mipinfo[mip][2];
2148         }
2149         dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
2150         if (!dds)
2151                 return -4;
2152         dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
2153         dds_caps2 = 0;
2154         if (bytesperblock)
2155         {
2156                 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
2157                 dds_format_flags = 0x4; // DDPF_FOURCC
2158         }
2159         else
2160         {
2161                 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
2162                 dds_format_flags = 0x40; // DDPF_RGB
2163         }
2164         if (mipmaps)
2165         {
2166                 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
2167                 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
2168         }
2169         if(hasalpha)
2170                 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
2171         memcpy(dds, "DDS ", 4);
2172         StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
2173         StoreLittleLong(dds+8, dds_flags);
2174         StoreLittleLong(dds+12, mipinfo[0][1]); // height
2175         StoreLittleLong(dds+16, mipinfo[0][0]); // width
2176         StoreLittleLong(dds+24, 0); // depth
2177         StoreLittleLong(dds+28, mipmaps); // mipmaps
2178         StoreLittleLong(dds+76, 32); // format size
2179         StoreLittleLong(dds+80, dds_format_flags);
2180         StoreLittleLong(dds+108, dds_caps1);
2181         StoreLittleLong(dds+112, dds_caps2);
2182         if (bytesperblock)
2183         {
2184                 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
2185                 memcpy(dds+84, ddsfourcc, 4);
2186                 for (mip = 0;mip < mipmaps;mip++)
2187                 {
2188                         qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
2189                 }
2190         }
2191         else
2192         {
2193                 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
2194                 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
2195                 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
2196                 for (mip = 0;mip < mipmaps;mip++)
2197                 {
2198                         qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
2199                 }
2200         }
2201         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2202         ret = FS_WriteFile(filename, dds, ddssize);
2203         Mem_Free(dds);
2204         return ret ? ddssize : -5;
2205 #endif
2206 }
2207
2208 #ifdef __ANDROID__
2209 // ELUAN: FIXME: separate this code
2210 #include "ktx10/include/ktx.h"
2211 #endif
2212
2213 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
2214 {
2215         int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
2216         //int dds_flags;
2217         textype_t textype;
2218         int bytesperblock, bytesperpixel;
2219         int mipcomplete;
2220         gltexture_t *glt;
2221         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
2222         textypeinfo_t *texinfo;
2223         int mip, mipwidth, mipheight, mipsize, mipsize_total;
2224         unsigned int c, r, g, b;
2225         GLint oldbindtexnum = 0;
2226         unsigned char *mippixels;
2227         unsigned char *mippixels_start;
2228         unsigned char *ddspixels;
2229         unsigned char *dds;
2230         fs_offset_t ddsfilesize;
2231         unsigned int ddssize;
2232         qboolean force_swdecode, npothack;
2233 #ifdef __ANDROID__
2234         // ELUAN: FIXME: separate this code
2235         char vabuf[1024];
2236         char vabuf2[1024];
2237         int strsize;
2238         KTX_dimensions sizes;
2239 #endif
2240
2241         if (cls.state == ca_dedicated)
2242                 return NULL;
2243
2244 #ifdef __ANDROID__
2245         // ELUAN: FIXME: separate this code
2246         if (vid.renderpath != RENDERPATH_GLES2)
2247         {
2248                 Con_DPrintf("KTX texture format is only supported on the GLES2 renderpath\n");
2249                 return NULL;
2250         }
2251
2252         // some textures are specified with extensions, so it becomes .tga.dds
2253         FS_StripExtension (filename, vabuf2, sizeof(vabuf2));
2254         FS_StripExtension (vabuf2, vabuf, sizeof(vabuf));
2255         FS_DefaultExtension (vabuf, ".ktx", sizeof(vabuf));
2256         strsize = strlen(vabuf);
2257         if (strsize > 5)
2258         for (i = 0; i <= strsize - 4; i++) // copy null termination
2259                 vabuf[i] = vabuf[i + 4];
2260
2261         Con_DPrintf("Loading %s...\n", vabuf);
2262         dds = FS_LoadFile(vabuf, tempmempool, true, &ddsfilesize);
2263         ddssize = ddsfilesize;
2264
2265         if (!dds)
2266         {
2267                 Con_DPrintf("Not found!\n");
2268                 return NULL; // not found
2269         }
2270         Con_DPrintf("Found!\n");
2271
2272         if (flags & TEXF_ALPHA)
2273         {
2274                 Con_DPrintf("KTX texture with alpha not supported yet, disabling\n");
2275                 flags &= ~TEXF_ALPHA;
2276         }
2277
2278         {
2279                 GLenum target;
2280                 GLenum glerror;
2281                 GLboolean isMipmapped;
2282                 KTX_error_code ktxerror;
2283
2284                 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2285
2286                 // texture uploading can take a while, so make sure we're sending keepalives
2287                 CL_KeepaliveMessage(false);
2288
2289                 // create the texture object
2290                 CHECKGLERROR
2291                 GL_ActiveTexture(0);
2292                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[GLTEXTURETYPE_2D]);
2293                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2294                 qglBindTexture(gltexturetypeenums[GLTEXTURETYPE_2D], glt->texnum);CHECKGLERROR
2295
2296                 // upload the texture
2297                 // we need to restore the texture binding after finishing the upload
2298
2299                 // NOTE: some drivers fail with ETC1 NPOT (only PowerVR?). This may make the driver crash later.
2300                 ktxerror = ktxLoadTextureM(dds, ddssize, &glt->texnum, &target, &sizes, &isMipmapped, &glerror,
2301                                                                 0, NULL);// can't CHECKGLERROR, the lib catches it
2302
2303                 // FIXME: delete texture if we fail here
2304                 if (target != GL_TEXTURE_2D)
2305                 {
2306                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2307                         Mem_Free(dds);
2308                         Con_DPrintf("%s target != GL_TEXTURE_2D, target == %x\n", vabuf, target);
2309                         return NULL; // FIXME: delete the texture from memory
2310                 }
2311
2312                 if (KTX_SUCCESS == ktxerror)
2313                 {
2314                         textype = TEXTYPE_ETC1;
2315                         flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2316
2317                         // return whether this texture is transparent
2318                         if (hasalphaflag)
2319                                 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2320
2321                         // TODO: apply gl_picmip
2322                         // TODO: avgcolor
2323                         // TODO: srgb
2324                         // TODO: only load mipmaps if requested
2325
2326                         if (isMipmapped)
2327                                 flags |= TEXF_MIPMAP;
2328                         else
2329                                 flags &= ~TEXF_MIPMAP;
2330
2331                         texinfo = R_GetTexTypeInfo(textype, flags);
2332
2333                         strlcpy (glt->identifier, vabuf, sizeof(glt->identifier));
2334                         glt->pool = pool;
2335                         glt->chain = pool->gltchain;
2336                         pool->gltchain = glt;
2337                         glt->inputwidth = sizes.width;
2338                         glt->inputheight = sizes.height;
2339                         glt->inputdepth = 1;
2340                         glt->flags = flags;
2341                         glt->textype = texinfo;
2342                         glt->texturetype = GLTEXTURETYPE_2D;
2343                         glt->inputdatasize = ddssize;
2344                         glt->glinternalformat = texinfo->glinternalformat;
2345                         glt->glformat = texinfo->glformat;
2346                         glt->gltype = texinfo->gltype;
2347                         glt->bytesperpixel = texinfo->internalbytesperpixel;
2348                         glt->sides = 1;
2349                         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2350                         glt->tilewidth = sizes.width;
2351                         glt->tileheight = sizes.height;
2352                         glt->tiledepth = 1;
2353                         glt->miplevels = isMipmapped ? 1 : 0; // FIXME
2354
2355                                 // after upload we have to set some parameters...
2356 #ifdef GL_TEXTURE_MAX_LEVEL
2357                         /* FIXME
2358                                 if (dds_miplevels >= 1 && !mipcomplete)
2359                                 {
2360                                         // need to set GL_TEXTURE_MAX_LEVEL
2361                                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2362                                 }
2363                         */
2364 #endif
2365                                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2366
2367                                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2368                                 Mem_Free(dds);
2369                                 return (rtexture_t *)glt;
2370                 }
2371                 else
2372                 {
2373                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2374                         Mem_Free(dds);
2375                         Con_DPrintf("KTX texture %s failed to load: %x\n", vabuf, ktxerror);
2376                         return NULL;
2377                 }
2378         }
2379 #endif // __ANDROID__
2380
2381         dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
2382         ddssize = ddsfilesize;
2383
2384         if (!dds)
2385         {
2386                 if (r_texture_dds_load_logfailure.integer && (r_texture_dds_load_logfailure.integer >= 2 || !optionaltexture))
2387                         Log_Printf("ddstexturefailures.log", "%s\n", filename);
2388                 return NULL; // not found
2389         }
2390
2391         if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
2392         {
2393                 Mem_Free(dds);
2394                 Con_Printf("^1%s: not a DDS image\n", filename);
2395                 return NULL;
2396         }
2397
2398         //dds_flags = BuffLittleLong(dds+8);
2399         dds_format_flags = BuffLittleLong(dds+80);
2400         dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
2401         dds_width = BuffLittleLong(dds+16);
2402         dds_height = BuffLittleLong(dds+12);
2403         ddspixels = dds + 128;
2404
2405         if(r_texture_dds_load_alphamode.integer == 0)
2406                 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
2407                         flags &= ~TEXF_ALPHA;
2408
2409         //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
2410         if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
2411         {
2412                 // very sloppy BGRA 32bit identification
2413                 textype = TEXTYPE_BGRA;
2414                 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2415                 bytesperblock = 0;
2416                 bytesperpixel = 4;
2417                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
2418                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2419                 {
2420                         Mem_Free(dds);
2421                         Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
2422                         return NULL;
2423                 }
2424                 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
2425                 {
2426                         // check alpha
2427                         for (i = 3;i < size;i += 4)
2428                                 if (ddspixels[i] < 255)
2429                                         break;
2430                         if (i >= size)
2431                                 flags &= ~TEXF_ALPHA;
2432                 }
2433         }
2434         else if (!memcmp(dds+84, "DXT1", 4))
2435         {
2436                 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
2437                 // LordHavoc: it is my belief that this does not infringe on the
2438                 // patent because it is not decoding pixels...
2439                 textype = TEXTYPE_DXT1;
2440                 bytesperblock = 8;
2441                 bytesperpixel = 0;
2442                 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
2443                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2444                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2445                 {
2446                         Mem_Free(dds);
2447                         Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
2448                         return NULL;
2449                 }
2450                 if (flags & TEXF_ALPHA)
2451                 {
2452                         if (r_texture_dds_load_alphamode.integer == 1)
2453                         {
2454                                 // check alpha
2455                                 for (i = 0;i < size;i += bytesperblock)
2456                                         if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
2457                                         {
2458                                                 // NOTE: this assumes sizeof(unsigned int) == 4
2459                                                 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
2460                                                 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
2461                                                 if(data & (data<<1) & 0xAAAAAAAA)//rgh
2462                                                         break;
2463                                         }
2464                                 if (i < size)
2465                                         textype = TEXTYPE_DXT1A;
2466                                 else
2467                                         flags &= ~TEXF_ALPHA;
2468                         }
2469                         else if (r_texture_dds_load_alphamode.integer == 0)
2470                                 textype = TEXTYPE_DXT1A;
2471                         else
2472                         {
2473                                 flags &= ~TEXF_ALPHA;
2474                         }
2475                 }
2476         }
2477         else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2478         {
2479                 if(!memcmp(dds+84, "DXT2", 4))
2480                 {
2481                         if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2482                         {
2483                                 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2484                         }
2485                 }
2486                 else
2487                 {
2488                         if(flags & TEXF_RGBMULTIPLYBYALPHA)
2489                         {
2490                                 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2491                         }
2492                 }
2493                 textype = TEXTYPE_DXT3;
2494                 bytesperblock = 16;
2495                 bytesperpixel = 0;
2496                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2497                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2498                 {
2499                         Mem_Free(dds);
2500                         Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2501                         return NULL;
2502                 }
2503                 // we currently always assume alpha
2504         }
2505         else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2506         {
2507                 if(!memcmp(dds+84, "DXT4", 4))
2508                 {
2509                         if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2510                         {
2511                                 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2512                         }
2513                 }
2514                 else
2515                 {
2516                         if(flags & TEXF_RGBMULTIPLYBYALPHA)
2517                         {
2518                                 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2519                         }
2520                 }
2521                 textype = TEXTYPE_DXT5;
2522                 bytesperblock = 16;
2523                 bytesperpixel = 0;
2524                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2525                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2526                 {
2527                         Mem_Free(dds);
2528                         Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2529                         return NULL;
2530                 }
2531                 // we currently always assume alpha
2532         }
2533         else
2534         {
2535                 Mem_Free(dds);
2536                 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2537                 return NULL;
2538         }
2539
2540         // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
2541         if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
2542         {
2543                 textype = TEXTYPE_DXT1;
2544                 bytesperblock = 8;
2545                 ddssize -= 128;
2546                 ddssize /= 2;
2547                 for (i = 0;i < (int)ddssize;i += bytesperblock)
2548                         memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
2549                 ddssize += 128;
2550         }
2551
2552         force_swdecode = false;
2553         npothack = 
2554                 (!vid.support.arb_texture_non_power_of_two &&
2555                         (
2556                                 (dds_width & (dds_width - 1))
2557                                 ||
2558                                 (dds_height & (dds_height - 1))
2559                         )
2560                 );
2561         if(bytesperblock)
2562         {
2563                 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && !npothack)
2564                 {
2565                         if(r_texture_dds_swdecode.integer > 1)
2566                                 force_swdecode = true;
2567                 }
2568                 else
2569                 {
2570                         if(r_texture_dds_swdecode.integer < 1)
2571                         {
2572                                 // unsupported
2573                                 Mem_Free(dds);
2574                                 return NULL;
2575                         }
2576                         force_swdecode = true;
2577                 }
2578         }
2579
2580         // return whether this texture is transparent
2581         if (hasalphaflag)
2582                 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2583
2584         // if we SW decode, choose 2 sizes bigger
2585         if(force_swdecode)
2586         {
2587                 // this is quarter res, so do not scale down more than we have to
2588                 miplevel -= 2;
2589
2590                 if(miplevel < 0)
2591                         Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2592         }
2593
2594         // this is where we apply gl_picmip
2595         mippixels_start = ddspixels;
2596         mipwidth = dds_width;
2597         mipheight = dds_height;
2598         while(miplevel >= 1 && dds_miplevels >= 1)
2599         {
2600                 if (mipwidth <= 1 && mipheight <= 1)
2601                         break;
2602                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2603                 mippixels_start += mipsize; // just skip
2604                 --dds_miplevels;
2605                 --miplevel;
2606                 if (mipwidth > 1)
2607                         mipwidth >>= 1;
2608                 if (mipheight > 1)
2609                         mipheight >>= 1;
2610         }
2611         mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2612         mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2613
2614         // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2615
2616         // fake decode S3TC if needed
2617         if(force_swdecode)
2618         {
2619                 int mipsize_new = mipsize_total / bytesperblock * 4;
2620                 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2621                 unsigned char *p = mipnewpixels;
2622                 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2623                 {
2624                         c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2625                         p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2626                         p[1] = (((c >>  5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2627                         p[0] = (((c      ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2628                         if(textype == TEXTYPE_DXT5)
2629                                 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2630                         else if(textype == TEXTYPE_DXT3)
2631                                 p[3] = (
2632                                           (mippixels_start[i-8] & 0x0F)
2633                                         + (mippixels_start[i-8] >> 4)
2634                                         + (mippixels_start[i-7] & 0x0F)
2635                                         + (mippixels_start[i-7] >> 4)
2636                                         + (mippixels_start[i-6] & 0x0F)
2637                                         + (mippixels_start[i-6] >> 4)
2638                                         + (mippixels_start[i-5] & 0x0F)
2639                                         + (mippixels_start[i-5] >> 4)
2640                                        ) * (0.125f / 15.0f * 255.0f);
2641                         else
2642                                 p[3] = 255;
2643                 }
2644
2645                 textype = TEXTYPE_BGRA;
2646                 bytesperblock = 0;
2647                 bytesperpixel = 4;
2648
2649                 // as each block becomes a pixel, we must use pixel count for this
2650                 mipwidth = (mipwidth + 3) / 4;
2651                 mipheight = (mipheight + 3) / 4;
2652                 mipsize = bytesperpixel * mipwidth * mipheight;
2653                 mippixels_start = mipnewpixels;
2654                 mipsize_total = mipsize_new;
2655         }
2656
2657         // start mip counting
2658         mippixels = mippixels_start;
2659
2660         // calculate average color if requested
2661         if (avgcolor)
2662         {
2663                 float f;
2664                 Vector4Clear(avgcolor);
2665                 if (bytesperblock)
2666                 {
2667                         for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2668                         {
2669                                 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2670                                 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2671                                 avgcolor[1] += ((c >>  5) & 0x3F) + ((c >> 21) & 0x3F);
2672                                 avgcolor[2] += ((c      ) & 0x1F) + ((c >> 16) & 0x1F);
2673                                 if(textype == TEXTYPE_DXT5)
2674                                         avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f);
2675                                 else if(textype == TEXTYPE_DXT3)
2676                                         avgcolor[3] += (
2677                                                   (mippixels_start[i-8] & 0x0F)
2678                                                 + (mippixels_start[i-8] >> 4)
2679                                                 + (mippixels_start[i-7] & 0x0F)
2680                                                 + (mippixels_start[i-7] >> 4)
2681                                                 + (mippixels_start[i-6] & 0x0F)
2682                                                 + (mippixels_start[i-6] >> 4)
2683                                                 + (mippixels_start[i-5] & 0x0F)
2684                                                 + (mippixels_start[i-5] >> 4)
2685                                                ) * (0.125f / 15.0f);
2686                                 else
2687                                         avgcolor[3] += 1.0f;
2688                         }
2689                         f = (float)bytesperblock / mipsize;
2690                         avgcolor[0] *= (0.5f / 31.0f) * f;
2691                         avgcolor[1] *= (0.5f / 63.0f) * f;
2692                         avgcolor[2] *= (0.5f / 31.0f) * f;
2693                         avgcolor[3] *= f;
2694                 }
2695                 else
2696                 {
2697                         for (i = 0;i < mipsize;i += 4)
2698                         {
2699                                 avgcolor[0] += mippixels[i+2];
2700                                 avgcolor[1] += mippixels[i+1];
2701                                 avgcolor[2] += mippixels[i];
2702                                 avgcolor[3] += mippixels[i+3];
2703                         }
2704                         f = (1.0f / 255.0f) * bytesperpixel / mipsize;
2705                         avgcolor[0] *= f;
2706                         avgcolor[1] *= f;
2707                         avgcolor[2] *= f;
2708                         avgcolor[3] *= f;
2709                 }
2710         }
2711
2712         // if we want sRGB, convert now
2713         if(srgb)
2714         {
2715                 if (vid.support.ext_texture_srgb)
2716                 {
2717                         switch(textype)
2718                         {
2719                         case TEXTYPE_DXT1:    textype = TEXTYPE_SRGB_DXT1   ;break;
2720                         case TEXTYPE_DXT1A:   textype = TEXTYPE_SRGB_DXT1A  ;break;
2721                         case TEXTYPE_DXT3:    textype = TEXTYPE_SRGB_DXT3   ;break;
2722                         case TEXTYPE_DXT5:    textype = TEXTYPE_SRGB_DXT5   ;break;
2723                         case TEXTYPE_RGBA:    textype = TEXTYPE_SRGB_RGBA   ;break;
2724                         default:
2725                                 break;
2726                         }
2727                 }
2728                 else
2729                 {
2730                         switch(textype)
2731                         {
2732                         case TEXTYPE_DXT1:
2733                         case TEXTYPE_DXT1A:
2734                         case TEXTYPE_DXT3:
2735                         case TEXTYPE_DXT5:
2736                                 {
2737                                         for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2738                                         {
2739                                                 int c0, c1, c0new, c1new;
2740                                                 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2741                                                 r = ((c0 >> 11) & 0x1F);
2742                                                 g = ((c0 >>  5) & 0x3F);
2743                                                 b = ((c0      ) & 0x1F);
2744                                                 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2745                                                 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2746                                                 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2747                                                 c0new = (r << 11) | (g << 5) | b;
2748                                                 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2749                                                 r = ((c1 >> 11) & 0x1F);
2750                                                 g = ((c1 >>  5) & 0x3F);
2751                                                 b = ((c1      ) & 0x1F);
2752                                                 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2753                                                 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2754                                                 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2755                                                 c1new = (r << 11) | (g << 5) | b;
2756                                                 // swap the colors if needed to fix order
2757                                                 if(c0 > c1) // thirds
2758                                                 {
2759                                                         if(c0new < c1new)
2760                                                         {
2761                                                                 c = c0new;
2762                                                                 c0new = c1new;
2763                                                                 c1new = c;
2764                                                                 if(c0new == c1new)
2765                                                                 mippixels_start[i+4] ^= 0x55;
2766                                                                 mippixels_start[i+5] ^= 0x55;
2767                                                                 mippixels_start[i+6] ^= 0x55;
2768                                                                 mippixels_start[i+7] ^= 0x55;
2769                                                         }
2770                                                         else if(c0new == c1new)
2771                                                         {
2772                                                                 mippixels_start[i+4] = 0x00;
2773                                                                 mippixels_start[i+5] = 0x00;
2774                                                                 mippixels_start[i+6] = 0x00;
2775                                                                 mippixels_start[i+7] = 0x00;
2776                                                         }
2777                                                 }
2778                                                 else // half + transparent
2779                                                 {
2780                                                         if(c0new > c1new)
2781                                                         {
2782                                                                 c = c0new;
2783                                                                 c0new = c1new;
2784                                                                 c1new = c;
2785                                                                 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2786                                                                 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2787                                                                 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2788                                                                 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2789                                                         }
2790                                                 }
2791                                                 mippixels_start[i] = c0new & 255;
2792                                                 mippixels_start[i+1] = c0new >> 8;
2793                                                 mippixels_start[i+2] = c1new & 255;
2794                                                 mippixels_start[i+3] = c1new >> 8;
2795                                         }
2796                                 }
2797                                 break;
2798                         case TEXTYPE_RGBA:
2799                                 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2800                                 break;
2801                         default:
2802                                 break;
2803                         }
2804                 }
2805         }
2806
2807         // when not requesting mipmaps, do not load them
2808         if(!(flags & TEXF_MIPMAP))
2809                 dds_miplevels = 0;
2810
2811         if (dds_miplevels >= 1)
2812                 flags |= TEXF_MIPMAP;
2813         else
2814                 flags &= ~TEXF_MIPMAP;
2815
2816         texinfo = R_GetTexTypeInfo(textype, flags);
2817
2818         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2819         strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2820         glt->pool = pool;
2821         glt->chain = pool->gltchain;
2822         pool->gltchain = glt;
2823         glt->inputwidth = mipwidth;
2824         glt->inputheight = mipheight;
2825         glt->inputdepth = 1;
2826         glt->flags = flags;
2827         glt->textype = texinfo;
2828         glt->texturetype = GLTEXTURETYPE_2D;
2829         glt->inputdatasize = ddssize;
2830         glt->glinternalformat = texinfo->glinternalformat;
2831         glt->glformat = texinfo->glformat;
2832         glt->gltype = texinfo->gltype;
2833         glt->bytesperpixel = texinfo->internalbytesperpixel;
2834         glt->sides = 1;
2835         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2836         glt->tilewidth = mipwidth;
2837         glt->tileheight = mipheight;
2838         glt->tiledepth = 1;
2839         glt->miplevels = dds_miplevels;
2840
2841         if(npothack)
2842         {
2843                 for (glt->tilewidth = 1;glt->tilewidth < mipwidth;glt->tilewidth <<= 1);
2844                 for (glt->tileheight = 1;glt->tileheight < mipheight;glt->tileheight <<= 1);
2845         }
2846
2847         // texture uploading can take a while, so make sure we're sending keepalives
2848         CL_KeepaliveMessage(false);
2849
2850         // create the texture object
2851         switch(vid.renderpath)
2852         {
2853         case RENDERPATH_GL11:
2854         case RENDERPATH_GL13:
2855         case RENDERPATH_GL20:
2856         case RENDERPATH_GLES1:
2857         case RENDERPATH_GLES2:
2858                 CHECKGLERROR
2859                 GL_ActiveTexture(0);
2860                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2861                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2862                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2863                 break;
2864         case RENDERPATH_D3D9:
2865 #ifdef SUPPORTD3D
2866                 {
2867                         D3DFORMAT d3dformat;
2868                         D3DPOOL d3dpool;
2869                         DWORD d3dusage;
2870                         switch(textype)
2871                         {
2872                         case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2873                         case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2874                         case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2875                         case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2876                         default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2877                         }
2878                         d3dusage = 0;
2879                         d3dpool = D3DPOOL_MANAGED;
2880                         IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2881                 }
2882 #endif
2883                 break;
2884         case RENDERPATH_D3D10:
2885                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2886                 break;
2887         case RENDERPATH_D3D11:
2888                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2889                 break;
2890         case RENDERPATH_SOFT:
2891                 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);
2892                 break;
2893         }
2894
2895         // upload the texture
2896         // we need to restore the texture binding after finishing the upload
2897         mipcomplete = false;
2898
2899         for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2900         {
2901                 unsigned char *upload_mippixels = mippixels;
2902                 int upload_mipwidth = mipwidth;
2903                 int upload_mipheight = mipheight;
2904                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2905                 if (mippixels + mipsize > mippixels_start + mipsize_total)
2906                         break;
2907                 if(npothack)
2908                 {
2909                         upload_mipwidth = (glt->tilewidth >> mip);
2910                         upload_mipheight = (glt->tileheight >> mip);
2911                         if(upload_mipwidth != mipwidth || upload_mipheight != mipheight)
2912                         // I _think_ they always mismatch, but I was too lazy
2913                         // to properly check, and this test here is really
2914                         // harmless
2915                         {
2916                                 upload_mippixels = (unsigned char *) Mem_Alloc(tempmempool, 4 * upload_mipwidth * upload_mipheight);
2917                                 Image_Resample32(mippixels, mipwidth, mipheight, 1, upload_mippixels, upload_mipwidth, upload_mipheight, 1, r_lerpimages.integer);
2918                         }
2919                 }
2920                 switch(vid.renderpath)
2921                 {
2922                 case RENDERPATH_GL11:
2923                 case RENDERPATH_GL13:
2924                 case RENDERPATH_GL20:
2925                 case RENDERPATH_GLES1:
2926                 case RENDERPATH_GLES2:
2927                         if (bytesperblock)
2928                         {
2929                                 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR
2930                         }
2931                         else
2932                         {
2933                                 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR
2934                         }
2935                         break;
2936                 case RENDERPATH_D3D9:
2937 #ifdef SUPPORTD3D
2938                         {
2939                                 D3DLOCKED_RECT d3dlockedrect;
2940                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2941                                 {
2942                                         memcpy(d3dlockedrect.pBits, upload_mippixels, mipsize);
2943                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2944                                 }
2945                                 break;
2946                         }
2947 #endif
2948                         break;
2949                 case RENDERPATH_D3D10:
2950                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2951                         break;
2952                 case RENDERPATH_D3D11:
2953                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2954                         break;
2955                 case RENDERPATH_SOFT:
2956                         if (bytesperblock)
2957                                 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2958                         else
2959                                 DPSOFTRAST_Texture_UpdateFull(glt->texnum, upload_mippixels);
2960                         // DPSOFTRAST calculates its own mipmaps
2961                         mip = dds_miplevels;
2962                         break;
2963                 }
2964                 if(upload_mippixels != mippixels)
2965                         Mem_Free(upload_mippixels);
2966                 mippixels += mipsize;
2967                 if (mipwidth <= 1 && mipheight <= 1)
2968                 {
2969                         mipcomplete = true;
2970                         break;
2971                 }
2972                 if (mipwidth > 1)
2973                         mipwidth >>= 1;
2974                 if (mipheight > 1)
2975                         mipheight >>= 1;
2976         }
2977
2978         // after upload we have to set some parameters...
2979         switch(vid.renderpath)
2980         {
2981         case RENDERPATH_GL11:
2982         case RENDERPATH_GL13:
2983         case RENDERPATH_GL20:
2984         case RENDERPATH_GLES1:
2985         case RENDERPATH_GLES2:
2986 #ifdef GL_TEXTURE_MAX_LEVEL
2987                 if (dds_miplevels >= 1 && !mipcomplete)
2988                 {
2989                         // need to set GL_TEXTURE_MAX_LEVEL
2990                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2991                 }
2992 #endif
2993                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2994                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2995                 break;
2996         case RENDERPATH_D3D9:
2997 #ifdef SUPPORTD3D
2998                 glt->d3daddressw = 0;
2999                 if (glt->flags & TEXF_CLAMP)
3000                 {
3001                         glt->d3daddressu = D3DTADDRESS_CLAMP;
3002                         glt->d3daddressv = D3DTADDRESS_CLAMP;
3003                         if (glt->tiledepth > 1)
3004                                 glt->d3daddressw = D3DTADDRESS_CLAMP;
3005                 }
3006                 else
3007                 {
3008                         glt->d3daddressu = D3DTADDRESS_WRAP;
3009                         glt->d3daddressv = D3DTADDRESS_WRAP;
3010                         if (glt->tiledepth > 1)
3011                                 glt->d3daddressw = D3DTADDRESS_WRAP;
3012                 }
3013                 glt->d3dmipmaplodbias = 0;
3014                 glt->d3dmaxmiplevel = 0;
3015                 glt->d3dmaxmiplevelfilter = 0;
3016                 if (glt->flags & TEXF_MIPMAP)
3017                 {
3018                         glt->d3dminfilter = d3d_filter_mipmin;
3019                         glt->d3dmagfilter = d3d_filter_mipmag;
3020                         glt->d3dmipfilter = d3d_filter_mipmix;
3021                 }
3022                 else
3023                 {
3024                         glt->d3dminfilter = d3d_filter_flatmin;
3025                         glt->d3dmagfilter = d3d_filter_flatmag;
3026                         glt->d3dmipfilter = d3d_filter_flatmix;
3027                 }
3028 #endif
3029                 break;
3030         case RENDERPATH_D3D10:
3031                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3032                 break;
3033         case RENDERPATH_D3D11:
3034                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3035                 break;
3036         case RENDERPATH_SOFT:
3037                 if (glt->flags & TEXF_FORCELINEAR)
3038                         DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
3039                 else if (glt->flags & TEXF_FORCENEAREST)
3040                         DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
3041                 else if (glt->flags & TEXF_MIPMAP)
3042                         DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
3043                 else
3044                         DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
3045                 break;
3046         }
3047
3048         Mem_Free(dds);
3049         if(force_swdecode)
3050                 Mem_Free((unsigned char *) mippixels_start);
3051         return (rtexture_t *)glt;
3052 }
3053
3054 int R_TextureWidth(rtexture_t *rt)
3055 {
3056         return rt ? ((gltexture_t *)rt)->inputwidth : 0;
3057 }
3058
3059 int R_TextureHeight(rtexture_t *rt)
3060 {
3061         return rt ? ((gltexture_t *)rt)->inputheight : 0;
3062 }
3063
3064 int R_TextureFlags(rtexture_t *rt)
3065 {
3066         return rt ? ((gltexture_t *)rt)->flags : 0;
3067 }
3068
3069 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
3070 {
3071         gltexture_t *glt = (gltexture_t *)rt;
3072         if (data == NULL)
3073                 Host_Error("R_UpdateTexture: no data supplied");
3074         if (glt == NULL)
3075                 Host_Error("R_UpdateTexture: no texture supplied");
3076         if (!glt->texnum && !glt->d3dtexture)
3077         {
3078                 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
3079                 return;
3080         }
3081         // update part of the texture
3082         if (glt->bufferpixels)
3083         {
3084                 int j;
3085                 int bpp = glt->bytesperpixel;
3086                 int inputskip = width*bpp;
3087                 int outputskip = glt->tilewidth*bpp;
3088                 const unsigned char *input = data;
3089                 unsigned char *output = glt->bufferpixels;
3090                 if (glt->inputdepth != 1 || glt->sides != 1)
3091                         Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
3092                 if (x < 0)
3093                 {
3094                         width += x;
3095                         input -= x*bpp;
3096                         x = 0;
3097                 }
3098                 if (y < 0)
3099                 {
3100                         height += y;
3101                         input -= y*inputskip;
3102                         y = 0;
3103                 }
3104                 if (width > glt->tilewidth - x)
3105                         width = glt->tilewidth - x;
3106                 if (height > glt->tileheight - y)
3107                         height = glt->tileheight - y;
3108                 if (width < 1 || height < 1)
3109                         return;
3110                 glt->dirty = true;
3111                 glt->buffermodified = true;
3112                 output += y*outputskip + x*bpp;
3113                 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
3114                         memcpy(output, input, width*bpp);
3115         }
3116         else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
3117                 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
3118         else
3119                 R_UploadFullTexture(glt, data);
3120 }
3121
3122 int R_RealGetTexture(rtexture_t *rt)
3123 {
3124         if (rt)
3125         {
3126                 gltexture_t *glt;
3127                 glt = (gltexture_t *)rt;
3128                 if (glt->flags & GLTEXF_DYNAMIC)
3129                         R_UpdateDynamicTexture(glt);
3130                 if (glt->buffermodified && glt->bufferpixels)
3131                 {
3132                         glt->buffermodified = false;
3133                         R_UploadFullTexture(glt, glt->bufferpixels);
3134                 }
3135                 glt->dirty = false;
3136                 return glt->texnum;
3137         }
3138         else
3139                 return 0;
3140 }
3141
3142 void R_ClearTexture (rtexture_t *rt)
3143 {
3144         gltexture_t *glt = (gltexture_t *)rt;
3145
3146         R_UploadFullTexture(glt, NULL);
3147 }
3148
3149 int R_PicmipForFlags(int flags)
3150 {
3151         int miplevel = 0;
3152         if(flags & TEXF_PICMIP)
3153         {
3154                 miplevel += gl_picmip.integer;
3155                 if (flags & TEXF_ISWORLD)
3156                 {
3157                         if (r_picmipworld.integer)
3158                                 miplevel += gl_picmip_world.integer;
3159                         else
3160                                 miplevel = 0;
3161                 }
3162                 else if (flags & TEXF_ISSPRITE)
3163                 {
3164                         if (r_picmipsprites.integer)
3165                                 miplevel += gl_picmip_sprites.integer;
3166                         else
3167                                 miplevel = 0;
3168                 }
3169                 else
3170                         miplevel += gl_picmip_other.integer;
3171         }
3172         return max(0, miplevel);
3173 }