5 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
10 #include "intoverflow.h"
11 #include "dpsoftrast.h"
14 #define GL_TEXTURE_3D 0x806F
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"};
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;
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;
61 static mempool_t *texturemempool;
62 static memexpandablearray_t texturearray;
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
70 typedef struct textypeinfo_s
74 int inputbytesperpixel;
75 int internalbytesperpixel;
76 float glinternalbytesperpixel;
84 // framebuffer texture formats
85 // GLES2 devices rarely support depth textures, so we actually use a renderbuffer there
86 static textypeinfo_t textype_shadowmap16 = {"shadowmap16", TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
87 static textypeinfo_t textype_shadowmap24 = {"shadowmap24", TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
88 static textypeinfo_t textype_shadowmap24s8 = {"shadowmap24", TEXTYPE_SHADOWMAP_STENCIL, 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
89 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
90 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F, 8, 8, 8.0f, GL_RGBA , GL_RGBA , GL_FLOAT };
91 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F, 16, 16, 16.0f, GL_RGBA , GL_RGBA , GL_FLOAT };
94 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
95 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
96 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
97 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
98 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
99 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
100 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
102 // framebuffer texture formats
103 static textypeinfo_t textype_shadowmap16 = {"shadowmap16", TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
104 static textypeinfo_t textype_shadowmap24 = {"shadowmap24", TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
105 static textypeinfo_t textype_shadowmap24s8 = {"shadowmap24", TEXTYPE_SHADOWMAP_STENCIL, 4, 4, 4.0f, GL_DEPTH24_STENCIL8_EXT , GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT};
106 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
107 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F, 8, 8, 8.0f, GL_RGBA16F_ARB , GL_RGBA , GL_FLOAT };
108 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F, 16, 16, 16.0f, GL_RGBA32F_ARB , GL_RGBA , GL_FLOAT };
111 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
112 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
113 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
114 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE };
115 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
116 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 };
117 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 };
118 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
119 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
120 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 };
121 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 };
122 static textypeinfo_t textype_dxt1 = {"dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
123 static textypeinfo_t textype_dxt1a = {"dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 };
124 static textypeinfo_t textype_dxt3 = {"dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 };
125 static textypeinfo_t textype_dxt5 = {"dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 };
126 static textypeinfo_t textype_sRGB_palette = {"sRGB_palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
127 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 };
128 static textypeinfo_t textype_sRGB_rgba = {"sRGB_rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
129 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 };
130 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 };
131 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 };
132 static textypeinfo_t textype_sRGB_bgra = {"sRGB_bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
133 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 };
134 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 };
135 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 };
136 static textypeinfo_t textype_sRGB_dxt1 = {"sRGB_dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , 0 , 0 };
137 static textypeinfo_t textype_sRGB_dxt1a = {"sRGB_dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 , 0 };
138 static textypeinfo_t textype_sRGB_dxt3 = {"sRGB_dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 , 0 };
139 static textypeinfo_t textype_sRGB_dxt5 = {"sRGB_dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 , 0 };
142 typedef enum gltexturetype_e
146 GLTEXTURETYPE_CUBEMAP,
151 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP};
152 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
153 static int cubemapside[6] =
155 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
156 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
157 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
158 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
159 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
160 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
163 typedef struct gltexture_s
165 // this portion of the struct is exposed to the R_GetTexture macro for
166 // speed reasons, must be identical in rtexture_t!
167 int texnum; // GL texture slot number
168 qboolean dirty; // indicates that R_RealGetTexture should be called
169 int gltexturetypeenum; // used by R_Mesh_TexBind
170 // d3d stuff the backend needs
173 qboolean d3disdepthsurface; // for depth/stencil surfaces
183 int d3dmaxmiplevelfilter;
184 int d3dmipmaplodbias;
188 // dynamic texture stuff [11/22/2007 Black]
189 updatecallback_t updatecallback;
190 void *updatacallback_data;
191 // --- [11/22/2007 Black]
193 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
194 unsigned char *bufferpixels;
195 qboolean buffermodified;
197 // pointer to texturepool (check this to see if the texture is allocated)
198 struct gltexturepool_s *pool;
199 // pointer to next texture in texturepool chain
200 struct gltexture_s *chain;
201 // name of the texture (this might be removed someday), no duplicates
202 char identifier[MAX_QPATH + 32];
203 // original data size in *inputtexels
204 int inputwidth, inputheight, inputdepth;
205 // copy of the original texture(s) supplied to the upload function, for
206 // delayed uploads (non-precached)
207 unsigned char *inputtexels;
208 // original data size in *inputtexels
210 // flags supplied to the LoadTexture function
211 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
215 // pointer to one of the textype_ structs
216 textypeinfo_t *textype;
217 // one of the GLTEXTURETYPE_ values
219 // palette if the texture is TEXTYPE_PALETTE
220 const unsigned int *palette;
221 // actual stored texture size after gl_picmip and gl_max_size are applied
222 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
223 int tilewidth, tileheight, tiledepth;
224 // 1 or 6 depending on texturetype
226 // how many mipmap levels in this texture
230 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
233 int glinternalformat;
234 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
239 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
241 typedef struct gltexturepool_s
243 unsigned int sentinel;
244 struct gltexture_s *gltchain;
245 struct gltexturepool_s *next;
249 static gltexturepool_t *gltexturepoolchain = NULL;
251 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
252 static int resizebuffersize = 0;
253 static const unsigned char *texturebuffer;
255 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
260 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
261 case TEXTYPE_RGBA: return ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba);
262 case TEXTYPE_BGRA: return ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra);
263 case TEXTYPE_ALPHA: return &textype_alpha;
264 case TEXTYPE_SHADOWMAP: return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
265 case TEXTYPE_SHADOWMAP_STENCIL: return &textype_shadowmap24s8;
266 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
267 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
268 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
270 Host_Error("R_GetTexTypeInfo: unknown texture format");
276 case TEXTYPE_DXT1: return &textype_dxt1;
277 case TEXTYPE_DXT1A: return &textype_dxt1a;
278 case TEXTYPE_DXT3: return &textype_dxt3;
279 case TEXTYPE_DXT5: return &textype_dxt5;
280 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
281 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);
282 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);
283 case TEXTYPE_ALPHA: return &textype_alpha;
284 case TEXTYPE_SHADOWMAP: return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
285 case TEXTYPE_SHADOWMAP_STENCIL: return &textype_shadowmap24s8;
286 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
287 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
288 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
289 case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1;
290 case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a;
291 case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
292 case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
293 case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
294 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);
295 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);
297 Host_Error("R_GetTexTypeInfo: unknown texture format");
304 // dynamic texture code [11/22/2007 Black]
305 void R_MarkDirtyTexture(rtexture_t *rt) {
306 gltexture_t *glt = (gltexture_t*) rt;
311 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
312 if (glt->flags & GLTEXF_DYNAMIC)
314 // mark it as dirty, so R_RealGetTexture gets called
319 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
320 gltexture_t *glt = (gltexture_t*) rt;
325 glt->flags |= GLTEXF_DYNAMIC;
326 glt->updatecallback = updatecallback;
327 glt->updatacallback_data = data;
330 static void R_UpdateDynamicTexture(gltexture_t *glt) {
332 if( glt->updatecallback ) {
333 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
337 void R_PurgeTexture(rtexture_t *rt)
339 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
344 void R_FreeTexture(rtexture_t *rt)
346 gltexture_t *glt, **gltpointer;
348 glt = (gltexture_t *)rt;
350 Host_Error("R_FreeTexture: texture == NULL");
352 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
353 if (*gltpointer == glt)
354 *gltpointer = glt->chain;
356 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
358 R_Mesh_ClearBindingsForTexture(glt->texnum);
360 switch(vid.renderpath)
362 case RENDERPATH_GL11:
363 case RENDERPATH_GL13:
364 case RENDERPATH_GL20:
365 case RENDERPATH_GLES1:
366 case RENDERPATH_GLES2:
370 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
373 case RENDERPATH_D3D9:
375 if (glt->d3disdepthsurface)
376 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
377 else if (glt->tiledepth > 1)
378 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
379 else if (glt->sides == 6)
380 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
382 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
383 glt->d3dtexture = NULL;
386 case RENDERPATH_D3D10:
387 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
389 case RENDERPATH_D3D11:
390 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
392 case RENDERPATH_SOFT:
394 DPSOFTRAST_Texture_Free(glt->texnum);
398 if (glt->inputtexels)
399 Mem_Free(glt->inputtexels);
400 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
403 rtexturepool_t *R_AllocTexturePool(void)
405 gltexturepool_t *pool;
406 if (texturemempool == NULL)
408 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
411 pool->next = gltexturepoolchain;
412 gltexturepoolchain = pool;
413 pool->sentinel = TEXTUREPOOL_SENTINEL;
414 return (rtexturepool_t *)pool;
417 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
419 gltexturepool_t *pool, **poolpointer;
420 if (rtexturepool == NULL)
422 if (*rtexturepool == NULL)
424 pool = (gltexturepool_t *)(*rtexturepool);
425 *rtexturepool = NULL;
426 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
427 Host_Error("R_FreeTexturePool: pool already freed");
428 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
429 if (*poolpointer == pool)
430 *poolpointer = pool->next;
432 Host_Error("R_FreeTexturePool: pool not linked");
433 while (pool->gltchain)
434 R_FreeTexture((rtexture_t *)pool->gltchain);
439 typedef struct glmode_s
442 int minification, magnification;
443 DPSOFTRAST_TEXTURE_FILTER dpsoftrastfilter_mipmap, dpsoftrastfilter_nomipmap;
447 static glmode_t modes[6] =
449 {"GL_NEAREST", GL_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
450 {"GL_LINEAR", GL_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
451 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
452 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
453 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
454 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR}
458 typedef struct d3dmode_s
465 static d3dmode_t d3dmodes[6] =
467 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
468 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
469 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
470 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
471 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
472 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
476 static void GL_TextureMode_f (void)
481 gltexturepool_t *pool;
485 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
486 for (i = 0;i < 6;i++)
488 if (gl_filter_min == modes[i].minification)
490 Con_Printf("%s\n", modes[i].name);
494 Con_Print("current filter is unknown???\n");
498 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
499 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
503 Con_Print("bad filter name\n");
507 gl_filter_min = modes[i].minification;
508 gl_filter_mag = modes[i].magnification;
509 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
511 dpsoftrast_filter_mipmap = modes[i].dpsoftrastfilter_mipmap;
512 dpsoftrast_filter_nomipmap = modes[i].dpsoftrastfilter_nomipmap;
514 switch(vid.renderpath)
516 case RENDERPATH_GL11:
517 case RENDERPATH_GL13:
518 case RENDERPATH_GL20:
519 case RENDERPATH_GLES1:
520 case RENDERPATH_GLES2:
521 // change all the existing mipmap texture objects
522 // FIXME: force renderer(/client/something?) restart instead?
525 for (pool = gltexturepoolchain;pool;pool = pool->next)
527 for (glt = pool->gltchain;glt;glt = glt->chain)
529 // only update already uploaded images
530 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
532 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
533 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
534 if (glt->flags & TEXF_MIPMAP)
536 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
540 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
542 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
543 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
548 case RENDERPATH_D3D9:
550 d3d_filter_flatmin = d3dmodes[i].m1;
551 d3d_filter_flatmag = d3dmodes[i].m1;
552 d3d_filter_flatmix = D3DTEXF_POINT;
553 d3d_filter_mipmin = d3dmodes[i].m1;
554 d3d_filter_mipmag = d3dmodes[i].m1;
555 d3d_filter_mipmix = d3dmodes[i].m2;
556 d3d_filter_nomip = i < 2;
557 if (gl_texture_anisotropy.integer > 1 && i == 5)
558 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
559 for (pool = gltexturepoolchain;pool;pool = pool->next)
561 for (glt = pool->gltchain;glt;glt = glt->chain)
563 // only update already uploaded images
564 if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
566 if (glt->flags & TEXF_MIPMAP)
568 glt->d3dminfilter = d3d_filter_mipmin;
569 glt->d3dmagfilter = d3d_filter_mipmag;
570 glt->d3dmipfilter = d3d_filter_mipmix;
571 glt->d3dmaxmiplevelfilter = 0;
575 glt->d3dminfilter = d3d_filter_flatmin;
576 glt->d3dmagfilter = d3d_filter_flatmag;
577 glt->d3dmipfilter = d3d_filter_flatmix;
578 glt->d3dmaxmiplevelfilter = 0;
585 case RENDERPATH_D3D10:
586 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
588 case RENDERPATH_D3D11:
589 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
591 case RENDERPATH_SOFT:
592 // change all the existing texture objects
593 for (pool = gltexturepoolchain;pool;pool = pool->next)
594 for (glt = pool->gltchain;glt;glt = glt->chain)
595 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
596 DPSOFTRAST_Texture_Filter(glt->texnum, (glt->flags & TEXF_MIPMAP) ? dpsoftrast_filter_mipmap : dpsoftrast_filter_nomipmap);
601 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)
603 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
608 case GLTEXTURETYPE_2D:
609 maxsize = vid.maxtexturesize_2d;
610 if (flags & TEXF_PICMIP)
612 maxsize = bound(1, gl_max_size.integer, maxsize);
616 case GLTEXTURETYPE_3D:
617 maxsize = vid.maxtexturesize_3d;
619 case GLTEXTURETYPE_CUBEMAP:
620 maxsize = vid.maxtexturesize_cubemap;
624 if (vid.support.arb_texture_non_power_of_two)
626 width2 = min(inwidth >> picmip, maxsize);
627 height2 = min(inheight >> picmip, maxsize);
628 depth2 = min(indepth >> picmip, maxsize);
632 for (width2 = 1;width2 < inwidth;width2 <<= 1);
633 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
634 for (height2 = 1;height2 < inheight;height2 <<= 1);
635 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
636 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
637 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
640 switch(vid.renderpath)
642 case RENDERPATH_GL11:
643 case RENDERPATH_GL13:
644 case RENDERPATH_GL20:
645 case RENDERPATH_D3D10:
646 case RENDERPATH_D3D11:
647 case RENDERPATH_SOFT:
648 case RENDERPATH_GLES1:
649 case RENDERPATH_GLES2:
651 case RENDERPATH_D3D9:
653 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
654 if (texturetype == GLTEXTURETYPE_2D)
656 width2 = max(width2, 2);
657 height2 = max(height2, 2);
664 if (flags & TEXF_MIPMAP)
666 int extent = max(width2, max(height2, depth2));
672 *outwidth = max(1, width2);
674 *outheight = max(1, height2);
676 *outdepth = max(1, depth2);
678 *outmiplevels = miplevels;
682 static int R_CalcTexelDataSize (gltexture_t *glt)
684 int width2, height2, depth2, size;
686 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
688 size = width2 * height2 * depth2;
690 if (glt->flags & TEXF_MIPMAP)
692 while (width2 > 1 || height2 > 1 || depth2 > 1)
700 size += width2 * height2 * depth2;
704 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
707 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
711 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
712 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
714 gltexturepool_t *pool;
716 Con_Print("glsize input loaded mip alpha name\n");
717 for (pool = gltexturepoolchain;pool;pool = pool->next)
725 for (glt = pool->gltchain;glt;glt = glt->chain)
727 glsize = R_CalcTexelDataSize(glt);
728 isloaded = glt->texnum != 0;
730 pooltotalt += glsize;
731 pooltotalp += glt->inputdatasize;
735 poolloadedt += glsize;
736 poolloadedp += glt->inputdatasize;
739 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);
742 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);
743 sumtotal += pooltotal;
744 sumtotalt += pooltotalt;
745 sumtotalp += pooltotalp;
746 sumloaded += poolloaded;
747 sumloadedt += poolloadedt;
748 sumloadedp += poolloadedp;
751 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);
754 static void R_TextureStats_f(void)
756 R_TextureStats_Print(true, true, true);
759 static void r_textures_start(void)
761 switch(vid.renderpath)
763 case RENDERPATH_GL11:
764 case RENDERPATH_GL13:
765 case RENDERPATH_GL20:
766 case RENDERPATH_GLES1:
767 case RENDERPATH_GLES2:
768 // LordHavoc: allow any alignment
770 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
771 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
773 case RENDERPATH_D3D9:
775 case RENDERPATH_D3D10:
776 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
778 case RENDERPATH_D3D11:
779 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
781 case RENDERPATH_SOFT:
785 texturemempool = Mem_AllocPool("texture management", 0, NULL);
786 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
788 // Disable JPEG screenshots if the DLL isn't loaded
789 if (! JPEG_OpenLibrary ())
790 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
791 if (! PNG_OpenLibrary ())
792 Cvar_SetValueQuick (&scr_screenshot_png, 0);
795 static void r_textures_shutdown(void)
797 rtexturepool_t *temp;
799 JPEG_CloseLibrary ();
801 while(gltexturepoolchain)
803 temp = (rtexturepool_t *) gltexturepoolchain;
804 R_FreeTexturePool(&temp);
807 resizebuffersize = 0;
809 colorconvertbuffer = NULL;
810 texturebuffer = NULL;
811 Mem_ExpandableArray_FreeArray(&texturearray);
812 Mem_FreePool(&texturemempool);
815 static void r_textures_newmap(void)
819 static void r_textures_devicelost(void)
823 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
824 for (i = 0;i < endindex;i++)
826 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
827 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
829 switch(vid.renderpath)
831 case RENDERPATH_GL11:
832 case RENDERPATH_GL13:
833 case RENDERPATH_GL20:
834 case RENDERPATH_GLES1:
835 case RENDERPATH_GLES2:
837 case RENDERPATH_D3D9:
839 if (glt->d3disdepthsurface)
840 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
841 else if (glt->tiledepth > 1)
842 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
843 else if (glt->sides == 6)
844 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
846 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
847 glt->d3dtexture = NULL;
850 case RENDERPATH_D3D10:
851 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
853 case RENDERPATH_D3D11:
854 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
856 case RENDERPATH_SOFT:
862 static void r_textures_devicerestored(void)
866 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
867 for (i = 0;i < endindex;i++)
869 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
870 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
872 switch(vid.renderpath)
874 case RENDERPATH_GL11:
875 case RENDERPATH_GL13:
876 case RENDERPATH_GL20:
877 case RENDERPATH_GLES1:
878 case RENDERPATH_GLES2:
880 case RENDERPATH_D3D9:
884 if (glt->d3disdepthsurface)
886 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
887 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
889 else if (glt->tiledepth > 1)
891 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)))
892 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
894 else if (glt->sides == 6)
896 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
897 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
901 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)))
902 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
907 case RENDERPATH_D3D10:
908 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
910 case RENDERPATH_D3D11:
911 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
913 case RENDERPATH_SOFT:
920 void R_Textures_Init (void)
922 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");
923 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
924 Cvar_RegisterVariable (&gl_max_size);
925 Cvar_RegisterVariable (&gl_picmip);
926 Cvar_RegisterVariable (&gl_picmip_world);
927 Cvar_RegisterVariable (&r_picmipworld);
928 Cvar_RegisterVariable (&gl_picmip_sprites);
929 Cvar_RegisterVariable (&r_picmipsprites);
930 Cvar_RegisterVariable (&gl_picmip_other);
931 Cvar_RegisterVariable (&gl_max_lightmapsize);
932 Cvar_RegisterVariable (&r_lerpimages);
933 Cvar_RegisterVariable (&gl_texture_anisotropy);
934 Cvar_RegisterVariable (&gl_texturecompression);
935 Cvar_RegisterVariable (&gl_texturecompression_color);
936 Cvar_RegisterVariable (&gl_texturecompression_normal);
937 Cvar_RegisterVariable (&gl_texturecompression_gloss);
938 Cvar_RegisterVariable (&gl_texturecompression_glow);
939 Cvar_RegisterVariable (&gl_texturecompression_2d);
940 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
941 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
942 Cvar_RegisterVariable (&gl_texturecompression_sky);
943 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
944 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
945 Cvar_RegisterVariable (&gl_texturecompression_sprites);
946 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
947 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
948 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
949 Cvar_RegisterVariable (&r_texture_dds_swdecode);
951 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
954 void R_Textures_Frame (void)
956 static int old_aniso = 0;
958 // could do procedural texture animation here, if we keep track of which
959 // textures were accessed this frame...
961 // free the resize buffers
962 resizebuffersize = 0;
965 Mem_Free(resizebuffer);
968 if (colorconvertbuffer)
970 Mem_Free(colorconvertbuffer);
971 colorconvertbuffer = NULL;
974 if (old_aniso != gl_texture_anisotropy.integer)
977 gltexturepool_t *pool;
980 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
982 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
984 switch(vid.renderpath)
986 case RENDERPATH_GL11:
987 case RENDERPATH_GL13:
988 case RENDERPATH_GL20:
989 case RENDERPATH_GLES1:
990 case RENDERPATH_GLES2:
993 for (pool = gltexturepoolchain;pool;pool = pool->next)
995 for (glt = pool->gltchain;glt;glt = glt->chain)
997 // only update already uploaded images
998 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
1000 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1002 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1003 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
1005 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1010 case RENDERPATH_D3D9:
1011 case RENDERPATH_D3D10:
1012 case RENDERPATH_D3D11:
1013 case RENDERPATH_SOFT:
1019 static void R_MakeResizeBufferBigger(int size)
1021 if (resizebuffersize < size)
1023 resizebuffersize = size;
1025 Mem_Free(resizebuffer);
1026 if (colorconvertbuffer)
1027 Mem_Free(colorconvertbuffer);
1028 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
1029 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
1030 if (!resizebuffer || !colorconvertbuffer)
1031 Host_Error("R_Upload: out of memory");
1035 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
1037 int textureenum = gltexturetypeenums[texturetype];
1038 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
1042 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
1044 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
1045 if (gl_texture_anisotropy.integer != aniso)
1046 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
1047 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
1049 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
1050 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
1051 #ifdef GL_TEXTURE_WRAP_R
1052 if (gltexturetypedimensions[texturetype] >= 3)
1054 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
1059 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
1061 if (flags & TEXF_MIPMAP)
1063 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
1067 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
1069 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
1071 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
1073 if (flags & TEXF_MIPMAP)
1075 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
1077 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
1081 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
1086 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
1088 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
1092 if (flags & TEXF_MIPMAP)
1094 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1098 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1100 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1104 if (textype == TEXTYPE_SHADOWMAP || TEXTYPE_SHADOWMAP_STENCIL)
1106 if (vid.support.arb_shadow)
1108 if (flags & TEXF_COMPARE)
1110 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1114 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1116 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1118 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1125 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1128 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1130 if (glt->texturetype != GLTEXTURETYPE_2D)
1131 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1133 if (glt->textype->textype == TEXTYPE_PALETTE)
1134 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1136 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1137 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1139 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1140 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1142 // update a portion of the image
1144 switch(vid.renderpath)
1146 case RENDERPATH_GL11:
1147 case RENDERPATH_GL13:
1148 case RENDERPATH_GL20:
1149 case RENDERPATH_GLES1:
1150 case RENDERPATH_GLES2:
1154 // we need to restore the texture binding after finishing the upload
1155 GL_ActiveTexture(0);
1156 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1157 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1158 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1159 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1162 case RENDERPATH_D3D9:
1166 D3DLOCKED_RECT d3dlockedrect;
1168 memset(&d3drect, 0, sizeof(d3drect));
1169 d3drect.left = fragx;
1170 d3drect.top = fragy;
1171 d3drect.right = fragx+fragwidth;
1172 d3drect.bottom = fragy+fragheight;
1173 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1175 for (y = 0;y < fragheight;y++)
1176 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1177 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1182 case RENDERPATH_D3D10:
1183 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1185 case RENDERPATH_D3D11:
1186 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1188 case RENDERPATH_SOFT:
1189 DPSOFTRAST_Texture_UpdatePartial(glt->texnum, 0, data, fragx, fragy, fragwidth, fragheight);
1194 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1196 int i, mip = 0, width, height, depth;
1197 GLint oldbindtexnum = 0;
1198 const unsigned char *prevbuffer;
1201 // error out if a stretch is needed on special texture types
1202 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1203 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1205 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1206 // of the target size and then use the mipmap reduction function to get
1207 // high quality supersampled results
1208 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1209 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1210 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1211 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1213 if (prevbuffer == NULL)
1215 width = glt->tilewidth;
1216 height = glt->tileheight;
1217 depth = glt->tiledepth;
1218 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1219 // prevbuffer = resizebuffer;
1223 if (glt->textype->textype == TEXTYPE_PALETTE)
1225 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1226 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1227 prevbuffer = colorconvertbuffer;
1229 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1231 // multiply RGB channels by A channel before uploading
1233 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1235 alpha = prevbuffer[i+3];
1236 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1237 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1238 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1239 colorconvertbuffer[i+3] = alpha;
1241 prevbuffer = colorconvertbuffer;
1243 // scale up to a power of 2 size (if appropriate)
1244 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1246 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1247 prevbuffer = resizebuffer;
1249 // apply mipmap reduction algorithm to get down to picmip/max_size
1250 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1252 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1253 prevbuffer = resizebuffer;
1257 // do the appropriate upload type...
1258 switch(vid.renderpath)
1260 case RENDERPATH_GL11:
1261 case RENDERPATH_GL13:
1262 case RENDERPATH_GL20:
1263 case RENDERPATH_GLES1:
1264 case RENDERPATH_GLES2:
1267 // we need to restore the texture binding after finishing the upload
1268 GL_ActiveTexture(0);
1269 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1270 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1272 #ifdef GL_TEXTURE_COMPRESSION_HINT_ARB
1273 if (qglGetCompressedTexImageARB)
1275 if (gl_texturecompression.integer >= 2)
1276 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1278 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1282 switch(glt->texturetype)
1284 case GLTEXTURETYPE_2D:
1285 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1286 if (glt->flags & TEXF_MIPMAP)
1288 while (width > 1 || height > 1 || depth > 1)
1290 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1291 prevbuffer = resizebuffer;
1292 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1296 case GLTEXTURETYPE_3D:
1298 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1299 if (glt->flags & TEXF_MIPMAP)
1301 while (width > 1 || height > 1 || depth > 1)
1303 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1304 prevbuffer = resizebuffer;
1305 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1310 case GLTEXTURETYPE_CUBEMAP:
1311 // convert and upload each side in turn,
1312 // from a continuous block of input texels
1313 texturebuffer = (unsigned char *)prevbuffer;
1314 for (i = 0;i < 6;i++)
1316 prevbuffer = texturebuffer;
1317 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1318 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1320 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1321 prevbuffer = resizebuffer;
1324 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1326 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1327 prevbuffer = resizebuffer;
1330 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1331 if (glt->flags & TEXF_MIPMAP)
1333 while (width > 1 || height > 1 || depth > 1)
1335 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1336 prevbuffer = resizebuffer;
1337 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1343 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1344 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1346 case RENDERPATH_D3D9:
1348 if (!(glt->flags & TEXF_RENDERTARGET))
1350 D3DLOCKED_RECT d3dlockedrect;
1351 D3DLOCKED_BOX d3dlockedbox;
1352 switch(glt->texturetype)
1354 case GLTEXTURETYPE_2D:
1355 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1358 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1360 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1361 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1364 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1366 while (width > 1 || height > 1 || depth > 1)
1368 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1369 prevbuffer = resizebuffer;
1370 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1372 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1373 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1379 case GLTEXTURETYPE_3D:
1380 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1382 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1383 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1384 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1387 if (glt->flags & TEXF_MIPMAP)
1389 while (width > 1 || height > 1 || depth > 1)
1391 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1392 prevbuffer = resizebuffer;
1393 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1395 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1396 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1397 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1403 case GLTEXTURETYPE_CUBEMAP:
1404 // convert and upload each side in turn,
1405 // from a continuous block of input texels
1406 texturebuffer = (unsigned char *)prevbuffer;
1407 for (i = 0;i < 6;i++)
1409 prevbuffer = texturebuffer;
1410 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1411 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1413 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1414 prevbuffer = resizebuffer;
1417 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1419 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1420 prevbuffer = resizebuffer;
1423 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1425 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1426 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1429 if (glt->flags & TEXF_MIPMAP)
1431 while (width > 1 || height > 1 || depth > 1)
1433 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1434 prevbuffer = resizebuffer;
1435 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1437 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1438 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1447 glt->d3daddressw = 0;
1448 if (glt->flags & TEXF_CLAMP)
1450 glt->d3daddressu = D3DTADDRESS_CLAMP;
1451 glt->d3daddressv = D3DTADDRESS_CLAMP;
1452 if (glt->tiledepth > 1)
1453 glt->d3daddressw = D3DTADDRESS_CLAMP;
1457 glt->d3daddressu = D3DTADDRESS_WRAP;
1458 glt->d3daddressv = D3DTADDRESS_WRAP;
1459 if (glt->tiledepth > 1)
1460 glt->d3daddressw = D3DTADDRESS_WRAP;
1462 glt->d3dmipmaplodbias = 0;
1463 glt->d3dmaxmiplevel = 0;
1464 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1465 if (glt->flags & TEXF_FORCELINEAR)
1467 glt->d3dminfilter = D3DTEXF_LINEAR;
1468 glt->d3dmagfilter = D3DTEXF_LINEAR;
1469 glt->d3dmipfilter = D3DTEXF_POINT;
1471 else if (glt->flags & TEXF_FORCENEAREST)
1473 glt->d3dminfilter = D3DTEXF_POINT;
1474 glt->d3dmagfilter = D3DTEXF_POINT;
1475 glt->d3dmipfilter = D3DTEXF_POINT;
1477 else if (glt->flags & TEXF_MIPMAP)
1479 glt->d3dminfilter = d3d_filter_mipmin;
1480 glt->d3dmagfilter = d3d_filter_mipmag;
1481 glt->d3dmipfilter = d3d_filter_mipmix;
1485 glt->d3dminfilter = d3d_filter_flatmin;
1486 glt->d3dmagfilter = d3d_filter_flatmag;
1487 glt->d3dmipfilter = d3d_filter_flatmix;
1491 case RENDERPATH_D3D10:
1492 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1494 case RENDERPATH_D3D11:
1495 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1497 case RENDERPATH_SOFT:
1498 switch(glt->texturetype)
1500 case GLTEXTURETYPE_2D:
1501 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1503 case GLTEXTURETYPE_3D:
1504 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1506 case GLTEXTURETYPE_CUBEMAP:
1507 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1509 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1510 // convert and upload each side in turn,
1511 // from a continuous block of input texels
1512 // copy the results into combinedbuffer
1513 texturebuffer = (unsigned char *)prevbuffer;
1514 for (i = 0;i < 6;i++)
1516 prevbuffer = texturebuffer;
1517 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1518 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1520 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1521 prevbuffer = resizebuffer;
1524 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1526 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1527 prevbuffer = resizebuffer;
1529 memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1531 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1532 Mem_Free(combinedbuffer);
1535 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1538 if (glt->flags & TEXF_FORCELINEAR)
1539 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1540 else if (glt->flags & TEXF_FORCENEAREST)
1541 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1542 else if (glt->flags & TEXF_MIPMAP)
1543 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1545 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1550 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)
1554 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1555 textypeinfo_t *texinfo, *texinfo2;
1556 unsigned char *temppixels = NULL;
1559 if (cls.state == ca_dedicated)
1562 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1563 if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1565 int numpixels = width * height * depth * sides;
1566 size = numpixels * 4;
1567 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1570 const unsigned char *p;
1571 unsigned char *o = temppixels;
1572 for (i = 0;i < numpixels;i++, o += 4)
1574 p = (const unsigned char *)palette + 4*data[i];
1582 textype = TEXTYPE_RGBA;
1587 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1588 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1589 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1590 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1596 static int rgbaswapindices[4] = {2, 1, 0, 3};
1597 size = width * height * depth * sides * 4;
1598 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1600 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1604 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1605 if (!vid.support.ext_texture_srgb)
1607 qboolean convertsRGB = false;
1610 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1611 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1612 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1613 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1614 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;convertsRGB = true;break;
1615 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1616 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1620 if (convertsRGB && data)
1622 size = width * height * depth * sides * 4;
1625 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1626 memcpy(temppixels, data, size);
1629 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1633 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1635 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1638 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1640 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1644 texinfo = R_GetTexTypeInfo(textype, flags);
1645 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1648 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1652 // clear the alpha flag if the texture has no transparent pixels
1655 case TEXTYPE_PALETTE:
1656 case TEXTYPE_SRGB_PALETTE:
1657 if (flags & TEXF_ALPHA)
1659 flags &= ~TEXF_ALPHA;
1662 for (i = 0;i < size;i++)
1664 if (((unsigned char *)&palette[data[i]])[3] < 255)
1666 flags |= TEXF_ALPHA;
1675 case TEXTYPE_SRGB_RGBA:
1676 case TEXTYPE_SRGB_BGRA:
1677 if (flags & TEXF_ALPHA)
1679 flags &= ~TEXF_ALPHA;
1682 for (i = 3;i < size;i += 4)
1686 flags |= TEXF_ALPHA;
1693 case TEXTYPE_SHADOWMAP:
1694 case TEXTYPE_SHADOWMAP_STENCIL:
1697 case TEXTYPE_SRGB_DXT1:
1700 case TEXTYPE_SRGB_DXT1A:
1702 case TEXTYPE_SRGB_DXT3:
1704 case TEXTYPE_SRGB_DXT5:
1705 flags |= TEXF_ALPHA;
1708 flags |= TEXF_ALPHA;
1710 case TEXTYPE_COLORBUFFER:
1711 case TEXTYPE_COLORBUFFER16F:
1712 case TEXTYPE_COLORBUFFER32F:
1713 flags |= TEXF_ALPHA;
1716 Sys_Error("R_LoadTexture: unknown texture type");
1719 texinfo2 = R_GetTexTypeInfo(textype, flags);
1720 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1723 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1725 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1727 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1729 glt->chain = pool->gltchain;
1730 pool->gltchain = glt;
1731 glt->inputwidth = width;
1732 glt->inputheight = height;
1733 glt->inputdepth = depth;
1735 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
1736 glt->textype = texinfo;
1737 glt->texturetype = texturetype;
1738 glt->inputdatasize = size;
1739 glt->palette = palette;
1740 glt->glinternalformat = texinfo->glinternalformat;
1741 glt->glformat = texinfo->glformat;
1742 glt->gltype = texinfo->gltype;
1743 glt->bytesperpixel = texinfo->internalbytesperpixel;
1744 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1747 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1748 // init the dynamic texture attributes, too [11/22/2007 Black]
1749 glt->updatecallback = NULL;
1750 glt->updatacallback_data = NULL;
1752 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1754 // upload the texture
1755 // data may be NULL (blank texture for dynamic rendering)
1756 switch(vid.renderpath)
1758 case RENDERPATH_GL11:
1759 case RENDERPATH_GL13:
1760 case RENDERPATH_GL20:
1761 case RENDERPATH_GLES1:
1762 case RENDERPATH_GLES2:
1764 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1766 case RENDERPATH_D3D9:
1769 D3DFORMAT d3dformat;
1774 d3dpool = D3DPOOL_MANAGED;
1775 if (flags & TEXF_RENDERTARGET)
1777 d3dusage |= D3DUSAGE_RENDERTARGET;
1778 d3dpool = D3DPOOL_DEFAULT;
1782 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1783 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1784 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1785 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
1786 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
1787 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
1788 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D24X8;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1789 case TEXTYPE_SHADOWMAP_STENCIL: d3dformat = D3DFMT_D24S8;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1790 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1791 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1793 glt->d3dformat = d3dformat;
1794 glt->d3dusage = d3dusage;
1795 glt->d3dpool = d3dpool;
1796 glt->d3disdepthsurface = (textype == TEXTYPE_SHADOWMAP || textype == TEXTYPE_SHADOWMAP_STENCIL);
1797 if (glt->d3disdepthsurface)
1799 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1800 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1802 else if (glt->tiledepth > 1)
1804 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)))
1805 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1807 else if (glt->sides == 6)
1809 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1810 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1814 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)))
1815 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1820 case RENDERPATH_D3D10:
1821 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1823 case RENDERPATH_D3D11:
1824 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1826 case RENDERPATH_SOFT:
1831 case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1832 case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1833 case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1834 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1835 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
1836 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
1837 case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1838 case TEXTYPE_SHADOWMAP_STENCIL: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1839 case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1840 default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1842 if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1843 if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1844 if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1845 if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1846 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1851 R_UploadFullTexture(glt, data);
1852 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1853 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1855 // free any temporary processing buffer we allocated...
1857 Mem_Free(temppixels);
1859 // texture converting and uploading can take a while, so make sure we're sending keepalives
1860 // FIXME: this causes rendering during R_Shadow_DrawLights
1861 // CL_KeepaliveMessage(false);
1863 return (rtexture_t *)glt;
1866 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)
1868 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1871 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)
1873 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1876 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)
1878 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1881 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1883 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1885 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1887 flags |= TEXF_FORCENEAREST;
1888 if (precision <= 16)
1889 flags |= TEXF_LOWPRECISION;
1893 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter, qboolean stencil)
1895 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, stencil ? TEXTYPE_SHADOWMAP_STENCIL : TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1898 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1901 return -1; // unsupported on this platform
1903 gltexture_t *glt = (gltexture_t *)rt;
1906 int bytesperpixel = 0;
1907 int bytesperblock = 0;
1909 int dds_format_flags;
1917 GLint internalformat;
1918 const char *ddsfourcc;
1920 return -1; // NULL pointer
1921 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1922 return -2; // broken driver - crashes on reading internal format
1923 if (!qglGetTexLevelParameteriv)
1925 GL_ActiveTexture(0);
1926 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1927 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1928 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1929 switch(internalformat)
1931 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1932 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1933 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1934 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1935 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1937 // if premultiplied alpha, say so in the DDS file
1938 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1940 switch(internalformat)
1942 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1943 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1946 if (!bytesperblock && skipuncompressed)
1947 return -3; // skipped
1948 memset(mipinfo, 0, sizeof(mipinfo));
1949 mipinfo[0][0] = glt->tilewidth;
1950 mipinfo[0][1] = glt->tileheight;
1952 if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tilewidth == 1))
1954 for (mip = 1;mip < 16;mip++)
1956 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1957 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1958 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1966 for (mip = 0;mip < mipmaps;mip++)
1968 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1969 mipinfo[mip][3] = ddssize;
1970 ddssize += mipinfo[mip][2];
1972 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1975 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1979 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1980 dds_format_flags = 0x4; // DDPF_FOURCC
1984 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1985 dds_format_flags = 0x40; // DDPF_RGB
1989 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1990 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1993 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1994 memcpy(dds, "DDS ", 4);
1995 StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
1996 StoreLittleLong(dds+8, dds_flags);
1997 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1998 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1999 StoreLittleLong(dds+24, 0); // depth
2000 StoreLittleLong(dds+28, mipmaps); // mipmaps
2001 StoreLittleLong(dds+76, 32); // format size
2002 StoreLittleLong(dds+80, dds_format_flags);
2003 StoreLittleLong(dds+108, dds_caps1);
2004 StoreLittleLong(dds+112, dds_caps2);
2007 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
2008 memcpy(dds+84, ddsfourcc, 4);
2009 for (mip = 0;mip < mipmaps;mip++)
2011 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
2016 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
2017 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
2018 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
2019 for (mip = 0;mip < mipmaps;mip++)
2021 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
2024 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2025 ret = FS_WriteFile(filename, dds, ddssize);
2027 return ret ? ddssize : -5;
2031 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
2033 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
2036 int bytesperblock, bytesperpixel;
2039 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
2040 textypeinfo_t *texinfo;
2041 int mip, mipwidth, mipheight, mipsize, mipsize_total;
2042 unsigned int c, r, g, b;
2043 GLint oldbindtexnum = 0;
2044 unsigned char *mippixels;
2045 unsigned char *mippixels_start;
2046 unsigned char *ddspixels;
2048 fs_offset_t ddsfilesize;
2049 unsigned int ddssize;
2050 qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
2052 if (cls.state == ca_dedicated)
2055 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
2056 ddssize = ddsfilesize;
2060 if(r_texture_dds_load_logfailure.integer)
2061 Log_Printf("ddstexturefailures.log", "%s\n", filename);
2062 return NULL; // not found
2065 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
2068 Con_Printf("^1%s: not a DDS image\n", filename);
2072 //dds_flags = BuffLittleLong(dds+8);
2073 dds_format_flags = BuffLittleLong(dds+80);
2074 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
2075 dds_width = BuffLittleLong(dds+16);
2076 dds_height = BuffLittleLong(dds+12);
2077 ddspixels = dds + 128;
2079 if(r_texture_dds_load_alphamode.integer == 0)
2080 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
2081 flags &= ~TEXF_ALPHA;
2083 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
2084 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
2086 // very sloppy BGRA 32bit identification
2087 textype = TEXTYPE_BGRA;
2088 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2091 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
2092 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2095 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
2098 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
2101 for (i = 3;i < size;i += 4)
2102 if (ddspixels[i] < 255)
2105 flags &= ~TEXF_ALPHA;
2108 else if (!memcmp(dds+84, "DXT1", 4))
2110 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
2111 // LordHavoc: it is my belief that this does not infringe on the
2112 // patent because it is not decoding pixels...
2113 textype = TEXTYPE_DXT1;
2116 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
2117 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2118 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2121 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
2124 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
2126 if(r_texture_dds_load_alphamode.integer == 1)
2129 for (i = 0;i < size;i += bytesperblock)
2130 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
2132 // NOTE: this assumes sizeof(unsigned int) == 4
2133 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
2134 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
2135 if(data & (data<<1) & 0xAAAAAAAA)//rgh
2139 textype = TEXTYPE_DXT1A;
2141 flags &= ~TEXF_ALPHA;
2145 flags &= ~TEXF_ALPHA;
2149 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2151 if(!memcmp(dds+84, "DXT2", 4))
2153 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2155 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2160 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2162 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2165 textype = TEXTYPE_DXT3;
2168 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2169 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2172 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2175 // we currently always assume alpha
2177 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2179 if(!memcmp(dds+84, "DXT4", 4))
2181 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2183 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2188 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2190 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2193 textype = TEXTYPE_DXT5;
2196 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2197 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2200 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2203 // we currently always assume alpha
2208 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2212 // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
2213 if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
2215 textype = TEXTYPE_DXT1;
2219 for (i = 0;i < (int)ddssize;i += bytesperblock)
2220 memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
2224 force_swdecode = false;
2227 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
2229 if(r_texture_dds_swdecode.integer > 1)
2230 force_swdecode = true;
2234 if(r_texture_dds_swdecode.integer < 1)
2240 force_swdecode = true;
2244 // return whether this texture is transparent
2246 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2248 // if we SW decode, choose 2 sizes bigger
2251 // this is quarter res, so do not scale down more than we have to
2255 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2258 // this is where we apply gl_picmip
2259 mippixels_start = ddspixels;
2260 mipwidth = dds_width;
2261 mipheight = dds_height;
2262 while(miplevel >= 1 && dds_miplevels >= 1)
2264 if (mipwidth <= 1 && mipheight <= 1)
2266 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2267 mippixels_start += mipsize; // just skip
2275 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2276 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2278 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2280 // fake decode S3TC if needed
2283 int mipsize_new = mipsize_total / bytesperblock * 4;
2284 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2285 unsigned char *p = mipnewpixels;
2286 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2288 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2289 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2290 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2291 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2292 if(textype == TEXTYPE_DXT5)
2293 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2294 else if(textype == TEXTYPE_DXT3)
2296 (mippixels_start[i-8] & 0x0F)
2297 + (mippixels_start[i-8] >> 4)
2298 + (mippixels_start[i-7] & 0x0F)
2299 + (mippixels_start[i-7] >> 4)
2300 + (mippixels_start[i-6] & 0x0F)
2301 + (mippixels_start[i-6] >> 4)
2302 + (mippixels_start[i-5] & 0x0F)
2303 + (mippixels_start[i-5] >> 4)
2304 ) * (0.125f / 15.0f * 255.0f);
2309 textype = TEXTYPE_BGRA;
2313 // as each block becomes a pixel, we must use pixel count for this
2314 mipwidth = (mipwidth + 3) / 4;
2315 mipheight = (mipheight + 3) / 4;
2316 mipsize = bytesperpixel * mipwidth * mipheight;
2317 mippixels_start = mipnewpixels;
2318 mipsize_total = mipsize_new;
2321 // start mip counting
2322 mippixels = mippixels_start;
2324 // calculate average color if requested
2328 Vector4Clear(avgcolor);
2331 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2333 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2334 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2335 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2336 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2337 if(textype == TEXTYPE_DXT5)
2338 avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2339 else if(textype == TEXTYPE_DXT3)
2341 (mippixels_start[i-8] & 0x0F)
2342 + (mippixels_start[i-8] >> 4)
2343 + (mippixels_start[i-7] & 0x0F)
2344 + (mippixels_start[i-7] >> 4)
2345 + (mippixels_start[i-6] & 0x0F)
2346 + (mippixels_start[i-6] >> 4)
2347 + (mippixels_start[i-5] & 0x0F)
2348 + (mippixels_start[i-5] >> 4)
2349 ) * (0.125f / 15.0f * 255.0f);
2353 f = (float)bytesperblock / size;
2354 avgcolor[0] *= (0.5f / 31.0f) * f;
2355 avgcolor[1] *= (0.5f / 63.0f) * f;
2356 avgcolor[2] *= (0.5f / 31.0f) * f;
2361 for (i = 0;i < mipsize;i += 4)
2363 avgcolor[0] += mippixels[i+2];
2364 avgcolor[1] += mippixels[i+1];
2365 avgcolor[2] += mippixels[i];
2366 avgcolor[3] += mippixels[i+3];
2368 f = (1.0f / 255.0f) * bytesperpixel / size;
2376 // if we want sRGB, convert now
2379 if (vid.support.ext_texture_srgb)
2383 case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break;
2384 case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break;
2385 case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break;
2386 case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break;
2387 case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break;
2401 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2403 int c0, c1, c0new, c1new;
2404 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2405 r = ((c0 >> 11) & 0x1F);
2406 g = ((c0 >> 5) & 0x3F);
2408 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2409 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2410 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2411 c0new = (r << 11) | (g << 5) | b;
2412 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2413 r = ((c1 >> 11) & 0x1F);
2414 g = ((c1 >> 5) & 0x3F);
2416 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2417 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2418 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2419 c1new = (r << 11) | (g << 5) | b;
2420 // swap the colors if needed to fix order
2421 if(c0 > c1) // thirds
2429 mippixels_start[i+4] ^= 0x55;
2430 mippixels_start[i+5] ^= 0x55;
2431 mippixels_start[i+6] ^= 0x55;
2432 mippixels_start[i+7] ^= 0x55;
2434 else if(c0new == c1new)
2436 mippixels_start[i+4] = 0x00;
2437 mippixels_start[i+5] = 0x00;
2438 mippixels_start[i+6] = 0x00;
2439 mippixels_start[i+7] = 0x00;
2442 else // half + transparent
2449 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2450 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2451 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2452 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2455 mippixels_start[i] = c0new & 255;
2456 mippixels_start[i+1] = c0new >> 8;
2457 mippixels_start[i+2] = c1new & 255;
2458 mippixels_start[i+3] = c1new >> 8;
2463 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2471 // when not requesting mipmaps, do not load them
2472 if(!(flags & TEXF_MIPMAP))
2475 if (dds_miplevels >= 1)
2476 flags |= TEXF_MIPMAP;
2478 flags &= ~TEXF_MIPMAP;
2480 texinfo = R_GetTexTypeInfo(textype, flags);
2482 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2483 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2485 glt->chain = pool->gltchain;
2486 pool->gltchain = glt;
2487 glt->inputwidth = mipwidth;
2488 glt->inputheight = mipheight;
2489 glt->inputdepth = 1;
2491 glt->textype = texinfo;
2492 glt->texturetype = GLTEXTURETYPE_2D;
2493 glt->inputdatasize = ddssize;
2494 glt->glinternalformat = texinfo->glinternalformat;
2495 glt->glformat = texinfo->glformat;
2496 glt->gltype = texinfo->gltype;
2497 glt->bytesperpixel = texinfo->internalbytesperpixel;
2499 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2500 glt->tilewidth = mipwidth;
2501 glt->tileheight = mipheight;
2503 glt->miplevels = dds_miplevels;
2505 // texture uploading can take a while, so make sure we're sending keepalives
2506 CL_KeepaliveMessage(false);
2508 // create the texture object
2509 switch(vid.renderpath)
2511 case RENDERPATH_GL11:
2512 case RENDERPATH_GL13:
2513 case RENDERPATH_GL20:
2514 case RENDERPATH_GLES1:
2515 case RENDERPATH_GLES2:
2517 GL_ActiveTexture(0);
2518 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2519 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2520 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2522 case RENDERPATH_D3D9:
2525 D3DFORMAT d3dformat;
2530 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2531 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2532 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2533 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2534 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2537 d3dpool = D3DPOOL_MANAGED;
2538 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2542 case RENDERPATH_D3D10:
2543 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2545 case RENDERPATH_D3D11:
2546 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2548 case RENDERPATH_SOFT:
2549 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);
2553 // upload the texture
2554 // we need to restore the texture binding after finishing the upload
2555 mipcomplete = false;
2557 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2559 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2560 if (mippixels + mipsize > mippixels_start + mipsize_total)
2562 switch(vid.renderpath)
2564 case RENDERPATH_GL11:
2565 case RENDERPATH_GL13:
2566 case RENDERPATH_GL20:
2567 case RENDERPATH_GLES1:
2568 case RENDERPATH_GLES2:
2571 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2575 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2578 case RENDERPATH_D3D9:
2581 D3DLOCKED_RECT d3dlockedrect;
2582 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2584 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2585 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2591 case RENDERPATH_D3D10:
2592 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2594 case RENDERPATH_D3D11:
2595 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2597 case RENDERPATH_SOFT:
2599 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2601 DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
2602 // DPSOFTRAST calculates its own mipmaps
2603 mip = dds_miplevels;
2606 mippixels += mipsize;
2607 if (mipwidth <= 1 && mipheight <= 1)
2618 // after upload we have to set some parameters...
2619 switch(vid.renderpath)
2621 case RENDERPATH_GL11:
2622 case RENDERPATH_GL13:
2623 case RENDERPATH_GL20:
2624 case RENDERPATH_GLES1:
2625 case RENDERPATH_GLES2:
2626 #ifdef GL_TEXTURE_MAX_LEVEL
2627 if (dds_miplevels >= 1 && !mipcomplete)
2629 // need to set GL_TEXTURE_MAX_LEVEL
2630 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2633 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2634 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2636 case RENDERPATH_D3D9:
2638 glt->d3daddressw = 0;
2639 if (glt->flags & TEXF_CLAMP)
2641 glt->d3daddressu = D3DTADDRESS_CLAMP;
2642 glt->d3daddressv = D3DTADDRESS_CLAMP;
2643 if (glt->tiledepth > 1)
2644 glt->d3daddressw = D3DTADDRESS_CLAMP;
2648 glt->d3daddressu = D3DTADDRESS_WRAP;
2649 glt->d3daddressv = D3DTADDRESS_WRAP;
2650 if (glt->tiledepth > 1)
2651 glt->d3daddressw = D3DTADDRESS_WRAP;
2653 glt->d3dmipmaplodbias = 0;
2654 glt->d3dmaxmiplevel = 0;
2655 glt->d3dmaxmiplevelfilter = 0;
2656 if (glt->flags & TEXF_MIPMAP)
2658 glt->d3dminfilter = d3d_filter_mipmin;
2659 glt->d3dmagfilter = d3d_filter_mipmag;
2660 glt->d3dmipfilter = d3d_filter_mipmix;
2664 glt->d3dminfilter = d3d_filter_flatmin;
2665 glt->d3dmagfilter = d3d_filter_flatmag;
2666 glt->d3dmipfilter = d3d_filter_flatmix;
2670 case RENDERPATH_D3D10:
2671 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2673 case RENDERPATH_D3D11:
2674 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2676 case RENDERPATH_SOFT:
2677 if (glt->flags & TEXF_FORCELINEAR)
2678 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2679 else if (glt->flags & TEXF_FORCENEAREST)
2680 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2681 else if (glt->flags & TEXF_MIPMAP)
2682 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2684 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2690 Mem_Free((unsigned char *) mippixels_start);
2691 return (rtexture_t *)glt;
2694 int R_TextureWidth(rtexture_t *rt)
2696 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2699 int R_TextureHeight(rtexture_t *rt)
2701 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2704 int R_TextureFlags(rtexture_t *rt)
2706 return rt ? ((gltexture_t *)rt)->flags : 0;
2709 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2711 gltexture_t *glt = (gltexture_t *)rt;
2713 Host_Error("R_UpdateTexture: no data supplied");
2715 Host_Error("R_UpdateTexture: no texture supplied");
2716 if (!glt->texnum && !glt->d3dtexture)
2718 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2721 // update part of the texture
2722 if (glt->bufferpixels)
2725 int bpp = glt->bytesperpixel;
2726 int inputskip = width*bpp;
2727 int outputskip = glt->tilewidth*bpp;
2728 const unsigned char *input = data;
2729 unsigned char *output = glt->bufferpixels;
2730 if (glt->inputdepth != 1 || glt->sides != 1)
2731 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2741 input -= y*inputskip;
2744 if (width > glt->tilewidth - x)
2745 width = glt->tilewidth - x;
2746 if (height > glt->tileheight - y)
2747 height = glt->tileheight - y;
2748 if (width < 1 || height < 1)
2751 glt->buffermodified = true;
2752 output += y*outputskip + x*bpp;
2753 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2754 memcpy(output, input, width*bpp);
2756 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2757 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2759 R_UploadFullTexture(glt, data);
2762 int R_RealGetTexture(rtexture_t *rt)
2767 glt = (gltexture_t *)rt;
2768 if (glt->flags & GLTEXF_DYNAMIC)
2769 R_UpdateDynamicTexture(glt);
2770 if (glt->buffermodified && glt->bufferpixels)
2772 glt->buffermodified = false;
2773 R_UploadFullTexture(glt, glt->bufferpixels);
2782 void R_ClearTexture (rtexture_t *rt)
2784 gltexture_t *glt = (gltexture_t *)rt;
2786 R_UploadFullTexture(glt, NULL);
2789 int R_PicmipForFlags(int flags)
2792 if(flags & TEXF_PICMIP)
2794 miplevel += gl_picmip.integer;
2795 if (flags & TEXF_ISWORLD)
2797 if (r_picmipworld.integer)
2798 miplevel += gl_picmip_world.integer;
2802 else if (flags & TEXF_ISSPRITE)
2804 if (r_picmipsprites.integer)
2805 miplevel += gl_picmip_sprites.integer;
2810 miplevel += gl_picmip_other.integer;
2812 return max(0, miplevel);