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_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
89 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F, 8, 8, 8.0f, GL_RGBA , GL_RGBA , GL_FLOAT };
90 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F, 16, 16, 16.0f, GL_RGBA , GL_RGBA , GL_FLOAT };
93 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
94 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
95 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
96 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
97 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
98 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
99 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
101 // framebuffer texture formats
102 static textypeinfo_t textype_shadowmap16 = {"shadowmap16", TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
103 static textypeinfo_t textype_shadowmap24 = {"shadowmap24", TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
104 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
105 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F, 8, 8, 8.0f, GL_RGBA16F_ARB , GL_RGBA , GL_FLOAT };
106 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F, 16, 16, 16.0f, GL_RGBA32F_ARB , GL_RGBA , GL_FLOAT };
109 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
110 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
111 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
112 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE };
113 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
114 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 };
115 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 };
116 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
117 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
118 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 };
119 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 };
120 static textypeinfo_t textype_dxt1 = {"dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
121 static textypeinfo_t textype_dxt1a = {"dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 };
122 static textypeinfo_t textype_dxt3 = {"dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 };
123 static textypeinfo_t textype_dxt5 = {"dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 };
124 static textypeinfo_t textype_sRGB_palette = {"sRGB_palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
125 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 };
126 static textypeinfo_t textype_sRGB_rgba = {"sRGB_rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
127 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 };
128 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 };
129 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 };
130 static textypeinfo_t textype_sRGB_bgra = {"sRGB_bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
131 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 };
132 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 };
133 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 };
134 static textypeinfo_t textype_sRGB_dxt1 = {"sRGB_dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , 0 , 0 };
135 static textypeinfo_t textype_sRGB_dxt1a = {"sRGB_dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 , 0 };
136 static textypeinfo_t textype_sRGB_dxt3 = {"sRGB_dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 , 0 };
137 static textypeinfo_t textype_sRGB_dxt5 = {"sRGB_dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 , 0 };
140 typedef enum gltexturetype_e
144 GLTEXTURETYPE_CUBEMAP,
149 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP};
150 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
151 static int cubemapside[6] =
153 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
154 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
155 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
156 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
157 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
158 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
161 typedef struct gltexture_s
163 // this portion of the struct is exposed to the R_GetTexture macro for
164 // speed reasons, must be identical in rtexture_t!
165 int texnum; // GL texture slot number
166 qboolean dirty; // indicates that R_RealGetTexture should be called
167 int gltexturetypeenum; // used by R_Mesh_TexBind
168 // d3d stuff the backend needs
171 qboolean d3disdepthsurface; // for depth/stencil surfaces
181 int d3dmaxmiplevelfilter;
182 int d3dmipmaplodbias;
186 // dynamic texture stuff [11/22/2007 Black]
187 updatecallback_t updatecallback;
188 void *updatacallback_data;
189 // --- [11/22/2007 Black]
191 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
192 unsigned char *bufferpixels;
193 qboolean buffermodified;
195 // pointer to texturepool (check this to see if the texture is allocated)
196 struct gltexturepool_s *pool;
197 // pointer to next texture in texturepool chain
198 struct gltexture_s *chain;
199 // name of the texture (this might be removed someday), no duplicates
200 char identifier[MAX_QPATH + 32];
201 // original data size in *inputtexels
202 int inputwidth, inputheight, inputdepth;
203 // copy of the original texture(s) supplied to the upload function, for
204 // delayed uploads (non-precached)
205 unsigned char *inputtexels;
206 // original data size in *inputtexels
208 // flags supplied to the LoadTexture function
209 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
213 // pointer to one of the textype_ structs
214 textypeinfo_t *textype;
215 // one of the GLTEXTURETYPE_ values
217 // palette if the texture is TEXTYPE_PALETTE
218 const unsigned int *palette;
219 // actual stored texture size after gl_picmip and gl_max_size are applied
220 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
221 int tilewidth, tileheight, tiledepth;
222 // 1 or 6 depending on texturetype
224 // how many mipmap levels in this texture
228 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
231 int glinternalformat;
232 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
237 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
239 typedef struct gltexturepool_s
241 unsigned int sentinel;
242 struct gltexture_s *gltchain;
243 struct gltexturepool_s *next;
247 static gltexturepool_t *gltexturepoolchain = NULL;
249 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
250 static int resizebuffersize = 0;
251 static const unsigned char *texturebuffer;
253 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
258 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
259 case TEXTYPE_RGBA: return ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba);
260 case TEXTYPE_BGRA: return ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra);
261 case TEXTYPE_ALPHA: return &textype_alpha;
262 case TEXTYPE_SHADOWMAP: return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
263 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
264 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
265 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
267 Host_Error("R_GetTexTypeInfo: unknown texture format");
273 case TEXTYPE_DXT1: return &textype_dxt1;
274 case TEXTYPE_DXT1A: return &textype_dxt1a;
275 case TEXTYPE_DXT3: return &textype_dxt3;
276 case TEXTYPE_DXT5: return &textype_dxt5;
277 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
278 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);
279 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);
280 case TEXTYPE_ALPHA: return &textype_alpha;
281 case TEXTYPE_SHADOWMAP: return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
282 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
283 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
284 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
285 case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1;
286 case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a;
287 case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
288 case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
289 case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
290 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);
291 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);
293 Host_Error("R_GetTexTypeInfo: unknown texture format");
300 // dynamic texture code [11/22/2007 Black]
301 void R_MarkDirtyTexture(rtexture_t *rt) {
302 gltexture_t *glt = (gltexture_t*) rt;
307 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
308 if (glt->flags & GLTEXF_DYNAMIC)
310 // mark it as dirty, so R_RealGetTexture gets called
315 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
316 gltexture_t *glt = (gltexture_t*) rt;
321 glt->flags |= GLTEXF_DYNAMIC;
322 glt->updatecallback = updatecallback;
323 glt->updatacallback_data = data;
326 static void R_UpdateDynamicTexture(gltexture_t *glt) {
328 if( glt->updatecallback ) {
329 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
333 void R_PurgeTexture(rtexture_t *rt)
335 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
340 void R_FreeTexture(rtexture_t *rt)
342 gltexture_t *glt, **gltpointer;
344 glt = (gltexture_t *)rt;
346 Host_Error("R_FreeTexture: texture == NULL");
348 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
349 if (*gltpointer == glt)
350 *gltpointer = glt->chain;
352 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
354 R_Mesh_ClearBindingsForTexture(glt->texnum);
356 switch(vid.renderpath)
358 case RENDERPATH_GL11:
359 case RENDERPATH_GL13:
360 case RENDERPATH_GL20:
361 case RENDERPATH_GLES1:
362 case RENDERPATH_GLES2:
366 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
369 case RENDERPATH_D3D9:
371 if (glt->d3disdepthsurface)
372 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
373 else if (glt->tiledepth > 1)
374 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
375 else if (glt->sides == 6)
376 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
378 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
379 glt->d3dtexture = NULL;
382 case RENDERPATH_D3D10:
383 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
385 case RENDERPATH_D3D11:
386 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
388 case RENDERPATH_SOFT:
390 DPSOFTRAST_Texture_Free(glt->texnum);
394 if (glt->inputtexels)
395 Mem_Free(glt->inputtexels);
396 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
399 rtexturepool_t *R_AllocTexturePool(void)
401 gltexturepool_t *pool;
402 if (texturemempool == NULL)
404 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
407 pool->next = gltexturepoolchain;
408 gltexturepoolchain = pool;
409 pool->sentinel = TEXTUREPOOL_SENTINEL;
410 return (rtexturepool_t *)pool;
413 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
415 gltexturepool_t *pool, **poolpointer;
416 if (rtexturepool == NULL)
418 if (*rtexturepool == NULL)
420 pool = (gltexturepool_t *)(*rtexturepool);
421 *rtexturepool = NULL;
422 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
423 Host_Error("R_FreeTexturePool: pool already freed");
424 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
425 if (*poolpointer == pool)
426 *poolpointer = pool->next;
428 Host_Error("R_FreeTexturePool: pool not linked");
429 while (pool->gltchain)
430 R_FreeTexture((rtexture_t *)pool->gltchain);
435 typedef struct glmode_s
438 int minification, magnification;
439 DPSOFTRAST_TEXTURE_FILTER dpsoftrastfilter_mipmap, dpsoftrastfilter_nomipmap;
443 static glmode_t modes[6] =
445 {"GL_NEAREST", GL_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
446 {"GL_LINEAR", GL_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
447 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
448 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
449 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
450 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR}
454 typedef struct d3dmode_s
461 static d3dmode_t d3dmodes[6] =
463 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
464 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
465 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
466 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
467 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
468 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
472 static void GL_TextureMode_f (void)
477 gltexturepool_t *pool;
481 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
482 for (i = 0;i < 6;i++)
484 if (gl_filter_min == modes[i].minification)
486 Con_Printf("%s\n", modes[i].name);
490 Con_Print("current filter is unknown???\n");
494 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
495 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
499 Con_Print("bad filter name\n");
503 gl_filter_min = modes[i].minification;
504 gl_filter_mag = modes[i].magnification;
505 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
507 dpsoftrast_filter_mipmap = modes[i].dpsoftrastfilter_mipmap;
508 dpsoftrast_filter_nomipmap = modes[i].dpsoftrastfilter_nomipmap;
510 switch(vid.renderpath)
512 case RENDERPATH_GL11:
513 case RENDERPATH_GL13:
514 case RENDERPATH_GL20:
515 case RENDERPATH_GLES1:
516 case RENDERPATH_GLES2:
517 // change all the existing mipmap texture objects
518 // FIXME: force renderer(/client/something?) restart instead?
521 for (pool = gltexturepoolchain;pool;pool = pool->next)
523 for (glt = pool->gltchain;glt;glt = glt->chain)
525 // only update already uploaded images
526 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
528 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
529 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
530 if (glt->flags & TEXF_MIPMAP)
532 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
536 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
538 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
539 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
544 case RENDERPATH_D3D9:
546 d3d_filter_flatmin = d3dmodes[i].m1;
547 d3d_filter_flatmag = d3dmodes[i].m1;
548 d3d_filter_flatmix = D3DTEXF_POINT;
549 d3d_filter_mipmin = d3dmodes[i].m1;
550 d3d_filter_mipmag = d3dmodes[i].m1;
551 d3d_filter_mipmix = d3dmodes[i].m2;
552 d3d_filter_nomip = i < 2;
553 if (gl_texture_anisotropy.integer > 1 && i == 5)
554 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
555 for (pool = gltexturepoolchain;pool;pool = pool->next)
557 for (glt = pool->gltchain;glt;glt = glt->chain)
559 // only update already uploaded images
560 if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
562 if (glt->flags & TEXF_MIPMAP)
564 glt->d3dminfilter = d3d_filter_mipmin;
565 glt->d3dmagfilter = d3d_filter_mipmag;
566 glt->d3dmipfilter = d3d_filter_mipmix;
567 glt->d3dmaxmiplevelfilter = 0;
571 glt->d3dminfilter = d3d_filter_flatmin;
572 glt->d3dmagfilter = d3d_filter_flatmag;
573 glt->d3dmipfilter = d3d_filter_flatmix;
574 glt->d3dmaxmiplevelfilter = 0;
581 case RENDERPATH_D3D10:
582 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
584 case RENDERPATH_D3D11:
585 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
587 case RENDERPATH_SOFT:
588 // change all the existing texture objects
589 for (pool = gltexturepoolchain;pool;pool = pool->next)
590 for (glt = pool->gltchain;glt;glt = glt->chain)
591 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
592 DPSOFTRAST_Texture_Filter(glt->texnum, (glt->flags & TEXF_MIPMAP) ? dpsoftrast_filter_mipmap : dpsoftrast_filter_nomipmap);
597 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)
599 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
604 case GLTEXTURETYPE_2D:
605 maxsize = vid.maxtexturesize_2d;
606 if (flags & TEXF_PICMIP)
608 maxsize = bound(1, gl_max_size.integer, maxsize);
612 case GLTEXTURETYPE_3D:
613 maxsize = vid.maxtexturesize_3d;
615 case GLTEXTURETYPE_CUBEMAP:
616 maxsize = vid.maxtexturesize_cubemap;
620 if (vid.support.arb_texture_non_power_of_two)
622 width2 = min(inwidth >> picmip, maxsize);
623 height2 = min(inheight >> picmip, maxsize);
624 depth2 = min(indepth >> picmip, maxsize);
628 for (width2 = 1;width2 < inwidth;width2 <<= 1);
629 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
630 for (height2 = 1;height2 < inheight;height2 <<= 1);
631 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
632 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
633 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
636 switch(vid.renderpath)
638 case RENDERPATH_GL11:
639 case RENDERPATH_GL13:
640 case RENDERPATH_GL20:
641 case RENDERPATH_D3D10:
642 case RENDERPATH_D3D11:
643 case RENDERPATH_SOFT:
644 case RENDERPATH_GLES1:
645 case RENDERPATH_GLES2:
647 case RENDERPATH_D3D9:
649 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
650 if (texturetype == GLTEXTURETYPE_2D)
652 width2 = max(width2, 2);
653 height2 = max(height2, 2);
660 if (flags & TEXF_MIPMAP)
662 int extent = max(width2, max(height2, depth2));
668 *outwidth = max(1, width2);
670 *outheight = max(1, height2);
672 *outdepth = max(1, depth2);
674 *outmiplevels = miplevels;
678 static int R_CalcTexelDataSize (gltexture_t *glt)
680 int width2, height2, depth2, size;
682 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
684 size = width2 * height2 * depth2;
686 if (glt->flags & TEXF_MIPMAP)
688 while (width2 > 1 || height2 > 1 || depth2 > 1)
696 size += width2 * height2 * depth2;
700 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
703 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
707 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
708 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
710 gltexturepool_t *pool;
712 Con_Print("glsize input loaded mip alpha name\n");
713 for (pool = gltexturepoolchain;pool;pool = pool->next)
721 for (glt = pool->gltchain;glt;glt = glt->chain)
723 glsize = R_CalcTexelDataSize(glt);
724 isloaded = glt->texnum != 0;
726 pooltotalt += glsize;
727 pooltotalp += glt->inputdatasize;
731 poolloadedt += glsize;
732 poolloadedp += glt->inputdatasize;
735 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);
738 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);
739 sumtotal += pooltotal;
740 sumtotalt += pooltotalt;
741 sumtotalp += pooltotalp;
742 sumloaded += poolloaded;
743 sumloadedt += poolloadedt;
744 sumloadedp += poolloadedp;
747 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);
750 static void R_TextureStats_f(void)
752 R_TextureStats_Print(true, true, true);
755 static void r_textures_start(void)
757 switch(vid.renderpath)
759 case RENDERPATH_GL11:
760 case RENDERPATH_GL13:
761 case RENDERPATH_GL20:
762 case RENDERPATH_GLES1:
763 case RENDERPATH_GLES2:
764 // LordHavoc: allow any alignment
766 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
767 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
769 case RENDERPATH_D3D9:
771 case RENDERPATH_D3D10:
772 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
774 case RENDERPATH_D3D11:
775 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
777 case RENDERPATH_SOFT:
781 texturemempool = Mem_AllocPool("texture management", 0, NULL);
782 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
784 // Disable JPEG screenshots if the DLL isn't loaded
785 if (! JPEG_OpenLibrary ())
786 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
787 if (! PNG_OpenLibrary ())
788 Cvar_SetValueQuick (&scr_screenshot_png, 0);
791 static void r_textures_shutdown(void)
793 rtexturepool_t *temp;
795 JPEG_CloseLibrary ();
797 while(gltexturepoolchain)
799 temp = (rtexturepool_t *) gltexturepoolchain;
800 R_FreeTexturePool(&temp);
803 resizebuffersize = 0;
805 colorconvertbuffer = NULL;
806 texturebuffer = NULL;
807 Mem_ExpandableArray_FreeArray(&texturearray);
808 Mem_FreePool(&texturemempool);
811 static void r_textures_newmap(void)
815 static void r_textures_devicelost(void)
819 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
820 for (i = 0;i < endindex;i++)
822 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
823 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
825 switch(vid.renderpath)
827 case RENDERPATH_GL11:
828 case RENDERPATH_GL13:
829 case RENDERPATH_GL20:
830 case RENDERPATH_GLES1:
831 case RENDERPATH_GLES2:
833 case RENDERPATH_D3D9:
835 if (glt->d3disdepthsurface)
836 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
837 else if (glt->tiledepth > 1)
838 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
839 else if (glt->sides == 6)
840 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
842 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
843 glt->d3dtexture = NULL;
846 case RENDERPATH_D3D10:
847 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
849 case RENDERPATH_D3D11:
850 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
852 case RENDERPATH_SOFT:
858 static void r_textures_devicerestored(void)
862 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
863 for (i = 0;i < endindex;i++)
865 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
866 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
868 switch(vid.renderpath)
870 case RENDERPATH_GL11:
871 case RENDERPATH_GL13:
872 case RENDERPATH_GL20:
873 case RENDERPATH_GLES1:
874 case RENDERPATH_GLES2:
876 case RENDERPATH_D3D9:
880 if (glt->d3disdepthsurface)
882 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
883 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
885 else if (glt->tiledepth > 1)
887 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)))
888 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
890 else if (glt->sides == 6)
892 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
893 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
897 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)))
898 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
903 case RENDERPATH_D3D10:
904 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
906 case RENDERPATH_D3D11:
907 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
909 case RENDERPATH_SOFT:
916 void R_Textures_Init (void)
918 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");
919 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
920 Cvar_RegisterVariable (&gl_max_size);
921 Cvar_RegisterVariable (&gl_picmip);
922 Cvar_RegisterVariable (&gl_picmip_world);
923 Cvar_RegisterVariable (&r_picmipworld);
924 Cvar_RegisterVariable (&gl_picmip_sprites);
925 Cvar_RegisterVariable (&r_picmipsprites);
926 Cvar_RegisterVariable (&gl_picmip_other);
927 Cvar_RegisterVariable (&gl_max_lightmapsize);
928 Cvar_RegisterVariable (&r_lerpimages);
929 Cvar_RegisterVariable (&gl_texture_anisotropy);
930 Cvar_RegisterVariable (&gl_texturecompression);
931 Cvar_RegisterVariable (&gl_texturecompression_color);
932 Cvar_RegisterVariable (&gl_texturecompression_normal);
933 Cvar_RegisterVariable (&gl_texturecompression_gloss);
934 Cvar_RegisterVariable (&gl_texturecompression_glow);
935 Cvar_RegisterVariable (&gl_texturecompression_2d);
936 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
937 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
938 Cvar_RegisterVariable (&gl_texturecompression_sky);
939 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
940 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
941 Cvar_RegisterVariable (&gl_texturecompression_sprites);
942 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
943 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
944 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
945 Cvar_RegisterVariable (&r_texture_dds_swdecode);
947 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
950 void R_Textures_Frame (void)
952 static int old_aniso = 0;
954 // could do procedural texture animation here, if we keep track of which
955 // textures were accessed this frame...
957 // free the resize buffers
958 resizebuffersize = 0;
961 Mem_Free(resizebuffer);
964 if (colorconvertbuffer)
966 Mem_Free(colorconvertbuffer);
967 colorconvertbuffer = NULL;
970 if (old_aniso != gl_texture_anisotropy.integer)
973 gltexturepool_t *pool;
976 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
978 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
980 switch(vid.renderpath)
982 case RENDERPATH_GL11:
983 case RENDERPATH_GL13:
984 case RENDERPATH_GL20:
985 case RENDERPATH_GLES1:
986 case RENDERPATH_GLES2:
989 for (pool = gltexturepoolchain;pool;pool = pool->next)
991 for (glt = pool->gltchain;glt;glt = glt->chain)
993 // only update already uploaded images
994 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
996 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
998 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
999 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
1001 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1006 case RENDERPATH_D3D9:
1007 case RENDERPATH_D3D10:
1008 case RENDERPATH_D3D11:
1009 case RENDERPATH_SOFT:
1015 void R_MakeResizeBufferBigger(int size)
1017 if (resizebuffersize < size)
1019 resizebuffersize = size;
1021 Mem_Free(resizebuffer);
1022 if (colorconvertbuffer)
1023 Mem_Free(colorconvertbuffer);
1024 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
1025 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
1026 if (!resizebuffer || !colorconvertbuffer)
1027 Host_Error("R_Upload: out of memory");
1031 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
1033 int textureenum = gltexturetypeenums[texturetype];
1034 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
1038 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
1040 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
1041 if (gl_texture_anisotropy.integer != aniso)
1042 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
1043 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
1045 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
1046 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
1047 #ifdef GL_TEXTURE_WRAP_R
1048 if (gltexturetypedimensions[texturetype] >= 3)
1050 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
1055 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
1057 if (flags & TEXF_MIPMAP)
1059 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
1063 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
1065 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
1067 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
1069 if (flags & TEXF_MIPMAP)
1071 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
1073 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
1077 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
1082 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
1084 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
1088 if (flags & TEXF_MIPMAP)
1090 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1094 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1096 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1100 if (textype == TEXTYPE_SHADOWMAP)
1102 if (vid.support.arb_shadow)
1104 if (flags & TEXF_COMPARE)
1106 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1110 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1112 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1114 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1121 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1124 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1126 if (glt->texturetype != GLTEXTURETYPE_2D)
1127 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1129 if (glt->textype->textype == TEXTYPE_PALETTE)
1130 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1132 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1133 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1135 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1136 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1138 // update a portion of the image
1140 switch(vid.renderpath)
1142 case RENDERPATH_GL11:
1143 case RENDERPATH_GL13:
1144 case RENDERPATH_GL20:
1145 case RENDERPATH_GLES1:
1146 case RENDERPATH_GLES2:
1150 // we need to restore the texture binding after finishing the upload
1151 GL_ActiveTexture(0);
1152 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1153 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1154 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1155 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1158 case RENDERPATH_D3D9:
1162 D3DLOCKED_RECT d3dlockedrect;
1164 memset(&d3drect, 0, sizeof(d3drect));
1165 d3drect.left = fragx;
1166 d3drect.top = fragy;
1167 d3drect.right = fragx+fragwidth;
1168 d3drect.bottom = fragy+fragheight;
1169 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1171 for (y = 0;y < fragheight;y++)
1172 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1173 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1178 case RENDERPATH_D3D10:
1179 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1181 case RENDERPATH_D3D11:
1182 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1184 case RENDERPATH_SOFT:
1185 DPSOFTRAST_Texture_UpdatePartial(glt->texnum, 0, data, fragx, fragy, fragwidth, fragheight);
1190 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1192 int i, mip = 0, width, height, depth;
1193 GLint oldbindtexnum = 0;
1194 const unsigned char *prevbuffer;
1197 // error out if a stretch is needed on special texture types
1198 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1199 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1201 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1202 // of the target size and then use the mipmap reduction function to get
1203 // high quality supersampled results
1204 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1205 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1206 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1207 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1209 if (prevbuffer == NULL)
1211 width = glt->tilewidth;
1212 height = glt->tileheight;
1213 depth = glt->tiledepth;
1214 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1215 // prevbuffer = resizebuffer;
1219 if (glt->textype->textype == TEXTYPE_PALETTE)
1221 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1222 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1223 prevbuffer = colorconvertbuffer;
1225 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1227 // multiply RGB channels by A channel before uploading
1229 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1231 alpha = prevbuffer[i+3];
1232 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1233 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1234 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1235 colorconvertbuffer[i+3] = alpha;
1237 prevbuffer = colorconvertbuffer;
1239 // scale up to a power of 2 size (if appropriate)
1240 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1242 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1243 prevbuffer = resizebuffer;
1245 // apply mipmap reduction algorithm to get down to picmip/max_size
1246 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1248 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1249 prevbuffer = resizebuffer;
1253 // do the appropriate upload type...
1254 switch(vid.renderpath)
1256 case RENDERPATH_GL11:
1257 case RENDERPATH_GL13:
1258 case RENDERPATH_GL20:
1259 case RENDERPATH_GLES1:
1260 case RENDERPATH_GLES2:
1263 // we need to restore the texture binding after finishing the upload
1264 GL_ActiveTexture(0);
1265 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1266 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1268 #ifdef GL_TEXTURE_COMPRESSION_HINT_ARB
1269 if (qglGetCompressedTexImageARB)
1271 if (gl_texturecompression.integer >= 2)
1272 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1274 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1278 switch(glt->texturetype)
1280 case GLTEXTURETYPE_2D:
1281 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1282 if (glt->flags & TEXF_MIPMAP)
1284 while (width > 1 || height > 1 || depth > 1)
1286 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1287 prevbuffer = resizebuffer;
1288 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1292 case GLTEXTURETYPE_3D:
1294 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1295 if (glt->flags & TEXF_MIPMAP)
1297 while (width > 1 || height > 1 || depth > 1)
1299 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1300 prevbuffer = resizebuffer;
1301 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1306 case GLTEXTURETYPE_CUBEMAP:
1307 // convert and upload each side in turn,
1308 // from a continuous block of input texels
1309 texturebuffer = (unsigned char *)prevbuffer;
1310 for (i = 0;i < 6;i++)
1312 prevbuffer = texturebuffer;
1313 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1314 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1316 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1317 prevbuffer = resizebuffer;
1320 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1322 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1323 prevbuffer = resizebuffer;
1326 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1327 if (glt->flags & TEXF_MIPMAP)
1329 while (width > 1 || height > 1 || depth > 1)
1331 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1332 prevbuffer = resizebuffer;
1333 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1339 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1340 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1342 case RENDERPATH_D3D9:
1344 if (!(glt->flags & TEXF_RENDERTARGET))
1346 D3DLOCKED_RECT d3dlockedrect;
1347 D3DLOCKED_BOX d3dlockedbox;
1348 switch(glt->texturetype)
1350 case GLTEXTURETYPE_2D:
1351 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1354 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1356 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1357 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1360 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1362 while (width > 1 || height > 1 || depth > 1)
1364 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1365 prevbuffer = resizebuffer;
1366 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1368 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1369 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1375 case GLTEXTURETYPE_3D:
1376 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1378 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1379 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1380 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1383 if (glt->flags & TEXF_MIPMAP)
1385 while (width > 1 || height > 1 || depth > 1)
1387 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1388 prevbuffer = resizebuffer;
1389 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1391 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1392 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1393 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1399 case GLTEXTURETYPE_CUBEMAP:
1400 // convert and upload each side in turn,
1401 // from a continuous block of input texels
1402 texturebuffer = (unsigned char *)prevbuffer;
1403 for (i = 0;i < 6;i++)
1405 prevbuffer = texturebuffer;
1406 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1407 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1409 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1410 prevbuffer = resizebuffer;
1413 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1415 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1416 prevbuffer = resizebuffer;
1419 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1421 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1422 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1425 if (glt->flags & TEXF_MIPMAP)
1427 while (width > 1 || height > 1 || depth > 1)
1429 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1430 prevbuffer = resizebuffer;
1431 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1433 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1434 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1443 glt->d3daddressw = 0;
1444 if (glt->flags & TEXF_CLAMP)
1446 glt->d3daddressu = D3DTADDRESS_CLAMP;
1447 glt->d3daddressv = D3DTADDRESS_CLAMP;
1448 if (glt->tiledepth > 1)
1449 glt->d3daddressw = D3DTADDRESS_CLAMP;
1453 glt->d3daddressu = D3DTADDRESS_WRAP;
1454 glt->d3daddressv = D3DTADDRESS_WRAP;
1455 if (glt->tiledepth > 1)
1456 glt->d3daddressw = D3DTADDRESS_WRAP;
1458 glt->d3dmipmaplodbias = 0;
1459 glt->d3dmaxmiplevel = 0;
1460 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1461 if (glt->flags & TEXF_FORCELINEAR)
1463 glt->d3dminfilter = D3DTEXF_LINEAR;
1464 glt->d3dmagfilter = D3DTEXF_LINEAR;
1465 glt->d3dmipfilter = D3DTEXF_POINT;
1467 else if (glt->flags & TEXF_FORCENEAREST)
1469 glt->d3dminfilter = D3DTEXF_POINT;
1470 glt->d3dmagfilter = D3DTEXF_POINT;
1471 glt->d3dmipfilter = D3DTEXF_POINT;
1473 else if (glt->flags & TEXF_MIPMAP)
1475 glt->d3dminfilter = d3d_filter_mipmin;
1476 glt->d3dmagfilter = d3d_filter_mipmag;
1477 glt->d3dmipfilter = d3d_filter_mipmix;
1481 glt->d3dminfilter = d3d_filter_flatmin;
1482 glt->d3dmagfilter = d3d_filter_flatmag;
1483 glt->d3dmipfilter = d3d_filter_flatmix;
1487 case RENDERPATH_D3D10:
1488 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1490 case RENDERPATH_D3D11:
1491 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1493 case RENDERPATH_SOFT:
1494 switch(glt->texturetype)
1496 case GLTEXTURETYPE_2D:
1497 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1499 case GLTEXTURETYPE_3D:
1500 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1502 case GLTEXTURETYPE_CUBEMAP:
1503 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1505 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1506 // convert and upload each side in turn,
1507 // from a continuous block of input texels
1508 // copy the results into combinedbuffer
1509 texturebuffer = (unsigned char *)prevbuffer;
1510 for (i = 0;i < 6;i++)
1512 prevbuffer = texturebuffer;
1513 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1514 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1516 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1517 prevbuffer = resizebuffer;
1520 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1522 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1523 prevbuffer = resizebuffer;
1525 memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1527 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1528 Mem_Free(combinedbuffer);
1531 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1534 if (glt->flags & TEXF_FORCELINEAR)
1535 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1536 else if (glt->flags & TEXF_FORCENEAREST)
1537 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1538 else if (glt->flags & TEXF_MIPMAP)
1539 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1541 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1546 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)
1550 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1551 textypeinfo_t *texinfo, *texinfo2;
1552 unsigned char *temppixels = NULL;
1555 if (cls.state == ca_dedicated)
1558 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1559 if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1561 int numpixels = width * height * depth * sides;
1562 size = numpixels * 4;
1563 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1566 const unsigned char *p;
1567 unsigned char *o = temppixels;
1568 for (i = 0;i < numpixels;i++, o += 4)
1570 p = (const unsigned char *)palette + 4*data[i];
1578 textype = TEXTYPE_RGBA;
1583 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1584 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1585 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1586 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1592 static int rgbaswapindices[4] = {2, 1, 0, 3};
1593 size = width * height * depth * sides * 4;
1594 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1596 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1600 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1601 if (!vid.support.ext_texture_srgb)
1603 qboolean convertsRGB = false;
1606 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1607 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1608 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1609 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1610 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;convertsRGB = true;break;
1611 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1612 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1616 if (convertsRGB && data)
1618 size = width * height * depth * sides * 4;
1621 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1622 memcpy(temppixels, data, size);
1624 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1628 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1630 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1633 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1635 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1639 texinfo = R_GetTexTypeInfo(textype, flags);
1640 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1643 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1647 // clear the alpha flag if the texture has no transparent pixels
1650 case TEXTYPE_PALETTE:
1651 case TEXTYPE_SRGB_PALETTE:
1652 if (flags & TEXF_ALPHA)
1654 flags &= ~TEXF_ALPHA;
1657 for (i = 0;i < size;i++)
1659 if (((unsigned char *)&palette[data[i]])[3] < 255)
1661 flags |= TEXF_ALPHA;
1670 case TEXTYPE_SRGB_RGBA:
1671 case TEXTYPE_SRGB_BGRA:
1672 if (flags & TEXF_ALPHA)
1674 flags &= ~TEXF_ALPHA;
1677 for (i = 3;i < size;i += 4)
1681 flags |= TEXF_ALPHA;
1688 case TEXTYPE_SHADOWMAP:
1691 case TEXTYPE_SRGB_DXT1:
1694 case TEXTYPE_SRGB_DXT1A:
1696 case TEXTYPE_SRGB_DXT3:
1698 case TEXTYPE_SRGB_DXT5:
1699 flags |= TEXF_ALPHA;
1702 flags |= TEXF_ALPHA;
1704 case TEXTYPE_COLORBUFFER:
1705 case TEXTYPE_COLORBUFFER16F:
1706 case TEXTYPE_COLORBUFFER32F:
1707 flags |= TEXF_ALPHA;
1710 Sys_Error("R_LoadTexture: unknown texture type");
1713 texinfo2 = R_GetTexTypeInfo(textype, flags);
1714 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1717 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1719 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1721 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1723 glt->chain = pool->gltchain;
1724 pool->gltchain = glt;
1725 glt->inputwidth = width;
1726 glt->inputheight = height;
1727 glt->inputdepth = depth;
1729 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
1730 glt->textype = texinfo;
1731 glt->texturetype = texturetype;
1732 glt->inputdatasize = size;
1733 glt->palette = palette;
1734 glt->glinternalformat = texinfo->glinternalformat;
1735 glt->glformat = texinfo->glformat;
1736 glt->gltype = texinfo->gltype;
1737 glt->bytesperpixel = texinfo->internalbytesperpixel;
1738 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1741 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1742 // init the dynamic texture attributes, too [11/22/2007 Black]
1743 glt->updatecallback = NULL;
1744 glt->updatacallback_data = NULL;
1746 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1748 // upload the texture
1749 // data may be NULL (blank texture for dynamic rendering)
1750 switch(vid.renderpath)
1752 case RENDERPATH_GL11:
1753 case RENDERPATH_GL13:
1754 case RENDERPATH_GL20:
1755 case RENDERPATH_GLES1:
1756 case RENDERPATH_GLES2:
1758 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1760 case RENDERPATH_D3D9:
1763 D3DFORMAT d3dformat;
1768 d3dpool = D3DPOOL_MANAGED;
1769 if (flags & TEXF_RENDERTARGET)
1771 d3dusage |= D3DUSAGE_RENDERTARGET;
1772 d3dpool = D3DPOOL_DEFAULT;
1776 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1777 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1778 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1779 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
1780 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
1781 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
1782 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1783 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1784 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1786 glt->d3dformat = d3dformat;
1787 glt->d3dusage = d3dusage;
1788 glt->d3dpool = d3dpool;
1789 glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1790 if (glt->d3disdepthsurface)
1792 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1793 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1795 else if (glt->tiledepth > 1)
1797 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)))
1798 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1800 else if (glt->sides == 6)
1802 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1803 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1807 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)))
1808 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1813 case RENDERPATH_D3D10:
1814 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1816 case RENDERPATH_D3D11:
1817 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1819 case RENDERPATH_SOFT:
1824 case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1825 case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1826 case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1827 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1828 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
1829 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
1830 case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1831 case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1832 default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1834 if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1835 if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1836 if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1837 if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1838 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1843 R_UploadFullTexture(glt, data);
1844 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1845 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1847 // free any temporary processing buffer we allocated...
1849 Mem_Free(temppixels);
1851 // texture converting and uploading can take a while, so make sure we're sending keepalives
1852 // FIXME: this causes rendering during R_Shadow_DrawLights
1853 // CL_KeepaliveMessage(false);
1855 return (rtexture_t *)glt;
1858 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)
1860 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1863 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)
1865 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1868 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)
1870 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1873 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1875 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1877 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1879 flags |= TEXF_FORCENEAREST;
1880 if (precision <= 16)
1881 flags |= TEXF_LOWPRECISION;
1885 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1887 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1890 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1893 return -1; // unsupported on this platform
1895 gltexture_t *glt = (gltexture_t *)rt;
1898 int bytesperpixel = 0;
1899 int bytesperblock = 0;
1901 int dds_format_flags;
1909 GLint internalformat;
1910 const char *ddsfourcc;
1912 return -1; // NULL pointer
1913 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1914 return -2; // broken driver - crashes on reading internal format
1915 if (!qglGetTexLevelParameteriv)
1917 GL_ActiveTexture(0);
1918 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1919 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1920 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1921 switch(internalformat)
1923 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1924 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1925 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1926 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1927 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1929 // if premultiplied alpha, say so in the DDS file
1930 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1932 switch(internalformat)
1934 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1935 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1938 if (!bytesperblock && skipuncompressed)
1939 return -3; // skipped
1940 memset(mipinfo, 0, sizeof(mipinfo));
1941 mipinfo[0][0] = glt->tilewidth;
1942 mipinfo[0][1] = glt->tileheight;
1944 if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tilewidth == 1))
1946 for (mip = 1;mip < 16;mip++)
1948 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1949 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1950 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1958 for (mip = 0;mip < mipmaps;mip++)
1960 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1961 mipinfo[mip][3] = ddssize;
1962 ddssize += mipinfo[mip][2];
1964 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1967 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1971 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1972 dds_format_flags = 0x4; // DDPF_FOURCC
1976 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1977 dds_format_flags = 0x40; // DDPF_RGB
1981 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1982 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1985 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1986 memcpy(dds, "DDS ", 4);
1987 StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
1988 StoreLittleLong(dds+8, dds_flags);
1989 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1990 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1991 StoreLittleLong(dds+24, 0); // depth
1992 StoreLittleLong(dds+28, mipmaps); // mipmaps
1993 StoreLittleLong(dds+76, 32); // format size
1994 StoreLittleLong(dds+80, dds_format_flags);
1995 StoreLittleLong(dds+108, dds_caps1);
1996 StoreLittleLong(dds+112, dds_caps2);
1999 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
2000 memcpy(dds+84, ddsfourcc, 4);
2001 for (mip = 0;mip < mipmaps;mip++)
2003 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
2008 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
2009 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
2010 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
2011 for (mip = 0;mip < mipmaps;mip++)
2013 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
2016 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2017 ret = FS_WriteFile(filename, dds, ddssize);
2019 return ret ? ddssize : -5;
2023 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
2025 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
2028 int bytesperblock, bytesperpixel;
2031 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
2032 textypeinfo_t *texinfo;
2033 int mip, mipwidth, mipheight, mipsize, mipsize_total;
2034 unsigned int c, r, g, b;
2035 GLint oldbindtexnum = 0;
2036 unsigned char *mippixels;
2037 unsigned char *mippixels_start;
2038 unsigned char *ddspixels;
2040 fs_offset_t ddsfilesize;
2041 unsigned int ddssize;
2042 qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
2044 if (cls.state == ca_dedicated)
2047 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
2048 ddssize = ddsfilesize;
2052 if(r_texture_dds_load_logfailure.integer)
2053 Log_Printf("ddstexturefailures.log", "%s\n", filename);
2054 return NULL; // not found
2057 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
2060 Con_Printf("^1%s: not a DDS image\n", filename);
2064 //dds_flags = BuffLittleLong(dds+8);
2065 dds_format_flags = BuffLittleLong(dds+80);
2066 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
2067 dds_width = BuffLittleLong(dds+16);
2068 dds_height = BuffLittleLong(dds+12);
2069 ddspixels = dds + 128;
2071 if(r_texture_dds_load_alphamode.integer == 0)
2072 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
2073 flags &= ~TEXF_ALPHA;
2075 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
2076 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
2078 // very sloppy BGRA 32bit identification
2079 textype = TEXTYPE_BGRA;
2080 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2083 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
2084 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2087 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
2090 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
2093 for (i = 3;i < size;i += 4)
2094 if (ddspixels[i] < 255)
2097 flags &= ~TEXF_ALPHA;
2100 else if (!memcmp(dds+84, "DXT1", 4))
2102 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
2103 // LordHavoc: it is my belief that this does not infringe on the
2104 // patent because it is not decoding pixels...
2105 textype = TEXTYPE_DXT1;
2108 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
2109 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2110 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2113 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
2116 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
2118 if(r_texture_dds_load_alphamode.integer == 1)
2121 for (i = 0;i < size;i += bytesperblock)
2122 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
2124 // NOTE: this assumes sizeof(unsigned int) == 4
2125 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
2126 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
2127 if(data & (data<<1) & 0xAAAAAAAA)//rgh
2131 textype = TEXTYPE_DXT1A;
2133 flags &= ~TEXF_ALPHA;
2137 flags &= ~TEXF_ALPHA;
2141 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2143 if(!memcmp(dds+84, "DXT2", 4))
2145 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2147 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2152 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2154 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2157 textype = TEXTYPE_DXT3;
2160 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2161 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2164 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2167 // we currently always assume alpha
2169 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2171 if(!memcmp(dds+84, "DXT4", 4))
2173 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2175 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2180 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2182 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2185 textype = TEXTYPE_DXT5;
2188 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2189 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2192 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2195 // we currently always assume alpha
2200 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2204 // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
2205 if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
2207 textype = TEXTYPE_DXT1;
2211 for (i = 0;i < (int)ddssize;i += bytesperblock)
2212 memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
2216 force_swdecode = false;
2219 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
2221 if(r_texture_dds_swdecode.integer > 1)
2222 force_swdecode = true;
2226 if(r_texture_dds_swdecode.integer < 1)
2232 force_swdecode = true;
2236 // return whether this texture is transparent
2238 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2240 // if we SW decode, choose 2 sizes bigger
2243 // this is quarter res, so do not scale down more than we have to
2247 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2250 // this is where we apply gl_picmip
2251 mippixels_start = ddspixels;
2252 mipwidth = dds_width;
2253 mipheight = dds_height;
2254 while(miplevel >= 1 && dds_miplevels >= 1)
2256 if (mipwidth <= 1 && mipheight <= 1)
2258 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2259 mippixels_start += mipsize; // just skip
2267 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2268 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2270 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2272 // fake decode S3TC if needed
2275 int mipsize_new = mipsize_total / bytesperblock * 4;
2276 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2277 unsigned char *p = mipnewpixels;
2278 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2280 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2281 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2282 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2283 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2284 if(textype == TEXTYPE_DXT5)
2285 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2286 else if(textype == TEXTYPE_DXT3)
2288 (mippixels_start[i-8] & 0x0F)
2289 + (mippixels_start[i-8] >> 4)
2290 + (mippixels_start[i-7] & 0x0F)
2291 + (mippixels_start[i-7] >> 4)
2292 + (mippixels_start[i-6] & 0x0F)
2293 + (mippixels_start[i-6] >> 4)
2294 + (mippixels_start[i-5] & 0x0F)
2295 + (mippixels_start[i-5] >> 4)
2296 ) * (0.125f / 15.0f * 255.0f);
2301 textype = TEXTYPE_BGRA;
2305 // as each block becomes a pixel, we must use pixel count for this
2306 mipwidth = (mipwidth + 3) / 4;
2307 mipheight = (mipheight + 3) / 4;
2308 mipsize = bytesperpixel * mipwidth * mipheight;
2309 mippixels_start = mipnewpixels;
2310 mipsize_total = mipsize_new;
2313 // start mip counting
2314 mippixels = mippixels_start;
2316 // calculate average color if requested
2320 Vector4Clear(avgcolor);
2323 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2325 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2326 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2327 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2328 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2329 if(textype == TEXTYPE_DXT5)
2330 avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2331 else if(textype == TEXTYPE_DXT3)
2333 (mippixels_start[i-8] & 0x0F)
2334 + (mippixels_start[i-8] >> 4)
2335 + (mippixels_start[i-7] & 0x0F)
2336 + (mippixels_start[i-7] >> 4)
2337 + (mippixels_start[i-6] & 0x0F)
2338 + (mippixels_start[i-6] >> 4)
2339 + (mippixels_start[i-5] & 0x0F)
2340 + (mippixels_start[i-5] >> 4)
2341 ) * (0.125f / 15.0f * 255.0f);
2345 f = (float)bytesperblock / size;
2346 avgcolor[0] *= (0.5f / 31.0f) * f;
2347 avgcolor[1] *= (0.5f / 63.0f) * f;
2348 avgcolor[2] *= (0.5f / 31.0f) * f;
2353 for (i = 0;i < mipsize;i += 4)
2355 avgcolor[0] += mippixels[i+2];
2356 avgcolor[1] += mippixels[i+1];
2357 avgcolor[2] += mippixels[i];
2358 avgcolor[3] += mippixels[i+3];
2360 f = (1.0f / 255.0f) * bytesperpixel / size;
2368 // if we want sRGB, convert now
2371 if (vid.support.ext_texture_srgb)
2375 case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break;
2376 case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break;
2377 case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break;
2378 case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break;
2379 case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break;
2393 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2395 int c0, c1, c0new, c1new;
2396 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2397 r = ((c0 >> 11) & 0x1F);
2398 g = ((c0 >> 5) & 0x3F);
2400 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2401 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2402 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2403 c0new = (r << 11) | (g << 5) | b;
2404 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2405 r = ((c1 >> 11) & 0x1F);
2406 g = ((c1 >> 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 c1new = (r << 11) | (g << 5) | b;
2412 // swap the colors if needed to fix order
2413 if(c0 > c1) // thirds
2421 mippixels_start[i+4] ^= 0x55;
2422 mippixels_start[i+5] ^= 0x55;
2423 mippixels_start[i+6] ^= 0x55;
2424 mippixels_start[i+7] ^= 0x55;
2426 else if(c0new == c1new)
2428 mippixels_start[i+4] = 0x00;
2429 mippixels_start[i+5] = 0x00;
2430 mippixels_start[i+6] = 0x00;
2431 mippixels_start[i+7] = 0x00;
2434 else // half + transparent
2441 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2442 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2443 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2444 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2447 mippixels_start[i] = c0new & 255;
2448 mippixels_start[i+1] = c0new >> 8;
2449 mippixels_start[i+2] = c1new & 255;
2450 mippixels_start[i+3] = c1new >> 8;
2455 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2463 // when not requesting mipmaps, do not load them
2464 if(!(flags & TEXF_MIPMAP))
2467 if (dds_miplevels >= 1)
2468 flags |= TEXF_MIPMAP;
2470 flags &= ~TEXF_MIPMAP;
2472 texinfo = R_GetTexTypeInfo(textype, flags);
2474 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2475 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2477 glt->chain = pool->gltchain;
2478 pool->gltchain = glt;
2479 glt->inputwidth = mipwidth;
2480 glt->inputheight = mipheight;
2481 glt->inputdepth = 1;
2483 glt->textype = texinfo;
2484 glt->texturetype = GLTEXTURETYPE_2D;
2485 glt->inputdatasize = ddssize;
2486 glt->glinternalformat = texinfo->glinternalformat;
2487 glt->glformat = texinfo->glformat;
2488 glt->gltype = texinfo->gltype;
2489 glt->bytesperpixel = texinfo->internalbytesperpixel;
2491 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2492 glt->tilewidth = mipwidth;
2493 glt->tileheight = mipheight;
2495 glt->miplevels = dds_miplevels;
2497 // texture uploading can take a while, so make sure we're sending keepalives
2498 CL_KeepaliveMessage(false);
2500 // create the texture object
2501 switch(vid.renderpath)
2503 case RENDERPATH_GL11:
2504 case RENDERPATH_GL13:
2505 case RENDERPATH_GL20:
2506 case RENDERPATH_GLES1:
2507 case RENDERPATH_GLES2:
2509 GL_ActiveTexture(0);
2510 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2511 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2512 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2514 case RENDERPATH_D3D9:
2517 D3DFORMAT d3dformat;
2522 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2523 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2524 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2525 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2526 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2529 d3dpool = D3DPOOL_MANAGED;
2530 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2534 case RENDERPATH_D3D10:
2535 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2537 case RENDERPATH_D3D11:
2538 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2540 case RENDERPATH_SOFT:
2541 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);
2545 // upload the texture
2546 // we need to restore the texture binding after finishing the upload
2547 mipcomplete = false;
2549 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2551 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2552 if (mippixels + mipsize > mippixels_start + mipsize_total)
2554 switch(vid.renderpath)
2556 case RENDERPATH_GL11:
2557 case RENDERPATH_GL13:
2558 case RENDERPATH_GL20:
2559 case RENDERPATH_GLES1:
2560 case RENDERPATH_GLES2:
2563 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2567 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2570 case RENDERPATH_D3D9:
2573 D3DLOCKED_RECT d3dlockedrect;
2574 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2576 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2577 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2583 case RENDERPATH_D3D10:
2584 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2586 case RENDERPATH_D3D11:
2587 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2589 case RENDERPATH_SOFT:
2591 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2593 DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
2594 // DPSOFTRAST calculates its own mipmaps
2595 mip = dds_miplevels;
2598 mippixels += mipsize;
2599 if (mipwidth <= 1 && mipheight <= 1)
2610 // after upload we have to set some parameters...
2611 switch(vid.renderpath)
2613 case RENDERPATH_GL11:
2614 case RENDERPATH_GL13:
2615 case RENDERPATH_GL20:
2616 case RENDERPATH_GLES1:
2617 case RENDERPATH_GLES2:
2618 #ifdef GL_TEXTURE_MAX_LEVEL
2619 if (dds_miplevels >= 1 && !mipcomplete)
2621 // need to set GL_TEXTURE_MAX_LEVEL
2622 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2625 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2626 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2628 case RENDERPATH_D3D9:
2630 glt->d3daddressw = 0;
2631 if (glt->flags & TEXF_CLAMP)
2633 glt->d3daddressu = D3DTADDRESS_CLAMP;
2634 glt->d3daddressv = D3DTADDRESS_CLAMP;
2635 if (glt->tiledepth > 1)
2636 glt->d3daddressw = D3DTADDRESS_CLAMP;
2640 glt->d3daddressu = D3DTADDRESS_WRAP;
2641 glt->d3daddressv = D3DTADDRESS_WRAP;
2642 if (glt->tiledepth > 1)
2643 glt->d3daddressw = D3DTADDRESS_WRAP;
2645 glt->d3dmipmaplodbias = 0;
2646 glt->d3dmaxmiplevel = 0;
2647 glt->d3dmaxmiplevelfilter = 0;
2648 if (glt->flags & TEXF_MIPMAP)
2650 glt->d3dminfilter = d3d_filter_mipmin;
2651 glt->d3dmagfilter = d3d_filter_mipmag;
2652 glt->d3dmipfilter = d3d_filter_mipmix;
2656 glt->d3dminfilter = d3d_filter_flatmin;
2657 glt->d3dmagfilter = d3d_filter_flatmag;
2658 glt->d3dmipfilter = d3d_filter_flatmix;
2662 case RENDERPATH_D3D10:
2663 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2665 case RENDERPATH_D3D11:
2666 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2668 case RENDERPATH_SOFT:
2669 if (glt->flags & TEXF_FORCELINEAR)
2670 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2671 else if (glt->flags & TEXF_FORCENEAREST)
2672 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2673 else if (glt->flags & TEXF_MIPMAP)
2674 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2676 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2682 Mem_Free((unsigned char *) mippixels_start);
2683 return (rtexture_t *)glt;
2686 int R_TextureWidth(rtexture_t *rt)
2688 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2691 int R_TextureHeight(rtexture_t *rt)
2693 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2696 int R_TextureFlags(rtexture_t *rt)
2698 return rt ? ((gltexture_t *)rt)->flags : 0;
2701 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2703 gltexture_t *glt = (gltexture_t *)rt;
2705 Host_Error("R_UpdateTexture: no data supplied");
2707 Host_Error("R_UpdateTexture: no texture supplied");
2708 if (!glt->texnum && !glt->d3dtexture)
2710 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2713 // update part of the texture
2714 if (glt->bufferpixels)
2717 int bpp = glt->bytesperpixel;
2718 int inputskip = width*bpp;
2719 int outputskip = glt->tilewidth*bpp;
2720 const unsigned char *input = data;
2721 unsigned char *output = glt->bufferpixels;
2722 if (glt->inputdepth != 1 || glt->sides != 1)
2723 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2733 input -= y*inputskip;
2736 if (width > glt->tilewidth - x)
2737 width = glt->tilewidth - x;
2738 if (height > glt->tileheight - y)
2739 height = glt->tileheight - y;
2740 if (width < 1 || height < 1)
2743 glt->buffermodified = true;
2744 output += y*outputskip + x*bpp;
2745 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2746 memcpy(output, input, width*bpp);
2748 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2749 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2751 R_UploadFullTexture(glt, data);
2754 int R_RealGetTexture(rtexture_t *rt)
2759 glt = (gltexture_t *)rt;
2760 if (glt->flags & GLTEXF_DYNAMIC)
2761 R_UpdateDynamicTexture(glt);
2762 if (glt->buffermodified && glt->bufferpixels)
2764 glt->buffermodified = false;
2765 R_UploadFullTexture(glt, glt->bufferpixels);
2774 void R_ClearTexture (rtexture_t *rt)
2776 gltexture_t *glt = (gltexture_t *)rt;
2778 R_UploadFullTexture(glt, NULL);
2781 int R_PicmipForFlags(int flags)
2784 if(flags & TEXF_PICMIP)
2786 miplevel += gl_picmip.integer;
2787 if (flags & TEXF_ISWORLD)
2789 if (r_picmipworld.integer)
2790 miplevel += gl_picmip_world.integer;
2794 else if (flags & TEXF_ISSPRITE)
2796 if (r_picmipsprites.integer)
2797 miplevel += gl_picmip_sprites.integer;
2802 miplevel += gl_picmip_other.integer;
2804 return max(0, miplevel);