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;
515 if (vid.support.arb_texture_non_power_of_two)
517 width2 = min(inwidth >> picmip, maxsize);
518 height2 = min(inheight >> picmip, maxsize);
519 depth2 = min(indepth >> picmip, maxsize);
523 for (width2 = 1;width2 < inwidth;width2 <<= 1);
524 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
525 for (height2 = 1;height2 < inheight;height2 <<= 1);
526 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
527 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
528 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
531 switch(vid.renderpath)
533 case RENDERPATH_GL11:
534 case RENDERPATH_GL13:
535 case RENDERPATH_GL20:
536 case RENDERPATH_CGGL:
537 case RENDERPATH_D3D10:
538 case RENDERPATH_D3D11:
540 case RENDERPATH_D3D9:
541 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
542 if (texturetype == GLTEXTURETYPE_2D)
544 width2 = max(width2, 2);
545 height2 = max(height2, 2);
551 if (flags & TEXF_MIPMAP)
553 int extent = max(width2, max(height2, depth2));
559 *outwidth = max(1, width2);
561 *outheight = max(1, height2);
563 *outdepth = max(1, depth2);
565 *outmiplevels = miplevels;
569 static int R_CalcTexelDataSize (gltexture_t *glt)
571 int width2, height2, depth2, size;
573 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
575 size = width2 * height2 * depth2;
577 if (glt->flags & TEXF_MIPMAP)
579 while (width2 > 1 || height2 > 1 || depth2 > 1)
587 size += width2 * height2 * depth2;
591 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
594 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
598 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
599 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
601 gltexturepool_t *pool;
603 Con_Print("glsize input loaded mip alpha name\n");
604 for (pool = gltexturepoolchain;pool;pool = pool->next)
612 for (glt = pool->gltchain;glt;glt = glt->chain)
614 glsize = R_CalcTexelDataSize(glt);
615 isloaded = glt->texnum != 0;
617 pooltotalt += glsize;
618 pooltotalp += glt->inputdatasize;
622 poolloadedt += glsize;
623 poolloadedp += glt->inputdatasize;
626 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);
629 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);
630 sumtotal += pooltotal;
631 sumtotalt += pooltotalt;
632 sumtotalp += pooltotalp;
633 sumloaded += poolloaded;
634 sumloadedt += poolloadedt;
635 sumloadedp += poolloadedp;
638 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);
641 static void R_TextureStats_f(void)
643 R_TextureStats_Print(true, true, true);
646 static void r_textures_start(void)
648 switch(vid.renderpath)
650 case RENDERPATH_GL11:
651 case RENDERPATH_GL13:
652 case RENDERPATH_GL20:
653 case RENDERPATH_CGGL:
654 // LordHavoc: allow any alignment
656 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
657 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
659 case RENDERPATH_D3D9:
661 case RENDERPATH_D3D10:
662 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
664 case RENDERPATH_D3D11:
665 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
669 texturemempool = Mem_AllocPool("texture management", 0, NULL);
670 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
672 // Disable JPEG screenshots if the DLL isn't loaded
673 if (! JPEG_OpenLibrary ())
674 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
675 if (! PNG_OpenLibrary ())
676 Cvar_SetValueQuick (&scr_screenshot_png, 0);
679 static void r_textures_shutdown(void)
681 rtexturepool_t *temp;
683 JPEG_CloseLibrary ();
685 while(gltexturepoolchain)
687 temp = (rtexturepool_t *) gltexturepoolchain;
688 R_FreeTexturePool(&temp);
691 resizebuffersize = 0;
693 colorconvertbuffer = NULL;
694 texturebuffer = NULL;
695 Mem_ExpandableArray_FreeArray(&texturearray);
696 Mem_FreePool(&texturemempool);
699 static void r_textures_newmap(void)
703 static void r_textures_devicelost(void)
707 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
708 for (i = 0;i < endindex;i++)
710 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
711 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
713 switch(vid.renderpath)
715 case RENDERPATH_GL11:
716 case RENDERPATH_GL13:
717 case RENDERPATH_GL20:
718 case RENDERPATH_CGGL:
720 case RENDERPATH_D3D9:
722 if (glt->tiledepth > 1)
723 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
724 else if (glt->sides == 6)
725 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
727 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
728 glt->d3dtexture = NULL;
731 case RENDERPATH_D3D10:
732 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
734 case RENDERPATH_D3D11:
735 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
741 static void r_textures_devicerestored(void)
745 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
746 for (i = 0;i < endindex;i++)
748 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
749 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
751 switch(vid.renderpath)
753 case RENDERPATH_GL11:
754 case RENDERPATH_GL13:
755 case RENDERPATH_GL20:
756 case RENDERPATH_CGGL:
758 case RENDERPATH_D3D9:
762 if (glt->tiledepth > 1)
764 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)))
765 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
767 else if (glt->sides == 6)
769 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
770 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
774 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)))
775 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
780 case RENDERPATH_D3D10:
781 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
783 case RENDERPATH_D3D11:
784 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
791 void R_Textures_Init (void)
793 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");
794 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
795 Cvar_RegisterVariable (&gl_max_size);
796 Cvar_RegisterVariable (&gl_picmip);
797 Cvar_RegisterVariable (&gl_picmip_world);
798 Cvar_RegisterVariable (&r_picmipworld);
799 Cvar_RegisterVariable (&gl_picmip_sprites);
800 Cvar_RegisterVariable (&r_picmipsprites);
801 Cvar_RegisterVariable (&gl_picmip_other);
802 Cvar_RegisterVariable (&gl_max_lightmapsize);
803 Cvar_RegisterVariable (&r_lerpimages);
804 Cvar_RegisterVariable (&gl_texture_anisotropy);
805 Cvar_RegisterVariable (&gl_texturecompression);
806 Cvar_RegisterVariable (&gl_texturecompression_color);
807 Cvar_RegisterVariable (&gl_texturecompression_normal);
808 Cvar_RegisterVariable (&gl_texturecompression_gloss);
809 Cvar_RegisterVariable (&gl_texturecompression_glow);
810 Cvar_RegisterVariable (&gl_texturecompression_2d);
811 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
812 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
813 Cvar_RegisterVariable (&gl_texturecompression_sky);
814 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
815 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
816 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
817 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
819 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
822 void R_Textures_Frame (void)
824 static int old_aniso = 0;
826 // could do procedural texture animation here, if we keep track of which
827 // textures were accessed this frame...
829 // free the resize buffers
830 resizebuffersize = 0;
833 Mem_Free(resizebuffer);
836 if (colorconvertbuffer)
838 Mem_Free(colorconvertbuffer);
839 colorconvertbuffer = NULL;
842 if (old_aniso != gl_texture_anisotropy.integer)
845 gltexturepool_t *pool;
848 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
850 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
852 switch(vid.renderpath)
854 case RENDERPATH_GL11:
855 case RENDERPATH_GL13:
856 case RENDERPATH_GL20:
857 case RENDERPATH_CGGL:
860 for (pool = gltexturepoolchain;pool;pool = pool->next)
862 for (glt = pool->gltchain;glt;glt = glt->chain)
864 // only update already uploaded images
865 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
867 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
869 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
870 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
872 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
877 case RENDERPATH_D3D9:
878 case RENDERPATH_D3D10:
879 case RENDERPATH_D3D11:
885 void R_MakeResizeBufferBigger(int size)
887 if (resizebuffersize < size)
889 resizebuffersize = size;
891 Mem_Free(resizebuffer);
892 if (colorconvertbuffer)
893 Mem_Free(colorconvertbuffer);
894 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
895 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
896 if (!resizebuffer || !colorconvertbuffer)
897 Host_Error("R_Upload: out of memory");
901 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
903 int textureenum = gltexturetypeenums[texturetype];
904 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
908 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
910 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
911 if (gl_texture_anisotropy.integer != aniso)
912 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
913 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
915 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
916 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
917 if (gltexturetypedimensions[texturetype] >= 3)
919 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
923 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
925 if (flags & TEXF_MIPMAP)
927 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
931 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
933 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
935 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
937 if (flags & TEXF_MIPMAP)
939 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
941 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
945 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
950 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
952 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
956 if (flags & TEXF_MIPMAP)
958 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
962 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
964 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
967 if (textype == TEXTYPE_SHADOWMAP)
969 if (vid.support.arb_shadow)
971 if (flags & TEXF_COMPARE)
973 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
977 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
979 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
981 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
987 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
990 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
992 if (glt->texturetype != GLTEXTURETYPE_2D)
993 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
995 if (glt->textype->textype == TEXTYPE_PALETTE)
996 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
998 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
999 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1001 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1002 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1004 // update a portion of the image
1006 switch(vid.renderpath)
1008 case RENDERPATH_GL11:
1009 case RENDERPATH_GL13:
1010 case RENDERPATH_GL20:
1011 case RENDERPATH_CGGL:
1015 // we need to restore the texture binding after finishing the upload
1016 GL_ActiveTexture(0);
1017 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1018 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1019 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1020 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1023 case RENDERPATH_D3D9:
1027 D3DLOCKED_RECT d3dlockedrect;
1029 memset(&d3drect, 0, sizeof(d3drect));
1030 d3drect.left = fragx;
1031 d3drect.top = fragy;
1032 d3drect.right = fragx+fragwidth;
1033 d3drect.bottom = fragy+fragheight;
1034 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1036 for (y = 0;y < fragheight;y++)
1037 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1038 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1043 case RENDERPATH_D3D10:
1044 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1046 case RENDERPATH_D3D11:
1047 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1052 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1054 int i, mip = 0, width, height, depth;
1055 GLint oldbindtexnum = 0;
1056 const unsigned char *prevbuffer;
1059 // error out if a stretch is needed on special texture types
1060 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1061 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1063 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1064 // of the target size and then use the mipmap reduction function to get
1065 // high quality supersampled results
1066 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1067 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1068 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1069 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1071 if (prevbuffer == NULL)
1073 width = glt->tilewidth;
1074 height = glt->tileheight;
1075 depth = glt->tiledepth;
1076 memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1077 prevbuffer = resizebuffer;
1079 else if (glt->textype->textype == TEXTYPE_PALETTE)
1081 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1082 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1083 prevbuffer = colorconvertbuffer;
1086 // scale up to a power of 2 size (if appropriate)
1087 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1089 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1090 prevbuffer = resizebuffer;
1092 // apply mipmap reduction algorithm to get down to picmip/max_size
1093 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1095 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1096 prevbuffer = resizebuffer;
1099 // do the appropriate upload type...
1100 switch(vid.renderpath)
1102 case RENDERPATH_GL11:
1103 case RENDERPATH_GL13:
1104 case RENDERPATH_GL20:
1105 case RENDERPATH_CGGL:
1108 // we need to restore the texture binding after finishing the upload
1109 GL_ActiveTexture(0);
1110 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1111 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1113 if (qglGetCompressedTexImageARB)
1115 if (gl_texturecompression.integer >= 2)
1116 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1118 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1121 switch(glt->texturetype)
1123 case GLTEXTURETYPE_2D:
1124 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1125 if (glt->flags & TEXF_MIPMAP)
1127 while (width > 1 || height > 1 || depth > 1)
1129 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1130 prevbuffer = resizebuffer;
1131 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1135 case GLTEXTURETYPE_3D:
1136 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1137 if (glt->flags & TEXF_MIPMAP)
1139 while (width > 1 || height > 1 || depth > 1)
1141 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1142 prevbuffer = resizebuffer;
1143 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1147 case GLTEXTURETYPE_CUBEMAP:
1148 // convert and upload each side in turn,
1149 // from a continuous block of input texels
1150 texturebuffer = (unsigned char *)prevbuffer;
1151 for (i = 0;i < 6;i++)
1153 prevbuffer = texturebuffer;
1154 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1155 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1157 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1158 prevbuffer = resizebuffer;
1161 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1163 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1164 prevbuffer = resizebuffer;
1167 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1168 if (glt->flags & TEXF_MIPMAP)
1170 while (width > 1 || height > 1 || depth > 1)
1172 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1173 prevbuffer = resizebuffer;
1174 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1179 case GLTEXTURETYPE_RECTANGLE:
1180 qglTexImage2D(GL_TEXTURE_RECTANGLE_ARB, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, NULL);CHECKGLERROR
1183 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1184 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1186 case RENDERPATH_D3D9:
1188 if (!(glt->flags & TEXF_RENDERTARGET))
1190 D3DLOCKED_RECT d3dlockedrect;
1191 D3DLOCKED_BOX d3dlockedbox;
1192 switch(glt->texturetype)
1194 case GLTEXTURETYPE_2D:
1195 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1198 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1200 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1201 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1204 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1206 while (width > 1 || height > 1 || depth > 1)
1208 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1209 prevbuffer = resizebuffer;
1210 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1212 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1213 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1219 case GLTEXTURETYPE_3D:
1220 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1222 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1223 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1224 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1227 if (glt->flags & TEXF_MIPMAP)
1229 while (width > 1 || height > 1 || depth > 1)
1231 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1232 prevbuffer = resizebuffer;
1233 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1235 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1236 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1237 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1243 case GLTEXTURETYPE_CUBEMAP:
1244 // convert and upload each side in turn,
1245 // from a continuous block of input texels
1246 texturebuffer = (unsigned char *)prevbuffer;
1247 for (i = 0;i < 6;i++)
1249 prevbuffer = texturebuffer;
1250 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1251 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1253 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1254 prevbuffer = resizebuffer;
1257 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1259 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1260 prevbuffer = resizebuffer;
1263 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1265 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1266 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1269 if (glt->flags & TEXF_MIPMAP)
1271 while (width > 1 || height > 1 || depth > 1)
1273 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1274 prevbuffer = resizebuffer;
1275 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1277 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1278 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1285 case GLTEXTURETYPE_RECTANGLE:
1286 Sys_Error("Direct3D does not have RECTANGLE textures\n");
1290 glt->d3daddressw = 0;
1291 if (glt->flags & TEXF_CLAMP)
1293 glt->d3daddressu = D3DTADDRESS_CLAMP;
1294 glt->d3daddressv = D3DTADDRESS_CLAMP;
1295 if (glt->tiledepth > 1)
1296 glt->d3daddressw = D3DTADDRESS_CLAMP;
1300 glt->d3daddressu = D3DTADDRESS_WRAP;
1301 glt->d3daddressv = D3DTADDRESS_WRAP;
1302 if (glt->tiledepth > 1)
1303 glt->d3daddressw = D3DTADDRESS_WRAP;
1305 glt->d3dmipmaplodbias = 0;
1306 glt->d3dmaxmiplevel = 0;
1307 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1308 if (glt->flags & TEXF_FORCELINEAR)
1310 glt->d3dminfilter = D3DTEXF_LINEAR;
1311 glt->d3dmagfilter = D3DTEXF_LINEAR;
1312 glt->d3dmipfilter = D3DTEXF_POINT;
1314 else if (glt->flags & TEXF_FORCENEAREST)
1316 glt->d3dminfilter = D3DTEXF_POINT;
1317 glt->d3dmagfilter = D3DTEXF_POINT;
1318 glt->d3dmipfilter = D3DTEXF_POINT;
1320 else if (glt->flags & TEXF_MIPMAP)
1322 glt->d3dminfilter = d3d_filter_mipmin;
1323 glt->d3dmagfilter = d3d_filter_mipmag;
1324 glt->d3dmipfilter = d3d_filter_mipmix;
1328 glt->d3dminfilter = d3d_filter_flatmin;
1329 glt->d3dmagfilter = d3d_filter_flatmag;
1330 glt->d3dmipfilter = d3d_filter_flatmix;
1334 case RENDERPATH_D3D10:
1335 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1337 case RENDERPATH_D3D11:
1338 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1343 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)
1347 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1348 textypeinfo_t *texinfo, *texinfo2;
1349 unsigned char *temppixels = NULL;
1351 if (cls.state == ca_dedicated)
1354 if (texturetype == GLTEXTURETYPE_RECTANGLE && !vid.support.arb_texture_rectangle)
1356 Con_Printf ("R_LoadTexture: rectangle texture not supported by driver\n");
1359 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1361 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1364 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1366 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1370 texinfo = R_GetTexTypeInfo(textype, flags);
1371 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1374 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1378 if (textype == TEXTYPE_RGBA)
1381 static int rgbaswapindices[4] = {2, 1, 0, 3};
1382 textype = TEXTYPE_BGRA;
1383 texinfo = R_GetTexTypeInfo(textype, flags);
1384 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1385 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1389 // clear the alpha flag if the texture has no transparent pixels
1392 case TEXTYPE_PALETTE:
1393 if (flags & TEXF_ALPHA)
1395 flags &= ~TEXF_ALPHA;
1398 for (i = 0;i < size;i++)
1400 if (((unsigned char *)&palette[data[i]])[3] < 255)
1402 flags |= TEXF_ALPHA;
1411 if (flags & TEXF_ALPHA)
1413 flags &= ~TEXF_ALPHA;
1416 for (i = 3;i < size;i += 4)
1420 flags |= TEXF_ALPHA;
1427 case TEXTYPE_SHADOWMAP:
1434 flags |= TEXF_ALPHA;
1437 flags |= TEXF_ALPHA;
1439 case TEXTYPE_COLORBUFFER:
1440 flags |= TEXF_ALPHA;
1443 Sys_Error("R_LoadTexture: unknown texture type");
1446 texinfo2 = R_GetTexTypeInfo(textype, flags);
1447 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1450 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1452 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1454 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1456 glt->chain = pool->gltchain;
1457 pool->gltchain = glt;
1458 glt->inputwidth = width;
1459 glt->inputheight = height;
1460 glt->inputdepth = depth;
1462 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
1463 glt->textype = texinfo;
1464 glt->texturetype = texturetype;
1465 glt->inputdatasize = size;
1466 glt->palette = palette;
1467 glt->glinternalformat = texinfo->glinternalformat;
1468 glt->glformat = texinfo->glformat;
1469 glt->gltype = texinfo->gltype;
1470 glt->bytesperpixel = texinfo->internalbytesperpixel;
1471 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1474 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1475 // init the dynamic texture attributes, too [11/22/2007 Black]
1476 glt->updatecallback = NULL;
1477 glt->updatacallback_data = NULL;
1479 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1481 // upload the texture
1482 // data may be NULL (blank texture for dynamic rendering)
1483 switch(vid.renderpath)
1485 case RENDERPATH_GL11:
1486 case RENDERPATH_GL13:
1487 case RENDERPATH_GL20:
1488 case RENDERPATH_CGGL:
1490 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1492 case RENDERPATH_D3D9:
1495 D3DFORMAT d3dformat;
1500 d3dpool = D3DPOOL_MANAGED;
1501 if (flags & TEXF_RENDERTARGET)
1503 d3dusage |= D3DUSAGE_RENDERTARGET;
1504 d3dpool = D3DPOOL_DEFAULT;
1508 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1509 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1510 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1511 case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1512 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1513 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1514 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1516 glt->d3dformat = d3dformat;
1517 glt->d3dusage = d3dusage;
1518 glt->d3dpool = d3dpool;
1519 if (glt->tiledepth > 1)
1521 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)))
1522 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1524 else if (glt->sides == 6)
1526 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1527 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1531 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)))
1532 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1537 case RENDERPATH_D3D10:
1538 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1540 case RENDERPATH_D3D11:
1541 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1545 R_UploadFullTexture(glt, data);
1546 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1547 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1549 // free any temporary processing buffer we allocated...
1551 Mem_Free(temppixels);
1553 // texture converting and uploading can take a while, so make sure we're sending keepalives
1554 // FIXME: this causes rendering during R_Shadow_DrawLights
1555 // CL_KeepaliveMessage(false);
1557 return (rtexture_t *)glt;
1560 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)
1562 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1565 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)
1567 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1570 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)
1572 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1575 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)
1577 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_RECTANGLE, data, palette);
1580 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1582 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1584 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1586 flags |= TEXF_FORCENEAREST;
1587 if (precision <= 16)
1588 flags |= TEXF_LOWPRECISION;
1592 rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1594 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
1597 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1599 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1602 rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter)
1604 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
1607 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1609 gltexture_t *glt = (gltexture_t *)rt;
1612 int bytesperpixel = 0;
1613 int bytesperblock = 0;
1615 int dds_format_flags;
1623 GLint internalformat;
1624 const char *ddsfourcc;
1626 return -1; // NULL pointer
1627 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1628 return -2; // broken driver - crashes on reading internal format
1629 if (!qglGetTexLevelParameteriv)
1631 GL_ActiveTexture(0);
1632 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1633 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1634 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1635 switch(internalformat)
1637 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1638 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1639 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1640 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1641 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1643 if (!bytesperblock && skipuncompressed)
1644 return -3; // skipped
1645 memset(mipinfo, 0, sizeof(mipinfo));
1646 mipinfo[0][0] = glt->tilewidth;
1647 mipinfo[0][1] = glt->tileheight;
1649 if (glt->flags & TEXF_MIPMAP)
1651 for (mip = 1;mip < 16;mip++)
1653 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1654 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1655 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1663 for (mip = 0;mip < mipmaps;mip++)
1665 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1666 mipinfo[mip][3] = ddssize;
1667 ddssize += mipinfo[mip][2];
1669 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1672 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1676 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1677 dds_format_flags = 0x4; // DDPF_FOURCC
1681 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1682 dds_format_flags = 0x40; // DDPF_RGB
1686 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1687 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1690 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1691 memcpy(dds, "DDS ", 4);
1692 StoreLittleLong(dds+4, ddssize);
1693 StoreLittleLong(dds+8, dds_flags);
1694 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1695 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1696 StoreLittleLong(dds+24, 1); // depth
1697 StoreLittleLong(dds+28, mipmaps); // mipmaps
1698 StoreLittleLong(dds+76, 32); // format size
1699 StoreLittleLong(dds+80, dds_format_flags);
1700 StoreLittleLong(dds+108, dds_caps1);
1701 StoreLittleLong(dds+112, dds_caps2);
1704 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1705 memcpy(dds+84, ddsfourcc, 4);
1706 for (mip = 0;mip < mipmaps;mip++)
1708 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1713 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1714 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1715 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1716 for (mip = 0;mip < mipmaps;mip++)
1718 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1721 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1722 ret = FS_WriteFile(filename, dds, ddssize);
1724 return ret ? ddssize : -5;
1727 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
1729 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1732 int bytesperblock, bytesperpixel;
1735 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1736 textypeinfo_t *texinfo;
1737 int mip, mipwidth, mipheight, mipsize;
1739 GLint oldbindtexnum = 0;
1740 const unsigned char *mippixels, *ddspixels;
1742 fs_offset_t ddsfilesize;
1743 unsigned int ddssize;
1745 if (cls.state == ca_dedicated)
1748 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1749 ddssize = ddsfilesize;
1753 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1754 return NULL; // not found
1757 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1760 Con_Printf("^1%s: not a DDS image\n", filename);
1764 //dds_flags = BuffLittleLong(dds+8);
1765 dds_format_flags = BuffLittleLong(dds+80);
1766 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1767 dds_width = BuffLittleLong(dds+16);
1768 dds_height = BuffLittleLong(dds+12);
1769 ddspixels = dds + 128;
1771 if(r_texture_dds_load_alphamode.integer == 0)
1772 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1773 flags &= ~TEXF_ALPHA;
1775 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1776 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1778 // very sloppy BGRA 32bit identification
1779 textype = TEXTYPE_BGRA;
1782 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1783 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1786 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1789 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1792 for (i = 3;i < size;i += 4)
1793 if (ddspixels[i] < 255)
1796 flags &= ~TEXF_ALPHA;
1799 else if (!memcmp(dds+84, "DXT1", 4))
1801 if(!vid.support.ext_texture_compression_s3tc)
1806 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1807 // LordHavoc: it is my belief that this does not infringe on the
1808 // patent because it is not decoding pixels...
1809 textype = TEXTYPE_DXT1;
1812 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1813 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1814 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1817 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1820 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1822 if(r_texture_dds_load_alphamode.integer == 1)
1825 for (i = 0;i < size;i += bytesperblock)
1826 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1828 // NOTE: this assumes sizeof(unsigned int) == 4
1829 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1830 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1831 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1835 textype = TEXTYPE_DXT1A;
1837 flags &= ~TEXF_ALPHA;
1841 flags &= ~TEXF_ALPHA;
1845 else if (!memcmp(dds+84, "DXT3", 4))
1847 if(!vid.support.ext_texture_compression_s3tc)
1852 textype = TEXTYPE_DXT3;
1855 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1856 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1859 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1862 // we currently always assume alpha
1864 else if (!memcmp(dds+84, "DXT5", 4))
1866 if(!vid.support.ext_texture_compression_s3tc)
1871 textype = TEXTYPE_DXT5;
1874 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1875 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1878 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1881 // we currently always assume alpha
1886 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1890 // return whether this texture is transparent
1892 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1894 // calculate average color if requested
1898 Vector4Clear(avgcolor);
1901 for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
1903 c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
1904 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1905 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
1906 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
1908 f = (float)bytesperblock / size;
1909 avgcolor[0] *= (0.5f / 31.0f) * f;
1910 avgcolor[1] *= (0.5f / 63.0f) * f;
1911 avgcolor[2] *= (0.5f / 31.0f) * f;
1912 avgcolor[3] = 1; // too hard to calculate
1916 for (i = 0;i < size;i += 4)
1918 avgcolor[0] += ddspixels[i+2];
1919 avgcolor[1] += ddspixels[i+1];
1920 avgcolor[2] += ddspixels[i];
1921 avgcolor[3] += ddspixels[i+3];
1923 f = (1.0f / 255.0f) * bytesperpixel / size;
1931 // this is where we apply gl_picmip
1932 mippixels = ddspixels;
1933 mipwidth = dds_width;
1934 mipheight = dds_height;
1935 while(miplevel >= 1 && dds_miplevels >= 1)
1937 if (mipwidth <= 1 && mipheight <= 1)
1939 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1940 mippixels += mipsize; // just skip
1949 // when not requesting mipmaps, do not load them
1950 if(!(flags & TEXF_MIPMAP))
1953 if (dds_miplevels >= 1)
1954 flags |= TEXF_MIPMAP;
1956 flags &= ~TEXF_MIPMAP;
1958 // if S3TC is not supported, there's very little we can do about it
1959 if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
1962 Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
1966 texinfo = R_GetTexTypeInfo(textype, flags);
1968 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1969 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
1971 glt->chain = pool->gltchain;
1972 pool->gltchain = glt;
1973 glt->inputwidth = mipwidth;
1974 glt->inputheight = mipheight;
1975 glt->inputdepth = 1;
1977 glt->textype = texinfo;
1978 glt->texturetype = GLTEXTURETYPE_2D;
1979 glt->inputdatasize = ddssize;
1980 glt->glinternalformat = texinfo->glinternalformat;
1981 glt->glformat = texinfo->glformat;
1982 glt->gltype = texinfo->gltype;
1983 glt->bytesperpixel = texinfo->internalbytesperpixel;
1985 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1986 glt->tilewidth = mipwidth;
1987 glt->tileheight = mipheight;
1989 glt->miplevels = dds_miplevels;
1991 // texture uploading can take a while, so make sure we're sending keepalives
1992 CL_KeepaliveMessage(false);
1994 // create the texture object
1995 switch(vid.renderpath)
1997 case RENDERPATH_GL11:
1998 case RENDERPATH_GL13:
1999 case RENDERPATH_GL20:
2000 case RENDERPATH_CGGL:
2002 GL_ActiveTexture(0);
2003 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2004 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2005 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2007 case RENDERPATH_D3D9:
2010 D3DFORMAT d3dformat;
2015 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2016 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2017 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2018 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2019 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2022 d3dpool = D3DPOOL_MANAGED;
2023 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2027 case RENDERPATH_D3D10:
2028 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2030 case RENDERPATH_D3D11:
2031 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2035 // upload the texture
2036 // we need to restore the texture binding after finishing the upload
2037 mipcomplete = false;
2039 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2041 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2042 if (mippixels + mipsize > dds + ddssize)
2044 switch(vid.renderpath)
2046 case RENDERPATH_GL11:
2047 case RENDERPATH_GL13:
2048 case RENDERPATH_GL20:
2049 case RENDERPATH_CGGL:
2052 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2056 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2059 case RENDERPATH_D3D9:
2062 D3DLOCKED_RECT d3dlockedrect;
2063 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2065 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2066 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2072 case RENDERPATH_D3D10:
2073 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2075 case RENDERPATH_D3D11:
2076 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2079 mippixels += mipsize;
2080 if (mipwidth <= 1 && mipheight <= 1)
2091 // after upload we have to set some parameters...
2092 switch(vid.renderpath)
2094 case RENDERPATH_GL11:
2095 case RENDERPATH_GL13:
2096 case RENDERPATH_GL20:
2097 case RENDERPATH_CGGL:
2098 if (dds_miplevels >= 1 && !mipcomplete)
2100 // need to set GL_TEXTURE_MAX_LEVEL
2101 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2103 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2104 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2106 case RENDERPATH_D3D9:
2108 glt->d3daddressw = 0;
2109 if (glt->flags & TEXF_CLAMP)
2111 glt->d3daddressu = D3DTADDRESS_CLAMP;
2112 glt->d3daddressv = D3DTADDRESS_CLAMP;
2113 if (glt->tiledepth > 1)
2114 glt->d3daddressw = D3DTADDRESS_CLAMP;
2118 glt->d3daddressu = D3DTADDRESS_WRAP;
2119 glt->d3daddressv = D3DTADDRESS_WRAP;
2120 if (glt->tiledepth > 1)
2121 glt->d3daddressw = D3DTADDRESS_WRAP;
2123 glt->d3dmipmaplodbias = 0;
2124 glt->d3dmaxmiplevel = 0;
2125 glt->d3dmaxmiplevelfilter = 0;
2126 if (glt->flags & TEXF_MIPMAP)
2128 glt->d3dminfilter = d3d_filter_mipmin;
2129 glt->d3dmagfilter = d3d_filter_mipmag;
2130 glt->d3dmipfilter = d3d_filter_mipmix;
2134 glt->d3dminfilter = d3d_filter_flatmin;
2135 glt->d3dmagfilter = d3d_filter_flatmag;
2136 glt->d3dmipfilter = d3d_filter_flatmix;
2140 case RENDERPATH_D3D10:
2141 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2143 case RENDERPATH_D3D11:
2144 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2149 return (rtexture_t *)glt;
2152 int R_TextureWidth(rtexture_t *rt)
2154 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2157 int R_TextureHeight(rtexture_t *rt)
2159 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2162 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
2164 gltexture_t *glt = (gltexture_t *)rt;
2166 Host_Error("R_UpdateTexture: no data supplied");
2168 Host_Error("R_UpdateTexture: no texture supplied");
2169 if (!glt->texnum && !glt->d3dtexture)
2171 Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", (void *)glt, glt->identifier, (void *)glt->pool);
2174 // update part of the texture
2175 if (glt->bufferpixels)
2178 int bpp = glt->bytesperpixel;
2179 int inputskip = width*bpp;
2180 int outputskip = glt->tilewidth*bpp;
2181 const unsigned char *input = data;
2182 unsigned char *output = glt->bufferpixels;
2192 input -= y*inputskip;
2195 if (width > glt->tilewidth - x)
2196 width = glt->tilewidth - x;
2197 if (height > glt->tileheight - y)
2198 height = glt->tileheight - y;
2199 if (width < 1 || height < 1)
2202 glt->buffermodified = true;
2203 output += y*outputskip + x*bpp;
2204 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2205 memcpy(output, input, width*bpp);
2207 else if (x || y || width != glt->inputwidth || height != glt->inputheight)
2208 R_UploadPartialTexture(glt, data, x, y, 0, width, height, 1);
2210 R_UploadFullTexture(glt, data);
2213 int R_RealGetTexture(rtexture_t *rt)
2218 glt = (gltexture_t *)rt;
2219 if (glt->flags & GLTEXF_DYNAMIC)
2220 R_UpdateDynamicTexture(glt);
2221 if (glt->buffermodified && glt->bufferpixels)
2223 glt->buffermodified = false;
2224 R_UploadFullTexture(glt, glt->bufferpixels);
2233 void R_ClearTexture (rtexture_t *rt)
2235 gltexture_t *glt = (gltexture_t *)rt;
2237 R_UploadFullTexture(glt, NULL);
2240 int R_PicmipForFlags(int flags)
2243 if(flags & TEXF_PICMIP)
2245 miplevel += gl_picmip.integer;
2246 if (flags & TEXF_ISWORLD)
2248 if (r_picmipworld.integer)
2249 miplevel += gl_picmip_world.integer;
2253 else if (flags & TEXF_ISSPRITE)
2255 if (r_picmipsprites.integer)
2256 miplevel += gl_picmip_sprites.integer;
2261 miplevel += gl_picmip_other.integer;
2263 return max(0, miplevel);