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