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", "0", "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 ambiguous, 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_LINEAR_MIPMAP_TRIANGLE;
43 DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_nomipmap = DPSOFTRAST_TEXTURE_FILTER_LINEAR;
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, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
79 static textypeinfo_t textype_palette_alpha = {TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
80 static textypeinfo_t textype_rgba = {TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
81 static textypeinfo_t textype_rgba_alpha = {TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , 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, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
85 static textypeinfo_t textype_bgra_alpha = {TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , 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, GL_RGBA , 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 R_Mesh_ClearBindingsForTexture(glt->texnum);
302 switch(vid.renderpath)
304 case RENDERPATH_GL11:
305 case RENDERPATH_GL13:
306 case RENDERPATH_GL20:
307 case RENDERPATH_GLES2:
311 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
314 case RENDERPATH_D3D9:
316 if (glt->d3disdepthsurface)
317 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
318 else if (glt->tiledepth > 1)
319 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
320 else if (glt->sides == 6)
321 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
323 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
324 glt->d3dtexture = NULL;
327 case RENDERPATH_D3D10:
328 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
330 case RENDERPATH_D3D11:
331 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
333 case RENDERPATH_SOFT:
335 DPSOFTRAST_Texture_Free(glt->texnum);
339 if (glt->inputtexels)
340 Mem_Free(glt->inputtexels);
341 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
344 rtexturepool_t *R_AllocTexturePool(void)
346 gltexturepool_t *pool;
347 if (texturemempool == NULL)
349 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
352 pool->next = gltexturepoolchain;
353 gltexturepoolchain = pool;
354 pool->sentinel = TEXTUREPOOL_SENTINEL;
355 return (rtexturepool_t *)pool;
358 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
360 gltexturepool_t *pool, **poolpointer;
361 if (rtexturepool == NULL)
363 if (*rtexturepool == NULL)
365 pool = (gltexturepool_t *)(*rtexturepool);
366 *rtexturepool = NULL;
367 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
368 Host_Error("R_FreeTexturePool: pool already freed");
369 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
370 if (*poolpointer == pool)
371 *poolpointer = pool->next;
373 Host_Error("R_FreeTexturePool: pool not linked");
374 while (pool->gltchain)
375 R_FreeTexture((rtexture_t *)pool->gltchain);
380 typedef struct glmode_s
383 int minification, magnification;
384 DPSOFTRAST_TEXTURE_FILTER dpsoftrastfilter_mipmap, dpsoftrastfilter_nomipmap;
388 static glmode_t modes[6] =
390 {"GL_NEAREST", GL_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
391 {"GL_LINEAR", GL_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
392 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
393 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
394 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
395 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR}
399 typedef struct d3dmode_s
406 static d3dmode_t d3dmodes[6] =
408 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
409 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
410 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
411 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
412 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
413 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
417 static void GL_TextureMode_f (void)
422 gltexturepool_t *pool;
426 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
427 for (i = 0;i < 6;i++)
429 if (gl_filter_min == modes[i].minification)
431 Con_Printf("%s\n", modes[i].name);
435 Con_Print("current filter is unknown???\n");
439 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
440 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
444 Con_Print("bad filter name\n");
448 gl_filter_min = modes[i].minification;
449 gl_filter_mag = modes[i].magnification;
450 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
452 dpsoftrast_filter_mipmap = modes[i].dpsoftrastfilter_mipmap;
453 dpsoftrast_filter_nomipmap = modes[i].dpsoftrastfilter_nomipmap;
455 switch(vid.renderpath)
457 case RENDERPATH_GL11:
458 case RENDERPATH_GL13:
459 case RENDERPATH_GL20:
460 case RENDERPATH_GLES2:
461 // change all the existing mipmap texture objects
462 // FIXME: force renderer(/client/something?) restart instead?
465 for (pool = gltexturepoolchain;pool;pool = pool->next)
467 for (glt = pool->gltchain;glt;glt = glt->chain)
469 // only update already uploaded images
470 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
472 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
473 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
474 if (glt->flags & TEXF_MIPMAP)
476 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
480 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
482 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
483 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
488 case RENDERPATH_D3D9:
490 d3d_filter_flatmin = d3dmodes[i].m1;
491 d3d_filter_flatmag = d3dmodes[i].m1;
492 d3d_filter_flatmix = D3DTEXF_POINT;
493 d3d_filter_mipmin = d3dmodes[i].m1;
494 d3d_filter_mipmag = d3dmodes[i].m1;
495 d3d_filter_mipmix = d3dmodes[i].m2;
496 d3d_filter_nomip = i < 2;
497 if (gl_texture_anisotropy.integer > 1 && i == 5)
498 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
499 for (pool = gltexturepoolchain;pool;pool = pool->next)
501 for (glt = pool->gltchain;glt;glt = glt->chain)
503 // only update already uploaded images
504 if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
506 if (glt->flags & TEXF_MIPMAP)
508 glt->d3dminfilter = d3d_filter_mipmin;
509 glt->d3dmagfilter = d3d_filter_mipmag;
510 glt->d3dmipfilter = d3d_filter_mipmix;
511 glt->d3dmaxmiplevelfilter = 0;
515 glt->d3dminfilter = d3d_filter_flatmin;
516 glt->d3dmagfilter = d3d_filter_flatmag;
517 glt->d3dmipfilter = d3d_filter_flatmix;
518 glt->d3dmaxmiplevelfilter = 0;
525 case RENDERPATH_D3D10:
526 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
528 case RENDERPATH_D3D11:
529 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
531 case RENDERPATH_SOFT:
532 // change all the existing texture objects
533 for (pool = gltexturepoolchain;pool;pool = pool->next)
534 for (glt = pool->gltchain;glt;glt = glt->chain)
535 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
536 DPSOFTRAST_Texture_Filter(glt->texnum, (glt->flags & TEXF_MIPMAP) ? dpsoftrast_filter_mipmap : dpsoftrast_filter_nomipmap);
541 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)
543 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
548 case GLTEXTURETYPE_2D:
549 maxsize = vid.maxtexturesize_2d;
550 if (flags & TEXF_PICMIP)
552 maxsize = bound(1, gl_max_size.integer, maxsize);
556 case GLTEXTURETYPE_3D:
557 maxsize = vid.maxtexturesize_3d;
559 case GLTEXTURETYPE_CUBEMAP:
560 maxsize = vid.maxtexturesize_cubemap;
564 if (vid.support.arb_texture_non_power_of_two)
566 width2 = min(inwidth >> picmip, maxsize);
567 height2 = min(inheight >> picmip, maxsize);
568 depth2 = min(indepth >> picmip, maxsize);
572 for (width2 = 1;width2 < inwidth;width2 <<= 1);
573 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
574 for (height2 = 1;height2 < inheight;height2 <<= 1);
575 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
576 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
577 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
580 switch(vid.renderpath)
582 case RENDERPATH_GL11:
583 case RENDERPATH_GL13:
584 case RENDERPATH_GL20:
585 case RENDERPATH_D3D10:
586 case RENDERPATH_D3D11:
587 case RENDERPATH_SOFT:
588 case RENDERPATH_GLES2:
590 case RENDERPATH_D3D9:
592 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
593 if (texturetype == GLTEXTURETYPE_2D)
595 width2 = max(width2, 2);
596 height2 = max(height2, 2);
603 if (flags & TEXF_MIPMAP)
605 int extent = max(width2, max(height2, depth2));
611 *outwidth = max(1, width2);
613 *outheight = max(1, height2);
615 *outdepth = max(1, depth2);
617 *outmiplevels = miplevels;
621 static int R_CalcTexelDataSize (gltexture_t *glt)
623 int width2, height2, depth2, size;
625 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
627 size = width2 * height2 * depth2;
629 if (glt->flags & TEXF_MIPMAP)
631 while (width2 > 1 || height2 > 1 || depth2 > 1)
639 size += width2 * height2 * depth2;
643 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
646 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
650 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
651 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
653 gltexturepool_t *pool;
655 Con_Print("glsize input loaded mip alpha name\n");
656 for (pool = gltexturepoolchain;pool;pool = pool->next)
664 for (glt = pool->gltchain;glt;glt = glt->chain)
666 glsize = R_CalcTexelDataSize(glt);
667 isloaded = glt->texnum != 0;
669 pooltotalt += glsize;
670 pooltotalp += glt->inputdatasize;
674 poolloadedt += glsize;
675 poolloadedp += glt->inputdatasize;
678 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);
681 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);
682 sumtotal += pooltotal;
683 sumtotalt += pooltotalt;
684 sumtotalp += pooltotalp;
685 sumloaded += poolloaded;
686 sumloadedt += poolloadedt;
687 sumloadedp += poolloadedp;
690 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);
693 static void R_TextureStats_f(void)
695 R_TextureStats_Print(true, true, true);
698 static void r_textures_start(void)
700 switch(vid.renderpath)
702 case RENDERPATH_GL11:
703 case RENDERPATH_GL13:
704 case RENDERPATH_GL20:
705 case RENDERPATH_GLES2:
706 // LordHavoc: allow any alignment
708 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
709 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
711 case RENDERPATH_D3D9:
713 case RENDERPATH_D3D10:
714 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
716 case RENDERPATH_D3D11:
717 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
719 case RENDERPATH_SOFT:
723 texturemempool = Mem_AllocPool("texture management", 0, NULL);
724 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
726 // Disable JPEG screenshots if the DLL isn't loaded
727 if (! JPEG_OpenLibrary ())
728 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
729 if (! PNG_OpenLibrary ())
730 Cvar_SetValueQuick (&scr_screenshot_png, 0);
733 static void r_textures_shutdown(void)
735 rtexturepool_t *temp;
737 JPEG_CloseLibrary ();
739 while(gltexturepoolchain)
741 temp = (rtexturepool_t *) gltexturepoolchain;
742 R_FreeTexturePool(&temp);
745 resizebuffersize = 0;
747 colorconvertbuffer = NULL;
748 texturebuffer = NULL;
749 Mem_ExpandableArray_FreeArray(&texturearray);
750 Mem_FreePool(&texturemempool);
753 static void r_textures_newmap(void)
757 static void r_textures_devicelost(void)
761 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
762 for (i = 0;i < endindex;i++)
764 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
765 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
767 switch(vid.renderpath)
769 case RENDERPATH_GL11:
770 case RENDERPATH_GL13:
771 case RENDERPATH_GL20:
772 case RENDERPATH_GLES2:
774 case RENDERPATH_D3D9:
776 if (glt->d3disdepthsurface)
777 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
778 else if (glt->tiledepth > 1)
779 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
780 else if (glt->sides == 6)
781 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
783 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
784 glt->d3dtexture = NULL;
787 case RENDERPATH_D3D10:
788 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
790 case RENDERPATH_D3D11:
791 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
793 case RENDERPATH_SOFT:
799 static void r_textures_devicerestored(void)
803 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
804 for (i = 0;i < endindex;i++)
806 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
807 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
809 switch(vid.renderpath)
811 case RENDERPATH_GL11:
812 case RENDERPATH_GL13:
813 case RENDERPATH_GL20:
814 case RENDERPATH_GLES2:
816 case RENDERPATH_D3D9:
820 if (glt->d3disdepthsurface)
822 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
823 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
825 else if (glt->tiledepth > 1)
827 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)))
828 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
830 else if (glt->sides == 6)
832 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
833 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
837 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)))
838 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
843 case RENDERPATH_D3D10:
844 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
846 case RENDERPATH_D3D11:
847 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
849 case RENDERPATH_SOFT:
856 void R_Textures_Init (void)
858 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");
859 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
860 Cvar_RegisterVariable (&gl_max_size);
861 Cvar_RegisterVariable (&gl_picmip);
862 Cvar_RegisterVariable (&gl_picmip_world);
863 Cvar_RegisterVariable (&r_picmipworld);
864 Cvar_RegisterVariable (&gl_picmip_sprites);
865 Cvar_RegisterVariable (&r_picmipsprites);
866 Cvar_RegisterVariable (&gl_picmip_other);
867 Cvar_RegisterVariable (&gl_max_lightmapsize);
868 Cvar_RegisterVariable (&r_lerpimages);
869 Cvar_RegisterVariable (&gl_texture_anisotropy);
870 Cvar_RegisterVariable (&gl_texturecompression);
871 Cvar_RegisterVariable (&gl_texturecompression_color);
872 Cvar_RegisterVariable (&gl_texturecompression_normal);
873 Cvar_RegisterVariable (&gl_texturecompression_gloss);
874 Cvar_RegisterVariable (&gl_texturecompression_glow);
875 Cvar_RegisterVariable (&gl_texturecompression_2d);
876 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
877 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
878 Cvar_RegisterVariable (&gl_texturecompression_sky);
879 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
880 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
881 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
882 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
883 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
884 Cvar_RegisterVariable (&r_texture_dds_swdecode);
886 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
889 void R_Textures_Frame (void)
891 static int old_aniso = 0;
893 // could do procedural texture animation here, if we keep track of which
894 // textures were accessed this frame...
896 // free the resize buffers
897 resizebuffersize = 0;
900 Mem_Free(resizebuffer);
903 if (colorconvertbuffer)
905 Mem_Free(colorconvertbuffer);
906 colorconvertbuffer = NULL;
909 if (old_aniso != gl_texture_anisotropy.integer)
912 gltexturepool_t *pool;
915 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
917 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
919 switch(vid.renderpath)
921 case RENDERPATH_GL11:
922 case RENDERPATH_GL13:
923 case RENDERPATH_GL20:
924 case RENDERPATH_GLES2:
927 for (pool = gltexturepoolchain;pool;pool = pool->next)
929 for (glt = pool->gltchain;glt;glt = glt->chain)
931 // only update already uploaded images
932 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
934 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
936 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
937 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
939 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
944 case RENDERPATH_D3D9:
945 case RENDERPATH_D3D10:
946 case RENDERPATH_D3D11:
947 case RENDERPATH_SOFT:
953 void R_MakeResizeBufferBigger(int size)
955 if (resizebuffersize < size)
957 resizebuffersize = size;
959 Mem_Free(resizebuffer);
960 if (colorconvertbuffer)
961 Mem_Free(colorconvertbuffer);
962 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
963 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
964 if (!resizebuffer || !colorconvertbuffer)
965 Host_Error("R_Upload: out of memory");
969 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
971 int textureenum = gltexturetypeenums[texturetype];
972 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
976 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
978 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
979 if (gl_texture_anisotropy.integer != aniso)
980 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
981 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
983 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
984 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
985 if (gltexturetypedimensions[texturetype] >= 3)
987 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
991 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
993 if (flags & TEXF_MIPMAP)
995 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
999 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
1001 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
1003 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
1005 if (flags & TEXF_MIPMAP)
1007 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
1009 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
1013 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
1018 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
1020 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
1024 if (flags & TEXF_MIPMAP)
1026 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1030 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1032 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1035 if (textype == TEXTYPE_SHADOWMAP)
1037 if (vid.support.arb_shadow)
1039 if (flags & TEXF_COMPARE)
1041 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1045 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1047 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1049 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1055 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1058 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1060 if (glt->texturetype != GLTEXTURETYPE_2D)
1061 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1063 if (glt->textype->textype == TEXTYPE_PALETTE)
1064 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1066 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1067 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1069 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1070 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1072 // update a portion of the image
1074 switch(vid.renderpath)
1076 case RENDERPATH_GL11:
1077 case RENDERPATH_GL13:
1078 case RENDERPATH_GL20:
1079 case RENDERPATH_GLES2:
1083 // we need to restore the texture binding after finishing the upload
1084 GL_ActiveTexture(0);
1085 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1086 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1087 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1088 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1091 case RENDERPATH_D3D9:
1095 D3DLOCKED_RECT d3dlockedrect;
1097 memset(&d3drect, 0, sizeof(d3drect));
1098 d3drect.left = fragx;
1099 d3drect.top = fragy;
1100 d3drect.right = fragx+fragwidth;
1101 d3drect.bottom = fragy+fragheight;
1102 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1104 for (y = 0;y < fragheight;y++)
1105 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1106 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1111 case RENDERPATH_D3D10:
1112 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1114 case RENDERPATH_D3D11:
1115 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1117 case RENDERPATH_SOFT:
1118 DPSOFTRAST_Texture_UpdatePartial(glt->texnum, 0, data, fragx, fragy, fragwidth, fragheight);
1123 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1125 int i, mip = 0, width, height, depth;
1126 GLint oldbindtexnum = 0;
1127 const unsigned char *prevbuffer;
1130 // error out if a stretch is needed on special texture types
1131 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1132 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1134 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1135 // of the target size and then use the mipmap reduction function to get
1136 // high quality supersampled results
1137 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1138 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1139 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1140 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1142 if (prevbuffer == NULL)
1144 width = glt->tilewidth;
1145 height = glt->tileheight;
1146 depth = glt->tiledepth;
1147 memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1148 prevbuffer = resizebuffer;
1150 else if (glt->textype->textype == TEXTYPE_PALETTE)
1152 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1153 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1154 prevbuffer = colorconvertbuffer;
1157 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1159 // multiply RGB channels by A channel before uploading
1161 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1163 alpha = prevbuffer[i+3];
1164 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1165 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1166 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1167 colorconvertbuffer[i+3] = alpha;
1169 prevbuffer = colorconvertbuffer;
1172 // scale up to a power of 2 size (if appropriate)
1173 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1175 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1176 prevbuffer = resizebuffer;
1178 // apply mipmap reduction algorithm to get down to picmip/max_size
1179 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1181 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1182 prevbuffer = resizebuffer;
1185 // do the appropriate upload type...
1186 switch(vid.renderpath)
1188 case RENDERPATH_GL11:
1189 case RENDERPATH_GL13:
1190 case RENDERPATH_GL20:
1191 case RENDERPATH_GLES2:
1194 // we need to restore the texture binding after finishing the upload
1195 GL_ActiveTexture(0);
1196 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1197 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1199 if (qglGetCompressedTexImageARB)
1201 if (gl_texturecompression.integer >= 2)
1202 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1204 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1207 switch(glt->texturetype)
1209 case GLTEXTURETYPE_2D:
1210 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1211 if (glt->flags & TEXF_MIPMAP)
1213 while (width > 1 || height > 1 || depth > 1)
1215 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1216 prevbuffer = resizebuffer;
1217 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1221 case GLTEXTURETYPE_3D:
1222 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1223 if (glt->flags & TEXF_MIPMAP)
1225 while (width > 1 || height > 1 || depth > 1)
1227 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1228 prevbuffer = resizebuffer;
1229 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1233 case GLTEXTURETYPE_CUBEMAP:
1234 // convert and upload each side in turn,
1235 // from a continuous block of input texels
1236 texturebuffer = (unsigned char *)prevbuffer;
1237 for (i = 0;i < 6;i++)
1239 prevbuffer = texturebuffer;
1240 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1241 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1243 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1244 prevbuffer = resizebuffer;
1247 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1249 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1250 prevbuffer = resizebuffer;
1253 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1254 if (glt->flags & TEXF_MIPMAP)
1256 while (width > 1 || height > 1 || depth > 1)
1258 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1259 prevbuffer = resizebuffer;
1260 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1266 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1267 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1269 case RENDERPATH_D3D9:
1271 if (!(glt->flags & TEXF_RENDERTARGET))
1273 D3DLOCKED_RECT d3dlockedrect;
1274 D3DLOCKED_BOX d3dlockedbox;
1275 switch(glt->texturetype)
1277 case GLTEXTURETYPE_2D:
1278 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1281 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1283 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1284 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1287 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1289 while (width > 1 || height > 1 || depth > 1)
1291 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1292 prevbuffer = resizebuffer;
1293 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1295 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1296 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1302 case GLTEXTURETYPE_3D:
1303 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1305 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1306 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1307 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1310 if (glt->flags & TEXF_MIPMAP)
1312 while (width > 1 || height > 1 || depth > 1)
1314 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1315 prevbuffer = resizebuffer;
1316 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1318 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1319 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1320 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1326 case GLTEXTURETYPE_CUBEMAP:
1327 // convert and upload each side in turn,
1328 // from a continuous block of input texels
1329 texturebuffer = (unsigned char *)prevbuffer;
1330 for (i = 0;i < 6;i++)
1332 prevbuffer = texturebuffer;
1333 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1334 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1336 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1337 prevbuffer = resizebuffer;
1340 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1342 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1343 prevbuffer = resizebuffer;
1346 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1348 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1349 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1352 if (glt->flags & TEXF_MIPMAP)
1354 while (width > 1 || height > 1 || depth > 1)
1356 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1357 prevbuffer = resizebuffer;
1358 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1360 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1361 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1370 glt->d3daddressw = 0;
1371 if (glt->flags & TEXF_CLAMP)
1373 glt->d3daddressu = D3DTADDRESS_CLAMP;
1374 glt->d3daddressv = D3DTADDRESS_CLAMP;
1375 if (glt->tiledepth > 1)
1376 glt->d3daddressw = D3DTADDRESS_CLAMP;
1380 glt->d3daddressu = D3DTADDRESS_WRAP;
1381 glt->d3daddressv = D3DTADDRESS_WRAP;
1382 if (glt->tiledepth > 1)
1383 glt->d3daddressw = D3DTADDRESS_WRAP;
1385 glt->d3dmipmaplodbias = 0;
1386 glt->d3dmaxmiplevel = 0;
1387 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1388 if (glt->flags & TEXF_FORCELINEAR)
1390 glt->d3dminfilter = D3DTEXF_LINEAR;
1391 glt->d3dmagfilter = D3DTEXF_LINEAR;
1392 glt->d3dmipfilter = D3DTEXF_POINT;
1394 else if (glt->flags & TEXF_FORCENEAREST)
1396 glt->d3dminfilter = D3DTEXF_POINT;
1397 glt->d3dmagfilter = D3DTEXF_POINT;
1398 glt->d3dmipfilter = D3DTEXF_POINT;
1400 else if (glt->flags & TEXF_MIPMAP)
1402 glt->d3dminfilter = d3d_filter_mipmin;
1403 glt->d3dmagfilter = d3d_filter_mipmag;
1404 glt->d3dmipfilter = d3d_filter_mipmix;
1408 glt->d3dminfilter = d3d_filter_flatmin;
1409 glt->d3dmagfilter = d3d_filter_flatmag;
1410 glt->d3dmipfilter = d3d_filter_flatmix;
1414 case RENDERPATH_D3D10:
1415 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1417 case RENDERPATH_D3D11:
1418 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1420 case RENDERPATH_SOFT:
1421 switch(glt->texturetype)
1423 case GLTEXTURETYPE_2D:
1424 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1426 case GLTEXTURETYPE_3D:
1427 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1429 case GLTEXTURETYPE_CUBEMAP:
1430 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1432 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1433 // convert and upload each side in turn,
1434 // from a continuous block of input texels
1435 // copy the results into combinedbuffer
1436 texturebuffer = (unsigned char *)prevbuffer;
1437 for (i = 0;i < 6;i++)
1439 prevbuffer = texturebuffer;
1440 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1441 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1443 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1444 prevbuffer = resizebuffer;
1447 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1449 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1450 prevbuffer = resizebuffer;
1452 memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1454 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1455 Mem_Free(combinedbuffer);
1458 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1461 if (glt->flags & TEXF_FORCELINEAR)
1462 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1463 else if (glt->flags & TEXF_FORCENEAREST)
1464 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1465 else if (glt->flags & TEXF_MIPMAP)
1466 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1468 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1473 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)
1477 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1478 textypeinfo_t *texinfo, *texinfo2;
1479 unsigned char *temppixels = NULL;
1481 if (cls.state == ca_dedicated)
1484 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1486 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1489 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1491 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1495 texinfo = R_GetTexTypeInfo(textype, flags);
1496 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1499 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1503 if (textype == TEXTYPE_RGBA)
1506 static int rgbaswapindices[4] = {2, 1, 0, 3};
1507 textype = TEXTYPE_BGRA;
1508 texinfo = R_GetTexTypeInfo(textype, flags);
1509 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1510 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1514 // clear the alpha flag if the texture has no transparent pixels
1517 case TEXTYPE_PALETTE:
1518 if (flags & TEXF_ALPHA)
1520 flags &= ~TEXF_ALPHA;
1523 for (i = 0;i < size;i++)
1525 if (((unsigned char *)&palette[data[i]])[3] < 255)
1527 flags |= TEXF_ALPHA;
1536 if (flags & TEXF_ALPHA)
1538 flags &= ~TEXF_ALPHA;
1541 for (i = 3;i < size;i += 4)
1545 flags |= TEXF_ALPHA;
1552 case TEXTYPE_SHADOWMAP:
1559 flags |= TEXF_ALPHA;
1562 flags |= TEXF_ALPHA;
1564 case TEXTYPE_COLORBUFFER:
1565 flags |= TEXF_ALPHA;
1568 Sys_Error("R_LoadTexture: unknown texture type");
1571 texinfo2 = R_GetTexTypeInfo(textype, flags);
1572 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1575 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1577 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1579 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1581 glt->chain = pool->gltchain;
1582 pool->gltchain = glt;
1583 glt->inputwidth = width;
1584 glt->inputheight = height;
1585 glt->inputdepth = depth;
1587 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
1588 glt->textype = texinfo;
1589 glt->texturetype = texturetype;
1590 glt->inputdatasize = size;
1591 glt->palette = palette;
1592 glt->glinternalformat = texinfo->glinternalformat;
1593 glt->glformat = texinfo->glformat;
1594 glt->gltype = texinfo->gltype;
1595 glt->bytesperpixel = texinfo->internalbytesperpixel;
1596 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1599 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1600 // init the dynamic texture attributes, too [11/22/2007 Black]
1601 glt->updatecallback = NULL;
1602 glt->updatacallback_data = NULL;
1604 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1606 // upload the texture
1607 // data may be NULL (blank texture for dynamic rendering)
1608 switch(vid.renderpath)
1610 case RENDERPATH_GL11:
1611 case RENDERPATH_GL13:
1612 case RENDERPATH_GL20:
1613 case RENDERPATH_GLES2:
1615 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1617 case RENDERPATH_D3D9:
1620 D3DFORMAT d3dformat;
1625 d3dpool = D3DPOOL_MANAGED;
1626 if (flags & TEXF_RENDERTARGET)
1628 d3dusage |= D3DUSAGE_RENDERTARGET;
1629 d3dpool = D3DPOOL_DEFAULT;
1633 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1634 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1635 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1636 case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1637 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1638 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1639 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1641 glt->d3dformat = d3dformat;
1642 glt->d3dusage = d3dusage;
1643 glt->d3dpool = d3dpool;
1644 glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1645 if (glt->d3disdepthsurface)
1647 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1648 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1650 else if (glt->tiledepth > 1)
1652 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)))
1653 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1655 else if (glt->sides == 6)
1657 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1658 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1662 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)))
1663 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1668 case RENDERPATH_D3D10:
1669 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1671 case RENDERPATH_D3D11:
1672 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1674 case RENDERPATH_SOFT:
1679 case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1680 case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1681 case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1682 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1683 case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1684 case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1685 default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1687 if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1688 if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1689 if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1690 if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1691 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1696 R_UploadFullTexture(glt, data);
1697 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1698 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1700 // free any temporary processing buffer we allocated...
1702 Mem_Free(temppixels);
1704 // texture converting and uploading can take a while, so make sure we're sending keepalives
1705 // FIXME: this causes rendering during R_Shadow_DrawLights
1706 // CL_KeepaliveMessage(false);
1708 return (rtexture_t *)glt;
1711 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)
1713 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1716 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)
1718 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1721 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)
1723 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1726 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1728 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1730 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1732 flags |= TEXF_FORCENEAREST;
1733 if (precision <= 16)
1734 flags |= TEXF_LOWPRECISION;
1738 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1740 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1743 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1745 gltexture_t *glt = (gltexture_t *)rt;
1748 int bytesperpixel = 0;
1749 int bytesperblock = 0;
1751 int dds_format_flags;
1759 GLint internalformat;
1760 const char *ddsfourcc;
1762 return -1; // NULL pointer
1763 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1764 return -2; // broken driver - crashes on reading internal format
1765 if (!qglGetTexLevelParameteriv)
1767 GL_ActiveTexture(0);
1768 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1769 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1770 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1771 switch(internalformat)
1773 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1774 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1775 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1776 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1777 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1779 // if premultiplied alpha, say so in the DDS file
1780 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1782 switch(internalformat)
1784 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1785 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1788 if (!bytesperblock && skipuncompressed)
1789 return -3; // skipped
1790 memset(mipinfo, 0, sizeof(mipinfo));
1791 mipinfo[0][0] = glt->tilewidth;
1792 mipinfo[0][1] = glt->tileheight;
1794 if (glt->flags & TEXF_MIPMAP)
1796 for (mip = 1;mip < 16;mip++)
1798 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1799 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1800 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1808 for (mip = 0;mip < mipmaps;mip++)
1810 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1811 mipinfo[mip][3] = ddssize;
1812 ddssize += mipinfo[mip][2];
1814 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1817 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1821 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1822 dds_format_flags = 0x4; // DDPF_FOURCC
1826 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1827 dds_format_flags = 0x40; // DDPF_RGB
1831 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1832 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1835 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1836 memcpy(dds, "DDS ", 4);
1837 StoreLittleLong(dds+4, ddssize);
1838 StoreLittleLong(dds+8, dds_flags);
1839 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1840 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1841 StoreLittleLong(dds+24, 1); // depth
1842 StoreLittleLong(dds+28, mipmaps); // mipmaps
1843 StoreLittleLong(dds+76, 32); // format size
1844 StoreLittleLong(dds+80, dds_format_flags);
1845 StoreLittleLong(dds+108, dds_caps1);
1846 StoreLittleLong(dds+112, dds_caps2);
1849 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1850 memcpy(dds+84, ddsfourcc, 4);
1851 for (mip = 0;mip < mipmaps;mip++)
1853 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1858 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1859 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1860 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1861 for (mip = 0;mip < mipmaps;mip++)
1863 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1866 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1867 ret = FS_WriteFile(filename, dds, ddssize);
1869 return ret ? ddssize : -5;
1872 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
1874 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1877 int bytesperblock, bytesperpixel;
1880 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1881 textypeinfo_t *texinfo;
1882 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1884 GLint oldbindtexnum = 0;
1885 const unsigned char *mippixels, *ddspixels, *mippixels_start;
1887 fs_offset_t ddsfilesize;
1888 unsigned int ddssize;
1889 qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
1891 if (cls.state == ca_dedicated)
1894 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1895 ddssize = ddsfilesize;
1899 if(r_texture_dds_load_logfailure.integer)
1900 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1901 return NULL; // not found
1904 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1907 Con_Printf("^1%s: not a DDS image\n", filename);
1911 //dds_flags = BuffLittleLong(dds+8);
1912 dds_format_flags = BuffLittleLong(dds+80);
1913 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1914 dds_width = BuffLittleLong(dds+16);
1915 dds_height = BuffLittleLong(dds+12);
1916 ddspixels = dds + 128;
1918 if(r_texture_dds_load_alphamode.integer == 0)
1919 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1920 flags &= ~TEXF_ALPHA;
1922 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1923 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1925 // very sloppy BGRA 32bit identification
1926 textype = TEXTYPE_BGRA;
1929 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1930 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1933 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1936 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1939 for (i = 3;i < size;i += 4)
1940 if (ddspixels[i] < 255)
1943 flags &= ~TEXF_ALPHA;
1946 else if (!memcmp(dds+84, "DXT1", 4))
1948 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1949 // LordHavoc: it is my belief that this does not infringe on the
1950 // patent because it is not decoding pixels...
1951 textype = TEXTYPE_DXT1;
1954 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1955 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1956 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1959 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1962 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1964 if(r_texture_dds_load_alphamode.integer == 1)
1967 for (i = 0;i < size;i += bytesperblock)
1968 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1970 // NOTE: this assumes sizeof(unsigned int) == 4
1971 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1972 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1973 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1977 textype = TEXTYPE_DXT1A;
1979 flags &= ~TEXF_ALPHA;
1983 flags &= ~TEXF_ALPHA;
1987 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
1989 if(!memcmp(dds+84, "DXT2", 4))
1991 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1993 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
1998 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2000 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2003 textype = TEXTYPE_DXT3;
2006 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2007 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2010 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2013 // we currently always assume alpha
2015 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2017 if(!memcmp(dds+84, "DXT4", 4))
2019 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2021 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2026 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2028 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2031 textype = TEXTYPE_DXT5;
2034 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2035 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2038 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2041 // we currently always assume alpha
2046 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2050 force_swdecode = false;
2053 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
2055 if(r_texture_dds_swdecode.integer > 1)
2056 force_swdecode = true;
2060 if(r_texture_dds_swdecode.integer < 1)
2066 force_swdecode = true;
2070 // return whether this texture is transparent
2072 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2074 // if we SW decode, choose 2 sizes bigger
2077 // this is quarter res, so do not scale down more than we have to
2081 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2084 // this is where we apply gl_picmip
2085 mippixels_start = ddspixels;
2086 mipwidth = dds_width;
2087 mipheight = dds_height;
2088 while(miplevel >= 1 && dds_miplevels >= 1)
2090 if (mipwidth <= 1 && mipheight <= 1)
2092 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2093 mippixels_start += mipsize; // just skip
2101 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2102 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2104 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2106 // fake decode S3TC if needed
2109 int mipsize_new = mipsize_total / bytesperblock * 4;
2110 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2111 unsigned char *p = mipnewpixels;
2112 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2114 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2115 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2116 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2117 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2118 if(textype == TEXTYPE_DXT5)
2119 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2120 else if(textype == TEXTYPE_DXT3)
2122 (mippixels_start[i-8] & 0x0F)
2123 + (mippixels_start[i-8] >> 4)
2124 + (mippixels_start[i-7] & 0x0F)
2125 + (mippixels_start[i-7] >> 4)
2126 + (mippixels_start[i-6] & 0x0F)
2127 + (mippixels_start[i-6] >> 4)
2128 + (mippixels_start[i-5] & 0x0F)
2129 + (mippixels_start[i-5] >> 4)
2130 ) * (0.125f / 15.0f * 255.0f);
2135 textype = TEXTYPE_BGRA;
2139 // as each block becomes a pixel, we must use pixel count for this
2140 mipwidth = (mipwidth + 3) / 4;
2141 mipheight = (mipheight + 3) / 4;
2142 mipsize = bytesperpixel * mipwidth * mipheight;
2143 mippixels_start = mipnewpixels;
2144 mipsize_total = mipsize_new;
2147 // start mip counting
2148 mippixels = mippixels_start;
2150 // calculate average color if requested
2154 Vector4Clear(avgcolor);
2157 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2159 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2160 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2161 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2162 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2163 if(textype == TEXTYPE_DXT5)
2164 avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2165 else if(textype == TEXTYPE_DXT3)
2167 (mippixels_start[i-8] & 0x0F)
2168 + (mippixels_start[i-8] >> 4)
2169 + (mippixels_start[i-7] & 0x0F)
2170 + (mippixels_start[i-7] >> 4)
2171 + (mippixels_start[i-6] & 0x0F)
2172 + (mippixels_start[i-6] >> 4)
2173 + (mippixels_start[i-5] & 0x0F)
2174 + (mippixels_start[i-5] >> 4)
2175 ) * (0.125f / 15.0f * 255.0f);
2179 f = (float)bytesperblock / size;
2180 avgcolor[0] *= (0.5f / 31.0f) * f;
2181 avgcolor[1] *= (0.5f / 63.0f) * f;
2182 avgcolor[2] *= (0.5f / 31.0f) * f;
2187 for (i = 0;i < mipsize;i += 4)
2189 avgcolor[0] += mippixels[i+2];
2190 avgcolor[1] += mippixels[i+1];
2191 avgcolor[2] += mippixels[i];
2192 avgcolor[3] += mippixels[i+3];
2194 f = (1.0f / 255.0f) * bytesperpixel / size;
2202 // when not requesting mipmaps, do not load them
2203 if(!(flags & TEXF_MIPMAP))
2206 if (dds_miplevels >= 1)
2207 flags |= TEXF_MIPMAP;
2209 flags &= ~TEXF_MIPMAP;
2211 texinfo = R_GetTexTypeInfo(textype, flags);
2213 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2214 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2216 glt->chain = pool->gltchain;
2217 pool->gltchain = glt;
2218 glt->inputwidth = mipwidth;
2219 glt->inputheight = mipheight;
2220 glt->inputdepth = 1;
2222 glt->textype = texinfo;
2223 glt->texturetype = GLTEXTURETYPE_2D;
2224 glt->inputdatasize = ddssize;
2225 glt->glinternalformat = texinfo->glinternalformat;
2226 glt->glformat = texinfo->glformat;
2227 glt->gltype = texinfo->gltype;
2228 glt->bytesperpixel = texinfo->internalbytesperpixel;
2230 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2231 glt->tilewidth = mipwidth;
2232 glt->tileheight = mipheight;
2234 glt->miplevels = dds_miplevels;
2236 // texture uploading can take a while, so make sure we're sending keepalives
2237 CL_KeepaliveMessage(false);
2239 // create the texture object
2240 switch(vid.renderpath)
2242 case RENDERPATH_GL11:
2243 case RENDERPATH_GL13:
2244 case RENDERPATH_GL20:
2245 case RENDERPATH_GLES2:
2247 GL_ActiveTexture(0);
2248 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2249 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2250 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2252 case RENDERPATH_D3D9:
2255 D3DFORMAT d3dformat;
2260 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2261 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2262 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2263 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2264 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2267 d3dpool = D3DPOOL_MANAGED;
2268 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2272 case RENDERPATH_D3D10:
2273 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2275 case RENDERPATH_D3D11:
2276 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2278 case RENDERPATH_SOFT:
2279 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);
2283 // upload the texture
2284 // we need to restore the texture binding after finishing the upload
2285 mipcomplete = false;
2287 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2289 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2290 if (mippixels + mipsize > mippixels_start + mipsize_total)
2292 switch(vid.renderpath)
2294 case RENDERPATH_GL11:
2295 case RENDERPATH_GL13:
2296 case RENDERPATH_GL20:
2297 case RENDERPATH_GLES2:
2300 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2304 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2307 case RENDERPATH_D3D9:
2310 D3DLOCKED_RECT d3dlockedrect;
2311 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2313 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2314 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2320 case RENDERPATH_D3D10:
2321 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2323 case RENDERPATH_D3D11:
2324 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2326 case RENDERPATH_SOFT:
2328 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2330 DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
2331 // DPSOFTRAST calculates its own mipmaps
2332 mip = dds_miplevels;
2335 mippixels += mipsize;
2336 if (mipwidth <= 1 && mipheight <= 1)
2347 // after upload we have to set some parameters...
2348 switch(vid.renderpath)
2350 case RENDERPATH_GL11:
2351 case RENDERPATH_GL13:
2352 case RENDERPATH_GL20:
2353 case RENDERPATH_GLES2:
2354 if (dds_miplevels >= 1 && !mipcomplete)
2356 // need to set GL_TEXTURE_MAX_LEVEL
2357 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2359 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2360 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2362 case RENDERPATH_D3D9:
2364 glt->d3daddressw = 0;
2365 if (glt->flags & TEXF_CLAMP)
2367 glt->d3daddressu = D3DTADDRESS_CLAMP;
2368 glt->d3daddressv = D3DTADDRESS_CLAMP;
2369 if (glt->tiledepth > 1)
2370 glt->d3daddressw = D3DTADDRESS_CLAMP;
2374 glt->d3daddressu = D3DTADDRESS_WRAP;
2375 glt->d3daddressv = D3DTADDRESS_WRAP;
2376 if (glt->tiledepth > 1)
2377 glt->d3daddressw = D3DTADDRESS_WRAP;
2379 glt->d3dmipmaplodbias = 0;
2380 glt->d3dmaxmiplevel = 0;
2381 glt->d3dmaxmiplevelfilter = 0;
2382 if (glt->flags & TEXF_MIPMAP)
2384 glt->d3dminfilter = d3d_filter_mipmin;
2385 glt->d3dmagfilter = d3d_filter_mipmag;
2386 glt->d3dmipfilter = d3d_filter_mipmix;
2390 glt->d3dminfilter = d3d_filter_flatmin;
2391 glt->d3dmagfilter = d3d_filter_flatmag;
2392 glt->d3dmipfilter = d3d_filter_flatmix;
2396 case RENDERPATH_D3D10:
2397 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2399 case RENDERPATH_D3D11:
2400 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2402 case RENDERPATH_SOFT:
2403 if (glt->flags & TEXF_FORCELINEAR)
2404 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2405 else if (glt->flags & TEXF_FORCENEAREST)
2406 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2407 else if (glt->flags & TEXF_MIPMAP)
2408 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2410 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2416 Mem_Free((unsigned char *) mippixels_start);
2417 return (rtexture_t *)glt;
2420 int R_TextureWidth(rtexture_t *rt)
2422 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2425 int R_TextureHeight(rtexture_t *rt)
2427 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2430 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2432 gltexture_t *glt = (gltexture_t *)rt;
2434 Host_Error("R_UpdateTexture: no data supplied");
2436 Host_Error("R_UpdateTexture: no texture supplied");
2437 if (!glt->texnum && !glt->d3dtexture)
2439 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2442 // update part of the texture
2443 if (glt->bufferpixels)
2446 int bpp = glt->bytesperpixel;
2447 int inputskip = width*bpp;
2448 int outputskip = glt->tilewidth*bpp;
2449 const unsigned char *input = data;
2450 unsigned char *output = glt->bufferpixels;
2451 if (glt->inputdepth != 1 || glt->sides != 1)
2452 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2462 input -= y*inputskip;
2465 if (width > glt->tilewidth - x)
2466 width = glt->tilewidth - x;
2467 if (height > glt->tileheight - y)
2468 height = glt->tileheight - y;
2469 if (width < 1 || height < 1)
2472 glt->buffermodified = true;
2473 output += y*outputskip + x*bpp;
2474 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2475 memcpy(output, input, width*bpp);
2477 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2478 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2480 R_UploadFullTexture(glt, data);
2483 int R_RealGetTexture(rtexture_t *rt)
2488 glt = (gltexture_t *)rt;
2489 if (glt->flags & GLTEXF_DYNAMIC)
2490 R_UpdateDynamicTexture(glt);
2491 if (glt->buffermodified && glt->bufferpixels)
2493 glt->buffermodified = false;
2494 R_UploadFullTexture(glt, glt->bufferpixels);
2503 void R_ClearTexture (rtexture_t *rt)
2505 gltexture_t *glt = (gltexture_t *)rt;
2507 R_UploadFullTexture(glt, NULL);
2510 int R_PicmipForFlags(int flags)
2513 if(flags & TEXF_PICMIP)
2515 miplevel += gl_picmip.integer;
2516 if (flags & TEXF_ISWORLD)
2518 if (r_picmipworld.integer)
2519 miplevel += gl_picmip_world.integer;
2523 else if (flags & TEXF_ISSPRITE)
2525 if (r_picmipsprites.integer)
2526 miplevel += gl_picmip_sprites.integer;
2531 miplevel += gl_picmip_other.integer;
2533 return max(0, miplevel);