5 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
10 #include "intoverflow.h"
12 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)"};
13 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)"};
14 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%"};
15 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)"};
16 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)"};
17 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)"};
18 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)"};
19 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)"};
20 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)"};
21 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"};
22 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"};
23 cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
24 cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
25 cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
26 cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
27 cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
28 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
29 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)"};
30 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
31 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
32 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)"};
33 cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "1", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"};
34 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 ambigous, 2: texture format only"};
36 qboolean gl_filter_force = false;
37 int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
38 int gl_filter_mag = GL_LINEAR;
41 int d3d_filter_flatmin = D3DTEXF_LINEAR;
42 int d3d_filter_flatmag = D3DTEXF_LINEAR;
43 int d3d_filter_flatmix = D3DTEXF_POINT;
44 int d3d_filter_mipmin = D3DTEXF_LINEAR;
45 int d3d_filter_mipmag = D3DTEXF_LINEAR;
46 int d3d_filter_mipmix = D3DTEXF_LINEAR;
47 int d3d_filter_nomip = false;
51 static mempool_t *texturemempool;
52 static memexpandablearray_t texturearray;
54 // note: this must not conflict with TEXF_ flags in r_textures.h
55 // bitmask for mismatch checking
56 #define GLTEXF_IMPORTANTBITS (0)
57 // dynamic texture (treat texnum == 0 differently)
58 #define GLTEXF_DYNAMIC 0x00080000
60 typedef struct textypeinfo_s
63 int inputbytesperpixel;
64 int internalbytesperpixel;
65 float glinternalbytesperpixel;
73 static textypeinfo_t textype_palette = {TEXTYPE_PALETTE , 1, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE };
74 static textypeinfo_t textype_palette_alpha = {TEXTYPE_PALETTE , 1, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
75 static textypeinfo_t textype_rgba = {TEXTYPE_RGBA , 4, 4, 4.0f, 3 , GL_RGBA , GL_UNSIGNED_BYTE };
76 static textypeinfo_t textype_rgba_alpha = {TEXTYPE_RGBA , 4, 4, 4.0f, 4 , GL_RGBA , GL_UNSIGNED_BYTE };
77 static textypeinfo_t textype_rgba_compress = {TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
78 static textypeinfo_t textype_rgba_alpha_compress = {TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA , GL_UNSIGNED_BYTE };
79 static textypeinfo_t textype_bgra = {TEXTYPE_BGRA , 4, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE };
80 static textypeinfo_t textype_bgra_alpha = {TEXTYPE_BGRA , 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
81 static textypeinfo_t textype_bgra_compress = {TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
82 static textypeinfo_t textype_bgra_alpha_compress = {TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_BGRA , GL_UNSIGNED_BYTE };
83 static textypeinfo_t textype_shadowmap16 = {TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
84 static textypeinfo_t textype_shadowmap24 = {TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
85 static textypeinfo_t textype_alpha = {TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
86 static textypeinfo_t textype_dxt1 = {TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
87 static textypeinfo_t textype_dxt1a = {TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0 , 0 };
88 static textypeinfo_t textype_dxt3 = {TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0 , 0 };
89 static textypeinfo_t textype_dxt5 = {TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0 , 0 };
90 static textypeinfo_t textype_colorbuffer = {TEXTYPE_COLORBUFFER, 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
93 typedef enum gltexturetype_e
97 GLTEXTURETYPE_CUBEMAP,
98 GLTEXTURETYPE_RECTANGLE,
103 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_RECTANGLE_ARB};
104 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2, 2};
105 static int cubemapside[6] =
107 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
108 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
109 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
110 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
111 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
112 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
115 typedef struct gltexture_s
117 // this portion of the struct is exposed to the R_GetTexture macro for
118 // speed reasons, must be identical in rtexture_t!
119 int texnum; // GL texture slot number
120 qboolean dirty; // indicates that R_RealGetTexture should be called
121 int gltexturetypeenum; // used by R_Mesh_TexBind
122 // d3d stuff the backend needs
134 int d3dmaxmiplevelfilter;
135 int d3dmipmaplodbias;
139 // dynamic texture stuff [11/22/2007 Black]
140 updatecallback_t updatecallback;
141 void *updatacallback_data;
142 // --- [11/22/2007 Black]
144 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
145 unsigned char *bufferpixels;
146 qboolean buffermodified;
148 // pointer to texturepool (check this to see if the texture is allocated)
149 struct gltexturepool_s *pool;
150 // pointer to next texture in texturepool chain
151 struct gltexture_s *chain;
152 // name of the texture (this might be removed someday), no duplicates
153 char identifier[MAX_QPATH + 32];
154 // original data size in *inputtexels
155 int inputwidth, inputheight, inputdepth;
156 // copy of the original texture(s) supplied to the upload function, for
157 // delayed uploads (non-precached)
158 unsigned char *inputtexels;
159 // original data size in *inputtexels
161 // flags supplied to the LoadTexture function
162 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
166 // pointer to one of the textype_ structs
167 textypeinfo_t *textype;
168 // one of the GLTEXTURETYPE_ values
170 // palette if the texture is TEXTYPE_PALETTE
171 const unsigned int *palette;
172 // actual stored texture size after gl_picmip and gl_max_size are applied
173 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
174 int tilewidth, tileheight, tiledepth;
175 // 1 or 6 depending on texturetype
177 // how many mipmap levels in this texture
181 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
184 int glinternalformat;
185 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
190 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
192 typedef struct gltexturepool_s
194 unsigned int sentinel;
195 struct gltexture_s *gltchain;
196 struct gltexturepool_s *next;
200 static gltexturepool_t *gltexturepoolchain = NULL;
202 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
203 static int resizebuffersize = 0;
204 static const unsigned char *texturebuffer;
206 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
211 return &textype_dxt1;
213 return &textype_dxt1a;
215 return &textype_dxt3;
217 return &textype_dxt5;
218 case TEXTYPE_PALETTE:
219 return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
221 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
222 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress;
223 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba;
225 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
226 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress;
227 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra;
229 return &textype_alpha;
230 case TEXTYPE_SHADOWMAP:
231 return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
232 case TEXTYPE_COLORBUFFER:
233 return &textype_colorbuffer;
235 Host_Error("R_GetTexTypeInfo: unknown texture format");
241 // dynamic texture code [11/22/2007 Black]
242 void R_MarkDirtyTexture(rtexture_t *rt) {
243 gltexture_t *glt = (gltexture_t*) rt;
248 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
249 if (glt->flags & GLTEXF_DYNAMIC)
251 // mark it as dirty, so R_RealGetTexture gets called
256 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
257 gltexture_t *glt = (gltexture_t*) rt;
262 glt->flags |= GLTEXF_DYNAMIC;
263 glt->updatecallback = updatecallback;
264 glt->updatacallback_data = data;
267 static void R_UpdateDynamicTexture(gltexture_t *glt) {
269 if( glt->updatecallback ) {
270 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
274 void R_PurgeTexture(rtexture_t *rt)
276 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
281 void R_FreeTexture(rtexture_t *rt)
283 gltexture_t *glt, **gltpointer;
285 glt = (gltexture_t *)rt;
287 Host_Error("R_FreeTexture: texture == NULL");
289 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
290 if (*gltpointer == glt)
291 *gltpointer = glt->chain;
293 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
298 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
301 if (glt->inputtexels)
302 Mem_Free(glt->inputtexels);
303 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
306 rtexturepool_t *R_AllocTexturePool(void)
308 gltexturepool_t *pool;
309 if (texturemempool == NULL)
311 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
314 pool->next = gltexturepoolchain;
315 gltexturepoolchain = pool;
316 pool->sentinel = TEXTUREPOOL_SENTINEL;
317 return (rtexturepool_t *)pool;
320 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
322 gltexturepool_t *pool, **poolpointer;
323 if (rtexturepool == NULL)
325 if (*rtexturepool == NULL)
327 pool = (gltexturepool_t *)(*rtexturepool);
328 *rtexturepool = NULL;
329 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
330 Host_Error("R_FreeTexturePool: pool already freed");
331 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
332 if (*poolpointer == pool)
333 *poolpointer = pool->next;
335 Host_Error("R_FreeTexturePool: pool not linked");
336 while (pool->gltchain)
337 R_FreeTexture((rtexture_t *)pool->gltchain);
342 typedef struct glmode_s
345 int minification, magnification;
349 static glmode_t modes[6] =
351 {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
352 {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
353 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
354 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
355 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
356 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
360 typedef struct d3dmode_s
367 static d3dmode_t d3dmodes[6] =
369 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
370 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
371 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
372 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
373 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
374 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
378 static void GL_TextureMode_f (void)
383 gltexturepool_t *pool;
387 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
388 for (i = 0;i < 6;i++)
390 if (gl_filter_min == modes[i].minification)
392 Con_Printf("%s\n", modes[i].name);
396 Con_Print("current filter is unknown???\n");
400 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
401 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
405 Con_Print("bad filter name\n");
409 gl_filter_min = modes[i].minification;
410 gl_filter_mag = modes[i].magnification;
411 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
413 switch(vid.renderpath)
415 case RENDERPATH_GL11:
416 case RENDERPATH_GL13:
417 case RENDERPATH_GL20:
418 case RENDERPATH_CGGL:
419 // change all the existing mipmap texture objects
420 // FIXME: force renderer(/client/something?) restart instead?
423 for (pool = gltexturepoolchain;pool;pool = pool->next)
425 for (glt = pool->gltchain;glt;glt = glt->chain)
427 // only update already uploaded images
428 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
430 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
431 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
432 if (glt->flags & TEXF_MIPMAP)
434 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
438 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
440 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
441 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
446 case RENDERPATH_D3D9:
448 d3d_filter_flatmin = d3dmodes[i].m1;
449 d3d_filter_flatmag = d3dmodes[i].m1;
450 d3d_filter_flatmix = D3DTEXF_POINT;
451 d3d_filter_mipmin = d3dmodes[i].m1;
452 d3d_filter_mipmag = d3dmodes[i].m1;
453 d3d_filter_mipmix = d3dmodes[i].m2;
454 d3d_filter_nomip = i < 2;
455 if (gl_texture_anisotropy.integer > 1 && i == 5)
456 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
457 for (pool = gltexturepoolchain;pool;pool = pool->next)
459 for (glt = pool->gltchain;glt;glt = glt->chain)
461 // only update already uploaded images
462 if (glt->d3dtexture && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
464 if (glt->flags & TEXF_MIPMAP)
466 glt->d3dminfilter = d3d_filter_mipmin;
467 glt->d3dmagfilter = d3d_filter_mipmag;
468 glt->d3dmipfilter = d3d_filter_mipmix;
469 glt->d3dmaxmiplevelfilter = 0;
473 glt->d3dminfilter = d3d_filter_flatmin;
474 glt->d3dmagfilter = d3d_filter_flatmag;
475 glt->d3dmipfilter = d3d_filter_flatmix;
476 glt->d3dmaxmiplevelfilter = 0;
483 case RENDERPATH_D3D10:
484 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
486 case RENDERPATH_D3D11:
487 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
492 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)
494 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
499 case GLTEXTURETYPE_2D:
500 maxsize = vid.maxtexturesize_2d;
501 if (flags & TEXF_PICMIP)
503 maxsize = bound(1, gl_max_size.integer, maxsize);
507 case GLTEXTURETYPE_3D:
508 maxsize = vid.maxtexturesize_3d;
510 case GLTEXTURETYPE_CUBEMAP:
511 maxsize = vid.maxtexturesize_cubemap;
517 if (vid.support.arb_texture_non_power_of_two)
518 width2 = min(inwidth >> picmip, maxsize);
521 for (width2 = 1;width2 < inwidth;width2 <<= 1);
522 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
524 *outwidth = max(1, width2);
528 if (vid.support.arb_texture_non_power_of_two)
529 height2 = min(inheight >> picmip, maxsize);
532 for (height2 = 1;height2 < inheight;height2 <<= 1);
533 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
535 *outheight = max(1, height2);
539 if (vid.support.arb_texture_non_power_of_two)
540 depth2 = min(indepth >> picmip, maxsize);
543 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
544 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
546 *outdepth = max(1, depth2);
550 if (flags & TEXF_MIPMAP)
552 int extent = max(width2, max(height2, depth2));
557 *outmiplevels = miplevels;
561 static int R_CalcTexelDataSize (gltexture_t *glt)
563 int width2, height2, depth2, size;
565 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
567 size = width2 * height2 * depth2;
569 if (glt->flags & TEXF_MIPMAP)
571 while (width2 > 1 || height2 > 1 || depth2 > 1)
579 size += width2 * height2 * depth2;
583 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
586 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
590 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
591 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
593 gltexturepool_t *pool;
595 Con_Print("glsize input loaded mip alpha name\n");
596 for (pool = gltexturepoolchain;pool;pool = pool->next)
604 for (glt = pool->gltchain;glt;glt = glt->chain)
606 glsize = R_CalcTexelDataSize(glt);
607 isloaded = glt->texnum != 0;
609 pooltotalt += glsize;
610 pooltotalp += glt->inputdatasize;
614 poolloadedt += glsize;
615 poolloadedp += glt->inputdatasize;
618 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);
621 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);
622 sumtotal += pooltotal;
623 sumtotalt += pooltotalt;
624 sumtotalp += pooltotalp;
625 sumloaded += poolloaded;
626 sumloadedt += poolloadedt;
627 sumloadedp += poolloadedp;
630 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);
633 static void R_TextureStats_f(void)
635 R_TextureStats_Print(true, true, true);
638 static void r_textures_start(void)
640 switch(vid.renderpath)
642 case RENDERPATH_GL11:
643 case RENDERPATH_GL13:
644 case RENDERPATH_GL20:
645 case RENDERPATH_CGGL:
646 // LordHavoc: allow any alignment
648 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
649 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
651 case RENDERPATH_D3D9:
653 case RENDERPATH_D3D10:
654 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
656 case RENDERPATH_D3D11:
657 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
661 texturemempool = Mem_AllocPool("texture management", 0, NULL);
662 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
664 // Disable JPEG screenshots if the DLL isn't loaded
665 if (! JPEG_OpenLibrary ())
666 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
667 if (! PNG_OpenLibrary ())
668 Cvar_SetValueQuick (&scr_screenshot_png, 0);
671 static void r_textures_shutdown(void)
673 rtexturepool_t *temp;
675 JPEG_CloseLibrary ();
677 while(gltexturepoolchain)
679 temp = (rtexturepool_t *) gltexturepoolchain;
680 R_FreeTexturePool(&temp);
683 resizebuffersize = 0;
685 colorconvertbuffer = NULL;
686 texturebuffer = NULL;
687 Mem_ExpandableArray_FreeArray(&texturearray);
688 Mem_FreePool(&texturemempool);
691 static void r_textures_newmap(void)
695 static void r_textures_devicelost(void)
699 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
700 for (i = 0;i < endindex;i++)
702 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
703 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
705 switch(vid.renderpath)
707 case RENDERPATH_GL11:
708 case RENDERPATH_GL13:
709 case RENDERPATH_GL20:
710 case RENDERPATH_CGGL:
712 case RENDERPATH_D3D9:
714 if (glt->tiledepth > 1)
715 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
716 else if (glt->sides == 6)
717 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
719 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
720 glt->d3dtexture = NULL;
723 case RENDERPATH_D3D10:
724 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
726 case RENDERPATH_D3D11:
727 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
733 static void r_textures_devicerestored(void)
737 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
738 for (i = 0;i < endindex;i++)
740 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
741 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
743 switch(vid.renderpath)
745 case RENDERPATH_GL11:
746 case RENDERPATH_GL13:
747 case RENDERPATH_GL20:
748 case RENDERPATH_CGGL:
750 case RENDERPATH_D3D9:
754 if (glt->tiledepth > 1)
756 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)))
757 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
759 else if (glt->sides == 6)
761 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
762 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
766 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)))
767 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
772 case RENDERPATH_D3D10:
773 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
775 case RENDERPATH_D3D11:
776 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
783 void R_Textures_Init (void)
785 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");
786 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
787 Cvar_RegisterVariable (&gl_max_size);
788 Cvar_RegisterVariable (&gl_picmip);
789 Cvar_RegisterVariable (&gl_picmip_world);
790 Cvar_RegisterVariable (&r_picmipworld);
791 Cvar_RegisterVariable (&gl_picmip_sprites);
792 Cvar_RegisterVariable (&r_picmipsprites);
793 Cvar_RegisterVariable (&gl_picmip_other);
794 Cvar_RegisterVariable (&gl_max_lightmapsize);
795 Cvar_RegisterVariable (&r_lerpimages);
796 Cvar_RegisterVariable (&gl_texture_anisotropy);
797 Cvar_RegisterVariable (&gl_texturecompression);
798 Cvar_RegisterVariable (&gl_texturecompression_color);
799 Cvar_RegisterVariable (&gl_texturecompression_normal);
800 Cvar_RegisterVariable (&gl_texturecompression_gloss);
801 Cvar_RegisterVariable (&gl_texturecompression_glow);
802 Cvar_RegisterVariable (&gl_texturecompression_2d);
803 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
804 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
805 Cvar_RegisterVariable (&gl_texturecompression_sky);
806 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
807 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
808 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
809 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
811 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
814 void R_Textures_Frame (void)
816 static int old_aniso = 0;
818 // could do procedural texture animation here, if we keep track of which
819 // textures were accessed this frame...
821 // free the resize buffers
822 resizebuffersize = 0;
825 Mem_Free(resizebuffer);
828 if (colorconvertbuffer)
830 Mem_Free(colorconvertbuffer);
831 colorconvertbuffer = NULL;
834 if (old_aniso != gl_texture_anisotropy.integer)
837 gltexturepool_t *pool;
840 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
842 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
844 switch(vid.renderpath)
846 case RENDERPATH_GL11:
847 case RENDERPATH_GL13:
848 case RENDERPATH_GL20:
849 case RENDERPATH_CGGL:
852 for (pool = gltexturepoolchain;pool;pool = pool->next)
854 for (glt = pool->gltchain;glt;glt = glt->chain)
856 // only update already uploaded images
857 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
859 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
861 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
862 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
864 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
869 case RENDERPATH_D3D9:
870 case RENDERPATH_D3D10:
871 case RENDERPATH_D3D11:
877 void R_MakeResizeBufferBigger(int size)
879 if (resizebuffersize < size)
881 resizebuffersize = size;
883 Mem_Free(resizebuffer);
884 if (colorconvertbuffer)
885 Mem_Free(colorconvertbuffer);
886 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
887 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
888 if (!resizebuffer || !colorconvertbuffer)
889 Host_Error("R_Upload: out of memory");
893 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
895 int textureenum = gltexturetypeenums[texturetype];
896 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
900 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
902 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
903 if (gl_texture_anisotropy.integer != aniso)
904 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
905 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
907 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
908 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
909 if (gltexturetypedimensions[texturetype] >= 3)
911 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
915 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
917 if (flags & TEXF_MIPMAP)
919 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
923 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
925 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
927 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
929 if (flags & TEXF_MIPMAP)
931 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
933 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
937 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
942 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
944 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
948 if (flags & TEXF_MIPMAP)
950 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
954 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
956 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
959 if (textype == TEXTYPE_SHADOWMAP)
961 if (vid.support.arb_shadow)
963 if (flags & TEXF_COMPARE)
965 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
969 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
971 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
973 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
979 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
982 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
984 if (glt->texturetype != GLTEXTURETYPE_2D)
985 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
987 if (glt->textype->textype == TEXTYPE_PALETTE)
988 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
990 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
991 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
993 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
994 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
996 // update a portion of the image
998 switch(vid.renderpath)
1000 case RENDERPATH_GL11:
1001 case RENDERPATH_GL13:
1002 case RENDERPATH_GL20:
1003 case RENDERPATH_CGGL:
1007 // we need to restore the texture binding after finishing the upload
1008 GL_ActiveTexture(0);
1009 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1010 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1011 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1012 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1015 case RENDERPATH_D3D9:
1019 D3DLOCKED_RECT d3dlockedrect;
1021 memset(&d3drect, 0, sizeof(d3drect));
1022 d3drect.left = fragx;
1023 d3drect.top = fragy;
1024 d3drect.right = fragx+fragwidth;
1025 d3drect.bottom = fragy+fragheight;
1026 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1028 for (y = 0;y < fragheight;y++)
1029 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1030 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1035 case RENDERPATH_D3D10:
1036 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1038 case RENDERPATH_D3D11:
1039 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1044 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1046 int i, mip = 0, width, height, depth;
1047 GLint oldbindtexnum = 0;
1048 const unsigned char *prevbuffer;
1051 // error out if a stretch is needed on special texture types
1052 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1053 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1055 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1056 // of the target size and then use the mipmap reduction function to get
1057 // high quality supersampled results
1058 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1059 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1060 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1061 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1063 if (prevbuffer == NULL)
1065 width = glt->tilewidth;
1066 height = glt->tileheight;
1067 depth = glt->tiledepth;
1068 memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1069 prevbuffer = resizebuffer;
1071 else if (glt->textype->textype == TEXTYPE_PALETTE)
1073 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1074 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1075 prevbuffer = colorconvertbuffer;
1078 // scale up to a power of 2 size (if appropriate)
1079 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1081 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1082 prevbuffer = resizebuffer;
1084 // apply mipmap reduction algorithm to get down to picmip/max_size
1085 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1087 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1088 prevbuffer = resizebuffer;
1091 // do the appropriate upload type...
1092 switch(vid.renderpath)
1094 case RENDERPATH_GL11:
1095 case RENDERPATH_GL13:
1096 case RENDERPATH_GL20:
1097 case RENDERPATH_CGGL:
1100 // we need to restore the texture binding after finishing the upload
1101 GL_ActiveTexture(0);
1102 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1103 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1105 if (qglGetCompressedTexImageARB)
1107 if (gl_texturecompression.integer >= 2)
1108 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1110 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1113 switch(glt->texturetype)
1115 case GLTEXTURETYPE_2D:
1116 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1117 if (glt->flags & TEXF_MIPMAP)
1119 while (width > 1 || height > 1 || depth > 1)
1121 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1122 prevbuffer = resizebuffer;
1123 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1127 case GLTEXTURETYPE_3D:
1128 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1129 if (glt->flags & TEXF_MIPMAP)
1131 while (width > 1 || height > 1 || depth > 1)
1133 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1134 prevbuffer = resizebuffer;
1135 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1139 case GLTEXTURETYPE_CUBEMAP:
1140 // convert and upload each side in turn,
1141 // from a continuous block of input texels
1142 texturebuffer = (unsigned char *)prevbuffer;
1143 for (i = 0;i < 6;i++)
1145 prevbuffer = texturebuffer;
1146 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1147 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1149 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1150 prevbuffer = resizebuffer;
1153 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1155 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1156 prevbuffer = resizebuffer;
1159 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1160 if (glt->flags & TEXF_MIPMAP)
1162 while (width > 1 || height > 1 || depth > 1)
1164 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1165 prevbuffer = resizebuffer;
1166 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1171 case GLTEXTURETYPE_RECTANGLE:
1172 qglTexImage2D(GL_TEXTURE_RECTANGLE_ARB, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, NULL);CHECKGLERROR
1175 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1176 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1178 case RENDERPATH_D3D9:
1180 if (!(glt->flags & TEXF_RENDERTARGET))
1182 D3DLOCKED_RECT d3dlockedrect;
1183 D3DLOCKED_BOX d3dlockedbox;
1184 switch(glt->texturetype)
1186 case GLTEXTURETYPE_2D:
1187 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1190 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1192 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1193 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1196 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1198 while (width > 1 || height > 1 || depth > 1)
1200 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1201 prevbuffer = resizebuffer;
1202 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1204 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1205 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1211 case GLTEXTURETYPE_3D:
1212 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1214 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1215 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1216 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1219 if (glt->flags & TEXF_MIPMAP)
1221 while (width > 1 || height > 1 || depth > 1)
1223 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1224 prevbuffer = resizebuffer;
1225 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1227 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1228 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1229 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1235 case GLTEXTURETYPE_CUBEMAP:
1236 // convert and upload each side in turn,
1237 // from a continuous block of input texels
1238 texturebuffer = (unsigned char *)prevbuffer;
1239 for (i = 0;i < 6;i++)
1241 prevbuffer = texturebuffer;
1242 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1243 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1245 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1246 prevbuffer = resizebuffer;
1249 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1251 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1252 prevbuffer = resizebuffer;
1255 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1257 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1258 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1261 if (glt->flags & TEXF_MIPMAP)
1263 while (width > 1 || height > 1 || depth > 1)
1265 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1266 prevbuffer = resizebuffer;
1267 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1269 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1270 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1277 case GLTEXTURETYPE_RECTANGLE:
1278 Sys_Error("Direct3D does not have RECTANGLE textures\n");
1282 glt->d3daddressw = 0;
1283 if (glt->flags & TEXF_CLAMP)
1285 glt->d3daddressu = D3DTADDRESS_CLAMP;
1286 glt->d3daddressv = D3DTADDRESS_CLAMP;
1287 if (glt->tiledepth > 1)
1288 glt->d3daddressw = D3DTADDRESS_CLAMP;
1292 glt->d3daddressu = D3DTADDRESS_WRAP;
1293 glt->d3daddressv = D3DTADDRESS_WRAP;
1294 if (glt->tiledepth > 1)
1295 glt->d3daddressw = D3DTADDRESS_WRAP;
1297 glt->d3dmipmaplodbias = 0;
1298 glt->d3dmaxmiplevel = 0;
1299 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1300 if (glt->flags & TEXF_FORCELINEAR)
1302 glt->d3dminfilter = D3DTEXF_LINEAR;
1303 glt->d3dmagfilter = D3DTEXF_LINEAR;
1304 glt->d3dmipfilter = D3DTEXF_POINT;
1306 else if (glt->flags & TEXF_FORCENEAREST)
1308 glt->d3dminfilter = D3DTEXF_POINT;
1309 glt->d3dmagfilter = D3DTEXF_POINT;
1310 glt->d3dmipfilter = D3DTEXF_POINT;
1312 else if (glt->flags & TEXF_MIPMAP)
1314 glt->d3dminfilter = d3d_filter_mipmin;
1315 glt->d3dmagfilter = d3d_filter_mipmag;
1316 glt->d3dmipfilter = d3d_filter_mipmix;
1320 glt->d3dminfilter = d3d_filter_flatmin;
1321 glt->d3dmagfilter = d3d_filter_flatmag;
1322 glt->d3dmipfilter = d3d_filter_flatmix;
1326 case RENDERPATH_D3D10:
1327 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1329 case RENDERPATH_D3D11:
1330 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1335 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)
1339 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1340 textypeinfo_t *texinfo, *texinfo2;
1341 unsigned char *temppixels = NULL;
1343 if (cls.state == ca_dedicated)
1346 if (texturetype == GLTEXTURETYPE_RECTANGLE && !vid.support.arb_texture_rectangle)
1348 Con_Printf ("R_LoadTexture: rectangle texture not supported by driver\n");
1351 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1353 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1356 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1358 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1362 texinfo = R_GetTexTypeInfo(textype, flags);
1363 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1366 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1370 if (textype == TEXTYPE_RGBA)
1373 static int rgbaswapindices[4] = {2, 1, 0, 3};
1374 textype = TEXTYPE_BGRA;
1375 texinfo = R_GetTexTypeInfo(textype, flags);
1376 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1377 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1381 // clear the alpha flag if the texture has no transparent pixels
1384 case TEXTYPE_PALETTE:
1385 if (flags & TEXF_ALPHA)
1387 flags &= ~TEXF_ALPHA;
1390 for (i = 0;i < size;i++)
1392 if (((unsigned char *)&palette[data[i]])[3] < 255)
1394 flags |= TEXF_ALPHA;
1403 if (flags & TEXF_ALPHA)
1405 flags &= ~TEXF_ALPHA;
1408 for (i = 3;i < size;i += 4)
1412 flags |= TEXF_ALPHA;
1419 case TEXTYPE_SHADOWMAP:
1426 flags |= TEXF_ALPHA;
1429 flags |= TEXF_ALPHA;
1431 case TEXTYPE_COLORBUFFER:
1432 flags |= TEXF_ALPHA;
1435 Sys_Error("R_LoadTexture: unknown texture type");
1438 texinfo2 = R_GetTexTypeInfo(textype, flags);
1439 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1442 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1444 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1446 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1448 glt->chain = pool->gltchain;
1449 pool->gltchain = glt;
1450 glt->inputwidth = width;
1451 glt->inputheight = height;
1452 glt->inputdepth = depth;
1454 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
1455 glt->textype = texinfo;
1456 glt->texturetype = texturetype;
1457 glt->inputdatasize = size;
1458 glt->palette = palette;
1459 glt->glinternalformat = texinfo->glinternalformat;
1460 glt->glformat = texinfo->glformat;
1461 glt->gltype = texinfo->gltype;
1462 glt->bytesperpixel = texinfo->internalbytesperpixel;
1463 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1466 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1467 // init the dynamic texture attributes, too [11/22/2007 Black]
1468 glt->updatecallback = NULL;
1469 glt->updatacallback_data = NULL;
1471 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1473 // upload the texture
1474 // data may be NULL (blank texture for dynamic rendering)
1475 switch(vid.renderpath)
1477 case RENDERPATH_GL11:
1478 case RENDERPATH_GL13:
1479 case RENDERPATH_GL20:
1480 case RENDERPATH_CGGL:
1482 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1484 case RENDERPATH_D3D9:
1487 D3DFORMAT d3dformat;
1492 d3dpool = D3DPOOL_MANAGED;
1493 if (flags & TEXF_RENDERTARGET)
1495 d3dusage |= D3DUSAGE_RENDERTARGET;
1496 d3dpool = D3DPOOL_DEFAULT;
1500 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1501 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1502 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1503 case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1504 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1505 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1506 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1508 glt->d3dformat = d3dformat;
1509 glt->d3dusage = d3dusage;
1510 glt->d3dpool = d3dpool;
1511 if (glt->tiledepth > 1)
1513 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)))
1514 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1516 else if (glt->sides == 6)
1518 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1519 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1523 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)))
1524 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1529 case RENDERPATH_D3D10:
1530 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1532 case RENDERPATH_D3D11:
1533 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1537 R_UploadFullTexture(glt, data);
1538 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1539 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1541 // free any temporary processing buffer we allocated...
1543 Mem_Free(temppixels);
1545 // texture converting and uploading can take a while, so make sure we're sending keepalives
1546 // FIXME: this causes rendering during R_Shadow_DrawLights
1547 // CL_KeepaliveMessage(false);
1549 return (rtexture_t *)glt;
1552 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)
1554 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1557 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)
1559 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1562 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)
1564 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1567 rtexture_t *R_LoadTextureRectangle(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)
1569 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_RECTANGLE, data, palette);
1572 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1574 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1576 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1578 flags |= TEXF_FORCENEAREST;
1579 if (precision <= 16)
1580 flags |= TEXF_LOWPRECISION;
1584 rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1586 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
1589 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1591 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1594 rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter)
1596 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
1599 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1601 gltexture_t *glt = (gltexture_t *)rt;
1604 int bytesperpixel = 0;
1605 int bytesperblock = 0;
1607 int dds_format_flags;
1615 GLint internalformat;
1616 const char *ddsfourcc;
1618 return -1; // NULL pointer
1619 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1620 return -2; // broken driver - crashes on reading internal format
1621 if (!qglGetTexLevelParameteriv)
1623 GL_ActiveTexture(0);
1624 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1625 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1626 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1627 switch(internalformat)
1629 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1630 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1631 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1632 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1633 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1635 if (!bytesperblock && skipuncompressed)
1636 return -3; // skipped
1637 memset(mipinfo, 0, sizeof(mipinfo));
1638 mipinfo[0][0] = glt->tilewidth;
1639 mipinfo[0][1] = glt->tileheight;
1641 if (glt->flags & TEXF_MIPMAP)
1643 for (mip = 1;mip < 16;mip++)
1645 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1646 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1647 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1655 for (mip = 0;mip < mipmaps;mip++)
1657 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1658 mipinfo[mip][3] = ddssize;
1659 ddssize += mipinfo[mip][2];
1661 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1664 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1668 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1669 dds_format_flags = 0x4; // DDPF_FOURCC
1673 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1674 dds_format_flags = 0x40; // DDPF_RGB
1678 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1679 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1682 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1683 memcpy(dds, "DDS ", 4);
1684 StoreLittleLong(dds+4, ddssize);
1685 StoreLittleLong(dds+8, dds_flags);
1686 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1687 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1688 StoreLittleLong(dds+24, 1); // depth
1689 StoreLittleLong(dds+28, mipmaps); // mipmaps
1690 StoreLittleLong(dds+76, 32); // format size
1691 StoreLittleLong(dds+80, dds_format_flags);
1692 StoreLittleLong(dds+108, dds_caps1);
1693 StoreLittleLong(dds+112, dds_caps2);
1696 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1697 memcpy(dds+84, ddsfourcc, 4);
1698 for (mip = 0;mip < mipmaps;mip++)
1700 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1705 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1706 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1707 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1708 for (mip = 0;mip < mipmaps;mip++)
1710 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1713 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1714 ret = FS_WriteFile(filename, dds, ddssize);
1716 return ret ? ddssize : -5;
1719 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
1721 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1724 int bytesperblock, bytesperpixel;
1727 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1728 textypeinfo_t *texinfo;
1729 int mip, mipwidth, mipheight, mipsize;
1731 GLint oldbindtexnum = 0;
1732 const unsigned char *mippixels, *ddspixels;
1734 fs_offset_t ddsfilesize;
1735 unsigned int ddssize;
1737 if (cls.state == ca_dedicated)
1740 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1741 ddssize = ddsfilesize;
1745 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1746 return NULL; // not found
1749 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1752 Con_Printf("^1%s: not a DDS image\n", filename);
1756 //dds_flags = BuffLittleLong(dds+8);
1757 dds_format_flags = BuffLittleLong(dds+80);
1758 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1759 dds_width = BuffLittleLong(dds+16);
1760 dds_height = BuffLittleLong(dds+12);
1761 ddspixels = dds + 128;
1763 if(r_texture_dds_load_alphamode.integer == 0)
1764 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1765 flags &= ~TEXF_ALPHA;
1767 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1768 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1770 // very sloppy BGRA 32bit identification
1771 textype = TEXTYPE_BGRA;
1774 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1775 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1778 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1781 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1784 for (i = 3;i < size;i += 4)
1785 if (ddspixels[i] < 255)
1788 flags &= ~TEXF_ALPHA;
1791 else if (!memcmp(dds+84, "DXT1", 4))
1793 if(!vid.support.ext_texture_compression_s3tc)
1798 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1799 // LordHavoc: it is my belief that this does not infringe on the
1800 // patent because it is not decoding pixels...
1801 textype = TEXTYPE_DXT1;
1804 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1805 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1806 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1809 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1812 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1814 if(r_texture_dds_load_alphamode.integer == 1)
1817 for (i = 0;i < size;i += bytesperblock)
1818 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1820 // NOTE: this assumes sizeof(unsigned int) == 4
1821 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1822 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1823 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1827 textype = TEXTYPE_DXT1A;
1829 flags &= ~TEXF_ALPHA;
1833 flags &= ~TEXF_ALPHA;
1837 else if (!memcmp(dds+84, "DXT3", 4))
1839 if(!vid.support.ext_texture_compression_s3tc)
1844 textype = TEXTYPE_DXT3;
1847 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1848 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1851 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1854 // we currently always assume alpha
1856 else if (!memcmp(dds+84, "DXT5", 4))
1858 if(!vid.support.ext_texture_compression_s3tc)
1863 textype = TEXTYPE_DXT5;
1866 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1867 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1870 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1873 // we currently always assume alpha
1878 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1882 // return whether this texture is transparent
1884 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1886 // calculate average color if requested
1890 Vector4Clear(avgcolor);
1893 for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
1895 c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
1896 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1897 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
1898 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
1900 f = (float)bytesperblock / size;
1901 avgcolor[0] *= (0.5f / 31.0f) * f;
1902 avgcolor[1] *= (0.5f / 63.0f) * f;
1903 avgcolor[2] *= (0.5f / 31.0f) * f;
1904 avgcolor[3] = 1; // too hard to calculate
1908 for (i = 0;i < size;i += 4)
1910 avgcolor[0] += ddspixels[i+2];
1911 avgcolor[1] += ddspixels[i+1];
1912 avgcolor[2] += ddspixels[i];
1913 avgcolor[3] += ddspixels[i+3];
1915 f = (1.0f / 255.0f) * bytesperpixel / size;
1923 // this is where we apply gl_picmip
1924 mippixels = ddspixels;
1925 mipwidth = dds_width;
1926 mipheight = dds_height;
1927 while(miplevel >= 1 && dds_miplevels >= 1)
1929 if (mipwidth <= 1 && mipheight <= 1)
1931 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1932 mippixels += mipsize; // just skip
1941 // when not requesting mipmaps, do not load them
1942 if(!(flags & TEXF_MIPMAP))
1945 if (dds_miplevels >= 1)
1946 flags |= TEXF_MIPMAP;
1948 flags &= ~TEXF_MIPMAP;
1950 // if S3TC is not supported, there's very little we can do about it
1951 if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
1954 Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
1958 texinfo = R_GetTexTypeInfo(textype, flags);
1960 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1961 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
1963 glt->chain = pool->gltchain;
1964 pool->gltchain = glt;
1965 glt->inputwidth = mipwidth;
1966 glt->inputheight = mipheight;
1967 glt->inputdepth = 1;
1969 glt->textype = texinfo;
1970 glt->texturetype = GLTEXTURETYPE_2D;
1971 glt->inputdatasize = ddssize;
1972 glt->glinternalformat = texinfo->glinternalformat;
1973 glt->glformat = texinfo->glformat;
1974 glt->gltype = texinfo->gltype;
1975 glt->bytesperpixel = texinfo->internalbytesperpixel;
1977 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1978 glt->tilewidth = mipwidth;
1979 glt->tileheight = mipheight;
1981 glt->miplevels = dds_miplevels;
1983 // texture uploading can take a while, so make sure we're sending keepalives
1984 CL_KeepaliveMessage(false);
1986 // create the texture object
1987 switch(vid.renderpath)
1989 case RENDERPATH_GL11:
1990 case RENDERPATH_GL13:
1991 case RENDERPATH_GL20:
1992 case RENDERPATH_CGGL:
1994 GL_ActiveTexture(0);
1995 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1996 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1997 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1999 case RENDERPATH_D3D9:
2002 D3DFORMAT d3dformat;
2007 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2008 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2009 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2010 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2011 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2014 d3dpool = D3DPOOL_MANAGED;
2015 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2019 case RENDERPATH_D3D10:
2020 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2022 case RENDERPATH_D3D11:
2023 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2027 // upload the texture
2028 // we need to restore the texture binding after finishing the upload
2029 mipcomplete = false;
2031 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2033 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2034 if (mippixels + mipsize > dds + ddssize)
2036 switch(vid.renderpath)
2038 case RENDERPATH_GL11:
2039 case RENDERPATH_GL13:
2040 case RENDERPATH_GL20:
2041 case RENDERPATH_CGGL:
2044 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2048 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2051 case RENDERPATH_D3D9:
2054 D3DLOCKED_RECT d3dlockedrect;
2055 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2057 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2058 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2064 case RENDERPATH_D3D10:
2065 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2067 case RENDERPATH_D3D11:
2068 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2071 mippixels += mipsize;
2072 if (mipwidth <= 1 && mipheight <= 1)
2083 // after upload we have to set some parameters...
2084 switch(vid.renderpath)
2086 case RENDERPATH_GL11:
2087 case RENDERPATH_GL13:
2088 case RENDERPATH_GL20:
2089 case RENDERPATH_CGGL:
2090 if (dds_miplevels >= 1 && !mipcomplete)
2092 // need to set GL_TEXTURE_MAX_LEVEL
2093 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2095 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2096 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2098 case RENDERPATH_D3D9:
2100 glt->d3daddressw = 0;
2101 if (glt->flags & TEXF_CLAMP)
2103 glt->d3daddressu = D3DTADDRESS_CLAMP;
2104 glt->d3daddressv = D3DTADDRESS_CLAMP;
2105 if (glt->tiledepth > 1)
2106 glt->d3daddressw = D3DTADDRESS_CLAMP;
2110 glt->d3daddressu = D3DTADDRESS_WRAP;
2111 glt->d3daddressv = D3DTADDRESS_WRAP;
2112 if (glt->tiledepth > 1)
2113 glt->d3daddressw = D3DTADDRESS_WRAP;
2115 glt->d3dmipmaplodbias = 0;
2116 glt->d3dmaxmiplevel = 0;
2117 glt->d3dmaxmiplevelfilter = 0;
2118 if (glt->flags & TEXF_MIPMAP)
2120 glt->d3dminfilter = d3d_filter_mipmin;
2121 glt->d3dmagfilter = d3d_filter_mipmag;
2122 glt->d3dmipfilter = d3d_filter_mipmix;
2126 glt->d3dminfilter = d3d_filter_flatmin;
2127 glt->d3dmagfilter = d3d_filter_flatmag;
2128 glt->d3dmipfilter = d3d_filter_flatmix;
2132 case RENDERPATH_D3D10:
2133 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2135 case RENDERPATH_D3D11:
2136 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2141 return (rtexture_t *)glt;
2144 int R_TextureWidth(rtexture_t *rt)
2146 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2149 int R_TextureHeight(rtexture_t *rt)
2151 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2154 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
2156 gltexture_t *glt = (gltexture_t *)rt;
2158 Host_Error("R_UpdateTexture: no data supplied");
2160 Host_Error("R_UpdateTexture: no texture supplied");
2161 if (!glt->texnum && !glt->d3dtexture)
2163 Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", (void *)glt, glt->identifier, (void *)glt->pool);
2166 // update part of the texture
2167 if (glt->bufferpixels)
2170 int bpp = glt->bytesperpixel;
2171 int inputskip = width*bpp;
2172 int outputskip = glt->tilewidth*bpp;
2173 const unsigned char *input = data;
2174 unsigned char *output = glt->bufferpixels;
2184 input -= y*inputskip;
2187 if (width > glt->tilewidth - x)
2188 width = glt->tilewidth - x;
2189 if (height > glt->tileheight - y)
2190 height = glt->tileheight - y;
2191 if (width < 1 || height < 1)
2194 glt->buffermodified = true;
2195 output += y*outputskip + x*bpp;
2196 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2197 memcpy(output, input, width*bpp);
2199 else if (x || y || width != glt->inputwidth || height != glt->inputheight)
2200 R_UploadPartialTexture(glt, data, x, y, 0, width, height, 1);
2202 R_UploadFullTexture(glt, data);
2205 int R_RealGetTexture(rtexture_t *rt)
2210 glt = (gltexture_t *)rt;
2211 if (glt->flags & GLTEXF_DYNAMIC)
2212 R_UpdateDynamicTexture(glt);
2213 if (glt->buffermodified && glt->bufferpixels)
2215 glt->buffermodified = false;
2216 R_UploadFullTexture(glt, glt->bufferpixels);
2225 void R_ClearTexture (rtexture_t *rt)
2227 gltexture_t *glt = (gltexture_t *)rt;
2229 R_UploadFullTexture(glt, NULL);
2232 int R_PicmipForFlags(int flags)
2235 if(flags & TEXF_PICMIP)
2237 miplevel += gl_picmip.integer;
2238 if (flags & TEXF_ISWORLD)
2240 if (r_picmipworld.integer)
2241 miplevel += gl_picmip_world.integer;
2245 else if (flags & TEXF_ISSPRITE)
2247 if (r_picmipsprites.integer)
2248 miplevel += gl_picmip_sprites.integer;
2253 miplevel += gl_picmip_other.integer;
2255 return max(0, miplevel);