5 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
10 #include "intoverflow.h"
12 cvar_t gl_max_size = {CVAR_SAVE, "gl_max_size", "2048", "maximum allowed texture size, can be used to reduce video memory usage, limited by hardware capabilities (typically 2048, 4096, or 8192)"};
13 cvar_t gl_max_lightmapsize = {CVAR_SAVE, "gl_max_lightmapsize", "1024", "maximum allowed texture size for lightmap textures, use larger values to improve rendering speed, as long as there is enough video memory available (setting it too high for the hardware will cause very bad performance)"};
14 cvar_t gl_picmip = {CVAR_SAVE, "gl_picmip", "0", "reduces resolution of textures by powers of 2, for example 1 will halve width/height, reducing texture memory usage by 75%"};
15 cvar_t gl_picmip_world = {CVAR_SAVE, "gl_picmip_world", "0", "extra picmip level for world textures (may be negative, which will then reduce gl_picmip for these)"};
16 cvar_t r_picmipworld = {CVAR_SAVE, "r_picmipworld", "1", "whether gl_picmip shall apply to world textures too (setting this to 0 is a shorthand for gl_picmip_world -9999999)"};
17 cvar_t gl_picmip_sprites = {CVAR_SAVE, "gl_picmip_sprites", "0", "extra picmip level for sprite textures (may be negative, which will then reduce gl_picmip for these)"};
18 cvar_t r_picmipsprites = {CVAR_SAVE, "r_picmipsprites", "1", "make gl_picmip affect sprites too (saves some graphics memory in sprite heavy games) (setting this to 0 is a shorthand for gl_picmip_sprites -9999999)"};
19 cvar_t gl_picmip_other = {CVAR_SAVE, "gl_picmip_other", "0", "extra picmip level for other textures (may be negative, which will then reduce gl_picmip for these)"};
20 cvar_t r_lerpimages = {CVAR_SAVE, "r_lerpimages", "1", "bilinear filters images when scaling them up to power of 2 size (mode 1), looks better than glquake (mode 0)"};
21 cvar_t gl_texture_anisotropy = {CVAR_SAVE, "gl_texture_anisotropy", "1", "anisotropic filtering quality (if supported by hardware), 1 sample (no anisotropy) and 8 sample (8 tap anisotropy) are recommended values"};
22 cvar_t gl_texturecompression = {CVAR_SAVE, "gl_texturecompression", "0", "whether to compress textures, a value of 0 disables compression (even if the individual cvars are 1), 1 enables fast (low quality) compression at startup, 2 enables slow (high quality) compression at startup"};
23 cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
24 cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
25 cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
26 cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
27 cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
28 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
29 cvar_t gl_texturecompression_q3bspdeluxemaps = {CVAR_SAVE, "gl_texturecompression_q3bspdeluxemaps", "0", "whether to compress deluxemaps in q3bsp format levels (only levels compiled with q3map2 -deluxe have these)"};
30 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
31 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
32 cvar_t gl_texturecompression_reflectmask = {CVAR_SAVE, "gl_texturecompression_reflectmask", "1", "whether to compress reflection cubemap masks (mask of which areas of the texture should reflect the generic shiny cubemap)"};
33 cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "1", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"};
34 cvar_t r_texture_dds_load_alphamode = {0, "r_texture_dds_load_alphamode", "1", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambigous, 2: texture format only"};
36 qboolean gl_filter_force = false;
37 int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
38 int gl_filter_mag = GL_LINEAR;
41 int d3d_filter_flatmin = D3DTEXF_LINEAR;
42 int d3d_filter_flatmag = D3DTEXF_LINEAR;
43 int d3d_filter_flatmix = D3DTEXF_POINT;
44 int d3d_filter_mipmin = D3DTEXF_LINEAR;
45 int d3d_filter_mipmag = D3DTEXF_LINEAR;
46 int d3d_filter_mipmix = D3DTEXF_LINEAR;
47 int d3d_filter_nomip = false;
51 static mempool_t *texturemempool;
52 static memexpandablearray_t texturearray;
54 // note: this must not conflict with TEXF_ flags in r_textures.h
55 // bitmask for mismatch checking
56 #define GLTEXF_IMPORTANTBITS (0)
57 // dynamic texture (treat texnum == 0 differently)
58 #define GLTEXF_DYNAMIC 0x00080000
60 typedef struct textypeinfo_s
63 int inputbytesperpixel;
64 int internalbytesperpixel;
65 float glinternalbytesperpixel;
73 static textypeinfo_t textype_palette = {TEXTYPE_PALETTE , 1, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE };
74 static textypeinfo_t textype_palette_alpha = {TEXTYPE_PALETTE , 1, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
75 static textypeinfo_t textype_rgba = {TEXTYPE_RGBA , 4, 4, 4.0f, 3 , GL_RGBA , GL_UNSIGNED_BYTE };
76 static textypeinfo_t textype_rgba_alpha = {TEXTYPE_RGBA , 4, 4, 4.0f, 4 , GL_RGBA , GL_UNSIGNED_BYTE };
77 static textypeinfo_t textype_rgba_compress = {TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
78 static textypeinfo_t textype_rgba_alpha_compress = {TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA , GL_UNSIGNED_BYTE };
79 static textypeinfo_t textype_bgra = {TEXTYPE_BGRA , 4, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE };
80 static textypeinfo_t textype_bgra_alpha = {TEXTYPE_BGRA , 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
81 static textypeinfo_t textype_bgra_compress = {TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
82 static textypeinfo_t textype_bgra_alpha_compress = {TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_BGRA , GL_UNSIGNED_BYTE };
83 static textypeinfo_t textype_shadowmap16 = {TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
84 static textypeinfo_t textype_shadowmap24 = {TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
85 static textypeinfo_t textype_alpha = {TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
86 static textypeinfo_t textype_dxt1 = {TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
87 static textypeinfo_t textype_dxt1a = {TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0 , 0 };
88 static textypeinfo_t textype_dxt3 = {TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0 , 0 };
89 static textypeinfo_t textype_dxt5 = {TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0 , 0 };
90 static textypeinfo_t textype_colorbuffer = {TEXTYPE_COLORBUFFER, 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
93 typedef enum gltexturetype_e
97 GLTEXTURETYPE_CUBEMAP,
98 GLTEXTURETYPE_RECTANGLE,
103 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_RECTANGLE_ARB};
104 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2, 2};
105 static int cubemapside[6] =
107 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
108 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
109 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
110 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
111 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
112 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
115 typedef struct gltexture_s
117 // this portion of the struct is exposed to the R_GetTexture macro for
118 // speed reasons, must be identical in rtexture_t!
119 int texnum; // GL texture slot number
120 qboolean dirty; // indicates that R_RealGetTexture should be called
121 int gltexturetypeenum; // used by R_Mesh_TexBind
122 // d3d stuff the backend needs
134 int d3dmaxmiplevelfilter;
135 int d3dmipmaplodbias;
139 // dynamic texture stuff [11/22/2007 Black]
140 updatecallback_t updatecallback;
141 void *updatacallback_data;
142 // --- [11/22/2007 Black]
144 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
145 unsigned char *bufferpixels;
146 qboolean buffermodified;
148 // pointer to texturepool (check this to see if the texture is allocated)
149 struct gltexturepool_s *pool;
150 // pointer to next texture in texturepool chain
151 struct gltexture_s *chain;
152 // name of the texture (this might be removed someday), no duplicates
153 char identifier[MAX_QPATH + 32];
154 // original data size in *inputtexels
155 int inputwidth, inputheight, inputdepth;
156 // copy of the original texture(s) supplied to the upload function, for
157 // delayed uploads (non-precached)
158 unsigned char *inputtexels;
159 // original data size in *inputtexels
161 // flags supplied to the LoadTexture function
162 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
166 // pointer to one of the textype_ structs
167 textypeinfo_t *textype;
168 // one of the GLTEXTURETYPE_ values
170 // palette if the texture is TEXTYPE_PALETTE
171 const unsigned int *palette;
172 // actual stored texture size after gl_picmip and gl_max_size are applied
173 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
174 int tilewidth, tileheight, tiledepth;
175 // 1 or 6 depending on texturetype
177 // how many mipmap levels in this texture
181 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
184 int glinternalformat;
185 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
190 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
192 typedef struct gltexturepool_s
194 unsigned int sentinel;
195 struct gltexture_s *gltchain;
196 struct gltexturepool_s *next;
200 static gltexturepool_t *gltexturepoolchain = NULL;
202 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
203 static int resizebuffersize = 0;
204 static const unsigned char *texturebuffer;
206 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
211 return &textype_dxt1;
213 return &textype_dxt1a;
215 return &textype_dxt3;
217 return &textype_dxt5;
218 case TEXTYPE_PALETTE:
219 return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
221 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
222 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress;
223 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba;
225 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
226 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress;
227 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra;
229 return &textype_alpha;
230 case TEXTYPE_SHADOWMAP:
231 return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
232 case TEXTYPE_COLORBUFFER:
233 return &textype_colorbuffer;
235 Host_Error("R_GetTexTypeInfo: unknown texture format");
241 // dynamic texture code [11/22/2007 Black]
242 void R_MarkDirtyTexture(rtexture_t *rt) {
243 gltexture_t *glt = (gltexture_t*) rt;
248 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
249 if (glt->flags & GLTEXF_DYNAMIC)
251 // mark it as dirty, so R_RealGetTexture gets called
256 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
257 gltexture_t *glt = (gltexture_t*) rt;
262 glt->flags |= GLTEXF_DYNAMIC;
263 glt->updatecallback = updatecallback;
264 glt->updatacallback_data = data;
267 static void R_UpdateDynamicTexture(gltexture_t *glt) {
269 if( glt->updatecallback ) {
270 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
274 void R_PurgeTexture(rtexture_t *rt)
276 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
281 void R_FreeTexture(rtexture_t *rt)
283 gltexture_t *glt, **gltpointer;
285 glt = (gltexture_t *)rt;
287 Host_Error("R_FreeTexture: texture == NULL");
289 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
290 if (*gltpointer == glt)
291 *gltpointer = glt->chain;
293 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
298 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
301 if (glt->inputtexels)
302 Mem_Free(glt->inputtexels);
303 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
306 rtexturepool_t *R_AllocTexturePool(void)
308 gltexturepool_t *pool;
309 if (texturemempool == NULL)
311 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
314 pool->next = gltexturepoolchain;
315 gltexturepoolchain = pool;
316 pool->sentinel = TEXTUREPOOL_SENTINEL;
317 return (rtexturepool_t *)pool;
320 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
322 gltexturepool_t *pool, **poolpointer;
323 if (rtexturepool == NULL)
325 if (*rtexturepool == NULL)
327 pool = (gltexturepool_t *)(*rtexturepool);
328 *rtexturepool = NULL;
329 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
330 Host_Error("R_FreeTexturePool: pool already freed");
331 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
332 if (*poolpointer == pool)
333 *poolpointer = pool->next;
335 Host_Error("R_FreeTexturePool: pool not linked");
336 while (pool->gltchain)
337 R_FreeTexture((rtexture_t *)pool->gltchain);
342 typedef struct glmode_s
345 int minification, magnification;
349 static glmode_t modes[6] =
351 {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
352 {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
353 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
354 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
355 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
356 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
360 typedef struct d3dmode_s
367 static d3dmode_t d3dmodes[6] =
369 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
370 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
371 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
372 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
373 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
374 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
378 static void GL_TextureMode_f (void)
383 gltexturepool_t *pool;
387 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
388 for (i = 0;i < 6;i++)
390 if (gl_filter_min == modes[i].minification)
392 Con_Printf("%s\n", modes[i].name);
396 Con_Print("current filter is unknown???\n");
400 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
401 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
405 Con_Print("bad filter name\n");
409 gl_filter_min = modes[i].minification;
410 gl_filter_mag = modes[i].magnification;
411 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
413 switch(vid.renderpath)
415 case RENDERPATH_GL11:
416 case RENDERPATH_GL13:
417 case RENDERPATH_GL20:
418 case RENDERPATH_CGGL:
419 // change all the existing mipmap texture objects
420 // FIXME: force renderer(/client/something?) restart instead?
423 for (pool = gltexturepoolchain;pool;pool = pool->next)
425 for (glt = pool->gltchain;glt;glt = glt->chain)
427 // only update already uploaded images
428 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
430 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
431 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
432 if (glt->flags & TEXF_MIPMAP)
434 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
438 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
440 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
441 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
446 case RENDERPATH_D3D9:
448 d3d_filter_flatmin = d3dmodes[i].m1;
449 d3d_filter_flatmag = d3dmodes[i].m1;
450 d3d_filter_flatmix = D3DTEXF_POINT;
451 d3d_filter_mipmin = d3dmodes[i].m1;
452 d3d_filter_mipmag = d3dmodes[i].m1;
453 d3d_filter_mipmix = d3dmodes[i].m2;
454 d3d_filter_nomip = i < 2;
455 if (gl_texture_anisotropy.integer > 1 && i == 5)
456 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
457 for (pool = gltexturepoolchain;pool;pool = pool->next)
459 for (glt = pool->gltchain;glt;glt = glt->chain)
461 // only update already uploaded images
462 if (glt->d3dtexture && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
464 if (glt->flags & TEXF_MIPMAP)
466 glt->d3dminfilter = d3d_filter_mipmin;
467 glt->d3dmagfilter = d3d_filter_mipmag;
468 glt->d3dmipfilter = d3d_filter_mipmix;
469 glt->d3dmaxmiplevelfilter = 0;
473 glt->d3dminfilter = d3d_filter_flatmin;
474 glt->d3dmagfilter = d3d_filter_flatmag;
475 glt->d3dmipfilter = d3d_filter_flatmix;
476 glt->d3dmaxmiplevelfilter = 0;
483 case RENDERPATH_D3D10:
484 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
486 case RENDERPATH_D3D11:
487 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
492 static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, int inwidth, int inheight, int indepth, int *outwidth, int *outheight, int *outdepth, int *outmiplevels)
494 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
499 case GLTEXTURETYPE_2D:
500 maxsize = vid.maxtexturesize_2d;
501 if (flags & TEXF_PICMIP)
503 maxsize = bound(1, gl_max_size.integer, maxsize);
507 case GLTEXTURETYPE_3D:
508 maxsize = vid.maxtexturesize_3d;
510 case GLTEXTURETYPE_CUBEMAP:
511 maxsize = vid.maxtexturesize_cubemap;
517 if (vid.support.arb_texture_non_power_of_two)
518 width2 = min(inwidth >> picmip, maxsize);
521 for (width2 = 1;width2 < inwidth;width2 <<= 1);
522 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
524 *outwidth = max(1, width2);
528 if (vid.support.arb_texture_non_power_of_two)
529 height2 = min(inheight >> picmip, maxsize);
532 for (height2 = 1;height2 < inheight;height2 <<= 1);
533 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
535 *outheight = max(1, height2);
539 if (vid.support.arb_texture_non_power_of_two)
540 depth2 = min(indepth >> picmip, maxsize);
543 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
544 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
546 *outdepth = max(1, depth2);
550 if (flags & TEXF_MIPMAP)
552 int extent = max(width2, max(height2, depth2));
557 *outmiplevels = miplevels;
561 static int R_CalcTexelDataSize (gltexture_t *glt)
563 int width2, height2, depth2, size;
565 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
567 size = width2 * height2 * depth2;
569 if (glt->flags & TEXF_MIPMAP)
571 while (width2 > 1 || height2 > 1 || depth2 > 1)
579 size += width2 * height2 * depth2;
583 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
586 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
590 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
591 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
593 gltexturepool_t *pool;
595 Con_Print("glsize input loaded mip alpha name\n");
596 for (pool = gltexturepoolchain;pool;pool = pool->next)
604 for (glt = pool->gltchain;glt;glt = glt->chain)
606 glsize = R_CalcTexelDataSize(glt);
607 isloaded = glt->texnum != 0;
609 pooltotalt += glsize;
610 pooltotalp += glt->inputdatasize;
614 poolloadedt += glsize;
615 poolloadedp += glt->inputdatasize;
618 Con_Printf("%c%4i%c%c%4i%c %s %s %s %s\n", isloaded ? '[' : ' ', (glsize + 1023) / 1024, isloaded ? ']' : ' ', glt->inputtexels ? '[' : ' ', (glt->inputdatasize + 1023) / 1024, glt->inputtexels ? ']' : ' ', isloaded ? "loaded" : " ", (glt->flags & TEXF_MIPMAP) ? "mip" : " ", (glt->flags & TEXF_ALPHA) ? "alpha" : " ", glt->identifier);
621 Con_Printf("texturepool %10p total: %i (%.3fMB, %.3fMB original), uploaded %i (%.3fMB, %.3fMB original), upload on demand %i (%.3fMB, %.3fMB original)\n", (void *)pool, pooltotal, pooltotalt / 1048576.0, pooltotalp / 1048576.0, poolloaded, poolloadedt / 1048576.0, poolloadedp / 1048576.0, pooltotal - poolloaded, (pooltotalt - poolloadedt) / 1048576.0, (pooltotalp - poolloadedp) / 1048576.0);
622 sumtotal += pooltotal;
623 sumtotalt += pooltotalt;
624 sumtotalp += pooltotalp;
625 sumloaded += poolloaded;
626 sumloadedt += poolloadedt;
627 sumloadedp += poolloadedp;
630 Con_Printf("textures total: %i (%.3fMB, %.3fMB original), uploaded %i (%.3fMB, %.3fMB original), upload on demand %i (%.3fMB, %.3fMB original)\n", sumtotal, sumtotalt / 1048576.0, sumtotalp / 1048576.0, sumloaded, sumloadedt / 1048576.0, sumloadedp / 1048576.0, sumtotal - sumloaded, (sumtotalt - sumloadedt) / 1048576.0, (sumtotalp - sumloadedp) / 1048576.0);
633 static void R_TextureStats_f(void)
635 R_TextureStats_Print(true, true, true);
638 static void r_textures_start(void)
640 switch(vid.renderpath)
642 case RENDERPATH_GL11:
643 case RENDERPATH_GL13:
644 case RENDERPATH_GL20:
645 case RENDERPATH_CGGL:
646 // LordHavoc: allow any alignment
648 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
649 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
651 case RENDERPATH_D3D9:
653 case RENDERPATH_D3D10:
654 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
656 case RENDERPATH_D3D11:
657 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
661 texturemempool = Mem_AllocPool("texture management", 0, NULL);
662 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
664 // Disable JPEG screenshots if the DLL isn't loaded
665 if (! JPEG_OpenLibrary ())
666 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
667 if (! PNG_OpenLibrary ())
668 Cvar_SetValueQuick (&scr_screenshot_png, 0);
671 static void r_textures_shutdown(void)
673 rtexturepool_t *temp;
675 JPEG_CloseLibrary ();
677 while(gltexturepoolchain)
679 temp = (rtexturepool_t *) gltexturepoolchain;
680 R_FreeTexturePool(&temp);
683 resizebuffersize = 0;
685 colorconvertbuffer = NULL;
686 texturebuffer = NULL;
687 Mem_ExpandableArray_FreeArray(&texturearray);
688 Mem_FreePool(&texturemempool);
691 static void r_textures_newmap(void)
695 static void r_textures_devicelost(void)
699 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
700 for (i = 0;i < endindex;i++)
702 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
703 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
705 switch(vid.renderpath)
707 case RENDERPATH_GL11:
708 case RENDERPATH_GL13:
709 case RENDERPATH_GL20:
710 case RENDERPATH_CGGL:
712 case RENDERPATH_D3D9:
714 if (glt->tiledepth > 1)
715 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
716 else if (glt->sides == 6)
717 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
719 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
720 glt->d3dtexture = NULL;
723 case RENDERPATH_D3D10:
724 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
726 case RENDERPATH_D3D11:
727 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
733 static void r_textures_devicerestored(void)
737 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
738 for (i = 0;i < endindex;i++)
740 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
741 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
743 switch(vid.renderpath)
745 case RENDERPATH_GL11:
746 case RENDERPATH_GL13:
747 case RENDERPATH_GL20:
748 case RENDERPATH_CGGL:
750 case RENDERPATH_D3D9:
754 if (glt->tiledepth > 1)
756 if (FAILED(d3dresult = IDirect3DDevice9_CreateVolumeTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->tiledepth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DVolumeTexture9 **)&glt->d3dtexture, NULL)))
757 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
759 else if (glt->sides == 6)
761 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
762 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
766 if (FAILED(d3dresult = IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL)))
767 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
772 case RENDERPATH_D3D10:
773 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
775 case RENDERPATH_D3D11:
776 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
783 void R_Textures_Init (void)
785 Cmd_AddCommand("gl_texturemode", &GL_TextureMode_f, "set texture filtering mode (GL_NEAREST, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, etc); an additional argument 'force' forces the texture mode even in cases where it may not be appropriate");
786 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
787 Cvar_RegisterVariable (&gl_max_size);
788 Cvar_RegisterVariable (&gl_picmip);
789 Cvar_RegisterVariable (&gl_picmip_world);
790 Cvar_RegisterVariable (&r_picmipworld);
791 Cvar_RegisterVariable (&gl_picmip_sprites);
792 Cvar_RegisterVariable (&r_picmipsprites);
793 Cvar_RegisterVariable (&gl_picmip_other);
794 Cvar_RegisterVariable (&gl_max_lightmapsize);
795 Cvar_RegisterVariable (&r_lerpimages);
796 Cvar_RegisterVariable (&gl_texture_anisotropy);
797 Cvar_RegisterVariable (&gl_texturecompression);
798 Cvar_RegisterVariable (&gl_texturecompression_color);
799 Cvar_RegisterVariable (&gl_texturecompression_normal);
800 Cvar_RegisterVariable (&gl_texturecompression_gloss);
801 Cvar_RegisterVariable (&gl_texturecompression_glow);
802 Cvar_RegisterVariable (&gl_texturecompression_2d);
803 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
804 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
805 Cvar_RegisterVariable (&gl_texturecompression_sky);
806 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
807 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
808 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
809 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
811 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
814 void R_Textures_Frame (void)
816 static int old_aniso = 0;
818 // could do procedural texture animation here, if we keep track of which
819 // textures were accessed this frame...
821 // free the resize buffers
822 resizebuffersize = 0;
825 Mem_Free(resizebuffer);
828 if (colorconvertbuffer)
830 Mem_Free(colorconvertbuffer);
831 colorconvertbuffer = NULL;
834 if (old_aniso != gl_texture_anisotropy.integer)
837 gltexturepool_t *pool;
840 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
842 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
844 switch(vid.renderpath)
846 case RENDERPATH_GL11:
847 case RENDERPATH_GL13:
848 case RENDERPATH_GL20:
849 case RENDERPATH_CGGL:
852 for (pool = gltexturepoolchain;pool;pool = pool->next)
854 for (glt = pool->gltchain;glt;glt = glt->chain)
856 // only update already uploaded images
857 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
859 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
861 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
862 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
864 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
869 case RENDERPATH_D3D9:
870 case RENDERPATH_D3D10:
871 case RENDERPATH_D3D11:
877 void R_MakeResizeBufferBigger(int size)
879 if (resizebuffersize < size)
881 resizebuffersize = size;
883 Mem_Free(resizebuffer);
884 if (colorconvertbuffer)
885 Mem_Free(colorconvertbuffer);
886 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
887 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
888 if (!resizebuffer || !colorconvertbuffer)
889 Host_Error("R_Upload: out of memory");
893 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
895 int textureenum = gltexturetypeenums[texturetype];
896 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
900 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
902 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
903 if (gl_texture_anisotropy.integer != aniso)
904 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
905 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
907 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
908 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
909 if (gltexturetypedimensions[texturetype] >= 3)
911 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
915 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
917 if (flags & TEXF_MIPMAP)
919 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
923 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
925 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
927 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
929 if (flags & TEXF_MIPMAP)
931 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
933 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
937 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
942 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
944 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
948 if (flags & TEXF_MIPMAP)
950 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
954 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
956 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
959 if (textype == TEXTYPE_SHADOWMAP)
961 if (vid.support.arb_shadow)
963 if (flags & TEXF_COMPARE)
965 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
969 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
971 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
973 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
979 static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
981 int i, mip, width, height, depth;
982 GLint oldbindtexnum = 0;
983 const unsigned char *prevbuffer;
986 switch(vid.renderpath)
988 case RENDERPATH_GL11:
989 case RENDERPATH_GL13:
990 case RENDERPATH_GL20:
991 case RENDERPATH_CGGL:
994 // we need to restore the texture binding after finishing the upload
996 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
997 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
999 case RENDERPATH_D3D9:
1000 case RENDERPATH_D3D10:
1001 case RENDERPATH_D3D11:
1005 // these are rounded up versions of the size to do better resampling
1006 if (vid.support.arb_texture_non_power_of_two || glt->texturetype == GLTEXTURETYPE_RECTANGLE)
1008 width = glt->inputwidth;
1009 height = glt->inputheight;
1010 depth = glt->inputdepth;
1014 for (width = 1;width < glt->inputwidth ;width <<= 1);
1015 for (height = 1;height < glt->inputheight;height <<= 1);
1016 for (depth = 1;depth < glt->inputdepth ;depth <<= 1);
1019 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1020 R_MakeResizeBufferBigger(fragwidth * fragheight * fragdepth * glt->sides * glt->bytesperpixel);
1022 if (prevbuffer == NULL)
1024 memset(resizebuffer, 0, fragwidth * fragheight * fragdepth * glt->bytesperpixel);
1025 prevbuffer = resizebuffer;
1027 else if (glt->textype->textype == TEXTYPE_PALETTE)
1029 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1030 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, fragwidth * fragheight * fragdepth * glt->sides, glt->palette);
1031 prevbuffer = colorconvertbuffer;
1034 // upload the image - preferring to do only complete uploads (drivers do not really like partial updates)
1036 if ((glt->flags & (TEXF_MIPMAP | TEXF_PICMIP)) == 0 && glt->inputwidth == glt->tilewidth && glt->inputheight == glt->tileheight && glt->inputdepth == glt->tiledepth && (fragx != 0 || fragy != 0 || fragwidth != glt->tilewidth || fragheight != glt->tileheight))
1038 // update a portion of the image
1039 if (glt->texturetype != GLTEXTURETYPE_2D)
1040 Sys_Error("R_Upload: partial update of type other than 2D");
1041 switch(vid.renderpath)
1043 case RENDERPATH_GL11:
1044 case RENDERPATH_GL13:
1045 case RENDERPATH_GL20:
1046 case RENDERPATH_CGGL:
1047 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1048 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1050 case RENDERPATH_D3D9:
1054 D3DLOCKED_RECT d3dlockedrect;
1056 memset(&d3drect, 0, sizeof(d3drect));
1057 d3drect.left = fragx;
1058 d3drect.top = fragy;
1059 d3drect.right = fragx+fragwidth;
1060 d3drect.bottom = fragy+fragheight;
1061 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1063 for (y = 0;y < fragheight;y++)
1064 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, (unsigned char *)prevbuffer + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1065 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1070 case RENDERPATH_D3D10:
1071 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1073 case RENDERPATH_D3D11:
1074 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1080 if (fragx || fragy || fragz || glt->inputwidth != fragwidth || glt->inputheight != fragheight || glt->inputdepth != fragdepth)
1081 Sys_Error("R_Upload \"%s\": partial update not allowed on initial upload or in combination with PICMIP or MIPMAP\n", glt->identifier);
1083 // cubemaps contain multiple images and thus get processed a bit differently
1084 if (glt->texturetype != GLTEXTURETYPE_CUBEMAP)
1086 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1088 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1089 prevbuffer = resizebuffer;
1092 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1094 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1095 prevbuffer = resizebuffer;
1099 switch(vid.renderpath)
1101 case RENDERPATH_GL11:
1102 case RENDERPATH_GL13:
1103 case RENDERPATH_GL20:
1104 case RENDERPATH_CGGL:
1105 if (qglGetCompressedTexImageARB)
1107 if (gl_texturecompression.integer >= 2)
1108 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1110 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1113 switch(glt->texturetype)
1115 case GLTEXTURETYPE_2D:
1116 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1117 if (glt->flags & TEXF_MIPMAP)
1119 while (width > 1 || height > 1 || depth > 1)
1121 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1122 prevbuffer = resizebuffer;
1123 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1127 case GLTEXTURETYPE_3D:
1128 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1129 if (glt->flags & TEXF_MIPMAP)
1131 while (width > 1 || height > 1 || depth > 1)
1133 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1134 prevbuffer = resizebuffer;
1135 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1139 case GLTEXTURETYPE_CUBEMAP:
1140 // convert and upload each side in turn,
1141 // from a continuous block of input texels
1142 texturebuffer = (unsigned char *)prevbuffer;
1143 for (i = 0;i < 6;i++)
1145 prevbuffer = texturebuffer;
1146 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1147 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1149 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1150 prevbuffer = resizebuffer;
1153 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1155 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1156 prevbuffer = resizebuffer;
1159 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1160 if (glt->flags & TEXF_MIPMAP)
1162 while (width > 1 || height > 1 || depth > 1)
1164 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1165 prevbuffer = resizebuffer;
1166 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1171 case GLTEXTURETYPE_RECTANGLE:
1172 qglTexImage2D(GL_TEXTURE_RECTANGLE_ARB, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, NULL);CHECKGLERROR
1175 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1176 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1178 case RENDERPATH_D3D9:
1180 if (!(glt->flags & TEXF_RENDERTARGET))
1182 D3DLOCKED_RECT d3dlockedrect;
1183 D3DLOCKED_BOX d3dlockedbox;
1184 switch(glt->texturetype)
1186 case GLTEXTURETYPE_2D:
1187 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1190 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1192 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1193 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1196 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1198 while (width > 1 || height > 1 || depth > 1)
1200 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1201 prevbuffer = resizebuffer;
1202 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1204 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1205 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1211 case GLTEXTURETYPE_3D:
1212 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1214 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1215 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1216 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1219 if (glt->flags & TEXF_MIPMAP)
1221 while (width > 1 || height > 1 || depth > 1)
1223 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1224 prevbuffer = resizebuffer;
1225 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1227 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1228 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1229 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1235 case GLTEXTURETYPE_CUBEMAP:
1236 // convert and upload each side in turn,
1237 // from a continuous block of input texels
1238 texturebuffer = (unsigned char *)prevbuffer;
1239 for (i = 0;i < 6;i++)
1241 prevbuffer = texturebuffer;
1242 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1243 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1245 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1246 prevbuffer = resizebuffer;
1249 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1251 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1252 prevbuffer = resizebuffer;
1255 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1257 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1258 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1261 if (glt->flags & TEXF_MIPMAP)
1263 while (width > 1 || height > 1 || depth > 1)
1265 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1266 prevbuffer = resizebuffer;
1267 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1269 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1270 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1277 case GLTEXTURETYPE_RECTANGLE:
1278 Sys_Error("Direct3D does not have RECTANGLE textures\n");
1282 glt->d3daddressw = 0;
1283 if (glt->flags & TEXF_CLAMP)
1285 glt->d3daddressu = D3DTADDRESS_CLAMP;
1286 glt->d3daddressv = D3DTADDRESS_CLAMP;
1287 if (glt->tiledepth > 1)
1288 glt->d3daddressw = D3DTADDRESS_CLAMP;
1292 glt->d3daddressu = D3DTADDRESS_WRAP;
1293 glt->d3daddressv = D3DTADDRESS_WRAP;
1294 if (glt->tiledepth > 1)
1295 glt->d3daddressw = D3DTADDRESS_WRAP;
1297 glt->d3dmipmaplodbias = 0;
1298 glt->d3dmaxmiplevel = 0;
1299 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1300 if (glt->flags & TEXF_FORCELINEAR)
1302 glt->d3dminfilter = D3DTEXF_LINEAR;
1303 glt->d3dmagfilter = D3DTEXF_LINEAR;
1304 glt->d3dmipfilter = D3DTEXF_POINT;
1306 else if (glt->flags & TEXF_FORCENEAREST)
1308 glt->d3dminfilter = D3DTEXF_POINT;
1309 glt->d3dmagfilter = D3DTEXF_POINT;
1310 glt->d3dmipfilter = D3DTEXF_POINT;
1312 else if (glt->flags & TEXF_MIPMAP)
1314 glt->d3dminfilter = d3d_filter_mipmin;
1315 glt->d3dmagfilter = d3d_filter_mipmag;
1316 glt->d3dmipfilter = d3d_filter_mipmix;
1320 glt->d3dminfilter = d3d_filter_flatmin;
1321 glt->d3dmagfilter = d3d_filter_flatmag;
1322 glt->d3dmipfilter = d3d_filter_flatmix;
1326 case RENDERPATH_D3D10:
1327 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1329 case RENDERPATH_D3D11:
1330 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1336 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)
1340 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1341 textypeinfo_t *texinfo, *texinfo2;
1342 unsigned char *temppixels = NULL;
1344 if (cls.state == ca_dedicated)
1347 if (texturetype == GLTEXTURETYPE_RECTANGLE && !vid.support.arb_texture_rectangle)
1349 Con_Printf ("R_LoadTexture: rectangle texture not supported by driver\n");
1352 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1354 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1357 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1359 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1363 texinfo = R_GetTexTypeInfo(textype, flags);
1364 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1367 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1371 if (textype == TEXTYPE_RGBA)
1374 static int rgbaswapindices[4] = {2, 1, 0, 3};
1375 textype = TEXTYPE_BGRA;
1376 texinfo = R_GetTexTypeInfo(textype, flags);
1377 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1378 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1382 // clear the alpha flag if the texture has no transparent pixels
1385 case TEXTYPE_PALETTE:
1386 if (flags & TEXF_ALPHA)
1388 flags &= ~TEXF_ALPHA;
1391 for (i = 0;i < size;i++)
1393 if (((unsigned char *)&palette[data[i]])[3] < 255)
1395 flags |= TEXF_ALPHA;
1404 if (flags & TEXF_ALPHA)
1406 flags &= ~TEXF_ALPHA;
1409 for (i = 3;i < size;i += 4)
1413 flags |= TEXF_ALPHA;
1420 case TEXTYPE_SHADOWMAP:
1427 flags |= TEXF_ALPHA;
1430 flags |= TEXF_ALPHA;
1432 case TEXTYPE_COLORBUFFER:
1433 flags |= TEXF_ALPHA;
1436 Sys_Error("R_LoadTexture: unknown texture type");
1439 texinfo2 = R_GetTexTypeInfo(textype, flags);
1440 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1443 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1445 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1447 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1449 glt->chain = pool->gltchain;
1450 pool->gltchain = glt;
1451 glt->inputwidth = width;
1452 glt->inputheight = height;
1453 glt->inputdepth = depth;
1455 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
1456 glt->textype = texinfo;
1457 glt->texturetype = texturetype;
1458 glt->inputdatasize = size;
1459 glt->palette = palette;
1460 glt->glinternalformat = texinfo->glinternalformat;
1461 glt->glformat = texinfo->glformat;
1462 glt->gltype = texinfo->gltype;
1463 glt->bytesperpixel = texinfo->internalbytesperpixel;
1464 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1467 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1468 // init the dynamic texture attributes, too [11/22/2007 Black]
1469 glt->updatecallback = NULL;
1470 glt->updatacallback_data = NULL;
1472 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1474 // upload the texture
1475 // data may be NULL (blank texture for dynamic rendering)
1476 switch(vid.renderpath)
1478 case RENDERPATH_GL11:
1479 case RENDERPATH_GL13:
1480 case RENDERPATH_GL20:
1481 case RENDERPATH_CGGL:
1483 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1485 case RENDERPATH_D3D9:
1488 D3DFORMAT d3dformat;
1493 d3dpool = D3DPOOL_MANAGED;
1494 if (flags & TEXF_RENDERTARGET)
1496 d3dusage |= D3DUSAGE_RENDERTARGET;
1497 d3dpool = D3DPOOL_DEFAULT;
1501 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1502 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1503 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1504 case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1505 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1506 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1507 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1509 glt->d3dformat = d3dformat;
1510 glt->d3dusage = d3dusage;
1511 glt->d3dpool = d3dpool;
1512 if (glt->tiledepth > 1)
1514 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)))
1515 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1517 else if (glt->sides == 6)
1519 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1520 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1524 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)))
1525 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1530 case RENDERPATH_D3D10:
1531 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1533 case RENDERPATH_D3D11:
1534 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1538 R_Upload(glt, data, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
1539 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1540 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1542 // free any temporary processing buffer we allocated...
1544 Mem_Free(temppixels);
1546 // texture converting and uploading can take a while, so make sure we're sending keepalives
1547 // FIXME: this causes rendering during R_Shadow_DrawLights
1548 // CL_KeepaliveMessage(false);
1550 return (rtexture_t *)glt;
1553 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)
1555 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1558 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)
1560 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1563 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)
1565 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1568 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)
1570 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_RECTANGLE, data, palette);
1573 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1575 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1577 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1579 flags |= TEXF_FORCENEAREST;
1580 if (precision <= 16)
1581 flags |= TEXF_LOWPRECISION;
1585 rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1587 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
1590 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1592 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1595 rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter)
1597 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
1600 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1602 gltexture_t *glt = (gltexture_t *)rt;
1605 int bytesperpixel = 0;
1606 int bytesperblock = 0;
1608 int dds_format_flags;
1616 GLint internalformat;
1617 const char *ddsfourcc;
1619 return -1; // NULL pointer
1620 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1621 return -2; // broken driver - crashes on reading internal format
1622 if (!qglGetTexLevelParameteriv)
1624 GL_ActiveTexture(0);
1625 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1626 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1627 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1628 switch(internalformat)
1630 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1631 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1632 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1633 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1634 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1636 if (!bytesperblock && skipuncompressed)
1637 return -3; // skipped
1638 memset(mipinfo, 0, sizeof(mipinfo));
1639 mipinfo[0][0] = glt->tilewidth;
1640 mipinfo[0][1] = glt->tileheight;
1642 if (glt->flags & TEXF_MIPMAP)
1644 for (mip = 1;mip < 16;mip++)
1646 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1647 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1648 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1656 for (mip = 0;mip < mipmaps;mip++)
1658 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1659 mipinfo[mip][3] = ddssize;
1660 ddssize += mipinfo[mip][2];
1662 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1665 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1669 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1670 dds_format_flags = 0x4; // DDPF_FOURCC
1674 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1675 dds_format_flags = 0x40; // DDPF_RGB
1679 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1680 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1683 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1684 memcpy(dds, "DDS ", 4);
1685 StoreLittleLong(dds+4, ddssize);
1686 StoreLittleLong(dds+8, dds_flags);
1687 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1688 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1689 StoreLittleLong(dds+24, 1); // depth
1690 StoreLittleLong(dds+28, mipmaps); // mipmaps
1691 StoreLittleLong(dds+76, 32); // format size
1692 StoreLittleLong(dds+80, dds_format_flags);
1693 StoreLittleLong(dds+108, dds_caps1);
1694 StoreLittleLong(dds+112, dds_caps2);
1697 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1698 memcpy(dds+84, ddsfourcc, 4);
1699 for (mip = 0;mip < mipmaps;mip++)
1701 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1706 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1707 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1708 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1709 for (mip = 0;mip < mipmaps;mip++)
1711 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1714 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1715 ret = FS_WriteFile(filename, dds, ddssize);
1717 return ret ? ddssize : -5;
1720 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
1722 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1725 int bytesperblock, bytesperpixel;
1728 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1729 textypeinfo_t *texinfo;
1730 int mip, mipwidth, mipheight, mipsize;
1732 GLint oldbindtexnum = 0;
1733 const unsigned char *mippixels, *ddspixels;
1735 fs_offset_t ddsfilesize;
1736 unsigned int ddssize;
1738 if (cls.state == ca_dedicated)
1741 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1742 ddssize = ddsfilesize;
1746 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1747 return NULL; // not found
1750 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1753 Con_Printf("^1%s: not a DDS image\n", filename);
1757 //dds_flags = BuffLittleLong(dds+8);
1758 dds_format_flags = BuffLittleLong(dds+80);
1759 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1760 dds_width = BuffLittleLong(dds+16);
1761 dds_height = BuffLittleLong(dds+12);
1762 ddspixels = dds + 128;
1764 if(r_texture_dds_load_alphamode.integer == 0)
1765 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1766 flags &= ~TEXF_ALPHA;
1768 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1769 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1771 // very sloppy BGRA 32bit identification
1772 textype = TEXTYPE_BGRA;
1775 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1776 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1779 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1782 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1785 for (i = 3;i < size;i += 4)
1786 if (ddspixels[i] < 255)
1789 flags &= ~TEXF_ALPHA;
1792 else if (!memcmp(dds+84, "DXT1", 4))
1794 if(!vid.support.ext_texture_compression_s3tc)
1799 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1800 // LordHavoc: it is my belief that this does not infringe on the
1801 // patent because it is not decoding pixels...
1802 textype = TEXTYPE_DXT1;
1805 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1806 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1807 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1810 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1813 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1815 if(r_texture_dds_load_alphamode.integer == 1)
1818 for (i = 0;i < size;i += bytesperblock)
1819 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1821 // NOTE: this assumes sizeof(unsigned int) == 4
1822 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1823 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1824 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1828 textype = TEXTYPE_DXT1A;
1830 flags &= ~TEXF_ALPHA;
1834 flags &= ~TEXF_ALPHA;
1838 else if (!memcmp(dds+84, "DXT3", 4))
1840 if(!vid.support.ext_texture_compression_s3tc)
1845 textype = TEXTYPE_DXT3;
1848 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1849 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1852 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1855 // we currently always assume alpha
1857 else if (!memcmp(dds+84, "DXT5", 4))
1859 if(!vid.support.ext_texture_compression_s3tc)
1864 textype = TEXTYPE_DXT5;
1867 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1868 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1871 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1874 // we currently always assume alpha
1879 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1883 // return whether this texture is transparent
1885 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1887 // calculate average color if requested
1891 Vector4Clear(avgcolor);
1894 for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
1896 c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
1897 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1898 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
1899 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
1901 f = (float)bytesperblock / size;
1902 avgcolor[0] *= (0.5f / 31.0f) * f;
1903 avgcolor[1] *= (0.5f / 63.0f) * f;
1904 avgcolor[2] *= (0.5f / 31.0f) * f;
1905 avgcolor[3] = 1; // too hard to calculate
1909 for (i = 0;i < size;i += 4)
1911 avgcolor[0] += ddspixels[i+2];
1912 avgcolor[1] += ddspixels[i+1];
1913 avgcolor[2] += ddspixels[i];
1914 avgcolor[3] += ddspixels[i+3];
1916 f = (1.0f / 255.0f) * bytesperpixel / size;
1924 // this is where we apply gl_picmip
1925 mippixels = ddspixels;
1926 mipwidth = dds_width;
1927 mipheight = dds_height;
1928 while(miplevel >= 1 && dds_miplevels >= 1)
1930 if (mipwidth <= 1 && mipheight <= 1)
1932 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1933 mippixels += mipsize; // just skip
1942 // when not requesting mipmaps, do not load them
1943 if(!(flags & TEXF_MIPMAP))
1946 if (dds_miplevels >= 1)
1947 flags |= TEXF_MIPMAP;
1949 flags &= ~TEXF_MIPMAP;
1951 // if S3TC is not supported, there's very little we can do about it
1952 if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
1955 Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
1959 texinfo = R_GetTexTypeInfo(textype, flags);
1961 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1962 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
1964 glt->chain = pool->gltchain;
1965 pool->gltchain = glt;
1966 glt->inputwidth = mipwidth;
1967 glt->inputheight = mipheight;
1968 glt->inputdepth = 1;
1970 glt->textype = texinfo;
1971 glt->texturetype = GLTEXTURETYPE_2D;
1972 glt->inputdatasize = ddssize;
1973 glt->glinternalformat = texinfo->glinternalformat;
1974 glt->glformat = texinfo->glformat;
1975 glt->gltype = texinfo->gltype;
1976 glt->bytesperpixel = texinfo->internalbytesperpixel;
1978 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1979 glt->tilewidth = mipwidth;
1980 glt->tileheight = mipheight;
1982 glt->miplevels = dds_miplevels;
1984 // texture uploading can take a while, so make sure we're sending keepalives
1985 CL_KeepaliveMessage(false);
1987 // create the texture object
1988 switch(vid.renderpath)
1990 case RENDERPATH_GL11:
1991 case RENDERPATH_GL13:
1992 case RENDERPATH_GL20:
1993 case RENDERPATH_CGGL:
1995 GL_ActiveTexture(0);
1996 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1997 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1998 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2000 case RENDERPATH_D3D9:
2003 D3DFORMAT d3dformat;
2008 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2009 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2010 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2011 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2012 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2015 d3dpool = D3DPOOL_MANAGED;
2016 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2020 case RENDERPATH_D3D10:
2021 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2023 case RENDERPATH_D3D11:
2024 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2028 // upload the texture
2029 // we need to restore the texture binding after finishing the upload
2030 mipcomplete = false;
2032 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2034 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2035 if (mippixels + mipsize > dds + ddssize)
2037 switch(vid.renderpath)
2039 case RENDERPATH_GL11:
2040 case RENDERPATH_GL13:
2041 case RENDERPATH_GL20:
2042 case RENDERPATH_CGGL:
2045 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2049 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2052 case RENDERPATH_D3D9:
2055 D3DLOCKED_RECT d3dlockedrect;
2056 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2058 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2059 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2065 case RENDERPATH_D3D10:
2066 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2068 case RENDERPATH_D3D11:
2069 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2072 mippixels += mipsize;
2073 if (mipwidth <= 1 && mipheight <= 1)
2084 // after upload we have to set some parameters...
2085 switch(vid.renderpath)
2087 case RENDERPATH_GL11:
2088 case RENDERPATH_GL13:
2089 case RENDERPATH_GL20:
2090 case RENDERPATH_CGGL:
2091 if (dds_miplevels >= 1 && !mipcomplete)
2093 // need to set GL_TEXTURE_MAX_LEVEL
2094 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2096 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2097 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2099 case RENDERPATH_D3D9:
2101 glt->d3daddressw = 0;
2102 if (glt->flags & TEXF_CLAMP)
2104 glt->d3daddressu = D3DTADDRESS_CLAMP;
2105 glt->d3daddressv = D3DTADDRESS_CLAMP;
2106 if (glt->tiledepth > 1)
2107 glt->d3daddressw = D3DTADDRESS_CLAMP;
2111 glt->d3daddressu = D3DTADDRESS_WRAP;
2112 glt->d3daddressv = D3DTADDRESS_WRAP;
2113 if (glt->tiledepth > 1)
2114 glt->d3daddressw = D3DTADDRESS_WRAP;
2116 glt->d3dmipmaplodbias = 0;
2117 glt->d3dmaxmiplevel = 0;
2118 glt->d3dmaxmiplevelfilter = 0;
2119 if (glt->flags & TEXF_MIPMAP)
2121 glt->d3dminfilter = d3d_filter_mipmin;
2122 glt->d3dmagfilter = d3d_filter_mipmag;
2123 glt->d3dmipfilter = d3d_filter_mipmix;
2127 glt->d3dminfilter = d3d_filter_flatmin;
2128 glt->d3dmagfilter = d3d_filter_flatmag;
2129 glt->d3dmipfilter = d3d_filter_flatmix;
2133 case RENDERPATH_D3D10:
2134 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2136 case RENDERPATH_D3D11:
2137 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2142 return (rtexture_t *)glt;
2145 int R_TextureWidth(rtexture_t *rt)
2147 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2150 int R_TextureHeight(rtexture_t *rt)
2152 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2155 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
2157 gltexture_t *glt = (gltexture_t *)rt;
2159 Host_Error("R_UpdateTexture: no data supplied");
2161 Host_Error("R_UpdateTexture: no texture supplied");
2162 if (!glt->texnum && !glt->d3dtexture)
2164 Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", glt, glt->identifier, glt->pool);
2167 // update part of the texture
2168 if (glt->bufferpixels)
2171 int bpp = glt->bytesperpixel;
2172 int inputskip = width*bpp;
2173 int outputskip = glt->tilewidth*bpp;
2174 const unsigned char *input = data;
2175 unsigned char *output = glt->bufferpixels;
2185 input -= y*inputskip;
2188 if (width > glt->tilewidth - x)
2189 width = glt->tilewidth - x;
2190 if (height > glt->tileheight - y)
2191 height = glt->tileheight - y;
2192 if (width < 1 || height < 1)
2195 glt->buffermodified = true;
2196 output += y*outputskip + x*bpp;
2197 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2198 memcpy(output, input, width*bpp);
2201 R_Upload(glt, data, x, y, 0, width, height, 1);
2204 int R_RealGetTexture(rtexture_t *rt)
2209 glt = (gltexture_t *)rt;
2210 if (glt->flags & GLTEXF_DYNAMIC)
2211 R_UpdateDynamicTexture(glt);
2212 if (glt->buffermodified && glt->bufferpixels)
2214 glt->buffermodified = false;
2215 R_Upload(glt, glt->bufferpixels, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth);
2224 void R_ClearTexture (rtexture_t *rt)
2226 gltexture_t *glt = (gltexture_t *)rt;
2228 R_Upload( glt, NULL, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth );
2231 int R_PicmipForFlags(int flags)
2234 if(flags & TEXF_PICMIP)
2236 miplevel += gl_picmip.integer;
2237 if (flags & TEXF_ISWORLD)
2239 if (r_picmipworld.integer)
2240 miplevel += gl_picmip_world.integer;
2244 else if (flags & TEXF_ISSPRITE)
2246 if (r_picmipsprites.integer)
2247 miplevel += gl_picmip_sprites.integer;
2252 miplevel += gl_picmip_other.integer;
2254 return max(0, miplevel);