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, 3 , GL_BGRA , GL_UNSIGNED_BYTE };
79 static textypeinfo_t textype_palette_alpha = {TEXTYPE_PALETTE , 1, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
80 static textypeinfo_t textype_rgba = {TEXTYPE_RGBA , 4, 4, 4.0f, 3 , GL_RGBA , GL_UNSIGNED_BYTE };
81 static textypeinfo_t textype_rgba_alpha = {TEXTYPE_RGBA , 4, 4, 4.0f, 4 , GL_RGBA , GL_UNSIGNED_BYTE };
82 static textypeinfo_t textype_rgba_compress = {TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
83 static textypeinfo_t textype_rgba_alpha_compress = {TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA , GL_UNSIGNED_BYTE };
84 static textypeinfo_t textype_bgra = {TEXTYPE_BGRA , 4, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE };
85 static textypeinfo_t textype_bgra_alpha = {TEXTYPE_BGRA , 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
86 static textypeinfo_t textype_bgra_compress = {TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
87 static textypeinfo_t textype_bgra_alpha_compress = {TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_BGRA , GL_UNSIGNED_BYTE };
88 static textypeinfo_t textype_shadowmap16 = {TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
89 static textypeinfo_t textype_shadowmap24 = {TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
90 static textypeinfo_t textype_alpha = {TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
91 static textypeinfo_t textype_dxt1 = {TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
92 static textypeinfo_t textype_dxt1a = {TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0 , 0 };
93 static textypeinfo_t textype_dxt3 = {TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0 , 0 };
94 static textypeinfo_t textype_dxt5 = {TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0 , 0 };
95 static textypeinfo_t textype_colorbuffer = {TEXTYPE_COLORBUFFER, 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
98 typedef enum gltexturetype_e
102 GLTEXTURETYPE_CUBEMAP,
107 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB};
108 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
109 static int cubemapside[6] =
111 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
112 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
113 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
114 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
115 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
116 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
119 typedef struct gltexture_s
121 // this portion of the struct is exposed to the R_GetTexture macro for
122 // speed reasons, must be identical in rtexture_t!
123 int texnum; // GL texture slot number
124 qboolean dirty; // indicates that R_RealGetTexture should be called
125 int gltexturetypeenum; // used by R_Mesh_TexBind
126 // d3d stuff the backend needs
129 qboolean d3disdepthsurface; // for depth/stencil surfaces
139 int d3dmaxmiplevelfilter;
140 int d3dmipmaplodbias;
144 // dynamic texture stuff [11/22/2007 Black]
145 updatecallback_t updatecallback;
146 void *updatacallback_data;
147 // --- [11/22/2007 Black]
149 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
150 unsigned char *bufferpixels;
151 qboolean buffermodified;
153 // pointer to texturepool (check this to see if the texture is allocated)
154 struct gltexturepool_s *pool;
155 // pointer to next texture in texturepool chain
156 struct gltexture_s *chain;
157 // name of the texture (this might be removed someday), no duplicates
158 char identifier[MAX_QPATH + 32];
159 // original data size in *inputtexels
160 int inputwidth, inputheight, inputdepth;
161 // copy of the original texture(s) supplied to the upload function, for
162 // delayed uploads (non-precached)
163 unsigned char *inputtexels;
164 // original data size in *inputtexels
166 // flags supplied to the LoadTexture function
167 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
171 // pointer to one of the textype_ structs
172 textypeinfo_t *textype;
173 // one of the GLTEXTURETYPE_ values
175 // palette if the texture is TEXTYPE_PALETTE
176 const unsigned int *palette;
177 // actual stored texture size after gl_picmip and gl_max_size are applied
178 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
179 int tilewidth, tileheight, tiledepth;
180 // 1 or 6 depending on texturetype
182 // how many mipmap levels in this texture
186 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
189 int glinternalformat;
190 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
195 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
197 typedef struct gltexturepool_s
199 unsigned int sentinel;
200 struct gltexture_s *gltchain;
201 struct gltexturepool_s *next;
205 static gltexturepool_t *gltexturepoolchain = NULL;
207 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
208 static int resizebuffersize = 0;
209 static const unsigned char *texturebuffer;
211 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
216 return &textype_dxt1;
218 return &textype_dxt1a;
220 return &textype_dxt3;
222 return &textype_dxt5;
223 case TEXTYPE_PALETTE:
224 return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
226 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
227 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress;
228 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba;
230 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
231 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress;
232 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra;
234 return &textype_alpha;
235 case TEXTYPE_SHADOWMAP:
236 return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
237 case TEXTYPE_COLORBUFFER:
238 return &textype_colorbuffer;
240 Host_Error("R_GetTexTypeInfo: unknown texture format");
246 // dynamic texture code [11/22/2007 Black]
247 void R_MarkDirtyTexture(rtexture_t *rt) {
248 gltexture_t *glt = (gltexture_t*) rt;
253 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
254 if (glt->flags & GLTEXF_DYNAMIC)
256 // mark it as dirty, so R_RealGetTexture gets called
261 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
262 gltexture_t *glt = (gltexture_t*) rt;
267 glt->flags |= GLTEXF_DYNAMIC;
268 glt->updatecallback = updatecallback;
269 glt->updatacallback_data = data;
272 static void R_UpdateDynamicTexture(gltexture_t *glt) {
274 if( glt->updatecallback ) {
275 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
279 void R_PurgeTexture(rtexture_t *rt)
281 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
286 void R_FreeTexture(rtexture_t *rt)
288 gltexture_t *glt, **gltpointer;
290 glt = (gltexture_t *)rt;
292 Host_Error("R_FreeTexture: texture == NULL");
294 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
295 if (*gltpointer == glt)
296 *gltpointer = glt->chain;
298 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
300 switch(vid.renderpath)
302 case RENDERPATH_GL11:
303 case RENDERPATH_GL13:
304 case RENDERPATH_GL20:
305 case RENDERPATH_CGGL:
306 case RENDERPATH_GLES2:
310 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
313 case RENDERPATH_D3D9:
315 if (glt->d3disdepthsurface)
316 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
317 else if (glt->tiledepth > 1)
318 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
319 else if (glt->sides == 6)
320 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
322 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
323 glt->d3dtexture = NULL;
326 case RENDERPATH_D3D10:
327 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
329 case RENDERPATH_D3D11:
330 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
332 case RENDERPATH_SOFT:
334 DPSOFTRAST_Texture_Free(glt->texnum);
338 if (glt->inputtexels)
339 Mem_Free(glt->inputtexels);
340 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
343 rtexturepool_t *R_AllocTexturePool(void)
345 gltexturepool_t *pool;
346 if (texturemempool == NULL)
348 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
351 pool->next = gltexturepoolchain;
352 gltexturepoolchain = pool;
353 pool->sentinel = TEXTUREPOOL_SENTINEL;
354 return (rtexturepool_t *)pool;
357 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
359 gltexturepool_t *pool, **poolpointer;
360 if (rtexturepool == NULL)
362 if (*rtexturepool == NULL)
364 pool = (gltexturepool_t *)(*rtexturepool);
365 *rtexturepool = NULL;
366 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
367 Host_Error("R_FreeTexturePool: pool already freed");
368 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
369 if (*poolpointer == pool)
370 *poolpointer = pool->next;
372 Host_Error("R_FreeTexturePool: pool not linked");
373 while (pool->gltchain)
374 R_FreeTexture((rtexture_t *)pool->gltchain);
379 typedef struct glmode_s
382 int minification, magnification;
383 DPSOFTRAST_TEXTURE_FILTER dpsoftrastfilter_mipmap, dpsoftrastfilter_nomipmap;
387 static glmode_t modes[6] =
389 {"GL_NEAREST", GL_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
390 {"GL_LINEAR", GL_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
391 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
392 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
393 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
394 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR}
398 typedef struct d3dmode_s
405 static d3dmode_t d3dmodes[6] =
407 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
408 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
409 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
410 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
411 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
412 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
416 static void GL_TextureMode_f (void)
421 gltexturepool_t *pool;
425 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
426 for (i = 0;i < 6;i++)
428 if (gl_filter_min == modes[i].minification)
430 Con_Printf("%s\n", modes[i].name);
434 Con_Print("current filter is unknown???\n");
438 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
439 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
443 Con_Print("bad filter name\n");
447 gl_filter_min = modes[i].minification;
448 gl_filter_mag = modes[i].magnification;
449 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
451 dpsoftrast_filter_mipmap = modes[i].dpsoftrastfilter_mipmap;
452 dpsoftrast_filter_nomipmap = modes[i].dpsoftrastfilter_nomipmap;
454 switch(vid.renderpath)
456 case RENDERPATH_GL11:
457 case RENDERPATH_GL13:
458 case RENDERPATH_GL20:
459 case RENDERPATH_CGGL:
460 case RENDERPATH_GLES2:
461 // change all the existing mipmap texture objects
462 // FIXME: force renderer(/client/something?) restart instead?
465 for (pool = gltexturepoolchain;pool;pool = pool->next)
467 for (glt = pool->gltchain;glt;glt = glt->chain)
469 // only update already uploaded images
470 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
472 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
473 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
474 if (glt->flags & TEXF_MIPMAP)
476 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
480 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
482 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
483 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
488 case RENDERPATH_D3D9:
490 d3d_filter_flatmin = d3dmodes[i].m1;
491 d3d_filter_flatmag = d3dmodes[i].m1;
492 d3d_filter_flatmix = D3DTEXF_POINT;
493 d3d_filter_mipmin = d3dmodes[i].m1;
494 d3d_filter_mipmag = d3dmodes[i].m1;
495 d3d_filter_mipmix = d3dmodes[i].m2;
496 d3d_filter_nomip = i < 2;
497 if (gl_texture_anisotropy.integer > 1 && i == 5)
498 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
499 for (pool = gltexturepoolchain;pool;pool = pool->next)
501 for (glt = pool->gltchain;glt;glt = glt->chain)
503 // only update already uploaded images
504 if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
506 if (glt->flags & TEXF_MIPMAP)
508 glt->d3dminfilter = d3d_filter_mipmin;
509 glt->d3dmagfilter = d3d_filter_mipmag;
510 glt->d3dmipfilter = d3d_filter_mipmix;
511 glt->d3dmaxmiplevelfilter = 0;
515 glt->d3dminfilter = d3d_filter_flatmin;
516 glt->d3dmagfilter = d3d_filter_flatmag;
517 glt->d3dmipfilter = d3d_filter_flatmix;
518 glt->d3dmaxmiplevelfilter = 0;
525 case RENDERPATH_D3D10:
526 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
528 case RENDERPATH_D3D11:
529 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
531 case RENDERPATH_SOFT:
532 // change all the existing texture objects
533 for (pool = gltexturepoolchain;pool;pool = pool->next)
534 for (glt = pool->gltchain;glt;glt = glt->chain)
535 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
536 DPSOFTRAST_Texture_Filter(glt->texnum, (glt->flags & TEXF_MIPMAP) ? dpsoftrast_filter_mipmap : dpsoftrast_filter_nomipmap);
541 static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, int inwidth, int inheight, int indepth, int *outwidth, int *outheight, int *outdepth, int *outmiplevels)
543 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
548 case GLTEXTURETYPE_2D:
549 maxsize = vid.maxtexturesize_2d;
550 if (flags & TEXF_PICMIP)
552 maxsize = bound(1, gl_max_size.integer, maxsize);
556 case GLTEXTURETYPE_3D:
557 maxsize = vid.maxtexturesize_3d;
559 case GLTEXTURETYPE_CUBEMAP:
560 maxsize = vid.maxtexturesize_cubemap;
564 if (vid.support.arb_texture_non_power_of_two)
566 width2 = min(inwidth >> picmip, maxsize);
567 height2 = min(inheight >> picmip, maxsize);
568 depth2 = min(indepth >> picmip, maxsize);
572 for (width2 = 1;width2 < inwidth;width2 <<= 1);
573 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
574 for (height2 = 1;height2 < inheight;height2 <<= 1);
575 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
576 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
577 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
580 switch(vid.renderpath)
582 case RENDERPATH_GL11:
583 case RENDERPATH_GL13:
584 case RENDERPATH_GL20:
585 case RENDERPATH_CGGL:
586 case RENDERPATH_D3D10:
587 case RENDERPATH_D3D11:
588 case RENDERPATH_SOFT:
589 case RENDERPATH_GLES2:
591 case RENDERPATH_D3D9:
593 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
594 if (texturetype == GLTEXTURETYPE_2D)
596 width2 = max(width2, 2);
597 height2 = max(height2, 2);
604 if (flags & TEXF_MIPMAP)
606 int extent = max(width2, max(height2, depth2));
612 *outwidth = max(1, width2);
614 *outheight = max(1, height2);
616 *outdepth = max(1, depth2);
618 *outmiplevels = miplevels;
622 static int R_CalcTexelDataSize (gltexture_t *glt)
624 int width2, height2, depth2, size;
626 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
628 size = width2 * height2 * depth2;
630 if (glt->flags & TEXF_MIPMAP)
632 while (width2 > 1 || height2 > 1 || depth2 > 1)
640 size += width2 * height2 * depth2;
644 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
647 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
651 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
652 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
654 gltexturepool_t *pool;
656 Con_Print("glsize input loaded mip alpha name\n");
657 for (pool = gltexturepoolchain;pool;pool = pool->next)
665 for (glt = pool->gltchain;glt;glt = glt->chain)
667 glsize = R_CalcTexelDataSize(glt);
668 isloaded = glt->texnum != 0;
670 pooltotalt += glsize;
671 pooltotalp += glt->inputdatasize;
675 poolloadedt += glsize;
676 poolloadedp += glt->inputdatasize;
679 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);
682 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);
683 sumtotal += pooltotal;
684 sumtotalt += pooltotalt;
685 sumtotalp += pooltotalp;
686 sumloaded += poolloaded;
687 sumloadedt += poolloadedt;
688 sumloadedp += poolloadedp;
691 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);
694 static void R_TextureStats_f(void)
696 R_TextureStats_Print(true, true, true);
699 static void r_textures_start(void)
701 switch(vid.renderpath)
703 case RENDERPATH_GL11:
704 case RENDERPATH_GL13:
705 case RENDERPATH_GL20:
706 case RENDERPATH_CGGL:
707 case RENDERPATH_GLES2:
708 // LordHavoc: allow any alignment
710 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
711 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
713 case RENDERPATH_D3D9:
715 case RENDERPATH_D3D10:
716 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
718 case RENDERPATH_D3D11:
719 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
721 case RENDERPATH_SOFT:
725 texturemempool = Mem_AllocPool("texture management", 0, NULL);
726 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
728 // Disable JPEG screenshots if the DLL isn't loaded
729 if (! JPEG_OpenLibrary ())
730 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
731 if (! PNG_OpenLibrary ())
732 Cvar_SetValueQuick (&scr_screenshot_png, 0);
735 static void r_textures_shutdown(void)
737 rtexturepool_t *temp;
739 JPEG_CloseLibrary ();
741 while(gltexturepoolchain)
743 temp = (rtexturepool_t *) gltexturepoolchain;
744 R_FreeTexturePool(&temp);
747 resizebuffersize = 0;
749 colorconvertbuffer = NULL;
750 texturebuffer = NULL;
751 Mem_ExpandableArray_FreeArray(&texturearray);
752 Mem_FreePool(&texturemempool);
755 static void r_textures_newmap(void)
759 static void r_textures_devicelost(void)
763 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
764 for (i = 0;i < endindex;i++)
766 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
767 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
769 switch(vid.renderpath)
771 case RENDERPATH_GL11:
772 case RENDERPATH_GL13:
773 case RENDERPATH_GL20:
774 case RENDERPATH_CGGL:
775 case RENDERPATH_GLES2:
777 case RENDERPATH_D3D9:
779 if (glt->d3disdepthsurface)
780 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
781 else if (glt->tiledepth > 1)
782 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
783 else if (glt->sides == 6)
784 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
786 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
787 glt->d3dtexture = NULL;
790 case RENDERPATH_D3D10:
791 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
793 case RENDERPATH_D3D11:
794 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
796 case RENDERPATH_SOFT:
802 static void r_textures_devicerestored(void)
806 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
807 for (i = 0;i < endindex;i++)
809 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
810 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
812 switch(vid.renderpath)
814 case RENDERPATH_GL11:
815 case RENDERPATH_GL13:
816 case RENDERPATH_GL20:
817 case RENDERPATH_CGGL:
818 case RENDERPATH_GLES2:
820 case RENDERPATH_D3D9:
824 if (glt->d3disdepthsurface)
826 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
827 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
829 else if (glt->tiledepth > 1)
831 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)))
832 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
834 else if (glt->sides == 6)
836 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
837 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
841 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)))
842 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
847 case RENDERPATH_D3D10:
848 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
850 case RENDERPATH_D3D11:
851 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
853 case RENDERPATH_SOFT:
860 void R_Textures_Init (void)
862 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");
863 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
864 Cvar_RegisterVariable (&gl_max_size);
865 Cvar_RegisterVariable (&gl_picmip);
866 Cvar_RegisterVariable (&gl_picmip_world);
867 Cvar_RegisterVariable (&r_picmipworld);
868 Cvar_RegisterVariable (&gl_picmip_sprites);
869 Cvar_RegisterVariable (&r_picmipsprites);
870 Cvar_RegisterVariable (&gl_picmip_other);
871 Cvar_RegisterVariable (&gl_max_lightmapsize);
872 Cvar_RegisterVariable (&r_lerpimages);
873 Cvar_RegisterVariable (&gl_texture_anisotropy);
874 Cvar_RegisterVariable (&gl_texturecompression);
875 Cvar_RegisterVariable (&gl_texturecompression_color);
876 Cvar_RegisterVariable (&gl_texturecompression_normal);
877 Cvar_RegisterVariable (&gl_texturecompression_gloss);
878 Cvar_RegisterVariable (&gl_texturecompression_glow);
879 Cvar_RegisterVariable (&gl_texturecompression_2d);
880 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
881 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
882 Cvar_RegisterVariable (&gl_texturecompression_sky);
883 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
884 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
885 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
886 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
887 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
888 Cvar_RegisterVariable (&r_texture_dds_swdecode);
890 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
893 void R_Textures_Frame (void)
895 static int old_aniso = 0;
897 // could do procedural texture animation here, if we keep track of which
898 // textures were accessed this frame...
900 // free the resize buffers
901 resizebuffersize = 0;
904 Mem_Free(resizebuffer);
907 if (colorconvertbuffer)
909 Mem_Free(colorconvertbuffer);
910 colorconvertbuffer = NULL;
913 if (old_aniso != gl_texture_anisotropy.integer)
916 gltexturepool_t *pool;
919 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
921 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
923 switch(vid.renderpath)
925 case RENDERPATH_GL11:
926 case RENDERPATH_GL13:
927 case RENDERPATH_GL20:
928 case RENDERPATH_CGGL:
929 case RENDERPATH_GLES2:
932 for (pool = gltexturepoolchain;pool;pool = pool->next)
934 for (glt = pool->gltchain;glt;glt = glt->chain)
936 // only update already uploaded images
937 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
939 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
941 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
942 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
944 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
949 case RENDERPATH_D3D9:
950 case RENDERPATH_D3D10:
951 case RENDERPATH_D3D11:
952 case RENDERPATH_SOFT:
958 void R_MakeResizeBufferBigger(int size)
960 if (resizebuffersize < size)
962 resizebuffersize = size;
964 Mem_Free(resizebuffer);
965 if (colorconvertbuffer)
966 Mem_Free(colorconvertbuffer);
967 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
968 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
969 if (!resizebuffer || !colorconvertbuffer)
970 Host_Error("R_Upload: out of memory");
974 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
976 int textureenum = gltexturetypeenums[texturetype];
977 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
981 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
983 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
984 if (gl_texture_anisotropy.integer != aniso)
985 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
986 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
988 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
989 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
990 if (gltexturetypedimensions[texturetype] >= 3)
992 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
996 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
998 if (flags & TEXF_MIPMAP)
1000 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
1004 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
1006 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
1008 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
1010 if (flags & TEXF_MIPMAP)
1012 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
1014 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
1018 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
1023 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
1025 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
1029 if (flags & TEXF_MIPMAP)
1031 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1035 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1037 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1040 if (textype == TEXTYPE_SHADOWMAP)
1042 if (vid.support.arb_shadow)
1044 if (flags & TEXF_COMPARE)
1046 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1050 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1052 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1054 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1060 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1063 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1065 if (glt->texturetype != GLTEXTURETYPE_2D)
1066 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1068 if (glt->textype->textype == TEXTYPE_PALETTE)
1069 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1071 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1072 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1074 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1075 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1077 // update a portion of the image
1079 switch(vid.renderpath)
1081 case RENDERPATH_GL11:
1082 case RENDERPATH_GL13:
1083 case RENDERPATH_GL20:
1084 case RENDERPATH_CGGL:
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 < width*height*depth*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_CGGL:
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 flags |= TEXF_ALPHA;
1575 Sys_Error("R_LoadTexture: unknown texture type");
1578 texinfo2 = R_GetTexTypeInfo(textype, flags);
1579 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1582 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1584 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1586 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1588 glt->chain = pool->gltchain;
1589 pool->gltchain = glt;
1590 glt->inputwidth = width;
1591 glt->inputheight = height;
1592 glt->inputdepth = depth;
1594 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
1595 glt->textype = texinfo;
1596 glt->texturetype = texturetype;
1597 glt->inputdatasize = size;
1598 glt->palette = palette;
1599 glt->glinternalformat = texinfo->glinternalformat;
1600 glt->glformat = texinfo->glformat;
1601 glt->gltype = texinfo->gltype;
1602 glt->bytesperpixel = texinfo->internalbytesperpixel;
1603 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1606 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1607 // init the dynamic texture attributes, too [11/22/2007 Black]
1608 glt->updatecallback = NULL;
1609 glt->updatacallback_data = NULL;
1611 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1613 // upload the texture
1614 // data may be NULL (blank texture for dynamic rendering)
1615 switch(vid.renderpath)
1617 case RENDERPATH_GL11:
1618 case RENDERPATH_GL13:
1619 case RENDERPATH_GL20:
1620 case RENDERPATH_CGGL:
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 = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1645 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1646 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1647 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1649 glt->d3dformat = d3dformat;
1650 glt->d3dusage = d3dusage;
1651 glt->d3dpool = d3dpool;
1652 glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1653 if (glt->d3disdepthsurface)
1655 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1656 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1658 else if (glt->tiledepth > 1)
1660 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)))
1661 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1663 else if (glt->sides == 6)
1665 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1666 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1670 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)))
1671 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1676 case RENDERPATH_D3D10:
1677 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1679 case RENDERPATH_D3D11:
1680 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1682 case RENDERPATH_SOFT:
1687 case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1688 case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1689 case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1690 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1691 case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1692 case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1693 default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1695 if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1696 if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1697 if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1698 if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1699 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1704 R_UploadFullTexture(glt, data);
1705 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1706 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1708 // free any temporary processing buffer we allocated...
1710 Mem_Free(temppixels);
1712 // texture converting and uploading can take a while, so make sure we're sending keepalives
1713 // FIXME: this causes rendering during R_Shadow_DrawLights
1714 // CL_KeepaliveMessage(false);
1716 return (rtexture_t *)glt;
1719 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)
1721 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1724 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)
1726 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1729 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)
1731 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1734 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1736 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1738 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1740 flags |= TEXF_FORCENEAREST;
1741 if (precision <= 16)
1742 flags |= TEXF_LOWPRECISION;
1746 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1748 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1751 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1753 gltexture_t *glt = (gltexture_t *)rt;
1756 int bytesperpixel = 0;
1757 int bytesperblock = 0;
1759 int dds_format_flags;
1767 GLint internalformat;
1768 const char *ddsfourcc;
1770 return -1; // NULL pointer
1771 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1772 return -2; // broken driver - crashes on reading internal format
1773 if (!qglGetTexLevelParameteriv)
1775 GL_ActiveTexture(0);
1776 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1777 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1778 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1779 switch(internalformat)
1781 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1782 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1783 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1784 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1785 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1787 // if premultiplied alpha, say so in the DDS file
1788 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1790 switch(internalformat)
1792 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1793 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1796 if (!bytesperblock && skipuncompressed)
1797 return -3; // skipped
1798 memset(mipinfo, 0, sizeof(mipinfo));
1799 mipinfo[0][0] = glt->tilewidth;
1800 mipinfo[0][1] = glt->tileheight;
1802 if (glt->flags & TEXF_MIPMAP)
1804 for (mip = 1;mip < 16;mip++)
1806 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1807 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1808 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1816 for (mip = 0;mip < mipmaps;mip++)
1818 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1819 mipinfo[mip][3] = ddssize;
1820 ddssize += mipinfo[mip][2];
1822 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1825 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1829 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1830 dds_format_flags = 0x4; // DDPF_FOURCC
1834 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1835 dds_format_flags = 0x40; // DDPF_RGB
1839 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1840 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1843 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1844 memcpy(dds, "DDS ", 4);
1845 StoreLittleLong(dds+4, ddssize);
1846 StoreLittleLong(dds+8, dds_flags);
1847 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1848 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1849 StoreLittleLong(dds+24, 1); // depth
1850 StoreLittleLong(dds+28, mipmaps); // mipmaps
1851 StoreLittleLong(dds+76, 32); // format size
1852 StoreLittleLong(dds+80, dds_format_flags);
1853 StoreLittleLong(dds+108, dds_caps1);
1854 StoreLittleLong(dds+112, dds_caps2);
1857 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1858 memcpy(dds+84, ddsfourcc, 4);
1859 for (mip = 0;mip < mipmaps;mip++)
1861 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1866 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1867 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1868 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1869 for (mip = 0;mip < mipmaps;mip++)
1871 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1874 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1875 ret = FS_WriteFile(filename, dds, ddssize);
1877 return ret ? ddssize : -5;
1880 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
1882 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1885 int bytesperblock, bytesperpixel;
1888 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1889 textypeinfo_t *texinfo;
1890 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1892 GLint oldbindtexnum = 0;
1893 const unsigned char *mippixels, *ddspixels, *mippixels_start;
1895 fs_offset_t ddsfilesize;
1896 unsigned int ddssize;
1897 qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
1899 if (cls.state == ca_dedicated)
1902 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1903 ddssize = ddsfilesize;
1907 if(r_texture_dds_load_logfailure.integer)
1908 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1909 return NULL; // not found
1912 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1915 Con_Printf("^1%s: not a DDS image\n", filename);
1919 //dds_flags = BuffLittleLong(dds+8);
1920 dds_format_flags = BuffLittleLong(dds+80);
1921 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1922 dds_width = BuffLittleLong(dds+16);
1923 dds_height = BuffLittleLong(dds+12);
1924 ddspixels = dds + 128;
1926 if(r_texture_dds_load_alphamode.integer == 0)
1927 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1928 flags &= ~TEXF_ALPHA;
1930 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1931 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1933 // very sloppy BGRA 32bit identification
1934 textype = TEXTYPE_BGRA;
1937 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1938 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1941 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1944 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1947 for (i = 3;i < size;i += 4)
1948 if (ddspixels[i] < 255)
1951 flags &= ~TEXF_ALPHA;
1954 else if (!memcmp(dds+84, "DXT1", 4))
1956 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1957 // LordHavoc: it is my belief that this does not infringe on the
1958 // patent because it is not decoding pixels...
1959 textype = TEXTYPE_DXT1;
1962 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1963 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1964 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1967 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1970 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1972 if(r_texture_dds_load_alphamode.integer == 1)
1975 for (i = 0;i < size;i += bytesperblock)
1976 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1978 // NOTE: this assumes sizeof(unsigned int) == 4
1979 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1980 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1981 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1985 textype = TEXTYPE_DXT1A;
1987 flags &= ~TEXF_ALPHA;
1991 flags &= ~TEXF_ALPHA;
1995 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
1997 if(!memcmp(dds+84, "DXT2", 4))
1999 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2001 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2006 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2008 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2011 textype = TEXTYPE_DXT3;
2014 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2015 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2018 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2021 // we currently always assume alpha
2023 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2025 if(!memcmp(dds+84, "DXT4", 4))
2027 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2029 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2034 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2036 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2039 textype = TEXTYPE_DXT5;
2042 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2043 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2046 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2049 // we currently always assume alpha
2054 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2058 force_swdecode = false;
2061 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
2063 if(r_texture_dds_swdecode.integer > 1)
2064 force_swdecode = true;
2068 if(r_texture_dds_swdecode.integer < 1)
2074 force_swdecode = true;
2078 // return whether this texture is transparent
2080 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2082 // if we SW decode, choose 2 sizes bigger
2085 // this is quarter res, so do not scale down more than we have to
2089 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2092 // this is where we apply gl_picmip
2093 mippixels_start = ddspixels;
2094 mipwidth = dds_width;
2095 mipheight = dds_height;
2096 while(miplevel >= 1 && dds_miplevels >= 1)
2098 if (mipwidth <= 1 && mipheight <= 1)
2100 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2101 mippixels_start += mipsize; // just skip
2109 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2110 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2112 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2114 // fake decode S3TC if needed
2117 int mipsize_new = mipsize_total / bytesperblock * 4;
2118 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2119 unsigned char *p = mipnewpixels;
2120 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2122 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2123 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2124 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2125 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2126 if(textype == TEXTYPE_DXT5)
2127 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2128 else if(textype == TEXTYPE_DXT3)
2130 (mippixels_start[i-8] & 0x0F)
2131 + (mippixels_start[i-8] >> 4)
2132 + (mippixels_start[i-7] & 0x0F)
2133 + (mippixels_start[i-7] >> 4)
2134 + (mippixels_start[i-6] & 0x0F)
2135 + (mippixels_start[i-6] >> 4)
2136 + (mippixels_start[i-5] & 0x0F)
2137 + (mippixels_start[i-5] >> 4)
2138 ) * (0.125f / 15.0f * 255.0f);
2143 textype = TEXTYPE_BGRA;
2147 // as each block becomes a pixel, we must use pixel count for this
2148 mipwidth = (mipwidth + 3) / 4;
2149 mipheight = (mipheight + 3) / 4;
2150 mipsize = bytesperpixel * mipwidth * mipheight;
2151 mippixels_start = mipnewpixels;
2152 mipsize_total = mipsize_new;
2155 // start mip counting
2156 mippixels = mippixels_start;
2158 // calculate average color if requested
2162 Vector4Clear(avgcolor);
2165 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2167 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2168 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2169 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2170 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2171 if(textype == TEXTYPE_DXT5)
2172 avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2173 else if(textype == TEXTYPE_DXT3)
2175 (mippixels_start[i-8] & 0x0F)
2176 + (mippixels_start[i-8] >> 4)
2177 + (mippixels_start[i-7] & 0x0F)
2178 + (mippixels_start[i-7] >> 4)
2179 + (mippixels_start[i-6] & 0x0F)
2180 + (mippixels_start[i-6] >> 4)
2181 + (mippixels_start[i-5] & 0x0F)
2182 + (mippixels_start[i-5] >> 4)
2183 ) * (0.125f / 15.0f * 255.0f);
2187 f = (float)bytesperblock / size;
2188 avgcolor[0] *= (0.5f / 31.0f) * f;
2189 avgcolor[1] *= (0.5f / 63.0f) * f;
2190 avgcolor[2] *= (0.5f / 31.0f) * f;
2195 for (i = 0;i < mipsize;i += 4)
2197 avgcolor[0] += mippixels[i+2];
2198 avgcolor[1] += mippixels[i+1];
2199 avgcolor[2] += mippixels[i];
2200 avgcolor[3] += mippixels[i+3];
2202 f = (1.0f / 255.0f) * bytesperpixel / size;
2210 // when not requesting mipmaps, do not load them
2211 if(!(flags & TEXF_MIPMAP))
2214 if (dds_miplevels >= 1)
2215 flags |= TEXF_MIPMAP;
2217 flags &= ~TEXF_MIPMAP;
2219 texinfo = R_GetTexTypeInfo(textype, flags);
2221 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2222 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2224 glt->chain = pool->gltchain;
2225 pool->gltchain = glt;
2226 glt->inputwidth = mipwidth;
2227 glt->inputheight = mipheight;
2228 glt->inputdepth = 1;
2230 glt->textype = texinfo;
2231 glt->texturetype = GLTEXTURETYPE_2D;
2232 glt->inputdatasize = ddssize;
2233 glt->glinternalformat = texinfo->glinternalformat;
2234 glt->glformat = texinfo->glformat;
2235 glt->gltype = texinfo->gltype;
2236 glt->bytesperpixel = texinfo->internalbytesperpixel;
2238 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2239 glt->tilewidth = mipwidth;
2240 glt->tileheight = mipheight;
2242 glt->miplevels = dds_miplevels;
2244 // texture uploading can take a while, so make sure we're sending keepalives
2245 CL_KeepaliveMessage(false);
2247 // create the texture object
2248 switch(vid.renderpath)
2250 case RENDERPATH_GL11:
2251 case RENDERPATH_GL13:
2252 case RENDERPATH_GL20:
2253 case RENDERPATH_CGGL:
2254 case RENDERPATH_GLES2:
2256 GL_ActiveTexture(0);
2257 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2258 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2259 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2261 case RENDERPATH_D3D9:
2264 D3DFORMAT d3dformat;
2269 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2270 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2271 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2272 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2273 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2276 d3dpool = D3DPOOL_MANAGED;
2277 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2281 case RENDERPATH_D3D10:
2282 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2284 case RENDERPATH_D3D11:
2285 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2287 case RENDERPATH_SOFT:
2288 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);
2292 // upload the texture
2293 // we need to restore the texture binding after finishing the upload
2294 mipcomplete = false;
2296 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2298 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2299 if (mippixels + mipsize > mippixels_start + mipsize_total)
2301 switch(vid.renderpath)
2303 case RENDERPATH_GL11:
2304 case RENDERPATH_GL13:
2305 case RENDERPATH_GL20:
2306 case RENDERPATH_CGGL:
2307 case RENDERPATH_GLES2:
2310 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2314 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2317 case RENDERPATH_D3D9:
2320 D3DLOCKED_RECT d3dlockedrect;
2321 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2323 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2324 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2330 case RENDERPATH_D3D10:
2331 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2333 case RENDERPATH_D3D11:
2334 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2336 case RENDERPATH_SOFT:
2338 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2340 DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
2341 // DPSOFTRAST calculates its own mipmaps
2342 mip = dds_miplevels;
2345 mippixels += mipsize;
2346 if (mipwidth <= 1 && mipheight <= 1)
2357 // after upload we have to set some parameters...
2358 switch(vid.renderpath)
2360 case RENDERPATH_GL11:
2361 case RENDERPATH_GL13:
2362 case RENDERPATH_GL20:
2363 case RENDERPATH_CGGL:
2364 case RENDERPATH_GLES2:
2365 if (dds_miplevels >= 1 && !mipcomplete)
2367 // need to set GL_TEXTURE_MAX_LEVEL
2368 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2370 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2371 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2373 case RENDERPATH_D3D9:
2375 glt->d3daddressw = 0;
2376 if (glt->flags & TEXF_CLAMP)
2378 glt->d3daddressu = D3DTADDRESS_CLAMP;
2379 glt->d3daddressv = D3DTADDRESS_CLAMP;
2380 if (glt->tiledepth > 1)
2381 glt->d3daddressw = D3DTADDRESS_CLAMP;
2385 glt->d3daddressu = D3DTADDRESS_WRAP;
2386 glt->d3daddressv = D3DTADDRESS_WRAP;
2387 if (glt->tiledepth > 1)
2388 glt->d3daddressw = D3DTADDRESS_WRAP;
2390 glt->d3dmipmaplodbias = 0;
2391 glt->d3dmaxmiplevel = 0;
2392 glt->d3dmaxmiplevelfilter = 0;
2393 if (glt->flags & TEXF_MIPMAP)
2395 glt->d3dminfilter = d3d_filter_mipmin;
2396 glt->d3dmagfilter = d3d_filter_mipmag;
2397 glt->d3dmipfilter = d3d_filter_mipmix;
2401 glt->d3dminfilter = d3d_filter_flatmin;
2402 glt->d3dmagfilter = d3d_filter_flatmag;
2403 glt->d3dmipfilter = d3d_filter_flatmix;
2407 case RENDERPATH_D3D10:
2408 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2410 case RENDERPATH_D3D11:
2411 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2413 case RENDERPATH_SOFT:
2414 if (glt->flags & TEXF_FORCELINEAR)
2415 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2416 else if (glt->flags & TEXF_FORCENEAREST)
2417 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2418 else if (glt->flags & TEXF_MIPMAP)
2419 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2421 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2427 Mem_Free((unsigned char *) mippixels_start);
2428 return (rtexture_t *)glt;
2431 int R_TextureWidth(rtexture_t *rt)
2433 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2436 int R_TextureHeight(rtexture_t *rt)
2438 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2441 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
2443 gltexture_t *glt = (gltexture_t *)rt;
2445 Host_Error("R_UpdateTexture: no data supplied");
2447 Host_Error("R_UpdateTexture: no texture supplied");
2448 if (!glt->texnum && !glt->d3dtexture)
2450 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2453 // update part of the texture
2454 if (glt->bufferpixels)
2457 int bpp = glt->bytesperpixel;
2458 int inputskip = width*bpp;
2459 int outputskip = glt->tilewidth*bpp;
2460 const unsigned char *input = data;
2461 unsigned char *output = glt->bufferpixels;
2471 input -= y*inputskip;
2474 if (width > glt->tilewidth - x)
2475 width = glt->tilewidth - x;
2476 if (height > glt->tileheight - y)
2477 height = glt->tileheight - y;
2478 if (width < 1 || height < 1)
2481 glt->buffermodified = true;
2482 output += y*outputskip + x*bpp;
2483 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2484 memcpy(output, input, width*bpp);
2486 else if (x || y || width != glt->inputwidth || height != glt->inputheight)
2487 R_UploadPartialTexture(glt, data, x, y, 0, width, height, 1);
2489 R_UploadFullTexture(glt, data);
2492 int R_RealGetTexture(rtexture_t *rt)
2497 glt = (gltexture_t *)rt;
2498 if (glt->flags & GLTEXF_DYNAMIC)
2499 R_UpdateDynamicTexture(glt);
2500 if (glt->buffermodified && glt->bufferpixels)
2502 glt->buffermodified = false;
2503 R_UploadFullTexture(glt, glt->bufferpixels);
2512 void R_ClearTexture (rtexture_t *rt)
2514 gltexture_t *glt = (gltexture_t *)rt;
2516 R_UploadFullTexture(glt, NULL);
2519 int R_PicmipForFlags(int flags)
2522 if(flags & TEXF_PICMIP)
2524 miplevel += gl_picmip.integer;
2525 if (flags & TEXF_ISWORLD)
2527 if (r_picmipworld.integer)
2528 miplevel += gl_picmip_world.integer;
2532 else if (flags & TEXF_ISSPRITE)
2534 if (r_picmipsprites.integer)
2535 miplevel += gl_picmip_sprites.integer;
2540 miplevel += gl_picmip_other.integer;
2542 return max(0, miplevel);