5 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
10 #include "intoverflow.h"
12 cvar_t gl_max_size = {CVAR_SAVE, "gl_max_size", "2048", "maximum allowed texture size, can be used to reduce video memory usage, limited by hardware capabilities (typically 2048, 4096, or 8192)"};
13 cvar_t gl_max_lightmapsize = {CVAR_SAVE, "gl_max_lightmapsize", "1024", "maximum allowed texture size for lightmap textures, use larger values to improve rendering speed, as long as there is enough video memory available (setting it too high for the hardware will cause very bad performance)"};
14 cvar_t gl_picmip = {CVAR_SAVE, "gl_picmip", "0", "reduces resolution of textures by powers of 2, for example 1 will halve width/height, reducing texture memory usage by 75%"};
15 cvar_t gl_picmip_world = {CVAR_SAVE, "gl_picmip_world", "0", "extra picmip level for world textures (may be negative, which will then reduce gl_picmip for these)"};
16 cvar_t r_picmipworld = {CVAR_SAVE, "r_picmipworld", "1", "whether gl_picmip shall apply to world textures too (setting this to 0 is a shorthand for gl_picmip_world -9999999)"};
17 cvar_t gl_picmip_sprites = {CVAR_SAVE, "gl_picmip_sprites", "0", "extra picmip level for sprite textures (may be negative, which will then reduce gl_picmip for these)"};
18 cvar_t r_picmipsprites = {CVAR_SAVE, "r_picmipsprites", "1", "make gl_picmip affect sprites too (saves some graphics memory in sprite heavy games) (setting this to 0 is a shorthand for gl_picmip_sprites -9999999)"};
19 cvar_t gl_picmip_other = {CVAR_SAVE, "gl_picmip_other", "0", "extra picmip level for other textures (may be negative, which will then reduce gl_picmip for these)"};
20 cvar_t r_lerpimages = {CVAR_SAVE, "r_lerpimages", "1", "bilinear filters images when scaling them up to power of 2 size (mode 1), looks better than glquake (mode 0)"};
21 cvar_t gl_texture_anisotropy = {CVAR_SAVE, "gl_texture_anisotropy", "1", "anisotropic filtering quality (if supported by hardware), 1 sample (no anisotropy) and 8 sample (8 tap anisotropy) are recommended values"};
22 cvar_t gl_texturecompression = {CVAR_SAVE, "gl_texturecompression", "0", "whether to compress textures, a value of 0 disables compression (even if the individual cvars are 1), 1 enables fast (low quality) compression at startup, 2 enables slow (high quality) compression at startup"};
23 cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
24 cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
25 cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
26 cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
27 cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
28 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
29 cvar_t gl_texturecompression_q3bspdeluxemaps = {CVAR_SAVE, "gl_texturecompression_q3bspdeluxemaps", "0", "whether to compress deluxemaps in q3bsp format levels (only levels compiled with q3map2 -deluxe have these)"};
30 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
31 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
32 cvar_t gl_texturecompression_reflectmask = {CVAR_SAVE, "gl_texturecompression_reflectmask", "1", "whether to compress reflection cubemap masks (mask of which areas of the texture should reflect the generic shiny cubemap)"};
33 cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "1", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"};
34 cvar_t r_texture_dds_load_alphamode = {0, "r_texture_dds_load_alphamode", "1", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambigous, 2: texture format only"};
36 qboolean gl_filter_force = false;
37 int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
38 int gl_filter_mag = GL_LINEAR;
41 int d3d_filter_flatmin = D3DTEXF_LINEAR;
42 int d3d_filter_flatmag = D3DTEXF_LINEAR;
43 int d3d_filter_flatmix = D3DTEXF_POINT;
44 int d3d_filter_mipmin = D3DTEXF_LINEAR;
45 int d3d_filter_mipmag = D3DTEXF_LINEAR;
46 int d3d_filter_mipmix = D3DTEXF_LINEAR;
47 int d3d_filter_nomip = false;
51 static mempool_t *texturemempool;
52 static memexpandablearray_t texturearray;
54 // note: this must not conflict with TEXF_ flags in r_textures.h
55 // bitmask for mismatch checking
56 #define GLTEXF_IMPORTANTBITS (0)
57 // dynamic texture (treat texnum == 0 differently)
58 #define GLTEXF_DYNAMIC 0x00080000
60 typedef struct textypeinfo_s
63 int inputbytesperpixel;
64 int internalbytesperpixel;
65 float glinternalbytesperpixel;
73 static textypeinfo_t textype_palette = {TEXTYPE_PALETTE , 1, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE };
74 static textypeinfo_t textype_palette_alpha = {TEXTYPE_PALETTE , 1, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
75 static textypeinfo_t textype_rgba = {TEXTYPE_RGBA , 4, 4, 4.0f, 3 , GL_RGBA , GL_UNSIGNED_BYTE };
76 static textypeinfo_t textype_rgba_alpha = {TEXTYPE_RGBA , 4, 4, 4.0f, 4 , GL_RGBA , GL_UNSIGNED_BYTE };
77 static textypeinfo_t textype_rgba_compress = {TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
78 static textypeinfo_t textype_rgba_alpha_compress = {TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA , GL_UNSIGNED_BYTE };
79 static textypeinfo_t textype_bgra = {TEXTYPE_BGRA , 4, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE };
80 static textypeinfo_t textype_bgra_alpha = {TEXTYPE_BGRA , 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
81 static textypeinfo_t textype_bgra_compress = {TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
82 static textypeinfo_t textype_bgra_alpha_compress = {TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_BGRA , GL_UNSIGNED_BYTE };
83 static textypeinfo_t textype_shadowmap16 = {TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
84 static textypeinfo_t textype_shadowmap24 = {TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
85 static textypeinfo_t textype_alpha = {TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
86 static textypeinfo_t textype_dxt1 = {TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
87 static textypeinfo_t textype_dxt1a = {TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0 , 0 };
88 static textypeinfo_t textype_dxt3 = {TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0 , 0 };
89 static textypeinfo_t textype_dxt5 = {TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0 , 0 };
90 static textypeinfo_t textype_colorbuffer = {TEXTYPE_COLORBUFFER, 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
93 typedef enum gltexturetype_e
97 GLTEXTURETYPE_CUBEMAP,
102 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB};
103 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 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
124 qboolean d3disdepthsurface; // for depth/stencil surfaces
134 int d3dmaxmiplevelfilter;
135 int d3dmipmaplodbias;
139 // dynamic texture stuff [11/22/2007 Black]
140 updatecallback_t updatecallback;
141 void *updatacallback_data;
142 // --- [11/22/2007 Black]
144 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
145 unsigned char *bufferpixels;
146 qboolean buffermodified;
148 // pointer to texturepool (check this to see if the texture is allocated)
149 struct gltexturepool_s *pool;
150 // pointer to next texture in texturepool chain
151 struct gltexture_s *chain;
152 // name of the texture (this might be removed someday), no duplicates
153 char identifier[MAX_QPATH + 32];
154 // original data size in *inputtexels
155 int inputwidth, inputheight, inputdepth;
156 // copy of the original texture(s) supplied to the upload function, for
157 // delayed uploads (non-precached)
158 unsigned char *inputtexels;
159 // original data size in *inputtexels
161 // flags supplied to the LoadTexture function
162 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
166 // pointer to one of the textype_ structs
167 textypeinfo_t *textype;
168 // one of the GLTEXTURETYPE_ values
170 // palette if the texture is TEXTYPE_PALETTE
171 const unsigned int *palette;
172 // actual stored texture size after gl_picmip and gl_max_size are applied
173 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
174 int tilewidth, tileheight, tiledepth;
175 // 1 or 6 depending on texturetype
177 // how many mipmap levels in this texture
181 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
184 int glinternalformat;
185 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
190 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
192 typedef struct gltexturepool_s
194 unsigned int sentinel;
195 struct gltexture_s *gltchain;
196 struct gltexturepool_s *next;
200 static gltexturepool_t *gltexturepoolchain = NULL;
202 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
203 static int resizebuffersize = 0;
204 static const unsigned char *texturebuffer;
206 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
211 return &textype_dxt1;
213 return &textype_dxt1a;
215 return &textype_dxt3;
217 return &textype_dxt5;
218 case TEXTYPE_PALETTE:
219 return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
221 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
222 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress;
223 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba;
225 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
226 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress;
227 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra;
229 return &textype_alpha;
230 case TEXTYPE_SHADOWMAP:
231 return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
232 case TEXTYPE_COLORBUFFER:
233 return &textype_colorbuffer;
235 Host_Error("R_GetTexTypeInfo: unknown texture format");
241 // dynamic texture code [11/22/2007 Black]
242 void R_MarkDirtyTexture(rtexture_t *rt) {
243 gltexture_t *glt = (gltexture_t*) rt;
248 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
249 if (glt->flags & GLTEXF_DYNAMIC)
251 // mark it as dirty, so R_RealGetTexture gets called
256 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
257 gltexture_t *glt = (gltexture_t*) rt;
262 glt->flags |= GLTEXF_DYNAMIC;
263 glt->updatecallback = updatecallback;
264 glt->updatacallback_data = data;
267 static void R_UpdateDynamicTexture(gltexture_t *glt) {
269 if( glt->updatecallback ) {
270 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
274 void R_PurgeTexture(rtexture_t *rt)
276 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
281 void R_FreeTexture(rtexture_t *rt)
283 gltexture_t *glt, **gltpointer;
285 glt = (gltexture_t *)rt;
287 Host_Error("R_FreeTexture: texture == NULL");
289 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
290 if (*gltpointer == glt)
291 *gltpointer = glt->chain;
293 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
295 switch(vid.renderpath)
297 case RENDERPATH_GL11:
298 case RENDERPATH_GL13:
299 case RENDERPATH_GL20:
300 case RENDERPATH_CGGL:
304 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
307 case RENDERPATH_D3D9:
309 if (glt->d3disdepthsurface)
310 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
311 else if (glt->tiledepth > 1)
312 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
313 else if (glt->sides == 6)
314 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
316 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
317 glt->d3dtexture = NULL;
320 case RENDERPATH_D3D10:
321 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
323 case RENDERPATH_D3D11:
324 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
328 if (glt->inputtexels)
329 Mem_Free(glt->inputtexels);
330 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
333 rtexturepool_t *R_AllocTexturePool(void)
335 gltexturepool_t *pool;
336 if (texturemempool == NULL)
338 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
341 pool->next = gltexturepoolchain;
342 gltexturepoolchain = pool;
343 pool->sentinel = TEXTUREPOOL_SENTINEL;
344 return (rtexturepool_t *)pool;
347 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
349 gltexturepool_t *pool, **poolpointer;
350 if (rtexturepool == NULL)
352 if (*rtexturepool == NULL)
354 pool = (gltexturepool_t *)(*rtexturepool);
355 *rtexturepool = NULL;
356 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
357 Host_Error("R_FreeTexturePool: pool already freed");
358 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
359 if (*poolpointer == pool)
360 *poolpointer = pool->next;
362 Host_Error("R_FreeTexturePool: pool not linked");
363 while (pool->gltchain)
364 R_FreeTexture((rtexture_t *)pool->gltchain);
369 typedef struct glmode_s
372 int minification, magnification;
376 static glmode_t modes[6] =
378 {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
379 {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
380 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
381 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
382 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
383 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
387 typedef struct d3dmode_s
394 static d3dmode_t d3dmodes[6] =
396 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
397 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
398 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
399 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
400 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
401 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
405 static void GL_TextureMode_f (void)
410 gltexturepool_t *pool;
414 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
415 for (i = 0;i < 6;i++)
417 if (gl_filter_min == modes[i].minification)
419 Con_Printf("%s\n", modes[i].name);
423 Con_Print("current filter is unknown???\n");
427 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
428 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
432 Con_Print("bad filter name\n");
436 gl_filter_min = modes[i].minification;
437 gl_filter_mag = modes[i].magnification;
438 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
440 switch(vid.renderpath)
442 case RENDERPATH_GL11:
443 case RENDERPATH_GL13:
444 case RENDERPATH_GL20:
445 case RENDERPATH_CGGL:
446 // change all the existing mipmap texture objects
447 // FIXME: force renderer(/client/something?) restart instead?
450 for (pool = gltexturepoolchain;pool;pool = pool->next)
452 for (glt = pool->gltchain;glt;glt = glt->chain)
454 // only update already uploaded images
455 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
457 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
458 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
459 if (glt->flags & TEXF_MIPMAP)
461 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
465 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
467 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
468 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
473 case RENDERPATH_D3D9:
475 d3d_filter_flatmin = d3dmodes[i].m1;
476 d3d_filter_flatmag = d3dmodes[i].m1;
477 d3d_filter_flatmix = D3DTEXF_POINT;
478 d3d_filter_mipmin = d3dmodes[i].m1;
479 d3d_filter_mipmag = d3dmodes[i].m1;
480 d3d_filter_mipmix = d3dmodes[i].m2;
481 d3d_filter_nomip = i < 2;
482 if (gl_texture_anisotropy.integer > 1 && i == 5)
483 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
484 for (pool = gltexturepoolchain;pool;pool = pool->next)
486 for (glt = pool->gltchain;glt;glt = glt->chain)
488 // only update already uploaded images
489 if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
491 if (glt->flags & TEXF_MIPMAP)
493 glt->d3dminfilter = d3d_filter_mipmin;
494 glt->d3dmagfilter = d3d_filter_mipmag;
495 glt->d3dmipfilter = d3d_filter_mipmix;
496 glt->d3dmaxmiplevelfilter = 0;
500 glt->d3dminfilter = d3d_filter_flatmin;
501 glt->d3dmagfilter = d3d_filter_flatmag;
502 glt->d3dmipfilter = d3d_filter_flatmix;
503 glt->d3dmaxmiplevelfilter = 0;
510 case RENDERPATH_D3D10:
511 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
513 case RENDERPATH_D3D11:
514 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
519 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)
521 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
526 case GLTEXTURETYPE_2D:
527 maxsize = vid.maxtexturesize_2d;
528 if (flags & TEXF_PICMIP)
530 maxsize = bound(1, gl_max_size.integer, maxsize);
534 case GLTEXTURETYPE_3D:
535 maxsize = vid.maxtexturesize_3d;
537 case GLTEXTURETYPE_CUBEMAP:
538 maxsize = vid.maxtexturesize_cubemap;
542 if (vid.support.arb_texture_non_power_of_two)
544 width2 = min(inwidth >> picmip, maxsize);
545 height2 = min(inheight >> picmip, maxsize);
546 depth2 = min(indepth >> picmip, maxsize);
550 for (width2 = 1;width2 < inwidth;width2 <<= 1);
551 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
552 for (height2 = 1;height2 < inheight;height2 <<= 1);
553 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
554 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
555 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
558 switch(vid.renderpath)
560 case RENDERPATH_GL11:
561 case RENDERPATH_GL13:
562 case RENDERPATH_GL20:
563 case RENDERPATH_CGGL:
564 case RENDERPATH_D3D10:
565 case RENDERPATH_D3D11:
567 case RENDERPATH_D3D9:
569 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
570 if (texturetype == GLTEXTURETYPE_2D)
572 width2 = max(width2, 2);
573 height2 = max(height2, 2);
580 if (flags & TEXF_MIPMAP)
582 int extent = max(width2, max(height2, depth2));
588 *outwidth = max(1, width2);
590 *outheight = max(1, height2);
592 *outdepth = max(1, depth2);
594 *outmiplevels = miplevels;
598 static int R_CalcTexelDataSize (gltexture_t *glt)
600 int width2, height2, depth2, size;
602 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
604 size = width2 * height2 * depth2;
606 if (glt->flags & TEXF_MIPMAP)
608 while (width2 > 1 || height2 > 1 || depth2 > 1)
616 size += width2 * height2 * depth2;
620 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
623 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
627 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
628 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
630 gltexturepool_t *pool;
632 Con_Print("glsize input loaded mip alpha name\n");
633 for (pool = gltexturepoolchain;pool;pool = pool->next)
641 for (glt = pool->gltchain;glt;glt = glt->chain)
643 glsize = R_CalcTexelDataSize(glt);
644 isloaded = glt->texnum != 0;
646 pooltotalt += glsize;
647 pooltotalp += glt->inputdatasize;
651 poolloadedt += glsize;
652 poolloadedp += glt->inputdatasize;
655 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);
658 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);
659 sumtotal += pooltotal;
660 sumtotalt += pooltotalt;
661 sumtotalp += pooltotalp;
662 sumloaded += poolloaded;
663 sumloadedt += poolloadedt;
664 sumloadedp += poolloadedp;
667 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);
670 static void R_TextureStats_f(void)
672 R_TextureStats_Print(true, true, true);
675 static void r_textures_start(void)
677 switch(vid.renderpath)
679 case RENDERPATH_GL11:
680 case RENDERPATH_GL13:
681 case RENDERPATH_GL20:
682 case RENDERPATH_CGGL:
683 // LordHavoc: allow any alignment
685 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
686 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
688 case RENDERPATH_D3D9:
690 case RENDERPATH_D3D10:
691 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
693 case RENDERPATH_D3D11:
694 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
698 texturemempool = Mem_AllocPool("texture management", 0, NULL);
699 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
701 // Disable JPEG screenshots if the DLL isn't loaded
702 if (! JPEG_OpenLibrary ())
703 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
704 if (! PNG_OpenLibrary ())
705 Cvar_SetValueQuick (&scr_screenshot_png, 0);
708 static void r_textures_shutdown(void)
710 rtexturepool_t *temp;
712 JPEG_CloseLibrary ();
714 while(gltexturepoolchain)
716 temp = (rtexturepool_t *) gltexturepoolchain;
717 R_FreeTexturePool(&temp);
720 resizebuffersize = 0;
722 colorconvertbuffer = NULL;
723 texturebuffer = NULL;
724 Mem_ExpandableArray_FreeArray(&texturearray);
725 Mem_FreePool(&texturemempool);
728 static void r_textures_newmap(void)
732 static void r_textures_devicelost(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:
751 if (glt->d3disdepthsurface)
752 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
753 else if (glt->tiledepth > 1)
754 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
755 else if (glt->sides == 6)
756 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
758 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
759 glt->d3dtexture = NULL;
762 case RENDERPATH_D3D10:
763 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
765 case RENDERPATH_D3D11:
766 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
772 static void r_textures_devicerestored(void)
776 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
777 for (i = 0;i < endindex;i++)
779 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
780 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
782 switch(vid.renderpath)
784 case RENDERPATH_GL11:
785 case RENDERPATH_GL13:
786 case RENDERPATH_GL20:
787 case RENDERPATH_CGGL:
789 case RENDERPATH_D3D9:
793 if (glt->d3disdepthsurface)
795 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
796 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
798 else if (glt->tiledepth > 1)
800 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)))
801 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
803 else if (glt->sides == 6)
805 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
806 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
810 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)))
811 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
816 case RENDERPATH_D3D10:
817 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
819 case RENDERPATH_D3D11:
820 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
827 void R_Textures_Init (void)
829 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");
830 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
831 Cvar_RegisterVariable (&gl_max_size);
832 Cvar_RegisterVariable (&gl_picmip);
833 Cvar_RegisterVariable (&gl_picmip_world);
834 Cvar_RegisterVariable (&r_picmipworld);
835 Cvar_RegisterVariable (&gl_picmip_sprites);
836 Cvar_RegisterVariable (&r_picmipsprites);
837 Cvar_RegisterVariable (&gl_picmip_other);
838 Cvar_RegisterVariable (&gl_max_lightmapsize);
839 Cvar_RegisterVariable (&r_lerpimages);
840 Cvar_RegisterVariable (&gl_texture_anisotropy);
841 Cvar_RegisterVariable (&gl_texturecompression);
842 Cvar_RegisterVariable (&gl_texturecompression_color);
843 Cvar_RegisterVariable (&gl_texturecompression_normal);
844 Cvar_RegisterVariable (&gl_texturecompression_gloss);
845 Cvar_RegisterVariable (&gl_texturecompression_glow);
846 Cvar_RegisterVariable (&gl_texturecompression_2d);
847 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
848 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
849 Cvar_RegisterVariable (&gl_texturecompression_sky);
850 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
851 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
852 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
853 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
855 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
858 void R_Textures_Frame (void)
860 static int old_aniso = 0;
862 // could do procedural texture animation here, if we keep track of which
863 // textures were accessed this frame...
865 // free the resize buffers
866 resizebuffersize = 0;
869 Mem_Free(resizebuffer);
872 if (colorconvertbuffer)
874 Mem_Free(colorconvertbuffer);
875 colorconvertbuffer = NULL;
878 if (old_aniso != gl_texture_anisotropy.integer)
881 gltexturepool_t *pool;
884 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
886 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
888 switch(vid.renderpath)
890 case RENDERPATH_GL11:
891 case RENDERPATH_GL13:
892 case RENDERPATH_GL20:
893 case RENDERPATH_CGGL:
896 for (pool = gltexturepoolchain;pool;pool = pool->next)
898 for (glt = pool->gltchain;glt;glt = glt->chain)
900 // only update already uploaded images
901 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
903 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
905 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
906 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
908 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
913 case RENDERPATH_D3D9:
914 case RENDERPATH_D3D10:
915 case RENDERPATH_D3D11:
921 void R_MakeResizeBufferBigger(int size)
923 if (resizebuffersize < size)
925 resizebuffersize = size;
927 Mem_Free(resizebuffer);
928 if (colorconvertbuffer)
929 Mem_Free(colorconvertbuffer);
930 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
931 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
932 if (!resizebuffer || !colorconvertbuffer)
933 Host_Error("R_Upload: out of memory");
937 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
939 int textureenum = gltexturetypeenums[texturetype];
940 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
944 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
946 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
947 if (gl_texture_anisotropy.integer != aniso)
948 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
949 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
951 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
952 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
953 if (gltexturetypedimensions[texturetype] >= 3)
955 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
959 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
961 if (flags & TEXF_MIPMAP)
963 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
967 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
969 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
971 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
973 if (flags & TEXF_MIPMAP)
975 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
977 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
981 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
986 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
988 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
992 if (flags & TEXF_MIPMAP)
994 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
998 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1000 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1003 if (textype == TEXTYPE_SHADOWMAP)
1005 if (vid.support.arb_shadow)
1007 if (flags & TEXF_COMPARE)
1009 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1013 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1015 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1017 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1023 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1026 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1028 if (glt->texturetype != GLTEXTURETYPE_2D)
1029 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1031 if (glt->textype->textype == TEXTYPE_PALETTE)
1032 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1034 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1035 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1037 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1038 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1040 // update a portion of the image
1042 switch(vid.renderpath)
1044 case RENDERPATH_GL11:
1045 case RENDERPATH_GL13:
1046 case RENDERPATH_GL20:
1047 case RENDERPATH_CGGL:
1051 // we need to restore the texture binding after finishing the upload
1052 GL_ActiveTexture(0);
1053 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1054 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1055 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1056 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1059 case RENDERPATH_D3D9:
1063 D3DLOCKED_RECT d3dlockedrect;
1065 memset(&d3drect, 0, sizeof(d3drect));
1066 d3drect.left = fragx;
1067 d3drect.top = fragy;
1068 d3drect.right = fragx+fragwidth;
1069 d3drect.bottom = fragy+fragheight;
1070 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1072 for (y = 0;y < fragheight;y++)
1073 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1074 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1079 case RENDERPATH_D3D10:
1080 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1082 case RENDERPATH_D3D11:
1083 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1088 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1090 int i, mip = 0, width, height, depth;
1091 GLint oldbindtexnum = 0;
1092 const unsigned char *prevbuffer;
1095 // error out if a stretch is needed on special texture types
1096 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1097 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1099 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1100 // of the target size and then use the mipmap reduction function to get
1101 // high quality supersampled results
1102 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1103 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1104 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1105 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1107 if (prevbuffer == NULL)
1109 width = glt->tilewidth;
1110 height = glt->tileheight;
1111 depth = glt->tiledepth;
1112 memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1113 prevbuffer = resizebuffer;
1115 else if (glt->textype->textype == TEXTYPE_PALETTE)
1117 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1118 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1119 prevbuffer = colorconvertbuffer;
1122 // scale up to a power of 2 size (if appropriate)
1123 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1125 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1126 prevbuffer = resizebuffer;
1128 // apply mipmap reduction algorithm to get down to picmip/max_size
1129 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1131 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1132 prevbuffer = resizebuffer;
1135 // do the appropriate upload type...
1136 switch(vid.renderpath)
1138 case RENDERPATH_GL11:
1139 case RENDERPATH_GL13:
1140 case RENDERPATH_GL20:
1141 case RENDERPATH_CGGL:
1144 // we need to restore the texture binding after finishing the upload
1145 GL_ActiveTexture(0);
1146 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1147 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1149 if (qglGetCompressedTexImageARB)
1151 if (gl_texturecompression.integer >= 2)
1152 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1154 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1157 switch(glt->texturetype)
1159 case GLTEXTURETYPE_2D:
1160 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1161 if (glt->flags & TEXF_MIPMAP)
1163 while (width > 1 || height > 1 || depth > 1)
1165 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1166 prevbuffer = resizebuffer;
1167 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1171 case GLTEXTURETYPE_3D:
1172 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1173 if (glt->flags & TEXF_MIPMAP)
1175 while (width > 1 || height > 1 || depth > 1)
1177 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1178 prevbuffer = resizebuffer;
1179 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1183 case GLTEXTURETYPE_CUBEMAP:
1184 // convert and upload each side in turn,
1185 // from a continuous block of input texels
1186 texturebuffer = (unsigned char *)prevbuffer;
1187 for (i = 0;i < 6;i++)
1189 prevbuffer = texturebuffer;
1190 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1191 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1193 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1194 prevbuffer = resizebuffer;
1197 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1199 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1200 prevbuffer = resizebuffer;
1203 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1204 if (glt->flags & TEXF_MIPMAP)
1206 while (width > 1 || height > 1 || depth > 1)
1208 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1209 prevbuffer = resizebuffer;
1210 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1216 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1217 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1219 case RENDERPATH_D3D9:
1221 if (!(glt->flags & TEXF_RENDERTARGET))
1223 D3DLOCKED_RECT d3dlockedrect;
1224 D3DLOCKED_BOX d3dlockedbox;
1225 switch(glt->texturetype)
1227 case GLTEXTURETYPE_2D:
1228 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1231 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1233 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1234 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1237 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1239 while (width > 1 || height > 1 || depth > 1)
1241 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1242 prevbuffer = resizebuffer;
1243 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1245 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1246 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1252 case GLTEXTURETYPE_3D:
1253 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1255 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1256 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1257 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1260 if (glt->flags & TEXF_MIPMAP)
1262 while (width > 1 || height > 1 || depth > 1)
1264 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1265 prevbuffer = resizebuffer;
1266 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1268 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1269 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1270 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1276 case GLTEXTURETYPE_CUBEMAP:
1277 // convert and upload each side in turn,
1278 // from a continuous block of input texels
1279 texturebuffer = (unsigned char *)prevbuffer;
1280 for (i = 0;i < 6;i++)
1282 prevbuffer = texturebuffer;
1283 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1284 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1286 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1287 prevbuffer = resizebuffer;
1290 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1292 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1293 prevbuffer = resizebuffer;
1296 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1298 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1299 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1302 if (glt->flags & TEXF_MIPMAP)
1304 while (width > 1 || height > 1 || depth > 1)
1306 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1307 prevbuffer = resizebuffer;
1308 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1310 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1311 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1320 glt->d3daddressw = 0;
1321 if (glt->flags & TEXF_CLAMP)
1323 glt->d3daddressu = D3DTADDRESS_CLAMP;
1324 glt->d3daddressv = D3DTADDRESS_CLAMP;
1325 if (glt->tiledepth > 1)
1326 glt->d3daddressw = D3DTADDRESS_CLAMP;
1330 glt->d3daddressu = D3DTADDRESS_WRAP;
1331 glt->d3daddressv = D3DTADDRESS_WRAP;
1332 if (glt->tiledepth > 1)
1333 glt->d3daddressw = D3DTADDRESS_WRAP;
1335 glt->d3dmipmaplodbias = 0;
1336 glt->d3dmaxmiplevel = 0;
1337 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1338 if (glt->flags & TEXF_FORCELINEAR)
1340 glt->d3dminfilter = D3DTEXF_LINEAR;
1341 glt->d3dmagfilter = D3DTEXF_LINEAR;
1342 glt->d3dmipfilter = D3DTEXF_POINT;
1344 else if (glt->flags & TEXF_FORCENEAREST)
1346 glt->d3dminfilter = D3DTEXF_POINT;
1347 glt->d3dmagfilter = D3DTEXF_POINT;
1348 glt->d3dmipfilter = D3DTEXF_POINT;
1350 else if (glt->flags & TEXF_MIPMAP)
1352 glt->d3dminfilter = d3d_filter_mipmin;
1353 glt->d3dmagfilter = d3d_filter_mipmag;
1354 glt->d3dmipfilter = d3d_filter_mipmix;
1358 glt->d3dminfilter = d3d_filter_flatmin;
1359 glt->d3dmagfilter = d3d_filter_flatmag;
1360 glt->d3dmipfilter = d3d_filter_flatmix;
1364 case RENDERPATH_D3D10:
1365 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1367 case RENDERPATH_D3D11:
1368 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1373 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)
1377 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1378 textypeinfo_t *texinfo, *texinfo2;
1379 unsigned char *temppixels = NULL;
1381 if (cls.state == ca_dedicated)
1384 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1386 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1389 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1391 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1395 texinfo = R_GetTexTypeInfo(textype, flags);
1396 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1399 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1403 if (textype == TEXTYPE_RGBA)
1406 static int rgbaswapindices[4] = {2, 1, 0, 3};
1407 textype = TEXTYPE_BGRA;
1408 texinfo = R_GetTexTypeInfo(textype, flags);
1409 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1410 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1414 // clear the alpha flag if the texture has no transparent pixels
1417 case TEXTYPE_PALETTE:
1418 if (flags & TEXF_ALPHA)
1420 flags &= ~TEXF_ALPHA;
1423 for (i = 0;i < size;i++)
1425 if (((unsigned char *)&palette[data[i]])[3] < 255)
1427 flags |= TEXF_ALPHA;
1436 if (flags & TEXF_ALPHA)
1438 flags &= ~TEXF_ALPHA;
1441 for (i = 3;i < size;i += 4)
1445 flags |= TEXF_ALPHA;
1452 case TEXTYPE_SHADOWMAP:
1459 flags |= TEXF_ALPHA;
1462 flags |= TEXF_ALPHA;
1464 case TEXTYPE_COLORBUFFER:
1465 flags |= TEXF_ALPHA;
1468 Sys_Error("R_LoadTexture: unknown texture type");
1471 texinfo2 = R_GetTexTypeInfo(textype, flags);
1472 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1475 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1477 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1479 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1481 glt->chain = pool->gltchain;
1482 pool->gltchain = glt;
1483 glt->inputwidth = width;
1484 glt->inputheight = height;
1485 glt->inputdepth = depth;
1487 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
1488 glt->textype = texinfo;
1489 glt->texturetype = texturetype;
1490 glt->inputdatasize = size;
1491 glt->palette = palette;
1492 glt->glinternalformat = texinfo->glinternalformat;
1493 glt->glformat = texinfo->glformat;
1494 glt->gltype = texinfo->gltype;
1495 glt->bytesperpixel = texinfo->internalbytesperpixel;
1496 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1499 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1500 // init the dynamic texture attributes, too [11/22/2007 Black]
1501 glt->updatecallback = NULL;
1502 glt->updatacallback_data = NULL;
1504 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1506 // upload the texture
1507 // data may be NULL (blank texture for dynamic rendering)
1508 switch(vid.renderpath)
1510 case RENDERPATH_GL11:
1511 case RENDERPATH_GL13:
1512 case RENDERPATH_GL20:
1513 case RENDERPATH_CGGL:
1515 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1517 case RENDERPATH_D3D9:
1520 D3DFORMAT d3dformat;
1525 d3dpool = D3DPOOL_MANAGED;
1526 if (flags & TEXF_RENDERTARGET)
1528 d3dusage |= D3DUSAGE_RENDERTARGET;
1529 d3dpool = D3DPOOL_DEFAULT;
1533 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1534 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1535 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1536 case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1537 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1538 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1539 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1541 glt->d3dformat = d3dformat;
1542 glt->d3dusage = d3dusage;
1543 glt->d3dpool = d3dpool;
1544 glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1545 if (glt->d3disdepthsurface)
1547 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1548 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1550 else if (glt->tiledepth > 1)
1552 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)))
1553 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1555 else if (glt->sides == 6)
1557 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1558 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1562 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)))
1563 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1568 case RENDERPATH_D3D10:
1569 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1571 case RENDERPATH_D3D11:
1572 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1576 R_UploadFullTexture(glt, data);
1577 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1578 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1580 // free any temporary processing buffer we allocated...
1582 Mem_Free(temppixels);
1584 // texture converting and uploading can take a while, so make sure we're sending keepalives
1585 // FIXME: this causes rendering during R_Shadow_DrawLights
1586 // CL_KeepaliveMessage(false);
1588 return (rtexture_t *)glt;
1591 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)
1593 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1596 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)
1598 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1601 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)
1603 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1606 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1608 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1610 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1612 flags |= TEXF_FORCENEAREST;
1613 if (precision <= 16)
1614 flags |= TEXF_LOWPRECISION;
1618 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1620 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1623 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1625 gltexture_t *glt = (gltexture_t *)rt;
1628 int bytesperpixel = 0;
1629 int bytesperblock = 0;
1631 int dds_format_flags;
1639 GLint internalformat;
1640 const char *ddsfourcc;
1642 return -1; // NULL pointer
1643 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1644 return -2; // broken driver - crashes on reading internal format
1645 if (!qglGetTexLevelParameteriv)
1647 GL_ActiveTexture(0);
1648 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1649 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1650 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1651 switch(internalformat)
1653 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1654 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1655 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1656 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1657 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1659 if (!bytesperblock && skipuncompressed)
1660 return -3; // skipped
1661 memset(mipinfo, 0, sizeof(mipinfo));
1662 mipinfo[0][0] = glt->tilewidth;
1663 mipinfo[0][1] = glt->tileheight;
1665 if (glt->flags & TEXF_MIPMAP)
1667 for (mip = 1;mip < 16;mip++)
1669 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1670 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1671 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1679 for (mip = 0;mip < mipmaps;mip++)
1681 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1682 mipinfo[mip][3] = ddssize;
1683 ddssize += mipinfo[mip][2];
1685 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1688 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1692 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1693 dds_format_flags = 0x4; // DDPF_FOURCC
1697 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1698 dds_format_flags = 0x40; // DDPF_RGB
1702 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1703 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1706 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1707 memcpy(dds, "DDS ", 4);
1708 StoreLittleLong(dds+4, ddssize);
1709 StoreLittleLong(dds+8, dds_flags);
1710 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1711 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1712 StoreLittleLong(dds+24, 1); // depth
1713 StoreLittleLong(dds+28, mipmaps); // mipmaps
1714 StoreLittleLong(dds+76, 32); // format size
1715 StoreLittleLong(dds+80, dds_format_flags);
1716 StoreLittleLong(dds+108, dds_caps1);
1717 StoreLittleLong(dds+112, dds_caps2);
1720 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1721 memcpy(dds+84, ddsfourcc, 4);
1722 for (mip = 0;mip < mipmaps;mip++)
1724 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1729 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1730 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1731 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1732 for (mip = 0;mip < mipmaps;mip++)
1734 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1737 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1738 ret = FS_WriteFile(filename, dds, ddssize);
1740 return ret ? ddssize : -5;
1743 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
1745 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1748 int bytesperblock, bytesperpixel;
1751 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1752 textypeinfo_t *texinfo;
1753 int mip, mipwidth, mipheight, mipsize;
1755 GLint oldbindtexnum = 0;
1756 const unsigned char *mippixels, *ddspixels;
1758 fs_offset_t ddsfilesize;
1759 unsigned int ddssize;
1761 if (cls.state == ca_dedicated)
1764 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1765 ddssize = ddsfilesize;
1769 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1770 return NULL; // not found
1773 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1776 Con_Printf("^1%s: not a DDS image\n", filename);
1780 //dds_flags = BuffLittleLong(dds+8);
1781 dds_format_flags = BuffLittleLong(dds+80);
1782 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1783 dds_width = BuffLittleLong(dds+16);
1784 dds_height = BuffLittleLong(dds+12);
1785 ddspixels = dds + 128;
1787 if(r_texture_dds_load_alphamode.integer == 0)
1788 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1789 flags &= ~TEXF_ALPHA;
1791 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1792 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1794 // very sloppy BGRA 32bit identification
1795 textype = TEXTYPE_BGRA;
1798 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1799 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1802 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1805 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1808 for (i = 3;i < size;i += 4)
1809 if (ddspixels[i] < 255)
1812 flags &= ~TEXF_ALPHA;
1815 else if (!memcmp(dds+84, "DXT1", 4))
1817 if(!vid.support.ext_texture_compression_s3tc)
1822 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1823 // LordHavoc: it is my belief that this does not infringe on the
1824 // patent because it is not decoding pixels...
1825 textype = TEXTYPE_DXT1;
1828 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1829 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1830 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1833 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1836 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1838 if(r_texture_dds_load_alphamode.integer == 1)
1841 for (i = 0;i < size;i += bytesperblock)
1842 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1844 // NOTE: this assumes sizeof(unsigned int) == 4
1845 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1846 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1847 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1851 textype = TEXTYPE_DXT1A;
1853 flags &= ~TEXF_ALPHA;
1857 flags &= ~TEXF_ALPHA;
1861 else if (!memcmp(dds+84, "DXT3", 4))
1863 if(!vid.support.ext_texture_compression_s3tc)
1868 textype = TEXTYPE_DXT3;
1871 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1872 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1875 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1878 // we currently always assume alpha
1880 else if (!memcmp(dds+84, "DXT5", 4))
1882 if(!vid.support.ext_texture_compression_s3tc)
1887 textype = TEXTYPE_DXT5;
1890 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1891 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1894 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1897 // we currently always assume alpha
1902 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1906 // return whether this texture is transparent
1908 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1910 // calculate average color if requested
1914 Vector4Clear(avgcolor);
1917 for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
1919 c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
1920 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1921 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
1922 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
1924 f = (float)bytesperblock / size;
1925 avgcolor[0] *= (0.5f / 31.0f) * f;
1926 avgcolor[1] *= (0.5f / 63.0f) * f;
1927 avgcolor[2] *= (0.5f / 31.0f) * f;
1928 avgcolor[3] = 1; // too hard to calculate
1932 for (i = 0;i < size;i += 4)
1934 avgcolor[0] += ddspixels[i+2];
1935 avgcolor[1] += ddspixels[i+1];
1936 avgcolor[2] += ddspixels[i];
1937 avgcolor[3] += ddspixels[i+3];
1939 f = (1.0f / 255.0f) * bytesperpixel / size;
1947 // this is where we apply gl_picmip
1948 mippixels = ddspixels;
1949 mipwidth = dds_width;
1950 mipheight = dds_height;
1951 while(miplevel >= 1 && dds_miplevels >= 1)
1953 if (mipwidth <= 1 && mipheight <= 1)
1955 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1956 mippixels += mipsize; // just skip
1965 // when not requesting mipmaps, do not load them
1966 if(!(flags & TEXF_MIPMAP))
1969 if (dds_miplevels >= 1)
1970 flags |= TEXF_MIPMAP;
1972 flags &= ~TEXF_MIPMAP;
1974 // if S3TC is not supported, there's very little we can do about it
1975 if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
1978 Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
1982 texinfo = R_GetTexTypeInfo(textype, flags);
1984 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1985 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
1987 glt->chain = pool->gltchain;
1988 pool->gltchain = glt;
1989 glt->inputwidth = mipwidth;
1990 glt->inputheight = mipheight;
1991 glt->inputdepth = 1;
1993 glt->textype = texinfo;
1994 glt->texturetype = GLTEXTURETYPE_2D;
1995 glt->inputdatasize = ddssize;
1996 glt->glinternalformat = texinfo->glinternalformat;
1997 glt->glformat = texinfo->glformat;
1998 glt->gltype = texinfo->gltype;
1999 glt->bytesperpixel = texinfo->internalbytesperpixel;
2001 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2002 glt->tilewidth = mipwidth;
2003 glt->tileheight = mipheight;
2005 glt->miplevels = dds_miplevels;
2007 // texture uploading can take a while, so make sure we're sending keepalives
2008 CL_KeepaliveMessage(false);
2010 // create the texture object
2011 switch(vid.renderpath)
2013 case RENDERPATH_GL11:
2014 case RENDERPATH_GL13:
2015 case RENDERPATH_GL20:
2016 case RENDERPATH_CGGL:
2018 GL_ActiveTexture(0);
2019 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2020 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2021 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2023 case RENDERPATH_D3D9:
2026 D3DFORMAT d3dformat;
2031 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2032 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2033 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2034 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2035 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2038 d3dpool = D3DPOOL_MANAGED;
2039 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2043 case RENDERPATH_D3D10:
2044 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2046 case RENDERPATH_D3D11:
2047 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2051 // upload the texture
2052 // we need to restore the texture binding after finishing the upload
2053 mipcomplete = false;
2055 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2057 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2058 if (mippixels + mipsize > dds + ddssize)
2060 switch(vid.renderpath)
2062 case RENDERPATH_GL11:
2063 case RENDERPATH_GL13:
2064 case RENDERPATH_GL20:
2065 case RENDERPATH_CGGL:
2068 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2072 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2075 case RENDERPATH_D3D9:
2078 D3DLOCKED_RECT d3dlockedrect;
2079 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2081 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2082 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2088 case RENDERPATH_D3D10:
2089 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2091 case RENDERPATH_D3D11:
2092 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2095 mippixels += mipsize;
2096 if (mipwidth <= 1 && mipheight <= 1)
2107 // after upload we have to set some parameters...
2108 switch(vid.renderpath)
2110 case RENDERPATH_GL11:
2111 case RENDERPATH_GL13:
2112 case RENDERPATH_GL20:
2113 case RENDERPATH_CGGL:
2114 if (dds_miplevels >= 1 && !mipcomplete)
2116 // need to set GL_TEXTURE_MAX_LEVEL
2117 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2119 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2120 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2122 case RENDERPATH_D3D9:
2124 glt->d3daddressw = 0;
2125 if (glt->flags & TEXF_CLAMP)
2127 glt->d3daddressu = D3DTADDRESS_CLAMP;
2128 glt->d3daddressv = D3DTADDRESS_CLAMP;
2129 if (glt->tiledepth > 1)
2130 glt->d3daddressw = D3DTADDRESS_CLAMP;
2134 glt->d3daddressu = D3DTADDRESS_WRAP;
2135 glt->d3daddressv = D3DTADDRESS_WRAP;
2136 if (glt->tiledepth > 1)
2137 glt->d3daddressw = D3DTADDRESS_WRAP;
2139 glt->d3dmipmaplodbias = 0;
2140 glt->d3dmaxmiplevel = 0;
2141 glt->d3dmaxmiplevelfilter = 0;
2142 if (glt->flags & TEXF_MIPMAP)
2144 glt->d3dminfilter = d3d_filter_mipmin;
2145 glt->d3dmagfilter = d3d_filter_mipmag;
2146 glt->d3dmipfilter = d3d_filter_mipmix;
2150 glt->d3dminfilter = d3d_filter_flatmin;
2151 glt->d3dmagfilter = d3d_filter_flatmag;
2152 glt->d3dmipfilter = d3d_filter_flatmix;
2156 case RENDERPATH_D3D10:
2157 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2159 case RENDERPATH_D3D11:
2160 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2165 return (rtexture_t *)glt;
2168 int R_TextureWidth(rtexture_t *rt)
2170 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2173 int R_TextureHeight(rtexture_t *rt)
2175 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2178 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
2180 gltexture_t *glt = (gltexture_t *)rt;
2182 Host_Error("R_UpdateTexture: no data supplied");
2184 Host_Error("R_UpdateTexture: no texture supplied");
2185 if (!glt->texnum && !glt->d3dtexture)
2187 Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", (void *)glt, glt->identifier, (void *)glt->pool);
2190 // update part of the texture
2191 if (glt->bufferpixels)
2194 int bpp = glt->bytesperpixel;
2195 int inputskip = width*bpp;
2196 int outputskip = glt->tilewidth*bpp;
2197 const unsigned char *input = data;
2198 unsigned char *output = glt->bufferpixels;
2208 input -= y*inputskip;
2211 if (width > glt->tilewidth - x)
2212 width = glt->tilewidth - x;
2213 if (height > glt->tileheight - y)
2214 height = glt->tileheight - y;
2215 if (width < 1 || height < 1)
2218 glt->buffermodified = true;
2219 output += y*outputskip + x*bpp;
2220 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2221 memcpy(output, input, width*bpp);
2223 else if (x || y || width != glt->inputwidth || height != glt->inputheight)
2224 R_UploadPartialTexture(glt, data, x, y, 0, width, height, 1);
2226 R_UploadFullTexture(glt, data);
2229 int R_RealGetTexture(rtexture_t *rt)
2234 glt = (gltexture_t *)rt;
2235 if (glt->flags & GLTEXF_DYNAMIC)
2236 R_UpdateDynamicTexture(glt);
2237 if (glt->buffermodified && glt->bufferpixels)
2239 glt->buffermodified = false;
2240 R_UploadFullTexture(glt, glt->bufferpixels);
2249 void R_ClearTexture (rtexture_t *rt)
2251 gltexture_t *glt = (gltexture_t *)rt;
2253 R_UploadFullTexture(glt, NULL);
2256 int R_PicmipForFlags(int flags)
2259 if(flags & TEXF_PICMIP)
2261 miplevel += gl_picmip.integer;
2262 if (flags & TEXF_ISWORLD)
2264 if (r_picmipworld.integer)
2265 miplevel += gl_picmip_world.integer;
2269 else if (flags & TEXF_ISSPRITE)
2271 if (r_picmipsprites.integer)
2272 miplevel += gl_picmip_sprites.integer;
2277 miplevel += gl_picmip_other.integer;
2279 return max(0, miplevel);