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;
496 switch(vid.renderpath)
498 case RENDERPATH_GL11:
499 case RENDERPATH_GL13:
500 case RENDERPATH_GL20:
501 case RENDERPATH_CGGL:
502 case RENDERPATH_D3D10:
503 case RENDERPATH_D3D11:
505 case RENDERPATH_D3D9:
506 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
509 width2 = max(width2, 2);
510 height2 = max(height2, 2);
518 case GLTEXTURETYPE_2D:
519 maxsize = vid.maxtexturesize_2d;
520 if (flags & TEXF_PICMIP)
522 maxsize = bound(1, gl_max_size.integer, maxsize);
526 case GLTEXTURETYPE_3D:
527 maxsize = vid.maxtexturesize_3d;
529 case GLTEXTURETYPE_CUBEMAP:
530 maxsize = vid.maxtexturesize_cubemap;
536 if (vid.support.arb_texture_non_power_of_two)
537 width2 = min(inwidth >> picmip, maxsize);
540 for (width2 = 1;width2 < inwidth;width2 <<= 1);
541 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
543 *outwidth = max(1, width2);
547 if (vid.support.arb_texture_non_power_of_two)
548 height2 = min(inheight >> picmip, maxsize);
551 for (height2 = 1;height2 < inheight;height2 <<= 1);
552 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
554 *outheight = max(1, height2);
558 if (vid.support.arb_texture_non_power_of_two)
559 depth2 = min(indepth >> picmip, maxsize);
562 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
563 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
565 *outdepth = max(1, depth2);
569 if (flags & TEXF_MIPMAP)
571 int extent = max(width2, max(height2, depth2));
576 *outmiplevels = miplevels;
580 static int R_CalcTexelDataSize (gltexture_t *glt)
582 int width2, height2, depth2, size;
584 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
586 size = width2 * height2 * depth2;
588 if (glt->flags & TEXF_MIPMAP)
590 while (width2 > 1 || height2 > 1 || depth2 > 1)
598 size += width2 * height2 * depth2;
602 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
605 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
609 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
610 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
612 gltexturepool_t *pool;
614 Con_Print("glsize input loaded mip alpha name\n");
615 for (pool = gltexturepoolchain;pool;pool = pool->next)
623 for (glt = pool->gltchain;glt;glt = glt->chain)
625 glsize = R_CalcTexelDataSize(glt);
626 isloaded = glt->texnum != 0;
628 pooltotalt += glsize;
629 pooltotalp += glt->inputdatasize;
633 poolloadedt += glsize;
634 poolloadedp += glt->inputdatasize;
637 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);
640 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);
641 sumtotal += pooltotal;
642 sumtotalt += pooltotalt;
643 sumtotalp += pooltotalp;
644 sumloaded += poolloaded;
645 sumloadedt += poolloadedt;
646 sumloadedp += poolloadedp;
649 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);
652 static void R_TextureStats_f(void)
654 R_TextureStats_Print(true, true, true);
657 static void r_textures_start(void)
659 switch(vid.renderpath)
661 case RENDERPATH_GL11:
662 case RENDERPATH_GL13:
663 case RENDERPATH_GL20:
664 case RENDERPATH_CGGL:
665 // LordHavoc: allow any alignment
667 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
668 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
670 case RENDERPATH_D3D9:
672 case RENDERPATH_D3D10:
673 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
675 case RENDERPATH_D3D11:
676 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
680 texturemempool = Mem_AllocPool("texture management", 0, NULL);
681 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
683 // Disable JPEG screenshots if the DLL isn't loaded
684 if (! JPEG_OpenLibrary ())
685 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
686 if (! PNG_OpenLibrary ())
687 Cvar_SetValueQuick (&scr_screenshot_png, 0);
690 static void r_textures_shutdown(void)
692 rtexturepool_t *temp;
694 JPEG_CloseLibrary ();
696 while(gltexturepoolchain)
698 temp = (rtexturepool_t *) gltexturepoolchain;
699 R_FreeTexturePool(&temp);
702 resizebuffersize = 0;
704 colorconvertbuffer = NULL;
705 texturebuffer = NULL;
706 Mem_ExpandableArray_FreeArray(&texturearray);
707 Mem_FreePool(&texturemempool);
710 static void r_textures_newmap(void)
714 static void r_textures_devicelost(void)
718 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
719 for (i = 0;i < endindex;i++)
721 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
722 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
724 switch(vid.renderpath)
726 case RENDERPATH_GL11:
727 case RENDERPATH_GL13:
728 case RENDERPATH_GL20:
729 case RENDERPATH_CGGL:
731 case RENDERPATH_D3D9:
733 if (glt->tiledepth > 1)
734 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
735 else if (glt->sides == 6)
736 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
738 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
739 glt->d3dtexture = NULL;
742 case RENDERPATH_D3D10:
743 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
745 case RENDERPATH_D3D11:
746 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
752 static void r_textures_devicerestored(void)
756 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
757 for (i = 0;i < endindex;i++)
759 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
760 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
762 switch(vid.renderpath)
764 case RENDERPATH_GL11:
765 case RENDERPATH_GL13:
766 case RENDERPATH_GL20:
767 case RENDERPATH_CGGL:
769 case RENDERPATH_D3D9:
773 if (glt->tiledepth > 1)
775 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)))
776 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
778 else if (glt->sides == 6)
780 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
781 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
785 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)))
786 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
791 case RENDERPATH_D3D10:
792 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
794 case RENDERPATH_D3D11:
795 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
802 void R_Textures_Init (void)
804 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");
805 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
806 Cvar_RegisterVariable (&gl_max_size);
807 Cvar_RegisterVariable (&gl_picmip);
808 Cvar_RegisterVariable (&gl_picmip_world);
809 Cvar_RegisterVariable (&r_picmipworld);
810 Cvar_RegisterVariable (&gl_picmip_sprites);
811 Cvar_RegisterVariable (&r_picmipsprites);
812 Cvar_RegisterVariable (&gl_picmip_other);
813 Cvar_RegisterVariable (&gl_max_lightmapsize);
814 Cvar_RegisterVariable (&r_lerpimages);
815 Cvar_RegisterVariable (&gl_texture_anisotropy);
816 Cvar_RegisterVariable (&gl_texturecompression);
817 Cvar_RegisterVariable (&gl_texturecompression_color);
818 Cvar_RegisterVariable (&gl_texturecompression_normal);
819 Cvar_RegisterVariable (&gl_texturecompression_gloss);
820 Cvar_RegisterVariable (&gl_texturecompression_glow);
821 Cvar_RegisterVariable (&gl_texturecompression_2d);
822 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
823 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
824 Cvar_RegisterVariable (&gl_texturecompression_sky);
825 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
826 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
827 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
828 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
830 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
833 void R_Textures_Frame (void)
835 static int old_aniso = 0;
837 // could do procedural texture animation here, if we keep track of which
838 // textures were accessed this frame...
840 // free the resize buffers
841 resizebuffersize = 0;
844 Mem_Free(resizebuffer);
847 if (colorconvertbuffer)
849 Mem_Free(colorconvertbuffer);
850 colorconvertbuffer = NULL;
853 if (old_aniso != gl_texture_anisotropy.integer)
856 gltexturepool_t *pool;
859 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
861 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
863 switch(vid.renderpath)
865 case RENDERPATH_GL11:
866 case RENDERPATH_GL13:
867 case RENDERPATH_GL20:
868 case RENDERPATH_CGGL:
871 for (pool = gltexturepoolchain;pool;pool = pool->next)
873 for (glt = pool->gltchain;glt;glt = glt->chain)
875 // only update already uploaded images
876 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
878 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
880 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
881 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
883 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
888 case RENDERPATH_D3D9:
889 case RENDERPATH_D3D10:
890 case RENDERPATH_D3D11:
896 void R_MakeResizeBufferBigger(int size)
898 if (resizebuffersize < size)
900 resizebuffersize = size;
902 Mem_Free(resizebuffer);
903 if (colorconvertbuffer)
904 Mem_Free(colorconvertbuffer);
905 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
906 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
907 if (!resizebuffer || !colorconvertbuffer)
908 Host_Error("R_Upload: out of memory");
912 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
914 int textureenum = gltexturetypeenums[texturetype];
915 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
919 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
921 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
922 if (gl_texture_anisotropy.integer != aniso)
923 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
924 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
926 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
927 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
928 if (gltexturetypedimensions[texturetype] >= 3)
930 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
934 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
936 if (flags & TEXF_MIPMAP)
938 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
942 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
944 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
946 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
948 if (flags & TEXF_MIPMAP)
950 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
952 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
956 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
961 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
963 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
967 if (flags & TEXF_MIPMAP)
969 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
973 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
975 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
978 if (textype == TEXTYPE_SHADOWMAP)
980 if (vid.support.arb_shadow)
982 if (flags & TEXF_COMPARE)
984 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
988 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
990 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
992 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
998 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1001 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1003 if (glt->texturetype != GLTEXTURETYPE_2D)
1004 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1006 if (glt->textype->textype == TEXTYPE_PALETTE)
1007 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1009 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1010 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1012 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1013 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1015 // update a portion of the image
1017 switch(vid.renderpath)
1019 case RENDERPATH_GL11:
1020 case RENDERPATH_GL13:
1021 case RENDERPATH_GL20:
1022 case RENDERPATH_CGGL:
1026 // we need to restore the texture binding after finishing the upload
1027 GL_ActiveTexture(0);
1028 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1029 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1030 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1031 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1034 case RENDERPATH_D3D9:
1038 D3DLOCKED_RECT d3dlockedrect;
1040 memset(&d3drect, 0, sizeof(d3drect));
1041 d3drect.left = fragx;
1042 d3drect.top = fragy;
1043 d3drect.right = fragx+fragwidth;
1044 d3drect.bottom = fragy+fragheight;
1045 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1047 for (y = 0;y < fragheight;y++)
1048 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1049 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1054 case RENDERPATH_D3D10:
1055 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1057 case RENDERPATH_D3D11:
1058 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1063 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1065 int i, mip = 0, width, height, depth;
1066 GLint oldbindtexnum = 0;
1067 const unsigned char *prevbuffer;
1070 // error out if a stretch is needed on special texture types
1071 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1072 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1074 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1075 // of the target size and then use the mipmap reduction function to get
1076 // high quality supersampled results
1077 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1078 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1079 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1080 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1082 if (prevbuffer == NULL)
1084 width = glt->tilewidth;
1085 height = glt->tileheight;
1086 depth = glt->tiledepth;
1087 memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1088 prevbuffer = resizebuffer;
1090 else if (glt->textype->textype == TEXTYPE_PALETTE)
1092 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1093 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1094 prevbuffer = colorconvertbuffer;
1097 // scale up to a power of 2 size (if appropriate)
1098 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1100 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1101 prevbuffer = resizebuffer;
1103 // apply mipmap reduction algorithm to get down to picmip/max_size
1104 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1106 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1107 prevbuffer = resizebuffer;
1110 // do the appropriate upload type...
1111 switch(vid.renderpath)
1113 case RENDERPATH_GL11:
1114 case RENDERPATH_GL13:
1115 case RENDERPATH_GL20:
1116 case RENDERPATH_CGGL:
1119 // we need to restore the texture binding after finishing the upload
1120 GL_ActiveTexture(0);
1121 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1122 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1124 if (qglGetCompressedTexImageARB)
1126 if (gl_texturecompression.integer >= 2)
1127 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1129 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1132 switch(glt->texturetype)
1134 case GLTEXTURETYPE_2D:
1135 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1136 if (glt->flags & TEXF_MIPMAP)
1138 while (width > 1 || height > 1 || depth > 1)
1140 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1141 prevbuffer = resizebuffer;
1142 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1146 case GLTEXTURETYPE_3D:
1147 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1148 if (glt->flags & TEXF_MIPMAP)
1150 while (width > 1 || height > 1 || depth > 1)
1152 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1153 prevbuffer = resizebuffer;
1154 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1158 case GLTEXTURETYPE_CUBEMAP:
1159 // convert and upload each side in turn,
1160 // from a continuous block of input texels
1161 texturebuffer = (unsigned char *)prevbuffer;
1162 for (i = 0;i < 6;i++)
1164 prevbuffer = texturebuffer;
1165 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1166 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1168 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1169 prevbuffer = resizebuffer;
1172 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1174 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1175 prevbuffer = resizebuffer;
1178 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1179 if (glt->flags & TEXF_MIPMAP)
1181 while (width > 1 || height > 1 || depth > 1)
1183 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1184 prevbuffer = resizebuffer;
1185 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1190 case GLTEXTURETYPE_RECTANGLE:
1191 qglTexImage2D(GL_TEXTURE_RECTANGLE_ARB, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, NULL);CHECKGLERROR
1194 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1195 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1197 case RENDERPATH_D3D9:
1199 if (!(glt->flags & TEXF_RENDERTARGET))
1201 D3DLOCKED_RECT d3dlockedrect;
1202 D3DLOCKED_BOX d3dlockedbox;
1203 switch(glt->texturetype)
1205 case GLTEXTURETYPE_2D:
1206 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1209 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1211 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1212 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1215 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1217 while (width > 1 || height > 1 || depth > 1)
1219 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1220 prevbuffer = resizebuffer;
1221 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1223 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1224 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1230 case GLTEXTURETYPE_3D:
1231 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1233 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1234 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1235 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1238 if (glt->flags & TEXF_MIPMAP)
1240 while (width > 1 || height > 1 || depth > 1)
1242 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1243 prevbuffer = resizebuffer;
1244 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1246 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1247 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1248 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1254 case GLTEXTURETYPE_CUBEMAP:
1255 // convert and upload each side in turn,
1256 // from a continuous block of input texels
1257 texturebuffer = (unsigned char *)prevbuffer;
1258 for (i = 0;i < 6;i++)
1260 prevbuffer = texturebuffer;
1261 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1262 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1264 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1265 prevbuffer = resizebuffer;
1268 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1270 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1271 prevbuffer = resizebuffer;
1274 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1276 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1277 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1280 if (glt->flags & TEXF_MIPMAP)
1282 while (width > 1 || height > 1 || depth > 1)
1284 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1285 prevbuffer = resizebuffer;
1286 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1288 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1289 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1296 case GLTEXTURETYPE_RECTANGLE:
1297 Sys_Error("Direct3D does not have RECTANGLE textures\n");
1301 glt->d3daddressw = 0;
1302 if (glt->flags & TEXF_CLAMP)
1304 glt->d3daddressu = D3DTADDRESS_CLAMP;
1305 glt->d3daddressv = D3DTADDRESS_CLAMP;
1306 if (glt->tiledepth > 1)
1307 glt->d3daddressw = D3DTADDRESS_CLAMP;
1311 glt->d3daddressu = D3DTADDRESS_WRAP;
1312 glt->d3daddressv = D3DTADDRESS_WRAP;
1313 if (glt->tiledepth > 1)
1314 glt->d3daddressw = D3DTADDRESS_WRAP;
1316 glt->d3dmipmaplodbias = 0;
1317 glt->d3dmaxmiplevel = 0;
1318 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1319 if (glt->flags & TEXF_FORCELINEAR)
1321 glt->d3dminfilter = D3DTEXF_LINEAR;
1322 glt->d3dmagfilter = D3DTEXF_LINEAR;
1323 glt->d3dmipfilter = D3DTEXF_POINT;
1325 else if (glt->flags & TEXF_FORCENEAREST)
1327 glt->d3dminfilter = D3DTEXF_POINT;
1328 glt->d3dmagfilter = D3DTEXF_POINT;
1329 glt->d3dmipfilter = D3DTEXF_POINT;
1331 else if (glt->flags & TEXF_MIPMAP)
1333 glt->d3dminfilter = d3d_filter_mipmin;
1334 glt->d3dmagfilter = d3d_filter_mipmag;
1335 glt->d3dmipfilter = d3d_filter_mipmix;
1339 glt->d3dminfilter = d3d_filter_flatmin;
1340 glt->d3dmagfilter = d3d_filter_flatmag;
1341 glt->d3dmipfilter = d3d_filter_flatmix;
1345 case RENDERPATH_D3D10:
1346 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1348 case RENDERPATH_D3D11:
1349 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1354 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)
1358 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1359 textypeinfo_t *texinfo, *texinfo2;
1360 unsigned char *temppixels = NULL;
1362 if (cls.state == ca_dedicated)
1365 if (texturetype == GLTEXTURETYPE_RECTANGLE && !vid.support.arb_texture_rectangle)
1367 Con_Printf ("R_LoadTexture: rectangle texture not supported by driver\n");
1370 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1372 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1375 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1377 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1381 texinfo = R_GetTexTypeInfo(textype, flags);
1382 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1385 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1389 if (textype == TEXTYPE_RGBA)
1392 static int rgbaswapindices[4] = {2, 1, 0, 3};
1393 textype = TEXTYPE_BGRA;
1394 texinfo = R_GetTexTypeInfo(textype, flags);
1395 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1396 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1400 // clear the alpha flag if the texture has no transparent pixels
1403 case TEXTYPE_PALETTE:
1404 if (flags & TEXF_ALPHA)
1406 flags &= ~TEXF_ALPHA;
1409 for (i = 0;i < size;i++)
1411 if (((unsigned char *)&palette[data[i]])[3] < 255)
1413 flags |= TEXF_ALPHA;
1422 if (flags & TEXF_ALPHA)
1424 flags &= ~TEXF_ALPHA;
1427 for (i = 3;i < size;i += 4)
1431 flags |= TEXF_ALPHA;
1438 case TEXTYPE_SHADOWMAP:
1445 flags |= TEXF_ALPHA;
1448 flags |= TEXF_ALPHA;
1450 case TEXTYPE_COLORBUFFER:
1451 flags |= TEXF_ALPHA;
1454 Sys_Error("R_LoadTexture: unknown texture type");
1457 texinfo2 = R_GetTexTypeInfo(textype, flags);
1458 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1461 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1463 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1465 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1467 glt->chain = pool->gltchain;
1468 pool->gltchain = glt;
1469 glt->inputwidth = width;
1470 glt->inputheight = height;
1471 glt->inputdepth = depth;
1473 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
1474 glt->textype = texinfo;
1475 glt->texturetype = texturetype;
1476 glt->inputdatasize = size;
1477 glt->palette = palette;
1478 glt->glinternalformat = texinfo->glinternalformat;
1479 glt->glformat = texinfo->glformat;
1480 glt->gltype = texinfo->gltype;
1481 glt->bytesperpixel = texinfo->internalbytesperpixel;
1482 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1485 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1486 // init the dynamic texture attributes, too [11/22/2007 Black]
1487 glt->updatecallback = NULL;
1488 glt->updatacallback_data = NULL;
1490 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1492 // upload the texture
1493 // data may be NULL (blank texture for dynamic rendering)
1494 switch(vid.renderpath)
1496 case RENDERPATH_GL11:
1497 case RENDERPATH_GL13:
1498 case RENDERPATH_GL20:
1499 case RENDERPATH_CGGL:
1501 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1503 case RENDERPATH_D3D9:
1506 D3DFORMAT d3dformat;
1511 d3dpool = D3DPOOL_MANAGED;
1512 if (flags & TEXF_RENDERTARGET)
1514 d3dusage |= D3DUSAGE_RENDERTARGET;
1515 d3dpool = D3DPOOL_DEFAULT;
1519 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1520 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1521 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1522 case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1523 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1524 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1525 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1527 glt->d3dformat = d3dformat;
1528 glt->d3dusage = d3dusage;
1529 glt->d3dpool = d3dpool;
1530 if (glt->tiledepth > 1)
1532 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)))
1533 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1535 else if (glt->sides == 6)
1537 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1538 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1542 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)))
1543 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1548 case RENDERPATH_D3D10:
1549 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1551 case RENDERPATH_D3D11:
1552 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1556 R_UploadFullTexture(glt, data);
1557 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1558 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1560 // free any temporary processing buffer we allocated...
1562 Mem_Free(temppixels);
1564 // texture converting and uploading can take a while, so make sure we're sending keepalives
1565 // FIXME: this causes rendering during R_Shadow_DrawLights
1566 // CL_KeepaliveMessage(false);
1568 return (rtexture_t *)glt;
1571 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)
1573 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1576 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)
1578 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1581 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)
1583 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1586 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)
1588 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_RECTANGLE, data, palette);
1591 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1593 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1595 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1597 flags |= TEXF_FORCENEAREST;
1598 if (precision <= 16)
1599 flags |= TEXF_LOWPRECISION;
1603 rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1605 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
1608 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1610 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1613 rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter)
1615 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
1618 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1620 gltexture_t *glt = (gltexture_t *)rt;
1623 int bytesperpixel = 0;
1624 int bytesperblock = 0;
1626 int dds_format_flags;
1634 GLint internalformat;
1635 const char *ddsfourcc;
1637 return -1; // NULL pointer
1638 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1639 return -2; // broken driver - crashes on reading internal format
1640 if (!qglGetTexLevelParameteriv)
1642 GL_ActiveTexture(0);
1643 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1644 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1645 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1646 switch(internalformat)
1648 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1649 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1650 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1651 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1652 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1654 if (!bytesperblock && skipuncompressed)
1655 return -3; // skipped
1656 memset(mipinfo, 0, sizeof(mipinfo));
1657 mipinfo[0][0] = glt->tilewidth;
1658 mipinfo[0][1] = glt->tileheight;
1660 if (glt->flags & TEXF_MIPMAP)
1662 for (mip = 1;mip < 16;mip++)
1664 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1665 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1666 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1674 for (mip = 0;mip < mipmaps;mip++)
1676 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1677 mipinfo[mip][3] = ddssize;
1678 ddssize += mipinfo[mip][2];
1680 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1683 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1687 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1688 dds_format_flags = 0x4; // DDPF_FOURCC
1692 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1693 dds_format_flags = 0x40; // DDPF_RGB
1697 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1698 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1701 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1702 memcpy(dds, "DDS ", 4);
1703 StoreLittleLong(dds+4, ddssize);
1704 StoreLittleLong(dds+8, dds_flags);
1705 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1706 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1707 StoreLittleLong(dds+24, 1); // depth
1708 StoreLittleLong(dds+28, mipmaps); // mipmaps
1709 StoreLittleLong(dds+76, 32); // format size
1710 StoreLittleLong(dds+80, dds_format_flags);
1711 StoreLittleLong(dds+108, dds_caps1);
1712 StoreLittleLong(dds+112, dds_caps2);
1715 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1716 memcpy(dds+84, ddsfourcc, 4);
1717 for (mip = 0;mip < mipmaps;mip++)
1719 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1724 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1725 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1726 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1727 for (mip = 0;mip < mipmaps;mip++)
1729 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1732 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1733 ret = FS_WriteFile(filename, dds, ddssize);
1735 return ret ? ddssize : -5;
1738 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
1740 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1743 int bytesperblock, bytesperpixel;
1746 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1747 textypeinfo_t *texinfo;
1748 int mip, mipwidth, mipheight, mipsize;
1750 GLint oldbindtexnum = 0;
1751 const unsigned char *mippixels, *ddspixels;
1753 fs_offset_t ddsfilesize;
1754 unsigned int ddssize;
1756 if (cls.state == ca_dedicated)
1759 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1760 ddssize = ddsfilesize;
1764 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1765 return NULL; // not found
1768 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1771 Con_Printf("^1%s: not a DDS image\n", filename);
1775 //dds_flags = BuffLittleLong(dds+8);
1776 dds_format_flags = BuffLittleLong(dds+80);
1777 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1778 dds_width = BuffLittleLong(dds+16);
1779 dds_height = BuffLittleLong(dds+12);
1780 ddspixels = dds + 128;
1782 if(r_texture_dds_load_alphamode.integer == 0)
1783 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1784 flags &= ~TEXF_ALPHA;
1786 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1787 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1789 // very sloppy BGRA 32bit identification
1790 textype = TEXTYPE_BGRA;
1793 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1794 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1797 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1800 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1803 for (i = 3;i < size;i += 4)
1804 if (ddspixels[i] < 255)
1807 flags &= ~TEXF_ALPHA;
1810 else if (!memcmp(dds+84, "DXT1", 4))
1812 if(!vid.support.ext_texture_compression_s3tc)
1817 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1818 // LordHavoc: it is my belief that this does not infringe on the
1819 // patent because it is not decoding pixels...
1820 textype = TEXTYPE_DXT1;
1823 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1824 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1825 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1828 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1831 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1833 if(r_texture_dds_load_alphamode.integer == 1)
1836 for (i = 0;i < size;i += bytesperblock)
1837 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1839 // NOTE: this assumes sizeof(unsigned int) == 4
1840 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1841 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1842 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1846 textype = TEXTYPE_DXT1A;
1848 flags &= ~TEXF_ALPHA;
1852 flags &= ~TEXF_ALPHA;
1856 else if (!memcmp(dds+84, "DXT3", 4))
1858 if(!vid.support.ext_texture_compression_s3tc)
1863 textype = TEXTYPE_DXT3;
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 DXT3 DDS image\n", filename);
1873 // we currently always assume alpha
1875 else if (!memcmp(dds+84, "DXT5", 4))
1877 if(!vid.support.ext_texture_compression_s3tc)
1882 textype = TEXTYPE_DXT5;
1885 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1886 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1889 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1892 // we currently always assume alpha
1897 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1901 // return whether this texture is transparent
1903 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1905 // calculate average color if requested
1909 Vector4Clear(avgcolor);
1912 for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
1914 c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
1915 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1916 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
1917 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
1919 f = (float)bytesperblock / size;
1920 avgcolor[0] *= (0.5f / 31.0f) * f;
1921 avgcolor[1] *= (0.5f / 63.0f) * f;
1922 avgcolor[2] *= (0.5f / 31.0f) * f;
1923 avgcolor[3] = 1; // too hard to calculate
1927 for (i = 0;i < size;i += 4)
1929 avgcolor[0] += ddspixels[i+2];
1930 avgcolor[1] += ddspixels[i+1];
1931 avgcolor[2] += ddspixels[i];
1932 avgcolor[3] += ddspixels[i+3];
1934 f = (1.0f / 255.0f) * bytesperpixel / size;
1942 // this is where we apply gl_picmip
1943 mippixels = ddspixels;
1944 mipwidth = dds_width;
1945 mipheight = dds_height;
1946 while(miplevel >= 1 && dds_miplevels >= 1)
1948 if (mipwidth <= 1 && mipheight <= 1)
1950 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1951 mippixels += mipsize; // just skip
1960 // when not requesting mipmaps, do not load them
1961 if(!(flags & TEXF_MIPMAP))
1964 if (dds_miplevels >= 1)
1965 flags |= TEXF_MIPMAP;
1967 flags &= ~TEXF_MIPMAP;
1969 // if S3TC is not supported, there's very little we can do about it
1970 if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
1973 Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
1977 texinfo = R_GetTexTypeInfo(textype, flags);
1979 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1980 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
1982 glt->chain = pool->gltchain;
1983 pool->gltchain = glt;
1984 glt->inputwidth = mipwidth;
1985 glt->inputheight = mipheight;
1986 glt->inputdepth = 1;
1988 glt->textype = texinfo;
1989 glt->texturetype = GLTEXTURETYPE_2D;
1990 glt->inputdatasize = ddssize;
1991 glt->glinternalformat = texinfo->glinternalformat;
1992 glt->glformat = texinfo->glformat;
1993 glt->gltype = texinfo->gltype;
1994 glt->bytesperpixel = texinfo->internalbytesperpixel;
1996 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1997 glt->tilewidth = mipwidth;
1998 glt->tileheight = mipheight;
2000 glt->miplevels = dds_miplevels;
2002 // texture uploading can take a while, so make sure we're sending keepalives
2003 CL_KeepaliveMessage(false);
2005 // create the texture object
2006 switch(vid.renderpath)
2008 case RENDERPATH_GL11:
2009 case RENDERPATH_GL13:
2010 case RENDERPATH_GL20:
2011 case RENDERPATH_CGGL:
2013 GL_ActiveTexture(0);
2014 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2015 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2016 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2018 case RENDERPATH_D3D9:
2021 D3DFORMAT d3dformat;
2026 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2027 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2028 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2029 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2030 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2033 d3dpool = D3DPOOL_MANAGED;
2034 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2038 case RENDERPATH_D3D10:
2039 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2041 case RENDERPATH_D3D11:
2042 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2046 // upload the texture
2047 // we need to restore the texture binding after finishing the upload
2048 mipcomplete = false;
2050 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2052 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2053 if (mippixels + mipsize > dds + ddssize)
2055 switch(vid.renderpath)
2057 case RENDERPATH_GL11:
2058 case RENDERPATH_GL13:
2059 case RENDERPATH_GL20:
2060 case RENDERPATH_CGGL:
2063 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2067 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2070 case RENDERPATH_D3D9:
2073 D3DLOCKED_RECT d3dlockedrect;
2074 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2076 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2077 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2083 case RENDERPATH_D3D10:
2084 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2086 case RENDERPATH_D3D11:
2087 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2090 mippixels += mipsize;
2091 if (mipwidth <= 1 && mipheight <= 1)
2102 // after upload we have to set some parameters...
2103 switch(vid.renderpath)
2105 case RENDERPATH_GL11:
2106 case RENDERPATH_GL13:
2107 case RENDERPATH_GL20:
2108 case RENDERPATH_CGGL:
2109 if (dds_miplevels >= 1 && !mipcomplete)
2111 // need to set GL_TEXTURE_MAX_LEVEL
2112 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2114 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2115 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2117 case RENDERPATH_D3D9:
2119 glt->d3daddressw = 0;
2120 if (glt->flags & TEXF_CLAMP)
2122 glt->d3daddressu = D3DTADDRESS_CLAMP;
2123 glt->d3daddressv = D3DTADDRESS_CLAMP;
2124 if (glt->tiledepth > 1)
2125 glt->d3daddressw = D3DTADDRESS_CLAMP;
2129 glt->d3daddressu = D3DTADDRESS_WRAP;
2130 glt->d3daddressv = D3DTADDRESS_WRAP;
2131 if (glt->tiledepth > 1)
2132 glt->d3daddressw = D3DTADDRESS_WRAP;
2134 glt->d3dmipmaplodbias = 0;
2135 glt->d3dmaxmiplevel = 0;
2136 glt->d3dmaxmiplevelfilter = 0;
2137 if (glt->flags & TEXF_MIPMAP)
2139 glt->d3dminfilter = d3d_filter_mipmin;
2140 glt->d3dmagfilter = d3d_filter_mipmag;
2141 glt->d3dmipfilter = d3d_filter_mipmix;
2145 glt->d3dminfilter = d3d_filter_flatmin;
2146 glt->d3dmagfilter = d3d_filter_flatmag;
2147 glt->d3dmipfilter = d3d_filter_flatmix;
2151 case RENDERPATH_D3D10:
2152 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2154 case RENDERPATH_D3D11:
2155 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2160 return (rtexture_t *)glt;
2163 int R_TextureWidth(rtexture_t *rt)
2165 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2168 int R_TextureHeight(rtexture_t *rt)
2170 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2173 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
2175 gltexture_t *glt = (gltexture_t *)rt;
2177 Host_Error("R_UpdateTexture: no data supplied");
2179 Host_Error("R_UpdateTexture: no texture supplied");
2180 if (!glt->texnum && !glt->d3dtexture)
2182 Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", (void *)glt, glt->identifier, (void *)glt->pool);
2185 // update part of the texture
2186 if (glt->bufferpixels)
2189 int bpp = glt->bytesperpixel;
2190 int inputskip = width*bpp;
2191 int outputskip = glt->tilewidth*bpp;
2192 const unsigned char *input = data;
2193 unsigned char *output = glt->bufferpixels;
2203 input -= y*inputskip;
2206 if (width > glt->tilewidth - x)
2207 width = glt->tilewidth - x;
2208 if (height > glt->tileheight - y)
2209 height = glt->tileheight - y;
2210 if (width < 1 || height < 1)
2213 glt->buffermodified = true;
2214 output += y*outputskip + x*bpp;
2215 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2216 memcpy(output, input, width*bpp);
2218 else if (x || y || width != glt->inputwidth || height != glt->inputheight)
2219 R_UploadPartialTexture(glt, data, x, y, 0, width, height, 1);
2221 R_UploadFullTexture(glt, data);
2224 int R_RealGetTexture(rtexture_t *rt)
2229 glt = (gltexture_t *)rt;
2230 if (glt->flags & GLTEXF_DYNAMIC)
2231 R_UpdateDynamicTexture(glt);
2232 if (glt->buffermodified && glt->bufferpixels)
2234 glt->buffermodified = false;
2235 R_UploadFullTexture(glt, glt->bufferpixels);
2244 void R_ClearTexture (rtexture_t *rt)
2246 gltexture_t *glt = (gltexture_t *)rt;
2248 R_UploadFullTexture(glt, NULL);
2251 int R_PicmipForFlags(int flags)
2254 if(flags & TEXF_PICMIP)
2256 miplevel += gl_picmip.integer;
2257 if (flags & TEXF_ISWORLD)
2259 if (r_picmipworld.integer)
2260 miplevel += gl_picmip_world.integer;
2264 else if (flags & TEXF_ISSPRITE)
2266 if (r_picmipsprites.integer)
2267 miplevel += gl_picmip_sprites.integer;
2272 miplevel += gl_picmip_other.integer;
2274 return max(0, miplevel);