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 };
96 static textypeinfo_t textype_colorbuffer16f = {TEXTYPE_COLORBUFFER16F,8,8,8.0f, GL_RGBA16F_ARB , GL_RGBA , GL_FLOAT };
97 static textypeinfo_t textype_colorbuffer32f = {TEXTYPE_COLORBUFFER32F,16,16,16.0f,GL_RGBA32F_ARB , GL_RGBA , GL_FLOAT };
100 typedef enum gltexturetype_e
104 GLTEXTURETYPE_CUBEMAP,
109 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB};
110 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
111 static int cubemapside[6] =
113 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
114 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
115 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
116 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
117 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
118 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
121 typedef struct gltexture_s
123 // this portion of the struct is exposed to the R_GetTexture macro for
124 // speed reasons, must be identical in rtexture_t!
125 int texnum; // GL texture slot number
126 qboolean dirty; // indicates that R_RealGetTexture should be called
127 int gltexturetypeenum; // used by R_Mesh_TexBind
128 // d3d stuff the backend needs
131 qboolean d3disdepthsurface; // for depth/stencil surfaces
141 int d3dmaxmiplevelfilter;
142 int d3dmipmaplodbias;
146 // dynamic texture stuff [11/22/2007 Black]
147 updatecallback_t updatecallback;
148 void *updatacallback_data;
149 // --- [11/22/2007 Black]
151 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
152 unsigned char *bufferpixels;
153 qboolean buffermodified;
155 // pointer to texturepool (check this to see if the texture is allocated)
156 struct gltexturepool_s *pool;
157 // pointer to next texture in texturepool chain
158 struct gltexture_s *chain;
159 // name of the texture (this might be removed someday), no duplicates
160 char identifier[MAX_QPATH + 32];
161 // original data size in *inputtexels
162 int inputwidth, inputheight, inputdepth;
163 // copy of the original texture(s) supplied to the upload function, for
164 // delayed uploads (non-precached)
165 unsigned char *inputtexels;
166 // original data size in *inputtexels
168 // flags supplied to the LoadTexture function
169 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
173 // pointer to one of the textype_ structs
174 textypeinfo_t *textype;
175 // one of the GLTEXTURETYPE_ values
177 // palette if the texture is TEXTYPE_PALETTE
178 const unsigned int *palette;
179 // actual stored texture size after gl_picmip and gl_max_size are applied
180 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
181 int tilewidth, tileheight, tiledepth;
182 // 1 or 6 depending on texturetype
184 // how many mipmap levels in this texture
188 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
191 int glinternalformat;
192 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
197 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
199 typedef struct gltexturepool_s
201 unsigned int sentinel;
202 struct gltexture_s *gltchain;
203 struct gltexturepool_s *next;
207 static gltexturepool_t *gltexturepoolchain = NULL;
209 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
210 static int resizebuffersize = 0;
211 static const unsigned char *texturebuffer;
213 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
218 return &textype_dxt1;
220 return &textype_dxt1a;
222 return &textype_dxt3;
224 return &textype_dxt5;
225 case TEXTYPE_PALETTE:
226 return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
228 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
229 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress;
230 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba;
232 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
233 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress;
234 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra;
236 return &textype_alpha;
237 case TEXTYPE_SHADOWMAP:
238 return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
239 case TEXTYPE_COLORBUFFER:
240 return &textype_colorbuffer;
241 case TEXTYPE_COLORBUFFER16F:
242 return &textype_colorbuffer16f;
243 case TEXTYPE_COLORBUFFER32F:
244 return &textype_colorbuffer32f;
246 Host_Error("R_GetTexTypeInfo: unknown texture format");
252 // dynamic texture code [11/22/2007 Black]
253 void R_MarkDirtyTexture(rtexture_t *rt) {
254 gltexture_t *glt = (gltexture_t*) rt;
259 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
260 if (glt->flags & GLTEXF_DYNAMIC)
262 // mark it as dirty, so R_RealGetTexture gets called
267 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
268 gltexture_t *glt = (gltexture_t*) rt;
273 glt->flags |= GLTEXF_DYNAMIC;
274 glt->updatecallback = updatecallback;
275 glt->updatacallback_data = data;
278 static void R_UpdateDynamicTexture(gltexture_t *glt) {
280 if( glt->updatecallback ) {
281 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
285 void R_PurgeTexture(rtexture_t *rt)
287 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
292 void R_FreeTexture(rtexture_t *rt)
294 gltexture_t *glt, **gltpointer;
296 glt = (gltexture_t *)rt;
298 Host_Error("R_FreeTexture: texture == NULL");
300 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
301 if (*gltpointer == glt)
302 *gltpointer = glt->chain;
304 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
306 R_Mesh_ClearBindingsForTexture(glt->texnum);
308 switch(vid.renderpath)
310 case RENDERPATH_GL11:
311 case RENDERPATH_GL13:
312 case RENDERPATH_GL20:
313 case RENDERPATH_GLES2:
317 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
320 case RENDERPATH_D3D9:
322 if (glt->d3disdepthsurface)
323 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
324 else if (glt->tiledepth > 1)
325 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
326 else if (glt->sides == 6)
327 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
329 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
330 glt->d3dtexture = NULL;
333 case RENDERPATH_D3D10:
334 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
336 case RENDERPATH_D3D11:
337 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
339 case RENDERPATH_SOFT:
341 DPSOFTRAST_Texture_Free(glt->texnum);
345 if (glt->inputtexels)
346 Mem_Free(glt->inputtexels);
347 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
350 rtexturepool_t *R_AllocTexturePool(void)
352 gltexturepool_t *pool;
353 if (texturemempool == NULL)
355 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
358 pool->next = gltexturepoolchain;
359 gltexturepoolchain = pool;
360 pool->sentinel = TEXTUREPOOL_SENTINEL;
361 return (rtexturepool_t *)pool;
364 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
366 gltexturepool_t *pool, **poolpointer;
367 if (rtexturepool == NULL)
369 if (*rtexturepool == NULL)
371 pool = (gltexturepool_t *)(*rtexturepool);
372 *rtexturepool = NULL;
373 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
374 Host_Error("R_FreeTexturePool: pool already freed");
375 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
376 if (*poolpointer == pool)
377 *poolpointer = pool->next;
379 Host_Error("R_FreeTexturePool: pool not linked");
380 while (pool->gltchain)
381 R_FreeTexture((rtexture_t *)pool->gltchain);
386 typedef struct glmode_s
389 int minification, magnification;
390 DPSOFTRAST_TEXTURE_FILTER dpsoftrastfilter_mipmap, dpsoftrastfilter_nomipmap;
394 static glmode_t modes[6] =
396 {"GL_NEAREST", GL_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
397 {"GL_LINEAR", GL_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
398 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
399 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
400 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
401 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR}
405 typedef struct d3dmode_s
412 static d3dmode_t d3dmodes[6] =
414 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
415 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
416 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
417 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
418 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
419 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
423 static void GL_TextureMode_f (void)
428 gltexturepool_t *pool;
432 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
433 for (i = 0;i < 6;i++)
435 if (gl_filter_min == modes[i].minification)
437 Con_Printf("%s\n", modes[i].name);
441 Con_Print("current filter is unknown???\n");
445 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
446 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
450 Con_Print("bad filter name\n");
454 gl_filter_min = modes[i].minification;
455 gl_filter_mag = modes[i].magnification;
456 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
458 dpsoftrast_filter_mipmap = modes[i].dpsoftrastfilter_mipmap;
459 dpsoftrast_filter_nomipmap = modes[i].dpsoftrastfilter_nomipmap;
461 switch(vid.renderpath)
463 case RENDERPATH_GL11:
464 case RENDERPATH_GL13:
465 case RENDERPATH_GL20:
466 case RENDERPATH_GLES2:
467 // change all the existing mipmap texture objects
468 // FIXME: force renderer(/client/something?) restart instead?
471 for (pool = gltexturepoolchain;pool;pool = pool->next)
473 for (glt = pool->gltchain;glt;glt = glt->chain)
475 // only update already uploaded images
476 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
478 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
479 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
480 if (glt->flags & TEXF_MIPMAP)
482 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
486 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
488 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
489 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
494 case RENDERPATH_D3D9:
496 d3d_filter_flatmin = d3dmodes[i].m1;
497 d3d_filter_flatmag = d3dmodes[i].m1;
498 d3d_filter_flatmix = D3DTEXF_POINT;
499 d3d_filter_mipmin = d3dmodes[i].m1;
500 d3d_filter_mipmag = d3dmodes[i].m1;
501 d3d_filter_mipmix = d3dmodes[i].m2;
502 d3d_filter_nomip = i < 2;
503 if (gl_texture_anisotropy.integer > 1 && i == 5)
504 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
505 for (pool = gltexturepoolchain;pool;pool = pool->next)
507 for (glt = pool->gltchain;glt;glt = glt->chain)
509 // only update already uploaded images
510 if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
512 if (glt->flags & TEXF_MIPMAP)
514 glt->d3dminfilter = d3d_filter_mipmin;
515 glt->d3dmagfilter = d3d_filter_mipmag;
516 glt->d3dmipfilter = d3d_filter_mipmix;
517 glt->d3dmaxmiplevelfilter = 0;
521 glt->d3dminfilter = d3d_filter_flatmin;
522 glt->d3dmagfilter = d3d_filter_flatmag;
523 glt->d3dmipfilter = d3d_filter_flatmix;
524 glt->d3dmaxmiplevelfilter = 0;
531 case RENDERPATH_D3D10:
532 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
534 case RENDERPATH_D3D11:
535 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
537 case RENDERPATH_SOFT:
538 // change all the existing texture objects
539 for (pool = gltexturepoolchain;pool;pool = pool->next)
540 for (glt = pool->gltchain;glt;glt = glt->chain)
541 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
542 DPSOFTRAST_Texture_Filter(glt->texnum, (glt->flags & TEXF_MIPMAP) ? dpsoftrast_filter_mipmap : dpsoftrast_filter_nomipmap);
547 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)
549 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
554 case GLTEXTURETYPE_2D:
555 maxsize = vid.maxtexturesize_2d;
556 if (flags & TEXF_PICMIP)
558 maxsize = bound(1, gl_max_size.integer, maxsize);
562 case GLTEXTURETYPE_3D:
563 maxsize = vid.maxtexturesize_3d;
565 case GLTEXTURETYPE_CUBEMAP:
566 maxsize = vid.maxtexturesize_cubemap;
570 if (vid.support.arb_texture_non_power_of_two)
572 width2 = min(inwidth >> picmip, maxsize);
573 height2 = min(inheight >> picmip, maxsize);
574 depth2 = min(indepth >> picmip, maxsize);
578 for (width2 = 1;width2 < inwidth;width2 <<= 1);
579 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
580 for (height2 = 1;height2 < inheight;height2 <<= 1);
581 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
582 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
583 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
586 switch(vid.renderpath)
588 case RENDERPATH_GL11:
589 case RENDERPATH_GL13:
590 case RENDERPATH_GL20:
591 case RENDERPATH_D3D10:
592 case RENDERPATH_D3D11:
593 case RENDERPATH_SOFT:
594 case RENDERPATH_GLES2:
596 case RENDERPATH_D3D9:
598 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
599 if (texturetype == GLTEXTURETYPE_2D)
601 width2 = max(width2, 2);
602 height2 = max(height2, 2);
609 if (flags & TEXF_MIPMAP)
611 int extent = max(width2, max(height2, depth2));
617 *outwidth = max(1, width2);
619 *outheight = max(1, height2);
621 *outdepth = max(1, depth2);
623 *outmiplevels = miplevels;
627 static int R_CalcTexelDataSize (gltexture_t *glt)
629 int width2, height2, depth2, size;
631 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
633 size = width2 * height2 * depth2;
635 if (glt->flags & TEXF_MIPMAP)
637 while (width2 > 1 || height2 > 1 || depth2 > 1)
645 size += width2 * height2 * depth2;
649 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
652 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
656 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
657 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
659 gltexturepool_t *pool;
661 Con_Print("glsize input loaded mip alpha name\n");
662 for (pool = gltexturepoolchain;pool;pool = pool->next)
670 for (glt = pool->gltchain;glt;glt = glt->chain)
672 glsize = R_CalcTexelDataSize(glt);
673 isloaded = glt->texnum != 0;
675 pooltotalt += glsize;
676 pooltotalp += glt->inputdatasize;
680 poolloadedt += glsize;
681 poolloadedp += glt->inputdatasize;
684 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);
687 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);
688 sumtotal += pooltotal;
689 sumtotalt += pooltotalt;
690 sumtotalp += pooltotalp;
691 sumloaded += poolloaded;
692 sumloadedt += poolloadedt;
693 sumloadedp += poolloadedp;
696 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);
699 static void R_TextureStats_f(void)
701 R_TextureStats_Print(true, true, true);
704 static void r_textures_start(void)
706 switch(vid.renderpath)
708 case RENDERPATH_GL11:
709 case RENDERPATH_GL13:
710 case RENDERPATH_GL20:
711 case RENDERPATH_GLES2:
712 // LordHavoc: allow any alignment
714 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
715 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
717 case RENDERPATH_D3D9:
719 case RENDERPATH_D3D10:
720 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
722 case RENDERPATH_D3D11:
723 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
725 case RENDERPATH_SOFT:
729 texturemempool = Mem_AllocPool("texture management", 0, NULL);
730 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
732 // Disable JPEG screenshots if the DLL isn't loaded
733 if (! JPEG_OpenLibrary ())
734 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
735 if (! PNG_OpenLibrary ())
736 Cvar_SetValueQuick (&scr_screenshot_png, 0);
739 static void r_textures_shutdown(void)
741 rtexturepool_t *temp;
743 JPEG_CloseLibrary ();
745 while(gltexturepoolchain)
747 temp = (rtexturepool_t *) gltexturepoolchain;
748 R_FreeTexturePool(&temp);
751 resizebuffersize = 0;
753 colorconvertbuffer = NULL;
754 texturebuffer = NULL;
755 Mem_ExpandableArray_FreeArray(&texturearray);
756 Mem_FreePool(&texturemempool);
759 static void r_textures_newmap(void)
763 static void r_textures_devicelost(void)
767 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
768 for (i = 0;i < endindex;i++)
770 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
771 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
773 switch(vid.renderpath)
775 case RENDERPATH_GL11:
776 case RENDERPATH_GL13:
777 case RENDERPATH_GL20:
778 case RENDERPATH_GLES2:
780 case RENDERPATH_D3D9:
782 if (glt->d3disdepthsurface)
783 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
784 else if (glt->tiledepth > 1)
785 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
786 else if (glt->sides == 6)
787 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
789 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
790 glt->d3dtexture = NULL;
793 case RENDERPATH_D3D10:
794 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
796 case RENDERPATH_D3D11:
797 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
799 case RENDERPATH_SOFT:
805 static void r_textures_devicerestored(void)
809 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
810 for (i = 0;i < endindex;i++)
812 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
813 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
815 switch(vid.renderpath)
817 case RENDERPATH_GL11:
818 case RENDERPATH_GL13:
819 case RENDERPATH_GL20:
820 case RENDERPATH_GLES2:
822 case RENDERPATH_D3D9:
826 if (glt->d3disdepthsurface)
828 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
829 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
831 else if (glt->tiledepth > 1)
833 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)))
834 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
836 else if (glt->sides == 6)
838 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
839 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
843 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)))
844 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
849 case RENDERPATH_D3D10:
850 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
852 case RENDERPATH_D3D11:
853 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
855 case RENDERPATH_SOFT:
862 void R_Textures_Init (void)
864 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");
865 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
866 Cvar_RegisterVariable (&gl_max_size);
867 Cvar_RegisterVariable (&gl_picmip);
868 Cvar_RegisterVariable (&gl_picmip_world);
869 Cvar_RegisterVariable (&r_picmipworld);
870 Cvar_RegisterVariable (&gl_picmip_sprites);
871 Cvar_RegisterVariable (&r_picmipsprites);
872 Cvar_RegisterVariable (&gl_picmip_other);
873 Cvar_RegisterVariable (&gl_max_lightmapsize);
874 Cvar_RegisterVariable (&r_lerpimages);
875 Cvar_RegisterVariable (&gl_texture_anisotropy);
876 Cvar_RegisterVariable (&gl_texturecompression);
877 Cvar_RegisterVariable (&gl_texturecompression_color);
878 Cvar_RegisterVariable (&gl_texturecompression_normal);
879 Cvar_RegisterVariable (&gl_texturecompression_gloss);
880 Cvar_RegisterVariable (&gl_texturecompression_glow);
881 Cvar_RegisterVariable (&gl_texturecompression_2d);
882 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
883 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
884 Cvar_RegisterVariable (&gl_texturecompression_sky);
885 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
886 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
887 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
888 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
889 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
890 Cvar_RegisterVariable (&r_texture_dds_swdecode);
892 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
895 void R_Textures_Frame (void)
897 static int old_aniso = 0;
899 // could do procedural texture animation here, if we keep track of which
900 // textures were accessed this frame...
902 // free the resize buffers
903 resizebuffersize = 0;
906 Mem_Free(resizebuffer);
909 if (colorconvertbuffer)
911 Mem_Free(colorconvertbuffer);
912 colorconvertbuffer = NULL;
915 if (old_aniso != gl_texture_anisotropy.integer)
918 gltexturepool_t *pool;
921 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
923 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
925 switch(vid.renderpath)
927 case RENDERPATH_GL11:
928 case RENDERPATH_GL13:
929 case RENDERPATH_GL20:
930 case RENDERPATH_GLES2:
933 for (pool = gltexturepoolchain;pool;pool = pool->next)
935 for (glt = pool->gltchain;glt;glt = glt->chain)
937 // only update already uploaded images
938 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
940 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
942 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
943 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
945 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
950 case RENDERPATH_D3D9:
951 case RENDERPATH_D3D10:
952 case RENDERPATH_D3D11:
953 case RENDERPATH_SOFT:
959 void R_MakeResizeBufferBigger(int size)
961 if (resizebuffersize < size)
963 resizebuffersize = size;
965 Mem_Free(resizebuffer);
966 if (colorconvertbuffer)
967 Mem_Free(colorconvertbuffer);
968 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
969 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
970 if (!resizebuffer || !colorconvertbuffer)
971 Host_Error("R_Upload: out of memory");
975 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
977 int textureenum = gltexturetypeenums[texturetype];
978 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
982 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
984 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
985 if (gl_texture_anisotropy.integer != aniso)
986 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
987 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
989 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
990 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
991 if (gltexturetypedimensions[texturetype] >= 3)
993 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
997 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
999 if (flags & TEXF_MIPMAP)
1001 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
1005 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
1007 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
1009 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
1011 if (flags & TEXF_MIPMAP)
1013 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
1015 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
1019 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
1024 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
1026 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
1030 if (flags & TEXF_MIPMAP)
1032 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1036 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1038 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1041 if (textype == TEXTYPE_SHADOWMAP)
1043 if (vid.support.arb_shadow)
1045 if (flags & TEXF_COMPARE)
1047 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1051 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1053 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1055 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1061 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1064 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1066 if (glt->texturetype != GLTEXTURETYPE_2D)
1067 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1069 if (glt->textype->textype == TEXTYPE_PALETTE)
1070 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1072 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1073 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1075 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1076 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1078 // update a portion of the image
1080 switch(vid.renderpath)
1082 case RENDERPATH_GL11:
1083 case RENDERPATH_GL13:
1084 case RENDERPATH_GL20:
1085 case RENDERPATH_GLES2:
1089 // we need to restore the texture binding after finishing the upload
1090 GL_ActiveTexture(0);
1091 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1092 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1093 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1094 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1097 case RENDERPATH_D3D9:
1101 D3DLOCKED_RECT d3dlockedrect;
1103 memset(&d3drect, 0, sizeof(d3drect));
1104 d3drect.left = fragx;
1105 d3drect.top = fragy;
1106 d3drect.right = fragx+fragwidth;
1107 d3drect.bottom = fragy+fragheight;
1108 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1110 for (y = 0;y < fragheight;y++)
1111 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1112 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1117 case RENDERPATH_D3D10:
1118 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1120 case RENDERPATH_D3D11:
1121 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1123 case RENDERPATH_SOFT:
1124 DPSOFTRAST_Texture_UpdatePartial(glt->texnum, 0, data, fragx, fragy, fragwidth, fragheight);
1129 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1131 int i, mip = 0, width, height, depth;
1132 GLint oldbindtexnum = 0;
1133 const unsigned char *prevbuffer;
1136 // error out if a stretch is needed on special texture types
1137 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1138 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1140 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1141 // of the target size and then use the mipmap reduction function to get
1142 // high quality supersampled results
1143 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1144 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1145 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1146 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1148 if (prevbuffer == NULL)
1150 width = glt->tilewidth;
1151 height = glt->tileheight;
1152 depth = glt->tiledepth;
1153 memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1154 prevbuffer = resizebuffer;
1156 else if (glt->textype->textype == TEXTYPE_PALETTE)
1158 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1159 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1160 prevbuffer = colorconvertbuffer;
1163 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1165 // multiply RGB channels by A channel before uploading
1167 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1169 alpha = prevbuffer[i+3];
1170 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1171 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1172 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1173 colorconvertbuffer[i+3] = alpha;
1175 prevbuffer = colorconvertbuffer;
1178 // scale up to a power of 2 size (if appropriate)
1179 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1181 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1182 prevbuffer = resizebuffer;
1184 // apply mipmap reduction algorithm to get down to picmip/max_size
1185 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1187 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1188 prevbuffer = resizebuffer;
1191 // do the appropriate upload type...
1192 switch(vid.renderpath)
1194 case RENDERPATH_GL11:
1195 case RENDERPATH_GL13:
1196 case RENDERPATH_GL20:
1197 case RENDERPATH_GLES2:
1200 // we need to restore the texture binding after finishing the upload
1201 GL_ActiveTexture(0);
1202 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1203 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1205 if (qglGetCompressedTexImageARB)
1207 if (gl_texturecompression.integer >= 2)
1208 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1210 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1213 switch(glt->texturetype)
1215 case GLTEXTURETYPE_2D:
1216 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1217 if (glt->flags & TEXF_MIPMAP)
1219 while (width > 1 || height > 1 || depth > 1)
1221 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1222 prevbuffer = resizebuffer;
1223 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1227 case GLTEXTURETYPE_3D:
1228 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1229 if (glt->flags & TEXF_MIPMAP)
1231 while (width > 1 || height > 1 || depth > 1)
1233 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1234 prevbuffer = resizebuffer;
1235 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1239 case GLTEXTURETYPE_CUBEMAP:
1240 // convert and upload each side in turn,
1241 // from a continuous block of input texels
1242 texturebuffer = (unsigned char *)prevbuffer;
1243 for (i = 0;i < 6;i++)
1245 prevbuffer = texturebuffer;
1246 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1247 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1249 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1250 prevbuffer = resizebuffer;
1253 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1255 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1256 prevbuffer = resizebuffer;
1259 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1260 if (glt->flags & TEXF_MIPMAP)
1262 while (width > 1 || height > 1 || depth > 1)
1264 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1265 prevbuffer = resizebuffer;
1266 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1272 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1273 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1275 case RENDERPATH_D3D9:
1277 if (!(glt->flags & TEXF_RENDERTARGET))
1279 D3DLOCKED_RECT d3dlockedrect;
1280 D3DLOCKED_BOX d3dlockedbox;
1281 switch(glt->texturetype)
1283 case GLTEXTURETYPE_2D:
1284 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1287 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1289 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1290 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1293 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1295 while (width > 1 || height > 1 || depth > 1)
1297 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1298 prevbuffer = resizebuffer;
1299 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1301 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1302 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1308 case GLTEXTURETYPE_3D:
1309 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1311 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1312 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1313 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1316 if (glt->flags & TEXF_MIPMAP)
1318 while (width > 1 || height > 1 || depth > 1)
1320 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1321 prevbuffer = resizebuffer;
1322 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1324 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1325 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1326 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1332 case GLTEXTURETYPE_CUBEMAP:
1333 // convert and upload each side in turn,
1334 // from a continuous block of input texels
1335 texturebuffer = (unsigned char *)prevbuffer;
1336 for (i = 0;i < 6;i++)
1338 prevbuffer = texturebuffer;
1339 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1340 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1342 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1343 prevbuffer = resizebuffer;
1346 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1348 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1349 prevbuffer = resizebuffer;
1352 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1354 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1355 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1358 if (glt->flags & TEXF_MIPMAP)
1360 while (width > 1 || height > 1 || depth > 1)
1362 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1363 prevbuffer = resizebuffer;
1364 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1366 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1367 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1376 glt->d3daddressw = 0;
1377 if (glt->flags & TEXF_CLAMP)
1379 glt->d3daddressu = D3DTADDRESS_CLAMP;
1380 glt->d3daddressv = D3DTADDRESS_CLAMP;
1381 if (glt->tiledepth > 1)
1382 glt->d3daddressw = D3DTADDRESS_CLAMP;
1386 glt->d3daddressu = D3DTADDRESS_WRAP;
1387 glt->d3daddressv = D3DTADDRESS_WRAP;
1388 if (glt->tiledepth > 1)
1389 glt->d3daddressw = D3DTADDRESS_WRAP;
1391 glt->d3dmipmaplodbias = 0;
1392 glt->d3dmaxmiplevel = 0;
1393 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1394 if (glt->flags & TEXF_FORCELINEAR)
1396 glt->d3dminfilter = D3DTEXF_LINEAR;
1397 glt->d3dmagfilter = D3DTEXF_LINEAR;
1398 glt->d3dmipfilter = D3DTEXF_POINT;
1400 else if (glt->flags & TEXF_FORCENEAREST)
1402 glt->d3dminfilter = D3DTEXF_POINT;
1403 glt->d3dmagfilter = D3DTEXF_POINT;
1404 glt->d3dmipfilter = D3DTEXF_POINT;
1406 else if (glt->flags & TEXF_MIPMAP)
1408 glt->d3dminfilter = d3d_filter_mipmin;
1409 glt->d3dmagfilter = d3d_filter_mipmag;
1410 glt->d3dmipfilter = d3d_filter_mipmix;
1414 glt->d3dminfilter = d3d_filter_flatmin;
1415 glt->d3dmagfilter = d3d_filter_flatmag;
1416 glt->d3dmipfilter = d3d_filter_flatmix;
1420 case RENDERPATH_D3D10:
1421 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1423 case RENDERPATH_D3D11:
1424 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1426 case RENDERPATH_SOFT:
1427 switch(glt->texturetype)
1429 case GLTEXTURETYPE_2D:
1430 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1432 case GLTEXTURETYPE_3D:
1433 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1435 case GLTEXTURETYPE_CUBEMAP:
1436 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1438 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1439 // convert and upload each side in turn,
1440 // from a continuous block of input texels
1441 // copy the results into combinedbuffer
1442 texturebuffer = (unsigned char *)prevbuffer;
1443 for (i = 0;i < 6;i++)
1445 prevbuffer = texturebuffer;
1446 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1447 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1449 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1450 prevbuffer = resizebuffer;
1453 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1455 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1456 prevbuffer = resizebuffer;
1458 memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1460 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1461 Mem_Free(combinedbuffer);
1464 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1467 if (glt->flags & TEXF_FORCELINEAR)
1468 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1469 else if (glt->flags & TEXF_FORCENEAREST)
1470 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1471 else if (glt->flags & TEXF_MIPMAP)
1472 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1474 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1479 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)
1483 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1484 textypeinfo_t *texinfo, *texinfo2;
1485 unsigned char *temppixels = NULL;
1487 if (cls.state == ca_dedicated)
1490 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1492 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1495 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1497 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1501 texinfo = R_GetTexTypeInfo(textype, flags);
1502 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1505 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1509 if (textype == TEXTYPE_RGBA)
1512 static int rgbaswapindices[4] = {2, 1, 0, 3};
1513 textype = TEXTYPE_BGRA;
1514 texinfo = R_GetTexTypeInfo(textype, flags);
1515 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1516 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1520 // clear the alpha flag if the texture has no transparent pixels
1523 case TEXTYPE_PALETTE:
1524 if (flags & TEXF_ALPHA)
1526 flags &= ~TEXF_ALPHA;
1529 for (i = 0;i < size;i++)
1531 if (((unsigned char *)&palette[data[i]])[3] < 255)
1533 flags |= TEXF_ALPHA;
1542 if (flags & TEXF_ALPHA)
1544 flags &= ~TEXF_ALPHA;
1547 for (i = 3;i < size;i += 4)
1551 flags |= TEXF_ALPHA;
1558 case TEXTYPE_SHADOWMAP:
1565 flags |= TEXF_ALPHA;
1568 flags |= TEXF_ALPHA;
1570 case TEXTYPE_COLORBUFFER:
1571 case TEXTYPE_COLORBUFFER16F:
1572 case TEXTYPE_COLORBUFFER32F:
1573 flags |= TEXF_ALPHA;
1576 Sys_Error("R_LoadTexture: unknown texture type");
1579 texinfo2 = R_GetTexTypeInfo(textype, flags);
1580 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1583 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1585 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1587 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1589 glt->chain = pool->gltchain;
1590 pool->gltchain = glt;
1591 glt->inputwidth = width;
1592 glt->inputheight = height;
1593 glt->inputdepth = depth;
1595 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
1596 glt->textype = texinfo;
1597 glt->texturetype = texturetype;
1598 glt->inputdatasize = size;
1599 glt->palette = palette;
1600 glt->glinternalformat = texinfo->glinternalformat;
1601 glt->glformat = texinfo->glformat;
1602 glt->gltype = texinfo->gltype;
1603 glt->bytesperpixel = texinfo->internalbytesperpixel;
1604 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1607 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1608 // init the dynamic texture attributes, too [11/22/2007 Black]
1609 glt->updatecallback = NULL;
1610 glt->updatacallback_data = NULL;
1612 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1614 // upload the texture
1615 // data may be NULL (blank texture for dynamic rendering)
1616 switch(vid.renderpath)
1618 case RENDERPATH_GL11:
1619 case RENDERPATH_GL13:
1620 case RENDERPATH_GL20:
1621 case RENDERPATH_GLES2:
1623 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1625 case RENDERPATH_D3D9:
1628 D3DFORMAT d3dformat;
1633 d3dpool = D3DPOOL_MANAGED;
1634 if (flags & TEXF_RENDERTARGET)
1636 d3dusage |= D3DUSAGE_RENDERTARGET;
1637 d3dpool = D3DPOOL_DEFAULT;
1641 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1642 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1643 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1644 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
1645 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
1646 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
1647 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1648 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1649 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1651 glt->d3dformat = d3dformat;
1652 glt->d3dusage = d3dusage;
1653 glt->d3dpool = d3dpool;
1654 glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1655 if (glt->d3disdepthsurface)
1657 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1658 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1660 else if (glt->tiledepth > 1)
1662 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)))
1663 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1665 else if (glt->sides == 6)
1667 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1668 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1672 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)))
1673 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1678 case RENDERPATH_D3D10:
1679 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1681 case RENDERPATH_D3D11:
1682 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1684 case RENDERPATH_SOFT:
1689 case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1690 case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1691 case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1692 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1693 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
1694 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
1695 case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1696 case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1697 default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1699 if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1700 if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1701 if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1702 if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1703 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1708 R_UploadFullTexture(glt, data);
1709 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1710 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1712 // free any temporary processing buffer we allocated...
1714 Mem_Free(temppixels);
1716 // texture converting and uploading can take a while, so make sure we're sending keepalives
1717 // FIXME: this causes rendering during R_Shadow_DrawLights
1718 // CL_KeepaliveMessage(false);
1720 return (rtexture_t *)glt;
1723 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)
1725 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1728 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)
1730 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1733 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)
1735 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1738 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1740 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1742 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1744 flags |= TEXF_FORCENEAREST;
1745 if (precision <= 16)
1746 flags |= TEXF_LOWPRECISION;
1750 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1752 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1755 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1757 gltexture_t *glt = (gltexture_t *)rt;
1760 int bytesperpixel = 0;
1761 int bytesperblock = 0;
1763 int dds_format_flags;
1771 GLint internalformat;
1772 const char *ddsfourcc;
1774 return -1; // NULL pointer
1775 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1776 return -2; // broken driver - crashes on reading internal format
1777 if (!qglGetTexLevelParameteriv)
1779 GL_ActiveTexture(0);
1780 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1781 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1782 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1783 switch(internalformat)
1785 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1786 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1787 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1788 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1789 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1791 // if premultiplied alpha, say so in the DDS file
1792 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1794 switch(internalformat)
1796 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1797 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1800 if (!bytesperblock && skipuncompressed)
1801 return -3; // skipped
1802 memset(mipinfo, 0, sizeof(mipinfo));
1803 mipinfo[0][0] = glt->tilewidth;
1804 mipinfo[0][1] = glt->tileheight;
1806 if (glt->flags & TEXF_MIPMAP)
1808 for (mip = 1;mip < 16;mip++)
1810 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1811 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1812 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1820 for (mip = 0;mip < mipmaps;mip++)
1822 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1823 mipinfo[mip][3] = ddssize;
1824 ddssize += mipinfo[mip][2];
1826 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1829 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1833 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1834 dds_format_flags = 0x4; // DDPF_FOURCC
1838 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1839 dds_format_flags = 0x40; // DDPF_RGB
1843 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1844 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1847 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1848 memcpy(dds, "DDS ", 4);
1849 StoreLittleLong(dds+4, ddssize);
1850 StoreLittleLong(dds+8, dds_flags);
1851 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1852 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1853 StoreLittleLong(dds+24, 1); // depth
1854 StoreLittleLong(dds+28, mipmaps); // mipmaps
1855 StoreLittleLong(dds+76, 32); // format size
1856 StoreLittleLong(dds+80, dds_format_flags);
1857 StoreLittleLong(dds+108, dds_caps1);
1858 StoreLittleLong(dds+112, dds_caps2);
1861 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1862 memcpy(dds+84, ddsfourcc, 4);
1863 for (mip = 0;mip < mipmaps;mip++)
1865 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1870 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1871 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1872 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1873 for (mip = 0;mip < mipmaps;mip++)
1875 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1878 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1879 ret = FS_WriteFile(filename, dds, ddssize);
1881 return ret ? ddssize : -5;
1884 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
1886 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1889 int bytesperblock, bytesperpixel;
1892 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1893 textypeinfo_t *texinfo;
1894 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1896 GLint oldbindtexnum = 0;
1897 const unsigned char *mippixels, *ddspixels, *mippixels_start;
1899 fs_offset_t ddsfilesize;
1900 unsigned int ddssize;
1901 qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
1903 if (cls.state == ca_dedicated)
1906 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1907 ddssize = ddsfilesize;
1911 if(r_texture_dds_load_logfailure.integer)
1912 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1913 return NULL; // not found
1916 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1919 Con_Printf("^1%s: not a DDS image\n", filename);
1923 //dds_flags = BuffLittleLong(dds+8);
1924 dds_format_flags = BuffLittleLong(dds+80);
1925 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1926 dds_width = BuffLittleLong(dds+16);
1927 dds_height = BuffLittleLong(dds+12);
1928 ddspixels = dds + 128;
1930 if(r_texture_dds_load_alphamode.integer == 0)
1931 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1932 flags &= ~TEXF_ALPHA;
1934 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1935 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1937 // very sloppy BGRA 32bit identification
1938 textype = TEXTYPE_BGRA;
1941 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1942 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1945 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1948 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1951 for (i = 3;i < size;i += 4)
1952 if (ddspixels[i] < 255)
1955 flags &= ~TEXF_ALPHA;
1958 else if (!memcmp(dds+84, "DXT1", 4))
1960 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1961 // LordHavoc: it is my belief that this does not infringe on the
1962 // patent because it is not decoding pixels...
1963 textype = TEXTYPE_DXT1;
1966 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1967 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1968 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1971 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1974 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1976 if(r_texture_dds_load_alphamode.integer == 1)
1979 for (i = 0;i < size;i += bytesperblock)
1980 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1982 // NOTE: this assumes sizeof(unsigned int) == 4
1983 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1984 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1985 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1989 textype = TEXTYPE_DXT1A;
1991 flags &= ~TEXF_ALPHA;
1995 flags &= ~TEXF_ALPHA;
1999 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2001 if(!memcmp(dds+84, "DXT2", 4))
2003 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2005 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2010 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2012 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2015 textype = TEXTYPE_DXT3;
2018 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2019 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2022 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2025 // we currently always assume alpha
2027 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2029 if(!memcmp(dds+84, "DXT4", 4))
2031 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2033 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2038 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2040 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2043 textype = TEXTYPE_DXT5;
2046 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2047 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2050 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2053 // we currently always assume alpha
2058 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2062 force_swdecode = false;
2065 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
2067 if(r_texture_dds_swdecode.integer > 1)
2068 force_swdecode = true;
2072 if(r_texture_dds_swdecode.integer < 1)
2078 force_swdecode = true;
2082 // return whether this texture is transparent
2084 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2086 // if we SW decode, choose 2 sizes bigger
2089 // this is quarter res, so do not scale down more than we have to
2093 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2096 // this is where we apply gl_picmip
2097 mippixels_start = ddspixels;
2098 mipwidth = dds_width;
2099 mipheight = dds_height;
2100 while(miplevel >= 1 && dds_miplevels >= 1)
2102 if (mipwidth <= 1 && mipheight <= 1)
2104 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2105 mippixels_start += mipsize; // just skip
2113 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2114 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2116 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2118 // fake decode S3TC if needed
2121 int mipsize_new = mipsize_total / bytesperblock * 4;
2122 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2123 unsigned char *p = mipnewpixels;
2124 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2126 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2127 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2128 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2129 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2130 if(textype == TEXTYPE_DXT5)
2131 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2132 else if(textype == TEXTYPE_DXT3)
2134 (mippixels_start[i-8] & 0x0F)
2135 + (mippixels_start[i-8] >> 4)
2136 + (mippixels_start[i-7] & 0x0F)
2137 + (mippixels_start[i-7] >> 4)
2138 + (mippixels_start[i-6] & 0x0F)
2139 + (mippixels_start[i-6] >> 4)
2140 + (mippixels_start[i-5] & 0x0F)
2141 + (mippixels_start[i-5] >> 4)
2142 ) * (0.125f / 15.0f * 255.0f);
2147 textype = TEXTYPE_BGRA;
2151 // as each block becomes a pixel, we must use pixel count for this
2152 mipwidth = (mipwidth + 3) / 4;
2153 mipheight = (mipheight + 3) / 4;
2154 mipsize = bytesperpixel * mipwidth * mipheight;
2155 mippixels_start = mipnewpixels;
2156 mipsize_total = mipsize_new;
2159 // start mip counting
2160 mippixels = mippixels_start;
2162 // calculate average color if requested
2166 Vector4Clear(avgcolor);
2169 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2171 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2172 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2173 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2174 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2175 if(textype == TEXTYPE_DXT5)
2176 avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2177 else if(textype == TEXTYPE_DXT3)
2179 (mippixels_start[i-8] & 0x0F)
2180 + (mippixels_start[i-8] >> 4)
2181 + (mippixels_start[i-7] & 0x0F)
2182 + (mippixels_start[i-7] >> 4)
2183 + (mippixels_start[i-6] & 0x0F)
2184 + (mippixels_start[i-6] >> 4)
2185 + (mippixels_start[i-5] & 0x0F)
2186 + (mippixels_start[i-5] >> 4)
2187 ) * (0.125f / 15.0f * 255.0f);
2191 f = (float)bytesperblock / size;
2192 avgcolor[0] *= (0.5f / 31.0f) * f;
2193 avgcolor[1] *= (0.5f / 63.0f) * f;
2194 avgcolor[2] *= (0.5f / 31.0f) * f;
2199 for (i = 0;i < mipsize;i += 4)
2201 avgcolor[0] += mippixels[i+2];
2202 avgcolor[1] += mippixels[i+1];
2203 avgcolor[2] += mippixels[i];
2204 avgcolor[3] += mippixels[i+3];
2206 f = (1.0f / 255.0f) * bytesperpixel / size;
2214 // when not requesting mipmaps, do not load them
2215 if(!(flags & TEXF_MIPMAP))
2218 if (dds_miplevels >= 1)
2219 flags |= TEXF_MIPMAP;
2221 flags &= ~TEXF_MIPMAP;
2223 texinfo = R_GetTexTypeInfo(textype, flags);
2225 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2226 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2228 glt->chain = pool->gltchain;
2229 pool->gltchain = glt;
2230 glt->inputwidth = mipwidth;
2231 glt->inputheight = mipheight;
2232 glt->inputdepth = 1;
2234 glt->textype = texinfo;
2235 glt->texturetype = GLTEXTURETYPE_2D;
2236 glt->inputdatasize = ddssize;
2237 glt->glinternalformat = texinfo->glinternalformat;
2238 glt->glformat = texinfo->glformat;
2239 glt->gltype = texinfo->gltype;
2240 glt->bytesperpixel = texinfo->internalbytesperpixel;
2242 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2243 glt->tilewidth = mipwidth;
2244 glt->tileheight = mipheight;
2246 glt->miplevels = dds_miplevels;
2248 // texture uploading can take a while, so make sure we're sending keepalives
2249 CL_KeepaliveMessage(false);
2251 // create the texture object
2252 switch(vid.renderpath)
2254 case RENDERPATH_GL11:
2255 case RENDERPATH_GL13:
2256 case RENDERPATH_GL20:
2257 case RENDERPATH_GLES2:
2259 GL_ActiveTexture(0);
2260 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2261 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2262 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2264 case RENDERPATH_D3D9:
2267 D3DFORMAT d3dformat;
2272 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2273 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2274 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2275 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2276 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2279 d3dpool = D3DPOOL_MANAGED;
2280 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2284 case RENDERPATH_D3D10:
2285 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2287 case RENDERPATH_D3D11:
2288 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2290 case RENDERPATH_SOFT:
2291 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);
2295 // upload the texture
2296 // we need to restore the texture binding after finishing the upload
2297 mipcomplete = false;
2299 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2301 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2302 if (mippixels + mipsize > mippixels_start + mipsize_total)
2304 switch(vid.renderpath)
2306 case RENDERPATH_GL11:
2307 case RENDERPATH_GL13:
2308 case RENDERPATH_GL20:
2309 case RENDERPATH_GLES2:
2312 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2316 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2319 case RENDERPATH_D3D9:
2322 D3DLOCKED_RECT d3dlockedrect;
2323 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2325 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2326 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2332 case RENDERPATH_D3D10:
2333 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2335 case RENDERPATH_D3D11:
2336 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2338 case RENDERPATH_SOFT:
2340 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2342 DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
2343 // DPSOFTRAST calculates its own mipmaps
2344 mip = dds_miplevels;
2347 mippixels += mipsize;
2348 if (mipwidth <= 1 && mipheight <= 1)
2359 // after upload we have to set some parameters...
2360 switch(vid.renderpath)
2362 case RENDERPATH_GL11:
2363 case RENDERPATH_GL13:
2364 case RENDERPATH_GL20:
2365 case RENDERPATH_GLES2:
2366 if (dds_miplevels >= 1 && !mipcomplete)
2368 // need to set GL_TEXTURE_MAX_LEVEL
2369 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2371 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2372 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2374 case RENDERPATH_D3D9:
2376 glt->d3daddressw = 0;
2377 if (glt->flags & TEXF_CLAMP)
2379 glt->d3daddressu = D3DTADDRESS_CLAMP;
2380 glt->d3daddressv = D3DTADDRESS_CLAMP;
2381 if (glt->tiledepth > 1)
2382 glt->d3daddressw = D3DTADDRESS_CLAMP;
2386 glt->d3daddressu = D3DTADDRESS_WRAP;
2387 glt->d3daddressv = D3DTADDRESS_WRAP;
2388 if (glt->tiledepth > 1)
2389 glt->d3daddressw = D3DTADDRESS_WRAP;
2391 glt->d3dmipmaplodbias = 0;
2392 glt->d3dmaxmiplevel = 0;
2393 glt->d3dmaxmiplevelfilter = 0;
2394 if (glt->flags & TEXF_MIPMAP)
2396 glt->d3dminfilter = d3d_filter_mipmin;
2397 glt->d3dmagfilter = d3d_filter_mipmag;
2398 glt->d3dmipfilter = d3d_filter_mipmix;
2402 glt->d3dminfilter = d3d_filter_flatmin;
2403 glt->d3dmagfilter = d3d_filter_flatmag;
2404 glt->d3dmipfilter = d3d_filter_flatmix;
2408 case RENDERPATH_D3D10:
2409 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2411 case RENDERPATH_D3D11:
2412 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2414 case RENDERPATH_SOFT:
2415 if (glt->flags & TEXF_FORCELINEAR)
2416 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2417 else if (glt->flags & TEXF_FORCENEAREST)
2418 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2419 else if (glt->flags & TEXF_MIPMAP)
2420 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2422 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2428 Mem_Free((unsigned char *) mippixels_start);
2429 return (rtexture_t *)glt;
2432 int R_TextureWidth(rtexture_t *rt)
2434 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2437 int R_TextureHeight(rtexture_t *rt)
2439 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2442 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2444 gltexture_t *glt = (gltexture_t *)rt;
2446 Host_Error("R_UpdateTexture: no data supplied");
2448 Host_Error("R_UpdateTexture: no texture supplied");
2449 if (!glt->texnum && !glt->d3dtexture)
2451 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2454 // update part of the texture
2455 if (glt->bufferpixels)
2458 int bpp = glt->bytesperpixel;
2459 int inputskip = width*bpp;
2460 int outputskip = glt->tilewidth*bpp;
2461 const unsigned char *input = data;
2462 unsigned char *output = glt->bufferpixels;
2463 if (glt->inputdepth != 1 || glt->sides != 1)
2464 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2474 input -= y*inputskip;
2477 if (width > glt->tilewidth - x)
2478 width = glt->tilewidth - x;
2479 if (height > glt->tileheight - y)
2480 height = glt->tileheight - y;
2481 if (width < 1 || height < 1)
2484 glt->buffermodified = true;
2485 output += y*outputskip + x*bpp;
2486 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2487 memcpy(output, input, width*bpp);
2489 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2490 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2492 R_UploadFullTexture(glt, data);
2495 int R_RealGetTexture(rtexture_t *rt)
2500 glt = (gltexture_t *)rt;
2501 if (glt->flags & GLTEXF_DYNAMIC)
2502 R_UpdateDynamicTexture(glt);
2503 if (glt->buffermodified && glt->bufferpixels)
2505 glt->buffermodified = false;
2506 R_UploadFullTexture(glt, glt->bufferpixels);
2515 void R_ClearTexture (rtexture_t *rt)
2517 gltexture_t *glt = (gltexture_t *)rt;
2519 R_UploadFullTexture(glt, NULL);
2522 int R_PicmipForFlags(int flags)
2525 if(flags & TEXF_PICMIP)
2527 miplevel += gl_picmip.integer;
2528 if (flags & TEXF_ISWORLD)
2530 if (r_picmipworld.integer)
2531 miplevel += gl_picmip_world.integer;
2535 else if (flags & TEXF_ISSPRITE)
2537 if (r_picmipsprites.integer)
2538 miplevel += gl_picmip_sprites.integer;
2543 miplevel += gl_picmip_other.integer;
2545 return max(0, miplevel);