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_RGB , 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_RGB , 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_RGB , 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;
1158 if (glt->textype->textype == TEXTYPE_PALETTE)
1160 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1161 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1162 prevbuffer = colorconvertbuffer;
1164 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1166 // multiply RGB channels by A channel before uploading
1168 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1170 alpha = prevbuffer[i+3];
1171 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1172 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1173 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1174 colorconvertbuffer[i+3] = alpha;
1176 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;
1192 // do the appropriate upload type...
1193 switch(vid.renderpath)
1195 case RENDERPATH_GL11:
1196 case RENDERPATH_GL13:
1197 case RENDERPATH_GL20:
1198 case RENDERPATH_GLES2:
1201 // we need to restore the texture binding after finishing the upload
1202 GL_ActiveTexture(0);
1203 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1204 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1206 if (qglGetCompressedTexImageARB)
1208 if (gl_texturecompression.integer >= 2)
1209 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1211 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1214 switch(glt->texturetype)
1216 case GLTEXTURETYPE_2D:
1217 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1218 if (glt->flags & TEXF_MIPMAP)
1220 while (width > 1 || height > 1 || depth > 1)
1222 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1223 prevbuffer = resizebuffer;
1224 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1228 case GLTEXTURETYPE_3D:
1229 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1230 if (glt->flags & TEXF_MIPMAP)
1232 while (width > 1 || height > 1 || depth > 1)
1234 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1235 prevbuffer = resizebuffer;
1236 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1240 case GLTEXTURETYPE_CUBEMAP:
1241 // convert and upload each side in turn,
1242 // from a continuous block of input texels
1243 texturebuffer = (unsigned char *)prevbuffer;
1244 for (i = 0;i < 6;i++)
1246 prevbuffer = texturebuffer;
1247 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1248 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1250 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1251 prevbuffer = resizebuffer;
1254 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1256 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1257 prevbuffer = resizebuffer;
1260 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1261 if (glt->flags & TEXF_MIPMAP)
1263 while (width > 1 || height > 1 || depth > 1)
1265 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1266 prevbuffer = resizebuffer;
1267 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1273 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1274 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1276 case RENDERPATH_D3D9:
1278 if (!(glt->flags & TEXF_RENDERTARGET))
1280 D3DLOCKED_RECT d3dlockedrect;
1281 D3DLOCKED_BOX d3dlockedbox;
1282 switch(glt->texturetype)
1284 case GLTEXTURETYPE_2D:
1285 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1288 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1290 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1291 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1294 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1296 while (width > 1 || height > 1 || depth > 1)
1298 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1299 prevbuffer = resizebuffer;
1300 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1302 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1303 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1309 case GLTEXTURETYPE_3D:
1310 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1312 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1313 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1314 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1317 if (glt->flags & TEXF_MIPMAP)
1319 while (width > 1 || height > 1 || depth > 1)
1321 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1322 prevbuffer = resizebuffer;
1323 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1325 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1326 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1327 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1333 case GLTEXTURETYPE_CUBEMAP:
1334 // convert and upload each side in turn,
1335 // from a continuous block of input texels
1336 texturebuffer = (unsigned char *)prevbuffer;
1337 for (i = 0;i < 6;i++)
1339 prevbuffer = texturebuffer;
1340 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1341 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1343 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1344 prevbuffer = resizebuffer;
1347 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1349 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1350 prevbuffer = resizebuffer;
1353 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1355 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1356 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1359 if (glt->flags & TEXF_MIPMAP)
1361 while (width > 1 || height > 1 || depth > 1)
1363 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1364 prevbuffer = resizebuffer;
1365 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1367 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1368 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1377 glt->d3daddressw = 0;
1378 if (glt->flags & TEXF_CLAMP)
1380 glt->d3daddressu = D3DTADDRESS_CLAMP;
1381 glt->d3daddressv = D3DTADDRESS_CLAMP;
1382 if (glt->tiledepth > 1)
1383 glt->d3daddressw = D3DTADDRESS_CLAMP;
1387 glt->d3daddressu = D3DTADDRESS_WRAP;
1388 glt->d3daddressv = D3DTADDRESS_WRAP;
1389 if (glt->tiledepth > 1)
1390 glt->d3daddressw = D3DTADDRESS_WRAP;
1392 glt->d3dmipmaplodbias = 0;
1393 glt->d3dmaxmiplevel = 0;
1394 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1395 if (glt->flags & TEXF_FORCELINEAR)
1397 glt->d3dminfilter = D3DTEXF_LINEAR;
1398 glt->d3dmagfilter = D3DTEXF_LINEAR;
1399 glt->d3dmipfilter = D3DTEXF_POINT;
1401 else if (glt->flags & TEXF_FORCENEAREST)
1403 glt->d3dminfilter = D3DTEXF_POINT;
1404 glt->d3dmagfilter = D3DTEXF_POINT;
1405 glt->d3dmipfilter = D3DTEXF_POINT;
1407 else if (glt->flags & TEXF_MIPMAP)
1409 glt->d3dminfilter = d3d_filter_mipmin;
1410 glt->d3dmagfilter = d3d_filter_mipmag;
1411 glt->d3dmipfilter = d3d_filter_mipmix;
1415 glt->d3dminfilter = d3d_filter_flatmin;
1416 glt->d3dmagfilter = d3d_filter_flatmag;
1417 glt->d3dmipfilter = d3d_filter_flatmix;
1421 case RENDERPATH_D3D10:
1422 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1424 case RENDERPATH_D3D11:
1425 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1427 case RENDERPATH_SOFT:
1428 switch(glt->texturetype)
1430 case GLTEXTURETYPE_2D:
1431 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1433 case GLTEXTURETYPE_3D:
1434 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1436 case GLTEXTURETYPE_CUBEMAP:
1437 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1439 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1440 // convert and upload each side in turn,
1441 // from a continuous block of input texels
1442 // copy the results into combinedbuffer
1443 texturebuffer = (unsigned char *)prevbuffer;
1444 for (i = 0;i < 6;i++)
1446 prevbuffer = texturebuffer;
1447 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1448 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1450 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1451 prevbuffer = resizebuffer;
1454 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1456 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1457 prevbuffer = resizebuffer;
1459 memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1461 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1462 Mem_Free(combinedbuffer);
1465 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1468 if (glt->flags & TEXF_FORCELINEAR)
1469 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1470 else if (glt->flags & TEXF_FORCENEAREST)
1471 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1472 else if (glt->flags & TEXF_MIPMAP)
1473 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1475 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1480 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)
1484 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1485 textypeinfo_t *texinfo, *texinfo2;
1486 unsigned char *temppixels = NULL;
1488 if (cls.state == ca_dedicated)
1491 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1493 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1496 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1498 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1502 texinfo = R_GetTexTypeInfo(textype, flags);
1503 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1506 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1510 if (textype == TEXTYPE_RGBA)
1513 static int rgbaswapindices[4] = {2, 1, 0, 3};
1514 textype = TEXTYPE_BGRA;
1515 texinfo = R_GetTexTypeInfo(textype, flags);
1516 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1517 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1521 // clear the alpha flag if the texture has no transparent pixels
1524 case TEXTYPE_PALETTE:
1525 if (flags & TEXF_ALPHA)
1527 flags &= ~TEXF_ALPHA;
1530 for (i = 0;i < size;i++)
1532 if (((unsigned char *)&palette[data[i]])[3] < 255)
1534 flags |= TEXF_ALPHA;
1543 if (flags & TEXF_ALPHA)
1545 flags &= ~TEXF_ALPHA;
1548 for (i = 3;i < size;i += 4)
1552 flags |= TEXF_ALPHA;
1559 case TEXTYPE_SHADOWMAP:
1566 flags |= TEXF_ALPHA;
1569 flags |= TEXF_ALPHA;
1571 case TEXTYPE_COLORBUFFER:
1572 case TEXTYPE_COLORBUFFER16F:
1573 case TEXTYPE_COLORBUFFER32F:
1574 flags |= TEXF_ALPHA;
1577 Sys_Error("R_LoadTexture: unknown texture type");
1580 texinfo2 = R_GetTexTypeInfo(textype, flags);
1581 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1584 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1586 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1588 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1590 glt->chain = pool->gltchain;
1591 pool->gltchain = glt;
1592 glt->inputwidth = width;
1593 glt->inputheight = height;
1594 glt->inputdepth = depth;
1596 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
1597 glt->textype = texinfo;
1598 glt->texturetype = texturetype;
1599 glt->inputdatasize = size;
1600 glt->palette = palette;
1601 glt->glinternalformat = texinfo->glinternalformat;
1602 glt->glformat = texinfo->glformat;
1603 glt->gltype = texinfo->gltype;
1604 glt->bytesperpixel = texinfo->internalbytesperpixel;
1605 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1608 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1609 // init the dynamic texture attributes, too [11/22/2007 Black]
1610 glt->updatecallback = NULL;
1611 glt->updatacallback_data = NULL;
1613 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1615 // upload the texture
1616 // data may be NULL (blank texture for dynamic rendering)
1617 switch(vid.renderpath)
1619 case RENDERPATH_GL11:
1620 case RENDERPATH_GL13:
1621 case RENDERPATH_GL20:
1622 case RENDERPATH_GLES2:
1624 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1626 case RENDERPATH_D3D9:
1629 D3DFORMAT d3dformat;
1634 d3dpool = D3DPOOL_MANAGED;
1635 if (flags & TEXF_RENDERTARGET)
1637 d3dusage |= D3DUSAGE_RENDERTARGET;
1638 d3dpool = D3DPOOL_DEFAULT;
1642 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1643 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1644 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1645 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
1646 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
1647 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
1648 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1649 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1650 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1652 glt->d3dformat = d3dformat;
1653 glt->d3dusage = d3dusage;
1654 glt->d3dpool = d3dpool;
1655 glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1656 if (glt->d3disdepthsurface)
1658 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1659 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1661 else if (glt->tiledepth > 1)
1663 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)))
1664 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1666 else if (glt->sides == 6)
1668 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1669 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1673 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)))
1674 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1679 case RENDERPATH_D3D10:
1680 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1682 case RENDERPATH_D3D11:
1683 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1685 case RENDERPATH_SOFT:
1690 case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1691 case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1692 case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1693 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1694 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
1695 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
1696 case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1697 case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1698 default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1700 if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1701 if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1702 if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1703 if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1704 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1709 R_UploadFullTexture(glt, data);
1710 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1711 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1713 // free any temporary processing buffer we allocated...
1715 Mem_Free(temppixels);
1717 // texture converting and uploading can take a while, so make sure we're sending keepalives
1718 // FIXME: this causes rendering during R_Shadow_DrawLights
1719 // CL_KeepaliveMessage(false);
1721 return (rtexture_t *)glt;
1724 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)
1726 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1729 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)
1731 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1734 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)
1736 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1739 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1741 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1743 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1745 flags |= TEXF_FORCENEAREST;
1746 if (precision <= 16)
1747 flags |= TEXF_LOWPRECISION;
1751 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1753 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1756 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1758 gltexture_t *glt = (gltexture_t *)rt;
1761 int bytesperpixel = 0;
1762 int bytesperblock = 0;
1764 int dds_format_flags;
1772 GLint internalformat;
1773 const char *ddsfourcc;
1775 return -1; // NULL pointer
1776 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1777 return -2; // broken driver - crashes on reading internal format
1778 if (!qglGetTexLevelParameteriv)
1780 GL_ActiveTexture(0);
1781 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1782 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1783 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1784 switch(internalformat)
1786 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1787 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1788 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1789 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1790 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1792 // if premultiplied alpha, say so in the DDS file
1793 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1795 switch(internalformat)
1797 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1798 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1801 if (!bytesperblock && skipuncompressed)
1802 return -3; // skipped
1803 memset(mipinfo, 0, sizeof(mipinfo));
1804 mipinfo[0][0] = glt->tilewidth;
1805 mipinfo[0][1] = glt->tileheight;
1807 if (glt->flags & TEXF_MIPMAP)
1809 for (mip = 1;mip < 16;mip++)
1811 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1812 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1813 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1821 for (mip = 0;mip < mipmaps;mip++)
1823 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1824 mipinfo[mip][3] = ddssize;
1825 ddssize += mipinfo[mip][2];
1827 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1830 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1834 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1835 dds_format_flags = 0x4; // DDPF_FOURCC
1839 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1840 dds_format_flags = 0x40; // DDPF_RGB
1844 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1845 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1848 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1849 memcpy(dds, "DDS ", 4);
1850 StoreLittleLong(dds+4, ddssize);
1851 StoreLittleLong(dds+8, dds_flags);
1852 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1853 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1854 StoreLittleLong(dds+24, 1); // depth
1855 StoreLittleLong(dds+28, mipmaps); // mipmaps
1856 StoreLittleLong(dds+76, 32); // format size
1857 StoreLittleLong(dds+80, dds_format_flags);
1858 StoreLittleLong(dds+108, dds_caps1);
1859 StoreLittleLong(dds+112, dds_caps2);
1862 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1863 memcpy(dds+84, ddsfourcc, 4);
1864 for (mip = 0;mip < mipmaps;mip++)
1866 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1871 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1872 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1873 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1874 for (mip = 0;mip < mipmaps;mip++)
1876 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1879 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1880 ret = FS_WriteFile(filename, dds, ddssize);
1882 return ret ? ddssize : -5;
1885 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
1887 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1890 int bytesperblock, bytesperpixel;
1893 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1894 textypeinfo_t *texinfo;
1895 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1897 GLint oldbindtexnum = 0;
1898 const unsigned char *mippixels, *ddspixels, *mippixels_start;
1900 fs_offset_t ddsfilesize;
1901 unsigned int ddssize;
1902 qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
1904 if (cls.state == ca_dedicated)
1907 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1908 ddssize = ddsfilesize;
1912 if(r_texture_dds_load_logfailure.integer)
1913 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1914 return NULL; // not found
1917 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1920 Con_Printf("^1%s: not a DDS image\n", filename);
1924 //dds_flags = BuffLittleLong(dds+8);
1925 dds_format_flags = BuffLittleLong(dds+80);
1926 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1927 dds_width = BuffLittleLong(dds+16);
1928 dds_height = BuffLittleLong(dds+12);
1929 ddspixels = dds + 128;
1931 if(r_texture_dds_load_alphamode.integer == 0)
1932 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1933 flags &= ~TEXF_ALPHA;
1935 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1936 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1938 // very sloppy BGRA 32bit identification
1939 textype = TEXTYPE_BGRA;
1942 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1943 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1946 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1949 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1952 for (i = 3;i < size;i += 4)
1953 if (ddspixels[i] < 255)
1956 flags &= ~TEXF_ALPHA;
1959 else if (!memcmp(dds+84, "DXT1", 4))
1961 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1962 // LordHavoc: it is my belief that this does not infringe on the
1963 // patent because it is not decoding pixels...
1964 textype = TEXTYPE_DXT1;
1967 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1968 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1969 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1972 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1975 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1977 if(r_texture_dds_load_alphamode.integer == 1)
1980 for (i = 0;i < size;i += bytesperblock)
1981 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1983 // NOTE: this assumes sizeof(unsigned int) == 4
1984 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1985 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1986 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1990 textype = TEXTYPE_DXT1A;
1992 flags &= ~TEXF_ALPHA;
1996 flags &= ~TEXF_ALPHA;
2000 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2002 if(!memcmp(dds+84, "DXT2", 4))
2004 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2006 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2011 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2013 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2016 textype = TEXTYPE_DXT3;
2019 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2020 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2023 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2026 // we currently always assume alpha
2028 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2030 if(!memcmp(dds+84, "DXT4", 4))
2032 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2034 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2039 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2041 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2044 textype = TEXTYPE_DXT5;
2047 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2048 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2051 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2054 // we currently always assume alpha
2059 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2063 force_swdecode = false;
2066 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
2068 if(r_texture_dds_swdecode.integer > 1)
2069 force_swdecode = true;
2073 if(r_texture_dds_swdecode.integer < 1)
2079 force_swdecode = true;
2083 // return whether this texture is transparent
2085 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2087 // if we SW decode, choose 2 sizes bigger
2090 // this is quarter res, so do not scale down more than we have to
2094 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2097 // this is where we apply gl_picmip
2098 mippixels_start = ddspixels;
2099 mipwidth = dds_width;
2100 mipheight = dds_height;
2101 while(miplevel >= 1 && dds_miplevels >= 1)
2103 if (mipwidth <= 1 && mipheight <= 1)
2105 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2106 mippixels_start += mipsize; // just skip
2114 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2115 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2117 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2119 // fake decode S3TC if needed
2122 int mipsize_new = mipsize_total / bytesperblock * 4;
2123 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2124 unsigned char *p = mipnewpixels;
2125 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2127 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2128 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2129 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2130 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2131 if(textype == TEXTYPE_DXT5)
2132 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2133 else if(textype == TEXTYPE_DXT3)
2135 (mippixels_start[i-8] & 0x0F)
2136 + (mippixels_start[i-8] >> 4)
2137 + (mippixels_start[i-7] & 0x0F)
2138 + (mippixels_start[i-7] >> 4)
2139 + (mippixels_start[i-6] & 0x0F)
2140 + (mippixels_start[i-6] >> 4)
2141 + (mippixels_start[i-5] & 0x0F)
2142 + (mippixels_start[i-5] >> 4)
2143 ) * (0.125f / 15.0f * 255.0f);
2148 textype = TEXTYPE_BGRA;
2152 // as each block becomes a pixel, we must use pixel count for this
2153 mipwidth = (mipwidth + 3) / 4;
2154 mipheight = (mipheight + 3) / 4;
2155 mipsize = bytesperpixel * mipwidth * mipheight;
2156 mippixels_start = mipnewpixels;
2157 mipsize_total = mipsize_new;
2160 // start mip counting
2161 mippixels = mippixels_start;
2163 // calculate average color if requested
2167 Vector4Clear(avgcolor);
2170 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2172 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2173 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2174 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2175 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2176 if(textype == TEXTYPE_DXT5)
2177 avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2178 else if(textype == TEXTYPE_DXT3)
2180 (mippixels_start[i-8] & 0x0F)
2181 + (mippixels_start[i-8] >> 4)
2182 + (mippixels_start[i-7] & 0x0F)
2183 + (mippixels_start[i-7] >> 4)
2184 + (mippixels_start[i-6] & 0x0F)
2185 + (mippixels_start[i-6] >> 4)
2186 + (mippixels_start[i-5] & 0x0F)
2187 + (mippixels_start[i-5] >> 4)
2188 ) * (0.125f / 15.0f * 255.0f);
2192 f = (float)bytesperblock / size;
2193 avgcolor[0] *= (0.5f / 31.0f) * f;
2194 avgcolor[1] *= (0.5f / 63.0f) * f;
2195 avgcolor[2] *= (0.5f / 31.0f) * f;
2200 for (i = 0;i < mipsize;i += 4)
2202 avgcolor[0] += mippixels[i+2];
2203 avgcolor[1] += mippixels[i+1];
2204 avgcolor[2] += mippixels[i];
2205 avgcolor[3] += mippixels[i+3];
2207 f = (1.0f / 255.0f) * bytesperpixel / size;
2215 // when not requesting mipmaps, do not load them
2216 if(!(flags & TEXF_MIPMAP))
2219 if (dds_miplevels >= 1)
2220 flags |= TEXF_MIPMAP;
2222 flags &= ~TEXF_MIPMAP;
2224 texinfo = R_GetTexTypeInfo(textype, flags);
2226 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2227 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2229 glt->chain = pool->gltchain;
2230 pool->gltchain = glt;
2231 glt->inputwidth = mipwidth;
2232 glt->inputheight = mipheight;
2233 glt->inputdepth = 1;
2235 glt->textype = texinfo;
2236 glt->texturetype = GLTEXTURETYPE_2D;
2237 glt->inputdatasize = ddssize;
2238 glt->glinternalformat = texinfo->glinternalformat;
2239 glt->glformat = texinfo->glformat;
2240 glt->gltype = texinfo->gltype;
2241 glt->bytesperpixel = texinfo->internalbytesperpixel;
2243 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2244 glt->tilewidth = mipwidth;
2245 glt->tileheight = mipheight;
2247 glt->miplevels = dds_miplevels;
2249 // texture uploading can take a while, so make sure we're sending keepalives
2250 CL_KeepaliveMessage(false);
2252 // create the texture object
2253 switch(vid.renderpath)
2255 case RENDERPATH_GL11:
2256 case RENDERPATH_GL13:
2257 case RENDERPATH_GL20:
2258 case RENDERPATH_GLES2:
2260 GL_ActiveTexture(0);
2261 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2262 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2263 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2265 case RENDERPATH_D3D9:
2268 D3DFORMAT d3dformat;
2273 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2274 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2275 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2276 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2277 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2280 d3dpool = D3DPOOL_MANAGED;
2281 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2285 case RENDERPATH_D3D10:
2286 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2288 case RENDERPATH_D3D11:
2289 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2291 case RENDERPATH_SOFT:
2292 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);
2296 // upload the texture
2297 // we need to restore the texture binding after finishing the upload
2298 mipcomplete = false;
2300 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2302 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2303 if (mippixels + mipsize > mippixels_start + mipsize_total)
2305 switch(vid.renderpath)
2307 case RENDERPATH_GL11:
2308 case RENDERPATH_GL13:
2309 case RENDERPATH_GL20:
2310 case RENDERPATH_GLES2:
2313 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2317 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2320 case RENDERPATH_D3D9:
2323 D3DLOCKED_RECT d3dlockedrect;
2324 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2326 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2327 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2333 case RENDERPATH_D3D10:
2334 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2336 case RENDERPATH_D3D11:
2337 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2339 case RENDERPATH_SOFT:
2341 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2343 DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
2344 // DPSOFTRAST calculates its own mipmaps
2345 mip = dds_miplevels;
2348 mippixels += mipsize;
2349 if (mipwidth <= 1 && mipheight <= 1)
2360 // after upload we have to set some parameters...
2361 switch(vid.renderpath)
2363 case RENDERPATH_GL11:
2364 case RENDERPATH_GL13:
2365 case RENDERPATH_GL20:
2366 case RENDERPATH_GLES2:
2367 if (dds_miplevels >= 1 && !mipcomplete)
2369 // need to set GL_TEXTURE_MAX_LEVEL
2370 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2372 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2373 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2375 case RENDERPATH_D3D9:
2377 glt->d3daddressw = 0;
2378 if (glt->flags & TEXF_CLAMP)
2380 glt->d3daddressu = D3DTADDRESS_CLAMP;
2381 glt->d3daddressv = D3DTADDRESS_CLAMP;
2382 if (glt->tiledepth > 1)
2383 glt->d3daddressw = D3DTADDRESS_CLAMP;
2387 glt->d3daddressu = D3DTADDRESS_WRAP;
2388 glt->d3daddressv = D3DTADDRESS_WRAP;
2389 if (glt->tiledepth > 1)
2390 glt->d3daddressw = D3DTADDRESS_WRAP;
2392 glt->d3dmipmaplodbias = 0;
2393 glt->d3dmaxmiplevel = 0;
2394 glt->d3dmaxmiplevelfilter = 0;
2395 if (glt->flags & TEXF_MIPMAP)
2397 glt->d3dminfilter = d3d_filter_mipmin;
2398 glt->d3dmagfilter = d3d_filter_mipmag;
2399 glt->d3dmipfilter = d3d_filter_mipmix;
2403 glt->d3dminfilter = d3d_filter_flatmin;
2404 glt->d3dmagfilter = d3d_filter_flatmag;
2405 glt->d3dmipfilter = d3d_filter_flatmix;
2409 case RENDERPATH_D3D10:
2410 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2412 case RENDERPATH_D3D11:
2413 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2415 case RENDERPATH_SOFT:
2416 if (glt->flags & TEXF_FORCELINEAR)
2417 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2418 else if (glt->flags & TEXF_FORCENEAREST)
2419 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2420 else if (glt->flags & TEXF_MIPMAP)
2421 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2423 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2429 Mem_Free((unsigned char *) mippixels_start);
2430 return (rtexture_t *)glt;
2433 int R_TextureWidth(rtexture_t *rt)
2435 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2438 int R_TextureHeight(rtexture_t *rt)
2440 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2443 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2445 gltexture_t *glt = (gltexture_t *)rt;
2447 Host_Error("R_UpdateTexture: no data supplied");
2449 Host_Error("R_UpdateTexture: no texture supplied");
2450 if (!glt->texnum && !glt->d3dtexture)
2452 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2455 // update part of the texture
2456 if (glt->bufferpixels)
2459 int bpp = glt->bytesperpixel;
2460 int inputskip = width*bpp;
2461 int outputskip = glt->tilewidth*bpp;
2462 const unsigned char *input = data;
2463 unsigned char *output = glt->bufferpixels;
2464 if (glt->inputdepth != 1 || glt->sides != 1)
2465 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2475 input -= y*inputskip;
2478 if (width > glt->tilewidth - x)
2479 width = glt->tilewidth - x;
2480 if (height > glt->tileheight - y)
2481 height = glt->tileheight - y;
2482 if (width < 1 || height < 1)
2485 glt->buffermodified = true;
2486 output += y*outputskip + x*bpp;
2487 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2488 memcpy(output, input, width*bpp);
2490 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2491 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2493 R_UploadFullTexture(glt, data);
2496 int R_RealGetTexture(rtexture_t *rt)
2501 glt = (gltexture_t *)rt;
2502 if (glt->flags & GLTEXF_DYNAMIC)
2503 R_UpdateDynamicTexture(glt);
2504 if (glt->buffermodified && glt->bufferpixels)
2506 glt->buffermodified = false;
2507 R_UploadFullTexture(glt, glt->bufferpixels);
2516 void R_ClearTexture (rtexture_t *rt)
2518 gltexture_t *glt = (gltexture_t *)rt;
2520 R_UploadFullTexture(glt, NULL);
2523 int R_PicmipForFlags(int flags)
2526 if(flags & TEXF_PICMIP)
2528 miplevel += gl_picmip.integer;
2529 if (flags & TEXF_ISWORLD)
2531 if (r_picmipworld.integer)
2532 miplevel += gl_picmip_world.integer;
2536 else if (flags & TEXF_ISSPRITE)
2538 if (r_picmipsprites.integer)
2539 miplevel += gl_picmip_sprites.integer;
2544 miplevel += gl_picmip_other.integer;
2546 return max(0, miplevel);