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", "0", "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.arb_texture_compression)
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.arb_texture_compression)
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 Host_Error("R_Upload: partial update not allowed on initial upload or in combination with PICMIP or MIPMAP\n");
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 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1795 // LordHavoc: it is my belief that this does not infringe on the
1796 // patent because it is not decoding pixels...
1797 textype = TEXTYPE_DXT1;
1800 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1801 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1802 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1805 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1808 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1810 if(r_texture_dds_load_alphamode.integer == 1)
1813 for (i = 0;i < size;i += bytesperblock)
1814 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1817 textype = TEXTYPE_DXT1A;
1819 flags &= ~TEXF_ALPHA;
1823 flags &= ~TEXF_ALPHA;
1827 else if (!memcmp(dds+84, "DXT3", 4))
1829 textype = TEXTYPE_DXT3;
1832 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1833 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1836 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1839 // we currently always assume alpha
1841 else if (!memcmp(dds+84, "DXT5", 4))
1843 textype = TEXTYPE_DXT5;
1846 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1847 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1850 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1853 // we currently always assume alpha
1858 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1862 // return whether this texture is transparent
1864 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1866 // calculate average color if requested
1870 Vector4Clear(avgcolor);
1873 for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
1875 c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
1876 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1877 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
1878 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
1880 f = (float)bytesperblock / size;
1881 avgcolor[0] *= (0.5f / 31.0f) * f;
1882 avgcolor[1] *= (0.5f / 63.0f) * f;
1883 avgcolor[2] *= (0.5f / 31.0f) * f;
1884 avgcolor[3] = 1; // too hard to calculate
1888 for (i = 0;i < size;i += 4)
1890 avgcolor[0] += ddspixels[i+2];
1891 avgcolor[1] += ddspixels[i+1];
1892 avgcolor[2] += ddspixels[i];
1893 avgcolor[3] += ddspixels[i+3];
1895 f = (1.0f / 255.0f) * bytesperpixel / size;
1903 // this is where we apply gl_picmip
1904 mippixels = ddspixels;
1905 mipwidth = dds_width;
1906 mipheight = dds_height;
1907 while(miplevel >= 1 && dds_miplevels >= 1)
1909 if (mipwidth <= 1 && mipheight <= 1)
1911 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1912 mippixels += mipsize; // just skip
1921 // when not requesting mipmaps, do not load them
1922 if(!(flags & TEXF_MIPMAP))
1925 if (dds_miplevels >= 1)
1926 flags |= TEXF_MIPMAP;
1928 flags &= ~TEXF_MIPMAP;
1930 // if S3TC is not supported, there's very little we can do about it
1931 if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
1934 Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
1938 texinfo = R_GetTexTypeInfo(textype, flags);
1940 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1941 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
1943 glt->chain = pool->gltchain;
1944 pool->gltchain = glt;
1945 glt->inputwidth = mipwidth;
1946 glt->inputheight = mipheight;
1947 glt->inputdepth = 1;
1949 glt->textype = texinfo;
1950 glt->texturetype = GLTEXTURETYPE_2D;
1951 glt->inputdatasize = ddssize;
1952 glt->glinternalformat = texinfo->glinternalformat;
1953 glt->glformat = texinfo->glformat;
1954 glt->gltype = texinfo->gltype;
1955 glt->bytesperpixel = texinfo->internalbytesperpixel;
1957 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1958 glt->tilewidth = mipwidth;
1959 glt->tileheight = mipheight;
1961 glt->miplevels = dds_miplevels;
1963 // texture uploading can take a while, so make sure we're sending keepalives
1964 CL_KeepaliveMessage(false);
1966 // create the texture object
1967 switch(vid.renderpath)
1969 case RENDERPATH_GL11:
1970 case RENDERPATH_GL13:
1971 case RENDERPATH_GL20:
1972 case RENDERPATH_CGGL:
1974 GL_ActiveTexture(0);
1975 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1976 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1977 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1979 case RENDERPATH_D3D9:
1982 D3DFORMAT d3dformat;
1987 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1988 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
1989 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
1990 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
1991 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1994 d3dpool = D3DPOOL_MANAGED;
1995 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
1999 case RENDERPATH_D3D10:
2000 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2002 case RENDERPATH_D3D11:
2003 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2007 // upload the texture
2008 // we need to restore the texture binding after finishing the upload
2009 mipcomplete = false;
2011 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2013 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2014 if (mippixels + mipsize > dds + ddssize)
2016 switch(vid.renderpath)
2018 case RENDERPATH_GL11:
2019 case RENDERPATH_GL13:
2020 case RENDERPATH_GL20:
2021 case RENDERPATH_CGGL:
2024 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2028 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2031 case RENDERPATH_D3D9:
2034 D3DLOCKED_RECT d3dlockedrect;
2035 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2037 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2038 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2044 case RENDERPATH_D3D10:
2045 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2047 case RENDERPATH_D3D11:
2048 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2051 mippixels += mipsize;
2052 if (mipwidth <= 1 && mipheight <= 1)
2063 // after upload we have to set some parameters...
2064 switch(vid.renderpath)
2066 case RENDERPATH_GL11:
2067 case RENDERPATH_GL13:
2068 case RENDERPATH_GL20:
2069 case RENDERPATH_CGGL:
2070 if (dds_miplevels >= 1 && !mipcomplete)
2072 // need to set GL_TEXTURE_MAX_LEVEL
2073 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2075 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2076 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2078 case RENDERPATH_D3D9:
2080 glt->d3daddressw = 0;
2081 if (glt->flags & TEXF_CLAMP)
2083 glt->d3daddressu = D3DTADDRESS_CLAMP;
2084 glt->d3daddressv = D3DTADDRESS_CLAMP;
2085 if (glt->tiledepth > 1)
2086 glt->d3daddressw = D3DTADDRESS_CLAMP;
2090 glt->d3daddressu = D3DTADDRESS_WRAP;
2091 glt->d3daddressv = D3DTADDRESS_WRAP;
2092 if (glt->tiledepth > 1)
2093 glt->d3daddressw = D3DTADDRESS_WRAP;
2095 glt->d3dmipmaplodbias = 0;
2096 glt->d3dmaxmiplevel = 0;
2097 glt->d3dmaxmiplevelfilter = 0;
2098 if (glt->flags & TEXF_MIPMAP)
2100 glt->d3dminfilter = d3d_filter_mipmin;
2101 glt->d3dmagfilter = d3d_filter_mipmag;
2102 glt->d3dmipfilter = d3d_filter_mipmix;
2106 glt->d3dminfilter = d3d_filter_flatmin;
2107 glt->d3dmagfilter = d3d_filter_flatmag;
2108 glt->d3dmipfilter = d3d_filter_flatmix;
2112 case RENDERPATH_D3D10:
2113 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2115 case RENDERPATH_D3D11:
2116 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2121 return (rtexture_t *)glt;
2124 int R_TextureWidth(rtexture_t *rt)
2126 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2129 int R_TextureHeight(rtexture_t *rt)
2131 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2134 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
2136 gltexture_t *glt = (gltexture_t *)rt;
2138 Host_Error("R_UpdateTexture: no data supplied");
2140 Host_Error("R_UpdateTexture: no texture supplied");
2141 if (!glt->texnum && !glt->d3dtexture)
2143 Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", glt, glt->identifier, glt->pool);
2146 // update part of the texture
2147 if (glt->bufferpixels)
2150 int bpp = glt->bytesperpixel;
2151 int inputskip = width*bpp;
2152 int outputskip = glt->tilewidth*bpp;
2153 const unsigned char *input = data;
2154 unsigned char *output = glt->bufferpixels;
2164 input -= y*inputskip;
2167 if (width > glt->tilewidth - x)
2168 width = glt->tilewidth - x;
2169 if (height > glt->tileheight - y)
2170 height = glt->tileheight - y;
2171 if (width < 1 || height < 1)
2174 glt->buffermodified = true;
2175 output += y*outputskip + x*bpp;
2176 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2177 memcpy(output, input, width*bpp);
2180 R_Upload(glt, data, x, y, 0, width, height, 1);
2183 int R_RealGetTexture(rtexture_t *rt)
2188 glt = (gltexture_t *)rt;
2189 if (glt->flags & GLTEXF_DYNAMIC)
2190 R_UpdateDynamicTexture(glt);
2191 if (glt->buffermodified && glt->bufferpixels)
2193 glt->buffermodified = false;
2194 R_Upload(glt, glt->bufferpixels, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth);
2203 void R_ClearTexture (rtexture_t *rt)
2205 gltexture_t *glt = (gltexture_t *)rt;
2207 R_Upload( glt, NULL, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth );
2210 int R_PicmipForFlags(int flags)
2213 if(flags & TEXF_PICMIP)
2215 miplevel += gl_picmip.integer;
2216 if (flags & TEXF_ISWORLD)
2218 if (r_picmipworld.integer)
2219 miplevel += gl_picmip_world.integer;
2223 else if (flags & TEXF_ISSPRITE)
2225 if (r_picmipsprites.integer)
2226 miplevel += gl_picmip_sprites.integer;
2231 miplevel += gl_picmip_other.integer;
2233 return max(0, miplevel);