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 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1124 // multiply RGB channels by A channel before uploading
1126 for (i = 0;i < width*height*depth*4;i += 4)
1128 alpha = prevbuffer[i+3];
1129 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1130 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1131 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1132 colorconvertbuffer[i+3] = alpha;
1134 prevbuffer = colorconvertbuffer;
1137 // scale up to a power of 2 size (if appropriate)
1138 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1140 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1141 prevbuffer = resizebuffer;
1143 // apply mipmap reduction algorithm to get down to picmip/max_size
1144 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1146 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1147 prevbuffer = resizebuffer;
1150 // do the appropriate upload type...
1151 switch(vid.renderpath)
1153 case RENDERPATH_GL11:
1154 case RENDERPATH_GL13:
1155 case RENDERPATH_GL20:
1156 case RENDERPATH_CGGL:
1159 // we need to restore the texture binding after finishing the upload
1160 GL_ActiveTexture(0);
1161 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1162 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1164 if (qglGetCompressedTexImageARB)
1166 if (gl_texturecompression.integer >= 2)
1167 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1169 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1172 switch(glt->texturetype)
1174 case GLTEXTURETYPE_2D:
1175 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1176 if (glt->flags & TEXF_MIPMAP)
1178 while (width > 1 || height > 1 || depth > 1)
1180 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1181 prevbuffer = resizebuffer;
1182 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1186 case GLTEXTURETYPE_3D:
1187 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1188 if (glt->flags & TEXF_MIPMAP)
1190 while (width > 1 || height > 1 || depth > 1)
1192 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1193 prevbuffer = resizebuffer;
1194 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1198 case GLTEXTURETYPE_CUBEMAP:
1199 // convert and upload each side in turn,
1200 // from a continuous block of input texels
1201 texturebuffer = (unsigned char *)prevbuffer;
1202 for (i = 0;i < 6;i++)
1204 prevbuffer = texturebuffer;
1205 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1206 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1208 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1209 prevbuffer = resizebuffer;
1212 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1214 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1215 prevbuffer = resizebuffer;
1218 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1219 if (glt->flags & TEXF_MIPMAP)
1221 while (width > 1 || height > 1 || depth > 1)
1223 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1224 prevbuffer = resizebuffer;
1225 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1231 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1232 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1234 case RENDERPATH_D3D9:
1236 if (!(glt->flags & TEXF_RENDERTARGET))
1238 D3DLOCKED_RECT d3dlockedrect;
1239 D3DLOCKED_BOX d3dlockedbox;
1240 switch(glt->texturetype)
1242 case GLTEXTURETYPE_2D:
1243 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1246 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1248 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1249 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1252 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1254 while (width > 1 || height > 1 || depth > 1)
1256 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1257 prevbuffer = resizebuffer;
1258 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1260 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1261 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1267 case GLTEXTURETYPE_3D:
1268 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1270 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1271 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1272 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1275 if (glt->flags & TEXF_MIPMAP)
1277 while (width > 1 || height > 1 || depth > 1)
1279 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1280 prevbuffer = resizebuffer;
1281 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1283 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1284 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1285 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1291 case GLTEXTURETYPE_CUBEMAP:
1292 // convert and upload each side in turn,
1293 // from a continuous block of input texels
1294 texturebuffer = (unsigned char *)prevbuffer;
1295 for (i = 0;i < 6;i++)
1297 prevbuffer = texturebuffer;
1298 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1299 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1301 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1302 prevbuffer = resizebuffer;
1305 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1307 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1308 prevbuffer = resizebuffer;
1311 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1313 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1314 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1317 if (glt->flags & TEXF_MIPMAP)
1319 while (width > 1 || height > 1 || depth > 1)
1321 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1322 prevbuffer = resizebuffer;
1323 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1325 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1326 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1335 glt->d3daddressw = 0;
1336 if (glt->flags & TEXF_CLAMP)
1338 glt->d3daddressu = D3DTADDRESS_CLAMP;
1339 glt->d3daddressv = D3DTADDRESS_CLAMP;
1340 if (glt->tiledepth > 1)
1341 glt->d3daddressw = D3DTADDRESS_CLAMP;
1345 glt->d3daddressu = D3DTADDRESS_WRAP;
1346 glt->d3daddressv = D3DTADDRESS_WRAP;
1347 if (glt->tiledepth > 1)
1348 glt->d3daddressw = D3DTADDRESS_WRAP;
1350 glt->d3dmipmaplodbias = 0;
1351 glt->d3dmaxmiplevel = 0;
1352 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1353 if (glt->flags & TEXF_FORCELINEAR)
1355 glt->d3dminfilter = D3DTEXF_LINEAR;
1356 glt->d3dmagfilter = D3DTEXF_LINEAR;
1357 glt->d3dmipfilter = D3DTEXF_POINT;
1359 else if (glt->flags & TEXF_FORCENEAREST)
1361 glt->d3dminfilter = D3DTEXF_POINT;
1362 glt->d3dmagfilter = D3DTEXF_POINT;
1363 glt->d3dmipfilter = D3DTEXF_POINT;
1365 else if (glt->flags & TEXF_MIPMAP)
1367 glt->d3dminfilter = d3d_filter_mipmin;
1368 glt->d3dmagfilter = d3d_filter_mipmag;
1369 glt->d3dmipfilter = d3d_filter_mipmix;
1373 glt->d3dminfilter = d3d_filter_flatmin;
1374 glt->d3dmagfilter = d3d_filter_flatmag;
1375 glt->d3dmipfilter = d3d_filter_flatmix;
1379 case RENDERPATH_D3D10:
1380 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1382 case RENDERPATH_D3D11:
1383 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1388 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)
1392 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1393 textypeinfo_t *texinfo, *texinfo2;
1394 unsigned char *temppixels = NULL;
1396 if (cls.state == ca_dedicated)
1399 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1401 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1404 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1406 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1410 texinfo = R_GetTexTypeInfo(textype, flags);
1411 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1414 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1418 if (textype == TEXTYPE_RGBA)
1421 static int rgbaswapindices[4] = {2, 1, 0, 3};
1422 textype = TEXTYPE_BGRA;
1423 texinfo = R_GetTexTypeInfo(textype, flags);
1424 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1425 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1429 // clear the alpha flag if the texture has no transparent pixels
1432 case TEXTYPE_PALETTE:
1433 if (flags & TEXF_ALPHA)
1435 flags &= ~TEXF_ALPHA;
1438 for (i = 0;i < size;i++)
1440 if (((unsigned char *)&palette[data[i]])[3] < 255)
1442 flags |= TEXF_ALPHA;
1451 if (flags & TEXF_ALPHA)
1453 flags &= ~TEXF_ALPHA;
1456 for (i = 3;i < size;i += 4)
1460 flags |= TEXF_ALPHA;
1467 case TEXTYPE_SHADOWMAP:
1474 flags |= TEXF_ALPHA;
1477 flags |= TEXF_ALPHA;
1479 case TEXTYPE_COLORBUFFER:
1480 flags |= TEXF_ALPHA;
1483 Sys_Error("R_LoadTexture: unknown texture type");
1486 texinfo2 = R_GetTexTypeInfo(textype, flags);
1487 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1490 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1492 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1494 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1496 glt->chain = pool->gltchain;
1497 pool->gltchain = glt;
1498 glt->inputwidth = width;
1499 glt->inputheight = height;
1500 glt->inputdepth = depth;
1502 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
1503 glt->textype = texinfo;
1504 glt->texturetype = texturetype;
1505 glt->inputdatasize = size;
1506 glt->palette = palette;
1507 glt->glinternalformat = texinfo->glinternalformat;
1508 glt->glformat = texinfo->glformat;
1509 glt->gltype = texinfo->gltype;
1510 glt->bytesperpixel = texinfo->internalbytesperpixel;
1511 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1514 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1515 // init the dynamic texture attributes, too [11/22/2007 Black]
1516 glt->updatecallback = NULL;
1517 glt->updatacallback_data = NULL;
1519 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1521 // upload the texture
1522 // data may be NULL (blank texture for dynamic rendering)
1523 switch(vid.renderpath)
1525 case RENDERPATH_GL11:
1526 case RENDERPATH_GL13:
1527 case RENDERPATH_GL20:
1528 case RENDERPATH_CGGL:
1530 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1532 case RENDERPATH_D3D9:
1535 D3DFORMAT d3dformat;
1540 d3dpool = D3DPOOL_MANAGED;
1541 if (flags & TEXF_RENDERTARGET)
1543 d3dusage |= D3DUSAGE_RENDERTARGET;
1544 d3dpool = D3DPOOL_DEFAULT;
1548 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1549 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1550 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1551 case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1552 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1553 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1554 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1556 glt->d3dformat = d3dformat;
1557 glt->d3dusage = d3dusage;
1558 glt->d3dpool = d3dpool;
1559 glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1560 if (glt->d3disdepthsurface)
1562 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1563 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1565 else if (glt->tiledepth > 1)
1567 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)))
1568 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1570 else if (glt->sides == 6)
1572 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1573 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1577 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)))
1578 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1583 case RENDERPATH_D3D10:
1584 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1586 case RENDERPATH_D3D11:
1587 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1591 R_UploadFullTexture(glt, data);
1592 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1593 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1595 // free any temporary processing buffer we allocated...
1597 Mem_Free(temppixels);
1599 // texture converting and uploading can take a while, so make sure we're sending keepalives
1600 // FIXME: this causes rendering during R_Shadow_DrawLights
1601 // CL_KeepaliveMessage(false);
1603 return (rtexture_t *)glt;
1606 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)
1608 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1611 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)
1613 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1616 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)
1618 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1621 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1623 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1625 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1627 flags |= TEXF_FORCENEAREST;
1628 if (precision <= 16)
1629 flags |= TEXF_LOWPRECISION;
1633 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1635 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1638 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1640 gltexture_t *glt = (gltexture_t *)rt;
1643 int bytesperpixel = 0;
1644 int bytesperblock = 0;
1646 int dds_format_flags;
1654 GLint internalformat;
1655 const char *ddsfourcc;
1657 return -1; // NULL pointer
1658 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1659 return -2; // broken driver - crashes on reading internal format
1660 if (!qglGetTexLevelParameteriv)
1662 GL_ActiveTexture(0);
1663 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1664 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1665 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1666 switch(internalformat)
1668 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1669 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1670 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1671 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1672 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1674 if (!bytesperblock && skipuncompressed)
1675 return -3; // skipped
1676 memset(mipinfo, 0, sizeof(mipinfo));
1677 mipinfo[0][0] = glt->tilewidth;
1678 mipinfo[0][1] = glt->tileheight;
1680 if (glt->flags & TEXF_MIPMAP)
1682 for (mip = 1;mip < 16;mip++)
1684 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1685 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1686 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1694 for (mip = 0;mip < mipmaps;mip++)
1696 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1697 mipinfo[mip][3] = ddssize;
1698 ddssize += mipinfo[mip][2];
1700 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1703 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1707 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1708 dds_format_flags = 0x4; // DDPF_FOURCC
1712 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1713 dds_format_flags = 0x40; // DDPF_RGB
1717 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1718 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1721 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1722 memcpy(dds, "DDS ", 4);
1723 StoreLittleLong(dds+4, ddssize);
1724 StoreLittleLong(dds+8, dds_flags);
1725 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1726 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1727 StoreLittleLong(dds+24, 1); // depth
1728 StoreLittleLong(dds+28, mipmaps); // mipmaps
1729 StoreLittleLong(dds+76, 32); // format size
1730 StoreLittleLong(dds+80, dds_format_flags);
1731 StoreLittleLong(dds+108, dds_caps1);
1732 StoreLittleLong(dds+112, dds_caps2);
1735 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1736 memcpy(dds+84, ddsfourcc, 4);
1737 for (mip = 0;mip < mipmaps;mip++)
1739 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1744 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1745 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1746 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1747 for (mip = 0;mip < mipmaps;mip++)
1749 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1752 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1753 ret = FS_WriteFile(filename, dds, ddssize);
1755 return ret ? ddssize : -5;
1758 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
1760 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1763 int bytesperblock, bytesperpixel;
1766 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1767 textypeinfo_t *texinfo;
1768 int mip, mipwidth, mipheight, mipsize;
1770 GLint oldbindtexnum = 0;
1771 const unsigned char *mippixels, *ddspixels;
1773 fs_offset_t ddsfilesize;
1774 unsigned int ddssize;
1776 if (cls.state == ca_dedicated)
1779 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1780 ddssize = ddsfilesize;
1784 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1785 return NULL; // not found
1788 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1791 Con_Printf("^1%s: not a DDS image\n", filename);
1795 //dds_flags = BuffLittleLong(dds+8);
1796 dds_format_flags = BuffLittleLong(dds+80);
1797 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1798 dds_width = BuffLittleLong(dds+16);
1799 dds_height = BuffLittleLong(dds+12);
1800 ddspixels = dds + 128;
1802 if(r_texture_dds_load_alphamode.integer == 0)
1803 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1804 flags &= ~TEXF_ALPHA;
1806 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1807 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1809 // very sloppy BGRA 32bit identification
1810 textype = TEXTYPE_BGRA;
1813 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1814 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1817 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1820 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1823 for (i = 3;i < size;i += 4)
1824 if (ddspixels[i] < 255)
1827 flags &= ~TEXF_ALPHA;
1830 else if (!memcmp(dds+84, "DXT1", 4))
1832 if(!vid.support.ext_texture_compression_s3tc)
1837 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1838 // LordHavoc: it is my belief that this does not infringe on the
1839 // patent because it is not decoding pixels...
1840 textype = TEXTYPE_DXT1;
1843 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1844 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1845 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1848 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1851 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1853 if(r_texture_dds_load_alphamode.integer == 1)
1856 for (i = 0;i < size;i += bytesperblock)
1857 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1859 // NOTE: this assumes sizeof(unsigned int) == 4
1860 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1861 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1862 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1866 textype = TEXTYPE_DXT1A;
1868 flags &= ~TEXF_ALPHA;
1872 flags &= ~TEXF_ALPHA;
1876 else if (!memcmp(dds+84, "DXT3", 4))
1878 if(!vid.support.ext_texture_compression_s3tc)
1883 textype = TEXTYPE_DXT3;
1886 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1887 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1890 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1893 // we currently always assume alpha
1895 else if (!memcmp(dds+84, "DXT5", 4))
1897 if(!vid.support.ext_texture_compression_s3tc)
1902 textype = TEXTYPE_DXT5;
1905 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1906 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1909 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1912 // we currently always assume alpha
1917 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1921 // return whether this texture is transparent
1923 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1925 // calculate average color if requested
1929 Vector4Clear(avgcolor);
1932 for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
1934 c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
1935 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1936 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
1937 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
1939 f = (float)bytesperblock / size;
1940 avgcolor[0] *= (0.5f / 31.0f) * f;
1941 avgcolor[1] *= (0.5f / 63.0f) * f;
1942 avgcolor[2] *= (0.5f / 31.0f) * f;
1943 avgcolor[3] = 1; // too hard to calculate
1947 for (i = 0;i < size;i += 4)
1949 avgcolor[0] += ddspixels[i+2];
1950 avgcolor[1] += ddspixels[i+1];
1951 avgcolor[2] += ddspixels[i];
1952 avgcolor[3] += ddspixels[i+3];
1954 f = (1.0f / 255.0f) * bytesperpixel / size;
1962 // this is where we apply gl_picmip
1963 mippixels = ddspixels;
1964 mipwidth = dds_width;
1965 mipheight = dds_height;
1966 while(miplevel >= 1 && dds_miplevels >= 1)
1968 if (mipwidth <= 1 && mipheight <= 1)
1970 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1971 mippixels += mipsize; // just skip
1980 // when not requesting mipmaps, do not load them
1981 if(!(flags & TEXF_MIPMAP))
1984 if (dds_miplevels >= 1)
1985 flags |= TEXF_MIPMAP;
1987 flags &= ~TEXF_MIPMAP;
1989 // if S3TC is not supported, there's very little we can do about it
1990 if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
1993 Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
1997 texinfo = R_GetTexTypeInfo(textype, flags);
1999 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2000 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2002 glt->chain = pool->gltchain;
2003 pool->gltchain = glt;
2004 glt->inputwidth = mipwidth;
2005 glt->inputheight = mipheight;
2006 glt->inputdepth = 1;
2008 glt->textype = texinfo;
2009 glt->texturetype = GLTEXTURETYPE_2D;
2010 glt->inputdatasize = ddssize;
2011 glt->glinternalformat = texinfo->glinternalformat;
2012 glt->glformat = texinfo->glformat;
2013 glt->gltype = texinfo->gltype;
2014 glt->bytesperpixel = texinfo->internalbytesperpixel;
2016 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2017 glt->tilewidth = mipwidth;
2018 glt->tileheight = mipheight;
2020 glt->miplevels = dds_miplevels;
2022 // texture uploading can take a while, so make sure we're sending keepalives
2023 CL_KeepaliveMessage(false);
2025 // create the texture object
2026 switch(vid.renderpath)
2028 case RENDERPATH_GL11:
2029 case RENDERPATH_GL13:
2030 case RENDERPATH_GL20:
2031 case RENDERPATH_CGGL:
2033 GL_ActiveTexture(0);
2034 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2035 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2036 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2038 case RENDERPATH_D3D9:
2041 D3DFORMAT d3dformat;
2046 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2047 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2048 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2049 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2050 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2053 d3dpool = D3DPOOL_MANAGED;
2054 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2058 case RENDERPATH_D3D10:
2059 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2061 case RENDERPATH_D3D11:
2062 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2066 // upload the texture
2067 // we need to restore the texture binding after finishing the upload
2068 mipcomplete = false;
2070 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2072 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2073 if (mippixels + mipsize > dds + ddssize)
2075 switch(vid.renderpath)
2077 case RENDERPATH_GL11:
2078 case RENDERPATH_GL13:
2079 case RENDERPATH_GL20:
2080 case RENDERPATH_CGGL:
2083 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2087 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2090 case RENDERPATH_D3D9:
2093 D3DLOCKED_RECT d3dlockedrect;
2094 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2096 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2097 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2103 case RENDERPATH_D3D10:
2104 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2106 case RENDERPATH_D3D11:
2107 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2110 mippixels += mipsize;
2111 if (mipwidth <= 1 && mipheight <= 1)
2122 // after upload we have to set some parameters...
2123 switch(vid.renderpath)
2125 case RENDERPATH_GL11:
2126 case RENDERPATH_GL13:
2127 case RENDERPATH_GL20:
2128 case RENDERPATH_CGGL:
2129 if (dds_miplevels >= 1 && !mipcomplete)
2131 // need to set GL_TEXTURE_MAX_LEVEL
2132 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2134 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2135 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2137 case RENDERPATH_D3D9:
2139 glt->d3daddressw = 0;
2140 if (glt->flags & TEXF_CLAMP)
2142 glt->d3daddressu = D3DTADDRESS_CLAMP;
2143 glt->d3daddressv = D3DTADDRESS_CLAMP;
2144 if (glt->tiledepth > 1)
2145 glt->d3daddressw = D3DTADDRESS_CLAMP;
2149 glt->d3daddressu = D3DTADDRESS_WRAP;
2150 glt->d3daddressv = D3DTADDRESS_WRAP;
2151 if (glt->tiledepth > 1)
2152 glt->d3daddressw = D3DTADDRESS_WRAP;
2154 glt->d3dmipmaplodbias = 0;
2155 glt->d3dmaxmiplevel = 0;
2156 glt->d3dmaxmiplevelfilter = 0;
2157 if (glt->flags & TEXF_MIPMAP)
2159 glt->d3dminfilter = d3d_filter_mipmin;
2160 glt->d3dmagfilter = d3d_filter_mipmag;
2161 glt->d3dmipfilter = d3d_filter_mipmix;
2165 glt->d3dminfilter = d3d_filter_flatmin;
2166 glt->d3dmagfilter = d3d_filter_flatmag;
2167 glt->d3dmipfilter = d3d_filter_flatmix;
2171 case RENDERPATH_D3D10:
2172 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2174 case RENDERPATH_D3D11:
2175 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2180 return (rtexture_t *)glt;
2183 int R_TextureWidth(rtexture_t *rt)
2185 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2188 int R_TextureHeight(rtexture_t *rt)
2190 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2193 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
2195 gltexture_t *glt = (gltexture_t *)rt;
2197 Host_Error("R_UpdateTexture: no data supplied");
2199 Host_Error("R_UpdateTexture: no texture supplied");
2200 if (!glt->texnum && !glt->d3dtexture)
2202 Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", (void *)glt, glt->identifier, (void *)glt->pool);
2205 // update part of the texture
2206 if (glt->bufferpixels)
2209 int bpp = glt->bytesperpixel;
2210 int inputskip = width*bpp;
2211 int outputskip = glt->tilewidth*bpp;
2212 const unsigned char *input = data;
2213 unsigned char *output = glt->bufferpixels;
2223 input -= y*inputskip;
2226 if (width > glt->tilewidth - x)
2227 width = glt->tilewidth - x;
2228 if (height > glt->tileheight - y)
2229 height = glt->tileheight - y;
2230 if (width < 1 || height < 1)
2233 glt->buffermodified = true;
2234 output += y*outputskip + x*bpp;
2235 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2236 memcpy(output, input, width*bpp);
2238 else if (x || y || width != glt->inputwidth || height != glt->inputheight)
2239 R_UploadPartialTexture(glt, data, x, y, 0, width, height, 1);
2241 R_UploadFullTexture(glt, data);
2244 int R_RealGetTexture(rtexture_t *rt)
2249 glt = (gltexture_t *)rt;
2250 if (glt->flags & GLTEXF_DYNAMIC)
2251 R_UpdateDynamicTexture(glt);
2252 if (glt->buffermodified && glt->bufferpixels)
2254 glt->buffermodified = false;
2255 R_UploadFullTexture(glt, glt->bufferpixels);
2264 void R_ClearTexture (rtexture_t *rt)
2266 gltexture_t *glt = (gltexture_t *)rt;
2268 R_UploadFullTexture(glt, NULL);
2271 int R_PicmipForFlags(int flags)
2274 if(flags & TEXF_PICMIP)
2276 miplevel += gl_picmip.integer;
2277 if (flags & TEXF_ISWORLD)
2279 if (r_picmipworld.integer)
2280 miplevel += gl_picmip_world.integer;
2284 else if (flags & TEXF_ISSPRITE)
2286 if (r_picmipsprites.integer)
2287 miplevel += gl_picmip_sprites.integer;
2292 miplevel += gl_picmip_other.integer;
2294 return max(0, miplevel);