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