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"};
35 cvar_t r_texture_dds_swdecode = {0, "r_texture_dds_swdecode", "0", "0: don't software decode DDS, 1: software decode DDS if unsupported, 2: always software decode DDS"};
37 qboolean gl_filter_force = false;
38 int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
39 int gl_filter_mag = GL_LINEAR;
42 int d3d_filter_flatmin = D3DTEXF_LINEAR;
43 int d3d_filter_flatmag = D3DTEXF_LINEAR;
44 int d3d_filter_flatmix = D3DTEXF_POINT;
45 int d3d_filter_mipmin = D3DTEXF_LINEAR;
46 int d3d_filter_mipmag = D3DTEXF_LINEAR;
47 int d3d_filter_mipmix = D3DTEXF_LINEAR;
48 int d3d_filter_nomip = false;
52 static mempool_t *texturemempool;
53 static memexpandablearray_t texturearray;
55 // note: this must not conflict with TEXF_ flags in r_textures.h
56 // bitmask for mismatch checking
57 #define GLTEXF_IMPORTANTBITS (0)
58 // dynamic texture (treat texnum == 0 differently)
59 #define GLTEXF_DYNAMIC 0x00080000
61 typedef struct textypeinfo_s
64 int inputbytesperpixel;
65 int internalbytesperpixel;
66 float glinternalbytesperpixel;
74 static textypeinfo_t textype_palette = {TEXTYPE_PALETTE , 1, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE };
75 static textypeinfo_t textype_palette_alpha = {TEXTYPE_PALETTE , 1, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
76 static textypeinfo_t textype_rgba = {TEXTYPE_RGBA , 4, 4, 4.0f, 3 , GL_RGBA , GL_UNSIGNED_BYTE };
77 static textypeinfo_t textype_rgba_alpha = {TEXTYPE_RGBA , 4, 4, 4.0f, 4 , GL_RGBA , GL_UNSIGNED_BYTE };
78 static textypeinfo_t textype_rgba_compress = {TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
79 static textypeinfo_t textype_rgba_alpha_compress = {TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA , GL_UNSIGNED_BYTE };
80 static textypeinfo_t textype_bgra = {TEXTYPE_BGRA , 4, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE };
81 static textypeinfo_t textype_bgra_alpha = {TEXTYPE_BGRA , 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
82 static textypeinfo_t textype_bgra_compress = {TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
83 static textypeinfo_t textype_bgra_alpha_compress = {TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_BGRA , GL_UNSIGNED_BYTE };
84 static textypeinfo_t textype_shadowmap16 = {TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
85 static textypeinfo_t textype_shadowmap24 = {TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
86 static textypeinfo_t textype_alpha = {TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
87 static textypeinfo_t textype_dxt1 = {TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
88 static textypeinfo_t textype_dxt1a = {TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0 , 0 };
89 static textypeinfo_t textype_dxt3 = {TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0 , 0 };
90 static textypeinfo_t textype_dxt5 = {TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0 , 0 };
91 static textypeinfo_t textype_colorbuffer = {TEXTYPE_COLORBUFFER, 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
94 typedef enum gltexturetype_e
98 GLTEXTURETYPE_CUBEMAP,
103 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB};
104 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 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);
855 Cvar_RegisterVariable (&r_texture_dds_swdecode);
857 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
860 void R_Textures_Frame (void)
862 static int old_aniso = 0;
864 // could do procedural texture animation here, if we keep track of which
865 // textures were accessed this frame...
867 // free the resize buffers
868 resizebuffersize = 0;
871 Mem_Free(resizebuffer);
874 if (colorconvertbuffer)
876 Mem_Free(colorconvertbuffer);
877 colorconvertbuffer = NULL;
880 if (old_aniso != gl_texture_anisotropy.integer)
883 gltexturepool_t *pool;
886 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
888 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
890 switch(vid.renderpath)
892 case RENDERPATH_GL11:
893 case RENDERPATH_GL13:
894 case RENDERPATH_GL20:
895 case RENDERPATH_CGGL:
898 for (pool = gltexturepoolchain;pool;pool = pool->next)
900 for (glt = pool->gltchain;glt;glt = glt->chain)
902 // only update already uploaded images
903 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
905 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
907 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
908 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
910 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
915 case RENDERPATH_D3D9:
916 case RENDERPATH_D3D10:
917 case RENDERPATH_D3D11:
923 void R_MakeResizeBufferBigger(int size)
925 if (resizebuffersize < size)
927 resizebuffersize = size;
929 Mem_Free(resizebuffer);
930 if (colorconvertbuffer)
931 Mem_Free(colorconvertbuffer);
932 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
933 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
934 if (!resizebuffer || !colorconvertbuffer)
935 Host_Error("R_Upload: out of memory");
939 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
941 int textureenum = gltexturetypeenums[texturetype];
942 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
946 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
948 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
949 if (gl_texture_anisotropy.integer != aniso)
950 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
951 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
953 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
954 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
955 if (gltexturetypedimensions[texturetype] >= 3)
957 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
961 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
963 if (flags & TEXF_MIPMAP)
965 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
969 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
971 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
973 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
975 if (flags & TEXF_MIPMAP)
977 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
979 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
983 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
988 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
990 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
994 if (flags & TEXF_MIPMAP)
996 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1000 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1002 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1005 if (textype == TEXTYPE_SHADOWMAP)
1007 if (vid.support.arb_shadow)
1009 if (flags & TEXF_COMPARE)
1011 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1015 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1017 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1019 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1025 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1028 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1030 if (glt->texturetype != GLTEXTURETYPE_2D)
1031 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1033 if (glt->textype->textype == TEXTYPE_PALETTE)
1034 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1036 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1037 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1039 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1040 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1042 // update a portion of the image
1044 switch(vid.renderpath)
1046 case RENDERPATH_GL11:
1047 case RENDERPATH_GL13:
1048 case RENDERPATH_GL20:
1049 case RENDERPATH_CGGL:
1053 // we need to restore the texture binding after finishing the upload
1054 GL_ActiveTexture(0);
1055 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1056 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1057 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1058 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1061 case RENDERPATH_D3D9:
1065 D3DLOCKED_RECT d3dlockedrect;
1067 memset(&d3drect, 0, sizeof(d3drect));
1068 d3drect.left = fragx;
1069 d3drect.top = fragy;
1070 d3drect.right = fragx+fragwidth;
1071 d3drect.bottom = fragy+fragheight;
1072 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1074 for (y = 0;y < fragheight;y++)
1075 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1076 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1081 case RENDERPATH_D3D10:
1082 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1084 case RENDERPATH_D3D11:
1085 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1090 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1092 int i, mip = 0, width, height, depth;
1093 GLint oldbindtexnum = 0;
1094 const unsigned char *prevbuffer;
1097 // error out if a stretch is needed on special texture types
1098 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1099 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1101 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1102 // of the target size and then use the mipmap reduction function to get
1103 // high quality supersampled results
1104 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1105 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1106 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1107 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1109 if (prevbuffer == NULL)
1111 width = glt->tilewidth;
1112 height = glt->tileheight;
1113 depth = glt->tiledepth;
1114 memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1115 prevbuffer = resizebuffer;
1117 else if (glt->textype->textype == TEXTYPE_PALETTE)
1119 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1120 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1121 prevbuffer = colorconvertbuffer;
1124 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1126 // multiply RGB channels by A channel before uploading
1128 for (i = 0;i < width*height*depth*4;i += 4)
1130 alpha = prevbuffer[i+3];
1131 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1132 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1133 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1134 colorconvertbuffer[i+3] = alpha;
1136 prevbuffer = colorconvertbuffer;
1139 // scale up to a power of 2 size (if appropriate)
1140 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1142 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1143 prevbuffer = resizebuffer;
1145 // apply mipmap reduction algorithm to get down to picmip/max_size
1146 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1148 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1149 prevbuffer = resizebuffer;
1152 // do the appropriate upload type...
1153 switch(vid.renderpath)
1155 case RENDERPATH_GL11:
1156 case RENDERPATH_GL13:
1157 case RENDERPATH_GL20:
1158 case RENDERPATH_CGGL:
1161 // we need to restore the texture binding after finishing the upload
1162 GL_ActiveTexture(0);
1163 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1164 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1166 if (qglGetCompressedTexImageARB)
1168 if (gl_texturecompression.integer >= 2)
1169 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1171 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1174 switch(glt->texturetype)
1176 case GLTEXTURETYPE_2D:
1177 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1178 if (glt->flags & TEXF_MIPMAP)
1180 while (width > 1 || height > 1 || depth > 1)
1182 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1183 prevbuffer = resizebuffer;
1184 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1188 case GLTEXTURETYPE_3D:
1189 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1190 if (glt->flags & TEXF_MIPMAP)
1192 while (width > 1 || height > 1 || depth > 1)
1194 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1195 prevbuffer = resizebuffer;
1196 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1200 case GLTEXTURETYPE_CUBEMAP:
1201 // convert and upload each side in turn,
1202 // from a continuous block of input texels
1203 texturebuffer = (unsigned char *)prevbuffer;
1204 for (i = 0;i < 6;i++)
1206 prevbuffer = texturebuffer;
1207 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1208 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1210 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1211 prevbuffer = resizebuffer;
1214 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1216 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1217 prevbuffer = resizebuffer;
1220 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1221 if (glt->flags & TEXF_MIPMAP)
1223 while (width > 1 || height > 1 || depth > 1)
1225 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1226 prevbuffer = resizebuffer;
1227 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1233 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1234 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1236 case RENDERPATH_D3D9:
1238 if (!(glt->flags & TEXF_RENDERTARGET))
1240 D3DLOCKED_RECT d3dlockedrect;
1241 D3DLOCKED_BOX d3dlockedbox;
1242 switch(glt->texturetype)
1244 case GLTEXTURETYPE_2D:
1245 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1248 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1250 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1251 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1254 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1256 while (width > 1 || height > 1 || depth > 1)
1258 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1259 prevbuffer = resizebuffer;
1260 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1262 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1263 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1269 case GLTEXTURETYPE_3D:
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);
1277 if (glt->flags & TEXF_MIPMAP)
1279 while (width > 1 || height > 1 || depth > 1)
1281 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1282 prevbuffer = resizebuffer;
1283 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1285 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1286 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1287 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1293 case GLTEXTURETYPE_CUBEMAP:
1294 // convert and upload each side in turn,
1295 // from a continuous block of input texels
1296 texturebuffer = (unsigned char *)prevbuffer;
1297 for (i = 0;i < 6;i++)
1299 prevbuffer = texturebuffer;
1300 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1301 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1303 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1304 prevbuffer = resizebuffer;
1307 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1309 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1310 prevbuffer = resizebuffer;
1313 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1315 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1316 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1319 if (glt->flags & TEXF_MIPMAP)
1321 while (width > 1 || height > 1 || depth > 1)
1323 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1324 prevbuffer = resizebuffer;
1325 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1327 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1328 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1337 glt->d3daddressw = 0;
1338 if (glt->flags & TEXF_CLAMP)
1340 glt->d3daddressu = D3DTADDRESS_CLAMP;
1341 glt->d3daddressv = D3DTADDRESS_CLAMP;
1342 if (glt->tiledepth > 1)
1343 glt->d3daddressw = D3DTADDRESS_CLAMP;
1347 glt->d3daddressu = D3DTADDRESS_WRAP;
1348 glt->d3daddressv = D3DTADDRESS_WRAP;
1349 if (glt->tiledepth > 1)
1350 glt->d3daddressw = D3DTADDRESS_WRAP;
1352 glt->d3dmipmaplodbias = 0;
1353 glt->d3dmaxmiplevel = 0;
1354 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1355 if (glt->flags & TEXF_FORCELINEAR)
1357 glt->d3dminfilter = D3DTEXF_LINEAR;
1358 glt->d3dmagfilter = D3DTEXF_LINEAR;
1359 glt->d3dmipfilter = D3DTEXF_POINT;
1361 else if (glt->flags & TEXF_FORCENEAREST)
1363 glt->d3dminfilter = D3DTEXF_POINT;
1364 glt->d3dmagfilter = D3DTEXF_POINT;
1365 glt->d3dmipfilter = D3DTEXF_POINT;
1367 else if (glt->flags & TEXF_MIPMAP)
1369 glt->d3dminfilter = d3d_filter_mipmin;
1370 glt->d3dmagfilter = d3d_filter_mipmag;
1371 glt->d3dmipfilter = d3d_filter_mipmix;
1375 glt->d3dminfilter = d3d_filter_flatmin;
1376 glt->d3dmagfilter = d3d_filter_flatmag;
1377 glt->d3dmipfilter = d3d_filter_flatmix;
1381 case RENDERPATH_D3D10:
1382 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1384 case RENDERPATH_D3D11:
1385 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1390 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)
1394 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1395 textypeinfo_t *texinfo, *texinfo2;
1396 unsigned char *temppixels = NULL;
1398 if (cls.state == ca_dedicated)
1401 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1403 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1406 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1408 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1412 texinfo = R_GetTexTypeInfo(textype, flags);
1413 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1416 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1420 if (textype == TEXTYPE_RGBA)
1423 static int rgbaswapindices[4] = {2, 1, 0, 3};
1424 textype = TEXTYPE_BGRA;
1425 texinfo = R_GetTexTypeInfo(textype, flags);
1426 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1427 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1431 // clear the alpha flag if the texture has no transparent pixels
1434 case TEXTYPE_PALETTE:
1435 if (flags & TEXF_ALPHA)
1437 flags &= ~TEXF_ALPHA;
1440 for (i = 0;i < size;i++)
1442 if (((unsigned char *)&palette[data[i]])[3] < 255)
1444 flags |= TEXF_ALPHA;
1453 if (flags & TEXF_ALPHA)
1455 flags &= ~TEXF_ALPHA;
1458 for (i = 3;i < size;i += 4)
1462 flags |= TEXF_ALPHA;
1469 case TEXTYPE_SHADOWMAP:
1476 flags |= TEXF_ALPHA;
1479 flags |= TEXF_ALPHA;
1481 case TEXTYPE_COLORBUFFER:
1482 flags |= TEXF_ALPHA;
1485 Sys_Error("R_LoadTexture: unknown texture type");
1488 texinfo2 = R_GetTexTypeInfo(textype, flags);
1489 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1492 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1494 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1496 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1498 glt->chain = pool->gltchain;
1499 pool->gltchain = glt;
1500 glt->inputwidth = width;
1501 glt->inputheight = height;
1502 glt->inputdepth = depth;
1504 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
1505 glt->textype = texinfo;
1506 glt->texturetype = texturetype;
1507 glt->inputdatasize = size;
1508 glt->palette = palette;
1509 glt->glinternalformat = texinfo->glinternalformat;
1510 glt->glformat = texinfo->glformat;
1511 glt->gltype = texinfo->gltype;
1512 glt->bytesperpixel = texinfo->internalbytesperpixel;
1513 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1516 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1517 // init the dynamic texture attributes, too [11/22/2007 Black]
1518 glt->updatecallback = NULL;
1519 glt->updatacallback_data = NULL;
1521 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1523 // upload the texture
1524 // data may be NULL (blank texture for dynamic rendering)
1525 switch(vid.renderpath)
1527 case RENDERPATH_GL11:
1528 case RENDERPATH_GL13:
1529 case RENDERPATH_GL20:
1530 case RENDERPATH_CGGL:
1532 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1534 case RENDERPATH_D3D9:
1537 D3DFORMAT d3dformat;
1542 d3dpool = D3DPOOL_MANAGED;
1543 if (flags & TEXF_RENDERTARGET)
1545 d3dusage |= D3DUSAGE_RENDERTARGET;
1546 d3dpool = D3DPOOL_DEFAULT;
1550 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1551 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1552 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1553 case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1554 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1555 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1556 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1558 glt->d3dformat = d3dformat;
1559 glt->d3dusage = d3dusage;
1560 glt->d3dpool = d3dpool;
1561 glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1562 if (glt->d3disdepthsurface)
1564 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1565 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1567 else if (glt->tiledepth > 1)
1569 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)))
1570 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1572 else if (glt->sides == 6)
1574 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1575 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1579 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)))
1580 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1585 case RENDERPATH_D3D10:
1586 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1588 case RENDERPATH_D3D11:
1589 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1593 R_UploadFullTexture(glt, data);
1594 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1595 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1597 // free any temporary processing buffer we allocated...
1599 Mem_Free(temppixels);
1601 // texture converting and uploading can take a while, so make sure we're sending keepalives
1602 // FIXME: this causes rendering during R_Shadow_DrawLights
1603 // CL_KeepaliveMessage(false);
1605 return (rtexture_t *)glt;
1608 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)
1610 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1613 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)
1615 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1618 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)
1620 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, 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_LoadTextureShadowMap2D(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_2D, NULL, NULL);
1640 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1642 gltexture_t *glt = (gltexture_t *)rt;
1645 int bytesperpixel = 0;
1646 int bytesperblock = 0;
1648 int dds_format_flags;
1656 GLint internalformat;
1657 const char *ddsfourcc;
1659 return -1; // NULL pointer
1660 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1661 return -2; // broken driver - crashes on reading internal format
1662 if (!qglGetTexLevelParameteriv)
1664 GL_ActiveTexture(0);
1665 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1666 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1667 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1668 switch(internalformat)
1670 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1671 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1672 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1673 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1674 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1676 // if premultiplied alpha, say so in the DDS file
1677 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1679 switch(internalformat)
1681 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1682 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1685 if (!bytesperblock && skipuncompressed)
1686 return -3; // skipped
1687 memset(mipinfo, 0, sizeof(mipinfo));
1688 mipinfo[0][0] = glt->tilewidth;
1689 mipinfo[0][1] = glt->tileheight;
1691 if (glt->flags & TEXF_MIPMAP)
1693 for (mip = 1;mip < 16;mip++)
1695 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1696 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1697 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1705 for (mip = 0;mip < mipmaps;mip++)
1707 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1708 mipinfo[mip][3] = ddssize;
1709 ddssize += mipinfo[mip][2];
1711 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1714 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1718 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1719 dds_format_flags = 0x4; // DDPF_FOURCC
1723 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1724 dds_format_flags = 0x40; // DDPF_RGB
1728 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1729 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1732 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1733 memcpy(dds, "DDS ", 4);
1734 StoreLittleLong(dds+4, ddssize);
1735 StoreLittleLong(dds+8, dds_flags);
1736 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1737 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1738 StoreLittleLong(dds+24, 1); // depth
1739 StoreLittleLong(dds+28, mipmaps); // mipmaps
1740 StoreLittleLong(dds+76, 32); // format size
1741 StoreLittleLong(dds+80, dds_format_flags);
1742 StoreLittleLong(dds+108, dds_caps1);
1743 StoreLittleLong(dds+112, dds_caps2);
1746 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1747 memcpy(dds+84, ddsfourcc, 4);
1748 for (mip = 0;mip < mipmaps;mip++)
1750 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1755 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1756 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1757 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1758 for (mip = 0;mip < mipmaps;mip++)
1760 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1763 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1764 ret = FS_WriteFile(filename, dds, ddssize);
1766 return ret ? ddssize : -5;
1769 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
1771 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1774 int bytesperblock, bytesperpixel;
1777 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1778 textypeinfo_t *texinfo;
1779 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1781 GLint oldbindtexnum = 0;
1782 const unsigned char *mippixels, *ddspixels, *mippixels_start;
1784 fs_offset_t ddsfilesize;
1785 unsigned int ddssize;
1786 qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
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 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1845 // LordHavoc: it is my belief that this does not infringe on the
1846 // patent because it is not decoding pixels...
1847 textype = TEXTYPE_DXT1;
1850 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1851 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1852 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1855 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1858 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1860 if(r_texture_dds_load_alphamode.integer == 1)
1863 for (i = 0;i < size;i += bytesperblock)
1864 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1866 // NOTE: this assumes sizeof(unsigned int) == 4
1867 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1868 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1869 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1873 textype = TEXTYPE_DXT1A;
1875 flags &= ~TEXF_ALPHA;
1879 flags &= ~TEXF_ALPHA;
1883 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
1885 if(!memcmp(dds+84, "DXT2", 4))
1887 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1889 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
1894 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1896 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
1899 textype = TEXTYPE_DXT3;
1902 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1903 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1906 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1909 // we currently always assume alpha
1911 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
1913 if(!memcmp(dds+84, "DXT4", 4))
1915 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1917 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
1922 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1924 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
1927 textype = TEXTYPE_DXT5;
1930 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1931 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1934 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1937 // we currently always assume alpha
1942 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1946 force_swdecode = false;
1949 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
1951 if(r_texture_dds_swdecode.integer > 1)
1952 force_swdecode = true;
1956 if(r_texture_dds_swdecode.integer < 1)
1962 force_swdecode = true;
1966 // return whether this texture is transparent
1968 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1970 // if we SW decode, choose 2 sizes bigger
1973 // this is quarter res, so do not scale down more than we have to
1977 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
1980 // this is where we apply gl_picmip
1981 mippixels_start = ddspixels;
1982 mipwidth = dds_width;
1983 mipheight = dds_height;
1984 while(miplevel >= 1 && dds_miplevels >= 1)
1986 if (mipwidth <= 1 && mipheight <= 1)
1988 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1989 mippixels_start += mipsize; // just skip
1997 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
1998 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2000 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2002 // fake decode S3TC if needed
2005 int mipsize_new = mipsize_total / bytesperblock * 4;
2006 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2007 unsigned char *p = mipnewpixels;
2008 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2010 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2011 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2012 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2013 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2014 if(textype == TEXTYPE_DXT5)
2015 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2016 else if(textype == TEXTYPE_DXT3)
2018 (mippixels_start[i-8] & 0x0F)
2019 + (mippixels_start[i-8] >> 4)
2020 + (mippixels_start[i-7] & 0x0F)
2021 + (mippixels_start[i-7] >> 4)
2022 + (mippixels_start[i-6] & 0x0F)
2023 + (mippixels_start[i-6] >> 4)
2024 + (mippixels_start[i-5] & 0x0F)
2025 + (mippixels_start[i-5] >> 4)
2026 ) * (0.125f / 15.0f * 255.0f);
2031 textype = TEXTYPE_BGRA;
2035 // as each block becomes a pixel, we must use pixel count for this
2036 mipwidth = (mipwidth + 3) / 4;
2037 mipheight = (mipheight + 3) / 4;
2038 mipsize = bytesperpixel * mipwidth * mipheight;
2039 mippixels_start = mipnewpixels;
2040 mipsize_total = mipsize_new;
2043 // start mip counting
2044 mippixels = mippixels_start;
2046 // calculate average color if requested
2050 Vector4Clear(avgcolor);
2053 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2055 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2056 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2057 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2058 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2059 if(textype == TEXTYPE_DXT5)
2060 avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2061 else if(textype == TEXTYPE_DXT3)
2063 (mippixels_start[i-8] & 0x0F)
2064 + (mippixels_start[i-8] >> 4)
2065 + (mippixels_start[i-7] & 0x0F)
2066 + (mippixels_start[i-7] >> 4)
2067 + (mippixels_start[i-6] & 0x0F)
2068 + (mippixels_start[i-6] >> 4)
2069 + (mippixels_start[i-5] & 0x0F)
2070 + (mippixels_start[i-5] >> 4)
2071 ) * (0.125f / 15.0f * 255.0f);
2075 f = (float)bytesperblock / size;
2076 avgcolor[0] *= (0.5f / 31.0f) * f;
2077 avgcolor[1] *= (0.5f / 63.0f) * f;
2078 avgcolor[2] *= (0.5f / 31.0f) * f;
2083 for (i = 0;i < mipsize;i += 4)
2085 avgcolor[0] += mippixels[i+2];
2086 avgcolor[1] += mippixels[i+1];
2087 avgcolor[2] += mippixels[i];
2088 avgcolor[3] += mippixels[i+3];
2090 f = (1.0f / 255.0f) * bytesperpixel / size;
2098 // when not requesting mipmaps, do not load them
2099 if(!(flags & TEXF_MIPMAP))
2102 if (dds_miplevels >= 1)
2103 flags |= TEXF_MIPMAP;
2105 flags &= ~TEXF_MIPMAP;
2107 texinfo = R_GetTexTypeInfo(textype, flags);
2109 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2110 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2112 glt->chain = pool->gltchain;
2113 pool->gltchain = glt;
2114 glt->inputwidth = mipwidth;
2115 glt->inputheight = mipheight;
2116 glt->inputdepth = 1;
2118 glt->textype = texinfo;
2119 glt->texturetype = GLTEXTURETYPE_2D;
2120 glt->inputdatasize = ddssize;
2121 glt->glinternalformat = texinfo->glinternalformat;
2122 glt->glformat = texinfo->glformat;
2123 glt->gltype = texinfo->gltype;
2124 glt->bytesperpixel = texinfo->internalbytesperpixel;
2126 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2127 glt->tilewidth = mipwidth;
2128 glt->tileheight = mipheight;
2130 glt->miplevels = dds_miplevels;
2132 // texture uploading can take a while, so make sure we're sending keepalives
2133 CL_KeepaliveMessage(false);
2135 // create the texture object
2136 switch(vid.renderpath)
2138 case RENDERPATH_GL11:
2139 case RENDERPATH_GL13:
2140 case RENDERPATH_GL20:
2141 case RENDERPATH_CGGL:
2143 GL_ActiveTexture(0);
2144 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2145 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2146 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2148 case RENDERPATH_D3D9:
2151 D3DFORMAT d3dformat;
2156 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2157 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2158 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2159 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2160 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2163 d3dpool = D3DPOOL_MANAGED;
2164 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2168 case RENDERPATH_D3D10:
2169 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2171 case RENDERPATH_D3D11:
2172 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2176 // upload the texture
2177 // we need to restore the texture binding after finishing the upload
2178 mipcomplete = false;
2180 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2182 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2183 if (mippixels + mipsize > mippixels_start + mipsize_total)
2185 switch(vid.renderpath)
2187 case RENDERPATH_GL11:
2188 case RENDERPATH_GL13:
2189 case RENDERPATH_GL20:
2190 case RENDERPATH_CGGL:
2193 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2197 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2200 case RENDERPATH_D3D9:
2203 D3DLOCKED_RECT d3dlockedrect;
2204 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2206 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2207 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2213 case RENDERPATH_D3D10:
2214 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2216 case RENDERPATH_D3D11:
2217 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2220 mippixels += mipsize;
2221 if (mipwidth <= 1 && mipheight <= 1)
2232 // after upload we have to set some parameters...
2233 switch(vid.renderpath)
2235 case RENDERPATH_GL11:
2236 case RENDERPATH_GL13:
2237 case RENDERPATH_GL20:
2238 case RENDERPATH_CGGL:
2239 if (dds_miplevels >= 1 && !mipcomplete)
2241 // need to set GL_TEXTURE_MAX_LEVEL
2242 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2244 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2245 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2247 case RENDERPATH_D3D9:
2249 glt->d3daddressw = 0;
2250 if (glt->flags & TEXF_CLAMP)
2252 glt->d3daddressu = D3DTADDRESS_CLAMP;
2253 glt->d3daddressv = D3DTADDRESS_CLAMP;
2254 if (glt->tiledepth > 1)
2255 glt->d3daddressw = D3DTADDRESS_CLAMP;
2259 glt->d3daddressu = D3DTADDRESS_WRAP;
2260 glt->d3daddressv = D3DTADDRESS_WRAP;
2261 if (glt->tiledepth > 1)
2262 glt->d3daddressw = D3DTADDRESS_WRAP;
2264 glt->d3dmipmaplodbias = 0;
2265 glt->d3dmaxmiplevel = 0;
2266 glt->d3dmaxmiplevelfilter = 0;
2267 if (glt->flags & TEXF_MIPMAP)
2269 glt->d3dminfilter = d3d_filter_mipmin;
2270 glt->d3dmagfilter = d3d_filter_mipmag;
2271 glt->d3dmipfilter = d3d_filter_mipmix;
2275 glt->d3dminfilter = d3d_filter_flatmin;
2276 glt->d3dmagfilter = d3d_filter_flatmag;
2277 glt->d3dmipfilter = d3d_filter_flatmix;
2281 case RENDERPATH_D3D10:
2282 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2284 case RENDERPATH_D3D11:
2285 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2291 Mem_Free((unsigned char *) mippixels_start);
2292 return (rtexture_t *)glt;
2295 int R_TextureWidth(rtexture_t *rt)
2297 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2300 int R_TextureHeight(rtexture_t *rt)
2302 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2305 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
2307 gltexture_t *glt = (gltexture_t *)rt;
2309 Host_Error("R_UpdateTexture: no data supplied");
2311 Host_Error("R_UpdateTexture: no texture supplied");
2312 if (!glt->texnum && !glt->d3dtexture)
2314 Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", (void *)glt, glt->identifier, (void *)glt->pool);
2317 // update part of the texture
2318 if (glt->bufferpixels)
2321 int bpp = glt->bytesperpixel;
2322 int inputskip = width*bpp;
2323 int outputskip = glt->tilewidth*bpp;
2324 const unsigned char *input = data;
2325 unsigned char *output = glt->bufferpixels;
2335 input -= y*inputskip;
2338 if (width > glt->tilewidth - x)
2339 width = glt->tilewidth - x;
2340 if (height > glt->tileheight - y)
2341 height = glt->tileheight - y;
2342 if (width < 1 || height < 1)
2345 glt->buffermodified = true;
2346 output += y*outputskip + x*bpp;
2347 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2348 memcpy(output, input, width*bpp);
2350 else if (x || y || width != glt->inputwidth || height != glt->inputheight)
2351 R_UploadPartialTexture(glt, data, x, y, 0, width, height, 1);
2353 R_UploadFullTexture(glt, data);
2356 int R_RealGetTexture(rtexture_t *rt)
2361 glt = (gltexture_t *)rt;
2362 if (glt->flags & GLTEXF_DYNAMIC)
2363 R_UpdateDynamicTexture(glt);
2364 if (glt->buffermodified && glt->bufferpixels)
2366 glt->buffermodified = false;
2367 R_UploadFullTexture(glt, glt->bufferpixels);
2376 void R_ClearTexture (rtexture_t *rt)
2378 gltexture_t *glt = (gltexture_t *)rt;
2380 R_UploadFullTexture(glt, NULL);
2383 int R_PicmipForFlags(int flags)
2386 if(flags & TEXF_PICMIP)
2388 miplevel += gl_picmip.integer;
2389 if (flags & TEXF_ISWORLD)
2391 if (r_picmipworld.integer)
2392 miplevel += gl_picmip_world.integer;
2396 else if (flags & TEXF_ISSPRITE)
2398 if (r_picmipsprites.integer)
2399 miplevel += gl_picmip_sprites.integer;
2404 miplevel += gl_picmip_other.integer;
2406 return max(0, miplevel);