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;
1152 if (glt->textype->textype == TEXTYPE_PALETTE)
1154 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1155 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1156 prevbuffer = colorconvertbuffer;
1158 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1160 // multiply RGB channels by A channel before uploading
1162 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1164 alpha = prevbuffer[i+3];
1165 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1166 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1167 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1168 colorconvertbuffer[i+3] = alpha;
1170 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;
1186 // do the appropriate upload type...
1187 switch(vid.renderpath)
1189 case RENDERPATH_GL11:
1190 case RENDERPATH_GL13:
1191 case RENDERPATH_GL20:
1192 case RENDERPATH_GLES2:
1195 // we need to restore the texture binding after finishing the upload
1196 GL_ActiveTexture(0);
1197 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1198 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1200 if (qglGetCompressedTexImageARB)
1202 if (gl_texturecompression.integer >= 2)
1203 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1205 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1208 switch(glt->texturetype)
1210 case GLTEXTURETYPE_2D:
1211 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1212 if (glt->flags & TEXF_MIPMAP)
1214 while (width > 1 || height > 1 || depth > 1)
1216 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1217 prevbuffer = resizebuffer;
1218 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1222 case GLTEXTURETYPE_3D:
1223 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1224 if (glt->flags & TEXF_MIPMAP)
1226 while (width > 1 || height > 1 || depth > 1)
1228 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1229 prevbuffer = resizebuffer;
1230 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1234 case GLTEXTURETYPE_CUBEMAP:
1235 // convert and upload each side in turn,
1236 // from a continuous block of input texels
1237 texturebuffer = (unsigned char *)prevbuffer;
1238 for (i = 0;i < 6;i++)
1240 prevbuffer = texturebuffer;
1241 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1242 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1244 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1245 prevbuffer = resizebuffer;
1248 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1250 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1251 prevbuffer = resizebuffer;
1254 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1255 if (glt->flags & TEXF_MIPMAP)
1257 while (width > 1 || height > 1 || depth > 1)
1259 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1260 prevbuffer = resizebuffer;
1261 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1267 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1268 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1270 case RENDERPATH_D3D9:
1272 if (!(glt->flags & TEXF_RENDERTARGET))
1274 D3DLOCKED_RECT d3dlockedrect;
1275 D3DLOCKED_BOX d3dlockedbox;
1276 switch(glt->texturetype)
1278 case GLTEXTURETYPE_2D:
1279 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1282 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1284 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1285 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1288 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1290 while (width > 1 || height > 1 || depth > 1)
1292 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1293 prevbuffer = resizebuffer;
1294 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1296 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1297 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1303 case GLTEXTURETYPE_3D:
1304 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1306 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1307 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1308 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1311 if (glt->flags & TEXF_MIPMAP)
1313 while (width > 1 || height > 1 || depth > 1)
1315 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1316 prevbuffer = resizebuffer;
1317 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1319 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1320 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1321 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1327 case GLTEXTURETYPE_CUBEMAP:
1328 // convert and upload each side in turn,
1329 // from a continuous block of input texels
1330 texturebuffer = (unsigned char *)prevbuffer;
1331 for (i = 0;i < 6;i++)
1333 prevbuffer = texturebuffer;
1334 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1335 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1337 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1338 prevbuffer = resizebuffer;
1341 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1343 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1344 prevbuffer = resizebuffer;
1347 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1349 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1350 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1353 if (glt->flags & TEXF_MIPMAP)
1355 while (width > 1 || height > 1 || depth > 1)
1357 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1358 prevbuffer = resizebuffer;
1359 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1361 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1362 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1371 glt->d3daddressw = 0;
1372 if (glt->flags & TEXF_CLAMP)
1374 glt->d3daddressu = D3DTADDRESS_CLAMP;
1375 glt->d3daddressv = D3DTADDRESS_CLAMP;
1376 if (glt->tiledepth > 1)
1377 glt->d3daddressw = D3DTADDRESS_CLAMP;
1381 glt->d3daddressu = D3DTADDRESS_WRAP;
1382 glt->d3daddressv = D3DTADDRESS_WRAP;
1383 if (glt->tiledepth > 1)
1384 glt->d3daddressw = D3DTADDRESS_WRAP;
1386 glt->d3dmipmaplodbias = 0;
1387 glt->d3dmaxmiplevel = 0;
1388 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1389 if (glt->flags & TEXF_FORCELINEAR)
1391 glt->d3dminfilter = D3DTEXF_LINEAR;
1392 glt->d3dmagfilter = D3DTEXF_LINEAR;
1393 glt->d3dmipfilter = D3DTEXF_POINT;
1395 else if (glt->flags & TEXF_FORCENEAREST)
1397 glt->d3dminfilter = D3DTEXF_POINT;
1398 glt->d3dmagfilter = D3DTEXF_POINT;
1399 glt->d3dmipfilter = D3DTEXF_POINT;
1401 else if (glt->flags & TEXF_MIPMAP)
1403 glt->d3dminfilter = d3d_filter_mipmin;
1404 glt->d3dmagfilter = d3d_filter_mipmag;
1405 glt->d3dmipfilter = d3d_filter_mipmix;
1409 glt->d3dminfilter = d3d_filter_flatmin;
1410 glt->d3dmagfilter = d3d_filter_flatmag;
1411 glt->d3dmipfilter = d3d_filter_flatmix;
1415 case RENDERPATH_D3D10:
1416 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1418 case RENDERPATH_D3D11:
1419 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1421 case RENDERPATH_SOFT:
1422 switch(glt->texturetype)
1424 case GLTEXTURETYPE_2D:
1425 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1427 case GLTEXTURETYPE_3D:
1428 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1430 case GLTEXTURETYPE_CUBEMAP:
1431 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1433 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1434 // convert and upload each side in turn,
1435 // from a continuous block of input texels
1436 // copy the results into combinedbuffer
1437 texturebuffer = (unsigned char *)prevbuffer;
1438 for (i = 0;i < 6;i++)
1440 prevbuffer = texturebuffer;
1441 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1442 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1444 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1445 prevbuffer = resizebuffer;
1448 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1450 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1451 prevbuffer = resizebuffer;
1453 memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1455 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1456 Mem_Free(combinedbuffer);
1459 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1462 if (glt->flags & TEXF_FORCELINEAR)
1463 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1464 else if (glt->flags & TEXF_FORCENEAREST)
1465 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1466 else if (glt->flags & TEXF_MIPMAP)
1467 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1469 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1474 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)
1478 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1479 textypeinfo_t *texinfo, *texinfo2;
1480 unsigned char *temppixels = NULL;
1482 if (cls.state == ca_dedicated)
1485 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1487 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1490 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1492 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1496 texinfo = R_GetTexTypeInfo(textype, flags);
1497 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1500 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1504 if (textype == TEXTYPE_RGBA)
1507 static int rgbaswapindices[4] = {2, 1, 0, 3};
1508 textype = TEXTYPE_BGRA;
1509 texinfo = R_GetTexTypeInfo(textype, flags);
1510 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1511 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1515 // clear the alpha flag if the texture has no transparent pixels
1518 case TEXTYPE_PALETTE:
1519 if (flags & TEXF_ALPHA)
1521 flags &= ~TEXF_ALPHA;
1524 for (i = 0;i < size;i++)
1526 if (((unsigned char *)&palette[data[i]])[3] < 255)
1528 flags |= TEXF_ALPHA;
1537 if (flags & TEXF_ALPHA)
1539 flags &= ~TEXF_ALPHA;
1542 for (i = 3;i < size;i += 4)
1546 flags |= TEXF_ALPHA;
1553 case TEXTYPE_SHADOWMAP:
1560 flags |= TEXF_ALPHA;
1563 flags |= TEXF_ALPHA;
1565 case TEXTYPE_COLORBUFFER:
1566 flags |= TEXF_ALPHA;
1569 Sys_Error("R_LoadTexture: unknown texture type");
1572 texinfo2 = R_GetTexTypeInfo(textype, flags);
1573 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1576 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1578 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1580 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1582 glt->chain = pool->gltchain;
1583 pool->gltchain = glt;
1584 glt->inputwidth = width;
1585 glt->inputheight = height;
1586 glt->inputdepth = depth;
1588 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
1589 glt->textype = texinfo;
1590 glt->texturetype = texturetype;
1591 glt->inputdatasize = size;
1592 glt->palette = palette;
1593 glt->glinternalformat = texinfo->glinternalformat;
1594 glt->glformat = texinfo->glformat;
1595 glt->gltype = texinfo->gltype;
1596 glt->bytesperpixel = texinfo->internalbytesperpixel;
1597 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1600 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1601 // init the dynamic texture attributes, too [11/22/2007 Black]
1602 glt->updatecallback = NULL;
1603 glt->updatacallback_data = NULL;
1605 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1607 // upload the texture
1608 // data may be NULL (blank texture for dynamic rendering)
1609 switch(vid.renderpath)
1611 case RENDERPATH_GL11:
1612 case RENDERPATH_GL13:
1613 case RENDERPATH_GL20:
1614 case RENDERPATH_GLES2:
1616 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1618 case RENDERPATH_D3D9:
1621 D3DFORMAT d3dformat;
1626 d3dpool = D3DPOOL_MANAGED;
1627 if (flags & TEXF_RENDERTARGET)
1629 d3dusage |= D3DUSAGE_RENDERTARGET;
1630 d3dpool = D3DPOOL_DEFAULT;
1634 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1635 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1636 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1637 case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1638 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1639 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1640 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1642 glt->d3dformat = d3dformat;
1643 glt->d3dusage = d3dusage;
1644 glt->d3dpool = d3dpool;
1645 glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1646 if (glt->d3disdepthsurface)
1648 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1649 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1651 else if (glt->tiledepth > 1)
1653 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)))
1654 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1656 else if (glt->sides == 6)
1658 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1659 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1663 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)))
1664 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1669 case RENDERPATH_D3D10:
1670 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1672 case RENDERPATH_D3D11:
1673 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1675 case RENDERPATH_SOFT:
1680 case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1681 case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1682 case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1683 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1684 case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1685 case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1686 default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1688 if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1689 if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1690 if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1691 if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1692 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1697 R_UploadFullTexture(glt, data);
1698 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1699 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1701 // free any temporary processing buffer we allocated...
1703 Mem_Free(temppixels);
1705 // texture converting and uploading can take a while, so make sure we're sending keepalives
1706 // FIXME: this causes rendering during R_Shadow_DrawLights
1707 // CL_KeepaliveMessage(false);
1709 return (rtexture_t *)glt;
1712 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)
1714 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1717 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)
1719 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1722 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)
1724 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1727 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1729 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1731 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1733 flags |= TEXF_FORCENEAREST;
1734 if (precision <= 16)
1735 flags |= TEXF_LOWPRECISION;
1739 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1741 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1744 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1746 gltexture_t *glt = (gltexture_t *)rt;
1749 int bytesperpixel = 0;
1750 int bytesperblock = 0;
1752 int dds_format_flags;
1760 GLint internalformat;
1761 const char *ddsfourcc;
1763 return -1; // NULL pointer
1764 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1765 return -2; // broken driver - crashes on reading internal format
1766 if (!qglGetTexLevelParameteriv)
1768 GL_ActiveTexture(0);
1769 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1770 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1771 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1772 switch(internalformat)
1774 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1775 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1776 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1777 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1778 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1780 // if premultiplied alpha, say so in the DDS file
1781 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1783 switch(internalformat)
1785 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1786 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1789 if (!bytesperblock && skipuncompressed)
1790 return -3; // skipped
1791 memset(mipinfo, 0, sizeof(mipinfo));
1792 mipinfo[0][0] = glt->tilewidth;
1793 mipinfo[0][1] = glt->tileheight;
1795 if (glt->flags & TEXF_MIPMAP)
1797 for (mip = 1;mip < 16;mip++)
1799 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1800 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1801 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1809 for (mip = 0;mip < mipmaps;mip++)
1811 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1812 mipinfo[mip][3] = ddssize;
1813 ddssize += mipinfo[mip][2];
1815 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1818 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1822 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1823 dds_format_flags = 0x4; // DDPF_FOURCC
1827 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1828 dds_format_flags = 0x40; // DDPF_RGB
1832 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1833 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1836 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1837 memcpy(dds, "DDS ", 4);
1838 StoreLittleLong(dds+4, ddssize);
1839 StoreLittleLong(dds+8, dds_flags);
1840 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1841 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1842 StoreLittleLong(dds+24, 1); // depth
1843 StoreLittleLong(dds+28, mipmaps); // mipmaps
1844 StoreLittleLong(dds+76, 32); // format size
1845 StoreLittleLong(dds+80, dds_format_flags);
1846 StoreLittleLong(dds+108, dds_caps1);
1847 StoreLittleLong(dds+112, dds_caps2);
1850 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1851 memcpy(dds+84, ddsfourcc, 4);
1852 for (mip = 0;mip < mipmaps;mip++)
1854 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1859 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1860 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1861 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1862 for (mip = 0;mip < mipmaps;mip++)
1864 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1867 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1868 ret = FS_WriteFile(filename, dds, ddssize);
1870 return ret ? ddssize : -5;
1873 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
1875 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1878 int bytesperblock, bytesperpixel;
1881 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1882 textypeinfo_t *texinfo;
1883 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1885 GLint oldbindtexnum = 0;
1886 const unsigned char *mippixels, *ddspixels, *mippixels_start;
1888 fs_offset_t ddsfilesize;
1889 unsigned int ddssize;
1890 qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
1892 if (cls.state == ca_dedicated)
1895 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1896 ddssize = ddsfilesize;
1900 if(r_texture_dds_load_logfailure.integer)
1901 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1902 return NULL; // not found
1905 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1908 Con_Printf("^1%s: not a DDS image\n", filename);
1912 //dds_flags = BuffLittleLong(dds+8);
1913 dds_format_flags = BuffLittleLong(dds+80);
1914 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1915 dds_width = BuffLittleLong(dds+16);
1916 dds_height = BuffLittleLong(dds+12);
1917 ddspixels = dds + 128;
1919 if(r_texture_dds_load_alphamode.integer == 0)
1920 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1921 flags &= ~TEXF_ALPHA;
1923 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1924 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1926 // very sloppy BGRA 32bit identification
1927 textype = TEXTYPE_BGRA;
1930 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1931 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1934 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1937 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1940 for (i = 3;i < size;i += 4)
1941 if (ddspixels[i] < 255)
1944 flags &= ~TEXF_ALPHA;
1947 else if (!memcmp(dds+84, "DXT1", 4))
1949 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1950 // LordHavoc: it is my belief that this does not infringe on the
1951 // patent because it is not decoding pixels...
1952 textype = TEXTYPE_DXT1;
1955 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1956 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1957 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1960 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1963 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1965 if(r_texture_dds_load_alphamode.integer == 1)
1968 for (i = 0;i < size;i += bytesperblock)
1969 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1971 // NOTE: this assumes sizeof(unsigned int) == 4
1972 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1973 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1974 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1978 textype = TEXTYPE_DXT1A;
1980 flags &= ~TEXF_ALPHA;
1984 flags &= ~TEXF_ALPHA;
1988 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
1990 if(!memcmp(dds+84, "DXT2", 4))
1992 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1994 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
1999 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2001 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2004 textype = TEXTYPE_DXT3;
2007 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2008 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2011 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2014 // we currently always assume alpha
2016 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2018 if(!memcmp(dds+84, "DXT4", 4))
2020 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2022 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2027 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2029 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2032 textype = TEXTYPE_DXT5;
2035 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2036 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2039 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2042 // we currently always assume alpha
2047 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2051 force_swdecode = false;
2054 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
2056 if(r_texture_dds_swdecode.integer > 1)
2057 force_swdecode = true;
2061 if(r_texture_dds_swdecode.integer < 1)
2067 force_swdecode = true;
2071 // return whether this texture is transparent
2073 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2075 // if we SW decode, choose 2 sizes bigger
2078 // this is quarter res, so do not scale down more than we have to
2082 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2085 // this is where we apply gl_picmip
2086 mippixels_start = ddspixels;
2087 mipwidth = dds_width;
2088 mipheight = dds_height;
2089 while(miplevel >= 1 && dds_miplevels >= 1)
2091 if (mipwidth <= 1 && mipheight <= 1)
2093 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2094 mippixels_start += mipsize; // just skip
2102 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2103 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2105 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2107 // fake decode S3TC if needed
2110 int mipsize_new = mipsize_total / bytesperblock * 4;
2111 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2112 unsigned char *p = mipnewpixels;
2113 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2115 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2116 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2117 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2118 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2119 if(textype == TEXTYPE_DXT5)
2120 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2121 else if(textype == TEXTYPE_DXT3)
2123 (mippixels_start[i-8] & 0x0F)
2124 + (mippixels_start[i-8] >> 4)
2125 + (mippixels_start[i-7] & 0x0F)
2126 + (mippixels_start[i-7] >> 4)
2127 + (mippixels_start[i-6] & 0x0F)
2128 + (mippixels_start[i-6] >> 4)
2129 + (mippixels_start[i-5] & 0x0F)
2130 + (mippixels_start[i-5] >> 4)
2131 ) * (0.125f / 15.0f * 255.0f);
2136 textype = TEXTYPE_BGRA;
2140 // as each block becomes a pixel, we must use pixel count for this
2141 mipwidth = (mipwidth + 3) / 4;
2142 mipheight = (mipheight + 3) / 4;
2143 mipsize = bytesperpixel * mipwidth * mipheight;
2144 mippixels_start = mipnewpixels;
2145 mipsize_total = mipsize_new;
2148 // start mip counting
2149 mippixels = mippixels_start;
2151 // calculate average color if requested
2155 Vector4Clear(avgcolor);
2158 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2160 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2161 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2162 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2163 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2164 if(textype == TEXTYPE_DXT5)
2165 avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2166 else if(textype == TEXTYPE_DXT3)
2168 (mippixels_start[i-8] & 0x0F)
2169 + (mippixels_start[i-8] >> 4)
2170 + (mippixels_start[i-7] & 0x0F)
2171 + (mippixels_start[i-7] >> 4)
2172 + (mippixels_start[i-6] & 0x0F)
2173 + (mippixels_start[i-6] >> 4)
2174 + (mippixels_start[i-5] & 0x0F)
2175 + (mippixels_start[i-5] >> 4)
2176 ) * (0.125f / 15.0f * 255.0f);
2180 f = (float)bytesperblock / size;
2181 avgcolor[0] *= (0.5f / 31.0f) * f;
2182 avgcolor[1] *= (0.5f / 63.0f) * f;
2183 avgcolor[2] *= (0.5f / 31.0f) * f;
2188 for (i = 0;i < mipsize;i += 4)
2190 avgcolor[0] += mippixels[i+2];
2191 avgcolor[1] += mippixels[i+1];
2192 avgcolor[2] += mippixels[i];
2193 avgcolor[3] += mippixels[i+3];
2195 f = (1.0f / 255.0f) * bytesperpixel / size;
2203 // when not requesting mipmaps, do not load them
2204 if(!(flags & TEXF_MIPMAP))
2207 if (dds_miplevels >= 1)
2208 flags |= TEXF_MIPMAP;
2210 flags &= ~TEXF_MIPMAP;
2212 texinfo = R_GetTexTypeInfo(textype, flags);
2214 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2215 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2217 glt->chain = pool->gltchain;
2218 pool->gltchain = glt;
2219 glt->inputwidth = mipwidth;
2220 glt->inputheight = mipheight;
2221 glt->inputdepth = 1;
2223 glt->textype = texinfo;
2224 glt->texturetype = GLTEXTURETYPE_2D;
2225 glt->inputdatasize = ddssize;
2226 glt->glinternalformat = texinfo->glinternalformat;
2227 glt->glformat = texinfo->glformat;
2228 glt->gltype = texinfo->gltype;
2229 glt->bytesperpixel = texinfo->internalbytesperpixel;
2231 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2232 glt->tilewidth = mipwidth;
2233 glt->tileheight = mipheight;
2235 glt->miplevels = dds_miplevels;
2237 // texture uploading can take a while, so make sure we're sending keepalives
2238 CL_KeepaliveMessage(false);
2240 // create the texture object
2241 switch(vid.renderpath)
2243 case RENDERPATH_GL11:
2244 case RENDERPATH_GL13:
2245 case RENDERPATH_GL20:
2246 case RENDERPATH_GLES2:
2248 GL_ActiveTexture(0);
2249 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2250 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2251 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2253 case RENDERPATH_D3D9:
2256 D3DFORMAT d3dformat;
2261 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2262 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2263 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2264 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2265 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2268 d3dpool = D3DPOOL_MANAGED;
2269 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2273 case RENDERPATH_D3D10:
2274 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2276 case RENDERPATH_D3D11:
2277 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2279 case RENDERPATH_SOFT:
2280 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);
2284 // upload the texture
2285 // we need to restore the texture binding after finishing the upload
2286 mipcomplete = false;
2288 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2290 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2291 if (mippixels + mipsize > mippixels_start + mipsize_total)
2293 switch(vid.renderpath)
2295 case RENDERPATH_GL11:
2296 case RENDERPATH_GL13:
2297 case RENDERPATH_GL20:
2298 case RENDERPATH_GLES2:
2301 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2305 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2308 case RENDERPATH_D3D9:
2311 D3DLOCKED_RECT d3dlockedrect;
2312 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2314 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2315 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2321 case RENDERPATH_D3D10:
2322 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2324 case RENDERPATH_D3D11:
2325 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2327 case RENDERPATH_SOFT:
2329 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2331 DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
2332 // DPSOFTRAST calculates its own mipmaps
2333 mip = dds_miplevels;
2336 mippixels += mipsize;
2337 if (mipwidth <= 1 && mipheight <= 1)
2348 // after upload we have to set some parameters...
2349 switch(vid.renderpath)
2351 case RENDERPATH_GL11:
2352 case RENDERPATH_GL13:
2353 case RENDERPATH_GL20:
2354 case RENDERPATH_GLES2:
2355 if (dds_miplevels >= 1 && !mipcomplete)
2357 // need to set GL_TEXTURE_MAX_LEVEL
2358 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2360 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2361 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2363 case RENDERPATH_D3D9:
2365 glt->d3daddressw = 0;
2366 if (glt->flags & TEXF_CLAMP)
2368 glt->d3daddressu = D3DTADDRESS_CLAMP;
2369 glt->d3daddressv = D3DTADDRESS_CLAMP;
2370 if (glt->tiledepth > 1)
2371 glt->d3daddressw = D3DTADDRESS_CLAMP;
2375 glt->d3daddressu = D3DTADDRESS_WRAP;
2376 glt->d3daddressv = D3DTADDRESS_WRAP;
2377 if (glt->tiledepth > 1)
2378 glt->d3daddressw = D3DTADDRESS_WRAP;
2380 glt->d3dmipmaplodbias = 0;
2381 glt->d3dmaxmiplevel = 0;
2382 glt->d3dmaxmiplevelfilter = 0;
2383 if (glt->flags & TEXF_MIPMAP)
2385 glt->d3dminfilter = d3d_filter_mipmin;
2386 glt->d3dmagfilter = d3d_filter_mipmag;
2387 glt->d3dmipfilter = d3d_filter_mipmix;
2391 glt->d3dminfilter = d3d_filter_flatmin;
2392 glt->d3dmagfilter = d3d_filter_flatmag;
2393 glt->d3dmipfilter = d3d_filter_flatmix;
2397 case RENDERPATH_D3D10:
2398 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2400 case RENDERPATH_D3D11:
2401 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2403 case RENDERPATH_SOFT:
2404 if (glt->flags & TEXF_FORCELINEAR)
2405 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2406 else if (glt->flags & TEXF_FORCENEAREST)
2407 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2408 else if (glt->flags & TEXF_MIPMAP)
2409 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2411 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2417 Mem_Free((unsigned char *) mippixels_start);
2418 return (rtexture_t *)glt;
2421 int R_TextureWidth(rtexture_t *rt)
2423 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2426 int R_TextureHeight(rtexture_t *rt)
2428 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2431 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2433 gltexture_t *glt = (gltexture_t *)rt;
2435 Host_Error("R_UpdateTexture: no data supplied");
2437 Host_Error("R_UpdateTexture: no texture supplied");
2438 if (!glt->texnum && !glt->d3dtexture)
2440 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2443 // update part of the texture
2444 if (glt->bufferpixels)
2447 int bpp = glt->bytesperpixel;
2448 int inputskip = width*bpp;
2449 int outputskip = glt->tilewidth*bpp;
2450 const unsigned char *input = data;
2451 unsigned char *output = glt->bufferpixels;
2452 if (glt->inputdepth != 1 || glt->sides != 1)
2453 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2463 input -= y*inputskip;
2466 if (width > glt->tilewidth - x)
2467 width = glt->tilewidth - x;
2468 if (height > glt->tileheight - y)
2469 height = glt->tileheight - y;
2470 if (width < 1 || height < 1)
2473 glt->buffermodified = true;
2474 output += y*outputskip + x*bpp;
2475 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2476 memcpy(output, input, width*bpp);
2478 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2479 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2481 R_UploadFullTexture(glt, data);
2484 int R_RealGetTexture(rtexture_t *rt)
2489 glt = (gltexture_t *)rt;
2490 if (glt->flags & GLTEXF_DYNAMIC)
2491 R_UpdateDynamicTexture(glt);
2492 if (glt->buffermodified && glt->bufferpixels)
2494 glt->buffermodified = false;
2495 R_UploadFullTexture(glt, glt->bufferpixels);
2504 void R_ClearTexture (rtexture_t *rt)
2506 gltexture_t *glt = (gltexture_t *)rt;
2508 R_UploadFullTexture(glt, NULL);
2511 int R_PicmipForFlags(int flags)
2514 if(flags & TEXF_PICMIP)
2516 miplevel += gl_picmip.integer;
2517 if (flags & TEXF_ISWORLD)
2519 if (r_picmipworld.integer)
2520 miplevel += gl_picmip_world.integer;
2524 else if (flags & TEXF_ISSPRITE)
2526 if (r_picmipsprites.integer)
2527 miplevel += gl_picmip_sprites.integer;
2532 miplevel += gl_picmip_other.integer;
2534 return max(0, miplevel);