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;
486 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)
488 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
493 case GLTEXTURETYPE_2D:
494 maxsize = vid.maxtexturesize_2d;
495 if (flags & TEXF_PICMIP)
497 maxsize = bound(1, gl_max_size.integer, maxsize);
501 case GLTEXTURETYPE_3D:
502 maxsize = vid.maxtexturesize_3d;
504 case GLTEXTURETYPE_CUBEMAP:
505 maxsize = vid.maxtexturesize_cubemap;
511 if (vid.support.arb_texture_non_power_of_two)
512 width2 = min(inwidth >> picmip, maxsize);
515 for (width2 = 1;width2 < inwidth;width2 <<= 1);
516 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
518 *outwidth = max(1, width2);
522 if (vid.support.arb_texture_non_power_of_two)
523 height2 = min(inheight >> picmip, maxsize);
526 for (height2 = 1;height2 < inheight;height2 <<= 1);
527 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
529 *outheight = max(1, height2);
533 if (vid.support.arb_texture_non_power_of_two)
534 depth2 = min(indepth >> picmip, maxsize);
537 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
538 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
540 *outdepth = max(1, depth2);
544 if (flags & TEXF_MIPMAP)
546 int extent = max(width2, max(height2, depth2));
551 *outmiplevels = miplevels;
555 static int R_CalcTexelDataSize (gltexture_t *glt)
557 int width2, height2, depth2, size;
559 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
561 size = width2 * height2 * depth2;
563 if (glt->flags & TEXF_MIPMAP)
565 while (width2 > 1 || height2 > 1 || depth2 > 1)
573 size += width2 * height2 * depth2;
577 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
580 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
584 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
585 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
587 gltexturepool_t *pool;
589 Con_Print("glsize input loaded mip alpha name\n");
590 for (pool = gltexturepoolchain;pool;pool = pool->next)
598 for (glt = pool->gltchain;glt;glt = glt->chain)
600 glsize = R_CalcTexelDataSize(glt);
601 isloaded = glt->texnum != 0;
603 pooltotalt += glsize;
604 pooltotalp += glt->inputdatasize;
608 poolloadedt += glsize;
609 poolloadedp += glt->inputdatasize;
612 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);
615 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);
616 sumtotal += pooltotal;
617 sumtotalt += pooltotalt;
618 sumtotalp += pooltotalp;
619 sumloaded += poolloaded;
620 sumloadedt += poolloadedt;
621 sumloadedp += poolloadedp;
624 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);
627 static void R_TextureStats_f(void)
629 R_TextureStats_Print(true, true, true);
632 static void r_textures_start(void)
634 switch(vid.renderpath)
636 case RENDERPATH_GL11:
637 case RENDERPATH_GL13:
638 case RENDERPATH_GL20:
639 case RENDERPATH_CGGL:
640 // LordHavoc: allow any alignment
642 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
643 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
645 case RENDERPATH_D3D9:
647 case RENDERPATH_D3D10:
648 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
650 case RENDERPATH_D3D11:
651 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
655 texturemempool = Mem_AllocPool("texture management", 0, NULL);
656 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
658 // Disable JPEG screenshots if the DLL isn't loaded
659 if (! JPEG_OpenLibrary ())
660 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
661 if (! PNG_OpenLibrary ())
662 Cvar_SetValueQuick (&scr_screenshot_png, 0);
665 static void r_textures_shutdown(void)
667 rtexturepool_t *temp;
669 JPEG_CloseLibrary ();
671 while(gltexturepoolchain)
673 temp = (rtexturepool_t *) gltexturepoolchain;
674 R_FreeTexturePool(&temp);
677 resizebuffersize = 0;
679 colorconvertbuffer = NULL;
680 texturebuffer = NULL;
681 Mem_ExpandableArray_FreeArray(&texturearray);
682 Mem_FreePool(&texturemempool);
685 static void r_textures_newmap(void)
689 static void r_textures_devicelost(void)
693 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
694 for (i = 0;i < endindex;i++)
696 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
697 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
699 switch(vid.renderpath)
701 case RENDERPATH_GL11:
702 case RENDERPATH_GL13:
703 case RENDERPATH_GL20:
704 case RENDERPATH_CGGL:
706 case RENDERPATH_D3D9:
708 if (glt->tiledepth > 1)
709 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
710 else if (glt->sides == 6)
711 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
713 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
714 glt->d3dtexture = NULL;
717 case RENDERPATH_D3D10:
718 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
720 case RENDERPATH_D3D11:
721 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
727 static void r_textures_devicerestored(void)
731 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
732 for (i = 0;i < endindex;i++)
734 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
735 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
737 switch(vid.renderpath)
739 case RENDERPATH_GL11:
740 case RENDERPATH_GL13:
741 case RENDERPATH_GL20:
742 case RENDERPATH_CGGL:
744 case RENDERPATH_D3D9:
748 if (glt->tiledepth > 1)
750 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)))
751 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
753 else if (glt->sides == 6)
755 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
756 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
760 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)))
761 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
766 case RENDERPATH_D3D10:
767 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
769 case RENDERPATH_D3D11:
770 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
777 void R_Textures_Init (void)
779 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");
780 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
781 Cvar_RegisterVariable (&gl_max_size);
782 Cvar_RegisterVariable (&gl_picmip);
783 Cvar_RegisterVariable (&gl_picmip_world);
784 Cvar_RegisterVariable (&r_picmipworld);
785 Cvar_RegisterVariable (&gl_picmip_sprites);
786 Cvar_RegisterVariable (&r_picmipsprites);
787 Cvar_RegisterVariable (&gl_picmip_other);
788 Cvar_RegisterVariable (&gl_max_lightmapsize);
789 Cvar_RegisterVariable (&r_lerpimages);
790 Cvar_RegisterVariable (&gl_texture_anisotropy);
791 Cvar_RegisterVariable (&gl_texturecompression);
792 Cvar_RegisterVariable (&gl_texturecompression_color);
793 Cvar_RegisterVariable (&gl_texturecompression_normal);
794 Cvar_RegisterVariable (&gl_texturecompression_gloss);
795 Cvar_RegisterVariable (&gl_texturecompression_glow);
796 Cvar_RegisterVariable (&gl_texturecompression_2d);
797 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
798 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
799 Cvar_RegisterVariable (&gl_texturecompression_sky);
800 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
801 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
802 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
803 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
805 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
808 void R_Textures_Frame (void)
810 static int old_aniso = 0;
812 // could do procedural texture animation here, if we keep track of which
813 // textures were accessed this frame...
815 // free the resize buffers
816 resizebuffersize = 0;
819 Mem_Free(resizebuffer);
822 if (colorconvertbuffer)
824 Mem_Free(colorconvertbuffer);
825 colorconvertbuffer = NULL;
828 if (old_aniso != gl_texture_anisotropy.integer)
831 gltexturepool_t *pool;
834 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
836 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
838 switch(vid.renderpath)
840 case RENDERPATH_GL11:
841 case RENDERPATH_GL13:
842 case RENDERPATH_GL20:
843 case RENDERPATH_CGGL:
846 for (pool = gltexturepoolchain;pool;pool = pool->next)
848 for (glt = pool->gltchain;glt;glt = glt->chain)
850 // only update already uploaded images
851 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
853 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
855 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
856 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
858 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
863 case RENDERPATH_D3D9:
864 case RENDERPATH_D3D10:
865 case RENDERPATH_D3D11:
871 void R_MakeResizeBufferBigger(int size)
873 if (resizebuffersize < size)
875 resizebuffersize = size;
877 Mem_Free(resizebuffer);
878 if (colorconvertbuffer)
879 Mem_Free(colorconvertbuffer);
880 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
881 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
882 if (!resizebuffer || !colorconvertbuffer)
883 Host_Error("R_Upload: out of memory");
887 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
889 int textureenum = gltexturetypeenums[texturetype];
890 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
894 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
896 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
897 if (gl_texture_anisotropy.integer != aniso)
898 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
899 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
901 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
902 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
903 if (gltexturetypedimensions[texturetype] >= 3)
905 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
909 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
911 if (flags & TEXF_MIPMAP)
913 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
917 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
919 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
921 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
923 if (flags & TEXF_MIPMAP)
925 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
927 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
931 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
936 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
938 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
942 if (flags & TEXF_MIPMAP)
944 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
948 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
950 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
953 if (textype == TEXTYPE_SHADOWMAP)
955 if (vid.support.arb_shadow)
957 if (flags & TEXF_COMPARE)
959 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
963 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
965 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
967 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
973 static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
975 int i, mip, width, height, depth;
976 GLint oldbindtexnum = 0;
977 const unsigned char *prevbuffer;
980 switch(vid.renderpath)
982 case RENDERPATH_GL11:
983 case RENDERPATH_GL13:
984 case RENDERPATH_GL20:
985 case RENDERPATH_CGGL:
988 // we need to restore the texture binding after finishing the upload
990 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
991 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
993 case RENDERPATH_D3D9:
994 case RENDERPATH_D3D10:
995 case RENDERPATH_D3D11:
999 // these are rounded up versions of the size to do better resampling
1000 if (vid.support.arb_texture_non_power_of_two || glt->texturetype == GLTEXTURETYPE_RECTANGLE)
1002 width = glt->inputwidth;
1003 height = glt->inputheight;
1004 depth = glt->inputdepth;
1008 for (width = 1;width < glt->inputwidth ;width <<= 1);
1009 for (height = 1;height < glt->inputheight;height <<= 1);
1010 for (depth = 1;depth < glt->inputdepth ;depth <<= 1);
1013 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1014 R_MakeResizeBufferBigger(fragwidth * fragheight * fragdepth * glt->sides * glt->bytesperpixel);
1016 if (prevbuffer == NULL)
1018 memset(resizebuffer, 0, fragwidth * fragheight * fragdepth * glt->bytesperpixel);
1019 prevbuffer = resizebuffer;
1021 else if (glt->textype->textype == TEXTYPE_PALETTE)
1023 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1024 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, fragwidth * fragheight * fragdepth * glt->sides, glt->palette);
1025 prevbuffer = colorconvertbuffer;
1028 // upload the image - preferring to do only complete uploads (drivers do not really like partial updates)
1030 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))
1032 // update a portion of the image
1033 if (glt->texturetype != GLTEXTURETYPE_2D)
1034 Sys_Error("R_Upload: partial update of type other than 2D");
1035 switch(vid.renderpath)
1037 case RENDERPATH_GL11:
1038 case RENDERPATH_GL13:
1039 case RENDERPATH_GL20:
1040 case RENDERPATH_CGGL:
1041 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1042 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1044 case RENDERPATH_D3D9:
1048 D3DLOCKED_RECT d3dlockedrect;
1050 memset(&d3drect, 0, sizeof(d3drect));
1051 d3drect.left = fragx;
1052 d3drect.top = fragy;
1053 d3drect.right = fragx+fragwidth;
1054 d3drect.bottom = fragy+fragheight;
1055 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1057 for (y = 0;y < fragheight;y++)
1058 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, (unsigned char *)prevbuffer + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1059 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1064 case RENDERPATH_D3D10:
1065 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1067 case RENDERPATH_D3D11:
1068 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1074 if (fragx || fragy || fragz || glt->inputwidth != fragwidth || glt->inputheight != fragheight || glt->inputdepth != fragdepth)
1075 Sys_Error("R_Upload \"%s\": partial update not allowed on initial upload or in combination with PICMIP or MIPMAP\n", glt->identifier);
1077 // cubemaps contain multiple images and thus get processed a bit differently
1078 if (glt->texturetype != GLTEXTURETYPE_CUBEMAP)
1080 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1082 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1083 prevbuffer = resizebuffer;
1086 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1088 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1089 prevbuffer = resizebuffer;
1093 switch(vid.renderpath)
1095 case RENDERPATH_GL11:
1096 case RENDERPATH_GL13:
1097 case RENDERPATH_GL20:
1098 case RENDERPATH_CGGL:
1099 if (qglGetCompressedTexImageARB)
1101 if (gl_texturecompression.integer >= 2)
1102 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1104 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1107 switch(glt->texturetype)
1109 case GLTEXTURETYPE_2D:
1110 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1111 if (glt->flags & TEXF_MIPMAP)
1113 while (width > 1 || height > 1 || depth > 1)
1115 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1116 prevbuffer = resizebuffer;
1117 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1121 case GLTEXTURETYPE_3D:
1122 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1123 if (glt->flags & TEXF_MIPMAP)
1125 while (width > 1 || height > 1 || depth > 1)
1127 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1128 prevbuffer = resizebuffer;
1129 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1133 case GLTEXTURETYPE_CUBEMAP:
1134 // convert and upload each side in turn,
1135 // from a continuous block of input texels
1136 texturebuffer = (unsigned char *)prevbuffer;
1137 for (i = 0;i < 6;i++)
1139 prevbuffer = texturebuffer;
1140 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1141 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1143 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1144 prevbuffer = resizebuffer;
1147 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1149 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1150 prevbuffer = resizebuffer;
1153 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1154 if (glt->flags & TEXF_MIPMAP)
1156 while (width > 1 || height > 1 || depth > 1)
1158 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1159 prevbuffer = resizebuffer;
1160 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1165 case GLTEXTURETYPE_RECTANGLE:
1166 qglTexImage2D(GL_TEXTURE_RECTANGLE_ARB, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, NULL);CHECKGLERROR
1169 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1170 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1172 case RENDERPATH_D3D9:
1174 if (!(glt->flags & TEXF_RENDERTARGET))
1176 D3DLOCKED_RECT d3dlockedrect;
1177 D3DLOCKED_BOX d3dlockedbox;
1178 switch(glt->texturetype)
1180 case GLTEXTURETYPE_2D:
1181 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1184 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1186 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1187 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1190 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1192 while (width > 1 || height > 1 || depth > 1)
1194 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1195 prevbuffer = resizebuffer;
1196 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1198 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1199 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1205 case GLTEXTURETYPE_3D:
1206 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1208 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1209 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1210 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1213 if (glt->flags & TEXF_MIPMAP)
1215 while (width > 1 || height > 1 || depth > 1)
1217 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1218 prevbuffer = resizebuffer;
1219 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1221 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1222 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1223 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1229 case GLTEXTURETYPE_CUBEMAP:
1230 // convert and upload each side in turn,
1231 // from a continuous block of input texels
1232 texturebuffer = (unsigned char *)prevbuffer;
1233 for (i = 0;i < 6;i++)
1235 prevbuffer = texturebuffer;
1236 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1237 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1239 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1240 prevbuffer = resizebuffer;
1243 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1245 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1246 prevbuffer = resizebuffer;
1249 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1251 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1252 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1255 if (glt->flags & TEXF_MIPMAP)
1257 while (width > 1 || height > 1 || depth > 1)
1259 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1260 prevbuffer = resizebuffer;
1261 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1263 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1264 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1271 case GLTEXTURETYPE_RECTANGLE:
1272 Sys_Error("Direct3D does not have RECTANGLE textures\n");
1276 glt->d3daddressw = 0;
1277 if (glt->flags & TEXF_CLAMP)
1279 glt->d3daddressu = D3DTADDRESS_CLAMP;
1280 glt->d3daddressv = D3DTADDRESS_CLAMP;
1281 if (glt->tiledepth > 1)
1282 glt->d3daddressw = D3DTADDRESS_CLAMP;
1286 glt->d3daddressu = D3DTADDRESS_WRAP;
1287 glt->d3daddressv = D3DTADDRESS_WRAP;
1288 if (glt->tiledepth > 1)
1289 glt->d3daddressw = D3DTADDRESS_WRAP;
1291 glt->d3dmipmaplodbias = 0;
1292 glt->d3dmaxmiplevel = 0;
1293 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1294 if (glt->flags & TEXF_FORCELINEAR)
1296 glt->d3dminfilter = D3DTEXF_LINEAR;
1297 glt->d3dmagfilter = D3DTEXF_LINEAR;
1298 glt->d3dmipfilter = D3DTEXF_POINT;
1300 else if (glt->flags & TEXF_FORCENEAREST)
1302 glt->d3dminfilter = D3DTEXF_POINT;
1303 glt->d3dmagfilter = D3DTEXF_POINT;
1304 glt->d3dmipfilter = D3DTEXF_POINT;
1306 else if (glt->flags & TEXF_MIPMAP)
1308 glt->d3dminfilter = d3d_filter_mipmin;
1309 glt->d3dmagfilter = d3d_filter_mipmag;
1310 glt->d3dmipfilter = d3d_filter_mipmix;
1314 glt->d3dminfilter = d3d_filter_flatmin;
1315 glt->d3dmagfilter = d3d_filter_flatmag;
1316 glt->d3dmipfilter = d3d_filter_flatmix;
1320 case RENDERPATH_D3D10:
1321 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1323 case RENDERPATH_D3D11:
1324 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1330 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)
1334 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1335 textypeinfo_t *texinfo, *texinfo2;
1336 unsigned char *temppixels = NULL;
1338 if (cls.state == ca_dedicated)
1341 if (texturetype == GLTEXTURETYPE_RECTANGLE && !vid.support.arb_texture_rectangle)
1343 Con_Printf ("R_LoadTexture: rectangle texture not supported by driver\n");
1346 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1348 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1351 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1353 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1357 texinfo = R_GetTexTypeInfo(textype, flags);
1358 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1361 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1365 if (textype == TEXTYPE_RGBA)
1368 static int rgbaswapindices[4] = {2, 1, 0, 3};
1369 textype = TEXTYPE_BGRA;
1370 texinfo = R_GetTexTypeInfo(textype, flags);
1371 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1372 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1376 // clear the alpha flag if the texture has no transparent pixels
1379 case TEXTYPE_PALETTE:
1380 if (flags & TEXF_ALPHA)
1382 flags &= ~TEXF_ALPHA;
1385 for (i = 0;i < size;i++)
1387 if (((unsigned char *)&palette[data[i]])[3] < 255)
1389 flags |= TEXF_ALPHA;
1398 if (flags & TEXF_ALPHA)
1400 flags &= ~TEXF_ALPHA;
1403 for (i = 3;i < size;i += 4)
1407 flags |= TEXF_ALPHA;
1414 case TEXTYPE_SHADOWMAP:
1421 flags |= TEXF_ALPHA;
1424 flags |= TEXF_ALPHA;
1426 case TEXTYPE_COLORBUFFER:
1427 flags |= TEXF_ALPHA;
1430 Sys_Error("R_LoadTexture: unknown texture type");
1433 texinfo2 = R_GetTexTypeInfo(textype, flags);
1434 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1437 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1439 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1441 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1443 glt->chain = pool->gltchain;
1444 pool->gltchain = glt;
1445 glt->inputwidth = width;
1446 glt->inputheight = height;
1447 glt->inputdepth = depth;
1449 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
1450 glt->textype = texinfo;
1451 glt->texturetype = texturetype;
1452 glt->inputdatasize = size;
1453 glt->palette = palette;
1454 glt->glinternalformat = texinfo->glinternalformat;
1455 glt->glformat = texinfo->glformat;
1456 glt->gltype = texinfo->gltype;
1457 glt->bytesperpixel = texinfo->internalbytesperpixel;
1458 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1461 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1462 // init the dynamic texture attributes, too [11/22/2007 Black]
1463 glt->updatecallback = NULL;
1464 glt->updatacallback_data = NULL;
1466 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1468 // upload the texture
1469 // data may be NULL (blank texture for dynamic rendering)
1470 switch(vid.renderpath)
1472 case RENDERPATH_GL11:
1473 case RENDERPATH_GL13:
1474 case RENDERPATH_GL20:
1475 case RENDERPATH_CGGL:
1477 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1479 case RENDERPATH_D3D9:
1482 D3DFORMAT d3dformat;
1487 d3dpool = D3DPOOL_MANAGED;
1488 if (flags & TEXF_RENDERTARGET)
1490 d3dusage |= D3DUSAGE_RENDERTARGET;
1491 d3dpool = D3DPOOL_DEFAULT;
1495 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1496 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1497 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1498 case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1499 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1500 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1501 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1503 glt->d3dformat = d3dformat;
1504 glt->d3dusage = d3dusage;
1505 glt->d3dpool = d3dpool;
1506 if (glt->tiledepth > 1)
1508 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)))
1509 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1511 else if (glt->sides == 6)
1513 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1514 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1518 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)))
1519 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1524 case RENDERPATH_D3D10:
1525 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1527 case RENDERPATH_D3D11:
1528 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1532 R_Upload(glt, data, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
1533 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1534 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1536 // free any temporary processing buffer we allocated...
1538 Mem_Free(temppixels);
1540 // texture converting and uploading can take a while, so make sure we're sending keepalives
1541 // FIXME: this causes rendering during R_Shadow_DrawLights
1542 // CL_KeepaliveMessage(false);
1544 return (rtexture_t *)glt;
1547 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)
1549 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1552 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)
1554 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1557 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)
1559 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1562 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)
1564 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_RECTANGLE, data, palette);
1567 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1569 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1571 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1573 flags |= TEXF_FORCENEAREST;
1574 if (precision <= 16)
1575 flags |= TEXF_LOWPRECISION;
1579 rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1581 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
1584 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1586 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1589 rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter)
1591 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
1594 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1596 gltexture_t *glt = (gltexture_t *)rt;
1599 int bytesperpixel = 0;
1600 int bytesperblock = 0;
1602 int dds_format_flags;
1610 GLint internalformat;
1611 const char *ddsfourcc;
1613 return -1; // NULL pointer
1614 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1615 return -2; // broken driver - crashes on reading internal format
1616 if (!qglGetTexLevelParameteriv)
1618 GL_ActiveTexture(0);
1619 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1620 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1621 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1622 switch(internalformat)
1624 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1625 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1626 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1627 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1628 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1630 if (!bytesperblock && skipuncompressed)
1631 return -3; // skipped
1632 memset(mipinfo, 0, sizeof(mipinfo));
1633 mipinfo[0][0] = glt->tilewidth;
1634 mipinfo[0][1] = glt->tileheight;
1636 if (glt->flags & TEXF_MIPMAP)
1638 for (mip = 1;mip < 16;mip++)
1640 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1641 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1642 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1650 for (mip = 0;mip < mipmaps;mip++)
1652 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1653 mipinfo[mip][3] = ddssize;
1654 ddssize += mipinfo[mip][2];
1656 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1659 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1663 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1664 dds_format_flags = 0x4; // DDPF_FOURCC
1668 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1669 dds_format_flags = 0x40; // DDPF_RGB
1673 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1674 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1677 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1678 memcpy(dds, "DDS ", 4);
1679 StoreLittleLong(dds+4, ddssize);
1680 StoreLittleLong(dds+8, dds_flags);
1681 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1682 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1683 StoreLittleLong(dds+24, 1); // depth
1684 StoreLittleLong(dds+28, mipmaps); // mipmaps
1685 StoreLittleLong(dds+76, 32); // format size
1686 StoreLittleLong(dds+80, dds_format_flags);
1687 StoreLittleLong(dds+108, dds_caps1);
1688 StoreLittleLong(dds+112, dds_caps2);
1691 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1692 memcpy(dds+84, ddsfourcc, 4);
1693 for (mip = 0;mip < mipmaps;mip++)
1695 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1700 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1701 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1702 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1703 for (mip = 0;mip < mipmaps;mip++)
1705 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1708 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1709 ret = FS_WriteFile(filename, dds, ddssize);
1711 return ret ? ddssize : -5;
1714 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
1716 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1719 int bytesperblock, bytesperpixel;
1722 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1723 textypeinfo_t *texinfo;
1724 int mip, mipwidth, mipheight, mipsize;
1726 GLint oldbindtexnum = 0;
1727 const unsigned char *mippixels, *ddspixels;
1729 fs_offset_t ddsfilesize;
1730 unsigned int ddssize;
1732 if (cls.state == ca_dedicated)
1735 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1736 ddssize = ddsfilesize;
1740 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1741 return NULL; // not found
1744 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1747 Con_Printf("^1%s: not a DDS image\n", filename);
1751 //dds_flags = BuffLittleLong(dds+8);
1752 dds_format_flags = BuffLittleLong(dds+80);
1753 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1754 dds_width = BuffLittleLong(dds+16);
1755 dds_height = BuffLittleLong(dds+12);
1756 ddspixels = dds + 128;
1758 if(r_texture_dds_load_alphamode.integer == 0)
1759 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1760 flags &= ~TEXF_ALPHA;
1762 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1763 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1765 // very sloppy BGRA 32bit identification
1766 textype = TEXTYPE_BGRA;
1769 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1770 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1773 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1776 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1779 for (i = 3;i < size;i += 4)
1780 if (ddspixels[i] < 255)
1783 flags &= ~TEXF_ALPHA;
1786 else if (!memcmp(dds+84, "DXT1", 4))
1788 if(!vid.support.ext_texture_compression_s3tc)
1793 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1794 // LordHavoc: it is my belief that this does not infringe on the
1795 // patent because it is not decoding pixels...
1796 textype = TEXTYPE_DXT1;
1799 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1800 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1801 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1804 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1807 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1809 if(r_texture_dds_load_alphamode.integer == 1)
1812 for (i = 0;i < size;i += bytesperblock)
1813 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1815 // NOTE: this assumes sizeof(unsigned int) == 4
1816 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1817 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1818 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1822 textype = TEXTYPE_DXT1A;
1824 flags &= ~TEXF_ALPHA;
1828 flags &= ~TEXF_ALPHA;
1832 else if (!memcmp(dds+84, "DXT3", 4))
1834 if(!vid.support.ext_texture_compression_s3tc)
1839 textype = TEXTYPE_DXT3;
1842 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1843 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1846 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1849 // we currently always assume alpha
1851 else if (!memcmp(dds+84, "DXT5", 4))
1853 if(!vid.support.ext_texture_compression_s3tc)
1858 textype = TEXTYPE_DXT5;
1861 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1862 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1865 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1868 // we currently always assume alpha
1873 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1877 // return whether this texture is transparent
1879 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1881 // calculate average color if requested
1885 Vector4Clear(avgcolor);
1888 for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
1890 c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
1891 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1892 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
1893 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
1895 f = (float)bytesperblock / size;
1896 avgcolor[0] *= (0.5f / 31.0f) * f;
1897 avgcolor[1] *= (0.5f / 63.0f) * f;
1898 avgcolor[2] *= (0.5f / 31.0f) * f;
1899 avgcolor[3] = 1; // too hard to calculate
1903 for (i = 0;i < size;i += 4)
1905 avgcolor[0] += ddspixels[i+2];
1906 avgcolor[1] += ddspixels[i+1];
1907 avgcolor[2] += ddspixels[i];
1908 avgcolor[3] += ddspixels[i+3];
1910 f = (1.0f / 255.0f) * bytesperpixel / size;
1918 // this is where we apply gl_picmip
1919 mippixels = ddspixels;
1920 mipwidth = dds_width;
1921 mipheight = dds_height;
1922 while(miplevel >= 1 && dds_miplevels >= 1)
1924 if (mipwidth <= 1 && mipheight <= 1)
1926 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1927 mippixels += mipsize; // just skip
1936 // when not requesting mipmaps, do not load them
1937 if(!(flags & TEXF_MIPMAP))
1940 if (dds_miplevels >= 1)
1941 flags |= TEXF_MIPMAP;
1943 flags &= ~TEXF_MIPMAP;
1945 // if S3TC is not supported, there's very little we can do about it
1946 if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
1949 Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
1953 texinfo = R_GetTexTypeInfo(textype, flags);
1955 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1956 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
1958 glt->chain = pool->gltchain;
1959 pool->gltchain = glt;
1960 glt->inputwidth = mipwidth;
1961 glt->inputheight = mipheight;
1962 glt->inputdepth = 1;
1964 glt->textype = texinfo;
1965 glt->texturetype = GLTEXTURETYPE_2D;
1966 glt->inputdatasize = ddssize;
1967 glt->glinternalformat = texinfo->glinternalformat;
1968 glt->glformat = texinfo->glformat;
1969 glt->gltype = texinfo->gltype;
1970 glt->bytesperpixel = texinfo->internalbytesperpixel;
1972 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1973 glt->tilewidth = mipwidth;
1974 glt->tileheight = mipheight;
1976 glt->miplevels = dds_miplevels;
1978 // texture uploading can take a while, so make sure we're sending keepalives
1979 CL_KeepaliveMessage(false);
1981 // create the texture object
1982 switch(vid.renderpath)
1984 case RENDERPATH_GL11:
1985 case RENDERPATH_GL13:
1986 case RENDERPATH_GL20:
1987 case RENDERPATH_CGGL:
1989 GL_ActiveTexture(0);
1990 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1991 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1992 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1994 case RENDERPATH_D3D9:
1997 D3DFORMAT d3dformat;
2002 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2003 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2004 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2005 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2006 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2009 d3dpool = D3DPOOL_MANAGED;
2010 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2014 case RENDERPATH_D3D10:
2015 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2017 case RENDERPATH_D3D11:
2018 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2022 // upload the texture
2023 // we need to restore the texture binding after finishing the upload
2024 mipcomplete = false;
2026 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2028 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2029 if (mippixels + mipsize > dds + ddssize)
2031 switch(vid.renderpath)
2033 case RENDERPATH_GL11:
2034 case RENDERPATH_GL13:
2035 case RENDERPATH_GL20:
2036 case RENDERPATH_CGGL:
2039 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2043 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2046 case RENDERPATH_D3D9:
2049 D3DLOCKED_RECT d3dlockedrect;
2050 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2052 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2053 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2059 case RENDERPATH_D3D10:
2060 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2062 case RENDERPATH_D3D11:
2063 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2066 mippixels += mipsize;
2067 if (mipwidth <= 1 && mipheight <= 1)
2078 // after upload we have to set some parameters...
2079 switch(vid.renderpath)
2081 case RENDERPATH_GL11:
2082 case RENDERPATH_GL13:
2083 case RENDERPATH_GL20:
2084 case RENDERPATH_CGGL:
2085 if (dds_miplevels >= 1 && !mipcomplete)
2087 // need to set GL_TEXTURE_MAX_LEVEL
2088 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2090 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2091 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2093 case RENDERPATH_D3D9:
2095 glt->d3daddressw = 0;
2096 if (glt->flags & TEXF_CLAMP)
2098 glt->d3daddressu = D3DTADDRESS_CLAMP;
2099 glt->d3daddressv = D3DTADDRESS_CLAMP;
2100 if (glt->tiledepth > 1)
2101 glt->d3daddressw = D3DTADDRESS_CLAMP;
2105 glt->d3daddressu = D3DTADDRESS_WRAP;
2106 glt->d3daddressv = D3DTADDRESS_WRAP;
2107 if (glt->tiledepth > 1)
2108 glt->d3daddressw = D3DTADDRESS_WRAP;
2110 glt->d3dmipmaplodbias = 0;
2111 glt->d3dmaxmiplevel = 0;
2112 glt->d3dmaxmiplevelfilter = 0;
2113 if (glt->flags & TEXF_MIPMAP)
2115 glt->d3dminfilter = d3d_filter_mipmin;
2116 glt->d3dmagfilter = d3d_filter_mipmag;
2117 glt->d3dmipfilter = d3d_filter_mipmix;
2121 glt->d3dminfilter = d3d_filter_flatmin;
2122 glt->d3dmagfilter = d3d_filter_flatmag;
2123 glt->d3dmipfilter = d3d_filter_flatmix;
2127 case RENDERPATH_D3D10:
2128 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2130 case RENDERPATH_D3D11:
2131 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2136 return (rtexture_t *)glt;
2139 int R_TextureWidth(rtexture_t *rt)
2141 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2144 int R_TextureHeight(rtexture_t *rt)
2146 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2149 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
2151 gltexture_t *glt = (gltexture_t *)rt;
2153 Host_Error("R_UpdateTexture: no data supplied");
2155 Host_Error("R_UpdateTexture: no texture supplied");
2156 if (!glt->texnum && !glt->d3dtexture)
2158 Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", glt, glt->identifier, glt->pool);
2161 // update part of the texture
2162 if (glt->bufferpixels)
2165 int bpp = glt->bytesperpixel;
2166 int inputskip = width*bpp;
2167 int outputskip = glt->tilewidth*bpp;
2168 const unsigned char *input = data;
2169 unsigned char *output = glt->bufferpixels;
2179 input -= y*inputskip;
2182 if (width > glt->tilewidth - x)
2183 width = glt->tilewidth - x;
2184 if (height > glt->tileheight - y)
2185 height = glt->tileheight - y;
2186 if (width < 1 || height < 1)
2189 glt->buffermodified = true;
2190 output += y*outputskip + x*bpp;
2191 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2192 memcpy(output, input, width*bpp);
2195 R_Upload(glt, data, x, y, 0, width, height, 1);
2198 int R_RealGetTexture(rtexture_t *rt)
2203 glt = (gltexture_t *)rt;
2204 if (glt->flags & GLTEXF_DYNAMIC)
2205 R_UpdateDynamicTexture(glt);
2206 if (glt->buffermodified && glt->bufferpixels)
2208 glt->buffermodified = false;
2209 R_Upload(glt, glt->bufferpixels, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth);
2218 void R_ClearTexture (rtexture_t *rt)
2220 gltexture_t *glt = (gltexture_t *)rt;
2222 R_Upload( glt, NULL, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth );
2225 int R_PicmipForFlags(int flags)
2228 if(flags & TEXF_PICMIP)
2230 miplevel += gl_picmip.integer;
2231 if (flags & TEXF_ISWORLD)
2233 if (r_picmipworld.integer)
2234 miplevel += gl_picmip_world.integer;
2238 else if (flags & TEXF_ISSPRITE)
2240 if (r_picmipsprites.integer)
2241 miplevel += gl_picmip_sprites.integer;
2246 miplevel += gl_picmip_other.integer;
2248 return max(0, miplevel);