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_texturecompression_sprites = {CVAR_SAVE, "gl_texturecompression_sprites", "1", "whether to compress sprites"};
35 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"};
36 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"};
37 cvar_t r_texture_dds_load_logfailure = {0, "r_texture_dds_load_logfailure", "0", "log missing DDS textures to ddstexturefailures.log"};
38 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"};
40 qboolean gl_filter_force = false;
41 int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
42 int gl_filter_mag = GL_LINEAR;
43 DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_mipmap = DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE;
44 DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_nomipmap = DPSOFTRAST_TEXTURE_FILTER_LINEAR;
47 int d3d_filter_flatmin = D3DTEXF_LINEAR;
48 int d3d_filter_flatmag = D3DTEXF_LINEAR;
49 int d3d_filter_flatmix = D3DTEXF_POINT;
50 int d3d_filter_mipmin = D3DTEXF_LINEAR;
51 int d3d_filter_mipmag = D3DTEXF_LINEAR;
52 int d3d_filter_mipmix = D3DTEXF_LINEAR;
53 int d3d_filter_nomip = false;
57 static mempool_t *texturemempool;
58 static memexpandablearray_t texturearray;
60 // note: this must not conflict with TEXF_ flags in r_textures.h
61 // bitmask for mismatch checking
62 #define GLTEXF_IMPORTANTBITS (0)
63 // dynamic texture (treat texnum == 0 differently)
64 #define GLTEXF_DYNAMIC 0x00080000
66 typedef struct textypeinfo_s
70 int inputbytesperpixel;
71 int internalbytesperpixel;
72 float glinternalbytesperpixel;
79 // framebuffer texture formats
80 static textypeinfo_t textype_shadowmap16 = {"shadowmap16", TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
81 static textypeinfo_t textype_shadowmap24 = {"shadowmap24", TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
82 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
83 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F, 8, 8, 8.0f, GL_RGBA16F_ARB , GL_RGBA , GL_FLOAT };
84 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F, 16, 16, 16.0f, GL_RGBA32F_ARB , GL_RGBA , GL_FLOAT };
87 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
88 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
89 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
90 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE };
91 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
92 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 };
93 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 };
94 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
95 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
96 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 };
97 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 };
98 static textypeinfo_t textype_dxt1 = {"dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
99 static textypeinfo_t textype_dxt1a = {"dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 };
100 static textypeinfo_t textype_dxt3 = {"dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 };
101 static textypeinfo_t textype_dxt5 = {"dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 };
102 static textypeinfo_t textype_sRGB_palette = {"sRGB_palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
103 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 };
104 static textypeinfo_t textype_sRGB_rgba = {"sRGB_rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
105 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 };
106 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 };
107 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 };
108 static textypeinfo_t textype_sRGB_bgra = {"sRGB_bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
109 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 };
110 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 };
111 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 };
112 static textypeinfo_t textype_sRGB_dxt1 = {"sRGB_dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , 0 , 0 };
113 static textypeinfo_t textype_sRGB_dxt1a = {"sRGB_dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 , 0 };
114 static textypeinfo_t textype_sRGB_dxt3 = {"sRGB_dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 , 0 };
115 static textypeinfo_t textype_sRGB_dxt5 = {"sRGB_dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 , 0 };
117 typedef enum gltexturetype_e
121 GLTEXTURETYPE_CUBEMAP,
126 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB};
127 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
128 static int cubemapside[6] =
130 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
131 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
132 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
133 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
134 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
135 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
138 typedef struct gltexture_s
140 // this portion of the struct is exposed to the R_GetTexture macro for
141 // speed reasons, must be identical in rtexture_t!
142 int texnum; // GL texture slot number
143 qboolean dirty; // indicates that R_RealGetTexture should be called
144 int gltexturetypeenum; // used by R_Mesh_TexBind
145 // d3d stuff the backend needs
148 qboolean d3disdepthsurface; // for depth/stencil surfaces
158 int d3dmaxmiplevelfilter;
159 int d3dmipmaplodbias;
163 // dynamic texture stuff [11/22/2007 Black]
164 updatecallback_t updatecallback;
165 void *updatacallback_data;
166 // --- [11/22/2007 Black]
168 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
169 unsigned char *bufferpixels;
170 qboolean buffermodified;
172 // pointer to texturepool (check this to see if the texture is allocated)
173 struct gltexturepool_s *pool;
174 // pointer to next texture in texturepool chain
175 struct gltexture_s *chain;
176 // name of the texture (this might be removed someday), no duplicates
177 char identifier[MAX_QPATH + 32];
178 // original data size in *inputtexels
179 int inputwidth, inputheight, inputdepth;
180 // copy of the original texture(s) supplied to the upload function, for
181 // delayed uploads (non-precached)
182 unsigned char *inputtexels;
183 // original data size in *inputtexels
185 // flags supplied to the LoadTexture function
186 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
190 // pointer to one of the textype_ structs
191 textypeinfo_t *textype;
192 // one of the GLTEXTURETYPE_ values
194 // palette if the texture is TEXTYPE_PALETTE
195 const unsigned int *palette;
196 // actual stored texture size after gl_picmip and gl_max_size are applied
197 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
198 int tilewidth, tileheight, tiledepth;
199 // 1 or 6 depending on texturetype
201 // how many mipmap levels in this texture
205 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
208 int glinternalformat;
209 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
214 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
216 typedef struct gltexturepool_s
218 unsigned int sentinel;
219 struct gltexture_s *gltchain;
220 struct gltexturepool_s *next;
224 static gltexturepool_t *gltexturepoolchain = NULL;
226 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
227 static int resizebuffersize = 0;
228 static const unsigned char *texturebuffer;
230 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
234 case TEXTYPE_DXT1: return &textype_dxt1;
235 case TEXTYPE_DXT1A: return &textype_dxt1a;
236 case TEXTYPE_DXT3: return &textype_dxt3;
237 case TEXTYPE_DXT5: return &textype_dxt5;
238 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
239 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);
240 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);
241 case TEXTYPE_ALPHA: return &textype_alpha;
242 case TEXTYPE_SHADOWMAP: return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
243 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
244 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
245 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
246 case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1;
247 case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a;
248 case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
249 case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
250 case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
251 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);
252 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);
254 Host_Error("R_GetTexTypeInfo: unknown texture format");
260 // dynamic texture code [11/22/2007 Black]
261 void R_MarkDirtyTexture(rtexture_t *rt) {
262 gltexture_t *glt = (gltexture_t*) rt;
267 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
268 if (glt->flags & GLTEXF_DYNAMIC)
270 // mark it as dirty, so R_RealGetTexture gets called
275 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
276 gltexture_t *glt = (gltexture_t*) rt;
281 glt->flags |= GLTEXF_DYNAMIC;
282 glt->updatecallback = updatecallback;
283 glt->updatacallback_data = data;
286 static void R_UpdateDynamicTexture(gltexture_t *glt) {
288 if( glt->updatecallback ) {
289 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
293 void R_PurgeTexture(rtexture_t *rt)
295 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
300 void R_FreeTexture(rtexture_t *rt)
302 gltexture_t *glt, **gltpointer;
304 glt = (gltexture_t *)rt;
306 Host_Error("R_FreeTexture: texture == NULL");
308 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
309 if (*gltpointer == glt)
310 *gltpointer = glt->chain;
312 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
314 R_Mesh_ClearBindingsForTexture(glt->texnum);
316 switch(vid.renderpath)
318 case RENDERPATH_GL11:
319 case RENDERPATH_GL13:
320 case RENDERPATH_GL20:
321 case RENDERPATH_GLES1:
322 case RENDERPATH_GLES2:
326 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
329 case RENDERPATH_D3D9:
331 if (glt->d3disdepthsurface)
332 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
333 else if (glt->tiledepth > 1)
334 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
335 else if (glt->sides == 6)
336 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
338 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
339 glt->d3dtexture = NULL;
342 case RENDERPATH_D3D10:
343 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
345 case RENDERPATH_D3D11:
346 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
348 case RENDERPATH_SOFT:
350 DPSOFTRAST_Texture_Free(glt->texnum);
354 if (glt->inputtexels)
355 Mem_Free(glt->inputtexels);
356 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
359 rtexturepool_t *R_AllocTexturePool(void)
361 gltexturepool_t *pool;
362 if (texturemempool == NULL)
364 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
367 pool->next = gltexturepoolchain;
368 gltexturepoolchain = pool;
369 pool->sentinel = TEXTUREPOOL_SENTINEL;
370 return (rtexturepool_t *)pool;
373 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
375 gltexturepool_t *pool, **poolpointer;
376 if (rtexturepool == NULL)
378 if (*rtexturepool == NULL)
380 pool = (gltexturepool_t *)(*rtexturepool);
381 *rtexturepool = NULL;
382 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
383 Host_Error("R_FreeTexturePool: pool already freed");
384 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
385 if (*poolpointer == pool)
386 *poolpointer = pool->next;
388 Host_Error("R_FreeTexturePool: pool not linked");
389 while (pool->gltchain)
390 R_FreeTexture((rtexture_t *)pool->gltchain);
395 typedef struct glmode_s
398 int minification, magnification;
399 DPSOFTRAST_TEXTURE_FILTER dpsoftrastfilter_mipmap, dpsoftrastfilter_nomipmap;
403 static glmode_t modes[6] =
405 {"GL_NEAREST", GL_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
406 {"GL_LINEAR", GL_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
407 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
408 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
409 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
410 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR}
414 typedef struct d3dmode_s
421 static d3dmode_t d3dmodes[6] =
423 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
424 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
425 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
426 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
427 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
428 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
432 static void GL_TextureMode_f (void)
437 gltexturepool_t *pool;
441 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
442 for (i = 0;i < 6;i++)
444 if (gl_filter_min == modes[i].minification)
446 Con_Printf("%s\n", modes[i].name);
450 Con_Print("current filter is unknown???\n");
454 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
455 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
459 Con_Print("bad filter name\n");
463 gl_filter_min = modes[i].minification;
464 gl_filter_mag = modes[i].magnification;
465 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
467 dpsoftrast_filter_mipmap = modes[i].dpsoftrastfilter_mipmap;
468 dpsoftrast_filter_nomipmap = modes[i].dpsoftrastfilter_nomipmap;
470 switch(vid.renderpath)
472 case RENDERPATH_GL11:
473 case RENDERPATH_GL13:
474 case RENDERPATH_GL20:
475 case RENDERPATH_GLES1:
476 case RENDERPATH_GLES2:
477 // change all the existing mipmap texture objects
478 // FIXME: force renderer(/client/something?) restart instead?
481 for (pool = gltexturepoolchain;pool;pool = pool->next)
483 for (glt = pool->gltchain;glt;glt = glt->chain)
485 // only update already uploaded images
486 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
488 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
489 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
490 if (glt->flags & TEXF_MIPMAP)
492 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
496 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
498 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
499 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
504 case RENDERPATH_D3D9:
506 d3d_filter_flatmin = d3dmodes[i].m1;
507 d3d_filter_flatmag = d3dmodes[i].m1;
508 d3d_filter_flatmix = D3DTEXF_POINT;
509 d3d_filter_mipmin = d3dmodes[i].m1;
510 d3d_filter_mipmag = d3dmodes[i].m1;
511 d3d_filter_mipmix = d3dmodes[i].m2;
512 d3d_filter_nomip = i < 2;
513 if (gl_texture_anisotropy.integer > 1 && i == 5)
514 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
515 for (pool = gltexturepoolchain;pool;pool = pool->next)
517 for (glt = pool->gltchain;glt;glt = glt->chain)
519 // only update already uploaded images
520 if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
522 if (glt->flags & TEXF_MIPMAP)
524 glt->d3dminfilter = d3d_filter_mipmin;
525 glt->d3dmagfilter = d3d_filter_mipmag;
526 glt->d3dmipfilter = d3d_filter_mipmix;
527 glt->d3dmaxmiplevelfilter = 0;
531 glt->d3dminfilter = d3d_filter_flatmin;
532 glt->d3dmagfilter = d3d_filter_flatmag;
533 glt->d3dmipfilter = d3d_filter_flatmix;
534 glt->d3dmaxmiplevelfilter = 0;
541 case RENDERPATH_D3D10:
542 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
544 case RENDERPATH_D3D11:
545 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
547 case RENDERPATH_SOFT:
548 // change all the existing texture objects
549 for (pool = gltexturepoolchain;pool;pool = pool->next)
550 for (glt = pool->gltchain;glt;glt = glt->chain)
551 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
552 DPSOFTRAST_Texture_Filter(glt->texnum, (glt->flags & TEXF_MIPMAP) ? dpsoftrast_filter_mipmap : dpsoftrast_filter_nomipmap);
557 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)
559 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
564 case GLTEXTURETYPE_2D:
565 maxsize = vid.maxtexturesize_2d;
566 if (flags & TEXF_PICMIP)
568 maxsize = bound(1, gl_max_size.integer, maxsize);
572 case GLTEXTURETYPE_3D:
573 maxsize = vid.maxtexturesize_3d;
575 case GLTEXTURETYPE_CUBEMAP:
576 maxsize = vid.maxtexturesize_cubemap;
580 if (vid.support.arb_texture_non_power_of_two)
582 width2 = min(inwidth >> picmip, maxsize);
583 height2 = min(inheight >> picmip, maxsize);
584 depth2 = min(indepth >> picmip, maxsize);
588 for (width2 = 1;width2 < inwidth;width2 <<= 1);
589 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
590 for (height2 = 1;height2 < inheight;height2 <<= 1);
591 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
592 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
593 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
596 switch(vid.renderpath)
598 case RENDERPATH_GL11:
599 case RENDERPATH_GL13:
600 case RENDERPATH_GL20:
601 case RENDERPATH_D3D10:
602 case RENDERPATH_D3D11:
603 case RENDERPATH_SOFT:
604 case RENDERPATH_GLES1:
605 case RENDERPATH_GLES2:
607 case RENDERPATH_D3D9:
609 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
610 if (texturetype == GLTEXTURETYPE_2D)
612 width2 = max(width2, 2);
613 height2 = max(height2, 2);
620 if (flags & TEXF_MIPMAP)
622 int extent = max(width2, max(height2, depth2));
628 *outwidth = max(1, width2);
630 *outheight = max(1, height2);
632 *outdepth = max(1, depth2);
634 *outmiplevels = miplevels;
638 static int R_CalcTexelDataSize (gltexture_t *glt)
640 int width2, height2, depth2, size;
642 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
644 size = width2 * height2 * depth2;
646 if (glt->flags & TEXF_MIPMAP)
648 while (width2 > 1 || height2 > 1 || depth2 > 1)
656 size += width2 * height2 * depth2;
660 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
663 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
667 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
668 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
670 gltexturepool_t *pool;
672 Con_Print("glsize input loaded mip alpha name\n");
673 for (pool = gltexturepoolchain;pool;pool = pool->next)
681 for (glt = pool->gltchain;glt;glt = glt->chain)
683 glsize = R_CalcTexelDataSize(glt);
684 isloaded = glt->texnum != 0;
686 pooltotalt += glsize;
687 pooltotalp += glt->inputdatasize;
691 poolloadedt += glsize;
692 poolloadedp += glt->inputdatasize;
695 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);
698 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);
699 sumtotal += pooltotal;
700 sumtotalt += pooltotalt;
701 sumtotalp += pooltotalp;
702 sumloaded += poolloaded;
703 sumloadedt += poolloadedt;
704 sumloadedp += poolloadedp;
707 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);
710 static void R_TextureStats_f(void)
712 R_TextureStats_Print(true, true, true);
715 static void r_textures_start(void)
717 switch(vid.renderpath)
719 case RENDERPATH_GL11:
720 case RENDERPATH_GL13:
721 case RENDERPATH_GL20:
722 case RENDERPATH_GLES1:
723 case RENDERPATH_GLES2:
724 // LordHavoc: allow any alignment
726 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
727 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
729 case RENDERPATH_D3D9:
731 case RENDERPATH_D3D10:
732 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
734 case RENDERPATH_D3D11:
735 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
737 case RENDERPATH_SOFT:
741 texturemempool = Mem_AllocPool("texture management", 0, NULL);
742 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
744 // Disable JPEG screenshots if the DLL isn't loaded
745 if (! JPEG_OpenLibrary ())
746 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
747 if (! PNG_OpenLibrary ())
748 Cvar_SetValueQuick (&scr_screenshot_png, 0);
751 static void r_textures_shutdown(void)
753 rtexturepool_t *temp;
755 JPEG_CloseLibrary ();
757 while(gltexturepoolchain)
759 temp = (rtexturepool_t *) gltexturepoolchain;
760 R_FreeTexturePool(&temp);
763 resizebuffersize = 0;
765 colorconvertbuffer = NULL;
766 texturebuffer = NULL;
767 Mem_ExpandableArray_FreeArray(&texturearray);
768 Mem_FreePool(&texturemempool);
771 static void r_textures_newmap(void)
775 static void r_textures_devicelost(void)
779 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
780 for (i = 0;i < endindex;i++)
782 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
783 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
785 switch(vid.renderpath)
787 case RENDERPATH_GL11:
788 case RENDERPATH_GL13:
789 case RENDERPATH_GL20:
790 case RENDERPATH_GLES1:
791 case RENDERPATH_GLES2:
793 case RENDERPATH_D3D9:
795 if (glt->d3disdepthsurface)
796 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
797 else if (glt->tiledepth > 1)
798 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
799 else if (glt->sides == 6)
800 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
802 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
803 glt->d3dtexture = NULL;
806 case RENDERPATH_D3D10:
807 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
809 case RENDERPATH_D3D11:
810 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
812 case RENDERPATH_SOFT:
818 static void r_textures_devicerestored(void)
822 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
823 for (i = 0;i < endindex;i++)
825 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
826 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
828 switch(vid.renderpath)
830 case RENDERPATH_GL11:
831 case RENDERPATH_GL13:
832 case RENDERPATH_GL20:
833 case RENDERPATH_GLES1:
834 case RENDERPATH_GLES2:
836 case RENDERPATH_D3D9:
840 if (glt->d3disdepthsurface)
842 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
843 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
845 else if (glt->tiledepth > 1)
847 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)))
848 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
850 else if (glt->sides == 6)
852 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
853 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
857 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)))
858 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
863 case RENDERPATH_D3D10:
864 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
866 case RENDERPATH_D3D11:
867 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
869 case RENDERPATH_SOFT:
876 void R_Textures_Init (void)
878 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");
879 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
880 Cvar_RegisterVariable (&gl_max_size);
881 Cvar_RegisterVariable (&gl_picmip);
882 Cvar_RegisterVariable (&gl_picmip_world);
883 Cvar_RegisterVariable (&r_picmipworld);
884 Cvar_RegisterVariable (&gl_picmip_sprites);
885 Cvar_RegisterVariable (&r_picmipsprites);
886 Cvar_RegisterVariable (&gl_picmip_other);
887 Cvar_RegisterVariable (&gl_max_lightmapsize);
888 Cvar_RegisterVariable (&r_lerpimages);
889 Cvar_RegisterVariable (&gl_texture_anisotropy);
890 Cvar_RegisterVariable (&gl_texturecompression);
891 Cvar_RegisterVariable (&gl_texturecompression_color);
892 Cvar_RegisterVariable (&gl_texturecompression_normal);
893 Cvar_RegisterVariable (&gl_texturecompression_gloss);
894 Cvar_RegisterVariable (&gl_texturecompression_glow);
895 Cvar_RegisterVariable (&gl_texturecompression_2d);
896 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
897 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
898 Cvar_RegisterVariable (&gl_texturecompression_sky);
899 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
900 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
901 Cvar_RegisterVariable (&gl_texturecompression_sprites);
902 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
903 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
904 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
905 Cvar_RegisterVariable (&r_texture_dds_swdecode);
907 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
910 void R_Textures_Frame (void)
912 static int old_aniso = 0;
914 // could do procedural texture animation here, if we keep track of which
915 // textures were accessed this frame...
917 // free the resize buffers
918 resizebuffersize = 0;
921 Mem_Free(resizebuffer);
924 if (colorconvertbuffer)
926 Mem_Free(colorconvertbuffer);
927 colorconvertbuffer = NULL;
930 if (old_aniso != gl_texture_anisotropy.integer)
933 gltexturepool_t *pool;
936 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
938 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
940 switch(vid.renderpath)
942 case RENDERPATH_GL11:
943 case RENDERPATH_GL13:
944 case RENDERPATH_GL20:
945 case RENDERPATH_GLES1:
946 case RENDERPATH_GLES2:
949 for (pool = gltexturepoolchain;pool;pool = pool->next)
951 for (glt = pool->gltchain;glt;glt = glt->chain)
953 // only update already uploaded images
954 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
956 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
958 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
959 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
961 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
966 case RENDERPATH_D3D9:
967 case RENDERPATH_D3D10:
968 case RENDERPATH_D3D11:
969 case RENDERPATH_SOFT:
975 void R_MakeResizeBufferBigger(int size)
977 if (resizebuffersize < size)
979 resizebuffersize = size;
981 Mem_Free(resizebuffer);
982 if (colorconvertbuffer)
983 Mem_Free(colorconvertbuffer);
984 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
985 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
986 if (!resizebuffer || !colorconvertbuffer)
987 Host_Error("R_Upload: out of memory");
991 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
993 int textureenum = gltexturetypeenums[texturetype];
994 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
998 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
1000 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
1001 if (gl_texture_anisotropy.integer != aniso)
1002 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
1003 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
1005 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
1006 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
1007 if (gltexturetypedimensions[texturetype] >= 3)
1009 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
1013 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
1015 if (flags & TEXF_MIPMAP)
1017 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
1021 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
1023 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
1025 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
1027 if (flags & TEXF_MIPMAP)
1029 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
1031 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
1035 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
1040 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
1042 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
1046 if (flags & TEXF_MIPMAP)
1048 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1052 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1054 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1057 if (textype == TEXTYPE_SHADOWMAP)
1059 if (vid.support.arb_shadow)
1061 if (flags & TEXF_COMPARE)
1063 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1067 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1069 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1071 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1077 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1080 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1082 if (glt->texturetype != GLTEXTURETYPE_2D)
1083 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1085 if (glt->textype->textype == TEXTYPE_PALETTE)
1086 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1088 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1089 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1091 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1092 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1094 // update a portion of the image
1096 switch(vid.renderpath)
1098 case RENDERPATH_GL11:
1099 case RENDERPATH_GL13:
1100 case RENDERPATH_GL20:
1101 case RENDERPATH_GLES1:
1102 case RENDERPATH_GLES2:
1106 // we need to restore the texture binding after finishing the upload
1107 GL_ActiveTexture(0);
1108 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1109 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1110 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1111 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1114 case RENDERPATH_D3D9:
1118 D3DLOCKED_RECT d3dlockedrect;
1120 memset(&d3drect, 0, sizeof(d3drect));
1121 d3drect.left = fragx;
1122 d3drect.top = fragy;
1123 d3drect.right = fragx+fragwidth;
1124 d3drect.bottom = fragy+fragheight;
1125 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1127 for (y = 0;y < fragheight;y++)
1128 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1129 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1134 case RENDERPATH_D3D10:
1135 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1137 case RENDERPATH_D3D11:
1138 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1140 case RENDERPATH_SOFT:
1141 DPSOFTRAST_Texture_UpdatePartial(glt->texnum, 0, data, fragx, fragy, fragwidth, fragheight);
1146 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1148 int i, mip = 0, width, height, depth;
1149 GLint oldbindtexnum = 0;
1150 const unsigned char *prevbuffer;
1153 // error out if a stretch is needed on special texture types
1154 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1155 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1157 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1158 // of the target size and then use the mipmap reduction function to get
1159 // high quality supersampled results
1160 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1161 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1162 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1163 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1165 if (prevbuffer == NULL)
1167 width = glt->tilewidth;
1168 height = glt->tileheight;
1169 depth = glt->tiledepth;
1170 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1171 // prevbuffer = resizebuffer;
1175 if (glt->textype->textype == TEXTYPE_PALETTE)
1177 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1178 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1179 prevbuffer = colorconvertbuffer;
1181 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1183 // multiply RGB channels by A channel before uploading
1185 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1187 alpha = prevbuffer[i+3];
1188 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1189 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1190 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1191 colorconvertbuffer[i+3] = alpha;
1193 prevbuffer = colorconvertbuffer;
1195 // scale up to a power of 2 size (if appropriate)
1196 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1198 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1199 prevbuffer = resizebuffer;
1201 // apply mipmap reduction algorithm to get down to picmip/max_size
1202 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1204 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1205 prevbuffer = resizebuffer;
1209 // do the appropriate upload type...
1210 switch(vid.renderpath)
1212 case RENDERPATH_GL11:
1213 case RENDERPATH_GL13:
1214 case RENDERPATH_GL20:
1215 case RENDERPATH_GLES1:
1216 case RENDERPATH_GLES2:
1219 // we need to restore the texture binding after finishing the upload
1220 GL_ActiveTexture(0);
1221 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1222 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1224 if (qglGetCompressedTexImageARB)
1226 if (gl_texturecompression.integer >= 2)
1227 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1229 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1232 switch(glt->texturetype)
1234 case GLTEXTURETYPE_2D:
1235 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1236 if (glt->flags & TEXF_MIPMAP)
1238 while (width > 1 || height > 1 || depth > 1)
1240 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1241 prevbuffer = resizebuffer;
1242 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1246 case GLTEXTURETYPE_3D:
1247 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1248 if (glt->flags & TEXF_MIPMAP)
1250 while (width > 1 || height > 1 || depth > 1)
1252 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1253 prevbuffer = resizebuffer;
1254 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1258 case GLTEXTURETYPE_CUBEMAP:
1259 // convert and upload each side in turn,
1260 // from a continuous block of input texels
1261 texturebuffer = (unsigned char *)prevbuffer;
1262 for (i = 0;i < 6;i++)
1264 prevbuffer = texturebuffer;
1265 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1266 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1268 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1269 prevbuffer = resizebuffer;
1272 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1274 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1275 prevbuffer = resizebuffer;
1278 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1279 if (glt->flags & TEXF_MIPMAP)
1281 while (width > 1 || height > 1 || depth > 1)
1283 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1284 prevbuffer = resizebuffer;
1285 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1291 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1292 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1294 case RENDERPATH_D3D9:
1296 if (!(glt->flags & TEXF_RENDERTARGET))
1298 D3DLOCKED_RECT d3dlockedrect;
1299 D3DLOCKED_BOX d3dlockedbox;
1300 switch(glt->texturetype)
1302 case GLTEXTURETYPE_2D:
1303 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1306 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1308 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1309 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1312 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1314 while (width > 1 || height > 1 || depth > 1)
1316 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1317 prevbuffer = resizebuffer;
1318 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1320 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1321 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1327 case GLTEXTURETYPE_3D:
1328 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1330 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1331 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1332 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1335 if (glt->flags & TEXF_MIPMAP)
1337 while (width > 1 || height > 1 || depth > 1)
1339 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1340 prevbuffer = resizebuffer;
1341 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1343 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1344 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1345 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1351 case GLTEXTURETYPE_CUBEMAP:
1352 // convert and upload each side in turn,
1353 // from a continuous block of input texels
1354 texturebuffer = (unsigned char *)prevbuffer;
1355 for (i = 0;i < 6;i++)
1357 prevbuffer = texturebuffer;
1358 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1359 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1361 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1362 prevbuffer = resizebuffer;
1365 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1367 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1368 prevbuffer = resizebuffer;
1371 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1373 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1374 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1377 if (glt->flags & TEXF_MIPMAP)
1379 while (width > 1 || height > 1 || depth > 1)
1381 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1382 prevbuffer = resizebuffer;
1383 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1385 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1386 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1395 glt->d3daddressw = 0;
1396 if (glt->flags & TEXF_CLAMP)
1398 glt->d3daddressu = D3DTADDRESS_CLAMP;
1399 glt->d3daddressv = D3DTADDRESS_CLAMP;
1400 if (glt->tiledepth > 1)
1401 glt->d3daddressw = D3DTADDRESS_CLAMP;
1405 glt->d3daddressu = D3DTADDRESS_WRAP;
1406 glt->d3daddressv = D3DTADDRESS_WRAP;
1407 if (glt->tiledepth > 1)
1408 glt->d3daddressw = D3DTADDRESS_WRAP;
1410 glt->d3dmipmaplodbias = 0;
1411 glt->d3dmaxmiplevel = 0;
1412 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1413 if (glt->flags & TEXF_FORCELINEAR)
1415 glt->d3dminfilter = D3DTEXF_LINEAR;
1416 glt->d3dmagfilter = D3DTEXF_LINEAR;
1417 glt->d3dmipfilter = D3DTEXF_POINT;
1419 else if (glt->flags & TEXF_FORCENEAREST)
1421 glt->d3dminfilter = D3DTEXF_POINT;
1422 glt->d3dmagfilter = D3DTEXF_POINT;
1423 glt->d3dmipfilter = D3DTEXF_POINT;
1425 else if (glt->flags & TEXF_MIPMAP)
1427 glt->d3dminfilter = d3d_filter_mipmin;
1428 glt->d3dmagfilter = d3d_filter_mipmag;
1429 glt->d3dmipfilter = d3d_filter_mipmix;
1433 glt->d3dminfilter = d3d_filter_flatmin;
1434 glt->d3dmagfilter = d3d_filter_flatmag;
1435 glt->d3dmipfilter = d3d_filter_flatmix;
1439 case RENDERPATH_D3D10:
1440 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1442 case RENDERPATH_D3D11:
1443 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1445 case RENDERPATH_SOFT:
1446 switch(glt->texturetype)
1448 case GLTEXTURETYPE_2D:
1449 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1451 case GLTEXTURETYPE_3D:
1452 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1454 case GLTEXTURETYPE_CUBEMAP:
1455 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1457 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1458 // convert and upload each side in turn,
1459 // from a continuous block of input texels
1460 // copy the results into combinedbuffer
1461 texturebuffer = (unsigned char *)prevbuffer;
1462 for (i = 0;i < 6;i++)
1464 prevbuffer = texturebuffer;
1465 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1466 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1468 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1469 prevbuffer = resizebuffer;
1472 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1474 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1475 prevbuffer = resizebuffer;
1477 memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1479 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1480 Mem_Free(combinedbuffer);
1483 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1486 if (glt->flags & TEXF_FORCELINEAR)
1487 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1488 else if (glt->flags & TEXF_FORCENEAREST)
1489 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1490 else if (glt->flags & TEXF_MIPMAP)
1491 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1493 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1498 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)
1502 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1503 textypeinfo_t *texinfo, *texinfo2;
1504 unsigned char *temppixels = NULL;
1507 if (cls.state == ca_dedicated)
1510 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1514 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1515 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1516 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1517 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1523 static int rgbaswapindices[4] = {2, 1, 0, 3};
1524 size = width * height * depth * sides * 4;
1525 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1526 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1530 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1531 if (!vid.support.ext_texture_srgb)
1533 qboolean convertsRGB = false;
1536 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1537 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1538 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1539 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1540 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;convertsRGB = true;break;
1541 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1542 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1546 if (convertsRGB && data)
1548 size = width * height * depth * sides * 4;
1551 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1552 memcpy(temppixels, data, size);
1554 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1558 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1560 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1563 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1565 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1569 texinfo = R_GetTexTypeInfo(textype, flags);
1570 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1573 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1577 // clear the alpha flag if the texture has no transparent pixels
1580 case TEXTYPE_PALETTE:
1581 case TEXTYPE_SRGB_PALETTE:
1582 if (flags & TEXF_ALPHA)
1584 flags &= ~TEXF_ALPHA;
1587 for (i = 0;i < size;i++)
1589 if (((unsigned char *)&palette[data[i]])[3] < 255)
1591 flags |= TEXF_ALPHA;
1600 case TEXTYPE_SRGB_RGBA:
1601 case TEXTYPE_SRGB_BGRA:
1602 if (flags & TEXF_ALPHA)
1604 flags &= ~TEXF_ALPHA;
1607 for (i = 3;i < size;i += 4)
1611 flags |= TEXF_ALPHA;
1618 case TEXTYPE_SHADOWMAP:
1621 case TEXTYPE_SRGB_DXT1:
1624 case TEXTYPE_SRGB_DXT1A:
1626 case TEXTYPE_SRGB_DXT3:
1628 case TEXTYPE_SRGB_DXT5:
1629 flags |= TEXF_ALPHA;
1632 flags |= TEXF_ALPHA;
1634 case TEXTYPE_COLORBUFFER:
1635 case TEXTYPE_COLORBUFFER16F:
1636 case TEXTYPE_COLORBUFFER32F:
1637 flags |= TEXF_ALPHA;
1640 Sys_Error("R_LoadTexture: unknown texture type");
1643 texinfo2 = R_GetTexTypeInfo(textype, flags);
1644 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1647 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1649 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1651 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1653 glt->chain = pool->gltchain;
1654 pool->gltchain = glt;
1655 glt->inputwidth = width;
1656 glt->inputheight = height;
1657 glt->inputdepth = depth;
1659 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
1660 glt->textype = texinfo;
1661 glt->texturetype = texturetype;
1662 glt->inputdatasize = size;
1663 glt->palette = palette;
1664 glt->glinternalformat = texinfo->glinternalformat;
1665 glt->glformat = texinfo->glformat;
1666 glt->gltype = texinfo->gltype;
1667 glt->bytesperpixel = texinfo->internalbytesperpixel;
1668 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1671 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1672 // init the dynamic texture attributes, too [11/22/2007 Black]
1673 glt->updatecallback = NULL;
1674 glt->updatacallback_data = NULL;
1676 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1678 // upload the texture
1679 // data may be NULL (blank texture for dynamic rendering)
1680 switch(vid.renderpath)
1682 case RENDERPATH_GL11:
1683 case RENDERPATH_GL13:
1684 case RENDERPATH_GL20:
1685 case RENDERPATH_GLES1:
1686 case RENDERPATH_GLES2:
1688 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1690 case RENDERPATH_D3D9:
1693 D3DFORMAT d3dformat;
1698 d3dpool = D3DPOOL_MANAGED;
1699 if (flags & TEXF_RENDERTARGET)
1701 d3dusage |= D3DUSAGE_RENDERTARGET;
1702 d3dpool = D3DPOOL_DEFAULT;
1706 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1707 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1708 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1709 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
1710 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
1711 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
1712 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1713 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1714 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1716 glt->d3dformat = d3dformat;
1717 glt->d3dusage = d3dusage;
1718 glt->d3dpool = d3dpool;
1719 glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1720 if (glt->d3disdepthsurface)
1722 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1723 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1725 else if (glt->tiledepth > 1)
1727 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)))
1728 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1730 else if (glt->sides == 6)
1732 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1733 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1737 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)))
1738 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1743 case RENDERPATH_D3D10:
1744 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1746 case RENDERPATH_D3D11:
1747 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1749 case RENDERPATH_SOFT:
1754 case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1755 case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1756 case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1757 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1758 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
1759 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
1760 case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1761 case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1762 default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1764 if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1765 if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1766 if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1767 if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1768 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1773 R_UploadFullTexture(glt, data);
1774 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1775 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1777 // free any temporary processing buffer we allocated...
1779 Mem_Free(temppixels);
1781 // texture converting and uploading can take a while, so make sure we're sending keepalives
1782 // FIXME: this causes rendering during R_Shadow_DrawLights
1783 // CL_KeepaliveMessage(false);
1785 return (rtexture_t *)glt;
1788 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)
1790 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1793 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)
1795 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1798 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)
1800 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1803 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1805 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1807 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1809 flags |= TEXF_FORCENEAREST;
1810 if (precision <= 16)
1811 flags |= TEXF_LOWPRECISION;
1815 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1817 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1820 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1822 gltexture_t *glt = (gltexture_t *)rt;
1825 int bytesperpixel = 0;
1826 int bytesperblock = 0;
1828 int dds_format_flags;
1836 GLint internalformat;
1837 const char *ddsfourcc;
1839 return -1; // NULL pointer
1840 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1841 return -2; // broken driver - crashes on reading internal format
1842 if (!qglGetTexLevelParameteriv)
1844 GL_ActiveTexture(0);
1845 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1846 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1847 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1848 switch(internalformat)
1850 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1851 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1852 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1853 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1854 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1856 // if premultiplied alpha, say so in the DDS file
1857 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1859 switch(internalformat)
1861 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1862 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1865 if (!bytesperblock && skipuncompressed)
1866 return -3; // skipped
1867 memset(mipinfo, 0, sizeof(mipinfo));
1868 mipinfo[0][0] = glt->tilewidth;
1869 mipinfo[0][1] = glt->tileheight;
1871 if (glt->flags & TEXF_MIPMAP)
1873 for (mip = 1;mip < 16;mip++)
1875 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1876 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1877 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1885 for (mip = 0;mip < mipmaps;mip++)
1887 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1888 mipinfo[mip][3] = ddssize;
1889 ddssize += mipinfo[mip][2];
1891 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1894 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1898 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1899 dds_format_flags = 0x4; // DDPF_FOURCC
1903 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1904 dds_format_flags = 0x40; // DDPF_RGB
1908 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1909 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1912 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1913 memcpy(dds, "DDS ", 4);
1914 StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
1915 StoreLittleLong(dds+8, dds_flags);
1916 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1917 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1918 StoreLittleLong(dds+24, 0); // depth
1919 StoreLittleLong(dds+28, mipmaps); // mipmaps
1920 StoreLittleLong(dds+76, 32); // format size
1921 StoreLittleLong(dds+80, dds_format_flags);
1922 StoreLittleLong(dds+108, dds_caps1);
1923 StoreLittleLong(dds+112, dds_caps2);
1926 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1927 memcpy(dds+84, ddsfourcc, 4);
1928 for (mip = 0;mip < mipmaps;mip++)
1930 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1935 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1936 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1937 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1938 for (mip = 0;mip < mipmaps;mip++)
1940 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1943 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1944 ret = FS_WriteFile(filename, dds, ddssize);
1946 return ret ? ddssize : -5;
1949 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
1951 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1954 int bytesperblock, bytesperpixel;
1957 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1958 textypeinfo_t *texinfo;
1959 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1961 GLint oldbindtexnum = 0;
1962 const unsigned char *mippixels, *ddspixels, *mippixels_start;
1964 fs_offset_t ddsfilesize;
1965 unsigned int ddssize;
1966 qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
1968 if (cls.state == ca_dedicated)
1971 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1972 ddssize = ddsfilesize;
1976 if(r_texture_dds_load_logfailure.integer)
1977 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1978 return NULL; // not found
1981 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1984 Con_Printf("^1%s: not a DDS image\n", filename);
1988 //dds_flags = BuffLittleLong(dds+8);
1989 dds_format_flags = BuffLittleLong(dds+80);
1990 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1991 dds_width = BuffLittleLong(dds+16);
1992 dds_height = BuffLittleLong(dds+12);
1993 ddspixels = dds + 128;
1995 if(r_texture_dds_load_alphamode.integer == 0)
1996 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1997 flags &= ~TEXF_ALPHA;
1999 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
2000 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
2002 // very sloppy BGRA 32bit identification
2003 textype = TEXTYPE_BGRA;
2004 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2007 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
2008 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2011 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
2014 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
2017 for (i = 3;i < size;i += 4)
2018 if (ddspixels[i] < 255)
2021 flags &= ~TEXF_ALPHA;
2024 else if (!memcmp(dds+84, "DXT1", 4))
2026 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
2027 // LordHavoc: it is my belief that this does not infringe on the
2028 // patent because it is not decoding pixels...
2029 textype = TEXTYPE_DXT1;
2032 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
2033 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2034 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2037 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
2040 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
2042 if(r_texture_dds_load_alphamode.integer == 1)
2045 for (i = 0;i < size;i += bytesperblock)
2046 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
2048 // NOTE: this assumes sizeof(unsigned int) == 4
2049 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
2050 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
2051 if(data & (data<<1) & 0xAAAAAAAA)//rgh
2055 textype = TEXTYPE_DXT1A;
2057 flags &= ~TEXF_ALPHA;
2061 flags &= ~TEXF_ALPHA;
2065 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2067 if(!memcmp(dds+84, "DXT2", 4))
2069 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2071 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2076 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2078 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2081 textype = TEXTYPE_DXT3;
2084 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2085 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2088 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2091 // we currently always assume alpha
2093 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2095 if(!memcmp(dds+84, "DXT4", 4))
2097 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2099 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2104 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2106 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2109 textype = TEXTYPE_DXT5;
2112 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2113 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2116 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2119 // we currently always assume alpha
2124 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2128 force_swdecode = false;
2131 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
2133 if(r_texture_dds_swdecode.integer > 1)
2134 force_swdecode = true;
2138 if(r_texture_dds_swdecode.integer < 1)
2144 force_swdecode = true;
2148 // return whether this texture is transparent
2150 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2152 // if we SW decode, choose 2 sizes bigger
2155 // this is quarter res, so do not scale down more than we have to
2159 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2162 // this is where we apply gl_picmip
2163 mippixels_start = ddspixels;
2164 mipwidth = dds_width;
2165 mipheight = dds_height;
2166 while(miplevel >= 1 && dds_miplevels >= 1)
2168 if (mipwidth <= 1 && mipheight <= 1)
2170 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2171 mippixels_start += mipsize; // just skip
2179 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2180 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2182 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2184 // fake decode S3TC if needed
2187 int mipsize_new = mipsize_total / bytesperblock * 4;
2188 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2189 unsigned char *p = mipnewpixels;
2190 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2192 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2193 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2194 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2195 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2196 if(textype == TEXTYPE_DXT5)
2197 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2198 else if(textype == TEXTYPE_DXT3)
2200 (mippixels_start[i-8] & 0x0F)
2201 + (mippixels_start[i-8] >> 4)
2202 + (mippixels_start[i-7] & 0x0F)
2203 + (mippixels_start[i-7] >> 4)
2204 + (mippixels_start[i-6] & 0x0F)
2205 + (mippixels_start[i-6] >> 4)
2206 + (mippixels_start[i-5] & 0x0F)
2207 + (mippixels_start[i-5] >> 4)
2208 ) * (0.125f / 15.0f * 255.0f);
2213 textype = TEXTYPE_BGRA;
2217 // as each block becomes a pixel, we must use pixel count for this
2218 mipwidth = (mipwidth + 3) / 4;
2219 mipheight = (mipheight + 3) / 4;
2220 mipsize = bytesperpixel * mipwidth * mipheight;
2221 mippixels_start = mipnewpixels;
2222 mipsize_total = mipsize_new;
2225 // start mip counting
2226 mippixels = mippixels_start;
2228 // calculate average color if requested
2232 Vector4Clear(avgcolor);
2235 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2237 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2238 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2239 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2240 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2241 if(textype == TEXTYPE_DXT5)
2242 avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2243 else if(textype == TEXTYPE_DXT3)
2245 (mippixels_start[i-8] & 0x0F)
2246 + (mippixels_start[i-8] >> 4)
2247 + (mippixels_start[i-7] & 0x0F)
2248 + (mippixels_start[i-7] >> 4)
2249 + (mippixels_start[i-6] & 0x0F)
2250 + (mippixels_start[i-6] >> 4)
2251 + (mippixels_start[i-5] & 0x0F)
2252 + (mippixels_start[i-5] >> 4)
2253 ) * (0.125f / 15.0f * 255.0f);
2257 f = (float)bytesperblock / size;
2258 avgcolor[0] *= (0.5f / 31.0f) * f;
2259 avgcolor[1] *= (0.5f / 63.0f) * f;
2260 avgcolor[2] *= (0.5f / 31.0f) * f;
2265 for (i = 0;i < mipsize;i += 4)
2267 avgcolor[0] += mippixels[i+2];
2268 avgcolor[1] += mippixels[i+1];
2269 avgcolor[2] += mippixels[i];
2270 avgcolor[3] += mippixels[i+3];
2272 f = (1.0f / 255.0f) * bytesperpixel / size;
2280 // when not requesting mipmaps, do not load them
2281 if(!(flags & TEXF_MIPMAP))
2284 if (dds_miplevels >= 1)
2285 flags |= TEXF_MIPMAP;
2287 flags &= ~TEXF_MIPMAP;
2289 texinfo = R_GetTexTypeInfo(textype, flags);
2291 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2292 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2294 glt->chain = pool->gltchain;
2295 pool->gltchain = glt;
2296 glt->inputwidth = mipwidth;
2297 glt->inputheight = mipheight;
2298 glt->inputdepth = 1;
2300 glt->textype = texinfo;
2301 glt->texturetype = GLTEXTURETYPE_2D;
2302 glt->inputdatasize = ddssize;
2303 glt->glinternalformat = texinfo->glinternalformat;
2304 glt->glformat = texinfo->glformat;
2305 glt->gltype = texinfo->gltype;
2306 glt->bytesperpixel = texinfo->internalbytesperpixel;
2308 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2309 glt->tilewidth = mipwidth;
2310 glt->tileheight = mipheight;
2312 glt->miplevels = dds_miplevels;
2314 // texture uploading can take a while, so make sure we're sending keepalives
2315 CL_KeepaliveMessage(false);
2317 // create the texture object
2318 switch(vid.renderpath)
2320 case RENDERPATH_GL11:
2321 case RENDERPATH_GL13:
2322 case RENDERPATH_GL20:
2323 case RENDERPATH_GLES1:
2324 case RENDERPATH_GLES2:
2326 GL_ActiveTexture(0);
2327 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2328 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2329 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2331 case RENDERPATH_D3D9:
2334 D3DFORMAT d3dformat;
2339 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2340 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2341 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2342 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2343 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2346 d3dpool = D3DPOOL_MANAGED;
2347 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2351 case RENDERPATH_D3D10:
2352 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2354 case RENDERPATH_D3D11:
2355 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2357 case RENDERPATH_SOFT:
2358 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);
2362 // upload the texture
2363 // we need to restore the texture binding after finishing the upload
2364 mipcomplete = false;
2366 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2368 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2369 if (mippixels + mipsize > mippixels_start + mipsize_total)
2371 switch(vid.renderpath)
2373 case RENDERPATH_GL11:
2374 case RENDERPATH_GL13:
2375 case RENDERPATH_GL20:
2376 case RENDERPATH_GLES1:
2377 case RENDERPATH_GLES2:
2380 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2384 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2387 case RENDERPATH_D3D9:
2390 D3DLOCKED_RECT d3dlockedrect;
2391 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2393 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2394 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2400 case RENDERPATH_D3D10:
2401 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2403 case RENDERPATH_D3D11:
2404 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2406 case RENDERPATH_SOFT:
2408 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2410 DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
2411 // DPSOFTRAST calculates its own mipmaps
2412 mip = dds_miplevels;
2415 mippixels += mipsize;
2416 if (mipwidth <= 1 && mipheight <= 1)
2427 // after upload we have to set some parameters...
2428 switch(vid.renderpath)
2430 case RENDERPATH_GL11:
2431 case RENDERPATH_GL13:
2432 case RENDERPATH_GL20:
2433 case RENDERPATH_GLES1:
2434 case RENDERPATH_GLES2:
2435 if (dds_miplevels >= 1 && !mipcomplete)
2437 // need to set GL_TEXTURE_MAX_LEVEL
2438 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2440 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2441 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2443 case RENDERPATH_D3D9:
2445 glt->d3daddressw = 0;
2446 if (glt->flags & TEXF_CLAMP)
2448 glt->d3daddressu = D3DTADDRESS_CLAMP;
2449 glt->d3daddressv = D3DTADDRESS_CLAMP;
2450 if (glt->tiledepth > 1)
2451 glt->d3daddressw = D3DTADDRESS_CLAMP;
2455 glt->d3daddressu = D3DTADDRESS_WRAP;
2456 glt->d3daddressv = D3DTADDRESS_WRAP;
2457 if (glt->tiledepth > 1)
2458 glt->d3daddressw = D3DTADDRESS_WRAP;
2460 glt->d3dmipmaplodbias = 0;
2461 glt->d3dmaxmiplevel = 0;
2462 glt->d3dmaxmiplevelfilter = 0;
2463 if (glt->flags & TEXF_MIPMAP)
2465 glt->d3dminfilter = d3d_filter_mipmin;
2466 glt->d3dmagfilter = d3d_filter_mipmag;
2467 glt->d3dmipfilter = d3d_filter_mipmix;
2471 glt->d3dminfilter = d3d_filter_flatmin;
2472 glt->d3dmagfilter = d3d_filter_flatmag;
2473 glt->d3dmipfilter = d3d_filter_flatmix;
2477 case RENDERPATH_D3D10:
2478 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2480 case RENDERPATH_D3D11:
2481 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2483 case RENDERPATH_SOFT:
2484 if (glt->flags & TEXF_FORCELINEAR)
2485 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2486 else if (glt->flags & TEXF_FORCENEAREST)
2487 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2488 else if (glt->flags & TEXF_MIPMAP)
2489 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2491 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2497 Mem_Free((unsigned char *) mippixels_start);
2498 return (rtexture_t *)glt;
2501 int R_TextureWidth(rtexture_t *rt)
2503 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2506 int R_TextureHeight(rtexture_t *rt)
2508 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2511 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2513 gltexture_t *glt = (gltexture_t *)rt;
2515 Host_Error("R_UpdateTexture: no data supplied");
2517 Host_Error("R_UpdateTexture: no texture supplied");
2518 if (!glt->texnum && !glt->d3dtexture)
2520 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2523 // update part of the texture
2524 if (glt->bufferpixels)
2527 int bpp = glt->bytesperpixel;
2528 int inputskip = width*bpp;
2529 int outputskip = glt->tilewidth*bpp;
2530 const unsigned char *input = data;
2531 unsigned char *output = glt->bufferpixels;
2532 if (glt->inputdepth != 1 || glt->sides != 1)
2533 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2543 input -= y*inputskip;
2546 if (width > glt->tilewidth - x)
2547 width = glt->tilewidth - x;
2548 if (height > glt->tileheight - y)
2549 height = glt->tileheight - y;
2550 if (width < 1 || height < 1)
2553 glt->buffermodified = true;
2554 output += y*outputskip + x*bpp;
2555 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2556 memcpy(output, input, width*bpp);
2558 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2559 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2561 R_UploadFullTexture(glt, data);
2564 int R_RealGetTexture(rtexture_t *rt)
2569 glt = (gltexture_t *)rt;
2570 if (glt->flags & GLTEXF_DYNAMIC)
2571 R_UpdateDynamicTexture(glt);
2572 if (glt->buffermodified && glt->bufferpixels)
2574 glt->buffermodified = false;
2575 R_UploadFullTexture(glt, glt->bufferpixels);
2584 void R_ClearTexture (rtexture_t *rt)
2586 gltexture_t *glt = (gltexture_t *)rt;
2588 R_UploadFullTexture(glt, NULL);
2591 int R_PicmipForFlags(int flags)
2594 if(flags & TEXF_PICMIP)
2596 miplevel += gl_picmip.integer;
2597 if (flags & TEXF_ISWORLD)
2599 if (r_picmipworld.integer)
2600 miplevel += gl_picmip_world.integer;
2604 else if (flags & TEXF_ISSPRITE)
2606 if (r_picmipsprites.integer)
2607 miplevel += gl_picmip_sprites.integer;
2612 miplevel += gl_picmip_other.integer;
2614 return max(0, miplevel);