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;
482 case RENDERPATH_D3D10:
483 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
485 case RENDERPATH_D3D11:
486 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
491 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)
493 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
498 case GLTEXTURETYPE_2D:
499 maxsize = vid.maxtexturesize_2d;
500 if (flags & TEXF_PICMIP)
502 maxsize = bound(1, gl_max_size.integer, maxsize);
506 case GLTEXTURETYPE_3D:
507 maxsize = vid.maxtexturesize_3d;
509 case GLTEXTURETYPE_CUBEMAP:
510 maxsize = vid.maxtexturesize_cubemap;
516 if (vid.support.arb_texture_non_power_of_two)
517 width2 = min(inwidth >> picmip, maxsize);
520 for (width2 = 1;width2 < inwidth;width2 <<= 1);
521 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
523 *outwidth = max(1, width2);
527 if (vid.support.arb_texture_non_power_of_two)
528 height2 = min(inheight >> picmip, maxsize);
531 for (height2 = 1;height2 < inheight;height2 <<= 1);
532 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
534 *outheight = max(1, height2);
538 if (vid.support.arb_texture_non_power_of_two)
539 depth2 = min(indepth >> picmip, maxsize);
542 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
543 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
545 *outdepth = max(1, depth2);
549 if (flags & TEXF_MIPMAP)
551 int extent = max(width2, max(height2, depth2));
556 *outmiplevels = miplevels;
560 static int R_CalcTexelDataSize (gltexture_t *glt)
562 int width2, height2, depth2, size;
564 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
566 size = width2 * height2 * depth2;
568 if (glt->flags & TEXF_MIPMAP)
570 while (width2 > 1 || height2 > 1 || depth2 > 1)
578 size += width2 * height2 * depth2;
582 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
585 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
589 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
590 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
592 gltexturepool_t *pool;
594 Con_Print("glsize input loaded mip alpha name\n");
595 for (pool = gltexturepoolchain;pool;pool = pool->next)
603 for (glt = pool->gltchain;glt;glt = glt->chain)
605 glsize = R_CalcTexelDataSize(glt);
606 isloaded = glt->texnum != 0;
608 pooltotalt += glsize;
609 pooltotalp += glt->inputdatasize;
613 poolloadedt += glsize;
614 poolloadedp += glt->inputdatasize;
617 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);
620 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);
621 sumtotal += pooltotal;
622 sumtotalt += pooltotalt;
623 sumtotalp += pooltotalp;
624 sumloaded += poolloaded;
625 sumloadedt += poolloadedt;
626 sumloadedp += poolloadedp;
629 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);
632 static void R_TextureStats_f(void)
634 R_TextureStats_Print(true, true, true);
637 static void r_textures_start(void)
639 switch(vid.renderpath)
641 case RENDERPATH_GL11:
642 case RENDERPATH_GL13:
643 case RENDERPATH_GL20:
644 case RENDERPATH_CGGL:
645 // LordHavoc: allow any alignment
647 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
648 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
650 case RENDERPATH_D3D9:
652 case RENDERPATH_D3D10:
653 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
655 case RENDERPATH_D3D11:
656 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
660 texturemempool = Mem_AllocPool("texture management", 0, NULL);
661 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
663 // Disable JPEG screenshots if the DLL isn't loaded
664 if (! JPEG_OpenLibrary ())
665 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
666 if (! PNG_OpenLibrary ())
667 Cvar_SetValueQuick (&scr_screenshot_png, 0);
670 static void r_textures_shutdown(void)
672 rtexturepool_t *temp;
674 JPEG_CloseLibrary ();
676 while(gltexturepoolchain)
678 temp = (rtexturepool_t *) gltexturepoolchain;
679 R_FreeTexturePool(&temp);
682 resizebuffersize = 0;
684 colorconvertbuffer = NULL;
685 texturebuffer = NULL;
686 Mem_ExpandableArray_FreeArray(&texturearray);
687 Mem_FreePool(&texturemempool);
690 static void r_textures_newmap(void)
694 static void r_textures_devicelost(void)
698 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
699 for (i = 0;i < endindex;i++)
701 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
702 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
704 switch(vid.renderpath)
706 case RENDERPATH_GL11:
707 case RENDERPATH_GL13:
708 case RENDERPATH_GL20:
709 case RENDERPATH_CGGL:
711 case RENDERPATH_D3D9:
713 if (glt->tiledepth > 1)
714 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
715 else if (glt->sides == 6)
716 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
718 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
719 glt->d3dtexture = NULL;
722 case RENDERPATH_D3D10:
723 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
725 case RENDERPATH_D3D11:
726 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
732 static void r_textures_devicerestored(void)
736 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
737 for (i = 0;i < endindex;i++)
739 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
740 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
742 switch(vid.renderpath)
744 case RENDERPATH_GL11:
745 case RENDERPATH_GL13:
746 case RENDERPATH_GL20:
747 case RENDERPATH_CGGL:
749 case RENDERPATH_D3D9:
753 if (glt->tiledepth > 1)
755 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)))
756 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
758 else if (glt->sides == 6)
760 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
761 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
765 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)))
766 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
771 case RENDERPATH_D3D10:
772 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
774 case RENDERPATH_D3D11:
775 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
782 void R_Textures_Init (void)
784 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");
785 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
786 Cvar_RegisterVariable (&gl_max_size);
787 Cvar_RegisterVariable (&gl_picmip);
788 Cvar_RegisterVariable (&gl_picmip_world);
789 Cvar_RegisterVariable (&r_picmipworld);
790 Cvar_RegisterVariable (&gl_picmip_sprites);
791 Cvar_RegisterVariable (&r_picmipsprites);
792 Cvar_RegisterVariable (&gl_picmip_other);
793 Cvar_RegisterVariable (&gl_max_lightmapsize);
794 Cvar_RegisterVariable (&r_lerpimages);
795 Cvar_RegisterVariable (&gl_texture_anisotropy);
796 Cvar_RegisterVariable (&gl_texturecompression);
797 Cvar_RegisterVariable (&gl_texturecompression_color);
798 Cvar_RegisterVariable (&gl_texturecompression_normal);
799 Cvar_RegisterVariable (&gl_texturecompression_gloss);
800 Cvar_RegisterVariable (&gl_texturecompression_glow);
801 Cvar_RegisterVariable (&gl_texturecompression_2d);
802 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
803 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
804 Cvar_RegisterVariable (&gl_texturecompression_sky);
805 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
806 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
807 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
809 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
812 void R_Textures_Frame (void)
814 static int old_aniso = 0;
816 // could do procedural texture animation here, if we keep track of which
817 // textures were accessed this frame...
819 // free the resize buffers
820 resizebuffersize = 0;
823 Mem_Free(resizebuffer);
826 if (colorconvertbuffer)
828 Mem_Free(colorconvertbuffer);
829 colorconvertbuffer = NULL;
832 if (old_aniso != gl_texture_anisotropy.integer)
835 gltexturepool_t *pool;
838 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
840 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
842 switch(vid.renderpath)
844 case RENDERPATH_GL11:
845 case RENDERPATH_GL13:
846 case RENDERPATH_GL20:
847 case RENDERPATH_CGGL:
850 for (pool = gltexturepoolchain;pool;pool = pool->next)
852 for (glt = pool->gltchain;glt;glt = glt->chain)
854 // only update already uploaded images
855 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
857 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
859 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
860 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
862 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
867 case RENDERPATH_D3D9:
868 case RENDERPATH_D3D10:
869 case RENDERPATH_D3D11:
875 void R_MakeResizeBufferBigger(int size)
877 if (resizebuffersize < size)
879 resizebuffersize = size;
881 Mem_Free(resizebuffer);
882 if (colorconvertbuffer)
883 Mem_Free(colorconvertbuffer);
884 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
885 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
886 if (!resizebuffer || !colorconvertbuffer)
887 Host_Error("R_Upload: out of memory");
891 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
893 int textureenum = gltexturetypeenums[texturetype];
894 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
898 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
900 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
901 if (gl_texture_anisotropy.integer != aniso)
902 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
903 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
905 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
906 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
907 if (gltexturetypedimensions[texturetype] >= 3)
909 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
913 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
915 if (flags & TEXF_MIPMAP)
917 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
921 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
923 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
925 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
927 if (flags & TEXF_MIPMAP)
929 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
931 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
935 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
940 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
942 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
946 if (flags & TEXF_MIPMAP)
948 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
952 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
954 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
957 if (textype == TEXTYPE_SHADOWMAP)
959 if (vid.support.arb_shadow)
961 if (flags & TEXF_COMPARE)
963 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
967 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
969 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
971 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
977 static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
979 int i, mip, width, height, depth;
980 GLint oldbindtexnum = 0;
981 const unsigned char *prevbuffer;
984 switch(vid.renderpath)
986 case RENDERPATH_GL11:
987 case RENDERPATH_GL13:
988 case RENDERPATH_GL20:
989 case RENDERPATH_CGGL:
992 // we need to restore the texture binding after finishing the upload
994 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
995 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
997 case RENDERPATH_D3D9:
998 case RENDERPATH_D3D10:
999 case RENDERPATH_D3D11:
1003 // these are rounded up versions of the size to do better resampling
1004 if (vid.support.arb_texture_non_power_of_two || glt->texturetype == GLTEXTURETYPE_RECTANGLE)
1006 width = glt->inputwidth;
1007 height = glt->inputheight;
1008 depth = glt->inputdepth;
1012 for (width = 1;width < glt->inputwidth ;width <<= 1);
1013 for (height = 1;height < glt->inputheight;height <<= 1);
1014 for (depth = 1;depth < glt->inputdepth ;depth <<= 1);
1017 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1018 R_MakeResizeBufferBigger(fragwidth * fragheight * fragdepth * glt->sides * glt->bytesperpixel);
1020 if (prevbuffer == NULL)
1022 memset(resizebuffer, 0, fragwidth * fragheight * fragdepth * glt->bytesperpixel);
1023 prevbuffer = resizebuffer;
1025 else if (glt->textype->textype == TEXTYPE_PALETTE)
1027 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1028 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, fragwidth * fragheight * fragdepth * glt->sides, glt->palette);
1029 prevbuffer = colorconvertbuffer;
1032 // upload the image - preferring to do only complete uploads (drivers do not really like partial updates)
1034 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))
1036 // update a portion of the image
1037 if (glt->texturetype != GLTEXTURETYPE_2D)
1038 Sys_Error("R_Upload: partial update of type other than 2D");
1039 switch(vid.renderpath)
1041 case RENDERPATH_GL11:
1042 case RENDERPATH_GL13:
1043 case RENDERPATH_GL20:
1044 case RENDERPATH_CGGL:
1045 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1046 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1048 case RENDERPATH_D3D9:
1052 D3DLOCKED_RECT d3dlockedrect;
1054 memset(&d3drect, 0, sizeof(d3drect));
1055 d3drect.left = fragx;
1056 d3drect.top = fragy;
1057 d3drect.right = fragx+fragwidth;
1058 d3drect.bottom = fragy+fragheight;
1059 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1061 for (y = 0;y < fragheight;y++)
1062 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, (unsigned char *)prevbuffer + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1063 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1068 case RENDERPATH_D3D10:
1069 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1071 case RENDERPATH_D3D11:
1072 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1078 if (fragx || fragy || fragz || glt->inputwidth != fragwidth || glt->inputheight != fragheight || glt->inputdepth != fragdepth)
1079 Host_Error("R_Upload: partial update not allowed on initial upload or in combination with PICMIP or MIPMAP\n");
1081 // cubemaps contain multiple images and thus get processed a bit differently
1082 if (glt->texturetype != GLTEXTURETYPE_CUBEMAP)
1084 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1086 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1087 prevbuffer = resizebuffer;
1090 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1092 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1093 prevbuffer = resizebuffer;
1097 switch(vid.renderpath)
1099 case RENDERPATH_GL11:
1100 case RENDERPATH_GL13:
1101 case RENDERPATH_GL20:
1102 case RENDERPATH_CGGL:
1103 if (qglGetCompressedTexImageARB)
1105 if (gl_texturecompression.integer >= 2)
1106 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1108 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1111 switch(glt->texturetype)
1113 case GLTEXTURETYPE_2D:
1114 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1115 if (glt->flags & TEXF_MIPMAP)
1117 while (width > 1 || height > 1 || depth > 1)
1119 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1120 prevbuffer = resizebuffer;
1121 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1125 case GLTEXTURETYPE_3D:
1126 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1127 if (glt->flags & TEXF_MIPMAP)
1129 while (width > 1 || height > 1 || depth > 1)
1131 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1132 prevbuffer = resizebuffer;
1133 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1137 case GLTEXTURETYPE_CUBEMAP:
1138 // convert and upload each side in turn,
1139 // from a continuous block of input texels
1140 texturebuffer = (unsigned char *)prevbuffer;
1141 for (i = 0;i < 6;i++)
1143 prevbuffer = texturebuffer;
1144 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1145 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1147 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1148 prevbuffer = resizebuffer;
1151 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1153 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1154 prevbuffer = resizebuffer;
1157 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1158 if (glt->flags & TEXF_MIPMAP)
1160 while (width > 1 || height > 1 || depth > 1)
1162 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1163 prevbuffer = resizebuffer;
1164 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1169 case GLTEXTURETYPE_RECTANGLE:
1170 qglTexImage2D(GL_TEXTURE_RECTANGLE_ARB, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, NULL);CHECKGLERROR
1173 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1174 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1176 case RENDERPATH_D3D9:
1178 if (!(glt->flags & TEXF_RENDERTARGET))
1180 D3DLOCKED_RECT d3dlockedrect;
1181 D3DLOCKED_BOX d3dlockedbox;
1182 switch(glt->texturetype)
1184 case GLTEXTURETYPE_2D:
1185 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1188 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1190 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1191 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1194 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1196 while (width > 1 || height > 1 || depth > 1)
1198 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1199 prevbuffer = resizebuffer;
1200 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1202 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1203 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1209 case GLTEXTURETYPE_3D:
1210 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1212 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1213 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1214 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1217 if (glt->flags & TEXF_MIPMAP)
1219 while (width > 1 || height > 1 || depth > 1)
1221 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1222 prevbuffer = resizebuffer;
1223 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1225 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1226 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1227 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1233 case GLTEXTURETYPE_CUBEMAP:
1234 // convert and upload each side in turn,
1235 // from a continuous block of input texels
1236 texturebuffer = (unsigned char *)prevbuffer;
1237 for (i = 0;i < 6;i++)
1239 prevbuffer = texturebuffer;
1240 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1241 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1243 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1244 prevbuffer = resizebuffer;
1247 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1249 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1250 prevbuffer = resizebuffer;
1253 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1255 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1256 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1259 if (glt->flags & TEXF_MIPMAP)
1261 while (width > 1 || height > 1 || depth > 1)
1263 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1264 prevbuffer = resizebuffer;
1265 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1267 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1268 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1275 case GLTEXTURETYPE_RECTANGLE:
1276 Sys_Error("Direct3D does not have RECTANGLE textures\n");
1280 glt->d3daddressw = 0;
1281 if (glt->flags & TEXF_CLAMP)
1283 glt->d3daddressu = D3DTADDRESS_CLAMP;
1284 glt->d3daddressv = D3DTADDRESS_CLAMP;
1285 if (glt->tiledepth > 1)
1286 glt->d3daddressw = D3DTADDRESS_CLAMP;
1290 glt->d3daddressu = D3DTADDRESS_WRAP;
1291 glt->d3daddressv = D3DTADDRESS_WRAP;
1292 if (glt->tiledepth > 1)
1293 glt->d3daddressw = D3DTADDRESS_WRAP;
1295 glt->d3dmipmaplodbias = 0;
1296 glt->d3dmaxmiplevel = 0;
1297 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1298 if (glt->flags & TEXF_FORCELINEAR)
1300 glt->d3dminfilter = D3DTEXF_LINEAR;
1301 glt->d3dmagfilter = D3DTEXF_LINEAR;
1302 glt->d3dmipfilter = D3DTEXF_POINT;
1304 else if (glt->flags & TEXF_FORCENEAREST)
1306 glt->d3dminfilter = D3DTEXF_POINT;
1307 glt->d3dmagfilter = D3DTEXF_POINT;
1308 glt->d3dmipfilter = D3DTEXF_POINT;
1310 else if (glt->flags & TEXF_MIPMAP)
1312 glt->d3dminfilter = d3d_filter_mipmin;
1313 glt->d3dmagfilter = d3d_filter_mipmag;
1314 glt->d3dmipfilter = d3d_filter_mipmix;
1318 glt->d3dminfilter = d3d_filter_flatmin;
1319 glt->d3dmagfilter = d3d_filter_flatmag;
1320 glt->d3dmipfilter = d3d_filter_flatmix;
1324 case RENDERPATH_D3D10:
1325 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1327 case RENDERPATH_D3D11:
1328 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1334 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)
1338 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1339 textypeinfo_t *texinfo, *texinfo2;
1340 unsigned char *temppixels = NULL;
1342 if (cls.state == ca_dedicated)
1345 if (texturetype == GLTEXTURETYPE_RECTANGLE && !vid.support.arb_texture_rectangle)
1347 Con_Printf ("R_LoadTexture: rectangle texture not supported by driver\n");
1350 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1352 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1355 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1357 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1361 texinfo = R_GetTexTypeInfo(textype, flags);
1362 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1365 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1369 if (textype == TEXTYPE_RGBA)
1372 static int rgbaswapindices[4] = {2, 1, 0, 3};
1373 textype = TEXTYPE_BGRA;
1374 texinfo = R_GetTexTypeInfo(textype, flags);
1375 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1376 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1380 // clear the alpha flag if the texture has no transparent pixels
1383 case TEXTYPE_PALETTE:
1384 if (flags & TEXF_ALPHA)
1386 flags &= ~TEXF_ALPHA;
1389 for (i = 0;i < size;i++)
1391 if (((unsigned char *)&palette[data[i]])[3] < 255)
1393 flags |= TEXF_ALPHA;
1402 if (flags & TEXF_ALPHA)
1404 flags &= ~TEXF_ALPHA;
1407 for (i = 3;i < size;i += 4)
1411 flags |= TEXF_ALPHA;
1418 case TEXTYPE_SHADOWMAP:
1425 flags |= TEXF_ALPHA;
1428 flags |= TEXF_ALPHA;
1430 case TEXTYPE_COLORBUFFER:
1431 flags |= TEXF_ALPHA;
1434 Sys_Error("R_LoadTexture: unknown texture type");
1437 texinfo2 = R_GetTexTypeInfo(textype, flags);
1438 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1441 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1443 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1445 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1447 glt->chain = pool->gltchain;
1448 pool->gltchain = glt;
1449 glt->inputwidth = width;
1450 glt->inputheight = height;
1451 glt->inputdepth = depth;
1453 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
1454 glt->textype = texinfo;
1455 glt->texturetype = texturetype;
1456 glt->inputdatasize = size;
1457 glt->palette = palette;
1458 glt->glinternalformat = texinfo->glinternalformat;
1459 glt->glformat = texinfo->glformat;
1460 glt->gltype = texinfo->gltype;
1461 glt->bytesperpixel = texinfo->internalbytesperpixel;
1462 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1465 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1466 // init the dynamic texture attributes, too [11/22/2007 Black]
1467 glt->updatecallback = NULL;
1468 glt->updatacallback_data = NULL;
1470 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1472 // upload the texture
1473 // data may be NULL (blank texture for dynamic rendering)
1474 switch(vid.renderpath)
1476 case RENDERPATH_GL11:
1477 case RENDERPATH_GL13:
1478 case RENDERPATH_GL20:
1479 case RENDERPATH_CGGL:
1481 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1483 case RENDERPATH_D3D9:
1486 D3DFORMAT d3dformat;
1491 d3dpool = D3DPOOL_MANAGED;
1492 if (flags & TEXF_RENDERTARGET)
1494 d3dusage |= D3DUSAGE_RENDERTARGET;
1495 d3dpool = D3DPOOL_DEFAULT;
1499 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1500 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1501 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1502 case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1503 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1504 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1505 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1507 glt->d3dformat = d3dformat;
1508 glt->d3dusage = d3dusage;
1509 glt->d3dpool = d3dpool;
1510 if (glt->tiledepth > 1)
1512 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)))
1513 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1515 else if (glt->sides == 6)
1517 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1518 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1522 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)))
1523 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1528 case RENDERPATH_D3D10:
1529 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1531 case RENDERPATH_D3D11:
1532 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1536 R_Upload(glt, data, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
1537 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1538 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1540 // free any temporary processing buffer we allocated...
1542 Mem_Free(temppixels);
1544 // texture converting and uploading can take a while, so make sure we're sending keepalives
1545 // FIXME: this causes rendering during R_Shadow_DrawLights
1546 // CL_KeepaliveMessage(false);
1548 return (rtexture_t *)glt;
1551 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)
1553 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1556 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)
1558 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1561 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)
1563 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1566 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)
1568 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_RECTANGLE, data, palette);
1571 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1573 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1575 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1577 flags |= TEXF_FORCENEAREST;
1578 if (precision <= 16)
1579 flags |= TEXF_LOWPRECISION;
1583 rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1585 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
1588 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1590 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1593 rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter)
1595 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
1598 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed)
1600 gltexture_t *glt = (gltexture_t *)rt;
1603 int bytesperpixel = 0;
1604 int bytesperblock = 0;
1606 int dds_format_flags;
1614 GLint internalformat;
1615 const char *ddsfourcc;
1617 return -1; // NULL pointer
1618 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1619 return -2; // broken driver - crashes on reading internal format
1620 if (!qglGetTexLevelParameteriv)
1622 GL_ActiveTexture(0);
1623 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1624 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1625 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1626 switch(internalformat)
1628 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1629 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1630 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1631 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1632 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1634 if (!bytesperblock && skipuncompressed)
1635 return -3; // skipped
1636 memset(mipinfo, 0, sizeof(mipinfo));
1637 mipinfo[0][0] = glt->tilewidth;
1638 mipinfo[0][1] = glt->tileheight;
1640 if (glt->flags & TEXF_MIPMAP)
1642 for (mip = 1;mip < 16;mip++)
1644 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1645 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1646 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1654 for (mip = 0;mip < mipmaps;mip++)
1656 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1657 mipinfo[mip][3] = ddssize;
1658 ddssize += mipinfo[mip][2];
1660 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1663 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1667 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1668 dds_format_flags = 0x4; // DDPF_FOURCC
1672 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1673 dds_format_flags = 0x41; // DDPF_RGB | DDPF_ALPHAPIXELS
1677 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1678 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1680 memcpy(dds, "DDS ", 4);
1681 StoreLittleLong(dds+4, ddssize);
1682 StoreLittleLong(dds+8, dds_flags);
1683 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1684 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1685 StoreLittleLong(dds+24, 1); // depth
1686 StoreLittleLong(dds+28, mipmaps); // mipmaps
1687 StoreLittleLong(dds+76, 32); // format size
1688 StoreLittleLong(dds+80, dds_format_flags);
1689 StoreLittleLong(dds+108, dds_caps1);
1690 StoreLittleLong(dds+112, dds_caps2);
1693 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1694 memcpy(dds+84, ddsfourcc, 4);
1695 for (mip = 0;mip < mipmaps;mip++)
1697 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1702 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1703 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1704 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1705 for (mip = 0;mip < mipmaps;mip++)
1707 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1710 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1711 ret = FS_WriteFile(filename, dds, ddssize);
1713 return ret ? ddssize : -5;
1716 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
1718 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1721 int bytesperblock, bytesperpixel;
1724 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1725 textypeinfo_t *texinfo;
1726 int mip, mipwidth, mipheight, mipsize;
1728 GLint oldbindtexnum = 0;
1729 const unsigned char *mippixels, *ddspixels;
1731 fs_offset_t ddsfilesize;
1732 unsigned int ddssize;
1734 if (cls.state == ca_dedicated)
1737 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1738 ddssize = ddsfilesize;
1742 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1743 return NULL; // not found
1746 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1749 Con_Printf("^1%s: not a DDS image\n", filename);
1753 //dds_flags = BuffLittleLong(dds+8);
1754 dds_format_flags = BuffLittleLong(dds+80);
1755 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1756 dds_width = BuffLittleLong(dds+16);
1757 dds_height = BuffLittleLong(dds+12);
1758 ddspixels = dds + 128;
1760 flags &= ~TEXF_ALPHA;
1761 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1763 // very sloppy BGRA 32bit identification
1764 textype = TEXTYPE_BGRA;
1767 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1768 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1771 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1775 for (i = 3;i < size;i += 4)
1776 if (ddspixels[i] < 255)
1779 flags &= ~TEXF_ALPHA;
1781 else if (!memcmp(dds+84, "DXT1", 4))
1783 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1784 // LordHavoc: it is my belief that this does not infringe on the
1785 // patent because it is not decoding pixels...
1786 textype = TEXTYPE_DXT1;
1789 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1790 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1791 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1794 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1797 for (i = 0;i < size;i += bytesperblock)
1798 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1801 textype = TEXTYPE_DXT1A;
1803 flags &= ~TEXF_ALPHA;
1805 else if (!memcmp(dds+84, "DXT3", 4))
1807 textype = TEXTYPE_DXT3;
1810 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1811 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1814 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1818 else if (!memcmp(dds+84, "DXT5", 4))
1820 textype = TEXTYPE_DXT5;
1823 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1824 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1827 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1834 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1838 // return whether this texture is transparent
1840 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1842 // calculate average color if requested
1846 Vector4Clear(avgcolor);
1849 for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
1851 c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
1852 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1853 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
1854 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
1856 f = (float)bytesperblock / size;
1857 avgcolor[0] *= (0.5f / 31.0f) * f;
1858 avgcolor[1] *= (0.5f / 63.0f) * f;
1859 avgcolor[2] *= (0.5f / 31.0f) * f;
1860 avgcolor[3] = 1; // too hard to calculate
1864 for (i = 0;i < size;i += 4)
1866 avgcolor[0] += ddspixels[i+2];
1867 avgcolor[1] += ddspixels[i+1];
1868 avgcolor[2] += ddspixels[i];
1869 avgcolor[3] += ddspixels[i+3];
1871 f = (1.0f / 255.0f) * bytesperpixel / size;
1879 // this is where we apply gl_picmip
1880 mippixels = ddspixels;
1881 mipwidth = dds_width;
1882 mipheight = dds_height;
1883 while(miplevel >= 1 && dds_miplevels >= 1)
1885 if (mipwidth <= 1 && mipheight <= 1)
1887 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1888 mippixels += mipsize; // just skip
1897 if (dds_miplevels > 1)
1898 flags |= TEXF_MIPMAP;
1900 flags &= ~TEXF_MIPMAP;
1902 // if S3TC is not supported, there's very little we can do about it
1903 if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
1906 Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
1910 texinfo = R_GetTexTypeInfo(textype, flags);
1912 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1913 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
1915 glt->chain = pool->gltchain;
1916 pool->gltchain = glt;
1917 glt->inputwidth = mipwidth;
1918 glt->inputheight = mipheight;
1919 glt->inputdepth = 1;
1921 glt->textype = texinfo;
1922 glt->texturetype = GLTEXTURETYPE_2D;
1923 glt->inputdatasize = ddssize;
1924 glt->glinternalformat = texinfo->glinternalformat;
1925 glt->glformat = texinfo->glformat;
1926 glt->gltype = texinfo->gltype;
1927 glt->bytesperpixel = texinfo->internalbytesperpixel;
1929 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1930 glt->tilewidth = mipwidth;
1931 glt->tileheight = mipheight;
1933 glt->miplevels = dds_miplevels;
1935 // texture uploading can take a while, so make sure we're sending keepalives
1936 CL_KeepaliveMessage(false);
1938 // create the texture object
1939 switch(vid.renderpath)
1941 case RENDERPATH_GL11:
1942 case RENDERPATH_GL13:
1943 case RENDERPATH_GL20:
1944 case RENDERPATH_CGGL:
1946 GL_ActiveTexture(0);
1947 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1948 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1949 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1951 case RENDERPATH_D3D9:
1954 D3DFORMAT d3dformat;
1959 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1960 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
1961 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
1962 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
1963 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1966 d3dpool = D3DPOOL_MANAGED;
1967 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
1971 case RENDERPATH_D3D10:
1972 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1974 case RENDERPATH_D3D11:
1975 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1979 // upload the texture
1980 // we need to restore the texture binding after finishing the upload
1981 mipcomplete = false;
1983 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
1985 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1986 if (mippixels + mipsize > dds + ddssize)
1988 switch(vid.renderpath)
1990 case RENDERPATH_GL11:
1991 case RENDERPATH_GL13:
1992 case RENDERPATH_GL20:
1993 case RENDERPATH_CGGL:
1996 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2000 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2003 case RENDERPATH_D3D9:
2006 D3DLOCKED_RECT d3dlockedrect;
2007 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2009 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2010 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2016 case RENDERPATH_D3D10:
2017 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2019 case RENDERPATH_D3D11:
2020 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2023 mippixels += mipsize;
2024 if (mipwidth <= 1 && mipheight <= 1)
2035 // after upload we have to set some parameters...
2036 switch(vid.renderpath)
2038 case RENDERPATH_GL11:
2039 case RENDERPATH_GL13:
2040 case RENDERPATH_GL20:
2041 case RENDERPATH_CGGL:
2042 if (dds_miplevels >= 1 && !mipcomplete)
2044 // need to set GL_TEXTURE_MAX_LEVEL
2045 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2047 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2048 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2050 case RENDERPATH_D3D9:
2052 glt->d3daddressw = 0;
2053 if (glt->flags & TEXF_CLAMP)
2055 glt->d3daddressu = D3DTADDRESS_CLAMP;
2056 glt->d3daddressv = D3DTADDRESS_CLAMP;
2057 if (glt->tiledepth > 1)
2058 glt->d3daddressw = D3DTADDRESS_CLAMP;
2062 glt->d3daddressu = D3DTADDRESS_WRAP;
2063 glt->d3daddressv = D3DTADDRESS_WRAP;
2064 if (glt->tiledepth > 1)
2065 glt->d3daddressw = D3DTADDRESS_WRAP;
2067 glt->d3dmipmaplodbias = 0;
2068 glt->d3dmaxmiplevel = 0;
2069 glt->d3dmaxmiplevelfilter = 0;
2070 if (glt->flags & TEXF_MIPMAP)
2072 glt->d3dminfilter = d3d_filter_mipmin;
2073 glt->d3dmagfilter = d3d_filter_mipmag;
2074 glt->d3dmipfilter = d3d_filter_mipmix;
2078 glt->d3dminfilter = d3d_filter_flatmin;
2079 glt->d3dmagfilter = d3d_filter_flatmag;
2080 glt->d3dmipfilter = d3d_filter_flatmix;
2084 case RENDERPATH_D3D10:
2085 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2087 case RENDERPATH_D3D11:
2088 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2093 return (rtexture_t *)glt;
2096 int R_TextureWidth(rtexture_t *rt)
2098 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2101 int R_TextureHeight(rtexture_t *rt)
2103 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2106 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
2108 gltexture_t *glt = (gltexture_t *)rt;
2110 Host_Error("R_UpdateTexture: no data supplied");
2112 Host_Error("R_UpdateTexture: no texture supplied");
2113 if (!glt->texnum && !glt->d3dtexture)
2115 Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", glt, glt->identifier, glt->pool);
2118 // update part of the texture
2119 if (glt->bufferpixels)
2122 int bpp = glt->bytesperpixel;
2123 int inputskip = width*bpp;
2124 int outputskip = glt->tilewidth*bpp;
2125 const unsigned char *input = data;
2126 unsigned char *output = glt->bufferpixels;
2136 input -= y*inputskip;
2139 if (width > glt->tilewidth - x)
2140 width = glt->tilewidth - x;
2141 if (height > glt->tileheight - y)
2142 height = glt->tileheight - y;
2143 if (width < 1 || height < 1)
2146 glt->buffermodified = true;
2147 output += y*outputskip + x*bpp;
2148 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2149 memcpy(output, input, width*bpp);
2152 R_Upload(glt, data, x, y, 0, width, height, 1);
2155 int R_RealGetTexture(rtexture_t *rt)
2160 glt = (gltexture_t *)rt;
2161 if (glt->flags & GLTEXF_DYNAMIC)
2162 R_UpdateDynamicTexture(glt);
2163 if (glt->buffermodified && glt->bufferpixels)
2165 glt->buffermodified = false;
2166 R_Upload(glt, glt->bufferpixels, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth);
2175 void R_ClearTexture (rtexture_t *rt)
2177 gltexture_t *glt = (gltexture_t *)rt;
2179 R_Upload( glt, NULL, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth );
2182 int R_PicmipForFlags(int flags)
2185 if(flags & TEXF_PICMIP)
2187 miplevel += gl_picmip.integer;
2188 if (flags & TEXF_ISWORLD)
2190 if (r_picmipworld.integer)
2191 miplevel += gl_picmip_world.integer;
2195 else if (flags & TEXF_ISSPRITE)
2197 if (r_picmipsprites.integer)
2198 miplevel += gl_picmip_sprites.integer;
2203 miplevel += gl_picmip_other.integer;