5 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
10 #include "intoverflow.h"
11 #include "dpsoftrast.h"
13 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)"};
14 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)"};
15 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%"};
16 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)"};
17 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)"};
18 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)"};
19 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)"};
20 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)"};
21 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)"};
22 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"};
23 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"};
24 cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
25 cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
26 cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
27 cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
28 cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
29 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
30 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)"};
31 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
32 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
33 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)"};
34 cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "1", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"};
35 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 cvar_t r_texture_dds_load_logfailure = {0, "r_texture_dds_load_logfailure", "1", "log missing DDS textures to ddstexturefailures.log"};
37 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"};
39 qboolean gl_filter_force = false;
40 int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
41 int gl_filter_mag = GL_LINEAR;
42 DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_mipmap = DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE;
43 DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_nomipmap = DPSOFTRAST_TEXTURE_FILTER_NEAREST;
46 int d3d_filter_flatmin = D3DTEXF_LINEAR;
47 int d3d_filter_flatmag = D3DTEXF_LINEAR;
48 int d3d_filter_flatmix = D3DTEXF_POINT;
49 int d3d_filter_mipmin = D3DTEXF_LINEAR;
50 int d3d_filter_mipmag = D3DTEXF_LINEAR;
51 int d3d_filter_mipmix = D3DTEXF_LINEAR;
52 int d3d_filter_nomip = false;
56 static mempool_t *texturemempool;
57 static memexpandablearray_t texturearray;
59 // note: this must not conflict with TEXF_ flags in r_textures.h
60 // bitmask for mismatch checking
61 #define GLTEXF_IMPORTANTBITS (0)
62 // dynamic texture (treat texnum == 0 differently)
63 #define GLTEXF_DYNAMIC 0x00080000
65 typedef struct textypeinfo_s
68 int inputbytesperpixel;
69 int internalbytesperpixel;
70 float glinternalbytesperpixel;
78 static textypeinfo_t textype_palette = {TEXTYPE_PALETTE , 1, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE };
79 static textypeinfo_t textype_palette_alpha = {TEXTYPE_PALETTE , 1, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
80 static textypeinfo_t textype_rgba = {TEXTYPE_RGBA , 4, 4, 4.0f, 3 , GL_RGBA , GL_UNSIGNED_BYTE };
81 static textypeinfo_t textype_rgba_alpha = {TEXTYPE_RGBA , 4, 4, 4.0f, 4 , GL_RGBA , GL_UNSIGNED_BYTE };
82 static textypeinfo_t textype_rgba_compress = {TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
83 static textypeinfo_t textype_rgba_alpha_compress = {TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA , GL_UNSIGNED_BYTE };
84 static textypeinfo_t textype_bgra = {TEXTYPE_BGRA , 4, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE };
85 static textypeinfo_t textype_bgra_alpha = {TEXTYPE_BGRA , 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
86 static textypeinfo_t textype_bgra_compress = {TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
87 static textypeinfo_t textype_bgra_alpha_compress = {TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_BGRA , GL_UNSIGNED_BYTE };
88 static textypeinfo_t textype_shadowmap16 = {TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
89 static textypeinfo_t textype_shadowmap24 = {TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
90 static textypeinfo_t textype_alpha = {TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
91 static textypeinfo_t textype_dxt1 = {TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
92 static textypeinfo_t textype_dxt1a = {TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0 , 0 };
93 static textypeinfo_t textype_dxt3 = {TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0 , 0 };
94 static textypeinfo_t textype_dxt5 = {TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0 , 0 };
95 static textypeinfo_t textype_colorbuffer = {TEXTYPE_COLORBUFFER, 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
98 typedef enum gltexturetype_e
102 GLTEXTURETYPE_CUBEMAP,
107 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB};
108 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
109 static int cubemapside[6] =
111 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
112 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
113 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
114 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
115 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
116 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
119 typedef struct gltexture_s
121 // this portion of the struct is exposed to the R_GetTexture macro for
122 // speed reasons, must be identical in rtexture_t!
123 int texnum; // GL texture slot number
124 qboolean dirty; // indicates that R_RealGetTexture should be called
125 int gltexturetypeenum; // used by R_Mesh_TexBind
126 // d3d stuff the backend needs
129 qboolean d3disdepthsurface; // for depth/stencil surfaces
139 int d3dmaxmiplevelfilter;
140 int d3dmipmaplodbias;
144 // dynamic texture stuff [11/22/2007 Black]
145 updatecallback_t updatecallback;
146 void *updatacallback_data;
147 // --- [11/22/2007 Black]
149 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
150 unsigned char *bufferpixels;
151 qboolean buffermodified;
153 // pointer to texturepool (check this to see if the texture is allocated)
154 struct gltexturepool_s *pool;
155 // pointer to next texture in texturepool chain
156 struct gltexture_s *chain;
157 // name of the texture (this might be removed someday), no duplicates
158 char identifier[MAX_QPATH + 32];
159 // original data size in *inputtexels
160 int inputwidth, inputheight, inputdepth;
161 // copy of the original texture(s) supplied to the upload function, for
162 // delayed uploads (non-precached)
163 unsigned char *inputtexels;
164 // original data size in *inputtexels
166 // flags supplied to the LoadTexture function
167 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
171 // pointer to one of the textype_ structs
172 textypeinfo_t *textype;
173 // one of the GLTEXTURETYPE_ values
175 // palette if the texture is TEXTYPE_PALETTE
176 const unsigned int *palette;
177 // actual stored texture size after gl_picmip and gl_max_size are applied
178 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
179 int tilewidth, tileheight, tiledepth;
180 // 1 or 6 depending on texturetype
182 // how many mipmap levels in this texture
186 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
189 int glinternalformat;
190 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
195 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
197 typedef struct gltexturepool_s
199 unsigned int sentinel;
200 struct gltexture_s *gltchain;
201 struct gltexturepool_s *next;
205 static gltexturepool_t *gltexturepoolchain = NULL;
207 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
208 static int resizebuffersize = 0;
209 static const unsigned char *texturebuffer;
211 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
216 return &textype_dxt1;
218 return &textype_dxt1a;
220 return &textype_dxt3;
222 return &textype_dxt5;
223 case TEXTYPE_PALETTE:
224 return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
226 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
227 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress;
228 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba;
230 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
231 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress;
232 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra;
234 return &textype_alpha;
235 case TEXTYPE_SHADOWMAP:
236 return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
237 case TEXTYPE_COLORBUFFER:
238 return &textype_colorbuffer;
240 Host_Error("R_GetTexTypeInfo: unknown texture format");
246 // dynamic texture code [11/22/2007 Black]
247 void R_MarkDirtyTexture(rtexture_t *rt) {
248 gltexture_t *glt = (gltexture_t*) rt;
253 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
254 if (glt->flags & GLTEXF_DYNAMIC)
256 // mark it as dirty, so R_RealGetTexture gets called
261 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
262 gltexture_t *glt = (gltexture_t*) rt;
267 glt->flags |= GLTEXF_DYNAMIC;
268 glt->updatecallback = updatecallback;
269 glt->updatacallback_data = data;
272 static void R_UpdateDynamicTexture(gltexture_t *glt) {
274 if( glt->updatecallback ) {
275 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
279 void R_PurgeTexture(rtexture_t *rt)
281 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
286 void R_FreeTexture(rtexture_t *rt)
288 gltexture_t *glt, **gltpointer;
290 glt = (gltexture_t *)rt;
292 Host_Error("R_FreeTexture: texture == NULL");
294 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
295 if (*gltpointer == glt)
296 *gltpointer = glt->chain;
298 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
300 switch(vid.renderpath)
302 case RENDERPATH_GL11:
303 case RENDERPATH_GL13:
304 case RENDERPATH_GL20:
305 case RENDERPATH_CGGL:
309 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
312 case RENDERPATH_D3D9:
314 if (glt->d3disdepthsurface)
315 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
316 else if (glt->tiledepth > 1)
317 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
318 else if (glt->sides == 6)
319 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
321 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
322 glt->d3dtexture = NULL;
325 case RENDERPATH_D3D10:
326 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
328 case RENDERPATH_D3D11:
329 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
331 case RENDERPATH_SOFT:
333 DPSOFTRAST_Texture_Free(glt->texnum);
337 if (glt->inputtexels)
338 Mem_Free(glt->inputtexels);
339 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
342 rtexturepool_t *R_AllocTexturePool(void)
344 gltexturepool_t *pool;
345 if (texturemempool == NULL)
347 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
350 pool->next = gltexturepoolchain;
351 gltexturepoolchain = pool;
352 pool->sentinel = TEXTUREPOOL_SENTINEL;
353 return (rtexturepool_t *)pool;
356 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
358 gltexturepool_t *pool, **poolpointer;
359 if (rtexturepool == NULL)
361 if (*rtexturepool == NULL)
363 pool = (gltexturepool_t *)(*rtexturepool);
364 *rtexturepool = NULL;
365 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
366 Host_Error("R_FreeTexturePool: pool already freed");
367 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
368 if (*poolpointer == pool)
369 *poolpointer = pool->next;
371 Host_Error("R_FreeTexturePool: pool not linked");
372 while (pool->gltchain)
373 R_FreeTexture((rtexture_t *)pool->gltchain);
378 typedef struct glmode_s
381 int minification, magnification;
382 DPSOFTRAST_TEXTURE_FILTER dpsoftrastfilter_mipmap, dpsoftrastfilter_nomipmap;
386 static glmode_t modes[6] =
388 {"GL_NEAREST", GL_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
389 {"GL_LINEAR", GL_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
390 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
391 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
392 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
393 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR}
397 typedef struct d3dmode_s
404 static d3dmode_t d3dmodes[6] =
406 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
407 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
408 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
409 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
410 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
411 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
415 static void GL_TextureMode_f (void)
420 gltexturepool_t *pool;
424 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
425 for (i = 0;i < 6;i++)
427 if (gl_filter_min == modes[i].minification)
429 Con_Printf("%s\n", modes[i].name);
433 Con_Print("current filter is unknown???\n");
437 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
438 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
442 Con_Print("bad filter name\n");
446 gl_filter_min = modes[i].minification;
447 gl_filter_mag = modes[i].magnification;
448 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
450 dpsoftrast_filter_mipmap = modes[i].dpsoftrastfilter_mipmap;
451 dpsoftrast_filter_nomipmap = modes[i].dpsoftrastfilter_nomipmap;
453 switch(vid.renderpath)
455 case RENDERPATH_GL11:
456 case RENDERPATH_GL13:
457 case RENDERPATH_GL20:
458 case RENDERPATH_CGGL:
459 // change all the existing mipmap texture objects
460 // FIXME: force renderer(/client/something?) restart instead?
463 for (pool = gltexturepoolchain;pool;pool = pool->next)
465 for (glt = pool->gltchain;glt;glt = glt->chain)
467 // only update already uploaded images
468 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
470 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
471 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
472 if (glt->flags & TEXF_MIPMAP)
474 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
478 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
480 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
481 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
486 case RENDERPATH_D3D9:
488 d3d_filter_flatmin = d3dmodes[i].m1;
489 d3d_filter_flatmag = d3dmodes[i].m1;
490 d3d_filter_flatmix = D3DTEXF_POINT;
491 d3d_filter_mipmin = d3dmodes[i].m1;
492 d3d_filter_mipmag = d3dmodes[i].m1;
493 d3d_filter_mipmix = d3dmodes[i].m2;
494 d3d_filter_nomip = i < 2;
495 if (gl_texture_anisotropy.integer > 1 && i == 5)
496 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
497 for (pool = gltexturepoolchain;pool;pool = pool->next)
499 for (glt = pool->gltchain;glt;glt = glt->chain)
501 // only update already uploaded images
502 if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
504 if (glt->flags & TEXF_MIPMAP)
506 glt->d3dminfilter = d3d_filter_mipmin;
507 glt->d3dmagfilter = d3d_filter_mipmag;
508 glt->d3dmipfilter = d3d_filter_mipmix;
509 glt->d3dmaxmiplevelfilter = 0;
513 glt->d3dminfilter = d3d_filter_flatmin;
514 glt->d3dmagfilter = d3d_filter_flatmag;
515 glt->d3dmipfilter = d3d_filter_flatmix;
516 glt->d3dmaxmiplevelfilter = 0;
523 case RENDERPATH_D3D10:
524 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
526 case RENDERPATH_D3D11:
527 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
529 case RENDERPATH_SOFT:
530 // change all the existing texture objects
531 for (pool = gltexturepoolchain;pool;pool = pool->next)
532 for (glt = pool->gltchain;glt;glt = glt->chain)
533 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
534 DPSOFTRAST_Texture_Filter(glt->texnum, (glt->flags & TEXF_MIPMAP) ? dpsoftrast_filter_mipmap : dpsoftrast_filter_nomipmap);
539 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)
541 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
546 case GLTEXTURETYPE_2D:
547 maxsize = vid.maxtexturesize_2d;
548 if (flags & TEXF_PICMIP)
550 maxsize = bound(1, gl_max_size.integer, maxsize);
554 case GLTEXTURETYPE_3D:
555 maxsize = vid.maxtexturesize_3d;
557 case GLTEXTURETYPE_CUBEMAP:
558 maxsize = vid.maxtexturesize_cubemap;
562 if (vid.support.arb_texture_non_power_of_two)
564 width2 = min(inwidth >> picmip, maxsize);
565 height2 = min(inheight >> picmip, maxsize);
566 depth2 = min(indepth >> picmip, maxsize);
570 for (width2 = 1;width2 < inwidth;width2 <<= 1);
571 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
572 for (height2 = 1;height2 < inheight;height2 <<= 1);
573 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
574 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
575 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
578 switch(vid.renderpath)
580 case RENDERPATH_GL11:
581 case RENDERPATH_GL13:
582 case RENDERPATH_GL20:
583 case RENDERPATH_CGGL:
584 case RENDERPATH_D3D10:
585 case RENDERPATH_D3D11:
586 case RENDERPATH_SOFT:
588 case RENDERPATH_D3D9:
590 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
591 if (texturetype == GLTEXTURETYPE_2D)
593 width2 = max(width2, 2);
594 height2 = max(height2, 2);
601 if (flags & TEXF_MIPMAP)
603 int extent = max(width2, max(height2, depth2));
609 *outwidth = max(1, width2);
611 *outheight = max(1, height2);
613 *outdepth = max(1, depth2);
615 *outmiplevels = miplevels;
619 static int R_CalcTexelDataSize (gltexture_t *glt)
621 int width2, height2, depth2, size;
623 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
625 size = width2 * height2 * depth2;
627 if (glt->flags & TEXF_MIPMAP)
629 while (width2 > 1 || height2 > 1 || depth2 > 1)
637 size += width2 * height2 * depth2;
641 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
644 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
648 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
649 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
651 gltexturepool_t *pool;
653 Con_Print("glsize input loaded mip alpha name\n");
654 for (pool = gltexturepoolchain;pool;pool = pool->next)
662 for (glt = pool->gltchain;glt;glt = glt->chain)
664 glsize = R_CalcTexelDataSize(glt);
665 isloaded = glt->texnum != 0;
667 pooltotalt += glsize;
668 pooltotalp += glt->inputdatasize;
672 poolloadedt += glsize;
673 poolloadedp += glt->inputdatasize;
676 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);
679 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);
680 sumtotal += pooltotal;
681 sumtotalt += pooltotalt;
682 sumtotalp += pooltotalp;
683 sumloaded += poolloaded;
684 sumloadedt += poolloadedt;
685 sumloadedp += poolloadedp;
688 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);
691 static void R_TextureStats_f(void)
693 R_TextureStats_Print(true, true, true);
696 static void r_textures_start(void)
698 switch(vid.renderpath)
700 case RENDERPATH_GL11:
701 case RENDERPATH_GL13:
702 case RENDERPATH_GL20:
703 case RENDERPATH_CGGL:
704 // LordHavoc: allow any alignment
706 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
707 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
709 case RENDERPATH_D3D9:
711 case RENDERPATH_D3D10:
712 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
714 case RENDERPATH_D3D11:
715 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
717 case RENDERPATH_SOFT:
721 texturemempool = Mem_AllocPool("texture management", 0, NULL);
722 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
724 // Disable JPEG screenshots if the DLL isn't loaded
725 if (! JPEG_OpenLibrary ())
726 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
727 if (! PNG_OpenLibrary ())
728 Cvar_SetValueQuick (&scr_screenshot_png, 0);
731 static void r_textures_shutdown(void)
733 rtexturepool_t *temp;
735 JPEG_CloseLibrary ();
737 while(gltexturepoolchain)
739 temp = (rtexturepool_t *) gltexturepoolchain;
740 R_FreeTexturePool(&temp);
743 resizebuffersize = 0;
745 colorconvertbuffer = NULL;
746 texturebuffer = NULL;
747 Mem_ExpandableArray_FreeArray(&texturearray);
748 Mem_FreePool(&texturemempool);
751 static void r_textures_newmap(void)
755 static void r_textures_devicelost(void)
759 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
760 for (i = 0;i < endindex;i++)
762 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
763 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
765 switch(vid.renderpath)
767 case RENDERPATH_GL11:
768 case RENDERPATH_GL13:
769 case RENDERPATH_GL20:
770 case RENDERPATH_CGGL:
772 case RENDERPATH_D3D9:
774 if (glt->d3disdepthsurface)
775 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
776 else if (glt->tiledepth > 1)
777 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
778 else if (glt->sides == 6)
779 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
781 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
782 glt->d3dtexture = NULL;
785 case RENDERPATH_D3D10:
786 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
788 case RENDERPATH_D3D11:
789 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
791 case RENDERPATH_SOFT:
797 static void r_textures_devicerestored(void)
801 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
802 for (i = 0;i < endindex;i++)
804 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
805 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
807 switch(vid.renderpath)
809 case RENDERPATH_GL11:
810 case RENDERPATH_GL13:
811 case RENDERPATH_GL20:
812 case RENDERPATH_CGGL:
814 case RENDERPATH_D3D9:
818 if (glt->d3disdepthsurface)
820 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
821 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
823 else if (glt->tiledepth > 1)
825 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)))
826 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
828 else if (glt->sides == 6)
830 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
831 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
835 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)))
836 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
841 case RENDERPATH_D3D10:
842 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
844 case RENDERPATH_D3D11:
845 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
847 case RENDERPATH_SOFT:
854 void R_Textures_Init (void)
856 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");
857 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
858 Cvar_RegisterVariable (&gl_max_size);
859 Cvar_RegisterVariable (&gl_picmip);
860 Cvar_RegisterVariable (&gl_picmip_world);
861 Cvar_RegisterVariable (&r_picmipworld);
862 Cvar_RegisterVariable (&gl_picmip_sprites);
863 Cvar_RegisterVariable (&r_picmipsprites);
864 Cvar_RegisterVariable (&gl_picmip_other);
865 Cvar_RegisterVariable (&gl_max_lightmapsize);
866 Cvar_RegisterVariable (&r_lerpimages);
867 Cvar_RegisterVariable (&gl_texture_anisotropy);
868 Cvar_RegisterVariable (&gl_texturecompression);
869 Cvar_RegisterVariable (&gl_texturecompression_color);
870 Cvar_RegisterVariable (&gl_texturecompression_normal);
871 Cvar_RegisterVariable (&gl_texturecompression_gloss);
872 Cvar_RegisterVariable (&gl_texturecompression_glow);
873 Cvar_RegisterVariable (&gl_texturecompression_2d);
874 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
875 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
876 Cvar_RegisterVariable (&gl_texturecompression_sky);
877 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
878 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
879 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
880 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
881 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
882 Cvar_RegisterVariable (&r_texture_dds_swdecode);
884 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
887 void R_Textures_Frame (void)
889 static int old_aniso = 0;
891 // could do procedural texture animation here, if we keep track of which
892 // textures were accessed this frame...
894 // free the resize buffers
895 resizebuffersize = 0;
898 Mem_Free(resizebuffer);
901 if (colorconvertbuffer)
903 Mem_Free(colorconvertbuffer);
904 colorconvertbuffer = NULL;
907 if (old_aniso != gl_texture_anisotropy.integer)
910 gltexturepool_t *pool;
913 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
915 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
917 switch(vid.renderpath)
919 case RENDERPATH_GL11:
920 case RENDERPATH_GL13:
921 case RENDERPATH_GL20:
922 case RENDERPATH_CGGL:
925 for (pool = gltexturepoolchain;pool;pool = pool->next)
927 for (glt = pool->gltchain;glt;glt = glt->chain)
929 // only update already uploaded images
930 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
932 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
934 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
935 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
937 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
942 case RENDERPATH_D3D9:
943 case RENDERPATH_D3D10:
944 case RENDERPATH_D3D11:
945 case RENDERPATH_SOFT:
951 void R_MakeResizeBufferBigger(int size)
953 if (resizebuffersize < size)
955 resizebuffersize = size;
957 Mem_Free(resizebuffer);
958 if (colorconvertbuffer)
959 Mem_Free(colorconvertbuffer);
960 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
961 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
962 if (!resizebuffer || !colorconvertbuffer)
963 Host_Error("R_Upload: out of memory");
967 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
969 int textureenum = gltexturetypeenums[texturetype];
970 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
974 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
976 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
977 if (gl_texture_anisotropy.integer != aniso)
978 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
979 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
981 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
982 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
983 if (gltexturetypedimensions[texturetype] >= 3)
985 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
989 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
991 if (flags & TEXF_MIPMAP)
993 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
997 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
999 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
1001 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
1003 if (flags & TEXF_MIPMAP)
1005 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
1007 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
1011 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
1016 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
1018 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
1022 if (flags & TEXF_MIPMAP)
1024 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1028 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1030 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1033 if (textype == TEXTYPE_SHADOWMAP)
1035 if (vid.support.arb_shadow)
1037 if (flags & TEXF_COMPARE)
1039 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1043 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1045 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1047 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1053 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1056 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1058 if (glt->texturetype != GLTEXTURETYPE_2D)
1059 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1061 if (glt->textype->textype == TEXTYPE_PALETTE)
1062 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1064 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1065 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1067 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1068 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1070 // update a portion of the image
1072 switch(vid.renderpath)
1074 case RENDERPATH_GL11:
1075 case RENDERPATH_GL13:
1076 case RENDERPATH_GL20:
1077 case RENDERPATH_CGGL:
1081 // we need to restore the texture binding after finishing the upload
1082 GL_ActiveTexture(0);
1083 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1084 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1085 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1086 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1089 case RENDERPATH_D3D9:
1093 D3DLOCKED_RECT d3dlockedrect;
1095 memset(&d3drect, 0, sizeof(d3drect));
1096 d3drect.left = fragx;
1097 d3drect.top = fragy;
1098 d3drect.right = fragx+fragwidth;
1099 d3drect.bottom = fragy+fragheight;
1100 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1102 for (y = 0;y < fragheight;y++)
1103 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1104 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1109 case RENDERPATH_D3D10:
1110 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1112 case RENDERPATH_D3D11:
1113 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1115 case RENDERPATH_SOFT:
1116 DPSOFTRAST_Texture_UpdatePartial(glt->texnum, 0, data, fragx, fragy, fragwidth, fragheight);
1121 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1123 int i, mip = 0, width, height, depth;
1124 GLint oldbindtexnum = 0;
1125 const unsigned char *prevbuffer;
1128 // error out if a stretch is needed on special texture types
1129 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1130 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1132 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1133 // of the target size and then use the mipmap reduction function to get
1134 // high quality supersampled results
1135 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1136 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1137 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1138 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1140 if (prevbuffer == NULL)
1142 width = glt->tilewidth;
1143 height = glt->tileheight;
1144 depth = glt->tiledepth;
1145 memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1146 prevbuffer = resizebuffer;
1148 else if (glt->textype->textype == TEXTYPE_PALETTE)
1150 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1151 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1152 prevbuffer = colorconvertbuffer;
1155 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1157 // multiply RGB channels by A channel before uploading
1159 for (i = 0;i < width*height*depth*4;i += 4)
1161 alpha = prevbuffer[i+3];
1162 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1163 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1164 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1165 colorconvertbuffer[i+3] = alpha;
1167 prevbuffer = colorconvertbuffer;
1170 // scale up to a power of 2 size (if appropriate)
1171 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1173 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1174 prevbuffer = resizebuffer;
1176 // apply mipmap reduction algorithm to get down to picmip/max_size
1177 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1179 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1180 prevbuffer = resizebuffer;
1183 // do the appropriate upload type...
1184 switch(vid.renderpath)
1186 case RENDERPATH_GL11:
1187 case RENDERPATH_GL13:
1188 case RENDERPATH_GL20:
1189 case RENDERPATH_CGGL:
1192 // we need to restore the texture binding after finishing the upload
1193 GL_ActiveTexture(0);
1194 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1195 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1197 if (qglGetCompressedTexImageARB)
1199 if (gl_texturecompression.integer >= 2)
1200 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1202 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1205 switch(glt->texturetype)
1207 case GLTEXTURETYPE_2D:
1208 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1209 if (glt->flags & TEXF_MIPMAP)
1211 while (width > 1 || height > 1 || depth > 1)
1213 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1214 prevbuffer = resizebuffer;
1215 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1219 case GLTEXTURETYPE_3D:
1220 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 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 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1231 case GLTEXTURETYPE_CUBEMAP:
1232 // convert and upload each side in turn,
1233 // from a continuous block of input texels
1234 texturebuffer = (unsigned char *)prevbuffer;
1235 for (i = 0;i < 6;i++)
1237 prevbuffer = texturebuffer;
1238 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1239 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1241 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1242 prevbuffer = resizebuffer;
1245 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1247 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1248 prevbuffer = resizebuffer;
1251 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1252 if (glt->flags & TEXF_MIPMAP)
1254 while (width > 1 || height > 1 || depth > 1)
1256 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1257 prevbuffer = resizebuffer;
1258 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1264 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1265 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1267 case RENDERPATH_D3D9:
1269 if (!(glt->flags & TEXF_RENDERTARGET))
1271 D3DLOCKED_RECT d3dlockedrect;
1272 D3DLOCKED_BOX d3dlockedbox;
1273 switch(glt->texturetype)
1275 case GLTEXTURETYPE_2D:
1276 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1279 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1281 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1282 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1285 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1287 while (width > 1 || height > 1 || depth > 1)
1289 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1290 prevbuffer = resizebuffer;
1291 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1293 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1294 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1300 case GLTEXTURETYPE_3D:
1301 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1303 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1304 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1305 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1308 if (glt->flags & TEXF_MIPMAP)
1310 while (width > 1 || height > 1 || depth > 1)
1312 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1313 prevbuffer = resizebuffer;
1314 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1316 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1317 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1318 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1324 case GLTEXTURETYPE_CUBEMAP:
1325 // convert and upload each side in turn,
1326 // from a continuous block of input texels
1327 texturebuffer = (unsigned char *)prevbuffer;
1328 for (i = 0;i < 6;i++)
1330 prevbuffer = texturebuffer;
1331 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1332 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1334 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1335 prevbuffer = resizebuffer;
1338 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1340 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1341 prevbuffer = resizebuffer;
1344 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1346 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1347 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1350 if (glt->flags & TEXF_MIPMAP)
1352 while (width > 1 || height > 1 || depth > 1)
1354 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1355 prevbuffer = resizebuffer;
1356 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1358 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1359 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1368 glt->d3daddressw = 0;
1369 if (glt->flags & TEXF_CLAMP)
1371 glt->d3daddressu = D3DTADDRESS_CLAMP;
1372 glt->d3daddressv = D3DTADDRESS_CLAMP;
1373 if (glt->tiledepth > 1)
1374 glt->d3daddressw = D3DTADDRESS_CLAMP;
1378 glt->d3daddressu = D3DTADDRESS_WRAP;
1379 glt->d3daddressv = D3DTADDRESS_WRAP;
1380 if (glt->tiledepth > 1)
1381 glt->d3daddressw = D3DTADDRESS_WRAP;
1383 glt->d3dmipmaplodbias = 0;
1384 glt->d3dmaxmiplevel = 0;
1385 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1386 if (glt->flags & TEXF_FORCELINEAR)
1388 glt->d3dminfilter = D3DTEXF_LINEAR;
1389 glt->d3dmagfilter = D3DTEXF_LINEAR;
1390 glt->d3dmipfilter = D3DTEXF_POINT;
1392 else if (glt->flags & TEXF_FORCENEAREST)
1394 glt->d3dminfilter = D3DTEXF_POINT;
1395 glt->d3dmagfilter = D3DTEXF_POINT;
1396 glt->d3dmipfilter = D3DTEXF_POINT;
1398 else if (glt->flags & TEXF_MIPMAP)
1400 glt->d3dminfilter = d3d_filter_mipmin;
1401 glt->d3dmagfilter = d3d_filter_mipmag;
1402 glt->d3dmipfilter = d3d_filter_mipmix;
1406 glt->d3dminfilter = d3d_filter_flatmin;
1407 glt->d3dmagfilter = d3d_filter_flatmag;
1408 glt->d3dmipfilter = d3d_filter_flatmix;
1412 case RENDERPATH_D3D10:
1413 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1415 case RENDERPATH_D3D11:
1416 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1418 case RENDERPATH_SOFT:
1419 switch(glt->texturetype)
1421 case GLTEXTURETYPE_2D:
1422 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1424 case GLTEXTURETYPE_3D:
1425 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1427 case GLTEXTURETYPE_CUBEMAP:
1428 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1430 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1431 // convert and upload each side in turn,
1432 // from a continuous block of input texels
1433 // copy the results into combinedbuffer
1434 texturebuffer = (unsigned char *)prevbuffer;
1435 for (i = 0;i < 6;i++)
1437 prevbuffer = texturebuffer;
1438 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1439 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1441 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1442 prevbuffer = resizebuffer;
1445 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1447 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1448 prevbuffer = resizebuffer;
1450 memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1452 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1453 Mem_Free(combinedbuffer);
1456 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1459 if (glt->flags & TEXF_FORCELINEAR)
1460 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1461 else if (glt->flags & TEXF_FORCENEAREST)
1462 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1463 else if (glt->flags & TEXF_MIPMAP)
1464 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1466 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1471 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)
1475 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1476 textypeinfo_t *texinfo, *texinfo2;
1477 unsigned char *temppixels = NULL;
1479 if (cls.state == ca_dedicated)
1482 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1484 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1487 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1489 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1493 texinfo = R_GetTexTypeInfo(textype, flags);
1494 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1497 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1501 if (textype == TEXTYPE_RGBA)
1504 static int rgbaswapindices[4] = {2, 1, 0, 3};
1505 textype = TEXTYPE_BGRA;
1506 texinfo = R_GetTexTypeInfo(textype, flags);
1507 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1508 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1512 // clear the alpha flag if the texture has no transparent pixels
1515 case TEXTYPE_PALETTE:
1516 if (flags & TEXF_ALPHA)
1518 flags &= ~TEXF_ALPHA;
1521 for (i = 0;i < size;i++)
1523 if (((unsigned char *)&palette[data[i]])[3] < 255)
1525 flags |= TEXF_ALPHA;
1534 if (flags & TEXF_ALPHA)
1536 flags &= ~TEXF_ALPHA;
1539 for (i = 3;i < size;i += 4)
1543 flags |= TEXF_ALPHA;
1550 case TEXTYPE_SHADOWMAP:
1557 flags |= TEXF_ALPHA;
1560 flags |= TEXF_ALPHA;
1562 case TEXTYPE_COLORBUFFER:
1563 flags |= TEXF_ALPHA;
1566 Sys_Error("R_LoadTexture: unknown texture type");
1569 texinfo2 = R_GetTexTypeInfo(textype, flags);
1570 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1573 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1575 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1577 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1579 glt->chain = pool->gltchain;
1580 pool->gltchain = glt;
1581 glt->inputwidth = width;
1582 glt->inputheight = height;
1583 glt->inputdepth = depth;
1585 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
1586 glt->textype = texinfo;
1587 glt->texturetype = texturetype;
1588 glt->inputdatasize = size;
1589 glt->palette = palette;
1590 glt->glinternalformat = texinfo->glinternalformat;
1591 glt->glformat = texinfo->glformat;
1592 glt->gltype = texinfo->gltype;
1593 glt->bytesperpixel = texinfo->internalbytesperpixel;
1594 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1597 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1598 // init the dynamic texture attributes, too [11/22/2007 Black]
1599 glt->updatecallback = NULL;
1600 glt->updatacallback_data = NULL;
1602 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1604 // upload the texture
1605 // data may be NULL (blank texture for dynamic rendering)
1606 switch(vid.renderpath)
1608 case RENDERPATH_GL11:
1609 case RENDERPATH_GL13:
1610 case RENDERPATH_GL20:
1611 case RENDERPATH_CGGL:
1613 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1615 case RENDERPATH_D3D9:
1618 D3DFORMAT d3dformat;
1623 d3dpool = D3DPOOL_MANAGED;
1624 if (flags & TEXF_RENDERTARGET)
1626 d3dusage |= D3DUSAGE_RENDERTARGET;
1627 d3dpool = D3DPOOL_DEFAULT;
1631 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1632 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1633 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1634 case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1635 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1636 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1637 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1639 glt->d3dformat = d3dformat;
1640 glt->d3dusage = d3dusage;
1641 glt->d3dpool = d3dpool;
1642 glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1643 if (glt->d3disdepthsurface)
1645 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1646 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1648 else if (glt->tiledepth > 1)
1650 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)))
1651 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1653 else if (glt->sides == 6)
1655 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1656 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1660 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)))
1661 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1666 case RENDERPATH_D3D10:
1667 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1669 case RENDERPATH_D3D11:
1670 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1672 case RENDERPATH_SOFT:
1677 case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1678 case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1679 case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1680 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1681 case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1682 case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1683 default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1685 if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1686 if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1687 if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1688 if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1689 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1694 R_UploadFullTexture(glt, data);
1695 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1696 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1698 // free any temporary processing buffer we allocated...
1700 Mem_Free(temppixels);
1702 // texture converting and uploading can take a while, so make sure we're sending keepalives
1703 // FIXME: this causes rendering during R_Shadow_DrawLights
1704 // CL_KeepaliveMessage(false);
1706 return (rtexture_t *)glt;
1709 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)
1711 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1714 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)
1716 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1719 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)
1721 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1724 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1726 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1728 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1730 flags |= TEXF_FORCENEAREST;
1731 if (precision <= 16)
1732 flags |= TEXF_LOWPRECISION;
1736 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1738 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1741 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1743 gltexture_t *glt = (gltexture_t *)rt;
1746 int bytesperpixel = 0;
1747 int bytesperblock = 0;
1749 int dds_format_flags;
1757 GLint internalformat;
1758 const char *ddsfourcc;
1760 return -1; // NULL pointer
1761 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1762 return -2; // broken driver - crashes on reading internal format
1763 if (!qglGetTexLevelParameteriv)
1765 GL_ActiveTexture(0);
1766 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1767 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1768 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1769 switch(internalformat)
1771 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1772 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1773 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1774 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1775 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1777 // if premultiplied alpha, say so in the DDS file
1778 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1780 switch(internalformat)
1782 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1783 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1786 if (!bytesperblock && skipuncompressed)
1787 return -3; // skipped
1788 memset(mipinfo, 0, sizeof(mipinfo));
1789 mipinfo[0][0] = glt->tilewidth;
1790 mipinfo[0][1] = glt->tileheight;
1792 if (glt->flags & TEXF_MIPMAP)
1794 for (mip = 1;mip < 16;mip++)
1796 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1797 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1798 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1806 for (mip = 0;mip < mipmaps;mip++)
1808 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1809 mipinfo[mip][3] = ddssize;
1810 ddssize += mipinfo[mip][2];
1812 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1815 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1819 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1820 dds_format_flags = 0x4; // DDPF_FOURCC
1824 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1825 dds_format_flags = 0x40; // DDPF_RGB
1829 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1830 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1833 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1834 memcpy(dds, "DDS ", 4);
1835 StoreLittleLong(dds+4, ddssize);
1836 StoreLittleLong(dds+8, dds_flags);
1837 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1838 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1839 StoreLittleLong(dds+24, 1); // depth
1840 StoreLittleLong(dds+28, mipmaps); // mipmaps
1841 StoreLittleLong(dds+76, 32); // format size
1842 StoreLittleLong(dds+80, dds_format_flags);
1843 StoreLittleLong(dds+108, dds_caps1);
1844 StoreLittleLong(dds+112, dds_caps2);
1847 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1848 memcpy(dds+84, ddsfourcc, 4);
1849 for (mip = 0;mip < mipmaps;mip++)
1851 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1856 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1857 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1858 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1859 for (mip = 0;mip < mipmaps;mip++)
1861 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1864 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1865 ret = FS_WriteFile(filename, dds, ddssize);
1867 return ret ? ddssize : -5;
1870 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
1872 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1875 int bytesperblock, bytesperpixel;
1878 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1879 textypeinfo_t *texinfo;
1880 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1882 GLint oldbindtexnum = 0;
1883 const unsigned char *mippixels, *ddspixels, *mippixels_start;
1885 fs_offset_t ddsfilesize;
1886 unsigned int ddssize;
1887 qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
1889 if (cls.state == ca_dedicated)
1892 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1893 ddssize = ddsfilesize;
1897 if(r_texture_dds_load_logfailure.integer)
1898 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1899 return NULL; // not found
1902 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1905 Con_Printf("^1%s: not a DDS image\n", filename);
1909 //dds_flags = BuffLittleLong(dds+8);
1910 dds_format_flags = BuffLittleLong(dds+80);
1911 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1912 dds_width = BuffLittleLong(dds+16);
1913 dds_height = BuffLittleLong(dds+12);
1914 ddspixels = dds + 128;
1916 if(r_texture_dds_load_alphamode.integer == 0)
1917 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1918 flags &= ~TEXF_ALPHA;
1920 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1921 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1923 // very sloppy BGRA 32bit identification
1924 textype = TEXTYPE_BGRA;
1927 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1928 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1931 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1934 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1937 for (i = 3;i < size;i += 4)
1938 if (ddspixels[i] < 255)
1941 flags &= ~TEXF_ALPHA;
1944 else if (!memcmp(dds+84, "DXT1", 4))
1946 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1947 // LordHavoc: it is my belief that this does not infringe on the
1948 // patent because it is not decoding pixels...
1949 textype = TEXTYPE_DXT1;
1952 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1953 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1954 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1957 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1960 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1962 if(r_texture_dds_load_alphamode.integer == 1)
1965 for (i = 0;i < size;i += bytesperblock)
1966 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1968 // NOTE: this assumes sizeof(unsigned int) == 4
1969 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1970 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1971 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1975 textype = TEXTYPE_DXT1A;
1977 flags &= ~TEXF_ALPHA;
1981 flags &= ~TEXF_ALPHA;
1985 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
1987 if(!memcmp(dds+84, "DXT2", 4))
1989 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1991 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
1996 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1998 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2001 textype = TEXTYPE_DXT3;
2004 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2005 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2008 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2011 // we currently always assume alpha
2013 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2015 if(!memcmp(dds+84, "DXT4", 4))
2017 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2019 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2024 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2026 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2029 textype = TEXTYPE_DXT5;
2032 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2033 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2036 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2039 // we currently always assume alpha
2044 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2048 force_swdecode = false;
2051 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
2053 if(r_texture_dds_swdecode.integer > 1)
2054 force_swdecode = true;
2058 if(r_texture_dds_swdecode.integer < 1)
2064 force_swdecode = true;
2068 // return whether this texture is transparent
2070 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2072 // if we SW decode, choose 2 sizes bigger
2075 // this is quarter res, so do not scale down more than we have to
2079 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2082 // this is where we apply gl_picmip
2083 mippixels_start = ddspixels;
2084 mipwidth = dds_width;
2085 mipheight = dds_height;
2086 while(miplevel >= 1 && dds_miplevels >= 1)
2088 if (mipwidth <= 1 && mipheight <= 1)
2090 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2091 mippixels_start += mipsize; // just skip
2099 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2100 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2102 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2104 // fake decode S3TC if needed
2107 int mipsize_new = mipsize_total / bytesperblock * 4;
2108 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2109 unsigned char *p = mipnewpixels;
2110 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2112 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2113 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2114 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2115 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2116 if(textype == TEXTYPE_DXT5)
2117 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2118 else if(textype == TEXTYPE_DXT3)
2120 (mippixels_start[i-8] & 0x0F)
2121 + (mippixels_start[i-8] >> 4)
2122 + (mippixels_start[i-7] & 0x0F)
2123 + (mippixels_start[i-7] >> 4)
2124 + (mippixels_start[i-6] & 0x0F)
2125 + (mippixels_start[i-6] >> 4)
2126 + (mippixels_start[i-5] & 0x0F)
2127 + (mippixels_start[i-5] >> 4)
2128 ) * (0.125f / 15.0f * 255.0f);
2133 textype = TEXTYPE_BGRA;
2137 // as each block becomes a pixel, we must use pixel count for this
2138 mipwidth = (mipwidth + 3) / 4;
2139 mipheight = (mipheight + 3) / 4;
2140 mipsize = bytesperpixel * mipwidth * mipheight;
2141 mippixels_start = mipnewpixels;
2142 mipsize_total = mipsize_new;
2145 // start mip counting
2146 mippixels = mippixels_start;
2148 // calculate average color if requested
2152 Vector4Clear(avgcolor);
2155 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2157 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2158 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2159 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2160 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2161 if(textype == TEXTYPE_DXT5)
2162 avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2163 else if(textype == TEXTYPE_DXT3)
2165 (mippixels_start[i-8] & 0x0F)
2166 + (mippixels_start[i-8] >> 4)
2167 + (mippixels_start[i-7] & 0x0F)
2168 + (mippixels_start[i-7] >> 4)
2169 + (mippixels_start[i-6] & 0x0F)
2170 + (mippixels_start[i-6] >> 4)
2171 + (mippixels_start[i-5] & 0x0F)
2172 + (mippixels_start[i-5] >> 4)
2173 ) * (0.125f / 15.0f * 255.0f);
2177 f = (float)bytesperblock / size;
2178 avgcolor[0] *= (0.5f / 31.0f) * f;
2179 avgcolor[1] *= (0.5f / 63.0f) * f;
2180 avgcolor[2] *= (0.5f / 31.0f) * f;
2185 for (i = 0;i < mipsize;i += 4)
2187 avgcolor[0] += mippixels[i+2];
2188 avgcolor[1] += mippixels[i+1];
2189 avgcolor[2] += mippixels[i];
2190 avgcolor[3] += mippixels[i+3];
2192 f = (1.0f / 255.0f) * bytesperpixel / size;
2200 // when not requesting mipmaps, do not load them
2201 if(!(flags & TEXF_MIPMAP))
2204 if (dds_miplevels >= 1)
2205 flags |= TEXF_MIPMAP;
2207 flags &= ~TEXF_MIPMAP;
2209 texinfo = R_GetTexTypeInfo(textype, flags);
2211 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2212 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2214 glt->chain = pool->gltchain;
2215 pool->gltchain = glt;
2216 glt->inputwidth = mipwidth;
2217 glt->inputheight = mipheight;
2218 glt->inputdepth = 1;
2220 glt->textype = texinfo;
2221 glt->texturetype = GLTEXTURETYPE_2D;
2222 glt->inputdatasize = ddssize;
2223 glt->glinternalformat = texinfo->glinternalformat;
2224 glt->glformat = texinfo->glformat;
2225 glt->gltype = texinfo->gltype;
2226 glt->bytesperpixel = texinfo->internalbytesperpixel;
2228 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2229 glt->tilewidth = mipwidth;
2230 glt->tileheight = mipheight;
2232 glt->miplevels = dds_miplevels;
2234 // texture uploading can take a while, so make sure we're sending keepalives
2235 CL_KeepaliveMessage(false);
2237 // create the texture object
2238 switch(vid.renderpath)
2240 case RENDERPATH_GL11:
2241 case RENDERPATH_GL13:
2242 case RENDERPATH_GL20:
2243 case RENDERPATH_CGGL:
2245 GL_ActiveTexture(0);
2246 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2247 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2248 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2250 case RENDERPATH_D3D9:
2253 D3DFORMAT d3dformat;
2258 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2259 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2260 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2261 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2262 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2265 d3dpool = D3DPOOL_MANAGED;
2266 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2270 case RENDERPATH_D3D10:
2271 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2273 case RENDERPATH_D3D11:
2274 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2276 case RENDERPATH_SOFT:
2277 glt->texnum = DPSOFTRAST_Texture_New(((glt->flags & TEXF_CLAMP) ? DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE : 0) | (dds_miplevels > 1 ? DPSOFTRAST_TEXTURE_FLAG_MIPMAP : 0), glt->tilewidth, glt->tileheight, glt->tiledepth);
2281 // upload the texture
2282 // we need to restore the texture binding after finishing the upload
2283 mipcomplete = false;
2285 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2287 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2288 if (mippixels + mipsize > mippixels_start + mipsize_total)
2290 switch(vid.renderpath)
2292 case RENDERPATH_GL11:
2293 case RENDERPATH_GL13:
2294 case RENDERPATH_GL20:
2295 case RENDERPATH_CGGL:
2298 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2302 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2305 case RENDERPATH_D3D9:
2308 D3DLOCKED_RECT d3dlockedrect;
2309 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2311 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2312 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2318 case RENDERPATH_D3D10:
2319 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2321 case RENDERPATH_D3D11:
2322 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2324 case RENDERPATH_SOFT:
2326 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2328 DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
2329 // DPSOFTRAST calculates its own mipmaps
2330 mip = dds_miplevels;
2333 mippixels += mipsize;
2334 if (mipwidth <= 1 && mipheight <= 1)
2345 // after upload we have to set some parameters...
2346 switch(vid.renderpath)
2348 case RENDERPATH_GL11:
2349 case RENDERPATH_GL13:
2350 case RENDERPATH_GL20:
2351 case RENDERPATH_CGGL:
2352 if (dds_miplevels >= 1 && !mipcomplete)
2354 // need to set GL_TEXTURE_MAX_LEVEL
2355 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2357 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2358 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2360 case RENDERPATH_D3D9:
2362 glt->d3daddressw = 0;
2363 if (glt->flags & TEXF_CLAMP)
2365 glt->d3daddressu = D3DTADDRESS_CLAMP;
2366 glt->d3daddressv = D3DTADDRESS_CLAMP;
2367 if (glt->tiledepth > 1)
2368 glt->d3daddressw = D3DTADDRESS_CLAMP;
2372 glt->d3daddressu = D3DTADDRESS_WRAP;
2373 glt->d3daddressv = D3DTADDRESS_WRAP;
2374 if (glt->tiledepth > 1)
2375 glt->d3daddressw = D3DTADDRESS_WRAP;
2377 glt->d3dmipmaplodbias = 0;
2378 glt->d3dmaxmiplevel = 0;
2379 glt->d3dmaxmiplevelfilter = 0;
2380 if (glt->flags & TEXF_MIPMAP)
2382 glt->d3dminfilter = d3d_filter_mipmin;
2383 glt->d3dmagfilter = d3d_filter_mipmag;
2384 glt->d3dmipfilter = d3d_filter_mipmix;
2388 glt->d3dminfilter = d3d_filter_flatmin;
2389 glt->d3dmagfilter = d3d_filter_flatmag;
2390 glt->d3dmipfilter = d3d_filter_flatmix;
2394 case RENDERPATH_D3D10:
2395 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2397 case RENDERPATH_D3D11:
2398 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2400 case RENDERPATH_SOFT:
2401 if (glt->flags & TEXF_FORCELINEAR)
2402 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2403 else if (glt->flags & TEXF_FORCENEAREST)
2404 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2405 else if (glt->flags & TEXF_MIPMAP)
2406 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2408 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2414 Mem_Free((unsigned char *) mippixels_start);
2415 return (rtexture_t *)glt;
2418 int R_TextureWidth(rtexture_t *rt)
2420 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2423 int R_TextureHeight(rtexture_t *rt)
2425 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2428 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
2430 gltexture_t *glt = (gltexture_t *)rt;
2432 Host_Error("R_UpdateTexture: no data supplied");
2434 Host_Error("R_UpdateTexture: no texture supplied");
2435 if (!glt->texnum && !glt->d3dtexture)
2437 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2440 // update part of the texture
2441 if (glt->bufferpixels)
2444 int bpp = glt->bytesperpixel;
2445 int inputskip = width*bpp;
2446 int outputskip = glt->tilewidth*bpp;
2447 const unsigned char *input = data;
2448 unsigned char *output = glt->bufferpixels;
2458 input -= y*inputskip;
2461 if (width > glt->tilewidth - x)
2462 width = glt->tilewidth - x;
2463 if (height > glt->tileheight - y)
2464 height = glt->tileheight - y;
2465 if (width < 1 || height < 1)
2468 glt->buffermodified = true;
2469 output += y*outputskip + x*bpp;
2470 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2471 memcpy(output, input, width*bpp);
2473 else if (x || y || width != glt->inputwidth || height != glt->inputheight)
2474 R_UploadPartialTexture(glt, data, x, y, 0, width, height, 1);
2476 R_UploadFullTexture(glt, data);
2479 int R_RealGetTexture(rtexture_t *rt)
2484 glt = (gltexture_t *)rt;
2485 if (glt->flags & GLTEXF_DYNAMIC)
2486 R_UpdateDynamicTexture(glt);
2487 if (glt->buffermodified && glt->bufferpixels)
2489 glt->buffermodified = false;
2490 R_UploadFullTexture(glt, glt->bufferpixels);
2499 void R_ClearTexture (rtexture_t *rt)
2501 gltexture_t *glt = (gltexture_t *)rt;
2503 R_UploadFullTexture(glt, NULL);
2506 int R_PicmipForFlags(int flags)
2509 if(flags & TEXF_PICMIP)
2511 miplevel += gl_picmip.integer;
2512 if (flags & TEXF_ISWORLD)
2514 if (r_picmipworld.integer)
2515 miplevel += gl_picmip_world.integer;
2519 else if (flags & TEXF_ISSPRITE)
2521 if (r_picmipsprites.integer)
2522 miplevel += gl_picmip_sprites.integer;
2527 miplevel += gl_picmip_other.integer;
2529 return max(0, miplevel);