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"};
35 qboolean gl_filter_force = false;
36 int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
37 int gl_filter_mag = GL_LINEAR;
40 int d3d_filter_flatmin = D3DTEXF_LINEAR;
41 int d3d_filter_flatmag = D3DTEXF_LINEAR;
42 int d3d_filter_flatmix = D3DTEXF_POINT;
43 int d3d_filter_mipmin = D3DTEXF_LINEAR;
44 int d3d_filter_mipmag = D3DTEXF_LINEAR;
45 int d3d_filter_mipmix = D3DTEXF_LINEAR;
46 int d3d_filter_nomip = false;
50 static mempool_t *texturemempool;
51 static memexpandablearray_t texturearray;
53 // note: this must not conflict with TEXF_ flags in r_textures.h
54 // bitmask for mismatch checking
55 #define GLTEXF_IMPORTANTBITS (0)
56 // dynamic texture (treat texnum == 0 differently)
57 #define GLTEXF_DYNAMIC 0x00080000
59 typedef struct textypeinfo_s
62 int inputbytesperpixel;
63 int internalbytesperpixel;
64 float glinternalbytesperpixel;
72 static textypeinfo_t textype_palette = {TEXTYPE_PALETTE , 1, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE };
73 static textypeinfo_t textype_palette_alpha = {TEXTYPE_PALETTE , 1, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
74 static textypeinfo_t textype_rgba = {TEXTYPE_RGBA , 4, 4, 4.0f, 3 , GL_RGBA , GL_UNSIGNED_BYTE };
75 static textypeinfo_t textype_rgba_alpha = {TEXTYPE_RGBA , 4, 4, 4.0f, 4 , GL_RGBA , GL_UNSIGNED_BYTE };
76 static textypeinfo_t textype_rgba_compress = {TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
77 static textypeinfo_t textype_rgba_alpha_compress = {TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA , GL_UNSIGNED_BYTE };
78 static textypeinfo_t textype_bgra = {TEXTYPE_BGRA , 4, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE };
79 static textypeinfo_t textype_bgra_alpha = {TEXTYPE_BGRA , 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
80 static textypeinfo_t textype_bgra_compress = {TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
81 static textypeinfo_t textype_bgra_alpha_compress = {TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_BGRA , GL_UNSIGNED_BYTE };
82 static textypeinfo_t textype_shadowmap16 = {TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
83 static textypeinfo_t textype_shadowmap24 = {TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
84 static textypeinfo_t textype_alpha = {TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
85 static textypeinfo_t textype_dxt1 = {TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
86 static textypeinfo_t textype_dxt1a = {TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0 , 0 };
87 static textypeinfo_t textype_dxt3 = {TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0 , 0 };
88 static textypeinfo_t textype_dxt5 = {TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0 , 0 };
89 static textypeinfo_t textype_colorbuffer = {TEXTYPE_COLORBUFFER, 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
92 typedef enum gltexturetype_e
96 GLTEXTURETYPE_CUBEMAP,
97 GLTEXTURETYPE_RECTANGLE,
102 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_RECTANGLE_ARB};
103 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2, 2};
104 static int cubemapside[6] =
106 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
107 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
108 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
109 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
110 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
111 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
114 typedef struct gltexture_s
116 // this portion of the struct is exposed to the R_GetTexture macro for
117 // speed reasons, must be identical in rtexture_t!
118 int texnum; // GL texture slot number
119 qboolean dirty; // indicates that R_RealGetTexture should be called
120 int gltexturetypeenum; // used by R_Mesh_TexBind
121 // d3d stuff the backend needs
133 int d3dmaxmiplevelfilter;
134 int d3dmipmaplodbias;
138 // dynamic texture stuff [11/22/2007 Black]
139 updatecallback_t updatecallback;
140 void *updatacallback_data;
141 // --- [11/22/2007 Black]
143 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
144 unsigned char *bufferpixels;
145 qboolean buffermodified;
147 // pointer to texturepool (check this to see if the texture is allocated)
148 struct gltexturepool_s *pool;
149 // pointer to next texture in texturepool chain
150 struct gltexture_s *chain;
151 // name of the texture (this might be removed someday), no duplicates
152 char identifier[MAX_QPATH + 32];
153 // original data size in *inputtexels
154 int inputwidth, inputheight, inputdepth;
155 // copy of the original texture(s) supplied to the upload function, for
156 // delayed uploads (non-precached)
157 unsigned char *inputtexels;
158 // original data size in *inputtexels
160 // flags supplied to the LoadTexture function
161 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
165 // pointer to one of the textype_ structs
166 textypeinfo_t *textype;
167 // one of the GLTEXTURETYPE_ values
169 // palette if the texture is TEXTYPE_PALETTE
170 const unsigned int *palette;
171 // actual stored texture size after gl_picmip and gl_max_size are applied
172 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
173 int tilewidth, tileheight, tiledepth;
174 // 1 or 6 depending on texturetype
176 // how many mipmap levels in this texture
180 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
183 int glinternalformat;
184 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
189 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
191 typedef struct gltexturepool_s
193 unsigned int sentinel;
194 struct gltexture_s *gltchain;
195 struct gltexturepool_s *next;
199 static gltexturepool_t *gltexturepoolchain = NULL;
201 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
202 static int resizebuffersize = 0;
203 static const unsigned char *texturebuffer;
205 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
210 return &textype_dxt1;
212 return &textype_dxt1a;
214 return &textype_dxt3;
216 return &textype_dxt5;
217 case TEXTYPE_PALETTE:
218 return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
220 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.arb_texture_compression)
221 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress;
222 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba;
224 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.arb_texture_compression)
225 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress;
226 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra;
228 return &textype_alpha;
229 case TEXTYPE_SHADOWMAP:
230 return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
231 case TEXTYPE_COLORBUFFER:
232 return &textype_colorbuffer;
234 Host_Error("R_GetTexTypeInfo: unknown texture format");
240 // dynamic texture code [11/22/2007 Black]
241 void R_MarkDirtyTexture(rtexture_t *rt) {
242 gltexture_t *glt = (gltexture_t*) rt;
247 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
248 if (glt->flags & GLTEXF_DYNAMIC)
250 // mark it as dirty, so R_RealGetTexture gets called
255 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
256 gltexture_t *glt = (gltexture_t*) rt;
261 glt->flags |= GLTEXF_DYNAMIC;
262 glt->updatecallback = updatecallback;
263 glt->updatacallback_data = data;
266 static void R_UpdateDynamicTexture(gltexture_t *glt) {
268 if( glt->updatecallback ) {
269 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
273 void R_PurgeTexture(rtexture_t *rt)
275 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
280 void R_FreeTexture(rtexture_t *rt)
282 gltexture_t *glt, **gltpointer;
284 glt = (gltexture_t *)rt;
286 Host_Error("R_FreeTexture: texture == NULL");
288 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
289 if (*gltpointer == glt)
290 *gltpointer = glt->chain;
292 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
297 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
300 if (glt->inputtexels)
301 Mem_Free(glt->inputtexels);
302 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
305 rtexturepool_t *R_AllocTexturePool(void)
307 gltexturepool_t *pool;
308 if (texturemempool == NULL)
310 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
313 pool->next = gltexturepoolchain;
314 gltexturepoolchain = pool;
315 pool->sentinel = TEXTUREPOOL_SENTINEL;
316 return (rtexturepool_t *)pool;
319 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
321 gltexturepool_t *pool, **poolpointer;
322 if (rtexturepool == NULL)
324 if (*rtexturepool == NULL)
326 pool = (gltexturepool_t *)(*rtexturepool);
327 *rtexturepool = NULL;
328 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
329 Host_Error("R_FreeTexturePool: pool already freed");
330 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
331 if (*poolpointer == pool)
332 *poolpointer = pool->next;
334 Host_Error("R_FreeTexturePool: pool not linked");
335 while (pool->gltchain)
336 R_FreeTexture((rtexture_t *)pool->gltchain);
341 typedef struct glmode_s
344 int minification, magnification;
348 static glmode_t modes[6] =
350 {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
351 {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
352 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
353 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
354 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
355 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
359 typedef struct d3dmode_s
366 static d3dmode_t d3dmodes[6] =
368 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
369 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
370 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
371 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
372 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
373 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
377 static void GL_TextureMode_f (void)
382 gltexturepool_t *pool;
386 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
387 for (i = 0;i < 6;i++)
389 if (gl_filter_min == modes[i].minification)
391 Con_Printf("%s\n", modes[i].name);
395 Con_Print("current filter is unknown???\n");
399 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
400 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
404 Con_Print("bad filter name\n");
408 gl_filter_min = modes[i].minification;
409 gl_filter_mag = modes[i].magnification;
410 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
412 switch(vid.renderpath)
414 case RENDERPATH_GL11:
415 case RENDERPATH_GL13:
416 case RENDERPATH_GL20:
417 case RENDERPATH_CGGL:
418 // change all the existing mipmap texture objects
419 // FIXME: force renderer(/client/something?) restart instead?
422 for (pool = gltexturepoolchain;pool;pool = pool->next)
424 for (glt = pool->gltchain;glt;glt = glt->chain)
426 // only update already uploaded images
427 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
429 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
430 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
431 if (glt->flags & TEXF_MIPMAP)
433 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
437 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
439 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
440 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
445 case RENDERPATH_D3D9:
447 d3d_filter_flatmin = d3dmodes[i].m1;
448 d3d_filter_flatmag = d3dmodes[i].m1;
449 d3d_filter_flatmix = D3DTEXF_POINT;
450 d3d_filter_mipmin = d3dmodes[i].m1;
451 d3d_filter_mipmag = d3dmodes[i].m1;
452 d3d_filter_mipmix = d3dmodes[i].m2;
453 d3d_filter_nomip = i < 2;
454 if (gl_texture_anisotropy.integer > 1 && i == 5)
455 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
456 for (pool = gltexturepoolchain;pool;pool = pool->next)
458 for (glt = pool->gltchain;glt;glt = glt->chain)
460 // only update already uploaded images
461 if (glt->d3dtexture && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
463 if (glt->flags & TEXF_MIPMAP)
465 glt->d3dminfilter = d3d_filter_mipmin;
466 glt->d3dmagfilter = d3d_filter_mipmag;
467 glt->d3dmipfilter = d3d_filter_mipmix;
468 glt->d3dmaxmiplevelfilter = 0;
472 glt->d3dminfilter = d3d_filter_flatmin;
473 glt->d3dmagfilter = d3d_filter_flatmag;
474 glt->d3dmipfilter = d3d_filter_flatmix;
475 glt->d3dmaxmiplevelfilter = 0;
485 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)
487 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
492 case GLTEXTURETYPE_2D:
493 maxsize = vid.maxtexturesize_2d;
494 if (flags & TEXF_PICMIP)
496 maxsize = bound(1, gl_max_size.integer, maxsize);
500 case GLTEXTURETYPE_3D:
501 maxsize = vid.maxtexturesize_3d;
503 case GLTEXTURETYPE_CUBEMAP:
504 maxsize = vid.maxtexturesize_cubemap;
510 if (vid.support.arb_texture_non_power_of_two)
511 width2 = min(inwidth >> picmip, maxsize);
514 for (width2 = 1;width2 < inwidth;width2 <<= 1);
515 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
517 *outwidth = max(1, width2);
521 if (vid.support.arb_texture_non_power_of_two)
522 height2 = min(inheight >> picmip, maxsize);
525 for (height2 = 1;height2 < inheight;height2 <<= 1);
526 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
528 *outheight = max(1, height2);
532 if (vid.support.arb_texture_non_power_of_two)
533 depth2 = min(indepth >> picmip, maxsize);
536 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
537 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
539 *outdepth = max(1, depth2);
543 if (flags & TEXF_MIPMAP)
545 int extent = max(width2, max(height2, depth2));
550 *outmiplevels = miplevels;
554 static int R_CalcTexelDataSize (gltexture_t *glt)
556 int width2, height2, depth2, size;
558 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
560 size = width2 * height2 * depth2;
562 if (glt->flags & TEXF_MIPMAP)
564 while (width2 > 1 || height2 > 1 || depth2 > 1)
572 size += width2 * height2 * depth2;
576 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
579 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
583 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
584 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
586 gltexturepool_t *pool;
588 Con_Print("glsize input loaded mip alpha name\n");
589 for (pool = gltexturepoolchain;pool;pool = pool->next)
597 for (glt = pool->gltchain;glt;glt = glt->chain)
599 glsize = R_CalcTexelDataSize(glt);
600 isloaded = glt->texnum != 0;
602 pooltotalt += glsize;
603 pooltotalp += glt->inputdatasize;
607 poolloadedt += glsize;
608 poolloadedp += glt->inputdatasize;
611 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);
614 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);
615 sumtotal += pooltotal;
616 sumtotalt += pooltotalt;
617 sumtotalp += pooltotalp;
618 sumloaded += poolloaded;
619 sumloadedt += poolloadedt;
620 sumloadedp += poolloadedp;
623 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);
626 static void R_TextureStats_f(void)
628 R_TextureStats_Print(true, true, true);
631 static void r_textures_start(void)
633 switch(vid.renderpath)
635 case RENDERPATH_GL11:
636 case RENDERPATH_GL13:
637 case RENDERPATH_GL20:
638 case RENDERPATH_CGGL:
639 // LordHavoc: allow any alignment
641 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
642 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
644 case RENDERPATH_D3D9:
646 case RENDERPATH_D3D10:
647 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
649 case RENDERPATH_D3D11:
650 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
654 texturemempool = Mem_AllocPool("texture management", 0, NULL);
655 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
657 // Disable JPEG screenshots if the DLL isn't loaded
658 if (! JPEG_OpenLibrary ())
659 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
660 if (! PNG_OpenLibrary ())
661 Cvar_SetValueQuick (&scr_screenshot_png, 0);
664 static void r_textures_shutdown(void)
666 rtexturepool_t *temp;
668 JPEG_CloseLibrary ();
670 while(gltexturepoolchain)
672 temp = (rtexturepool_t *) gltexturepoolchain;
673 R_FreeTexturePool(&temp);
676 resizebuffersize = 0;
678 colorconvertbuffer = NULL;
679 texturebuffer = NULL;
680 Mem_ExpandableArray_FreeArray(&texturearray);
681 Mem_FreePool(&texturemempool);
684 static void r_textures_newmap(void)
688 static void r_textures_devicelost(void)
692 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
693 for (i = 0;i < endindex;i++)
695 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
696 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
698 switch(vid.renderpath)
700 case RENDERPATH_GL11:
701 case RENDERPATH_GL13:
702 case RENDERPATH_GL20:
703 case RENDERPATH_CGGL:
705 case RENDERPATH_D3D9:
707 if (glt->tiledepth > 1)
708 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
709 else if (glt->sides == 6)
710 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
712 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
713 glt->d3dtexture = NULL;
716 case RENDERPATH_D3D10:
717 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
719 case RENDERPATH_D3D11:
720 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
726 static void r_textures_devicerestored(void)
730 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
731 for (i = 0;i < endindex;i++)
733 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
734 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
736 switch(vid.renderpath)
738 case RENDERPATH_GL11:
739 case RENDERPATH_GL13:
740 case RENDERPATH_GL20:
741 case RENDERPATH_CGGL:
743 case RENDERPATH_D3D9:
747 if (glt->tiledepth > 1)
749 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)))
750 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
752 else if (glt->sides == 6)
754 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
755 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
759 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)))
760 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
765 case RENDERPATH_D3D10:
766 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
768 case RENDERPATH_D3D11:
769 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
776 void R_Textures_Init (void)
778 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");
779 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
780 Cvar_RegisterVariable (&gl_max_size);
781 Cvar_RegisterVariable (&gl_picmip);
782 Cvar_RegisterVariable (&gl_picmip_world);
783 Cvar_RegisterVariable (&r_picmipworld);
784 Cvar_RegisterVariable (&gl_picmip_sprites);
785 Cvar_RegisterVariable (&r_picmipsprites);
786 Cvar_RegisterVariable (&gl_picmip_other);
787 Cvar_RegisterVariable (&gl_max_lightmapsize);
788 Cvar_RegisterVariable (&r_lerpimages);
789 Cvar_RegisterVariable (&gl_texture_anisotropy);
790 Cvar_RegisterVariable (&gl_texturecompression);
791 Cvar_RegisterVariable (&gl_texturecompression_color);
792 Cvar_RegisterVariable (&gl_texturecompression_normal);
793 Cvar_RegisterVariable (&gl_texturecompression_gloss);
794 Cvar_RegisterVariable (&gl_texturecompression_glow);
795 Cvar_RegisterVariable (&gl_texturecompression_2d);
796 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
797 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
798 Cvar_RegisterVariable (&gl_texturecompression_sky);
799 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
800 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
801 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
803 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
806 void R_Textures_Frame (void)
808 static int old_aniso = 0;
810 // could do procedural texture animation here, if we keep track of which
811 // textures were accessed this frame...
813 // free the resize buffers
814 resizebuffersize = 0;
817 Mem_Free(resizebuffer);
820 if (colorconvertbuffer)
822 Mem_Free(colorconvertbuffer);
823 colorconvertbuffer = NULL;
826 if (old_aniso != gl_texture_anisotropy.integer)
829 gltexturepool_t *pool;
832 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
834 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
836 switch(vid.renderpath)
838 case RENDERPATH_GL11:
839 case RENDERPATH_GL13:
840 case RENDERPATH_GL20:
841 case RENDERPATH_CGGL:
844 for (pool = gltexturepoolchain;pool;pool = pool->next)
846 for (glt = pool->gltchain;glt;glt = glt->chain)
848 // only update already uploaded images
849 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
851 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
853 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
854 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
856 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
861 case RENDERPATH_D3D9:
862 case RENDERPATH_D3D10:
863 case RENDERPATH_D3D11:
869 void R_MakeResizeBufferBigger(int size)
871 if (resizebuffersize < size)
873 resizebuffersize = size;
875 Mem_Free(resizebuffer);
876 if (colorconvertbuffer)
877 Mem_Free(colorconvertbuffer);
878 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
879 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
880 if (!resizebuffer || !colorconvertbuffer)
881 Host_Error("R_Upload: out of memory");
885 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
887 int textureenum = gltexturetypeenums[texturetype];
888 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
892 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
894 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
895 if (gl_texture_anisotropy.integer != aniso)
896 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
897 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
899 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
900 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
901 if (gltexturetypedimensions[texturetype] >= 3)
903 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
907 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
909 if (flags & TEXF_MIPMAP)
911 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
915 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
917 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
919 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
921 if (flags & TEXF_MIPMAP)
923 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
925 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
929 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
934 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
936 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
940 if (flags & TEXF_MIPMAP)
942 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
946 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
948 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
951 if (textype == TEXTYPE_SHADOWMAP)
953 if (vid.support.arb_shadow)
955 if (flags & TEXF_COMPARE)
957 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
961 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
963 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
965 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
971 static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
973 int i, mip, width, height, depth;
974 GLint oldbindtexnum = 0;
975 const unsigned char *prevbuffer;
978 switch(vid.renderpath)
980 case RENDERPATH_GL11:
981 case RENDERPATH_GL13:
982 case RENDERPATH_GL20:
983 case RENDERPATH_CGGL:
986 // we need to restore the texture binding after finishing the upload
988 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
989 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
991 case RENDERPATH_D3D9:
992 case RENDERPATH_D3D10:
993 case RENDERPATH_D3D11:
997 // these are rounded up versions of the size to do better resampling
998 if (vid.support.arb_texture_non_power_of_two || glt->texturetype == GLTEXTURETYPE_RECTANGLE)
1000 width = glt->inputwidth;
1001 height = glt->inputheight;
1002 depth = glt->inputdepth;
1006 for (width = 1;width < glt->inputwidth ;width <<= 1);
1007 for (height = 1;height < glt->inputheight;height <<= 1);
1008 for (depth = 1;depth < glt->inputdepth ;depth <<= 1);
1011 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1012 R_MakeResizeBufferBigger(fragwidth * fragheight * fragdepth * glt->sides * glt->bytesperpixel);
1014 if (prevbuffer == NULL)
1016 memset(resizebuffer, 0, fragwidth * fragheight * fragdepth * glt->bytesperpixel);
1017 prevbuffer = resizebuffer;
1019 else if (glt->textype->textype == TEXTYPE_PALETTE)
1021 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1022 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, fragwidth * fragheight * fragdepth * glt->sides, glt->palette);
1023 prevbuffer = colorconvertbuffer;
1026 // upload the image - preferring to do only complete uploads (drivers do not really like partial updates)
1028 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))
1030 // update a portion of the image
1031 if (glt->texturetype != GLTEXTURETYPE_2D)
1032 Sys_Error("R_Upload: partial update of type other than 2D");
1033 switch(vid.renderpath)
1035 case RENDERPATH_GL11:
1036 case RENDERPATH_GL13:
1037 case RENDERPATH_GL20:
1038 case RENDERPATH_CGGL:
1039 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1040 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1042 case RENDERPATH_D3D9:
1046 D3DLOCKED_RECT d3dlockedrect;
1048 memset(&d3drect, 0, sizeof(d3drect));
1049 d3drect.left = fragx;
1050 d3drect.top = fragy;
1051 d3drect.right = fragx+fragwidth;
1052 d3drect.bottom = fragy+fragheight;
1053 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1055 for (y = 0;y < fragheight;y++)
1056 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, (unsigned char *)prevbuffer + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1057 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1062 case RENDERPATH_D3D10:
1063 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1065 case RENDERPATH_D3D11:
1066 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1072 if (fragx || fragy || fragz || glt->inputwidth != fragwidth || glt->inputheight != fragheight || glt->inputdepth != fragdepth)
1073 Host_Error("R_Upload: partial update not allowed on initial upload or in combination with PICMIP or MIPMAP\n");
1075 // cubemaps contain multiple images and thus get processed a bit differently
1076 if (glt->texturetype != GLTEXTURETYPE_CUBEMAP)
1078 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1080 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1081 prevbuffer = resizebuffer;
1084 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1086 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1087 prevbuffer = resizebuffer;
1091 switch(vid.renderpath)
1093 case RENDERPATH_GL11:
1094 case RENDERPATH_GL13:
1095 case RENDERPATH_GL20:
1096 case RENDERPATH_CGGL:
1097 if (qglGetCompressedTexImageARB)
1099 if (gl_texturecompression.integer >= 2)
1100 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1102 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1105 switch(glt->texturetype)
1107 case GLTEXTURETYPE_2D:
1108 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1109 if (glt->flags & TEXF_MIPMAP)
1111 while (width > 1 || height > 1 || depth > 1)
1113 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1114 prevbuffer = resizebuffer;
1115 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1119 case GLTEXTURETYPE_3D:
1120 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1121 if (glt->flags & TEXF_MIPMAP)
1123 while (width > 1 || height > 1 || depth > 1)
1125 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1126 prevbuffer = resizebuffer;
1127 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1131 case GLTEXTURETYPE_CUBEMAP:
1132 // convert and upload each side in turn,
1133 // from a continuous block of input texels
1134 texturebuffer = (unsigned char *)prevbuffer;
1135 for (i = 0;i < 6;i++)
1137 prevbuffer = texturebuffer;
1138 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1139 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1141 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1142 prevbuffer = resizebuffer;
1145 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1147 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1148 prevbuffer = resizebuffer;
1151 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1152 if (glt->flags & TEXF_MIPMAP)
1154 while (width > 1 || height > 1 || depth > 1)
1156 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1157 prevbuffer = resizebuffer;
1158 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1163 case GLTEXTURETYPE_RECTANGLE:
1164 qglTexImage2D(GL_TEXTURE_RECTANGLE_ARB, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, NULL);CHECKGLERROR
1167 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1168 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1170 case RENDERPATH_D3D9:
1172 if (!(glt->flags & TEXF_RENDERTARGET))
1174 D3DLOCKED_RECT d3dlockedrect;
1175 D3DLOCKED_BOX d3dlockedbox;
1176 switch(glt->texturetype)
1178 case GLTEXTURETYPE_2D:
1179 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1182 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1184 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1185 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1188 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1190 while (width > 1 || height > 1 || depth > 1)
1192 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1193 prevbuffer = resizebuffer;
1194 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1196 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1197 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1203 case GLTEXTURETYPE_3D:
1204 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1206 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1207 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1208 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1211 if (glt->flags & TEXF_MIPMAP)
1213 while (width > 1 || height > 1 || depth > 1)
1215 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1216 prevbuffer = resizebuffer;
1217 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1219 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1220 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1221 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1227 case GLTEXTURETYPE_CUBEMAP:
1228 // convert and upload each side in turn,
1229 // from a continuous block of input texels
1230 texturebuffer = (unsigned char *)prevbuffer;
1231 for (i = 0;i < 6;i++)
1233 prevbuffer = texturebuffer;
1234 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1235 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1237 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1238 prevbuffer = resizebuffer;
1241 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1243 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1244 prevbuffer = resizebuffer;
1247 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1249 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1250 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1253 if (glt->flags & TEXF_MIPMAP)
1255 while (width > 1 || height > 1 || depth > 1)
1257 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1258 prevbuffer = resizebuffer;
1259 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1261 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1262 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1269 case GLTEXTURETYPE_RECTANGLE:
1270 Sys_Error("Direct3D does not have RECTANGLE textures\n");
1274 glt->d3daddressw = 0;
1275 if (glt->flags & TEXF_CLAMP)
1277 glt->d3daddressu = D3DTADDRESS_CLAMP;
1278 glt->d3daddressv = D3DTADDRESS_CLAMP;
1279 if (glt->tiledepth > 1)
1280 glt->d3daddressw = D3DTADDRESS_CLAMP;
1284 glt->d3daddressu = D3DTADDRESS_WRAP;
1285 glt->d3daddressv = D3DTADDRESS_WRAP;
1286 if (glt->tiledepth > 1)
1287 glt->d3daddressw = D3DTADDRESS_WRAP;
1289 glt->d3dmipmaplodbias = 0;
1290 glt->d3dmaxmiplevel = 0;
1291 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1292 if (glt->flags & TEXF_FORCELINEAR)
1294 glt->d3dminfilter = D3DTEXF_LINEAR;
1295 glt->d3dmagfilter = D3DTEXF_LINEAR;
1296 glt->d3dmipfilter = D3DTEXF_POINT;
1298 else if (glt->flags & TEXF_FORCENEAREST)
1300 glt->d3dminfilter = D3DTEXF_POINT;
1301 glt->d3dmagfilter = D3DTEXF_POINT;
1302 glt->d3dmipfilter = D3DTEXF_POINT;
1304 else if (glt->flags & TEXF_MIPMAP)
1306 glt->d3dminfilter = d3d_filter_mipmin;
1307 glt->d3dmagfilter = d3d_filter_mipmag;
1308 glt->d3dmipfilter = d3d_filter_mipmix;
1312 glt->d3dminfilter = d3d_filter_flatmin;
1313 glt->d3dmagfilter = d3d_filter_flatmag;
1314 glt->d3dmipfilter = d3d_filter_flatmix;
1318 case RENDERPATH_D3D10:
1319 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1321 case RENDERPATH_D3D11:
1322 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1328 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)
1332 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1333 textypeinfo_t *texinfo, *texinfo2;
1334 unsigned char *temppixels = NULL;
1336 if (cls.state == ca_dedicated)
1339 if (texturetype == GLTEXTURETYPE_RECTANGLE && !vid.support.arb_texture_rectangle)
1341 Con_Printf ("R_LoadTexture: rectangle texture not supported by driver\n");
1344 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1346 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1349 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1351 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1355 texinfo = R_GetTexTypeInfo(textype, flags);
1356 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1359 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1363 if (textype == TEXTYPE_RGBA)
1366 static int rgbaswapindices[4] = {2, 1, 0, 3};
1367 textype = TEXTYPE_BGRA;
1368 texinfo = R_GetTexTypeInfo(textype, flags);
1369 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1370 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1374 // clear the alpha flag if the texture has no transparent pixels
1377 case TEXTYPE_PALETTE:
1378 if (flags & TEXF_ALPHA)
1380 flags &= ~TEXF_ALPHA;
1383 for (i = 0;i < size;i++)
1385 if (((unsigned char *)&palette[data[i]])[3] < 255)
1387 flags |= TEXF_ALPHA;
1396 if (flags & TEXF_ALPHA)
1398 flags &= ~TEXF_ALPHA;
1401 for (i = 3;i < size;i += 4)
1405 flags |= TEXF_ALPHA;
1412 case TEXTYPE_SHADOWMAP:
1419 flags |= TEXF_ALPHA;
1422 flags |= TEXF_ALPHA;
1424 case TEXTYPE_COLORBUFFER:
1425 flags |= TEXF_ALPHA;
1428 Sys_Error("R_LoadTexture: unknown texture type");
1431 texinfo2 = R_GetTexTypeInfo(textype, flags);
1432 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1435 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1437 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1439 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1441 glt->chain = pool->gltchain;
1442 pool->gltchain = glt;
1443 glt->inputwidth = width;
1444 glt->inputheight = height;
1445 glt->inputdepth = depth;
1447 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
1448 glt->textype = texinfo;
1449 glt->texturetype = texturetype;
1450 glt->inputdatasize = size;
1451 glt->palette = palette;
1452 glt->glinternalformat = texinfo->glinternalformat;
1453 glt->glformat = texinfo->glformat;
1454 glt->gltype = texinfo->gltype;
1455 glt->bytesperpixel = texinfo->internalbytesperpixel;
1456 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1459 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1460 // init the dynamic texture attributes, too [11/22/2007 Black]
1461 glt->updatecallback = NULL;
1462 glt->updatacallback_data = NULL;
1464 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1466 // upload the texture
1467 // data may be NULL (blank texture for dynamic rendering)
1468 switch(vid.renderpath)
1470 case RENDERPATH_GL11:
1471 case RENDERPATH_GL13:
1472 case RENDERPATH_GL20:
1473 case RENDERPATH_CGGL:
1475 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1477 case RENDERPATH_D3D9:
1480 D3DFORMAT d3dformat;
1485 d3dpool = D3DPOOL_MANAGED;
1486 if (flags & TEXF_RENDERTARGET)
1488 d3dusage |= D3DUSAGE_RENDERTARGET;
1489 d3dpool = D3DPOOL_DEFAULT;
1493 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1494 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1495 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1496 case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1497 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1498 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1499 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1501 glt->d3dformat = d3dformat;
1502 glt->d3dusage = d3dusage;
1503 glt->d3dpool = d3dpool;
1504 if (glt->tiledepth > 1)
1506 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)))
1507 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1509 else if (glt->sides == 6)
1511 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1512 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1516 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)))
1517 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1522 case RENDERPATH_D3D10:
1523 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1525 case RENDERPATH_D3D11:
1526 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1530 R_Upload(glt, data, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
1531 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1532 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1534 // free any temporary processing buffer we allocated...
1536 Mem_Free(temppixels);
1538 // texture converting and uploading can take a while, so make sure we're sending keepalives
1539 // FIXME: this causes rendering during R_Shadow_DrawLights
1540 // CL_KeepaliveMessage(false);
1542 return (rtexture_t *)glt;
1545 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)
1547 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1550 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)
1552 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1555 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)
1557 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1560 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)
1562 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_RECTANGLE, data, palette);
1565 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1567 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1569 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1571 flags |= TEXF_FORCENEAREST;
1572 if (precision <= 16)
1573 flags |= TEXF_LOWPRECISION;
1577 rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1579 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
1582 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1584 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1587 rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter)
1589 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
1592 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed)
1594 gltexture_t *glt = (gltexture_t *)rt;
1597 int bytesperpixel = 0;
1598 int bytesperblock = 0;
1600 int dds_format_flags;
1608 GLint internalformat;
1609 const char *ddsfourcc;
1611 return -1; // NULL pointer
1612 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1613 return -2; // broken driver - crashes on reading internal format
1614 if (!qglGetTexLevelParameteriv)
1616 GL_ActiveTexture(0);
1617 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1618 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1619 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1620 switch(internalformat)
1622 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1623 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1624 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1625 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1626 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1628 if (!bytesperblock && skipuncompressed)
1629 return -3; // skipped
1630 memset(mipinfo, 0, sizeof(mipinfo));
1631 mipinfo[0][0] = glt->tilewidth;
1632 mipinfo[0][1] = glt->tileheight;
1634 if (glt->flags & TEXF_MIPMAP)
1636 for (mip = 1;mip < 16;mip++)
1638 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1639 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1640 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1648 for (mip = 0;mip < mipmaps;mip++)
1650 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1651 mipinfo[mip][3] = ddssize;
1652 ddssize += mipinfo[mip][2];
1654 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1657 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1661 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1662 dds_format_flags = 0x4; // DDPF_FOURCC
1666 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1667 dds_format_flags = 0x41; // DDPF_RGB | DDPF_ALPHAPIXELS
1671 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1672 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1674 memcpy(dds, "DDS ", 4);
1675 StoreLittleLong(dds+4, ddssize);
1676 StoreLittleLong(dds+8, dds_flags);
1677 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1678 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1679 StoreLittleLong(dds+24, 1); // depth
1680 StoreLittleLong(dds+28, mipmaps); // mipmaps
1681 StoreLittleLong(dds+76, 32); // format size
1682 StoreLittleLong(dds+80, dds_format_flags);
1683 StoreLittleLong(dds+108, dds_caps1);
1684 StoreLittleLong(dds+112, dds_caps2);
1687 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1688 memcpy(dds+84, ddsfourcc, 4);
1689 for (mip = 0;mip < mipmaps;mip++)
1691 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1696 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1697 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1698 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1699 for (mip = 0;mip < mipmaps;mip++)
1701 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1704 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1705 ret = FS_WriteFile(filename, dds, ddssize);
1707 return ret ? ddssize : -5;
1710 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
1712 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1715 int bytesperblock, bytesperpixel;
1718 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1719 textypeinfo_t *texinfo;
1720 int mip, mipwidth, mipheight, mipsize;
1722 GLint oldbindtexnum = 0;
1723 const unsigned char *mippixels, *ddspixels;
1725 fs_offset_t ddsfilesize;
1726 unsigned int ddssize;
1728 if (cls.state == ca_dedicated)
1731 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1732 ddssize = ddsfilesize;
1736 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1737 return NULL; // not found
1740 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1743 Con_Printf("^1%s: not a DDS image\n", filename);
1747 //dds_flags = BuffLittleLong(dds+8);
1748 dds_format_flags = BuffLittleLong(dds+80);
1749 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1750 dds_width = BuffLittleLong(dds+16);
1751 dds_height = BuffLittleLong(dds+12);
1752 ddspixels = dds + 128;
1754 flags &= ~TEXF_ALPHA;
1755 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1757 // very sloppy BGRA 32bit identification
1758 textype = TEXTYPE_BGRA;
1761 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1762 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1765 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1769 for (i = 3;i < size;i += 4)
1770 if (ddspixels[i] < 255)
1773 flags &= ~TEXF_ALPHA;
1775 else if (!memcmp(dds+84, "DXT1", 4))
1777 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1778 // LordHavoc: it is my belief that this does not infringe on the
1779 // patent because it is not decoding pixels...
1780 textype = TEXTYPE_DXT1;
1783 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1784 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1785 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1788 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1791 for (i = 0;i < size;i += bytesperblock)
1792 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1795 textype = TEXTYPE_DXT1A;
1797 flags &= ~TEXF_ALPHA;
1799 else if (!memcmp(dds+84, "DXT3", 4))
1801 textype = TEXTYPE_DXT3;
1804 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1805 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1808 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1812 else if (!memcmp(dds+84, "DXT5", 4))
1814 textype = TEXTYPE_DXT5;
1817 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1818 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1821 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1828 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1832 // return whether this texture is transparent
1834 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1836 // calculate average color if requested
1840 Vector4Clear(avgcolor);
1843 for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
1845 c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
1846 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1847 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
1848 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
1850 f = (float)bytesperblock / size;
1851 avgcolor[0] *= (0.5f / 31.0f) * f;
1852 avgcolor[1] *= (0.5f / 63.0f) * f;
1853 avgcolor[2] *= (0.5f / 31.0f) * f;
1854 avgcolor[3] = 1; // too hard to calculate
1858 for (i = 0;i < size;i += 4)
1860 avgcolor[0] += ddspixels[i+2];
1861 avgcolor[1] += ddspixels[i+1];
1862 avgcolor[2] += ddspixels[i];
1863 avgcolor[3] += ddspixels[i+3];
1865 f = (1.0f / 255.0f) * bytesperpixel / size;
1873 // this is where we apply gl_picmip
1874 mippixels = ddspixels;
1875 mipwidth = dds_width;
1876 mipheight = dds_height;
1877 while(miplevel >= 1 && dds_miplevels >= 1)
1879 if (mipwidth <= 1 && mipheight <= 1)
1881 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1882 mippixels += mipsize; // just skip
1891 if (dds_miplevels > 1)
1892 flags |= TEXF_MIPMAP;
1894 flags &= ~TEXF_MIPMAP;
1896 // if S3TC is not supported, there's very little we can do about it
1897 if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
1900 Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
1904 texinfo = R_GetTexTypeInfo(textype, flags);
1906 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1907 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
1909 glt->chain = pool->gltchain;
1910 pool->gltchain = glt;
1911 glt->inputwidth = mipwidth;
1912 glt->inputheight = mipheight;
1913 glt->inputdepth = 1;
1915 glt->textype = texinfo;
1916 glt->texturetype = GLTEXTURETYPE_2D;
1917 glt->inputdatasize = ddssize;
1918 glt->glinternalformat = texinfo->glinternalformat;
1919 glt->glformat = texinfo->glformat;
1920 glt->gltype = texinfo->gltype;
1921 glt->bytesperpixel = texinfo->internalbytesperpixel;
1923 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1924 glt->tilewidth = mipwidth;
1925 glt->tileheight = mipheight;
1927 glt->miplevels = dds_miplevels;
1929 // texture uploading can take a while, so make sure we're sending keepalives
1930 CL_KeepaliveMessage(false);
1932 // create the texture object
1933 switch(vid.renderpath)
1935 case RENDERPATH_GL11:
1936 case RENDERPATH_GL13:
1937 case RENDERPATH_GL20:
1938 case RENDERPATH_CGGL:
1940 GL_ActiveTexture(0);
1941 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1942 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1943 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1945 case RENDERPATH_D3D9:
1948 D3DFORMAT d3dformat;
1953 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1954 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
1955 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
1956 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
1957 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1960 d3dpool = D3DPOOL_MANAGED;
1961 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
1965 case RENDERPATH_D3D10:
1966 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1968 case RENDERPATH_D3D11:
1969 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1973 // upload the texture
1974 // we need to restore the texture binding after finishing the upload
1975 mipcomplete = false;
1977 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
1979 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1980 if (mippixels + mipsize > dds + ddssize)
1982 switch(vid.renderpath)
1984 case RENDERPATH_GL11:
1985 case RENDERPATH_GL13:
1986 case RENDERPATH_GL20:
1987 case RENDERPATH_CGGL:
1990 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
1994 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
1997 case RENDERPATH_D3D9:
2000 D3DLOCKED_RECT d3dlockedrect;
2001 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2003 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2004 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2010 case RENDERPATH_D3D10:
2011 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2013 case RENDERPATH_D3D11:
2014 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2017 mippixels += mipsize;
2018 if (mipwidth <= 1 && mipheight <= 1)
2029 // after upload we have to set some parameters...
2030 switch(vid.renderpath)
2032 case RENDERPATH_GL11:
2033 case RENDERPATH_GL13:
2034 case RENDERPATH_GL20:
2035 case RENDERPATH_CGGL:
2036 if (dds_miplevels >= 1 && !mipcomplete)
2038 // need to set GL_TEXTURE_MAX_LEVEL
2039 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2041 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2042 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2044 case RENDERPATH_D3D9:
2046 glt->d3daddressw = 0;
2047 if (glt->flags & TEXF_CLAMP)
2049 glt->d3daddressu = D3DTADDRESS_CLAMP;
2050 glt->d3daddressv = D3DTADDRESS_CLAMP;
2051 if (glt->tiledepth > 1)
2052 glt->d3daddressw = D3DTADDRESS_CLAMP;
2056 glt->d3daddressu = D3DTADDRESS_WRAP;
2057 glt->d3daddressv = D3DTADDRESS_WRAP;
2058 if (glt->tiledepth > 1)
2059 glt->d3daddressw = D3DTADDRESS_WRAP;
2061 glt->d3dmipmaplodbias = 0;
2062 glt->d3dmaxmiplevel = 0;
2063 glt->d3dmaxmiplevelfilter = 0;
2064 if (glt->flags & TEXF_MIPMAP)
2066 glt->d3dminfilter = d3d_filter_mipmin;
2067 glt->d3dmagfilter = d3d_filter_mipmag;
2068 glt->d3dmipfilter = d3d_filter_mipmix;
2072 glt->d3dminfilter = d3d_filter_flatmin;
2073 glt->d3dmagfilter = d3d_filter_flatmag;
2074 glt->d3dmipfilter = d3d_filter_flatmix;
2078 case RENDERPATH_D3D10:
2079 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2081 case RENDERPATH_D3D11:
2082 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2087 return (rtexture_t *)glt;
2090 int R_TextureWidth(rtexture_t *rt)
2092 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2095 int R_TextureHeight(rtexture_t *rt)
2097 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2100 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
2102 gltexture_t *glt = (gltexture_t *)rt;
2104 Host_Error("R_UpdateTexture: no data supplied");
2106 Host_Error("R_UpdateTexture: no texture supplied");
2107 if (!glt->texnum && !glt->d3dtexture)
2109 Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", glt, glt->identifier, glt->pool);
2112 // update part of the texture
2113 if (glt->bufferpixels)
2116 int bpp = glt->bytesperpixel;
2117 int inputskip = width*bpp;
2118 int outputskip = glt->tilewidth*bpp;
2119 const unsigned char *input = data;
2120 unsigned char *output = glt->bufferpixels;
2130 input -= y*inputskip;
2133 if (width > glt->tilewidth - x)
2134 width = glt->tilewidth - x;
2135 if (height > glt->tileheight - y)
2136 height = glt->tileheight - y;
2137 if (width < 1 || height < 1)
2140 glt->buffermodified = true;
2141 output += y*outputskip + x*bpp;
2142 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2143 memcpy(output, input, width*bpp);
2146 R_Upload(glt, data, x, y, 0, width, height, 1);
2149 int R_RealGetTexture(rtexture_t *rt)
2154 glt = (gltexture_t *)rt;
2155 if (glt->flags & GLTEXF_DYNAMIC)
2156 R_UpdateDynamicTexture(glt);
2157 if (glt->buffermodified && glt->bufferpixels)
2159 glt->buffermodified = false;
2160 R_Upload(glt, glt->bufferpixels, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth);
2169 void R_ClearTexture (rtexture_t *rt)
2171 gltexture_t *glt = (gltexture_t *)rt;
2173 R_Upload( glt, NULL, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth );
2176 int R_PicmipForFlags(int flags)
2179 if(flags & TEXF_PICMIP)
2181 miplevel += gl_picmip.integer;
2182 if (flags & TEXF_ISWORLD)
2184 if (r_picmipworld.integer)
2185 miplevel += gl_picmip_world.integer;
2189 else if (flags & TEXF_ISSPRITE)
2191 if (r_picmipsprites.integer)
2192 miplevel += gl_picmip_sprites.integer;
2197 miplevel += gl_picmip_other.integer;