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
68 int inputbytesperpixel;
69 int internalbytesperpixel;
70 float glinternalbytesperpixel;
77 // framebuffer texture formats
78 static textypeinfo_t textype_shadowmap16 = {TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
79 static textypeinfo_t textype_shadowmap24 = {TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
80 static textypeinfo_t textype_colorbuffer = {TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
81 static textypeinfo_t textype_colorbuffer16f = {TEXTYPE_COLORBUFFER16F, 8, 8, 8.0f, GL_RGBA16F_ARB , GL_RGBA , GL_FLOAT };
82 static textypeinfo_t textype_colorbuffer32f = {TEXTYPE_COLORBUFFER32F, 16, 16, 16.0f, GL_RGBA32F_ARB , GL_RGBA , GL_FLOAT };
85 static textypeinfo_t textype_alpha = {TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
86 static textypeinfo_t textype_palette = {TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
87 static textypeinfo_t textype_palette_alpha = {TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
88 static textypeinfo_t textype_rgba = {TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE };
89 static textypeinfo_t textype_rgba_alpha = {TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
90 static textypeinfo_t textype_rgba_compress = {TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
91 static textypeinfo_t textype_rgba_alpha_compress = {TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
92 static textypeinfo_t textype_bgra = {TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
93 static textypeinfo_t textype_bgra_alpha = {TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
94 static textypeinfo_t textype_bgra_compress = {TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
95 static textypeinfo_t textype_bgra_alpha_compress = {TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
96 static textypeinfo_t textype_dxt1 = {TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
97 static textypeinfo_t textype_dxt1a = {TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 };
98 static textypeinfo_t textype_dxt3 = {TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 };
99 static textypeinfo_t textype_dxt5 = {TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 };
100 static textypeinfo_t textype_sRGB_palette = {TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
101 static textypeinfo_t textype_sRGB_palette_alpha = {TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_ALPHA_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
102 static textypeinfo_t textype_sRGB_rgba = {TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
103 static textypeinfo_t textype_sRGB_rgba_alpha = {TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_ALPHA_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
104 static textypeinfo_t textype_sRGB_rgba_compress = {TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
105 static textypeinfo_t textype_sRGB_rgba_alpha_compress = {TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA , GL_UNSIGNED_BYTE };
106 static textypeinfo_t textype_sRGB_bgra = {TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
107 static textypeinfo_t textype_sRGB_bgra_alpha = {TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_ALPHA_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
108 static textypeinfo_t textype_sRGB_bgra_compress = {TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
109 static textypeinfo_t textype_sRGB_bgra_alpha_compress = {TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_BGRA , GL_UNSIGNED_BYTE };
110 static textypeinfo_t textype_sRGB_dxt1 = {TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , 0 , 0 };
111 static textypeinfo_t textype_sRGB_dxt1a = {TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 , 0 };
112 static textypeinfo_t textype_sRGB_dxt3 = {TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 , 0 };
113 static textypeinfo_t textype_sRGB_dxt5 = {TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 , 0 };
115 typedef enum gltexturetype_e
119 GLTEXTURETYPE_CUBEMAP,
124 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB};
125 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
126 static int cubemapside[6] =
128 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
129 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
130 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
131 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
132 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
133 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
136 typedef struct gltexture_s
138 // this portion of the struct is exposed to the R_GetTexture macro for
139 // speed reasons, must be identical in rtexture_t!
140 int texnum; // GL texture slot number
141 qboolean dirty; // indicates that R_RealGetTexture should be called
142 int gltexturetypeenum; // used by R_Mesh_TexBind
143 // d3d stuff the backend needs
146 qboolean d3disdepthsurface; // for depth/stencil surfaces
156 int d3dmaxmiplevelfilter;
157 int d3dmipmaplodbias;
161 // dynamic texture stuff [11/22/2007 Black]
162 updatecallback_t updatecallback;
163 void *updatacallback_data;
164 // --- [11/22/2007 Black]
166 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
167 unsigned char *bufferpixels;
168 qboolean buffermodified;
170 // pointer to texturepool (check this to see if the texture is allocated)
171 struct gltexturepool_s *pool;
172 // pointer to next texture in texturepool chain
173 struct gltexture_s *chain;
174 // name of the texture (this might be removed someday), no duplicates
175 char identifier[MAX_QPATH + 32];
176 // original data size in *inputtexels
177 int inputwidth, inputheight, inputdepth;
178 // copy of the original texture(s) supplied to the upload function, for
179 // delayed uploads (non-precached)
180 unsigned char *inputtexels;
181 // original data size in *inputtexels
183 // flags supplied to the LoadTexture function
184 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
188 // pointer to one of the textype_ structs
189 textypeinfo_t *textype;
190 // one of the GLTEXTURETYPE_ values
192 // palette if the texture is TEXTYPE_PALETTE
193 const unsigned int *palette;
194 // actual stored texture size after gl_picmip and gl_max_size are applied
195 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
196 int tilewidth, tileheight, tiledepth;
197 // 1 or 6 depending on texturetype
199 // how many mipmap levels in this texture
203 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
206 int glinternalformat;
207 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
212 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
214 typedef struct gltexturepool_s
216 unsigned int sentinel;
217 struct gltexture_s *gltchain;
218 struct gltexturepool_s *next;
222 static gltexturepool_t *gltexturepoolchain = NULL;
224 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
225 static int resizebuffersize = 0;
226 static const unsigned char *texturebuffer;
228 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
232 case TEXTYPE_DXT1: return &textype_dxt1;
233 case TEXTYPE_DXT1A: return &textype_dxt1a;
234 case TEXTYPE_DXT3: return &textype_dxt3;
235 case TEXTYPE_DXT5: return &textype_dxt5;
236 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
237 case TEXTYPE_RGBA: return ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress) : ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba);
238 case TEXTYPE_BGRA: return ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress) : ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra);
239 case TEXTYPE_ALPHA: return &textype_alpha;
240 case TEXTYPE_SHADOWMAP: return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
241 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
242 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
243 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
244 case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1;
245 case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a;
246 case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
247 case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
248 case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
249 case TEXTYPE_SRGB_RGBA: return ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && 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);
250 case TEXTYPE_SRGB_BGRA: return ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && 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);
252 Host_Error("R_GetTexTypeInfo: unknown texture format");
258 // dynamic texture code [11/22/2007 Black]
259 void R_MarkDirtyTexture(rtexture_t *rt) {
260 gltexture_t *glt = (gltexture_t*) rt;
265 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
266 if (glt->flags & GLTEXF_DYNAMIC)
268 // mark it as dirty, so R_RealGetTexture gets called
273 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
274 gltexture_t *glt = (gltexture_t*) rt;
279 glt->flags |= GLTEXF_DYNAMIC;
280 glt->updatecallback = updatecallback;
281 glt->updatacallback_data = data;
284 static void R_UpdateDynamicTexture(gltexture_t *glt) {
286 if( glt->updatecallback ) {
287 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
291 void R_PurgeTexture(rtexture_t *rt)
293 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
298 void R_FreeTexture(rtexture_t *rt)
300 gltexture_t *glt, **gltpointer;
302 glt = (gltexture_t *)rt;
304 Host_Error("R_FreeTexture: texture == NULL");
306 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
307 if (*gltpointer == glt)
308 *gltpointer = glt->chain;
310 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
312 R_Mesh_ClearBindingsForTexture(glt->texnum);
314 switch(vid.renderpath)
316 case RENDERPATH_GL11:
317 case RENDERPATH_GL13:
318 case RENDERPATH_GL20:
319 case RENDERPATH_GLES2:
323 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
326 case RENDERPATH_D3D9:
328 if (glt->d3disdepthsurface)
329 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
330 else if (glt->tiledepth > 1)
331 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
332 else if (glt->sides == 6)
333 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
335 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
336 glt->d3dtexture = NULL;
339 case RENDERPATH_D3D10:
340 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
342 case RENDERPATH_D3D11:
343 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
345 case RENDERPATH_SOFT:
347 DPSOFTRAST_Texture_Free(glt->texnum);
351 if (glt->inputtexels)
352 Mem_Free(glt->inputtexels);
353 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
356 rtexturepool_t *R_AllocTexturePool(void)
358 gltexturepool_t *pool;
359 if (texturemempool == NULL)
361 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
364 pool->next = gltexturepoolchain;
365 gltexturepoolchain = pool;
366 pool->sentinel = TEXTUREPOOL_SENTINEL;
367 return (rtexturepool_t *)pool;
370 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
372 gltexturepool_t *pool, **poolpointer;
373 if (rtexturepool == NULL)
375 if (*rtexturepool == NULL)
377 pool = (gltexturepool_t *)(*rtexturepool);
378 *rtexturepool = NULL;
379 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
380 Host_Error("R_FreeTexturePool: pool already freed");
381 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
382 if (*poolpointer == pool)
383 *poolpointer = pool->next;
385 Host_Error("R_FreeTexturePool: pool not linked");
386 while (pool->gltchain)
387 R_FreeTexture((rtexture_t *)pool->gltchain);
392 typedef struct glmode_s
395 int minification, magnification;
396 DPSOFTRAST_TEXTURE_FILTER dpsoftrastfilter_mipmap, dpsoftrastfilter_nomipmap;
400 static glmode_t modes[6] =
402 {"GL_NEAREST", GL_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
403 {"GL_LINEAR", GL_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
404 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
405 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
406 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
407 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR}
411 typedef struct d3dmode_s
418 static d3dmode_t d3dmodes[6] =
420 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
421 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
422 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
423 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
424 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
425 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
429 static void GL_TextureMode_f (void)
434 gltexturepool_t *pool;
438 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
439 for (i = 0;i < 6;i++)
441 if (gl_filter_min == modes[i].minification)
443 Con_Printf("%s\n", modes[i].name);
447 Con_Print("current filter is unknown???\n");
451 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
452 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
456 Con_Print("bad filter name\n");
460 gl_filter_min = modes[i].minification;
461 gl_filter_mag = modes[i].magnification;
462 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
464 dpsoftrast_filter_mipmap = modes[i].dpsoftrastfilter_mipmap;
465 dpsoftrast_filter_nomipmap = modes[i].dpsoftrastfilter_nomipmap;
467 switch(vid.renderpath)
469 case RENDERPATH_GL11:
470 case RENDERPATH_GL13:
471 case RENDERPATH_GL20:
472 case RENDERPATH_GLES2:
473 // change all the existing mipmap texture objects
474 // FIXME: force renderer(/client/something?) restart instead?
477 for (pool = gltexturepoolchain;pool;pool = pool->next)
479 for (glt = pool->gltchain;glt;glt = glt->chain)
481 // only update already uploaded images
482 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
484 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
485 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
486 if (glt->flags & TEXF_MIPMAP)
488 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
492 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
494 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
495 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
500 case RENDERPATH_D3D9:
502 d3d_filter_flatmin = d3dmodes[i].m1;
503 d3d_filter_flatmag = d3dmodes[i].m1;
504 d3d_filter_flatmix = D3DTEXF_POINT;
505 d3d_filter_mipmin = d3dmodes[i].m1;
506 d3d_filter_mipmag = d3dmodes[i].m1;
507 d3d_filter_mipmix = d3dmodes[i].m2;
508 d3d_filter_nomip = i < 2;
509 if (gl_texture_anisotropy.integer > 1 && i == 5)
510 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
511 for (pool = gltexturepoolchain;pool;pool = pool->next)
513 for (glt = pool->gltchain;glt;glt = glt->chain)
515 // only update already uploaded images
516 if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
518 if (glt->flags & TEXF_MIPMAP)
520 glt->d3dminfilter = d3d_filter_mipmin;
521 glt->d3dmagfilter = d3d_filter_mipmag;
522 glt->d3dmipfilter = d3d_filter_mipmix;
523 glt->d3dmaxmiplevelfilter = 0;
527 glt->d3dminfilter = d3d_filter_flatmin;
528 glt->d3dmagfilter = d3d_filter_flatmag;
529 glt->d3dmipfilter = d3d_filter_flatmix;
530 glt->d3dmaxmiplevelfilter = 0;
537 case RENDERPATH_D3D10:
538 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
540 case RENDERPATH_D3D11:
541 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
543 case RENDERPATH_SOFT:
544 // change all the existing texture objects
545 for (pool = gltexturepoolchain;pool;pool = pool->next)
546 for (glt = pool->gltchain;glt;glt = glt->chain)
547 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
548 DPSOFTRAST_Texture_Filter(glt->texnum, (glt->flags & TEXF_MIPMAP) ? dpsoftrast_filter_mipmap : dpsoftrast_filter_nomipmap);
553 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)
555 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
560 case GLTEXTURETYPE_2D:
561 maxsize = vid.maxtexturesize_2d;
562 if (flags & TEXF_PICMIP)
564 maxsize = bound(1, gl_max_size.integer, maxsize);
568 case GLTEXTURETYPE_3D:
569 maxsize = vid.maxtexturesize_3d;
571 case GLTEXTURETYPE_CUBEMAP:
572 maxsize = vid.maxtexturesize_cubemap;
576 if (vid.support.arb_texture_non_power_of_two)
578 width2 = min(inwidth >> picmip, maxsize);
579 height2 = min(inheight >> picmip, maxsize);
580 depth2 = min(indepth >> picmip, maxsize);
584 for (width2 = 1;width2 < inwidth;width2 <<= 1);
585 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
586 for (height2 = 1;height2 < inheight;height2 <<= 1);
587 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
588 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
589 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
592 switch(vid.renderpath)
594 case RENDERPATH_GL11:
595 case RENDERPATH_GL13:
596 case RENDERPATH_GL20:
597 case RENDERPATH_D3D10:
598 case RENDERPATH_D3D11:
599 case RENDERPATH_SOFT:
600 case RENDERPATH_GLES2:
602 case RENDERPATH_D3D9:
604 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
605 if (texturetype == GLTEXTURETYPE_2D)
607 width2 = max(width2, 2);
608 height2 = max(height2, 2);
615 if (flags & TEXF_MIPMAP)
617 int extent = max(width2, max(height2, depth2));
623 *outwidth = max(1, width2);
625 *outheight = max(1, height2);
627 *outdepth = max(1, depth2);
629 *outmiplevels = miplevels;
633 static int R_CalcTexelDataSize (gltexture_t *glt)
635 int width2, height2, depth2, size;
637 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
639 size = width2 * height2 * depth2;
641 if (glt->flags & TEXF_MIPMAP)
643 while (width2 > 1 || height2 > 1 || depth2 > 1)
651 size += width2 * height2 * depth2;
655 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
658 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
662 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
663 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
665 gltexturepool_t *pool;
667 Con_Print("glsize input loaded mip alpha name\n");
668 for (pool = gltexturepoolchain;pool;pool = pool->next)
676 for (glt = pool->gltchain;glt;glt = glt->chain)
678 glsize = R_CalcTexelDataSize(glt);
679 isloaded = glt->texnum != 0;
681 pooltotalt += glsize;
682 pooltotalp += glt->inputdatasize;
686 poolloadedt += glsize;
687 poolloadedp += glt->inputdatasize;
690 Con_Printf("%c%4i%c%c%4i%c %s %s %s %s\n", isloaded ? '[' : ' ', (glsize + 1023) / 1024, isloaded ? ']' : ' ', glt->inputtexels ? '[' : ' ', (glt->inputdatasize + 1023) / 1024, glt->inputtexels ? ']' : ' ', isloaded ? "loaded" : " ", (glt->flags & TEXF_MIPMAP) ? "mip" : " ", (glt->flags & TEXF_ALPHA) ? "alpha" : " ", glt->identifier);
693 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);
694 sumtotal += pooltotal;
695 sumtotalt += pooltotalt;
696 sumtotalp += pooltotalp;
697 sumloaded += poolloaded;
698 sumloadedt += poolloadedt;
699 sumloadedp += poolloadedp;
702 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);
705 static void R_TextureStats_f(void)
707 R_TextureStats_Print(true, true, true);
710 static void r_textures_start(void)
712 switch(vid.renderpath)
714 case RENDERPATH_GL11:
715 case RENDERPATH_GL13:
716 case RENDERPATH_GL20:
717 case RENDERPATH_GLES2:
718 // LordHavoc: allow any alignment
720 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
721 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
723 case RENDERPATH_D3D9:
725 case RENDERPATH_D3D10:
726 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
728 case RENDERPATH_D3D11:
729 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
731 case RENDERPATH_SOFT:
735 texturemempool = Mem_AllocPool("texture management", 0, NULL);
736 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
738 // Disable JPEG screenshots if the DLL isn't loaded
739 if (! JPEG_OpenLibrary ())
740 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
741 if (! PNG_OpenLibrary ())
742 Cvar_SetValueQuick (&scr_screenshot_png, 0);
745 static void r_textures_shutdown(void)
747 rtexturepool_t *temp;
749 JPEG_CloseLibrary ();
751 while(gltexturepoolchain)
753 temp = (rtexturepool_t *) gltexturepoolchain;
754 R_FreeTexturePool(&temp);
757 resizebuffersize = 0;
759 colorconvertbuffer = NULL;
760 texturebuffer = NULL;
761 Mem_ExpandableArray_FreeArray(&texturearray);
762 Mem_FreePool(&texturemempool);
765 static void r_textures_newmap(void)
769 static void r_textures_devicelost(void)
773 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
774 for (i = 0;i < endindex;i++)
776 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
777 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
779 switch(vid.renderpath)
781 case RENDERPATH_GL11:
782 case RENDERPATH_GL13:
783 case RENDERPATH_GL20:
784 case RENDERPATH_GLES2:
786 case RENDERPATH_D3D9:
788 if (glt->d3disdepthsurface)
789 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
790 else if (glt->tiledepth > 1)
791 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
792 else if (glt->sides == 6)
793 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
795 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
796 glt->d3dtexture = NULL;
799 case RENDERPATH_D3D10:
800 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
802 case RENDERPATH_D3D11:
803 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
805 case RENDERPATH_SOFT:
811 static void r_textures_devicerestored(void)
815 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
816 for (i = 0;i < endindex;i++)
818 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
819 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
821 switch(vid.renderpath)
823 case RENDERPATH_GL11:
824 case RENDERPATH_GL13:
825 case RENDERPATH_GL20:
826 case RENDERPATH_GLES2:
828 case RENDERPATH_D3D9:
832 if (glt->d3disdepthsurface)
834 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
835 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
837 else if (glt->tiledepth > 1)
839 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)))
840 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
842 else if (glt->sides == 6)
844 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
845 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
849 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)))
850 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
855 case RENDERPATH_D3D10:
856 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
858 case RENDERPATH_D3D11:
859 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
861 case RENDERPATH_SOFT:
868 void R_Textures_Init (void)
870 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");
871 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
872 Cvar_RegisterVariable (&gl_max_size);
873 Cvar_RegisterVariable (&gl_picmip);
874 Cvar_RegisterVariable (&gl_picmip_world);
875 Cvar_RegisterVariable (&r_picmipworld);
876 Cvar_RegisterVariable (&gl_picmip_sprites);
877 Cvar_RegisterVariable (&r_picmipsprites);
878 Cvar_RegisterVariable (&gl_picmip_other);
879 Cvar_RegisterVariable (&gl_max_lightmapsize);
880 Cvar_RegisterVariable (&r_lerpimages);
881 Cvar_RegisterVariable (&gl_texture_anisotropy);
882 Cvar_RegisterVariable (&gl_texturecompression);
883 Cvar_RegisterVariable (&gl_texturecompression_color);
884 Cvar_RegisterVariable (&gl_texturecompression_normal);
885 Cvar_RegisterVariable (&gl_texturecompression_gloss);
886 Cvar_RegisterVariable (&gl_texturecompression_glow);
887 Cvar_RegisterVariable (&gl_texturecompression_2d);
888 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
889 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
890 Cvar_RegisterVariable (&gl_texturecompression_sky);
891 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
892 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
893 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
894 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
895 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
896 Cvar_RegisterVariable (&r_texture_dds_swdecode);
898 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
901 void R_Textures_Frame (void)
903 static int old_aniso = 0;
905 // could do procedural texture animation here, if we keep track of which
906 // textures were accessed this frame...
908 // free the resize buffers
909 resizebuffersize = 0;
912 Mem_Free(resizebuffer);
915 if (colorconvertbuffer)
917 Mem_Free(colorconvertbuffer);
918 colorconvertbuffer = NULL;
921 if (old_aniso != gl_texture_anisotropy.integer)
924 gltexturepool_t *pool;
927 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
929 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
931 switch(vid.renderpath)
933 case RENDERPATH_GL11:
934 case RENDERPATH_GL13:
935 case RENDERPATH_GL20:
936 case RENDERPATH_GLES2:
939 for (pool = gltexturepoolchain;pool;pool = pool->next)
941 for (glt = pool->gltchain;glt;glt = glt->chain)
943 // only update already uploaded images
944 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
946 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
948 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
949 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
951 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
956 case RENDERPATH_D3D9:
957 case RENDERPATH_D3D10:
958 case RENDERPATH_D3D11:
959 case RENDERPATH_SOFT:
965 void R_MakeResizeBufferBigger(int size)
967 if (resizebuffersize < size)
969 resizebuffersize = size;
971 Mem_Free(resizebuffer);
972 if (colorconvertbuffer)
973 Mem_Free(colorconvertbuffer);
974 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
975 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
976 if (!resizebuffer || !colorconvertbuffer)
977 Host_Error("R_Upload: out of memory");
981 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
983 int textureenum = gltexturetypeenums[texturetype];
984 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
988 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
990 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
991 if (gl_texture_anisotropy.integer != aniso)
992 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
993 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
995 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
996 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
997 if (gltexturetypedimensions[texturetype] >= 3)
999 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
1003 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
1005 if (flags & TEXF_MIPMAP)
1007 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
1011 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
1013 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
1015 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
1017 if (flags & TEXF_MIPMAP)
1019 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
1021 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
1025 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
1030 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
1032 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
1036 if (flags & TEXF_MIPMAP)
1038 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1042 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1044 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1047 if (textype == TEXTYPE_SHADOWMAP)
1049 if (vid.support.arb_shadow)
1051 if (flags & TEXF_COMPARE)
1053 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1057 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1059 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1061 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1067 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1070 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1072 if (glt->texturetype != GLTEXTURETYPE_2D)
1073 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1075 if (glt->textype->textype == TEXTYPE_PALETTE)
1076 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1078 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1079 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1081 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1082 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1084 // update a portion of the image
1086 switch(vid.renderpath)
1088 case RENDERPATH_GL11:
1089 case RENDERPATH_GL13:
1090 case RENDERPATH_GL20:
1091 case RENDERPATH_GLES2:
1095 // we need to restore the texture binding after finishing the upload
1096 GL_ActiveTexture(0);
1097 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1098 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1099 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1100 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1103 case RENDERPATH_D3D9:
1107 D3DLOCKED_RECT d3dlockedrect;
1109 memset(&d3drect, 0, sizeof(d3drect));
1110 d3drect.left = fragx;
1111 d3drect.top = fragy;
1112 d3drect.right = fragx+fragwidth;
1113 d3drect.bottom = fragy+fragheight;
1114 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1116 for (y = 0;y < fragheight;y++)
1117 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1118 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1123 case RENDERPATH_D3D10:
1124 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1126 case RENDERPATH_D3D11:
1127 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1129 case RENDERPATH_SOFT:
1130 DPSOFTRAST_Texture_UpdatePartial(glt->texnum, 0, data, fragx, fragy, fragwidth, fragheight);
1135 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1137 int i, mip = 0, width, height, depth;
1138 GLint oldbindtexnum = 0;
1139 const unsigned char *prevbuffer;
1142 // error out if a stretch is needed on special texture types
1143 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1144 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1146 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1147 // of the target size and then use the mipmap reduction function to get
1148 // high quality supersampled results
1149 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1150 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1151 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1152 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1154 if (prevbuffer == NULL)
1156 width = glt->tilewidth;
1157 height = glt->tileheight;
1158 depth = glt->tiledepth;
1159 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1160 // prevbuffer = resizebuffer;
1164 if (glt->textype->textype == TEXTYPE_PALETTE)
1166 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1167 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1168 prevbuffer = colorconvertbuffer;
1170 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1172 // multiply RGB channels by A channel before uploading
1174 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1176 alpha = prevbuffer[i+3];
1177 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1178 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1179 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1180 colorconvertbuffer[i+3] = alpha;
1182 prevbuffer = colorconvertbuffer;
1184 // scale up to a power of 2 size (if appropriate)
1185 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1187 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1188 prevbuffer = resizebuffer;
1190 // apply mipmap reduction algorithm to get down to picmip/max_size
1191 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1193 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1194 prevbuffer = resizebuffer;
1198 // do the appropriate upload type...
1199 switch(vid.renderpath)
1201 case RENDERPATH_GL11:
1202 case RENDERPATH_GL13:
1203 case RENDERPATH_GL20:
1204 case RENDERPATH_GLES2:
1207 // we need to restore the texture binding after finishing the upload
1208 GL_ActiveTexture(0);
1209 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1210 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1212 if (qglGetCompressedTexImageARB)
1214 if (gl_texturecompression.integer >= 2)
1215 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1217 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1220 switch(glt->texturetype)
1222 case GLTEXTURETYPE_2D:
1223 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1224 if (glt->flags & TEXF_MIPMAP)
1226 while (width > 1 || height > 1 || depth > 1)
1228 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1229 prevbuffer = resizebuffer;
1230 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1234 case GLTEXTURETYPE_3D:
1235 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 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 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1246 case GLTEXTURETYPE_CUBEMAP:
1247 // convert and upload each side in turn,
1248 // from a continuous block of input texels
1249 texturebuffer = (unsigned char *)prevbuffer;
1250 for (i = 0;i < 6;i++)
1252 prevbuffer = texturebuffer;
1253 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1254 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1256 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1257 prevbuffer = resizebuffer;
1260 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1262 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1263 prevbuffer = resizebuffer;
1266 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1267 if (glt->flags & TEXF_MIPMAP)
1269 while (width > 1 || height > 1 || depth > 1)
1271 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1272 prevbuffer = resizebuffer;
1273 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1279 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1280 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1282 case RENDERPATH_D3D9:
1284 if (!(glt->flags & TEXF_RENDERTARGET))
1286 D3DLOCKED_RECT d3dlockedrect;
1287 D3DLOCKED_BOX d3dlockedbox;
1288 switch(glt->texturetype)
1290 case GLTEXTURETYPE_2D:
1291 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1294 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1296 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1297 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1300 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1302 while (width > 1 || height > 1 || depth > 1)
1304 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1305 prevbuffer = resizebuffer;
1306 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1308 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1309 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1315 case GLTEXTURETYPE_3D:
1316 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1318 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1319 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1320 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1323 if (glt->flags & TEXF_MIPMAP)
1325 while (width > 1 || height > 1 || depth > 1)
1327 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1328 prevbuffer = resizebuffer;
1329 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1331 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1332 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1333 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1339 case GLTEXTURETYPE_CUBEMAP:
1340 // convert and upload each side in turn,
1341 // from a continuous block of input texels
1342 texturebuffer = (unsigned char *)prevbuffer;
1343 for (i = 0;i < 6;i++)
1345 prevbuffer = texturebuffer;
1346 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1347 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1349 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1350 prevbuffer = resizebuffer;
1353 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1355 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1356 prevbuffer = resizebuffer;
1359 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1361 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1362 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1365 if (glt->flags & TEXF_MIPMAP)
1367 while (width > 1 || height > 1 || depth > 1)
1369 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1370 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);
1383 glt->d3daddressw = 0;
1384 if (glt->flags & TEXF_CLAMP)
1386 glt->d3daddressu = D3DTADDRESS_CLAMP;
1387 glt->d3daddressv = D3DTADDRESS_CLAMP;
1388 if (glt->tiledepth > 1)
1389 glt->d3daddressw = D3DTADDRESS_CLAMP;
1393 glt->d3daddressu = D3DTADDRESS_WRAP;
1394 glt->d3daddressv = D3DTADDRESS_WRAP;
1395 if (glt->tiledepth > 1)
1396 glt->d3daddressw = D3DTADDRESS_WRAP;
1398 glt->d3dmipmaplodbias = 0;
1399 glt->d3dmaxmiplevel = 0;
1400 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1401 if (glt->flags & TEXF_FORCELINEAR)
1403 glt->d3dminfilter = D3DTEXF_LINEAR;
1404 glt->d3dmagfilter = D3DTEXF_LINEAR;
1405 glt->d3dmipfilter = D3DTEXF_POINT;
1407 else if (glt->flags & TEXF_FORCENEAREST)
1409 glt->d3dminfilter = D3DTEXF_POINT;
1410 glt->d3dmagfilter = D3DTEXF_POINT;
1411 glt->d3dmipfilter = D3DTEXF_POINT;
1413 else if (glt->flags & TEXF_MIPMAP)
1415 glt->d3dminfilter = d3d_filter_mipmin;
1416 glt->d3dmagfilter = d3d_filter_mipmag;
1417 glt->d3dmipfilter = d3d_filter_mipmix;
1421 glt->d3dminfilter = d3d_filter_flatmin;
1422 glt->d3dmagfilter = d3d_filter_flatmag;
1423 glt->d3dmipfilter = d3d_filter_flatmix;
1427 case RENDERPATH_D3D10:
1428 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1430 case RENDERPATH_D3D11:
1431 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1433 case RENDERPATH_SOFT:
1434 switch(glt->texturetype)
1436 case GLTEXTURETYPE_2D:
1437 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1439 case GLTEXTURETYPE_3D:
1440 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1442 case GLTEXTURETYPE_CUBEMAP:
1443 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1445 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1446 // convert and upload each side in turn,
1447 // from a continuous block of input texels
1448 // copy the results into combinedbuffer
1449 texturebuffer = (unsigned char *)prevbuffer;
1450 for (i = 0;i < 6;i++)
1452 prevbuffer = texturebuffer;
1453 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1454 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1456 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1457 prevbuffer = resizebuffer;
1460 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1462 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1463 prevbuffer = resizebuffer;
1465 memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1467 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1468 Mem_Free(combinedbuffer);
1471 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1474 if (glt->flags & TEXF_FORCELINEAR)
1475 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1476 else if (glt->flags & TEXF_FORCENEAREST)
1477 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1478 else if (glt->flags & TEXF_MIPMAP)
1479 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1481 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1486 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)
1490 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1491 textypeinfo_t *texinfo, *texinfo2;
1492 unsigned char *temppixels = NULL;
1495 if (cls.state == ca_dedicated)
1498 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1502 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1503 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1504 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1505 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1511 static int rgbaswapindices[4] = {2, 1, 0, 3};
1512 size = width * height * depth * sides * 4;
1513 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1514 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1518 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1519 if (!vid.support.ext_texture_srgb)
1521 qboolean convertsRGB = false;
1524 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1525 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1526 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1527 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1528 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;convertsRGB = true;break;
1529 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1530 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1534 if (convertsRGB && data)
1536 size = width * height * depth * sides * 4;
1539 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1540 memcpy(temppixels, data, size);
1542 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1546 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1548 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1551 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1553 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1557 texinfo = R_GetTexTypeInfo(textype, flags);
1558 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1561 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1565 // clear the alpha flag if the texture has no transparent pixels
1568 case TEXTYPE_PALETTE:
1569 case TEXTYPE_SRGB_PALETTE:
1570 if (flags & TEXF_ALPHA)
1572 flags &= ~TEXF_ALPHA;
1575 for (i = 0;i < size;i++)
1577 if (((unsigned char *)&palette[data[i]])[3] < 255)
1579 flags |= TEXF_ALPHA;
1588 case TEXTYPE_SRGB_RGBA:
1589 case TEXTYPE_SRGB_BGRA:
1590 if (flags & TEXF_ALPHA)
1592 flags &= ~TEXF_ALPHA;
1595 for (i = 3;i < size;i += 4)
1599 flags |= TEXF_ALPHA;
1606 case TEXTYPE_SHADOWMAP:
1609 case TEXTYPE_SRGB_DXT1:
1612 case TEXTYPE_SRGB_DXT1A:
1614 case TEXTYPE_SRGB_DXT3:
1616 case TEXTYPE_SRGB_DXT5:
1617 flags |= TEXF_ALPHA;
1620 flags |= TEXF_ALPHA;
1622 case TEXTYPE_COLORBUFFER:
1623 case TEXTYPE_COLORBUFFER16F:
1624 case TEXTYPE_COLORBUFFER32F:
1625 flags |= TEXF_ALPHA;
1628 Sys_Error("R_LoadTexture: unknown texture type");
1631 texinfo2 = R_GetTexTypeInfo(textype, flags);
1632 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1635 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1637 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1639 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1641 glt->chain = pool->gltchain;
1642 pool->gltchain = glt;
1643 glt->inputwidth = width;
1644 glt->inputheight = height;
1645 glt->inputdepth = depth;
1647 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
1648 glt->textype = texinfo;
1649 glt->texturetype = texturetype;
1650 glt->inputdatasize = size;
1651 glt->palette = palette;
1652 glt->glinternalformat = texinfo->glinternalformat;
1653 glt->glformat = texinfo->glformat;
1654 glt->gltype = texinfo->gltype;
1655 glt->bytesperpixel = texinfo->internalbytesperpixel;
1656 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1659 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1660 // init the dynamic texture attributes, too [11/22/2007 Black]
1661 glt->updatecallback = NULL;
1662 glt->updatacallback_data = NULL;
1664 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1666 // upload the texture
1667 // data may be NULL (blank texture for dynamic rendering)
1668 switch(vid.renderpath)
1670 case RENDERPATH_GL11:
1671 case RENDERPATH_GL13:
1672 case RENDERPATH_GL20:
1673 case RENDERPATH_GLES2:
1675 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1677 case RENDERPATH_D3D9:
1680 D3DFORMAT d3dformat;
1685 d3dpool = D3DPOOL_MANAGED;
1686 if (flags & TEXF_RENDERTARGET)
1688 d3dusage |= D3DUSAGE_RENDERTARGET;
1689 d3dpool = D3DPOOL_DEFAULT;
1693 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1694 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1695 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1696 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
1697 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
1698 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
1699 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1700 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1701 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1703 glt->d3dformat = d3dformat;
1704 glt->d3dusage = d3dusage;
1705 glt->d3dpool = d3dpool;
1706 glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1707 if (glt->d3disdepthsurface)
1709 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1710 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1712 else if (glt->tiledepth > 1)
1714 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)))
1715 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1717 else if (glt->sides == 6)
1719 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1720 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1724 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)))
1725 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1730 case RENDERPATH_D3D10:
1731 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1733 case RENDERPATH_D3D11:
1734 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1736 case RENDERPATH_SOFT:
1741 case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1742 case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1743 case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1744 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1745 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
1746 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
1747 case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1748 case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1749 default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1751 if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1752 if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1753 if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1754 if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1755 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1760 R_UploadFullTexture(glt, data);
1761 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1762 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1764 // free any temporary processing buffer we allocated...
1766 Mem_Free(temppixels);
1768 // texture converting and uploading can take a while, so make sure we're sending keepalives
1769 // FIXME: this causes rendering during R_Shadow_DrawLights
1770 // CL_KeepaliveMessage(false);
1772 return (rtexture_t *)glt;
1775 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)
1777 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1780 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)
1782 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1785 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)
1787 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1790 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1792 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1794 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1796 flags |= TEXF_FORCENEAREST;
1797 if (precision <= 16)
1798 flags |= TEXF_LOWPRECISION;
1802 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1804 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1807 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1809 gltexture_t *glt = (gltexture_t *)rt;
1812 int bytesperpixel = 0;
1813 int bytesperblock = 0;
1815 int dds_format_flags;
1823 GLint internalformat;
1824 const char *ddsfourcc;
1826 return -1; // NULL pointer
1827 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1828 return -2; // broken driver - crashes on reading internal format
1829 if (!qglGetTexLevelParameteriv)
1831 GL_ActiveTexture(0);
1832 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1833 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1834 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1835 switch(internalformat)
1837 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1838 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1839 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1840 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1841 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1843 // if premultiplied alpha, say so in the DDS file
1844 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1846 switch(internalformat)
1848 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1849 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1852 if (!bytesperblock && skipuncompressed)
1853 return -3; // skipped
1854 memset(mipinfo, 0, sizeof(mipinfo));
1855 mipinfo[0][0] = glt->tilewidth;
1856 mipinfo[0][1] = glt->tileheight;
1858 if (glt->flags & TEXF_MIPMAP)
1860 for (mip = 1;mip < 16;mip++)
1862 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1863 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1864 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1872 for (mip = 0;mip < mipmaps;mip++)
1874 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1875 mipinfo[mip][3] = ddssize;
1876 ddssize += mipinfo[mip][2];
1878 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1881 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1885 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1886 dds_format_flags = 0x4; // DDPF_FOURCC
1890 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1891 dds_format_flags = 0x40; // DDPF_RGB
1895 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1896 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1899 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1900 memcpy(dds, "DDS ", 4);
1901 StoreLittleLong(dds+4, ddssize);
1902 StoreLittleLong(dds+8, dds_flags);
1903 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1904 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1905 StoreLittleLong(dds+24, 1); // depth
1906 StoreLittleLong(dds+28, mipmaps); // mipmaps
1907 StoreLittleLong(dds+76, 32); // format size
1908 StoreLittleLong(dds+80, dds_format_flags);
1909 StoreLittleLong(dds+108, dds_caps1);
1910 StoreLittleLong(dds+112, dds_caps2);
1913 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1914 memcpy(dds+84, ddsfourcc, 4);
1915 for (mip = 0;mip < mipmaps;mip++)
1917 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1922 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1923 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1924 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1925 for (mip = 0;mip < mipmaps;mip++)
1927 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1930 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1931 ret = FS_WriteFile(filename, dds, ddssize);
1933 return ret ? ddssize : -5;
1936 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
1938 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1941 int bytesperblock, bytesperpixel;
1944 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1945 textypeinfo_t *texinfo;
1946 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1948 GLint oldbindtexnum = 0;
1949 const unsigned char *mippixels, *ddspixels, *mippixels_start;
1951 fs_offset_t ddsfilesize;
1952 unsigned int ddssize;
1953 qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
1955 if (cls.state == ca_dedicated)
1958 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1959 ddssize = ddsfilesize;
1963 if(r_texture_dds_load_logfailure.integer)
1964 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1965 return NULL; // not found
1968 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1971 Con_Printf("^1%s: not a DDS image\n", filename);
1975 //dds_flags = BuffLittleLong(dds+8);
1976 dds_format_flags = BuffLittleLong(dds+80);
1977 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1978 dds_width = BuffLittleLong(dds+16);
1979 dds_height = BuffLittleLong(dds+12);
1980 ddspixels = dds + 128;
1982 if(r_texture_dds_load_alphamode.integer == 0)
1983 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1984 flags &= ~TEXF_ALPHA;
1986 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1987 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1989 // very sloppy BGRA 32bit identification
1990 textype = TEXTYPE_BGRA;
1993 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1994 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1997 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
2000 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
2003 for (i = 3;i < size;i += 4)
2004 if (ddspixels[i] < 255)
2007 flags &= ~TEXF_ALPHA;
2010 else if (!memcmp(dds+84, "DXT1", 4))
2012 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
2013 // LordHavoc: it is my belief that this does not infringe on the
2014 // patent because it is not decoding pixels...
2015 textype = TEXTYPE_DXT1;
2018 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
2019 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2020 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2023 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
2026 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
2028 if(r_texture_dds_load_alphamode.integer == 1)
2031 for (i = 0;i < size;i += bytesperblock)
2032 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
2034 // NOTE: this assumes sizeof(unsigned int) == 4
2035 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
2036 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
2037 if(data & (data<<1) & 0xAAAAAAAA)//rgh
2041 textype = TEXTYPE_DXT1A;
2043 flags &= ~TEXF_ALPHA;
2047 flags &= ~TEXF_ALPHA;
2051 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2053 if(!memcmp(dds+84, "DXT2", 4))
2055 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2057 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2062 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2064 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2067 textype = TEXTYPE_DXT3;
2070 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2071 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2074 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2077 // we currently always assume alpha
2079 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2081 if(!memcmp(dds+84, "DXT4", 4))
2083 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2085 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2090 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2092 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2095 textype = TEXTYPE_DXT5;
2098 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2099 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2102 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2105 // we currently always assume alpha
2110 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2114 force_swdecode = false;
2117 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
2119 if(r_texture_dds_swdecode.integer > 1)
2120 force_swdecode = true;
2124 if(r_texture_dds_swdecode.integer < 1)
2130 force_swdecode = true;
2134 // return whether this texture is transparent
2136 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2138 // if we SW decode, choose 2 sizes bigger
2141 // this is quarter res, so do not scale down more than we have to
2145 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2148 // this is where we apply gl_picmip
2149 mippixels_start = ddspixels;
2150 mipwidth = dds_width;
2151 mipheight = dds_height;
2152 while(miplevel >= 1 && dds_miplevels >= 1)
2154 if (mipwidth <= 1 && mipheight <= 1)
2156 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2157 mippixels_start += mipsize; // just skip
2165 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2166 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2168 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2170 // fake decode S3TC if needed
2173 int mipsize_new = mipsize_total / bytesperblock * 4;
2174 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2175 unsigned char *p = mipnewpixels;
2176 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2178 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2179 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2180 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2181 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2182 if(textype == TEXTYPE_DXT5)
2183 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2184 else if(textype == TEXTYPE_DXT3)
2186 (mippixels_start[i-8] & 0x0F)
2187 + (mippixels_start[i-8] >> 4)
2188 + (mippixels_start[i-7] & 0x0F)
2189 + (mippixels_start[i-7] >> 4)
2190 + (mippixels_start[i-6] & 0x0F)
2191 + (mippixels_start[i-6] >> 4)
2192 + (mippixels_start[i-5] & 0x0F)
2193 + (mippixels_start[i-5] >> 4)
2194 ) * (0.125f / 15.0f * 255.0f);
2199 textype = TEXTYPE_BGRA;
2203 // as each block becomes a pixel, we must use pixel count for this
2204 mipwidth = (mipwidth + 3) / 4;
2205 mipheight = (mipheight + 3) / 4;
2206 mipsize = bytesperpixel * mipwidth * mipheight;
2207 mippixels_start = mipnewpixels;
2208 mipsize_total = mipsize_new;
2211 // start mip counting
2212 mippixels = mippixels_start;
2214 // calculate average color if requested
2218 Vector4Clear(avgcolor);
2221 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2223 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2224 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2225 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2226 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2227 if(textype == TEXTYPE_DXT5)
2228 avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2229 else if(textype == TEXTYPE_DXT3)
2231 (mippixels_start[i-8] & 0x0F)
2232 + (mippixels_start[i-8] >> 4)
2233 + (mippixels_start[i-7] & 0x0F)
2234 + (mippixels_start[i-7] >> 4)
2235 + (mippixels_start[i-6] & 0x0F)
2236 + (mippixels_start[i-6] >> 4)
2237 + (mippixels_start[i-5] & 0x0F)
2238 + (mippixels_start[i-5] >> 4)
2239 ) * (0.125f / 15.0f * 255.0f);
2243 f = (float)bytesperblock / size;
2244 avgcolor[0] *= (0.5f / 31.0f) * f;
2245 avgcolor[1] *= (0.5f / 63.0f) * f;
2246 avgcolor[2] *= (0.5f / 31.0f) * f;
2251 for (i = 0;i < mipsize;i += 4)
2253 avgcolor[0] += mippixels[i+2];
2254 avgcolor[1] += mippixels[i+1];
2255 avgcolor[2] += mippixels[i];
2256 avgcolor[3] += mippixels[i+3];
2258 f = (1.0f / 255.0f) * bytesperpixel / size;
2266 // when not requesting mipmaps, do not load them
2267 if(!(flags & TEXF_MIPMAP))
2270 if (dds_miplevels >= 1)
2271 flags |= TEXF_MIPMAP;
2273 flags &= ~TEXF_MIPMAP;
2275 texinfo = R_GetTexTypeInfo(textype, flags);
2277 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2278 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2280 glt->chain = pool->gltchain;
2281 pool->gltchain = glt;
2282 glt->inputwidth = mipwidth;
2283 glt->inputheight = mipheight;
2284 glt->inputdepth = 1;
2286 glt->textype = texinfo;
2287 glt->texturetype = GLTEXTURETYPE_2D;
2288 glt->inputdatasize = ddssize;
2289 glt->glinternalformat = texinfo->glinternalformat;
2290 glt->glformat = texinfo->glformat;
2291 glt->gltype = texinfo->gltype;
2292 glt->bytesperpixel = texinfo->internalbytesperpixel;
2294 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2295 glt->tilewidth = mipwidth;
2296 glt->tileheight = mipheight;
2298 glt->miplevels = dds_miplevels;
2300 // texture uploading can take a while, so make sure we're sending keepalives
2301 CL_KeepaliveMessage(false);
2303 // create the texture object
2304 switch(vid.renderpath)
2306 case RENDERPATH_GL11:
2307 case RENDERPATH_GL13:
2308 case RENDERPATH_GL20:
2309 case RENDERPATH_GLES2:
2311 GL_ActiveTexture(0);
2312 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2313 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2314 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2316 case RENDERPATH_D3D9:
2319 D3DFORMAT d3dformat;
2324 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2325 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2326 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2327 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2328 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2331 d3dpool = D3DPOOL_MANAGED;
2332 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2336 case RENDERPATH_D3D10:
2337 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2339 case RENDERPATH_D3D11:
2340 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2342 case RENDERPATH_SOFT:
2343 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);
2347 // upload the texture
2348 // we need to restore the texture binding after finishing the upload
2349 mipcomplete = false;
2351 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2353 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2354 if (mippixels + mipsize > mippixels_start + mipsize_total)
2356 switch(vid.renderpath)
2358 case RENDERPATH_GL11:
2359 case RENDERPATH_GL13:
2360 case RENDERPATH_GL20:
2361 case RENDERPATH_GLES2:
2364 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2368 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2371 case RENDERPATH_D3D9:
2374 D3DLOCKED_RECT d3dlockedrect;
2375 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2377 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2378 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2384 case RENDERPATH_D3D10:
2385 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2387 case RENDERPATH_D3D11:
2388 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2390 case RENDERPATH_SOFT:
2392 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2394 DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
2395 // DPSOFTRAST calculates its own mipmaps
2396 mip = dds_miplevels;
2399 mippixels += mipsize;
2400 if (mipwidth <= 1 && mipheight <= 1)
2411 // after upload we have to set some parameters...
2412 switch(vid.renderpath)
2414 case RENDERPATH_GL11:
2415 case RENDERPATH_GL13:
2416 case RENDERPATH_GL20:
2417 case RENDERPATH_GLES2:
2418 if (dds_miplevels >= 1 && !mipcomplete)
2420 // need to set GL_TEXTURE_MAX_LEVEL
2421 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2423 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2424 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2426 case RENDERPATH_D3D9:
2428 glt->d3daddressw = 0;
2429 if (glt->flags & TEXF_CLAMP)
2431 glt->d3daddressu = D3DTADDRESS_CLAMP;
2432 glt->d3daddressv = D3DTADDRESS_CLAMP;
2433 if (glt->tiledepth > 1)
2434 glt->d3daddressw = D3DTADDRESS_CLAMP;
2438 glt->d3daddressu = D3DTADDRESS_WRAP;
2439 glt->d3daddressv = D3DTADDRESS_WRAP;
2440 if (glt->tiledepth > 1)
2441 glt->d3daddressw = D3DTADDRESS_WRAP;
2443 glt->d3dmipmaplodbias = 0;
2444 glt->d3dmaxmiplevel = 0;
2445 glt->d3dmaxmiplevelfilter = 0;
2446 if (glt->flags & TEXF_MIPMAP)
2448 glt->d3dminfilter = d3d_filter_mipmin;
2449 glt->d3dmagfilter = d3d_filter_mipmag;
2450 glt->d3dmipfilter = d3d_filter_mipmix;
2454 glt->d3dminfilter = d3d_filter_flatmin;
2455 glt->d3dmagfilter = d3d_filter_flatmag;
2456 glt->d3dmipfilter = d3d_filter_flatmix;
2460 case RENDERPATH_D3D10:
2461 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2463 case RENDERPATH_D3D11:
2464 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2466 case RENDERPATH_SOFT:
2467 if (glt->flags & TEXF_FORCELINEAR)
2468 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2469 else if (glt->flags & TEXF_FORCENEAREST)
2470 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2471 else if (glt->flags & TEXF_MIPMAP)
2472 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2474 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2480 Mem_Free((unsigned char *) mippixels_start);
2481 return (rtexture_t *)glt;
2484 int R_TextureWidth(rtexture_t *rt)
2486 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2489 int R_TextureHeight(rtexture_t *rt)
2491 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2494 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2496 gltexture_t *glt = (gltexture_t *)rt;
2498 Host_Error("R_UpdateTexture: no data supplied");
2500 Host_Error("R_UpdateTexture: no texture supplied");
2501 if (!glt->texnum && !glt->d3dtexture)
2503 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2506 // update part of the texture
2507 if (glt->bufferpixels)
2510 int bpp = glt->bytesperpixel;
2511 int inputskip = width*bpp;
2512 int outputskip = glt->tilewidth*bpp;
2513 const unsigned char *input = data;
2514 unsigned char *output = glt->bufferpixels;
2515 if (glt->inputdepth != 1 || glt->sides != 1)
2516 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2526 input -= y*inputskip;
2529 if (width > glt->tilewidth - x)
2530 width = glt->tilewidth - x;
2531 if (height > glt->tileheight - y)
2532 height = glt->tileheight - y;
2533 if (width < 1 || height < 1)
2536 glt->buffermodified = true;
2537 output += y*outputskip + x*bpp;
2538 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2539 memcpy(output, input, width*bpp);
2541 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2542 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2544 R_UploadFullTexture(glt, data);
2547 int R_RealGetTexture(rtexture_t *rt)
2552 glt = (gltexture_t *)rt;
2553 if (glt->flags & GLTEXF_DYNAMIC)
2554 R_UpdateDynamicTexture(glt);
2555 if (glt->buffermodified && glt->bufferpixels)
2557 glt->buffermodified = false;
2558 R_UploadFullTexture(glt, glt->bufferpixels);
2567 void R_ClearTexture (rtexture_t *rt)
2569 gltexture_t *glt = (gltexture_t *)rt;
2571 R_UploadFullTexture(glt, NULL);
2574 int R_PicmipForFlags(int flags)
2577 if(flags & TEXF_PICMIP)
2579 miplevel += gl_picmip.integer;
2580 if (flags & TEXF_ISWORLD)
2582 if (r_picmipworld.integer)
2583 miplevel += gl_picmip_world.integer;
2587 else if (flags & TEXF_ISSPRITE)
2589 if (r_picmipsprites.integer)
2590 miplevel += gl_picmip_sprites.integer;
2595 miplevel += gl_picmip_other.integer;
2597 return max(0, miplevel);