5 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
10 #include "intoverflow.h"
12 cvar_t gl_max_size = {CVAR_SAVE, "gl_max_size", "2048", "maximum allowed texture size, can be used to reduce video memory usage, limited by hardware capabilities (typically 2048, 4096, or 8192)"};
13 cvar_t gl_max_lightmapsize = {CVAR_SAVE, "gl_max_lightmapsize", "1024", "maximum allowed texture size for lightmap textures, use larger values to improve rendering speed, as long as there is enough video memory available (setting it too high for the hardware will cause very bad performance)"};
14 cvar_t gl_picmip = {CVAR_SAVE, "gl_picmip", "0", "reduces resolution of textures by powers of 2, for example 1 will halve width/height, reducing texture memory usage by 75%"};
15 cvar_t gl_picmip_world = {CVAR_SAVE, "gl_picmip_world", "0", "extra picmip level for world textures (may be negative, which will then reduce gl_picmip for these)"};
16 cvar_t r_picmipworld = {CVAR_SAVE, "r_picmipworld", "1", "whether gl_picmip shall apply to world textures too (setting this to 0 is a shorthand for gl_picmip_world -9999999)"};
17 cvar_t gl_picmip_sprites = {CVAR_SAVE, "gl_picmip_sprites", "0", "extra picmip level for sprite textures (may be negative, which will then reduce gl_picmip for these)"};
18 cvar_t r_picmipsprites = {CVAR_SAVE, "r_picmipsprites", "1", "make gl_picmip affect sprites too (saves some graphics memory in sprite heavy games) (setting this to 0 is a shorthand for gl_picmip_sprites -9999999)"};
19 cvar_t gl_picmip_other = {CVAR_SAVE, "gl_picmip_other", "0", "extra picmip level for other textures (may be negative, which will then reduce gl_picmip for these)"};
20 cvar_t r_lerpimages = {CVAR_SAVE, "r_lerpimages", "1", "bilinear filters images when scaling them up to power of 2 size (mode 1), looks better than glquake (mode 0)"};
21 cvar_t gl_texture_anisotropy = {CVAR_SAVE, "gl_texture_anisotropy", "1", "anisotropic filtering quality (if supported by hardware), 1 sample (no anisotropy) and 8 sample (8 tap anisotropy) are recommended values"};
22 cvar_t gl_texturecompression = {CVAR_SAVE, "gl_texturecompression", "0", "whether to compress textures, a value of 0 disables compression (even if the individual cvars are 1), 1 enables fast (low quality) compression at startup, 2 enables slow (high quality) compression at startup"};
23 cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
24 cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
25 cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
26 cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
27 cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
28 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
29 cvar_t gl_texturecompression_q3bspdeluxemaps = {CVAR_SAVE, "gl_texturecompression_q3bspdeluxemaps", "0", "whether to compress deluxemaps in q3bsp format levels (only levels compiled with q3map2 -deluxe have these)"};
30 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
31 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
32 cvar_t gl_texturecompression_reflectmask = {CVAR_SAVE, "gl_texturecompression_reflectmask", "1", "whether to compress reflection cubemap masks (mask of which areas of the texture should reflect the generic shiny cubemap)"};
33 cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "1", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"};
34 cvar_t r_texture_dds_load_alphamode = {0, "r_texture_dds_load_alphamode", "1", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambigous, 2: texture format only"};
36 qboolean gl_filter_force = false;
37 int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
38 int gl_filter_mag = GL_LINEAR;
41 int d3d_filter_flatmin = D3DTEXF_LINEAR;
42 int d3d_filter_flatmag = D3DTEXF_LINEAR;
43 int d3d_filter_flatmix = D3DTEXF_POINT;
44 int d3d_filter_mipmin = D3DTEXF_LINEAR;
45 int d3d_filter_mipmag = D3DTEXF_LINEAR;
46 int d3d_filter_mipmix = D3DTEXF_LINEAR;
47 int d3d_filter_nomip = false;
51 static mempool_t *texturemempool;
52 static memexpandablearray_t texturearray;
54 // note: this must not conflict with TEXF_ flags in r_textures.h
55 // bitmask for mismatch checking
56 #define GLTEXF_IMPORTANTBITS (0)
57 // dynamic texture (treat texnum == 0 differently)
58 #define GLTEXF_DYNAMIC 0x00080000
60 typedef struct textypeinfo_s
63 int inputbytesperpixel;
64 int internalbytesperpixel;
65 float glinternalbytesperpixel;
73 static textypeinfo_t textype_palette = {TEXTYPE_PALETTE , 1, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE };
74 static textypeinfo_t textype_palette_alpha = {TEXTYPE_PALETTE , 1, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
75 static textypeinfo_t textype_rgba = {TEXTYPE_RGBA , 4, 4, 4.0f, 3 , GL_RGBA , GL_UNSIGNED_BYTE };
76 static textypeinfo_t textype_rgba_alpha = {TEXTYPE_RGBA , 4, 4, 4.0f, 4 , GL_RGBA , GL_UNSIGNED_BYTE };
77 static textypeinfo_t textype_rgba_compress = {TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
78 static textypeinfo_t textype_rgba_alpha_compress = {TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA , GL_UNSIGNED_BYTE };
79 static textypeinfo_t textype_bgra = {TEXTYPE_BGRA , 4, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE };
80 static textypeinfo_t textype_bgra_alpha = {TEXTYPE_BGRA , 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
81 static textypeinfo_t textype_bgra_compress = {TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
82 static textypeinfo_t textype_bgra_alpha_compress = {TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_BGRA , GL_UNSIGNED_BYTE };
83 static textypeinfo_t textype_shadowmap16 = {TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
84 static textypeinfo_t textype_shadowmap24 = {TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
85 static textypeinfo_t textype_alpha = {TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
86 static textypeinfo_t textype_dxt1 = {TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
87 static textypeinfo_t textype_dxt1a = {TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0 , 0 };
88 static textypeinfo_t textype_dxt3 = {TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0 , 0 };
89 static textypeinfo_t textype_dxt5 = {TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0 , 0 };
90 static textypeinfo_t textype_colorbuffer = {TEXTYPE_COLORBUFFER, 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
93 typedef enum gltexturetype_e
97 GLTEXTURETYPE_CUBEMAP,
98 GLTEXTURETYPE_RECTANGLE,
103 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_RECTANGLE_ARB};
104 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2, 2};
105 static int cubemapside[6] =
107 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
108 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
109 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
110 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
111 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
112 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
115 typedef struct gltexture_s
117 // this portion of the struct is exposed to the R_GetTexture macro for
118 // speed reasons, must be identical in rtexture_t!
119 int texnum; // GL texture slot number
120 qboolean dirty; // indicates that R_RealGetTexture should be called
121 int gltexturetypeenum; // used by R_Mesh_TexBind
122 // d3d stuff the backend needs
125 qboolean d3disdepthsurface; // for depth/stencil surfaces
135 int d3dmaxmiplevelfilter;
136 int d3dmipmaplodbias;
140 // dynamic texture stuff [11/22/2007 Black]
141 updatecallback_t updatecallback;
142 void *updatacallback_data;
143 // --- [11/22/2007 Black]
145 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
146 unsigned char *bufferpixels;
147 qboolean buffermodified;
149 // pointer to texturepool (check this to see if the texture is allocated)
150 struct gltexturepool_s *pool;
151 // pointer to next texture in texturepool chain
152 struct gltexture_s *chain;
153 // name of the texture (this might be removed someday), no duplicates
154 char identifier[MAX_QPATH + 32];
155 // original data size in *inputtexels
156 int inputwidth, inputheight, inputdepth;
157 // copy of the original texture(s) supplied to the upload function, for
158 // delayed uploads (non-precached)
159 unsigned char *inputtexels;
160 // original data size in *inputtexels
162 // flags supplied to the LoadTexture function
163 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
167 // pointer to one of the textype_ structs
168 textypeinfo_t *textype;
169 // one of the GLTEXTURETYPE_ values
171 // palette if the texture is TEXTYPE_PALETTE
172 const unsigned int *palette;
173 // actual stored texture size after gl_picmip and gl_max_size are applied
174 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
175 int tilewidth, tileheight, tiledepth;
176 // 1 or 6 depending on texturetype
178 // how many mipmap levels in this texture
182 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
185 int glinternalformat;
186 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
191 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
193 typedef struct gltexturepool_s
195 unsigned int sentinel;
196 struct gltexture_s *gltchain;
197 struct gltexturepool_s *next;
201 static gltexturepool_t *gltexturepoolchain = NULL;
203 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
204 static int resizebuffersize = 0;
205 static const unsigned char *texturebuffer;
207 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
212 return &textype_dxt1;
214 return &textype_dxt1a;
216 return &textype_dxt3;
218 return &textype_dxt5;
219 case TEXTYPE_PALETTE:
220 return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
222 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
223 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress;
224 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba;
226 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
227 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress;
228 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra;
230 return &textype_alpha;
231 case TEXTYPE_SHADOWMAP:
232 return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
233 case TEXTYPE_COLORBUFFER:
234 return &textype_colorbuffer;
236 Host_Error("R_GetTexTypeInfo: unknown texture format");
242 // dynamic texture code [11/22/2007 Black]
243 void R_MarkDirtyTexture(rtexture_t *rt) {
244 gltexture_t *glt = (gltexture_t*) rt;
249 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
250 if (glt->flags & GLTEXF_DYNAMIC)
252 // mark it as dirty, so R_RealGetTexture gets called
257 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
258 gltexture_t *glt = (gltexture_t*) rt;
263 glt->flags |= GLTEXF_DYNAMIC;
264 glt->updatecallback = updatecallback;
265 glt->updatacallback_data = data;
268 static void R_UpdateDynamicTexture(gltexture_t *glt) {
270 if( glt->updatecallback ) {
271 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
275 void R_PurgeTexture(rtexture_t *rt)
277 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
282 void R_FreeTexture(rtexture_t *rt)
284 gltexture_t *glt, **gltpointer;
286 glt = (gltexture_t *)rt;
288 Host_Error("R_FreeTexture: texture == NULL");
290 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
291 if (*gltpointer == glt)
292 *gltpointer = glt->chain;
294 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
296 switch(vid.renderpath)
298 case RENDERPATH_GL11:
299 case RENDERPATH_GL13:
300 case RENDERPATH_GL20:
301 case RENDERPATH_CGGL:
305 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
308 case RENDERPATH_D3D9:
310 if (glt->d3disdepthsurface)
311 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
312 else if (glt->tiledepth > 1)
313 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
314 else if (glt->sides == 6)
315 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
317 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
318 glt->d3dtexture = NULL;
321 case RENDERPATH_D3D10:
322 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
324 case RENDERPATH_D3D11:
325 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
329 if (glt->inputtexels)
330 Mem_Free(glt->inputtexels);
331 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
334 rtexturepool_t *R_AllocTexturePool(void)
336 gltexturepool_t *pool;
337 if (texturemempool == NULL)
339 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
342 pool->next = gltexturepoolchain;
343 gltexturepoolchain = pool;
344 pool->sentinel = TEXTUREPOOL_SENTINEL;
345 return (rtexturepool_t *)pool;
348 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
350 gltexturepool_t *pool, **poolpointer;
351 if (rtexturepool == NULL)
353 if (*rtexturepool == NULL)
355 pool = (gltexturepool_t *)(*rtexturepool);
356 *rtexturepool = NULL;
357 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
358 Host_Error("R_FreeTexturePool: pool already freed");
359 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
360 if (*poolpointer == pool)
361 *poolpointer = pool->next;
363 Host_Error("R_FreeTexturePool: pool not linked");
364 while (pool->gltchain)
365 R_FreeTexture((rtexture_t *)pool->gltchain);
370 typedef struct glmode_s
373 int minification, magnification;
377 static glmode_t modes[6] =
379 {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
380 {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
381 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
382 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
383 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
384 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
388 typedef struct d3dmode_s
395 static d3dmode_t d3dmodes[6] =
397 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
398 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
399 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
400 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
401 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
402 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
406 static void GL_TextureMode_f (void)
411 gltexturepool_t *pool;
415 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
416 for (i = 0;i < 6;i++)
418 if (gl_filter_min == modes[i].minification)
420 Con_Printf("%s\n", modes[i].name);
424 Con_Print("current filter is unknown???\n");
428 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
429 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
433 Con_Print("bad filter name\n");
437 gl_filter_min = modes[i].minification;
438 gl_filter_mag = modes[i].magnification;
439 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
441 switch(vid.renderpath)
443 case RENDERPATH_GL11:
444 case RENDERPATH_GL13:
445 case RENDERPATH_GL20:
446 case RENDERPATH_CGGL:
447 // change all the existing mipmap texture objects
448 // FIXME: force renderer(/client/something?) restart instead?
451 for (pool = gltexturepoolchain;pool;pool = pool->next)
453 for (glt = pool->gltchain;glt;glt = glt->chain)
455 // only update already uploaded images
456 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
458 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
459 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
460 if (glt->flags & TEXF_MIPMAP)
462 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
466 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
468 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
469 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
474 case RENDERPATH_D3D9:
476 d3d_filter_flatmin = d3dmodes[i].m1;
477 d3d_filter_flatmag = d3dmodes[i].m1;
478 d3d_filter_flatmix = D3DTEXF_POINT;
479 d3d_filter_mipmin = d3dmodes[i].m1;
480 d3d_filter_mipmag = d3dmodes[i].m1;
481 d3d_filter_mipmix = d3dmodes[i].m2;
482 d3d_filter_nomip = i < 2;
483 if (gl_texture_anisotropy.integer > 1 && i == 5)
484 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
485 for (pool = gltexturepoolchain;pool;pool = pool->next)
487 for (glt = pool->gltchain;glt;glt = glt->chain)
489 // only update already uploaded images
490 if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
492 if (glt->flags & TEXF_MIPMAP)
494 glt->d3dminfilter = d3d_filter_mipmin;
495 glt->d3dmagfilter = d3d_filter_mipmag;
496 glt->d3dmipfilter = d3d_filter_mipmix;
497 glt->d3dmaxmiplevelfilter = 0;
501 glt->d3dminfilter = d3d_filter_flatmin;
502 glt->d3dmagfilter = d3d_filter_flatmag;
503 glt->d3dmipfilter = d3d_filter_flatmix;
504 glt->d3dmaxmiplevelfilter = 0;
511 case RENDERPATH_D3D10:
512 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
514 case RENDERPATH_D3D11:
515 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
520 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)
522 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
527 case GLTEXTURETYPE_2D:
528 maxsize = vid.maxtexturesize_2d;
529 if (flags & TEXF_PICMIP)
531 maxsize = bound(1, gl_max_size.integer, maxsize);
535 case GLTEXTURETYPE_3D:
536 maxsize = vid.maxtexturesize_3d;
538 case GLTEXTURETYPE_CUBEMAP:
539 maxsize = vid.maxtexturesize_cubemap;
543 if (vid.support.arb_texture_non_power_of_two)
545 width2 = min(inwidth >> picmip, maxsize);
546 height2 = min(inheight >> picmip, maxsize);
547 depth2 = min(indepth >> picmip, maxsize);
551 for (width2 = 1;width2 < inwidth;width2 <<= 1);
552 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
553 for (height2 = 1;height2 < inheight;height2 <<= 1);
554 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
555 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
556 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
559 switch(vid.renderpath)
561 case RENDERPATH_GL11:
562 case RENDERPATH_GL13:
563 case RENDERPATH_GL20:
564 case RENDERPATH_CGGL:
565 case RENDERPATH_D3D10:
566 case RENDERPATH_D3D11:
568 case RENDERPATH_D3D9:
570 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
571 if (texturetype == GLTEXTURETYPE_2D)
573 width2 = max(width2, 2);
574 height2 = max(height2, 2);
581 if (flags & TEXF_MIPMAP)
583 int extent = max(width2, max(height2, depth2));
589 *outwidth = max(1, width2);
591 *outheight = max(1, height2);
593 *outdepth = max(1, depth2);
595 *outmiplevels = miplevels;
599 static int R_CalcTexelDataSize (gltexture_t *glt)
601 int width2, height2, depth2, size;
603 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
605 size = width2 * height2 * depth2;
607 if (glt->flags & TEXF_MIPMAP)
609 while (width2 > 1 || height2 > 1 || depth2 > 1)
617 size += width2 * height2 * depth2;
621 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
624 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
628 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
629 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
631 gltexturepool_t *pool;
633 Con_Print("glsize input loaded mip alpha name\n");
634 for (pool = gltexturepoolchain;pool;pool = pool->next)
642 for (glt = pool->gltchain;glt;glt = glt->chain)
644 glsize = R_CalcTexelDataSize(glt);
645 isloaded = glt->texnum != 0;
647 pooltotalt += glsize;
648 pooltotalp += glt->inputdatasize;
652 poolloadedt += glsize;
653 poolloadedp += glt->inputdatasize;
656 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);
659 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);
660 sumtotal += pooltotal;
661 sumtotalt += pooltotalt;
662 sumtotalp += pooltotalp;
663 sumloaded += poolloaded;
664 sumloadedt += poolloadedt;
665 sumloadedp += poolloadedp;
668 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);
671 static void R_TextureStats_f(void)
673 R_TextureStats_Print(true, true, true);
676 static void r_textures_start(void)
678 switch(vid.renderpath)
680 case RENDERPATH_GL11:
681 case RENDERPATH_GL13:
682 case RENDERPATH_GL20:
683 case RENDERPATH_CGGL:
684 // LordHavoc: allow any alignment
686 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
687 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
689 case RENDERPATH_D3D9:
691 case RENDERPATH_D3D10:
692 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
694 case RENDERPATH_D3D11:
695 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
699 texturemempool = Mem_AllocPool("texture management", 0, NULL);
700 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
702 // Disable JPEG screenshots if the DLL isn't loaded
703 if (! JPEG_OpenLibrary ())
704 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
705 if (! PNG_OpenLibrary ())
706 Cvar_SetValueQuick (&scr_screenshot_png, 0);
709 static void r_textures_shutdown(void)
711 rtexturepool_t *temp;
713 JPEG_CloseLibrary ();
715 while(gltexturepoolchain)
717 temp = (rtexturepool_t *) gltexturepoolchain;
718 R_FreeTexturePool(&temp);
721 resizebuffersize = 0;
723 colorconvertbuffer = NULL;
724 texturebuffer = NULL;
725 Mem_ExpandableArray_FreeArray(&texturearray);
726 Mem_FreePool(&texturemempool);
729 static void r_textures_newmap(void)
733 static void r_textures_devicelost(void)
737 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
738 for (i = 0;i < endindex;i++)
740 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
741 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
743 switch(vid.renderpath)
745 case RENDERPATH_GL11:
746 case RENDERPATH_GL13:
747 case RENDERPATH_GL20:
748 case RENDERPATH_CGGL:
750 case RENDERPATH_D3D9:
752 if (glt->d3disdepthsurface)
753 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
754 else if (glt->tiledepth > 1)
755 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
756 else if (glt->sides == 6)
757 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
759 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
760 glt->d3dtexture = NULL;
763 case RENDERPATH_D3D10:
764 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
766 case RENDERPATH_D3D11:
767 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
773 static void r_textures_devicerestored(void)
777 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
778 for (i = 0;i < endindex;i++)
780 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
781 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
783 switch(vid.renderpath)
785 case RENDERPATH_GL11:
786 case RENDERPATH_GL13:
787 case RENDERPATH_GL20:
788 case RENDERPATH_CGGL:
790 case RENDERPATH_D3D9:
794 if (glt->d3disdepthsurface)
796 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
797 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
799 else if (glt->tiledepth > 1)
801 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)))
802 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
804 else if (glt->sides == 6)
806 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
807 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
811 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)))
812 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
817 case RENDERPATH_D3D10:
818 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
820 case RENDERPATH_D3D11:
821 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
828 void R_Textures_Init (void)
830 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");
831 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
832 Cvar_RegisterVariable (&gl_max_size);
833 Cvar_RegisterVariable (&gl_picmip);
834 Cvar_RegisterVariable (&gl_picmip_world);
835 Cvar_RegisterVariable (&r_picmipworld);
836 Cvar_RegisterVariable (&gl_picmip_sprites);
837 Cvar_RegisterVariable (&r_picmipsprites);
838 Cvar_RegisterVariable (&gl_picmip_other);
839 Cvar_RegisterVariable (&gl_max_lightmapsize);
840 Cvar_RegisterVariable (&r_lerpimages);
841 Cvar_RegisterVariable (&gl_texture_anisotropy);
842 Cvar_RegisterVariable (&gl_texturecompression);
843 Cvar_RegisterVariable (&gl_texturecompression_color);
844 Cvar_RegisterVariable (&gl_texturecompression_normal);
845 Cvar_RegisterVariable (&gl_texturecompression_gloss);
846 Cvar_RegisterVariable (&gl_texturecompression_glow);
847 Cvar_RegisterVariable (&gl_texturecompression_2d);
848 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
849 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
850 Cvar_RegisterVariable (&gl_texturecompression_sky);
851 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
852 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
853 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
854 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
856 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
859 void R_Textures_Frame (void)
861 static int old_aniso = 0;
863 // could do procedural texture animation here, if we keep track of which
864 // textures were accessed this frame...
866 // free the resize buffers
867 resizebuffersize = 0;
870 Mem_Free(resizebuffer);
873 if (colorconvertbuffer)
875 Mem_Free(colorconvertbuffer);
876 colorconvertbuffer = NULL;
879 if (old_aniso != gl_texture_anisotropy.integer)
882 gltexturepool_t *pool;
885 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
887 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
889 switch(vid.renderpath)
891 case RENDERPATH_GL11:
892 case RENDERPATH_GL13:
893 case RENDERPATH_GL20:
894 case RENDERPATH_CGGL:
897 for (pool = gltexturepoolchain;pool;pool = pool->next)
899 for (glt = pool->gltchain;glt;glt = glt->chain)
901 // only update already uploaded images
902 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
904 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
906 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
907 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
909 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
914 case RENDERPATH_D3D9:
915 case RENDERPATH_D3D10:
916 case RENDERPATH_D3D11:
922 void R_MakeResizeBufferBigger(int size)
924 if (resizebuffersize < size)
926 resizebuffersize = size;
928 Mem_Free(resizebuffer);
929 if (colorconvertbuffer)
930 Mem_Free(colorconvertbuffer);
931 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
932 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
933 if (!resizebuffer || !colorconvertbuffer)
934 Host_Error("R_Upload: out of memory");
938 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
940 int textureenum = gltexturetypeenums[texturetype];
941 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
945 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
947 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
948 if (gl_texture_anisotropy.integer != aniso)
949 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
950 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
952 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
953 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
954 if (gltexturetypedimensions[texturetype] >= 3)
956 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
960 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
962 if (flags & TEXF_MIPMAP)
964 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
968 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
970 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
972 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
974 if (flags & TEXF_MIPMAP)
976 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
978 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
982 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
987 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
989 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
993 if (flags & TEXF_MIPMAP)
995 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
999 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1001 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1004 if (textype == TEXTYPE_SHADOWMAP)
1006 if (vid.support.arb_shadow)
1008 if (flags & TEXF_COMPARE)
1010 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1014 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1016 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1018 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1024 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1027 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1029 if (glt->texturetype != GLTEXTURETYPE_2D)
1030 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1032 if (glt->textype->textype == TEXTYPE_PALETTE)
1033 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1035 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1036 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1038 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1039 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1041 // update a portion of the image
1043 switch(vid.renderpath)
1045 case RENDERPATH_GL11:
1046 case RENDERPATH_GL13:
1047 case RENDERPATH_GL20:
1048 case RENDERPATH_CGGL:
1052 // we need to restore the texture binding after finishing the upload
1053 GL_ActiveTexture(0);
1054 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1055 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1056 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1057 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1060 case RENDERPATH_D3D9:
1064 D3DLOCKED_RECT d3dlockedrect;
1066 memset(&d3drect, 0, sizeof(d3drect));
1067 d3drect.left = fragx;
1068 d3drect.top = fragy;
1069 d3drect.right = fragx+fragwidth;
1070 d3drect.bottom = fragy+fragheight;
1071 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1073 for (y = 0;y < fragheight;y++)
1074 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1075 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1080 case RENDERPATH_D3D10:
1081 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1083 case RENDERPATH_D3D11:
1084 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1089 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1091 int i, mip = 0, width, height, depth;
1092 GLint oldbindtexnum = 0;
1093 const unsigned char *prevbuffer;
1096 // error out if a stretch is needed on special texture types
1097 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1098 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1100 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1101 // of the target size and then use the mipmap reduction function to get
1102 // high quality supersampled results
1103 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1104 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1105 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1106 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1108 if (prevbuffer == NULL)
1110 width = glt->tilewidth;
1111 height = glt->tileheight;
1112 depth = glt->tiledepth;
1113 memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1114 prevbuffer = resizebuffer;
1116 else if (glt->textype->textype == TEXTYPE_PALETTE)
1118 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1119 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1120 prevbuffer = colorconvertbuffer;
1123 // scale up to a power of 2 size (if appropriate)
1124 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1126 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1127 prevbuffer = resizebuffer;
1129 // apply mipmap reduction algorithm to get down to picmip/max_size
1130 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1132 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1133 prevbuffer = resizebuffer;
1136 // do the appropriate upload type...
1137 switch(vid.renderpath)
1139 case RENDERPATH_GL11:
1140 case RENDERPATH_GL13:
1141 case RENDERPATH_GL20:
1142 case RENDERPATH_CGGL:
1145 // we need to restore the texture binding after finishing the upload
1146 GL_ActiveTexture(0);
1147 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1148 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1150 if (qglGetCompressedTexImageARB)
1152 if (gl_texturecompression.integer >= 2)
1153 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1155 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1158 switch(glt->texturetype)
1160 case GLTEXTURETYPE_2D:
1161 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1162 if (glt->flags & TEXF_MIPMAP)
1164 while (width > 1 || height > 1 || depth > 1)
1166 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1167 prevbuffer = resizebuffer;
1168 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1172 case GLTEXTURETYPE_3D:
1173 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1174 if (glt->flags & TEXF_MIPMAP)
1176 while (width > 1 || height > 1 || depth > 1)
1178 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1179 prevbuffer = resizebuffer;
1180 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1184 case GLTEXTURETYPE_CUBEMAP:
1185 // convert and upload each side in turn,
1186 // from a continuous block of input texels
1187 texturebuffer = (unsigned char *)prevbuffer;
1188 for (i = 0;i < 6;i++)
1190 prevbuffer = texturebuffer;
1191 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1192 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1194 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1195 prevbuffer = resizebuffer;
1198 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1200 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1201 prevbuffer = resizebuffer;
1204 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1205 if (glt->flags & TEXF_MIPMAP)
1207 while (width > 1 || height > 1 || depth > 1)
1209 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1210 prevbuffer = resizebuffer;
1211 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1216 case GLTEXTURETYPE_RECTANGLE:
1217 qglTexImage2D(GL_TEXTURE_RECTANGLE_ARB, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, NULL);CHECKGLERROR
1220 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1221 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1223 case RENDERPATH_D3D9:
1225 if (!(glt->flags & TEXF_RENDERTARGET))
1227 D3DLOCKED_RECT d3dlockedrect;
1228 D3DLOCKED_BOX d3dlockedbox;
1229 switch(glt->texturetype)
1231 case GLTEXTURETYPE_2D:
1232 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1235 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1237 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1238 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1241 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1243 while (width > 1 || height > 1 || depth > 1)
1245 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1246 prevbuffer = resizebuffer;
1247 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1249 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1250 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1256 case GLTEXTURETYPE_3D:
1257 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1259 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1260 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1261 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1264 if (glt->flags & TEXF_MIPMAP)
1266 while (width > 1 || height > 1 || depth > 1)
1268 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1269 prevbuffer = resizebuffer;
1270 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1272 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1273 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1274 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1280 case GLTEXTURETYPE_CUBEMAP:
1281 // convert and upload each side in turn,
1282 // from a continuous block of input texels
1283 texturebuffer = (unsigned char *)prevbuffer;
1284 for (i = 0;i < 6;i++)
1286 prevbuffer = texturebuffer;
1287 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1288 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1290 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1291 prevbuffer = resizebuffer;
1294 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1296 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1297 prevbuffer = resizebuffer;
1300 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1302 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1303 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1306 if (glt->flags & TEXF_MIPMAP)
1308 while (width > 1 || height > 1 || depth > 1)
1310 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1311 prevbuffer = resizebuffer;
1312 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1314 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1315 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1322 case GLTEXTURETYPE_RECTANGLE:
1323 Sys_Error("Direct3D does not have RECTANGLE textures\n");
1327 glt->d3daddressw = 0;
1328 if (glt->flags & TEXF_CLAMP)
1330 glt->d3daddressu = D3DTADDRESS_CLAMP;
1331 glt->d3daddressv = D3DTADDRESS_CLAMP;
1332 if (glt->tiledepth > 1)
1333 glt->d3daddressw = D3DTADDRESS_CLAMP;
1337 glt->d3daddressu = D3DTADDRESS_WRAP;
1338 glt->d3daddressv = D3DTADDRESS_WRAP;
1339 if (glt->tiledepth > 1)
1340 glt->d3daddressw = D3DTADDRESS_WRAP;
1342 glt->d3dmipmaplodbias = 0;
1343 glt->d3dmaxmiplevel = 0;
1344 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1345 if (glt->flags & TEXF_FORCELINEAR)
1347 glt->d3dminfilter = D3DTEXF_LINEAR;
1348 glt->d3dmagfilter = D3DTEXF_LINEAR;
1349 glt->d3dmipfilter = D3DTEXF_POINT;
1351 else if (glt->flags & TEXF_FORCENEAREST)
1353 glt->d3dminfilter = D3DTEXF_POINT;
1354 glt->d3dmagfilter = D3DTEXF_POINT;
1355 glt->d3dmipfilter = D3DTEXF_POINT;
1357 else if (glt->flags & TEXF_MIPMAP)
1359 glt->d3dminfilter = d3d_filter_mipmin;
1360 glt->d3dmagfilter = d3d_filter_mipmag;
1361 glt->d3dmipfilter = d3d_filter_mipmix;
1365 glt->d3dminfilter = d3d_filter_flatmin;
1366 glt->d3dmagfilter = d3d_filter_flatmag;
1367 glt->d3dmipfilter = d3d_filter_flatmix;
1371 case RENDERPATH_D3D10:
1372 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1374 case RENDERPATH_D3D11:
1375 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1380 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)
1384 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1385 textypeinfo_t *texinfo, *texinfo2;
1386 unsigned char *temppixels = NULL;
1388 if (cls.state == ca_dedicated)
1391 if (texturetype == GLTEXTURETYPE_RECTANGLE && !vid.support.arb_texture_rectangle)
1393 Con_Printf ("R_LoadTexture: rectangle texture not supported by driver\n");
1396 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1398 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1401 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1403 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1407 texinfo = R_GetTexTypeInfo(textype, flags);
1408 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1411 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1415 if (textype == TEXTYPE_RGBA)
1418 static int rgbaswapindices[4] = {2, 1, 0, 3};
1419 textype = TEXTYPE_BGRA;
1420 texinfo = R_GetTexTypeInfo(textype, flags);
1421 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1422 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1426 // clear the alpha flag if the texture has no transparent pixels
1429 case TEXTYPE_PALETTE:
1430 if (flags & TEXF_ALPHA)
1432 flags &= ~TEXF_ALPHA;
1435 for (i = 0;i < size;i++)
1437 if (((unsigned char *)&palette[data[i]])[3] < 255)
1439 flags |= TEXF_ALPHA;
1448 if (flags & TEXF_ALPHA)
1450 flags &= ~TEXF_ALPHA;
1453 for (i = 3;i < size;i += 4)
1457 flags |= TEXF_ALPHA;
1464 case TEXTYPE_SHADOWMAP:
1471 flags |= TEXF_ALPHA;
1474 flags |= TEXF_ALPHA;
1476 case TEXTYPE_COLORBUFFER:
1477 flags |= TEXF_ALPHA;
1480 Sys_Error("R_LoadTexture: unknown texture type");
1483 texinfo2 = R_GetTexTypeInfo(textype, flags);
1484 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1487 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1489 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1491 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1493 glt->chain = pool->gltchain;
1494 pool->gltchain = glt;
1495 glt->inputwidth = width;
1496 glt->inputheight = height;
1497 glt->inputdepth = depth;
1499 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
1500 glt->textype = texinfo;
1501 glt->texturetype = texturetype;
1502 glt->inputdatasize = size;
1503 glt->palette = palette;
1504 glt->glinternalformat = texinfo->glinternalformat;
1505 glt->glformat = texinfo->glformat;
1506 glt->gltype = texinfo->gltype;
1507 glt->bytesperpixel = texinfo->internalbytesperpixel;
1508 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1511 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1512 // init the dynamic texture attributes, too [11/22/2007 Black]
1513 glt->updatecallback = NULL;
1514 glt->updatacallback_data = NULL;
1516 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1518 // upload the texture
1519 // data may be NULL (blank texture for dynamic rendering)
1520 switch(vid.renderpath)
1522 case RENDERPATH_GL11:
1523 case RENDERPATH_GL13:
1524 case RENDERPATH_GL20:
1525 case RENDERPATH_CGGL:
1527 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1529 case RENDERPATH_D3D9:
1532 D3DFORMAT d3dformat;
1537 d3dpool = D3DPOOL_MANAGED;
1538 if (flags & TEXF_RENDERTARGET)
1540 d3dusage |= D3DUSAGE_RENDERTARGET;
1541 d3dpool = D3DPOOL_DEFAULT;
1545 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1546 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1547 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1548 case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1549 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1550 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1551 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1553 glt->d3dformat = d3dformat;
1554 glt->d3dusage = d3dusage;
1555 glt->d3dpool = d3dpool;
1556 glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1557 if (glt->d3disdepthsurface)
1559 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1560 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1562 else if (glt->tiledepth > 1)
1564 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)))
1565 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1567 else if (glt->sides == 6)
1569 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1570 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1574 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)))
1575 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1580 case RENDERPATH_D3D10:
1581 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1583 case RENDERPATH_D3D11:
1584 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1588 R_UploadFullTexture(glt, data);
1589 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1590 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1592 // free any temporary processing buffer we allocated...
1594 Mem_Free(temppixels);
1596 // texture converting and uploading can take a while, so make sure we're sending keepalives
1597 // FIXME: this causes rendering during R_Shadow_DrawLights
1598 // CL_KeepaliveMessage(false);
1600 return (rtexture_t *)glt;
1603 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)
1605 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1608 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)
1610 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1613 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)
1615 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1618 rtexture_t *R_LoadTextureRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette)
1620 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_RECTANGLE, data, palette);
1623 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1625 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1627 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1629 flags |= TEXF_FORCENEAREST;
1630 if (precision <= 16)
1631 flags |= TEXF_LOWPRECISION;
1635 rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1637 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
1640 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1642 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1645 rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter)
1647 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
1650 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1652 gltexture_t *glt = (gltexture_t *)rt;
1655 int bytesperpixel = 0;
1656 int bytesperblock = 0;
1658 int dds_format_flags;
1666 GLint internalformat;
1667 const char *ddsfourcc;
1669 return -1; // NULL pointer
1670 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1671 return -2; // broken driver - crashes on reading internal format
1672 if (!qglGetTexLevelParameteriv)
1674 GL_ActiveTexture(0);
1675 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1676 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1677 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1678 switch(internalformat)
1680 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1681 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1682 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1683 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1684 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1686 if (!bytesperblock && skipuncompressed)
1687 return -3; // skipped
1688 memset(mipinfo, 0, sizeof(mipinfo));
1689 mipinfo[0][0] = glt->tilewidth;
1690 mipinfo[0][1] = glt->tileheight;
1692 if (glt->flags & TEXF_MIPMAP)
1694 for (mip = 1;mip < 16;mip++)
1696 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1697 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1698 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1706 for (mip = 0;mip < mipmaps;mip++)
1708 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1709 mipinfo[mip][3] = ddssize;
1710 ddssize += mipinfo[mip][2];
1712 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1715 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1719 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1720 dds_format_flags = 0x4; // DDPF_FOURCC
1724 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1725 dds_format_flags = 0x40; // DDPF_RGB
1729 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1730 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1733 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1734 memcpy(dds, "DDS ", 4);
1735 StoreLittleLong(dds+4, ddssize);
1736 StoreLittleLong(dds+8, dds_flags);
1737 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1738 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1739 StoreLittleLong(dds+24, 1); // depth
1740 StoreLittleLong(dds+28, mipmaps); // mipmaps
1741 StoreLittleLong(dds+76, 32); // format size
1742 StoreLittleLong(dds+80, dds_format_flags);
1743 StoreLittleLong(dds+108, dds_caps1);
1744 StoreLittleLong(dds+112, dds_caps2);
1747 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1748 memcpy(dds+84, ddsfourcc, 4);
1749 for (mip = 0;mip < mipmaps;mip++)
1751 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1756 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1757 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1758 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1759 for (mip = 0;mip < mipmaps;mip++)
1761 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1764 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1765 ret = FS_WriteFile(filename, dds, ddssize);
1767 return ret ? ddssize : -5;
1770 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
1772 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1775 int bytesperblock, bytesperpixel;
1778 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1779 textypeinfo_t *texinfo;
1780 int mip, mipwidth, mipheight, mipsize;
1782 GLint oldbindtexnum = 0;
1783 const unsigned char *mippixels, *ddspixels;
1785 fs_offset_t ddsfilesize;
1786 unsigned int ddssize;
1788 if (cls.state == ca_dedicated)
1791 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1792 ddssize = ddsfilesize;
1796 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1797 return NULL; // not found
1800 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1803 Con_Printf("^1%s: not a DDS image\n", filename);
1807 //dds_flags = BuffLittleLong(dds+8);
1808 dds_format_flags = BuffLittleLong(dds+80);
1809 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1810 dds_width = BuffLittleLong(dds+16);
1811 dds_height = BuffLittleLong(dds+12);
1812 ddspixels = dds + 128;
1814 if(r_texture_dds_load_alphamode.integer == 0)
1815 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1816 flags &= ~TEXF_ALPHA;
1818 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1819 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1821 // very sloppy BGRA 32bit identification
1822 textype = TEXTYPE_BGRA;
1825 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1826 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1829 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1832 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1835 for (i = 3;i < size;i += 4)
1836 if (ddspixels[i] < 255)
1839 flags &= ~TEXF_ALPHA;
1842 else if (!memcmp(dds+84, "DXT1", 4))
1844 if(!vid.support.ext_texture_compression_s3tc)
1849 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1850 // LordHavoc: it is my belief that this does not infringe on the
1851 // patent because it is not decoding pixels...
1852 textype = TEXTYPE_DXT1;
1855 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1856 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1857 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1860 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1863 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1865 if(r_texture_dds_load_alphamode.integer == 1)
1868 for (i = 0;i < size;i += bytesperblock)
1869 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1871 // NOTE: this assumes sizeof(unsigned int) == 4
1872 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1873 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1874 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1878 textype = TEXTYPE_DXT1A;
1880 flags &= ~TEXF_ALPHA;
1884 flags &= ~TEXF_ALPHA;
1888 else if (!memcmp(dds+84, "DXT3", 4))
1890 if(!vid.support.ext_texture_compression_s3tc)
1895 textype = TEXTYPE_DXT3;
1898 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1899 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1902 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1905 // we currently always assume alpha
1907 else if (!memcmp(dds+84, "DXT5", 4))
1909 if(!vid.support.ext_texture_compression_s3tc)
1914 textype = TEXTYPE_DXT5;
1917 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1918 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1921 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1924 // we currently always assume alpha
1929 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1933 // return whether this texture is transparent
1935 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1937 // calculate average color if requested
1941 Vector4Clear(avgcolor);
1944 for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
1946 c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
1947 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1948 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
1949 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
1951 f = (float)bytesperblock / size;
1952 avgcolor[0] *= (0.5f / 31.0f) * f;
1953 avgcolor[1] *= (0.5f / 63.0f) * f;
1954 avgcolor[2] *= (0.5f / 31.0f) * f;
1955 avgcolor[3] = 1; // too hard to calculate
1959 for (i = 0;i < size;i += 4)
1961 avgcolor[0] += ddspixels[i+2];
1962 avgcolor[1] += ddspixels[i+1];
1963 avgcolor[2] += ddspixels[i];
1964 avgcolor[3] += ddspixels[i+3];
1966 f = (1.0f / 255.0f) * bytesperpixel / size;
1974 // this is where we apply gl_picmip
1975 mippixels = ddspixels;
1976 mipwidth = dds_width;
1977 mipheight = dds_height;
1978 while(miplevel >= 1 && dds_miplevels >= 1)
1980 if (mipwidth <= 1 && mipheight <= 1)
1982 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1983 mippixels += mipsize; // just skip
1992 // when not requesting mipmaps, do not load them
1993 if(!(flags & TEXF_MIPMAP))
1996 if (dds_miplevels >= 1)
1997 flags |= TEXF_MIPMAP;
1999 flags &= ~TEXF_MIPMAP;
2001 // if S3TC is not supported, there's very little we can do about it
2002 if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
2005 Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
2009 texinfo = R_GetTexTypeInfo(textype, flags);
2011 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2012 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2014 glt->chain = pool->gltchain;
2015 pool->gltchain = glt;
2016 glt->inputwidth = mipwidth;
2017 glt->inputheight = mipheight;
2018 glt->inputdepth = 1;
2020 glt->textype = texinfo;
2021 glt->texturetype = GLTEXTURETYPE_2D;
2022 glt->inputdatasize = ddssize;
2023 glt->glinternalformat = texinfo->glinternalformat;
2024 glt->glformat = texinfo->glformat;
2025 glt->gltype = texinfo->gltype;
2026 glt->bytesperpixel = texinfo->internalbytesperpixel;
2028 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2029 glt->tilewidth = mipwidth;
2030 glt->tileheight = mipheight;
2032 glt->miplevels = dds_miplevels;
2034 // texture uploading can take a while, so make sure we're sending keepalives
2035 CL_KeepaliveMessage(false);
2037 // create the texture object
2038 switch(vid.renderpath)
2040 case RENDERPATH_GL11:
2041 case RENDERPATH_GL13:
2042 case RENDERPATH_GL20:
2043 case RENDERPATH_CGGL:
2045 GL_ActiveTexture(0);
2046 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2047 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2048 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2050 case RENDERPATH_D3D9:
2053 D3DFORMAT d3dformat;
2058 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2059 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2060 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2061 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2062 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2065 d3dpool = D3DPOOL_MANAGED;
2066 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2070 case RENDERPATH_D3D10:
2071 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2073 case RENDERPATH_D3D11:
2074 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2078 // upload the texture
2079 // we need to restore the texture binding after finishing the upload
2080 mipcomplete = false;
2082 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2084 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2085 if (mippixels + mipsize > dds + ddssize)
2087 switch(vid.renderpath)
2089 case RENDERPATH_GL11:
2090 case RENDERPATH_GL13:
2091 case RENDERPATH_GL20:
2092 case RENDERPATH_CGGL:
2095 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2099 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2102 case RENDERPATH_D3D9:
2105 D3DLOCKED_RECT d3dlockedrect;
2106 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2108 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2109 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2115 case RENDERPATH_D3D10:
2116 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2118 case RENDERPATH_D3D11:
2119 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2122 mippixels += mipsize;
2123 if (mipwidth <= 1 && mipheight <= 1)
2134 // after upload we have to set some parameters...
2135 switch(vid.renderpath)
2137 case RENDERPATH_GL11:
2138 case RENDERPATH_GL13:
2139 case RENDERPATH_GL20:
2140 case RENDERPATH_CGGL:
2141 if (dds_miplevels >= 1 && !mipcomplete)
2143 // need to set GL_TEXTURE_MAX_LEVEL
2144 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2146 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2147 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2149 case RENDERPATH_D3D9:
2151 glt->d3daddressw = 0;
2152 if (glt->flags & TEXF_CLAMP)
2154 glt->d3daddressu = D3DTADDRESS_CLAMP;
2155 glt->d3daddressv = D3DTADDRESS_CLAMP;
2156 if (glt->tiledepth > 1)
2157 glt->d3daddressw = D3DTADDRESS_CLAMP;
2161 glt->d3daddressu = D3DTADDRESS_WRAP;
2162 glt->d3daddressv = D3DTADDRESS_WRAP;
2163 if (glt->tiledepth > 1)
2164 glt->d3daddressw = D3DTADDRESS_WRAP;
2166 glt->d3dmipmaplodbias = 0;
2167 glt->d3dmaxmiplevel = 0;
2168 glt->d3dmaxmiplevelfilter = 0;
2169 if (glt->flags & TEXF_MIPMAP)
2171 glt->d3dminfilter = d3d_filter_mipmin;
2172 glt->d3dmagfilter = d3d_filter_mipmag;
2173 glt->d3dmipfilter = d3d_filter_mipmix;
2177 glt->d3dminfilter = d3d_filter_flatmin;
2178 glt->d3dmagfilter = d3d_filter_flatmag;
2179 glt->d3dmipfilter = d3d_filter_flatmix;
2183 case RENDERPATH_D3D10:
2184 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2186 case RENDERPATH_D3D11:
2187 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2192 return (rtexture_t *)glt;
2195 int R_TextureWidth(rtexture_t *rt)
2197 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2200 int R_TextureHeight(rtexture_t *rt)
2202 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2205 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
2207 gltexture_t *glt = (gltexture_t *)rt;
2209 Host_Error("R_UpdateTexture: no data supplied");
2211 Host_Error("R_UpdateTexture: no texture supplied");
2212 if (!glt->texnum && !glt->d3dtexture)
2214 Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", (void *)glt, glt->identifier, (void *)glt->pool);
2217 // update part of the texture
2218 if (glt->bufferpixels)
2221 int bpp = glt->bytesperpixel;
2222 int inputskip = width*bpp;
2223 int outputskip = glt->tilewidth*bpp;
2224 const unsigned char *input = data;
2225 unsigned char *output = glt->bufferpixels;
2235 input -= y*inputskip;
2238 if (width > glt->tilewidth - x)
2239 width = glt->tilewidth - x;
2240 if (height > glt->tileheight - y)
2241 height = glt->tileheight - y;
2242 if (width < 1 || height < 1)
2245 glt->buffermodified = true;
2246 output += y*outputskip + x*bpp;
2247 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2248 memcpy(output, input, width*bpp);
2250 else if (x || y || width != glt->inputwidth || height != glt->inputheight)
2251 R_UploadPartialTexture(glt, data, x, y, 0, width, height, 1);
2253 R_UploadFullTexture(glt, data);
2256 int R_RealGetTexture(rtexture_t *rt)
2261 glt = (gltexture_t *)rt;
2262 if (glt->flags & GLTEXF_DYNAMIC)
2263 R_UpdateDynamicTexture(glt);
2264 if (glt->buffermodified && glt->bufferpixels)
2266 glt->buffermodified = false;
2267 R_UploadFullTexture(glt, glt->bufferpixels);
2276 void R_ClearTexture (rtexture_t *rt)
2278 gltexture_t *glt = (gltexture_t *)rt;
2280 R_UploadFullTexture(glt, NULL);
2283 int R_PicmipForFlags(int flags)
2286 if(flags & TEXF_PICMIP)
2288 miplevel += gl_picmip.integer;
2289 if (flags & TEXF_ISWORLD)
2291 if (r_picmipworld.integer)
2292 miplevel += gl_picmip_world.integer;
2296 else if (flags & TEXF_ISSPRITE)
2298 if (r_picmipsprites.integer)
2299 miplevel += gl_picmip_sprites.integer;
2304 miplevel += gl_picmip_other.integer;
2306 return max(0, miplevel);