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_GLES1:
320 case RENDERPATH_GLES2:
324 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
327 case RENDERPATH_D3D9:
329 if (glt->d3disdepthsurface)
330 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
331 else if (glt->tiledepth > 1)
332 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
333 else if (glt->sides == 6)
334 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
336 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
337 glt->d3dtexture = NULL;
340 case RENDERPATH_D3D10:
341 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
343 case RENDERPATH_D3D11:
344 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
346 case RENDERPATH_SOFT:
348 DPSOFTRAST_Texture_Free(glt->texnum);
352 if (glt->inputtexels)
353 Mem_Free(glt->inputtexels);
354 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
357 rtexturepool_t *R_AllocTexturePool(void)
359 gltexturepool_t *pool;
360 if (texturemempool == NULL)
362 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
365 pool->next = gltexturepoolchain;
366 gltexturepoolchain = pool;
367 pool->sentinel = TEXTUREPOOL_SENTINEL;
368 return (rtexturepool_t *)pool;
371 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
373 gltexturepool_t *pool, **poolpointer;
374 if (rtexturepool == NULL)
376 if (*rtexturepool == NULL)
378 pool = (gltexturepool_t *)(*rtexturepool);
379 *rtexturepool = NULL;
380 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
381 Host_Error("R_FreeTexturePool: pool already freed");
382 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
383 if (*poolpointer == pool)
384 *poolpointer = pool->next;
386 Host_Error("R_FreeTexturePool: pool not linked");
387 while (pool->gltchain)
388 R_FreeTexture((rtexture_t *)pool->gltchain);
393 typedef struct glmode_s
396 int minification, magnification;
397 DPSOFTRAST_TEXTURE_FILTER dpsoftrastfilter_mipmap, dpsoftrastfilter_nomipmap;
401 static glmode_t modes[6] =
403 {"GL_NEAREST", GL_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
404 {"GL_LINEAR", GL_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
405 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
406 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
407 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
408 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR}
412 typedef struct d3dmode_s
419 static d3dmode_t d3dmodes[6] =
421 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
422 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
423 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
424 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
425 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
426 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
430 static void GL_TextureMode_f (void)
435 gltexturepool_t *pool;
439 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
440 for (i = 0;i < 6;i++)
442 if (gl_filter_min == modes[i].minification)
444 Con_Printf("%s\n", modes[i].name);
448 Con_Print("current filter is unknown???\n");
452 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
453 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
457 Con_Print("bad filter name\n");
461 gl_filter_min = modes[i].minification;
462 gl_filter_mag = modes[i].magnification;
463 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
465 dpsoftrast_filter_mipmap = modes[i].dpsoftrastfilter_mipmap;
466 dpsoftrast_filter_nomipmap = modes[i].dpsoftrastfilter_nomipmap;
468 switch(vid.renderpath)
470 case RENDERPATH_GL11:
471 case RENDERPATH_GL13:
472 case RENDERPATH_GL20:
473 case RENDERPATH_GLES1:
474 case RENDERPATH_GLES2:
475 // change all the existing mipmap texture objects
476 // FIXME: force renderer(/client/something?) restart instead?
479 for (pool = gltexturepoolchain;pool;pool = pool->next)
481 for (glt = pool->gltchain;glt;glt = glt->chain)
483 // only update already uploaded images
484 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
486 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
487 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
488 if (glt->flags & TEXF_MIPMAP)
490 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
494 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
496 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
497 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
502 case RENDERPATH_D3D9:
504 d3d_filter_flatmin = d3dmodes[i].m1;
505 d3d_filter_flatmag = d3dmodes[i].m1;
506 d3d_filter_flatmix = D3DTEXF_POINT;
507 d3d_filter_mipmin = d3dmodes[i].m1;
508 d3d_filter_mipmag = d3dmodes[i].m1;
509 d3d_filter_mipmix = d3dmodes[i].m2;
510 d3d_filter_nomip = i < 2;
511 if (gl_texture_anisotropy.integer > 1 && i == 5)
512 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
513 for (pool = gltexturepoolchain;pool;pool = pool->next)
515 for (glt = pool->gltchain;glt;glt = glt->chain)
517 // only update already uploaded images
518 if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
520 if (glt->flags & TEXF_MIPMAP)
522 glt->d3dminfilter = d3d_filter_mipmin;
523 glt->d3dmagfilter = d3d_filter_mipmag;
524 glt->d3dmipfilter = d3d_filter_mipmix;
525 glt->d3dmaxmiplevelfilter = 0;
529 glt->d3dminfilter = d3d_filter_flatmin;
530 glt->d3dmagfilter = d3d_filter_flatmag;
531 glt->d3dmipfilter = d3d_filter_flatmix;
532 glt->d3dmaxmiplevelfilter = 0;
539 case RENDERPATH_D3D10:
540 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
542 case RENDERPATH_D3D11:
543 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
545 case RENDERPATH_SOFT:
546 // change all the existing texture objects
547 for (pool = gltexturepoolchain;pool;pool = pool->next)
548 for (glt = pool->gltchain;glt;glt = glt->chain)
549 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
550 DPSOFTRAST_Texture_Filter(glt->texnum, (glt->flags & TEXF_MIPMAP) ? dpsoftrast_filter_mipmap : dpsoftrast_filter_nomipmap);
555 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)
557 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
562 case GLTEXTURETYPE_2D:
563 maxsize = vid.maxtexturesize_2d;
564 if (flags & TEXF_PICMIP)
566 maxsize = bound(1, gl_max_size.integer, maxsize);
570 case GLTEXTURETYPE_3D:
571 maxsize = vid.maxtexturesize_3d;
573 case GLTEXTURETYPE_CUBEMAP:
574 maxsize = vid.maxtexturesize_cubemap;
578 if (vid.support.arb_texture_non_power_of_two)
580 width2 = min(inwidth >> picmip, maxsize);
581 height2 = min(inheight >> picmip, maxsize);
582 depth2 = min(indepth >> picmip, maxsize);
586 for (width2 = 1;width2 < inwidth;width2 <<= 1);
587 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
588 for (height2 = 1;height2 < inheight;height2 <<= 1);
589 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
590 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
591 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
594 switch(vid.renderpath)
596 case RENDERPATH_GL11:
597 case RENDERPATH_GL13:
598 case RENDERPATH_GL20:
599 case RENDERPATH_D3D10:
600 case RENDERPATH_D3D11:
601 case RENDERPATH_SOFT:
602 case RENDERPATH_GLES1:
603 case RENDERPATH_GLES2:
605 case RENDERPATH_D3D9:
607 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
608 if (texturetype == GLTEXTURETYPE_2D)
610 width2 = max(width2, 2);
611 height2 = max(height2, 2);
618 if (flags & TEXF_MIPMAP)
620 int extent = max(width2, max(height2, depth2));
626 *outwidth = max(1, width2);
628 *outheight = max(1, height2);
630 *outdepth = max(1, depth2);
632 *outmiplevels = miplevels;
636 static int R_CalcTexelDataSize (gltexture_t *glt)
638 int width2, height2, depth2, size;
640 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
642 size = width2 * height2 * depth2;
644 if (glt->flags & TEXF_MIPMAP)
646 while (width2 > 1 || height2 > 1 || depth2 > 1)
654 size += width2 * height2 * depth2;
658 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
661 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
665 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
666 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
668 gltexturepool_t *pool;
670 Con_Print("glsize input loaded mip alpha name\n");
671 for (pool = gltexturepoolchain;pool;pool = pool->next)
679 for (glt = pool->gltchain;glt;glt = glt->chain)
681 glsize = R_CalcTexelDataSize(glt);
682 isloaded = glt->texnum != 0;
684 pooltotalt += glsize;
685 pooltotalp += glt->inputdatasize;
689 poolloadedt += glsize;
690 poolloadedp += glt->inputdatasize;
693 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);
696 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);
697 sumtotal += pooltotal;
698 sumtotalt += pooltotalt;
699 sumtotalp += pooltotalp;
700 sumloaded += poolloaded;
701 sumloadedt += poolloadedt;
702 sumloadedp += poolloadedp;
705 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);
708 static void R_TextureStats_f(void)
710 R_TextureStats_Print(true, true, true);
713 static void r_textures_start(void)
715 switch(vid.renderpath)
717 case RENDERPATH_GL11:
718 case RENDERPATH_GL13:
719 case RENDERPATH_GL20:
720 case RENDERPATH_GLES1:
721 case RENDERPATH_GLES2:
722 // LordHavoc: allow any alignment
724 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
725 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
727 case RENDERPATH_D3D9:
729 case RENDERPATH_D3D10:
730 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
732 case RENDERPATH_D3D11:
733 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
735 case RENDERPATH_SOFT:
739 texturemempool = Mem_AllocPool("texture management", 0, NULL);
740 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
742 // Disable JPEG screenshots if the DLL isn't loaded
743 if (! JPEG_OpenLibrary ())
744 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
745 if (! PNG_OpenLibrary ())
746 Cvar_SetValueQuick (&scr_screenshot_png, 0);
749 static void r_textures_shutdown(void)
751 rtexturepool_t *temp;
753 JPEG_CloseLibrary ();
755 while(gltexturepoolchain)
757 temp = (rtexturepool_t *) gltexturepoolchain;
758 R_FreeTexturePool(&temp);
761 resizebuffersize = 0;
763 colorconvertbuffer = NULL;
764 texturebuffer = NULL;
765 Mem_ExpandableArray_FreeArray(&texturearray);
766 Mem_FreePool(&texturemempool);
769 static void r_textures_newmap(void)
773 static void r_textures_devicelost(void)
777 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
778 for (i = 0;i < endindex;i++)
780 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
781 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
783 switch(vid.renderpath)
785 case RENDERPATH_GL11:
786 case RENDERPATH_GL13:
787 case RENDERPATH_GL20:
788 case RENDERPATH_GLES1:
789 case RENDERPATH_GLES2:
791 case RENDERPATH_D3D9:
793 if (glt->d3disdepthsurface)
794 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
795 else if (glt->tiledepth > 1)
796 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
797 else if (glt->sides == 6)
798 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
800 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
801 glt->d3dtexture = NULL;
804 case RENDERPATH_D3D10:
805 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
807 case RENDERPATH_D3D11:
808 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
810 case RENDERPATH_SOFT:
816 static void r_textures_devicerestored(void)
820 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
821 for (i = 0;i < endindex;i++)
823 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
824 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
826 switch(vid.renderpath)
828 case RENDERPATH_GL11:
829 case RENDERPATH_GL13:
830 case RENDERPATH_GL20:
831 case RENDERPATH_GLES1:
832 case RENDERPATH_GLES2:
834 case RENDERPATH_D3D9:
838 if (glt->d3disdepthsurface)
840 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
841 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
843 else if (glt->tiledepth > 1)
845 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)))
846 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
848 else if (glt->sides == 6)
850 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
851 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
855 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)))
856 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
861 case RENDERPATH_D3D10:
862 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
864 case RENDERPATH_D3D11:
865 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
867 case RENDERPATH_SOFT:
874 void R_Textures_Init (void)
876 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");
877 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
878 Cvar_RegisterVariable (&gl_max_size);
879 Cvar_RegisterVariable (&gl_picmip);
880 Cvar_RegisterVariable (&gl_picmip_world);
881 Cvar_RegisterVariable (&r_picmipworld);
882 Cvar_RegisterVariable (&gl_picmip_sprites);
883 Cvar_RegisterVariable (&r_picmipsprites);
884 Cvar_RegisterVariable (&gl_picmip_other);
885 Cvar_RegisterVariable (&gl_max_lightmapsize);
886 Cvar_RegisterVariable (&r_lerpimages);
887 Cvar_RegisterVariable (&gl_texture_anisotropy);
888 Cvar_RegisterVariable (&gl_texturecompression);
889 Cvar_RegisterVariable (&gl_texturecompression_color);
890 Cvar_RegisterVariable (&gl_texturecompression_normal);
891 Cvar_RegisterVariable (&gl_texturecompression_gloss);
892 Cvar_RegisterVariable (&gl_texturecompression_glow);
893 Cvar_RegisterVariable (&gl_texturecompression_2d);
894 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
895 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
896 Cvar_RegisterVariable (&gl_texturecompression_sky);
897 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
898 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
899 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
900 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
901 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
902 Cvar_RegisterVariable (&r_texture_dds_swdecode);
904 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
907 void R_Textures_Frame (void)
909 static int old_aniso = 0;
911 // could do procedural texture animation here, if we keep track of which
912 // textures were accessed this frame...
914 // free the resize buffers
915 resizebuffersize = 0;
918 Mem_Free(resizebuffer);
921 if (colorconvertbuffer)
923 Mem_Free(colorconvertbuffer);
924 colorconvertbuffer = NULL;
927 if (old_aniso != gl_texture_anisotropy.integer)
930 gltexturepool_t *pool;
933 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
935 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
937 switch(vid.renderpath)
939 case RENDERPATH_GL11:
940 case RENDERPATH_GL13:
941 case RENDERPATH_GL20:
942 case RENDERPATH_GLES1:
943 case RENDERPATH_GLES2:
946 for (pool = gltexturepoolchain;pool;pool = pool->next)
948 for (glt = pool->gltchain;glt;glt = glt->chain)
950 // only update already uploaded images
951 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
953 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
955 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
956 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
958 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
963 case RENDERPATH_D3D9:
964 case RENDERPATH_D3D10:
965 case RENDERPATH_D3D11:
966 case RENDERPATH_SOFT:
972 void R_MakeResizeBufferBigger(int size)
974 if (resizebuffersize < size)
976 resizebuffersize = size;
978 Mem_Free(resizebuffer);
979 if (colorconvertbuffer)
980 Mem_Free(colorconvertbuffer);
981 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
982 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
983 if (!resizebuffer || !colorconvertbuffer)
984 Host_Error("R_Upload: out of memory");
988 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
990 int textureenum = gltexturetypeenums[texturetype];
991 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
995 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
997 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
998 if (gl_texture_anisotropy.integer != aniso)
999 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
1000 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
1002 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
1003 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
1004 if (gltexturetypedimensions[texturetype] >= 3)
1006 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
1010 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
1012 if (flags & TEXF_MIPMAP)
1014 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
1018 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
1020 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
1022 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
1024 if (flags & TEXF_MIPMAP)
1026 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
1028 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
1032 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
1037 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
1039 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
1043 if (flags & TEXF_MIPMAP)
1045 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1049 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1051 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1054 if (textype == TEXTYPE_SHADOWMAP)
1056 if (vid.support.arb_shadow)
1058 if (flags & TEXF_COMPARE)
1060 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1064 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1066 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1068 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1074 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1077 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1079 if (glt->texturetype != GLTEXTURETYPE_2D)
1080 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1082 if (glt->textype->textype == TEXTYPE_PALETTE)
1083 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1085 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1086 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1088 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1089 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1091 // update a portion of the image
1093 switch(vid.renderpath)
1095 case RENDERPATH_GL11:
1096 case RENDERPATH_GL13:
1097 case RENDERPATH_GL20:
1098 case RENDERPATH_GLES1:
1099 case RENDERPATH_GLES2:
1103 // we need to restore the texture binding after finishing the upload
1104 GL_ActiveTexture(0);
1105 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1106 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1107 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1108 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1111 case RENDERPATH_D3D9:
1115 D3DLOCKED_RECT d3dlockedrect;
1117 memset(&d3drect, 0, sizeof(d3drect));
1118 d3drect.left = fragx;
1119 d3drect.top = fragy;
1120 d3drect.right = fragx+fragwidth;
1121 d3drect.bottom = fragy+fragheight;
1122 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1124 for (y = 0;y < fragheight;y++)
1125 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1126 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1131 case RENDERPATH_D3D10:
1132 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1134 case RENDERPATH_D3D11:
1135 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1137 case RENDERPATH_SOFT:
1138 DPSOFTRAST_Texture_UpdatePartial(glt->texnum, 0, data, fragx, fragy, fragwidth, fragheight);
1143 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1145 int i, mip = 0, width, height, depth;
1146 GLint oldbindtexnum = 0;
1147 const unsigned char *prevbuffer;
1150 // error out if a stretch is needed on special texture types
1151 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1152 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1154 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1155 // of the target size and then use the mipmap reduction function to get
1156 // high quality supersampled results
1157 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1158 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1159 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1160 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1162 if (prevbuffer == NULL)
1164 width = glt->tilewidth;
1165 height = glt->tileheight;
1166 depth = glt->tiledepth;
1167 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1168 // prevbuffer = resizebuffer;
1172 if (glt->textype->textype == TEXTYPE_PALETTE)
1174 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1175 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1176 prevbuffer = colorconvertbuffer;
1178 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1180 // multiply RGB channels by A channel before uploading
1182 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1184 alpha = prevbuffer[i+3];
1185 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1186 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1187 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1188 colorconvertbuffer[i+3] = alpha;
1190 prevbuffer = colorconvertbuffer;
1192 // scale up to a power of 2 size (if appropriate)
1193 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1195 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1196 prevbuffer = resizebuffer;
1198 // apply mipmap reduction algorithm to get down to picmip/max_size
1199 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1201 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1202 prevbuffer = resizebuffer;
1206 // do the appropriate upload type...
1207 switch(vid.renderpath)
1209 case RENDERPATH_GL11:
1210 case RENDERPATH_GL13:
1211 case RENDERPATH_GL20:
1212 case RENDERPATH_GLES1:
1213 case RENDERPATH_GLES2:
1216 // we need to restore the texture binding after finishing the upload
1217 GL_ActiveTexture(0);
1218 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1219 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1221 if (qglGetCompressedTexImageARB)
1223 if (gl_texturecompression.integer >= 2)
1224 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1226 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1229 switch(glt->texturetype)
1231 case GLTEXTURETYPE_2D:
1232 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1233 if (glt->flags & TEXF_MIPMAP)
1235 while (width > 1 || height > 1 || depth > 1)
1237 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1238 prevbuffer = resizebuffer;
1239 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1243 case GLTEXTURETYPE_3D:
1244 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1245 if (glt->flags & TEXF_MIPMAP)
1247 while (width > 1 || height > 1 || depth > 1)
1249 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1250 prevbuffer = resizebuffer;
1251 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1255 case GLTEXTURETYPE_CUBEMAP:
1256 // convert and upload each side in turn,
1257 // from a continuous block of input texels
1258 texturebuffer = (unsigned char *)prevbuffer;
1259 for (i = 0;i < 6;i++)
1261 prevbuffer = texturebuffer;
1262 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1263 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1265 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1266 prevbuffer = resizebuffer;
1269 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1271 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1272 prevbuffer = resizebuffer;
1275 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1276 if (glt->flags & TEXF_MIPMAP)
1278 while (width > 1 || height > 1 || depth > 1)
1280 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1281 prevbuffer = resizebuffer;
1282 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1288 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1289 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1291 case RENDERPATH_D3D9:
1293 if (!(glt->flags & TEXF_RENDERTARGET))
1295 D3DLOCKED_RECT d3dlockedrect;
1296 D3DLOCKED_BOX d3dlockedbox;
1297 switch(glt->texturetype)
1299 case GLTEXTURETYPE_2D:
1300 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1303 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1305 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1306 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1309 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1311 while (width > 1 || height > 1 || depth > 1)
1313 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1314 prevbuffer = resizebuffer;
1315 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1317 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1318 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1324 case GLTEXTURETYPE_3D:
1325 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1327 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1328 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1329 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1332 if (glt->flags & TEXF_MIPMAP)
1334 while (width > 1 || height > 1 || depth > 1)
1336 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1337 prevbuffer = resizebuffer;
1338 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1340 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1341 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1342 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1348 case GLTEXTURETYPE_CUBEMAP:
1349 // convert and upload each side in turn,
1350 // from a continuous block of input texels
1351 texturebuffer = (unsigned char *)prevbuffer;
1352 for (i = 0;i < 6;i++)
1354 prevbuffer = texturebuffer;
1355 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1356 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1358 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1359 prevbuffer = resizebuffer;
1362 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1364 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1365 prevbuffer = resizebuffer;
1368 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1370 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1371 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1374 if (glt->flags & TEXF_MIPMAP)
1376 while (width > 1 || height > 1 || depth > 1)
1378 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1379 prevbuffer = resizebuffer;
1380 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1382 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1383 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1392 glt->d3daddressw = 0;
1393 if (glt->flags & TEXF_CLAMP)
1395 glt->d3daddressu = D3DTADDRESS_CLAMP;
1396 glt->d3daddressv = D3DTADDRESS_CLAMP;
1397 if (glt->tiledepth > 1)
1398 glt->d3daddressw = D3DTADDRESS_CLAMP;
1402 glt->d3daddressu = D3DTADDRESS_WRAP;
1403 glt->d3daddressv = D3DTADDRESS_WRAP;
1404 if (glt->tiledepth > 1)
1405 glt->d3daddressw = D3DTADDRESS_WRAP;
1407 glt->d3dmipmaplodbias = 0;
1408 glt->d3dmaxmiplevel = 0;
1409 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1410 if (glt->flags & TEXF_FORCELINEAR)
1412 glt->d3dminfilter = D3DTEXF_LINEAR;
1413 glt->d3dmagfilter = D3DTEXF_LINEAR;
1414 glt->d3dmipfilter = D3DTEXF_POINT;
1416 else if (glt->flags & TEXF_FORCENEAREST)
1418 glt->d3dminfilter = D3DTEXF_POINT;
1419 glt->d3dmagfilter = D3DTEXF_POINT;
1420 glt->d3dmipfilter = D3DTEXF_POINT;
1422 else if (glt->flags & TEXF_MIPMAP)
1424 glt->d3dminfilter = d3d_filter_mipmin;
1425 glt->d3dmagfilter = d3d_filter_mipmag;
1426 glt->d3dmipfilter = d3d_filter_mipmix;
1430 glt->d3dminfilter = d3d_filter_flatmin;
1431 glt->d3dmagfilter = d3d_filter_flatmag;
1432 glt->d3dmipfilter = d3d_filter_flatmix;
1436 case RENDERPATH_D3D10:
1437 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1439 case RENDERPATH_D3D11:
1440 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1442 case RENDERPATH_SOFT:
1443 switch(glt->texturetype)
1445 case GLTEXTURETYPE_2D:
1446 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1448 case GLTEXTURETYPE_3D:
1449 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1451 case GLTEXTURETYPE_CUBEMAP:
1452 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1454 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1455 // convert and upload each side in turn,
1456 // from a continuous block of input texels
1457 // copy the results into combinedbuffer
1458 texturebuffer = (unsigned char *)prevbuffer;
1459 for (i = 0;i < 6;i++)
1461 prevbuffer = texturebuffer;
1462 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1463 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1465 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1466 prevbuffer = resizebuffer;
1469 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1471 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1472 prevbuffer = resizebuffer;
1474 memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1476 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1477 Mem_Free(combinedbuffer);
1480 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1483 if (glt->flags & TEXF_FORCELINEAR)
1484 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1485 else if (glt->flags & TEXF_FORCENEAREST)
1486 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1487 else if (glt->flags & TEXF_MIPMAP)
1488 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1490 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1495 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)
1499 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1500 textypeinfo_t *texinfo, *texinfo2;
1501 unsigned char *temppixels = NULL;
1504 if (cls.state == ca_dedicated)
1507 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1511 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1512 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1513 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1514 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1520 static int rgbaswapindices[4] = {2, 1, 0, 3};
1521 size = width * height * depth * sides * 4;
1522 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1523 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1527 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1528 if (!vid.support.ext_texture_srgb)
1530 qboolean convertsRGB = false;
1533 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1534 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1535 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1536 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1537 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;convertsRGB = true;break;
1538 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1539 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1543 if (convertsRGB && data)
1545 size = width * height * depth * sides * 4;
1548 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1549 memcpy(temppixels, data, size);
1551 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1555 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1557 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1560 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1562 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1566 texinfo = R_GetTexTypeInfo(textype, flags);
1567 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1570 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1574 // clear the alpha flag if the texture has no transparent pixels
1577 case TEXTYPE_PALETTE:
1578 case TEXTYPE_SRGB_PALETTE:
1579 if (flags & TEXF_ALPHA)
1581 flags &= ~TEXF_ALPHA;
1584 for (i = 0;i < size;i++)
1586 if (((unsigned char *)&palette[data[i]])[3] < 255)
1588 flags |= TEXF_ALPHA;
1597 case TEXTYPE_SRGB_RGBA:
1598 case TEXTYPE_SRGB_BGRA:
1599 if (flags & TEXF_ALPHA)
1601 flags &= ~TEXF_ALPHA;
1604 for (i = 3;i < size;i += 4)
1608 flags |= TEXF_ALPHA;
1615 case TEXTYPE_SHADOWMAP:
1618 case TEXTYPE_SRGB_DXT1:
1621 case TEXTYPE_SRGB_DXT1A:
1623 case TEXTYPE_SRGB_DXT3:
1625 case TEXTYPE_SRGB_DXT5:
1626 flags |= TEXF_ALPHA;
1629 flags |= TEXF_ALPHA;
1631 case TEXTYPE_COLORBUFFER:
1632 case TEXTYPE_COLORBUFFER16F:
1633 case TEXTYPE_COLORBUFFER32F:
1634 flags |= TEXF_ALPHA;
1637 Sys_Error("R_LoadTexture: unknown texture type");
1640 texinfo2 = R_GetTexTypeInfo(textype, flags);
1641 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1644 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1646 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1648 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1650 glt->chain = pool->gltchain;
1651 pool->gltchain = glt;
1652 glt->inputwidth = width;
1653 glt->inputheight = height;
1654 glt->inputdepth = depth;
1656 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
1657 glt->textype = texinfo;
1658 glt->texturetype = texturetype;
1659 glt->inputdatasize = size;
1660 glt->palette = palette;
1661 glt->glinternalformat = texinfo->glinternalformat;
1662 glt->glformat = texinfo->glformat;
1663 glt->gltype = texinfo->gltype;
1664 glt->bytesperpixel = texinfo->internalbytesperpixel;
1665 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1668 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1669 // init the dynamic texture attributes, too [11/22/2007 Black]
1670 glt->updatecallback = NULL;
1671 glt->updatacallback_data = NULL;
1673 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1675 // upload the texture
1676 // data may be NULL (blank texture for dynamic rendering)
1677 switch(vid.renderpath)
1679 case RENDERPATH_GL11:
1680 case RENDERPATH_GL13:
1681 case RENDERPATH_GL20:
1682 case RENDERPATH_GLES1:
1683 case RENDERPATH_GLES2:
1685 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1687 case RENDERPATH_D3D9:
1690 D3DFORMAT d3dformat;
1695 d3dpool = D3DPOOL_MANAGED;
1696 if (flags & TEXF_RENDERTARGET)
1698 d3dusage |= D3DUSAGE_RENDERTARGET;
1699 d3dpool = D3DPOOL_DEFAULT;
1703 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1704 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1705 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1706 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
1707 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
1708 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
1709 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1710 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1711 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1713 glt->d3dformat = d3dformat;
1714 glt->d3dusage = d3dusage;
1715 glt->d3dpool = d3dpool;
1716 glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1717 if (glt->d3disdepthsurface)
1719 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1720 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1722 else if (glt->tiledepth > 1)
1724 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)))
1725 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1727 else if (glt->sides == 6)
1729 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1730 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1734 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)))
1735 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1740 case RENDERPATH_D3D10:
1741 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1743 case RENDERPATH_D3D11:
1744 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1746 case RENDERPATH_SOFT:
1751 case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1752 case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1753 case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1754 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1755 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
1756 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
1757 case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1758 case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1759 default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1761 if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1762 if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1763 if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1764 if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1765 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1770 R_UploadFullTexture(glt, data);
1771 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1772 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1774 // free any temporary processing buffer we allocated...
1776 Mem_Free(temppixels);
1778 // texture converting and uploading can take a while, so make sure we're sending keepalives
1779 // FIXME: this causes rendering during R_Shadow_DrawLights
1780 // CL_KeepaliveMessage(false);
1782 return (rtexture_t *)glt;
1785 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)
1787 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1790 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)
1792 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1795 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)
1797 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1800 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1802 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1804 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1806 flags |= TEXF_FORCENEAREST;
1807 if (precision <= 16)
1808 flags |= TEXF_LOWPRECISION;
1812 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1814 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1817 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1819 gltexture_t *glt = (gltexture_t *)rt;
1822 int bytesperpixel = 0;
1823 int bytesperblock = 0;
1825 int dds_format_flags;
1833 GLint internalformat;
1834 const char *ddsfourcc;
1836 return -1; // NULL pointer
1837 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1838 return -2; // broken driver - crashes on reading internal format
1839 if (!qglGetTexLevelParameteriv)
1841 GL_ActiveTexture(0);
1842 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1843 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1844 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1845 switch(internalformat)
1847 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1848 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1849 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1850 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1851 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1853 // if premultiplied alpha, say so in the DDS file
1854 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1856 switch(internalformat)
1858 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1859 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1862 if (!bytesperblock && skipuncompressed)
1863 return -3; // skipped
1864 memset(mipinfo, 0, sizeof(mipinfo));
1865 mipinfo[0][0] = glt->tilewidth;
1866 mipinfo[0][1] = glt->tileheight;
1868 if (glt->flags & TEXF_MIPMAP)
1870 for (mip = 1;mip < 16;mip++)
1872 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1873 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1874 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1882 for (mip = 0;mip < mipmaps;mip++)
1884 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1885 mipinfo[mip][3] = ddssize;
1886 ddssize += mipinfo[mip][2];
1888 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1891 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1895 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1896 dds_format_flags = 0x4; // DDPF_FOURCC
1900 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1901 dds_format_flags = 0x40; // DDPF_RGB
1905 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1906 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1909 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1910 memcpy(dds, "DDS ", 4);
1911 StoreLittleLong(dds+4, ddssize);
1912 StoreLittleLong(dds+8, dds_flags);
1913 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1914 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1915 StoreLittleLong(dds+24, 1); // depth
1916 StoreLittleLong(dds+28, mipmaps); // mipmaps
1917 StoreLittleLong(dds+76, 32); // format size
1918 StoreLittleLong(dds+80, dds_format_flags);
1919 StoreLittleLong(dds+108, dds_caps1);
1920 StoreLittleLong(dds+112, dds_caps2);
1923 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1924 memcpy(dds+84, ddsfourcc, 4);
1925 for (mip = 0;mip < mipmaps;mip++)
1927 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1932 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1933 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1934 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1935 for (mip = 0;mip < mipmaps;mip++)
1937 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1940 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1941 ret = FS_WriteFile(filename, dds, ddssize);
1943 return ret ? ddssize : -5;
1946 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
1948 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1951 int bytesperblock, bytesperpixel;
1954 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1955 textypeinfo_t *texinfo;
1956 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1958 GLint oldbindtexnum = 0;
1959 const unsigned char *mippixels, *ddspixels, *mippixels_start;
1961 fs_offset_t ddsfilesize;
1962 unsigned int ddssize;
1963 qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
1965 if (cls.state == ca_dedicated)
1968 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1969 ddssize = ddsfilesize;
1973 if(r_texture_dds_load_logfailure.integer)
1974 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1975 return NULL; // not found
1978 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1981 Con_Printf("^1%s: not a DDS image\n", filename);
1985 //dds_flags = BuffLittleLong(dds+8);
1986 dds_format_flags = BuffLittleLong(dds+80);
1987 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1988 dds_width = BuffLittleLong(dds+16);
1989 dds_height = BuffLittleLong(dds+12);
1990 ddspixels = dds + 128;
1992 if(r_texture_dds_load_alphamode.integer == 0)
1993 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1994 flags &= ~TEXF_ALPHA;
1996 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1997 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1999 // very sloppy BGRA 32bit identification
2000 textype = TEXTYPE_BGRA;
2003 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
2004 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2007 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
2010 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
2013 for (i = 3;i < size;i += 4)
2014 if (ddspixels[i] < 255)
2017 flags &= ~TEXF_ALPHA;
2020 else if (!memcmp(dds+84, "DXT1", 4))
2022 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
2023 // LordHavoc: it is my belief that this does not infringe on the
2024 // patent because it is not decoding pixels...
2025 textype = TEXTYPE_DXT1;
2028 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
2029 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2030 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2033 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
2036 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
2038 if(r_texture_dds_load_alphamode.integer == 1)
2041 for (i = 0;i < size;i += bytesperblock)
2042 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
2044 // NOTE: this assumes sizeof(unsigned int) == 4
2045 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
2046 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
2047 if(data & (data<<1) & 0xAAAAAAAA)//rgh
2051 textype = TEXTYPE_DXT1A;
2053 flags &= ~TEXF_ALPHA;
2057 flags &= ~TEXF_ALPHA;
2061 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2063 if(!memcmp(dds+84, "DXT2", 4))
2065 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2067 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2072 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2074 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2077 textype = TEXTYPE_DXT3;
2080 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2081 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2084 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2087 // we currently always assume alpha
2089 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2091 if(!memcmp(dds+84, "DXT4", 4))
2093 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2095 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2100 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2102 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2105 textype = TEXTYPE_DXT5;
2108 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2109 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2112 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2115 // we currently always assume alpha
2120 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2124 force_swdecode = false;
2127 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
2129 if(r_texture_dds_swdecode.integer > 1)
2130 force_swdecode = true;
2134 if(r_texture_dds_swdecode.integer < 1)
2140 force_swdecode = true;
2144 // return whether this texture is transparent
2146 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2148 // if we SW decode, choose 2 sizes bigger
2151 // this is quarter res, so do not scale down more than we have to
2155 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2158 // this is where we apply gl_picmip
2159 mippixels_start = ddspixels;
2160 mipwidth = dds_width;
2161 mipheight = dds_height;
2162 while(miplevel >= 1 && dds_miplevels >= 1)
2164 if (mipwidth <= 1 && mipheight <= 1)
2166 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2167 mippixels_start += mipsize; // just skip
2175 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2176 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2178 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2180 // fake decode S3TC if needed
2183 int mipsize_new = mipsize_total / bytesperblock * 4;
2184 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2185 unsigned char *p = mipnewpixels;
2186 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2188 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2189 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2190 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2191 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2192 if(textype == TEXTYPE_DXT5)
2193 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2194 else if(textype == TEXTYPE_DXT3)
2196 (mippixels_start[i-8] & 0x0F)
2197 + (mippixels_start[i-8] >> 4)
2198 + (mippixels_start[i-7] & 0x0F)
2199 + (mippixels_start[i-7] >> 4)
2200 + (mippixels_start[i-6] & 0x0F)
2201 + (mippixels_start[i-6] >> 4)
2202 + (mippixels_start[i-5] & 0x0F)
2203 + (mippixels_start[i-5] >> 4)
2204 ) * (0.125f / 15.0f * 255.0f);
2209 textype = TEXTYPE_BGRA;
2213 // as each block becomes a pixel, we must use pixel count for this
2214 mipwidth = (mipwidth + 3) / 4;
2215 mipheight = (mipheight + 3) / 4;
2216 mipsize = bytesperpixel * mipwidth * mipheight;
2217 mippixels_start = mipnewpixels;
2218 mipsize_total = mipsize_new;
2221 // start mip counting
2222 mippixels = mippixels_start;
2224 // calculate average color if requested
2228 Vector4Clear(avgcolor);
2231 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2233 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2234 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2235 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2236 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2237 if(textype == TEXTYPE_DXT5)
2238 avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2239 else if(textype == TEXTYPE_DXT3)
2241 (mippixels_start[i-8] & 0x0F)
2242 + (mippixels_start[i-8] >> 4)
2243 + (mippixels_start[i-7] & 0x0F)
2244 + (mippixels_start[i-7] >> 4)
2245 + (mippixels_start[i-6] & 0x0F)
2246 + (mippixels_start[i-6] >> 4)
2247 + (mippixels_start[i-5] & 0x0F)
2248 + (mippixels_start[i-5] >> 4)
2249 ) * (0.125f / 15.0f * 255.0f);
2253 f = (float)bytesperblock / size;
2254 avgcolor[0] *= (0.5f / 31.0f) * f;
2255 avgcolor[1] *= (0.5f / 63.0f) * f;
2256 avgcolor[2] *= (0.5f / 31.0f) * f;
2261 for (i = 0;i < mipsize;i += 4)
2263 avgcolor[0] += mippixels[i+2];
2264 avgcolor[1] += mippixels[i+1];
2265 avgcolor[2] += mippixels[i];
2266 avgcolor[3] += mippixels[i+3];
2268 f = (1.0f / 255.0f) * bytesperpixel / size;
2276 // when not requesting mipmaps, do not load them
2277 if(!(flags & TEXF_MIPMAP))
2280 if (dds_miplevels >= 1)
2281 flags |= TEXF_MIPMAP;
2283 flags &= ~TEXF_MIPMAP;
2285 texinfo = R_GetTexTypeInfo(textype, flags);
2287 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2288 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2290 glt->chain = pool->gltchain;
2291 pool->gltchain = glt;
2292 glt->inputwidth = mipwidth;
2293 glt->inputheight = mipheight;
2294 glt->inputdepth = 1;
2296 glt->textype = texinfo;
2297 glt->texturetype = GLTEXTURETYPE_2D;
2298 glt->inputdatasize = ddssize;
2299 glt->glinternalformat = texinfo->glinternalformat;
2300 glt->glformat = texinfo->glformat;
2301 glt->gltype = texinfo->gltype;
2302 glt->bytesperpixel = texinfo->internalbytesperpixel;
2304 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2305 glt->tilewidth = mipwidth;
2306 glt->tileheight = mipheight;
2308 glt->miplevels = dds_miplevels;
2310 // texture uploading can take a while, so make sure we're sending keepalives
2311 CL_KeepaliveMessage(false);
2313 // create the texture object
2314 switch(vid.renderpath)
2316 case RENDERPATH_GL11:
2317 case RENDERPATH_GL13:
2318 case RENDERPATH_GL20:
2319 case RENDERPATH_GLES1:
2320 case RENDERPATH_GLES2:
2322 GL_ActiveTexture(0);
2323 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2324 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2325 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2327 case RENDERPATH_D3D9:
2330 D3DFORMAT d3dformat;
2335 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2336 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2337 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2338 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2339 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2342 d3dpool = D3DPOOL_MANAGED;
2343 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2347 case RENDERPATH_D3D10:
2348 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2350 case RENDERPATH_D3D11:
2351 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2353 case RENDERPATH_SOFT:
2354 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);
2358 // upload the texture
2359 // we need to restore the texture binding after finishing the upload
2360 mipcomplete = false;
2362 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2364 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2365 if (mippixels + mipsize > mippixels_start + mipsize_total)
2367 switch(vid.renderpath)
2369 case RENDERPATH_GL11:
2370 case RENDERPATH_GL13:
2371 case RENDERPATH_GL20:
2372 case RENDERPATH_GLES1:
2373 case RENDERPATH_GLES2:
2376 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2380 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2383 case RENDERPATH_D3D9:
2386 D3DLOCKED_RECT d3dlockedrect;
2387 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2389 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2390 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2396 case RENDERPATH_D3D10:
2397 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2399 case RENDERPATH_D3D11:
2400 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2402 case RENDERPATH_SOFT:
2404 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2406 DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
2407 // DPSOFTRAST calculates its own mipmaps
2408 mip = dds_miplevels;
2411 mippixels += mipsize;
2412 if (mipwidth <= 1 && mipheight <= 1)
2423 // after upload we have to set some parameters...
2424 switch(vid.renderpath)
2426 case RENDERPATH_GL11:
2427 case RENDERPATH_GL13:
2428 case RENDERPATH_GL20:
2429 case RENDERPATH_GLES1:
2430 case RENDERPATH_GLES2:
2431 if (dds_miplevels >= 1 && !mipcomplete)
2433 // need to set GL_TEXTURE_MAX_LEVEL
2434 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2436 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2437 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2439 case RENDERPATH_D3D9:
2441 glt->d3daddressw = 0;
2442 if (glt->flags & TEXF_CLAMP)
2444 glt->d3daddressu = D3DTADDRESS_CLAMP;
2445 glt->d3daddressv = D3DTADDRESS_CLAMP;
2446 if (glt->tiledepth > 1)
2447 glt->d3daddressw = D3DTADDRESS_CLAMP;
2451 glt->d3daddressu = D3DTADDRESS_WRAP;
2452 glt->d3daddressv = D3DTADDRESS_WRAP;
2453 if (glt->tiledepth > 1)
2454 glt->d3daddressw = D3DTADDRESS_WRAP;
2456 glt->d3dmipmaplodbias = 0;
2457 glt->d3dmaxmiplevel = 0;
2458 glt->d3dmaxmiplevelfilter = 0;
2459 if (glt->flags & TEXF_MIPMAP)
2461 glt->d3dminfilter = d3d_filter_mipmin;
2462 glt->d3dmagfilter = d3d_filter_mipmag;
2463 glt->d3dmipfilter = d3d_filter_mipmix;
2467 glt->d3dminfilter = d3d_filter_flatmin;
2468 glt->d3dmagfilter = d3d_filter_flatmag;
2469 glt->d3dmipfilter = d3d_filter_flatmix;
2473 case RENDERPATH_D3D10:
2474 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2476 case RENDERPATH_D3D11:
2477 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2479 case RENDERPATH_SOFT:
2480 if (glt->flags & TEXF_FORCELINEAR)
2481 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2482 else if (glt->flags & TEXF_FORCENEAREST)
2483 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2484 else if (glt->flags & TEXF_MIPMAP)
2485 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2487 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2493 Mem_Free((unsigned char *) mippixels_start);
2494 return (rtexture_t *)glt;
2497 int R_TextureWidth(rtexture_t *rt)
2499 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2502 int R_TextureHeight(rtexture_t *rt)
2504 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2507 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2509 gltexture_t *glt = (gltexture_t *)rt;
2511 Host_Error("R_UpdateTexture: no data supplied");
2513 Host_Error("R_UpdateTexture: no texture supplied");
2514 if (!glt->texnum && !glt->d3dtexture)
2516 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2519 // update part of the texture
2520 if (glt->bufferpixels)
2523 int bpp = glt->bytesperpixel;
2524 int inputskip = width*bpp;
2525 int outputskip = glt->tilewidth*bpp;
2526 const unsigned char *input = data;
2527 unsigned char *output = glt->bufferpixels;
2528 if (glt->inputdepth != 1 || glt->sides != 1)
2529 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2539 input -= y*inputskip;
2542 if (width > glt->tilewidth - x)
2543 width = glt->tilewidth - x;
2544 if (height > glt->tileheight - y)
2545 height = glt->tileheight - y;
2546 if (width < 1 || height < 1)
2549 glt->buffermodified = true;
2550 output += y*outputskip + x*bpp;
2551 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2552 memcpy(output, input, width*bpp);
2554 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2555 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2557 R_UploadFullTexture(glt, data);
2560 int R_RealGetTexture(rtexture_t *rt)
2565 glt = (gltexture_t *)rt;
2566 if (glt->flags & GLTEXF_DYNAMIC)
2567 R_UpdateDynamicTexture(glt);
2568 if (glt->buffermodified && glt->bufferpixels)
2570 glt->buffermodified = false;
2571 R_UploadFullTexture(glt, glt->bufferpixels);
2580 void R_ClearTexture (rtexture_t *rt)
2582 gltexture_t *glt = (gltexture_t *)rt;
2584 R_UploadFullTexture(glt, NULL);
2587 int R_PicmipForFlags(int flags)
2590 if(flags & TEXF_PICMIP)
2592 miplevel += gl_picmip.integer;
2593 if (flags & TEXF_ISWORLD)
2595 if (r_picmipworld.integer)
2596 miplevel += gl_picmip_world.integer;
2600 else if (flags & TEXF_ISSPRITE)
2602 if (r_picmipsprites.integer)
2603 miplevel += gl_picmip_sprites.integer;
2608 miplevel += gl_picmip_other.integer;
2610 return max(0, miplevel);