5 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
10 #include "intoverflow.h"
11 #include "dpsoftrast.h"
13 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)"};
14 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)"};
15 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%"};
16 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)"};
17 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)"};
18 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)"};
19 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)"};
20 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)"};
21 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)"};
22 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"};
23 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"};
24 cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
25 cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
26 cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
27 cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
28 cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
29 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
30 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)"};
31 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
32 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
33 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)"};
34 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"};
35 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"};
36 cvar_t r_texture_dds_load_logfailure = {0, "r_texture_dds_load_logfailure", "1", "log missing DDS textures to ddstexturefailures.log"};
37 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"};
39 qboolean gl_filter_force = false;
40 int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
41 int gl_filter_mag = GL_LINEAR;
42 DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_mipmap = DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE;
43 DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_nomipmap = DPSOFTRAST_TEXTURE_FILTER_LINEAR;
46 int d3d_filter_flatmin = D3DTEXF_LINEAR;
47 int d3d_filter_flatmag = D3DTEXF_LINEAR;
48 int d3d_filter_flatmix = D3DTEXF_POINT;
49 int d3d_filter_mipmin = D3DTEXF_LINEAR;
50 int d3d_filter_mipmag = D3DTEXF_LINEAR;
51 int d3d_filter_mipmix = D3DTEXF_LINEAR;
52 int d3d_filter_nomip = false;
56 static mempool_t *texturemempool;
57 static memexpandablearray_t texturearray;
59 // note: this must not conflict with TEXF_ flags in r_textures.h
60 // bitmask for mismatch checking
61 #define GLTEXF_IMPORTANTBITS (0)
62 // dynamic texture (treat texnum == 0 differently)
63 #define GLTEXF_DYNAMIC 0x00080000
65 typedef struct textypeinfo_s
69 int inputbytesperpixel;
70 int internalbytesperpixel;
71 float glinternalbytesperpixel;
78 // framebuffer texture formats
79 static textypeinfo_t textype_shadowmap16 = {"shadowmap16", TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
80 static textypeinfo_t textype_shadowmap24 = {"shadowmap24", TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
81 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
82 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F, 8, 8, 8.0f, GL_RGBA16F_ARB , GL_RGBA , GL_FLOAT };
83 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F, 16, 16, 16.0f, GL_RGBA32F_ARB , GL_RGBA , GL_FLOAT };
86 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
87 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
88 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
89 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE };
90 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
91 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 };
92 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 };
93 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
94 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
95 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 };
96 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 };
97 static textypeinfo_t textype_dxt1 = {"dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
98 static textypeinfo_t textype_dxt1a = {"dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 };
99 static textypeinfo_t textype_dxt3 = {"dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 };
100 static textypeinfo_t textype_dxt5 = {"dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 };
101 static textypeinfo_t textype_sRGB_palette = {"sRGB_palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
102 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 };
103 static textypeinfo_t textype_sRGB_rgba = {"sRGB_rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
104 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 };
105 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 };
106 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 };
107 static textypeinfo_t textype_sRGB_bgra = {"sRGB_bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
108 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 };
109 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 };
110 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 };
111 static textypeinfo_t textype_sRGB_dxt1 = {"sRGB_dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , 0 , 0 };
112 static textypeinfo_t textype_sRGB_dxt1a = {"sRGB_dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 , 0 };
113 static textypeinfo_t textype_sRGB_dxt3 = {"sRGB_dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 , 0 };
114 static textypeinfo_t textype_sRGB_dxt5 = {"sRGB_dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 , 0 };
116 typedef enum gltexturetype_e
120 GLTEXTURETYPE_CUBEMAP,
125 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB};
126 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
127 static int cubemapside[6] =
129 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
130 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
131 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
132 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
133 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
134 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
137 typedef struct gltexture_s
139 // this portion of the struct is exposed to the R_GetTexture macro for
140 // speed reasons, must be identical in rtexture_t!
141 int texnum; // GL texture slot number
142 qboolean dirty; // indicates that R_RealGetTexture should be called
143 int gltexturetypeenum; // used by R_Mesh_TexBind
144 // d3d stuff the backend needs
147 qboolean d3disdepthsurface; // for depth/stencil surfaces
157 int d3dmaxmiplevelfilter;
158 int d3dmipmaplodbias;
162 // dynamic texture stuff [11/22/2007 Black]
163 updatecallback_t updatecallback;
164 void *updatacallback_data;
165 // --- [11/22/2007 Black]
167 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
168 unsigned char *bufferpixels;
169 qboolean buffermodified;
171 // pointer to texturepool (check this to see if the texture is allocated)
172 struct gltexturepool_s *pool;
173 // pointer to next texture in texturepool chain
174 struct gltexture_s *chain;
175 // name of the texture (this might be removed someday), no duplicates
176 char identifier[MAX_QPATH + 32];
177 // original data size in *inputtexels
178 int inputwidth, inputheight, inputdepth;
179 // copy of the original texture(s) supplied to the upload function, for
180 // delayed uploads (non-precached)
181 unsigned char *inputtexels;
182 // original data size in *inputtexels
184 // flags supplied to the LoadTexture function
185 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
189 // pointer to one of the textype_ structs
190 textypeinfo_t *textype;
191 // one of the GLTEXTURETYPE_ values
193 // palette if the texture is TEXTYPE_PALETTE
194 const unsigned int *palette;
195 // actual stored texture size after gl_picmip and gl_max_size are applied
196 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
197 int tilewidth, tileheight, tiledepth;
198 // 1 or 6 depending on texturetype
200 // how many mipmap levels in this texture
204 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
207 int glinternalformat;
208 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
213 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
215 typedef struct gltexturepool_s
217 unsigned int sentinel;
218 struct gltexture_s *gltchain;
219 struct gltexturepool_s *next;
223 static gltexturepool_t *gltexturepoolchain = NULL;
225 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
226 static int resizebuffersize = 0;
227 static const unsigned char *texturebuffer;
229 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
233 case TEXTYPE_DXT1: return &textype_dxt1;
234 case TEXTYPE_DXT1A: return &textype_dxt1a;
235 case TEXTYPE_DXT3: return &textype_dxt3;
236 case TEXTYPE_DXT5: return &textype_dxt5;
237 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
238 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);
239 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);
240 case TEXTYPE_ALPHA: return &textype_alpha;
241 case TEXTYPE_SHADOWMAP: return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
242 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
243 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
244 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
245 case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1;
246 case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a;
247 case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
248 case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
249 case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
250 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);
251 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);
253 Host_Error("R_GetTexTypeInfo: unknown texture format");
259 // dynamic texture code [11/22/2007 Black]
260 void R_MarkDirtyTexture(rtexture_t *rt) {
261 gltexture_t *glt = (gltexture_t*) rt;
266 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
267 if (glt->flags & GLTEXF_DYNAMIC)
269 // mark it as dirty, so R_RealGetTexture gets called
274 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
275 gltexture_t *glt = (gltexture_t*) rt;
280 glt->flags |= GLTEXF_DYNAMIC;
281 glt->updatecallback = updatecallback;
282 glt->updatacallback_data = data;
285 static void R_UpdateDynamicTexture(gltexture_t *glt) {
287 if( glt->updatecallback ) {
288 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
292 void R_PurgeTexture(rtexture_t *rt)
294 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
299 void R_FreeTexture(rtexture_t *rt)
301 gltexture_t *glt, **gltpointer;
303 glt = (gltexture_t *)rt;
305 Host_Error("R_FreeTexture: texture == NULL");
307 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
308 if (*gltpointer == glt)
309 *gltpointer = glt->chain;
311 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
313 R_Mesh_ClearBindingsForTexture(glt->texnum);
315 switch(vid.renderpath)
317 case RENDERPATH_GL11:
318 case RENDERPATH_GL13:
319 case RENDERPATH_GL20:
320 case RENDERPATH_GLES1:
321 case RENDERPATH_GLES2:
325 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
328 case RENDERPATH_D3D9:
330 if (glt->d3disdepthsurface)
331 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
332 else if (glt->tiledepth > 1)
333 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
334 else if (glt->sides == 6)
335 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
337 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
338 glt->d3dtexture = NULL;
341 case RENDERPATH_D3D10:
342 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
344 case RENDERPATH_D3D11:
345 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
347 case RENDERPATH_SOFT:
349 DPSOFTRAST_Texture_Free(glt->texnum);
353 if (glt->inputtexels)
354 Mem_Free(glt->inputtexels);
355 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
358 rtexturepool_t *R_AllocTexturePool(void)
360 gltexturepool_t *pool;
361 if (texturemempool == NULL)
363 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
366 pool->next = gltexturepoolchain;
367 gltexturepoolchain = pool;
368 pool->sentinel = TEXTUREPOOL_SENTINEL;
369 return (rtexturepool_t *)pool;
372 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
374 gltexturepool_t *pool, **poolpointer;
375 if (rtexturepool == NULL)
377 if (*rtexturepool == NULL)
379 pool = (gltexturepool_t *)(*rtexturepool);
380 *rtexturepool = NULL;
381 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
382 Host_Error("R_FreeTexturePool: pool already freed");
383 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
384 if (*poolpointer == pool)
385 *poolpointer = pool->next;
387 Host_Error("R_FreeTexturePool: pool not linked");
388 while (pool->gltchain)
389 R_FreeTexture((rtexture_t *)pool->gltchain);
394 typedef struct glmode_s
397 int minification, magnification;
398 DPSOFTRAST_TEXTURE_FILTER dpsoftrastfilter_mipmap, dpsoftrastfilter_nomipmap;
402 static glmode_t modes[6] =
404 {"GL_NEAREST", GL_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
405 {"GL_LINEAR", GL_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
406 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
407 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
408 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
409 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR}
413 typedef struct d3dmode_s
420 static d3dmode_t d3dmodes[6] =
422 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
423 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
424 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
425 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
426 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
427 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
431 static void GL_TextureMode_f (void)
436 gltexturepool_t *pool;
440 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
441 for (i = 0;i < 6;i++)
443 if (gl_filter_min == modes[i].minification)
445 Con_Printf("%s\n", modes[i].name);
449 Con_Print("current filter is unknown???\n");
453 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
454 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
458 Con_Print("bad filter name\n");
462 gl_filter_min = modes[i].minification;
463 gl_filter_mag = modes[i].magnification;
464 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
466 dpsoftrast_filter_mipmap = modes[i].dpsoftrastfilter_mipmap;
467 dpsoftrast_filter_nomipmap = modes[i].dpsoftrastfilter_nomipmap;
469 switch(vid.renderpath)
471 case RENDERPATH_GL11:
472 case RENDERPATH_GL13:
473 case RENDERPATH_GL20:
474 case RENDERPATH_GLES1:
475 case RENDERPATH_GLES2:
476 // change all the existing mipmap texture objects
477 // FIXME: force renderer(/client/something?) restart instead?
480 for (pool = gltexturepoolchain;pool;pool = pool->next)
482 for (glt = pool->gltchain;glt;glt = glt->chain)
484 // only update already uploaded images
485 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
487 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
488 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
489 if (glt->flags & TEXF_MIPMAP)
491 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
495 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
497 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
498 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
503 case RENDERPATH_D3D9:
505 d3d_filter_flatmin = d3dmodes[i].m1;
506 d3d_filter_flatmag = d3dmodes[i].m1;
507 d3d_filter_flatmix = D3DTEXF_POINT;
508 d3d_filter_mipmin = d3dmodes[i].m1;
509 d3d_filter_mipmag = d3dmodes[i].m1;
510 d3d_filter_mipmix = d3dmodes[i].m2;
511 d3d_filter_nomip = i < 2;
512 if (gl_texture_anisotropy.integer > 1 && i == 5)
513 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
514 for (pool = gltexturepoolchain;pool;pool = pool->next)
516 for (glt = pool->gltchain;glt;glt = glt->chain)
518 // only update already uploaded images
519 if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
521 if (glt->flags & TEXF_MIPMAP)
523 glt->d3dminfilter = d3d_filter_mipmin;
524 glt->d3dmagfilter = d3d_filter_mipmag;
525 glt->d3dmipfilter = d3d_filter_mipmix;
526 glt->d3dmaxmiplevelfilter = 0;
530 glt->d3dminfilter = d3d_filter_flatmin;
531 glt->d3dmagfilter = d3d_filter_flatmag;
532 glt->d3dmipfilter = d3d_filter_flatmix;
533 glt->d3dmaxmiplevelfilter = 0;
540 case RENDERPATH_D3D10:
541 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
543 case RENDERPATH_D3D11:
544 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
546 case RENDERPATH_SOFT:
547 // change all the existing texture objects
548 for (pool = gltexturepoolchain;pool;pool = pool->next)
549 for (glt = pool->gltchain;glt;glt = glt->chain)
550 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
551 DPSOFTRAST_Texture_Filter(glt->texnum, (glt->flags & TEXF_MIPMAP) ? dpsoftrast_filter_mipmap : dpsoftrast_filter_nomipmap);
556 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)
558 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
563 case GLTEXTURETYPE_2D:
564 maxsize = vid.maxtexturesize_2d;
565 if (flags & TEXF_PICMIP)
567 maxsize = bound(1, gl_max_size.integer, maxsize);
571 case GLTEXTURETYPE_3D:
572 maxsize = vid.maxtexturesize_3d;
574 case GLTEXTURETYPE_CUBEMAP:
575 maxsize = vid.maxtexturesize_cubemap;
579 if (vid.support.arb_texture_non_power_of_two)
581 width2 = min(inwidth >> picmip, maxsize);
582 height2 = min(inheight >> picmip, maxsize);
583 depth2 = min(indepth >> picmip, maxsize);
587 for (width2 = 1;width2 < inwidth;width2 <<= 1);
588 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
589 for (height2 = 1;height2 < inheight;height2 <<= 1);
590 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
591 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
592 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
595 switch(vid.renderpath)
597 case RENDERPATH_GL11:
598 case RENDERPATH_GL13:
599 case RENDERPATH_GL20:
600 case RENDERPATH_D3D10:
601 case RENDERPATH_D3D11:
602 case RENDERPATH_SOFT:
603 case RENDERPATH_GLES1:
604 case RENDERPATH_GLES2:
606 case RENDERPATH_D3D9:
608 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
609 if (texturetype == GLTEXTURETYPE_2D)
611 width2 = max(width2, 2);
612 height2 = max(height2, 2);
619 if (flags & TEXF_MIPMAP)
621 int extent = max(width2, max(height2, depth2));
627 *outwidth = max(1, width2);
629 *outheight = max(1, height2);
631 *outdepth = max(1, depth2);
633 *outmiplevels = miplevels;
637 static int R_CalcTexelDataSize (gltexture_t *glt)
639 int width2, height2, depth2, size;
641 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
643 size = width2 * height2 * depth2;
645 if (glt->flags & TEXF_MIPMAP)
647 while (width2 > 1 || height2 > 1 || depth2 > 1)
655 size += width2 * height2 * depth2;
659 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
662 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
666 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
667 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
669 gltexturepool_t *pool;
671 Con_Print("glsize input loaded mip alpha name\n");
672 for (pool = gltexturepoolchain;pool;pool = pool->next)
680 for (glt = pool->gltchain;glt;glt = glt->chain)
682 glsize = R_CalcTexelDataSize(glt);
683 isloaded = glt->texnum != 0;
685 pooltotalt += glsize;
686 pooltotalp += glt->inputdatasize;
690 poolloadedt += glsize;
691 poolloadedp += glt->inputdatasize;
694 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);
697 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);
698 sumtotal += pooltotal;
699 sumtotalt += pooltotalt;
700 sumtotalp += pooltotalp;
701 sumloaded += poolloaded;
702 sumloadedt += poolloadedt;
703 sumloadedp += poolloadedp;
706 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);
709 static void R_TextureStats_f(void)
711 R_TextureStats_Print(true, true, true);
714 static void r_textures_start(void)
716 switch(vid.renderpath)
718 case RENDERPATH_GL11:
719 case RENDERPATH_GL13:
720 case RENDERPATH_GL20:
721 case RENDERPATH_GLES1:
722 case RENDERPATH_GLES2:
723 // LordHavoc: allow any alignment
725 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
726 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
728 case RENDERPATH_D3D9:
730 case RENDERPATH_D3D10:
731 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
733 case RENDERPATH_D3D11:
734 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
736 case RENDERPATH_SOFT:
740 texturemempool = Mem_AllocPool("texture management", 0, NULL);
741 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
743 // Disable JPEG screenshots if the DLL isn't loaded
744 if (! JPEG_OpenLibrary ())
745 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
746 if (! PNG_OpenLibrary ())
747 Cvar_SetValueQuick (&scr_screenshot_png, 0);
750 static void r_textures_shutdown(void)
752 rtexturepool_t *temp;
754 JPEG_CloseLibrary ();
756 while(gltexturepoolchain)
758 temp = (rtexturepool_t *) gltexturepoolchain;
759 R_FreeTexturePool(&temp);
762 resizebuffersize = 0;
764 colorconvertbuffer = NULL;
765 texturebuffer = NULL;
766 Mem_ExpandableArray_FreeArray(&texturearray);
767 Mem_FreePool(&texturemempool);
770 static void r_textures_newmap(void)
774 static void r_textures_devicelost(void)
778 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
779 for (i = 0;i < endindex;i++)
781 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
782 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
784 switch(vid.renderpath)
786 case RENDERPATH_GL11:
787 case RENDERPATH_GL13:
788 case RENDERPATH_GL20:
789 case RENDERPATH_GLES1:
790 case RENDERPATH_GLES2:
792 case RENDERPATH_D3D9:
794 if (glt->d3disdepthsurface)
795 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
796 else if (glt->tiledepth > 1)
797 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
798 else if (glt->sides == 6)
799 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
801 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
802 glt->d3dtexture = NULL;
805 case RENDERPATH_D3D10:
806 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
808 case RENDERPATH_D3D11:
809 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
811 case RENDERPATH_SOFT:
817 static void r_textures_devicerestored(void)
821 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
822 for (i = 0;i < endindex;i++)
824 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
825 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
827 switch(vid.renderpath)
829 case RENDERPATH_GL11:
830 case RENDERPATH_GL13:
831 case RENDERPATH_GL20:
832 case RENDERPATH_GLES1:
833 case RENDERPATH_GLES2:
835 case RENDERPATH_D3D9:
839 if (glt->d3disdepthsurface)
841 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
842 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
844 else if (glt->tiledepth > 1)
846 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)))
847 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
849 else if (glt->sides == 6)
851 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
852 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
856 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)))
857 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
862 case RENDERPATH_D3D10:
863 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
865 case RENDERPATH_D3D11:
866 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
868 case RENDERPATH_SOFT:
875 void R_Textures_Init (void)
877 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");
878 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
879 Cvar_RegisterVariable (&gl_max_size);
880 Cvar_RegisterVariable (&gl_picmip);
881 Cvar_RegisterVariable (&gl_picmip_world);
882 Cvar_RegisterVariable (&r_picmipworld);
883 Cvar_RegisterVariable (&gl_picmip_sprites);
884 Cvar_RegisterVariable (&r_picmipsprites);
885 Cvar_RegisterVariable (&gl_picmip_other);
886 Cvar_RegisterVariable (&gl_max_lightmapsize);
887 Cvar_RegisterVariable (&r_lerpimages);
888 Cvar_RegisterVariable (&gl_texture_anisotropy);
889 Cvar_RegisterVariable (&gl_texturecompression);
890 Cvar_RegisterVariable (&gl_texturecompression_color);
891 Cvar_RegisterVariable (&gl_texturecompression_normal);
892 Cvar_RegisterVariable (&gl_texturecompression_gloss);
893 Cvar_RegisterVariable (&gl_texturecompression_glow);
894 Cvar_RegisterVariable (&gl_texturecompression_2d);
895 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
896 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
897 Cvar_RegisterVariable (&gl_texturecompression_sky);
898 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
899 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
900 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
901 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
902 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
903 Cvar_RegisterVariable (&r_texture_dds_swdecode);
905 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
908 void R_Textures_Frame (void)
910 static int old_aniso = 0;
912 // could do procedural texture animation here, if we keep track of which
913 // textures were accessed this frame...
915 // free the resize buffers
916 resizebuffersize = 0;
919 Mem_Free(resizebuffer);
922 if (colorconvertbuffer)
924 Mem_Free(colorconvertbuffer);
925 colorconvertbuffer = NULL;
928 if (old_aniso != gl_texture_anisotropy.integer)
931 gltexturepool_t *pool;
934 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
936 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
938 switch(vid.renderpath)
940 case RENDERPATH_GL11:
941 case RENDERPATH_GL13:
942 case RENDERPATH_GL20:
943 case RENDERPATH_GLES1:
944 case RENDERPATH_GLES2:
947 for (pool = gltexturepoolchain;pool;pool = pool->next)
949 for (glt = pool->gltchain;glt;glt = glt->chain)
951 // only update already uploaded images
952 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
954 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
956 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
957 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
959 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
964 case RENDERPATH_D3D9:
965 case RENDERPATH_D3D10:
966 case RENDERPATH_D3D11:
967 case RENDERPATH_SOFT:
973 void R_MakeResizeBufferBigger(int size)
975 if (resizebuffersize < size)
977 resizebuffersize = size;
979 Mem_Free(resizebuffer);
980 if (colorconvertbuffer)
981 Mem_Free(colorconvertbuffer);
982 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
983 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
984 if (!resizebuffer || !colorconvertbuffer)
985 Host_Error("R_Upload: out of memory");
989 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
991 int textureenum = gltexturetypeenums[texturetype];
992 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
996 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
998 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
999 if (gl_texture_anisotropy.integer != aniso)
1000 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
1001 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
1003 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
1004 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
1005 if (gltexturetypedimensions[texturetype] >= 3)
1007 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
1011 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
1013 if (flags & TEXF_MIPMAP)
1015 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
1019 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
1021 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
1023 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
1025 if (flags & TEXF_MIPMAP)
1027 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
1029 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
1033 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
1038 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
1040 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
1044 if (flags & TEXF_MIPMAP)
1046 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1050 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1052 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1055 if (textype == TEXTYPE_SHADOWMAP)
1057 if (vid.support.arb_shadow)
1059 if (flags & TEXF_COMPARE)
1061 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1065 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1067 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1069 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1075 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1078 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1080 if (glt->texturetype != GLTEXTURETYPE_2D)
1081 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1083 if (glt->textype->textype == TEXTYPE_PALETTE)
1084 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1086 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1087 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1089 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1090 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1092 // update a portion of the image
1094 switch(vid.renderpath)
1096 case RENDERPATH_GL11:
1097 case RENDERPATH_GL13:
1098 case RENDERPATH_GL20:
1099 case RENDERPATH_GLES1:
1100 case RENDERPATH_GLES2:
1104 // we need to restore the texture binding after finishing the upload
1105 GL_ActiveTexture(0);
1106 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1107 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1108 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1109 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1112 case RENDERPATH_D3D9:
1116 D3DLOCKED_RECT d3dlockedrect;
1118 memset(&d3drect, 0, sizeof(d3drect));
1119 d3drect.left = fragx;
1120 d3drect.top = fragy;
1121 d3drect.right = fragx+fragwidth;
1122 d3drect.bottom = fragy+fragheight;
1123 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1125 for (y = 0;y < fragheight;y++)
1126 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1127 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1132 case RENDERPATH_D3D10:
1133 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1135 case RENDERPATH_D3D11:
1136 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1138 case RENDERPATH_SOFT:
1139 DPSOFTRAST_Texture_UpdatePartial(glt->texnum, 0, data, fragx, fragy, fragwidth, fragheight);
1144 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1146 int i, mip = 0, width, height, depth;
1147 GLint oldbindtexnum = 0;
1148 const unsigned char *prevbuffer;
1151 // error out if a stretch is needed on special texture types
1152 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1153 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1155 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1156 // of the target size and then use the mipmap reduction function to get
1157 // high quality supersampled results
1158 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1159 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1160 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1161 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1163 if (prevbuffer == NULL)
1165 width = glt->tilewidth;
1166 height = glt->tileheight;
1167 depth = glt->tiledepth;
1168 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1169 // prevbuffer = resizebuffer;
1173 if (glt->textype->textype == TEXTYPE_PALETTE)
1175 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1176 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1177 prevbuffer = colorconvertbuffer;
1179 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1181 // multiply RGB channels by A channel before uploading
1183 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1185 alpha = prevbuffer[i+3];
1186 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1187 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1188 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1189 colorconvertbuffer[i+3] = alpha;
1191 prevbuffer = colorconvertbuffer;
1193 // scale up to a power of 2 size (if appropriate)
1194 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1196 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1197 prevbuffer = resizebuffer;
1199 // apply mipmap reduction algorithm to get down to picmip/max_size
1200 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1202 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1203 prevbuffer = resizebuffer;
1207 // do the appropriate upload type...
1208 switch(vid.renderpath)
1210 case RENDERPATH_GL11:
1211 case RENDERPATH_GL13:
1212 case RENDERPATH_GL20:
1213 case RENDERPATH_GLES1:
1214 case RENDERPATH_GLES2:
1217 // we need to restore the texture binding after finishing the upload
1218 GL_ActiveTexture(0);
1219 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1220 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1222 if (qglGetCompressedTexImageARB)
1224 if (gl_texturecompression.integer >= 2)
1225 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1227 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1230 switch(glt->texturetype)
1232 case GLTEXTURETYPE_2D:
1233 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1234 if (glt->flags & TEXF_MIPMAP)
1236 while (width > 1 || height > 1 || depth > 1)
1238 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1239 prevbuffer = resizebuffer;
1240 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1244 case GLTEXTURETYPE_3D:
1245 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1246 if (glt->flags & TEXF_MIPMAP)
1248 while (width > 1 || height > 1 || depth > 1)
1250 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1251 prevbuffer = resizebuffer;
1252 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1256 case GLTEXTURETYPE_CUBEMAP:
1257 // convert and upload each side in turn,
1258 // from a continuous block of input texels
1259 texturebuffer = (unsigned char *)prevbuffer;
1260 for (i = 0;i < 6;i++)
1262 prevbuffer = texturebuffer;
1263 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1264 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1266 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1267 prevbuffer = resizebuffer;
1270 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1272 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1273 prevbuffer = resizebuffer;
1276 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1277 if (glt->flags & TEXF_MIPMAP)
1279 while (width > 1 || height > 1 || depth > 1)
1281 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1282 prevbuffer = resizebuffer;
1283 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1289 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1290 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1292 case RENDERPATH_D3D9:
1294 if (!(glt->flags & TEXF_RENDERTARGET))
1296 D3DLOCKED_RECT d3dlockedrect;
1297 D3DLOCKED_BOX d3dlockedbox;
1298 switch(glt->texturetype)
1300 case GLTEXTURETYPE_2D:
1301 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1304 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1306 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1307 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1310 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1312 while (width > 1 || height > 1 || depth > 1)
1314 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1315 prevbuffer = resizebuffer;
1316 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1318 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1319 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1325 case GLTEXTURETYPE_3D:
1326 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1328 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1329 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1330 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1333 if (glt->flags & TEXF_MIPMAP)
1335 while (width > 1 || height > 1 || depth > 1)
1337 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1338 prevbuffer = resizebuffer;
1339 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1341 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1342 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1343 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1349 case GLTEXTURETYPE_CUBEMAP:
1350 // convert and upload each side in turn,
1351 // from a continuous block of input texels
1352 texturebuffer = (unsigned char *)prevbuffer;
1353 for (i = 0;i < 6;i++)
1355 prevbuffer = texturebuffer;
1356 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1357 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1359 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1360 prevbuffer = resizebuffer;
1363 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1365 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1366 prevbuffer = resizebuffer;
1369 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1371 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1372 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1375 if (glt->flags & TEXF_MIPMAP)
1377 while (width > 1 || height > 1 || depth > 1)
1379 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1380 prevbuffer = resizebuffer;
1381 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1383 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1384 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1393 glt->d3daddressw = 0;
1394 if (glt->flags & TEXF_CLAMP)
1396 glt->d3daddressu = D3DTADDRESS_CLAMP;
1397 glt->d3daddressv = D3DTADDRESS_CLAMP;
1398 if (glt->tiledepth > 1)
1399 glt->d3daddressw = D3DTADDRESS_CLAMP;
1403 glt->d3daddressu = D3DTADDRESS_WRAP;
1404 glt->d3daddressv = D3DTADDRESS_WRAP;
1405 if (glt->tiledepth > 1)
1406 glt->d3daddressw = D3DTADDRESS_WRAP;
1408 glt->d3dmipmaplodbias = 0;
1409 glt->d3dmaxmiplevel = 0;
1410 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1411 if (glt->flags & TEXF_FORCELINEAR)
1413 glt->d3dminfilter = D3DTEXF_LINEAR;
1414 glt->d3dmagfilter = D3DTEXF_LINEAR;
1415 glt->d3dmipfilter = D3DTEXF_POINT;
1417 else if (glt->flags & TEXF_FORCENEAREST)
1419 glt->d3dminfilter = D3DTEXF_POINT;
1420 glt->d3dmagfilter = D3DTEXF_POINT;
1421 glt->d3dmipfilter = D3DTEXF_POINT;
1423 else if (glt->flags & TEXF_MIPMAP)
1425 glt->d3dminfilter = d3d_filter_mipmin;
1426 glt->d3dmagfilter = d3d_filter_mipmag;
1427 glt->d3dmipfilter = d3d_filter_mipmix;
1431 glt->d3dminfilter = d3d_filter_flatmin;
1432 glt->d3dmagfilter = d3d_filter_flatmag;
1433 glt->d3dmipfilter = d3d_filter_flatmix;
1437 case RENDERPATH_D3D10:
1438 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1440 case RENDERPATH_D3D11:
1441 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1443 case RENDERPATH_SOFT:
1444 switch(glt->texturetype)
1446 case GLTEXTURETYPE_2D:
1447 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1449 case GLTEXTURETYPE_3D:
1450 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1452 case GLTEXTURETYPE_CUBEMAP:
1453 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1455 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1456 // convert and upload each side in turn,
1457 // from a continuous block of input texels
1458 // copy the results into combinedbuffer
1459 texturebuffer = (unsigned char *)prevbuffer;
1460 for (i = 0;i < 6;i++)
1462 prevbuffer = texturebuffer;
1463 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1464 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1466 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1467 prevbuffer = resizebuffer;
1470 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1472 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1473 prevbuffer = resizebuffer;
1475 memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1477 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1478 Mem_Free(combinedbuffer);
1481 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1484 if (glt->flags & TEXF_FORCELINEAR)
1485 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1486 else if (glt->flags & TEXF_FORCENEAREST)
1487 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1488 else if (glt->flags & TEXF_MIPMAP)
1489 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1491 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1496 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)
1500 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1501 textypeinfo_t *texinfo, *texinfo2;
1502 unsigned char *temppixels = NULL;
1505 if (cls.state == ca_dedicated)
1508 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1512 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1513 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1514 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1515 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1521 static int rgbaswapindices[4] = {2, 1, 0, 3};
1522 size = width * height * depth * sides * 4;
1523 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1524 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1528 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1529 if (!vid.support.ext_texture_srgb)
1531 qboolean convertsRGB = false;
1534 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1535 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1536 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1537 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1538 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;convertsRGB = true;break;
1539 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1540 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1544 if (convertsRGB && data)
1546 size = width * height * depth * sides * 4;
1549 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1550 memcpy(temppixels, data, size);
1552 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1556 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1558 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1561 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1563 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1567 texinfo = R_GetTexTypeInfo(textype, flags);
1568 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1571 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1575 // clear the alpha flag if the texture has no transparent pixels
1578 case TEXTYPE_PALETTE:
1579 case TEXTYPE_SRGB_PALETTE:
1580 if (flags & TEXF_ALPHA)
1582 flags &= ~TEXF_ALPHA;
1585 for (i = 0;i < size;i++)
1587 if (((unsigned char *)&palette[data[i]])[3] < 255)
1589 flags |= TEXF_ALPHA;
1598 case TEXTYPE_SRGB_RGBA:
1599 case TEXTYPE_SRGB_BGRA:
1600 if (flags & TEXF_ALPHA)
1602 flags &= ~TEXF_ALPHA;
1605 for (i = 3;i < size;i += 4)
1609 flags |= TEXF_ALPHA;
1616 case TEXTYPE_SHADOWMAP:
1619 case TEXTYPE_SRGB_DXT1:
1622 case TEXTYPE_SRGB_DXT1A:
1624 case TEXTYPE_SRGB_DXT3:
1626 case TEXTYPE_SRGB_DXT5:
1627 flags |= TEXF_ALPHA;
1630 flags |= TEXF_ALPHA;
1632 case TEXTYPE_COLORBUFFER:
1633 case TEXTYPE_COLORBUFFER16F:
1634 case TEXTYPE_COLORBUFFER32F:
1635 flags |= TEXF_ALPHA;
1638 Sys_Error("R_LoadTexture: unknown texture type");
1641 texinfo2 = R_GetTexTypeInfo(textype, flags);
1642 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1645 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1647 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1649 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1651 glt->chain = pool->gltchain;
1652 pool->gltchain = glt;
1653 glt->inputwidth = width;
1654 glt->inputheight = height;
1655 glt->inputdepth = depth;
1657 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
1658 glt->textype = texinfo;
1659 glt->texturetype = texturetype;
1660 glt->inputdatasize = size;
1661 glt->palette = palette;
1662 glt->glinternalformat = texinfo->glinternalformat;
1663 glt->glformat = texinfo->glformat;
1664 glt->gltype = texinfo->gltype;
1665 glt->bytesperpixel = texinfo->internalbytesperpixel;
1666 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1669 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1670 // init the dynamic texture attributes, too [11/22/2007 Black]
1671 glt->updatecallback = NULL;
1672 glt->updatacallback_data = NULL;
1674 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1676 // upload the texture
1677 // data may be NULL (blank texture for dynamic rendering)
1678 switch(vid.renderpath)
1680 case RENDERPATH_GL11:
1681 case RENDERPATH_GL13:
1682 case RENDERPATH_GL20:
1683 case RENDERPATH_GLES1:
1684 case RENDERPATH_GLES2:
1686 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1688 case RENDERPATH_D3D9:
1691 D3DFORMAT d3dformat;
1696 d3dpool = D3DPOOL_MANAGED;
1697 if (flags & TEXF_RENDERTARGET)
1699 d3dusage |= D3DUSAGE_RENDERTARGET;
1700 d3dpool = D3DPOOL_DEFAULT;
1704 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1705 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1706 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1707 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
1708 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
1709 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
1710 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1711 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1712 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1714 glt->d3dformat = d3dformat;
1715 glt->d3dusage = d3dusage;
1716 glt->d3dpool = d3dpool;
1717 glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1718 if (glt->d3disdepthsurface)
1720 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1721 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1723 else if (glt->tiledepth > 1)
1725 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)))
1726 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1728 else if (glt->sides == 6)
1730 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1731 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1735 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)))
1736 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1741 case RENDERPATH_D3D10:
1742 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1744 case RENDERPATH_D3D11:
1745 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1747 case RENDERPATH_SOFT:
1752 case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1753 case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1754 case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1755 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1756 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
1757 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
1758 case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1759 case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1760 default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1762 if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1763 if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1764 if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1765 if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1766 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1771 R_UploadFullTexture(glt, data);
1772 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1773 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1775 // free any temporary processing buffer we allocated...
1777 Mem_Free(temppixels);
1779 // texture converting and uploading can take a while, so make sure we're sending keepalives
1780 // FIXME: this causes rendering during R_Shadow_DrawLights
1781 // CL_KeepaliveMessage(false);
1783 return (rtexture_t *)glt;
1786 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)
1788 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1791 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)
1793 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1796 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)
1798 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1801 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1803 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1805 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1807 flags |= TEXF_FORCENEAREST;
1808 if (precision <= 16)
1809 flags |= TEXF_LOWPRECISION;
1813 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1815 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1818 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1820 gltexture_t *glt = (gltexture_t *)rt;
1823 int bytesperpixel = 0;
1824 int bytesperblock = 0;
1826 int dds_format_flags;
1834 GLint internalformat;
1835 const char *ddsfourcc;
1837 return -1; // NULL pointer
1838 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1839 return -2; // broken driver - crashes on reading internal format
1840 if (!qglGetTexLevelParameteriv)
1842 GL_ActiveTexture(0);
1843 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1844 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1845 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1846 switch(internalformat)
1848 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1849 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1850 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1851 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1852 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1854 // if premultiplied alpha, say so in the DDS file
1855 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1857 switch(internalformat)
1859 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1860 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1863 if (!bytesperblock && skipuncompressed)
1864 return -3; // skipped
1865 memset(mipinfo, 0, sizeof(mipinfo));
1866 mipinfo[0][0] = glt->tilewidth;
1867 mipinfo[0][1] = glt->tileheight;
1869 if (glt->flags & TEXF_MIPMAP)
1871 for (mip = 1;mip < 16;mip++)
1873 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1874 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1875 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1883 for (mip = 0;mip < mipmaps;mip++)
1885 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1886 mipinfo[mip][3] = ddssize;
1887 ddssize += mipinfo[mip][2];
1889 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1892 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1896 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1897 dds_format_flags = 0x4; // DDPF_FOURCC
1901 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1902 dds_format_flags = 0x40; // DDPF_RGB
1906 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1907 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1910 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1911 memcpy(dds, "DDS ", 4);
1912 StoreLittleLong(dds+4, ddssize);
1913 StoreLittleLong(dds+8, dds_flags);
1914 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1915 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1916 StoreLittleLong(dds+24, 1); // depth
1917 StoreLittleLong(dds+28, mipmaps); // mipmaps
1918 StoreLittleLong(dds+76, 32); // format size
1919 StoreLittleLong(dds+80, dds_format_flags);
1920 StoreLittleLong(dds+108, dds_caps1);
1921 StoreLittleLong(dds+112, dds_caps2);
1924 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1925 memcpy(dds+84, ddsfourcc, 4);
1926 for (mip = 0;mip < mipmaps;mip++)
1928 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1933 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1934 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1935 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1936 for (mip = 0;mip < mipmaps;mip++)
1938 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1941 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1942 ret = FS_WriteFile(filename, dds, ddssize);
1944 return ret ? ddssize : -5;
1947 rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint
1949 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1952 int bytesperblock, bytesperpixel;
1955 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1956 textypeinfo_t *texinfo;
1957 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1959 GLint oldbindtexnum = 0;
1960 const unsigned char *mippixels, *ddspixels, *mippixels_start;
1962 fs_offset_t ddsfilesize;
1963 unsigned int ddssize;
1964 qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
1966 if (cls.state == ca_dedicated)
1969 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1970 ddssize = ddsfilesize;
1974 if(r_texture_dds_load_logfailure.integer)
1975 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1976 return NULL; // not found
1979 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1982 Con_Printf("^1%s: not a DDS image\n", filename);
1986 //dds_flags = BuffLittleLong(dds+8);
1987 dds_format_flags = BuffLittleLong(dds+80);
1988 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1989 dds_width = BuffLittleLong(dds+16);
1990 dds_height = BuffLittleLong(dds+12);
1991 ddspixels = dds + 128;
1993 if(r_texture_dds_load_alphamode.integer == 0)
1994 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1995 flags &= ~TEXF_ALPHA;
1997 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1998 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
2000 // very sloppy BGRA 32bit identification
2001 textype = TEXTYPE_BGRA;
2002 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2005 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
2006 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2009 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
2012 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
2015 for (i = 3;i < size;i += 4)
2016 if (ddspixels[i] < 255)
2019 flags &= ~TEXF_ALPHA;
2022 else if (!memcmp(dds+84, "DXT1", 4))
2024 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
2025 // LordHavoc: it is my belief that this does not infringe on the
2026 // patent because it is not decoding pixels...
2027 textype = TEXTYPE_DXT1;
2030 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
2031 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2032 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2035 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
2038 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
2040 if(r_texture_dds_load_alphamode.integer == 1)
2043 for (i = 0;i < size;i += bytesperblock)
2044 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
2046 // NOTE: this assumes sizeof(unsigned int) == 4
2047 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
2048 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
2049 if(data & (data<<1) & 0xAAAAAAAA)//rgh
2053 textype = TEXTYPE_DXT1A;
2055 flags &= ~TEXF_ALPHA;
2059 flags &= ~TEXF_ALPHA;
2063 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2065 if(!memcmp(dds+84, "DXT2", 4))
2067 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2069 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2074 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2076 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2079 textype = TEXTYPE_DXT3;
2082 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2083 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2086 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2089 // we currently always assume alpha
2091 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2093 if(!memcmp(dds+84, "DXT4", 4))
2095 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2097 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2102 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2104 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2107 textype = TEXTYPE_DXT5;
2110 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2111 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2114 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2117 // we currently always assume alpha
2122 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2126 force_swdecode = false;
2129 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
2131 if(r_texture_dds_swdecode.integer > 1)
2132 force_swdecode = true;
2136 if(r_texture_dds_swdecode.integer < 1)
2142 force_swdecode = true;
2146 // return whether this texture is transparent
2148 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2150 // if we SW decode, choose 2 sizes bigger
2153 // this is quarter res, so do not scale down more than we have to
2157 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2160 // this is where we apply gl_picmip
2161 mippixels_start = ddspixels;
2162 mipwidth = dds_width;
2163 mipheight = dds_height;
2164 while(miplevel >= 1 && dds_miplevels >= 1)
2166 if (mipwidth <= 1 && mipheight <= 1)
2168 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2169 mippixels_start += mipsize; // just skip
2177 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2178 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2180 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2182 // fake decode S3TC if needed
2185 int mipsize_new = mipsize_total / bytesperblock * 4;
2186 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2187 unsigned char *p = mipnewpixels;
2188 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2190 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2191 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2192 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2193 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2194 if(textype == TEXTYPE_DXT5)
2195 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2196 else if(textype == TEXTYPE_DXT3)
2198 (mippixels_start[i-8] & 0x0F)
2199 + (mippixels_start[i-8] >> 4)
2200 + (mippixels_start[i-7] & 0x0F)
2201 + (mippixels_start[i-7] >> 4)
2202 + (mippixels_start[i-6] & 0x0F)
2203 + (mippixels_start[i-6] >> 4)
2204 + (mippixels_start[i-5] & 0x0F)
2205 + (mippixels_start[i-5] >> 4)
2206 ) * (0.125f / 15.0f * 255.0f);
2211 textype = TEXTYPE_BGRA;
2215 // as each block becomes a pixel, we must use pixel count for this
2216 mipwidth = (mipwidth + 3) / 4;
2217 mipheight = (mipheight + 3) / 4;
2218 mipsize = bytesperpixel * mipwidth * mipheight;
2219 mippixels_start = mipnewpixels;
2220 mipsize_total = mipsize_new;
2223 // start mip counting
2224 mippixels = mippixels_start;
2226 // calculate average color if requested
2230 Vector4Clear(avgcolor);
2233 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2235 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2236 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2237 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2238 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2239 if(textype == TEXTYPE_DXT5)
2240 avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2241 else if(textype == TEXTYPE_DXT3)
2243 (mippixels_start[i-8] & 0x0F)
2244 + (mippixels_start[i-8] >> 4)
2245 + (mippixels_start[i-7] & 0x0F)
2246 + (mippixels_start[i-7] >> 4)
2247 + (mippixels_start[i-6] & 0x0F)
2248 + (mippixels_start[i-6] >> 4)
2249 + (mippixels_start[i-5] & 0x0F)
2250 + (mippixels_start[i-5] >> 4)
2251 ) * (0.125f / 15.0f * 255.0f);
2255 f = (float)bytesperblock / size;
2256 avgcolor[0] *= (0.5f / 31.0f) * f;
2257 avgcolor[1] *= (0.5f / 63.0f) * f;
2258 avgcolor[2] *= (0.5f / 31.0f) * f;
2263 for (i = 0;i < mipsize;i += 4)
2265 avgcolor[0] += mippixels[i+2];
2266 avgcolor[1] += mippixels[i+1];
2267 avgcolor[2] += mippixels[i];
2268 avgcolor[3] += mippixels[i+3];
2270 f = (1.0f / 255.0f) * bytesperpixel / size;
2278 // when not requesting mipmaps, do not load them
2279 if(!(flags & TEXF_MIPMAP))
2282 if (dds_miplevels >= 1)
2283 flags |= TEXF_MIPMAP;
2285 flags &= ~TEXF_MIPMAP;
2287 texinfo = R_GetTexTypeInfo(textype, flags);
2289 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2290 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2292 glt->chain = pool->gltchain;
2293 pool->gltchain = glt;
2294 glt->inputwidth = mipwidth;
2295 glt->inputheight = mipheight;
2296 glt->inputdepth = 1;
2298 glt->textype = texinfo;
2299 glt->texturetype = GLTEXTURETYPE_2D;
2300 glt->inputdatasize = ddssize;
2301 glt->glinternalformat = texinfo->glinternalformat;
2302 glt->glformat = texinfo->glformat;
2303 glt->gltype = texinfo->gltype;
2304 glt->bytesperpixel = texinfo->internalbytesperpixel;
2306 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2307 glt->tilewidth = mipwidth;
2308 glt->tileheight = mipheight;
2310 glt->miplevels = dds_miplevels;
2312 // texture uploading can take a while, so make sure we're sending keepalives
2313 CL_KeepaliveMessage(false);
2315 // create the texture object
2316 switch(vid.renderpath)
2318 case RENDERPATH_GL11:
2319 case RENDERPATH_GL13:
2320 case RENDERPATH_GL20:
2321 case RENDERPATH_GLES1:
2322 case RENDERPATH_GLES2:
2324 GL_ActiveTexture(0);
2325 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2326 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2327 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2329 case RENDERPATH_D3D9:
2332 D3DFORMAT d3dformat;
2337 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2338 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2339 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2340 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2341 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2344 d3dpool = D3DPOOL_MANAGED;
2345 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2349 case RENDERPATH_D3D10:
2350 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2352 case RENDERPATH_D3D11:
2353 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2355 case RENDERPATH_SOFT:
2356 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);
2360 // upload the texture
2361 // we need to restore the texture binding after finishing the upload
2362 mipcomplete = false;
2364 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2366 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2367 if (mippixels + mipsize > mippixels_start + mipsize_total)
2369 switch(vid.renderpath)
2371 case RENDERPATH_GL11:
2372 case RENDERPATH_GL13:
2373 case RENDERPATH_GL20:
2374 case RENDERPATH_GLES1:
2375 case RENDERPATH_GLES2:
2378 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2382 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2385 case RENDERPATH_D3D9:
2388 D3DLOCKED_RECT d3dlockedrect;
2389 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2391 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2392 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2398 case RENDERPATH_D3D10:
2399 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2401 case RENDERPATH_D3D11:
2402 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2404 case RENDERPATH_SOFT:
2406 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2408 DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
2409 // DPSOFTRAST calculates its own mipmaps
2410 mip = dds_miplevels;
2413 mippixels += mipsize;
2414 if (mipwidth <= 1 && mipheight <= 1)
2425 // after upload we have to set some parameters...
2426 switch(vid.renderpath)
2428 case RENDERPATH_GL11:
2429 case RENDERPATH_GL13:
2430 case RENDERPATH_GL20:
2431 case RENDERPATH_GLES1:
2432 case RENDERPATH_GLES2:
2433 if (dds_miplevels >= 1 && !mipcomplete)
2435 // need to set GL_TEXTURE_MAX_LEVEL
2436 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2438 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2439 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2441 case RENDERPATH_D3D9:
2443 glt->d3daddressw = 0;
2444 if (glt->flags & TEXF_CLAMP)
2446 glt->d3daddressu = D3DTADDRESS_CLAMP;
2447 glt->d3daddressv = D3DTADDRESS_CLAMP;
2448 if (glt->tiledepth > 1)
2449 glt->d3daddressw = D3DTADDRESS_CLAMP;
2453 glt->d3daddressu = D3DTADDRESS_WRAP;
2454 glt->d3daddressv = D3DTADDRESS_WRAP;
2455 if (glt->tiledepth > 1)
2456 glt->d3daddressw = D3DTADDRESS_WRAP;
2458 glt->d3dmipmaplodbias = 0;
2459 glt->d3dmaxmiplevel = 0;
2460 glt->d3dmaxmiplevelfilter = 0;
2461 if (glt->flags & TEXF_MIPMAP)
2463 glt->d3dminfilter = d3d_filter_mipmin;
2464 glt->d3dmagfilter = d3d_filter_mipmag;
2465 glt->d3dmipfilter = d3d_filter_mipmix;
2469 glt->d3dminfilter = d3d_filter_flatmin;
2470 glt->d3dmagfilter = d3d_filter_flatmag;
2471 glt->d3dmipfilter = d3d_filter_flatmix;
2475 case RENDERPATH_D3D10:
2476 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2478 case RENDERPATH_D3D11:
2479 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2481 case RENDERPATH_SOFT:
2482 if (glt->flags & TEXF_FORCELINEAR)
2483 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2484 else if (glt->flags & TEXF_FORCENEAREST)
2485 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2486 else if (glt->flags & TEXF_MIPMAP)
2487 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2489 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2495 Mem_Free((unsigned char *) mippixels_start);
2496 return (rtexture_t *)glt;
2499 int R_TextureWidth(rtexture_t *rt)
2501 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2504 int R_TextureHeight(rtexture_t *rt)
2506 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2509 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2511 gltexture_t *glt = (gltexture_t *)rt;
2513 Host_Error("R_UpdateTexture: no data supplied");
2515 Host_Error("R_UpdateTexture: no texture supplied");
2516 if (!glt->texnum && !glt->d3dtexture)
2518 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2521 // update part of the texture
2522 if (glt->bufferpixels)
2525 int bpp = glt->bytesperpixel;
2526 int inputskip = width*bpp;
2527 int outputskip = glt->tilewidth*bpp;
2528 const unsigned char *input = data;
2529 unsigned char *output = glt->bufferpixels;
2530 if (glt->inputdepth != 1 || glt->sides != 1)
2531 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2541 input -= y*inputskip;
2544 if (width > glt->tilewidth - x)
2545 width = glt->tilewidth - x;
2546 if (height > glt->tileheight - y)
2547 height = glt->tileheight - y;
2548 if (width < 1 || height < 1)
2551 glt->buffermodified = true;
2552 output += y*outputskip + x*bpp;
2553 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2554 memcpy(output, input, width*bpp);
2556 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2557 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2559 R_UploadFullTexture(glt, data);
2562 int R_RealGetTexture(rtexture_t *rt)
2567 glt = (gltexture_t *)rt;
2568 if (glt->flags & GLTEXF_DYNAMIC)
2569 R_UpdateDynamicTexture(glt);
2570 if (glt->buffermodified && glt->bufferpixels)
2572 glt->buffermodified = false;
2573 R_UploadFullTexture(glt, glt->bufferpixels);
2582 void R_ClearTexture (rtexture_t *rt)
2584 gltexture_t *glt = (gltexture_t *)rt;
2586 R_UploadFullTexture(glt, NULL);
2589 int R_PicmipForFlags(int flags)
2592 if(flags & TEXF_PICMIP)
2594 miplevel += gl_picmip.integer;
2595 if (flags & TEXF_ISWORLD)
2597 if (r_picmipworld.integer)
2598 miplevel += gl_picmip_world.integer;
2602 else if (flags & TEXF_ISSPRITE)
2604 if (r_picmipsprites.integer)
2605 miplevel += gl_picmip_sprites.integer;
2610 miplevel += gl_picmip_other.integer;
2612 return max(0, miplevel);