5 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
10 #include "intoverflow.h"
12 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)"};
13 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)"};
14 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%"};
15 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)"};
16 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)"};
17 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)"};
18 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)"};
19 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)"};
20 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)"};
21 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"};
22 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"};
23 cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
24 cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
25 cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
26 cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
27 cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
28 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
29 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)"};
30 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
31 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
32 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)"};
33 cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "1", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"};
34 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 ambigous, 2: texture format only"};
35 cvar_t r_texture_dds_load_logfailure = {0, "r_texture_dds_load_logfailure", "1", "log missing DDS textures to ddstexturefailures.log"};
36 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"};
38 qboolean gl_filter_force = false;
39 int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
40 int gl_filter_mag = GL_LINEAR;
43 int d3d_filter_flatmin = D3DTEXF_LINEAR;
44 int d3d_filter_flatmag = D3DTEXF_LINEAR;
45 int d3d_filter_flatmix = D3DTEXF_POINT;
46 int d3d_filter_mipmin = D3DTEXF_LINEAR;
47 int d3d_filter_mipmag = D3DTEXF_LINEAR;
48 int d3d_filter_mipmix = D3DTEXF_LINEAR;
49 int d3d_filter_nomip = false;
53 static mempool_t *texturemempool;
54 static memexpandablearray_t texturearray;
56 // note: this must not conflict with TEXF_ flags in r_textures.h
57 // bitmask for mismatch checking
58 #define GLTEXF_IMPORTANTBITS (0)
59 // dynamic texture (treat texnum == 0 differently)
60 #define GLTEXF_DYNAMIC 0x00080000
62 typedef struct textypeinfo_s
65 int inputbytesperpixel;
66 int internalbytesperpixel;
67 float glinternalbytesperpixel;
75 static textypeinfo_t textype_palette = {TEXTYPE_PALETTE , 1, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE };
76 static textypeinfo_t textype_palette_alpha = {TEXTYPE_PALETTE , 1, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
77 static textypeinfo_t textype_rgba = {TEXTYPE_RGBA , 4, 4, 4.0f, 3 , GL_RGBA , GL_UNSIGNED_BYTE };
78 static textypeinfo_t textype_rgba_alpha = {TEXTYPE_RGBA , 4, 4, 4.0f, 4 , GL_RGBA , GL_UNSIGNED_BYTE };
79 static textypeinfo_t textype_rgba_compress = {TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
80 static textypeinfo_t textype_rgba_alpha_compress = {TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA , GL_UNSIGNED_BYTE };
81 static textypeinfo_t textype_bgra = {TEXTYPE_BGRA , 4, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE };
82 static textypeinfo_t textype_bgra_alpha = {TEXTYPE_BGRA , 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
83 static textypeinfo_t textype_bgra_compress = {TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
84 static textypeinfo_t textype_bgra_alpha_compress = {TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_BGRA , GL_UNSIGNED_BYTE };
85 static textypeinfo_t textype_shadowmap16 = {TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
86 static textypeinfo_t textype_shadowmap24 = {TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
87 static textypeinfo_t textype_alpha = {TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
88 static textypeinfo_t textype_dxt1 = {TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
89 static textypeinfo_t textype_dxt1a = {TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0 , 0 };
90 static textypeinfo_t textype_dxt3 = {TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0 , 0 };
91 static textypeinfo_t textype_dxt5 = {TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0 , 0 };
92 static textypeinfo_t textype_colorbuffer = {TEXTYPE_COLORBUFFER, 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE };
95 typedef enum gltexturetype_e
99 GLTEXTURETYPE_CUBEMAP,
104 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB};
105 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
106 static int cubemapside[6] =
108 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
109 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
110 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
111 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
112 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
113 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
116 typedef struct gltexture_s
118 // this portion of the struct is exposed to the R_GetTexture macro for
119 // speed reasons, must be identical in rtexture_t!
120 int texnum; // GL texture slot number
121 qboolean dirty; // indicates that R_RealGetTexture should be called
122 int gltexturetypeenum; // used by R_Mesh_TexBind
123 // d3d stuff the backend needs
126 qboolean d3disdepthsurface; // for depth/stencil surfaces
136 int d3dmaxmiplevelfilter;
137 int d3dmipmaplodbias;
141 // dynamic texture stuff [11/22/2007 Black]
142 updatecallback_t updatecallback;
143 void *updatacallback_data;
144 // --- [11/22/2007 Black]
146 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
147 unsigned char *bufferpixels;
148 qboolean buffermodified;
150 // pointer to texturepool (check this to see if the texture is allocated)
151 struct gltexturepool_s *pool;
152 // pointer to next texture in texturepool chain
153 struct gltexture_s *chain;
154 // name of the texture (this might be removed someday), no duplicates
155 char identifier[MAX_QPATH + 32];
156 // original data size in *inputtexels
157 int inputwidth, inputheight, inputdepth;
158 // copy of the original texture(s) supplied to the upload function, for
159 // delayed uploads (non-precached)
160 unsigned char *inputtexels;
161 // original data size in *inputtexels
163 // flags supplied to the LoadTexture function
164 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
168 // pointer to one of the textype_ structs
169 textypeinfo_t *textype;
170 // one of the GLTEXTURETYPE_ values
172 // palette if the texture is TEXTYPE_PALETTE
173 const unsigned int *palette;
174 // actual stored texture size after gl_picmip and gl_max_size are applied
175 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
176 int tilewidth, tileheight, tiledepth;
177 // 1 or 6 depending on texturetype
179 // how many mipmap levels in this texture
183 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
186 int glinternalformat;
187 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
192 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
194 typedef struct gltexturepool_s
196 unsigned int sentinel;
197 struct gltexture_s *gltchain;
198 struct gltexturepool_s *next;
202 static gltexturepool_t *gltexturepoolchain = NULL;
204 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
205 static int resizebuffersize = 0;
206 static const unsigned char *texturebuffer;
208 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
213 return &textype_dxt1;
215 return &textype_dxt1a;
217 return &textype_dxt3;
219 return &textype_dxt5;
220 case TEXTYPE_PALETTE:
221 return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
223 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
224 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress;
225 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba;
227 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
228 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress;
229 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra;
231 return &textype_alpha;
232 case TEXTYPE_SHADOWMAP:
233 return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
234 case TEXTYPE_COLORBUFFER:
235 return &textype_colorbuffer;
237 Host_Error("R_GetTexTypeInfo: unknown texture format");
243 // dynamic texture code [11/22/2007 Black]
244 void R_MarkDirtyTexture(rtexture_t *rt) {
245 gltexture_t *glt = (gltexture_t*) rt;
250 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
251 if (glt->flags & GLTEXF_DYNAMIC)
253 // mark it as dirty, so R_RealGetTexture gets called
258 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
259 gltexture_t *glt = (gltexture_t*) rt;
264 glt->flags |= GLTEXF_DYNAMIC;
265 glt->updatecallback = updatecallback;
266 glt->updatacallback_data = data;
269 static void R_UpdateDynamicTexture(gltexture_t *glt) {
271 if( glt->updatecallback ) {
272 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
276 void R_PurgeTexture(rtexture_t *rt)
278 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
283 void R_FreeTexture(rtexture_t *rt)
285 gltexture_t *glt, **gltpointer;
287 glt = (gltexture_t *)rt;
289 Host_Error("R_FreeTexture: texture == NULL");
291 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
292 if (*gltpointer == glt)
293 *gltpointer = glt->chain;
295 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
297 switch(vid.renderpath)
299 case RENDERPATH_GL11:
300 case RENDERPATH_GL13:
301 case RENDERPATH_GL20:
302 case RENDERPATH_CGGL:
306 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
309 case RENDERPATH_D3D9:
311 if (glt->d3disdepthsurface)
312 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
313 else if (glt->tiledepth > 1)
314 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
315 else if (glt->sides == 6)
316 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
318 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
319 glt->d3dtexture = NULL;
322 case RENDERPATH_D3D10:
323 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
325 case RENDERPATH_D3D11:
326 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
330 if (glt->inputtexels)
331 Mem_Free(glt->inputtexels);
332 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
335 rtexturepool_t *R_AllocTexturePool(void)
337 gltexturepool_t *pool;
338 if (texturemempool == NULL)
340 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
343 pool->next = gltexturepoolchain;
344 gltexturepoolchain = pool;
345 pool->sentinel = TEXTUREPOOL_SENTINEL;
346 return (rtexturepool_t *)pool;
349 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
351 gltexturepool_t *pool, **poolpointer;
352 if (rtexturepool == NULL)
354 if (*rtexturepool == NULL)
356 pool = (gltexturepool_t *)(*rtexturepool);
357 *rtexturepool = NULL;
358 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
359 Host_Error("R_FreeTexturePool: pool already freed");
360 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
361 if (*poolpointer == pool)
362 *poolpointer = pool->next;
364 Host_Error("R_FreeTexturePool: pool not linked");
365 while (pool->gltchain)
366 R_FreeTexture((rtexture_t *)pool->gltchain);
371 typedef struct glmode_s
374 int minification, magnification;
378 static glmode_t modes[6] =
380 {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
381 {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
382 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
383 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
384 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
385 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
389 typedef struct d3dmode_s
396 static d3dmode_t d3dmodes[6] =
398 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
399 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
400 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
401 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
402 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
403 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
407 static void GL_TextureMode_f (void)
412 gltexturepool_t *pool;
416 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
417 for (i = 0;i < 6;i++)
419 if (gl_filter_min == modes[i].minification)
421 Con_Printf("%s\n", modes[i].name);
425 Con_Print("current filter is unknown???\n");
429 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
430 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
434 Con_Print("bad filter name\n");
438 gl_filter_min = modes[i].minification;
439 gl_filter_mag = modes[i].magnification;
440 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
442 switch(vid.renderpath)
444 case RENDERPATH_GL11:
445 case RENDERPATH_GL13:
446 case RENDERPATH_GL20:
447 case RENDERPATH_CGGL:
448 // change all the existing mipmap texture objects
449 // FIXME: force renderer(/client/something?) restart instead?
452 for (pool = gltexturepoolchain;pool;pool = pool->next)
454 for (glt = pool->gltchain;glt;glt = glt->chain)
456 // only update already uploaded images
457 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
459 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
460 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
461 if (glt->flags & TEXF_MIPMAP)
463 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
467 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
469 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
470 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
475 case RENDERPATH_D3D9:
477 d3d_filter_flatmin = d3dmodes[i].m1;
478 d3d_filter_flatmag = d3dmodes[i].m1;
479 d3d_filter_flatmix = D3DTEXF_POINT;
480 d3d_filter_mipmin = d3dmodes[i].m1;
481 d3d_filter_mipmag = d3dmodes[i].m1;
482 d3d_filter_mipmix = d3dmodes[i].m2;
483 d3d_filter_nomip = i < 2;
484 if (gl_texture_anisotropy.integer > 1 && i == 5)
485 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
486 for (pool = gltexturepoolchain;pool;pool = pool->next)
488 for (glt = pool->gltchain;glt;glt = glt->chain)
490 // only update already uploaded images
491 if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
493 if (glt->flags & TEXF_MIPMAP)
495 glt->d3dminfilter = d3d_filter_mipmin;
496 glt->d3dmagfilter = d3d_filter_mipmag;
497 glt->d3dmipfilter = d3d_filter_mipmix;
498 glt->d3dmaxmiplevelfilter = 0;
502 glt->d3dminfilter = d3d_filter_flatmin;
503 glt->d3dmagfilter = d3d_filter_flatmag;
504 glt->d3dmipfilter = d3d_filter_flatmix;
505 glt->d3dmaxmiplevelfilter = 0;
512 case RENDERPATH_D3D10:
513 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
515 case RENDERPATH_D3D11:
516 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
521 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)
523 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
528 case GLTEXTURETYPE_2D:
529 maxsize = vid.maxtexturesize_2d;
530 if (flags & TEXF_PICMIP)
532 maxsize = bound(1, gl_max_size.integer, maxsize);
536 case GLTEXTURETYPE_3D:
537 maxsize = vid.maxtexturesize_3d;
539 case GLTEXTURETYPE_CUBEMAP:
540 maxsize = vid.maxtexturesize_cubemap;
544 if (vid.support.arb_texture_non_power_of_two)
546 width2 = min(inwidth >> picmip, maxsize);
547 height2 = min(inheight >> picmip, maxsize);
548 depth2 = min(indepth >> picmip, maxsize);
552 for (width2 = 1;width2 < inwidth;width2 <<= 1);
553 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
554 for (height2 = 1;height2 < inheight;height2 <<= 1);
555 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
556 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
557 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
560 switch(vid.renderpath)
562 case RENDERPATH_GL11:
563 case RENDERPATH_GL13:
564 case RENDERPATH_GL20:
565 case RENDERPATH_CGGL:
566 case RENDERPATH_D3D10:
567 case RENDERPATH_D3D11:
569 case RENDERPATH_D3D9:
571 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
572 if (texturetype == GLTEXTURETYPE_2D)
574 width2 = max(width2, 2);
575 height2 = max(height2, 2);
582 if (flags & TEXF_MIPMAP)
584 int extent = max(width2, max(height2, depth2));
590 *outwidth = max(1, width2);
592 *outheight = max(1, height2);
594 *outdepth = max(1, depth2);
596 *outmiplevels = miplevels;
600 static int R_CalcTexelDataSize (gltexture_t *glt)
602 int width2, height2, depth2, size;
604 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
606 size = width2 * height2 * depth2;
608 if (glt->flags & TEXF_MIPMAP)
610 while (width2 > 1 || height2 > 1 || depth2 > 1)
618 size += width2 * height2 * depth2;
622 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
625 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
629 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
630 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
632 gltexturepool_t *pool;
634 Con_Print("glsize input loaded mip alpha name\n");
635 for (pool = gltexturepoolchain;pool;pool = pool->next)
643 for (glt = pool->gltchain;glt;glt = glt->chain)
645 glsize = R_CalcTexelDataSize(glt);
646 isloaded = glt->texnum != 0;
648 pooltotalt += glsize;
649 pooltotalp += glt->inputdatasize;
653 poolloadedt += glsize;
654 poolloadedp += glt->inputdatasize;
657 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);
660 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);
661 sumtotal += pooltotal;
662 sumtotalt += pooltotalt;
663 sumtotalp += pooltotalp;
664 sumloaded += poolloaded;
665 sumloadedt += poolloadedt;
666 sumloadedp += poolloadedp;
669 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);
672 static void R_TextureStats_f(void)
674 R_TextureStats_Print(true, true, true);
677 static void r_textures_start(void)
679 switch(vid.renderpath)
681 case RENDERPATH_GL11:
682 case RENDERPATH_GL13:
683 case RENDERPATH_GL20:
684 case RENDERPATH_CGGL:
685 // LordHavoc: allow any alignment
687 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
688 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
690 case RENDERPATH_D3D9:
692 case RENDERPATH_D3D10:
693 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
695 case RENDERPATH_D3D11:
696 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
700 texturemempool = Mem_AllocPool("texture management", 0, NULL);
701 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
703 // Disable JPEG screenshots if the DLL isn't loaded
704 if (! JPEG_OpenLibrary ())
705 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
706 if (! PNG_OpenLibrary ())
707 Cvar_SetValueQuick (&scr_screenshot_png, 0);
710 static void r_textures_shutdown(void)
712 rtexturepool_t *temp;
714 JPEG_CloseLibrary ();
716 while(gltexturepoolchain)
718 temp = (rtexturepool_t *) gltexturepoolchain;
719 R_FreeTexturePool(&temp);
722 resizebuffersize = 0;
724 colorconvertbuffer = NULL;
725 texturebuffer = NULL;
726 Mem_ExpandableArray_FreeArray(&texturearray);
727 Mem_FreePool(&texturemempool);
730 static void r_textures_newmap(void)
734 static void r_textures_devicelost(void)
738 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
739 for (i = 0;i < endindex;i++)
741 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
742 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
744 switch(vid.renderpath)
746 case RENDERPATH_GL11:
747 case RENDERPATH_GL13:
748 case RENDERPATH_GL20:
749 case RENDERPATH_CGGL:
751 case RENDERPATH_D3D9:
753 if (glt->d3disdepthsurface)
754 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
755 else if (glt->tiledepth > 1)
756 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
757 else if (glt->sides == 6)
758 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
760 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
761 glt->d3dtexture = NULL;
764 case RENDERPATH_D3D10:
765 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
767 case RENDERPATH_D3D11:
768 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
774 static void r_textures_devicerestored(void)
778 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
779 for (i = 0;i < endindex;i++)
781 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
782 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
784 switch(vid.renderpath)
786 case RENDERPATH_GL11:
787 case RENDERPATH_GL13:
788 case RENDERPATH_GL20:
789 case RENDERPATH_CGGL:
791 case RENDERPATH_D3D9:
795 if (glt->d3disdepthsurface)
797 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
798 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
800 else if (glt->tiledepth > 1)
802 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)))
803 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
805 else if (glt->sides == 6)
807 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
808 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
812 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)))
813 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
818 case RENDERPATH_D3D10:
819 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
821 case RENDERPATH_D3D11:
822 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
829 void R_Textures_Init (void)
831 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");
832 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
833 Cvar_RegisterVariable (&gl_max_size);
834 Cvar_RegisterVariable (&gl_picmip);
835 Cvar_RegisterVariable (&gl_picmip_world);
836 Cvar_RegisterVariable (&r_picmipworld);
837 Cvar_RegisterVariable (&gl_picmip_sprites);
838 Cvar_RegisterVariable (&r_picmipsprites);
839 Cvar_RegisterVariable (&gl_picmip_other);
840 Cvar_RegisterVariable (&gl_max_lightmapsize);
841 Cvar_RegisterVariable (&r_lerpimages);
842 Cvar_RegisterVariable (&gl_texture_anisotropy);
843 Cvar_RegisterVariable (&gl_texturecompression);
844 Cvar_RegisterVariable (&gl_texturecompression_color);
845 Cvar_RegisterVariable (&gl_texturecompression_normal);
846 Cvar_RegisterVariable (&gl_texturecompression_gloss);
847 Cvar_RegisterVariable (&gl_texturecompression_glow);
848 Cvar_RegisterVariable (&gl_texturecompression_2d);
849 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
850 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
851 Cvar_RegisterVariable (&gl_texturecompression_sky);
852 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
853 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
854 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
855 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
856 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
857 Cvar_RegisterVariable (&r_texture_dds_swdecode);
859 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
862 void R_Textures_Frame (void)
864 static int old_aniso = 0;
866 // could do procedural texture animation here, if we keep track of which
867 // textures were accessed this frame...
869 // free the resize buffers
870 resizebuffersize = 0;
873 Mem_Free(resizebuffer);
876 if (colorconvertbuffer)
878 Mem_Free(colorconvertbuffer);
879 colorconvertbuffer = NULL;
882 if (old_aniso != gl_texture_anisotropy.integer)
885 gltexturepool_t *pool;
888 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
890 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
892 switch(vid.renderpath)
894 case RENDERPATH_GL11:
895 case RENDERPATH_GL13:
896 case RENDERPATH_GL20:
897 case RENDERPATH_CGGL:
900 for (pool = gltexturepoolchain;pool;pool = pool->next)
902 for (glt = pool->gltchain;glt;glt = glt->chain)
904 // only update already uploaded images
905 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
907 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
909 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
910 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
912 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
917 case RENDERPATH_D3D9:
918 case RENDERPATH_D3D10:
919 case RENDERPATH_D3D11:
925 void R_MakeResizeBufferBigger(int size)
927 if (resizebuffersize < size)
929 resizebuffersize = size;
931 Mem_Free(resizebuffer);
932 if (colorconvertbuffer)
933 Mem_Free(colorconvertbuffer);
934 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
935 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
936 if (!resizebuffer || !colorconvertbuffer)
937 Host_Error("R_Upload: out of memory");
941 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
943 int textureenum = gltexturetypeenums[texturetype];
944 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
948 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
950 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
951 if (gl_texture_anisotropy.integer != aniso)
952 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
953 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
955 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
956 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
957 if (gltexturetypedimensions[texturetype] >= 3)
959 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
963 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
965 if (flags & TEXF_MIPMAP)
967 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
971 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
973 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
975 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
977 if (flags & TEXF_MIPMAP)
979 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
981 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
985 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
990 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
992 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
996 if (flags & TEXF_MIPMAP)
998 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1002 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1004 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1007 if (textype == TEXTYPE_SHADOWMAP)
1009 if (vid.support.arb_shadow)
1011 if (flags & TEXF_COMPARE)
1013 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1017 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1019 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1021 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1027 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1030 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1032 if (glt->texturetype != GLTEXTURETYPE_2D)
1033 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1035 if (glt->textype->textype == TEXTYPE_PALETTE)
1036 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1038 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1039 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1041 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1042 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1044 // update a portion of the image
1046 switch(vid.renderpath)
1048 case RENDERPATH_GL11:
1049 case RENDERPATH_GL13:
1050 case RENDERPATH_GL20:
1051 case RENDERPATH_CGGL:
1055 // we need to restore the texture binding after finishing the upload
1056 GL_ActiveTexture(0);
1057 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1058 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1059 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1060 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1063 case RENDERPATH_D3D9:
1067 D3DLOCKED_RECT d3dlockedrect;
1069 memset(&d3drect, 0, sizeof(d3drect));
1070 d3drect.left = fragx;
1071 d3drect.top = fragy;
1072 d3drect.right = fragx+fragwidth;
1073 d3drect.bottom = fragy+fragheight;
1074 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1076 for (y = 0;y < fragheight;y++)
1077 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1078 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1083 case RENDERPATH_D3D10:
1084 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1086 case RENDERPATH_D3D11:
1087 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1092 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1094 int i, mip = 0, width, height, depth;
1095 GLint oldbindtexnum = 0;
1096 const unsigned char *prevbuffer;
1099 // error out if a stretch is needed on special texture types
1100 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1101 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1103 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1104 // of the target size and then use the mipmap reduction function to get
1105 // high quality supersampled results
1106 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1107 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1108 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1109 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1111 if (prevbuffer == NULL)
1113 width = glt->tilewidth;
1114 height = glt->tileheight;
1115 depth = glt->tiledepth;
1116 memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1117 prevbuffer = resizebuffer;
1119 else if (glt->textype->textype == TEXTYPE_PALETTE)
1121 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1122 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1123 prevbuffer = colorconvertbuffer;
1126 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1128 // multiply RGB channels by A channel before uploading
1130 for (i = 0;i < width*height*depth*4;i += 4)
1132 alpha = prevbuffer[i+3];
1133 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1134 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1135 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1136 colorconvertbuffer[i+3] = alpha;
1138 prevbuffer = colorconvertbuffer;
1141 // scale up to a power of 2 size (if appropriate)
1142 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1144 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1145 prevbuffer = resizebuffer;
1147 // apply mipmap reduction algorithm to get down to picmip/max_size
1148 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1150 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1151 prevbuffer = resizebuffer;
1154 // do the appropriate upload type...
1155 switch(vid.renderpath)
1157 case RENDERPATH_GL11:
1158 case RENDERPATH_GL13:
1159 case RENDERPATH_GL20:
1160 case RENDERPATH_CGGL:
1163 // we need to restore the texture binding after finishing the upload
1164 GL_ActiveTexture(0);
1165 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1166 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1168 if (qglGetCompressedTexImageARB)
1170 if (gl_texturecompression.integer >= 2)
1171 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1173 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1176 switch(glt->texturetype)
1178 case GLTEXTURETYPE_2D:
1179 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1180 if (glt->flags & TEXF_MIPMAP)
1182 while (width > 1 || height > 1 || depth > 1)
1184 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1185 prevbuffer = resizebuffer;
1186 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1190 case GLTEXTURETYPE_3D:
1191 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1192 if (glt->flags & TEXF_MIPMAP)
1194 while (width > 1 || height > 1 || depth > 1)
1196 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1197 prevbuffer = resizebuffer;
1198 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1202 case GLTEXTURETYPE_CUBEMAP:
1203 // convert and upload each side in turn,
1204 // from a continuous block of input texels
1205 texturebuffer = (unsigned char *)prevbuffer;
1206 for (i = 0;i < 6;i++)
1208 prevbuffer = texturebuffer;
1209 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1210 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1212 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1213 prevbuffer = resizebuffer;
1216 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1218 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1219 prevbuffer = resizebuffer;
1222 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1223 if (glt->flags & TEXF_MIPMAP)
1225 while (width > 1 || height > 1 || depth > 1)
1227 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1228 prevbuffer = resizebuffer;
1229 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1235 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1236 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1238 case RENDERPATH_D3D9:
1240 if (!(glt->flags & TEXF_RENDERTARGET))
1242 D3DLOCKED_RECT d3dlockedrect;
1243 D3DLOCKED_BOX d3dlockedbox;
1244 switch(glt->texturetype)
1246 case GLTEXTURETYPE_2D:
1247 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1250 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1252 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1253 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1256 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1258 while (width > 1 || height > 1 || depth > 1)
1260 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1261 prevbuffer = resizebuffer;
1262 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1264 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1265 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1271 case GLTEXTURETYPE_3D:
1272 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1274 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1275 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1276 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1279 if (glt->flags & TEXF_MIPMAP)
1281 while (width > 1 || height > 1 || depth > 1)
1283 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1284 prevbuffer = resizebuffer;
1285 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1287 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1288 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1289 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1295 case GLTEXTURETYPE_CUBEMAP:
1296 // convert and upload each side in turn,
1297 // from a continuous block of input texels
1298 texturebuffer = (unsigned char *)prevbuffer;
1299 for (i = 0;i < 6;i++)
1301 prevbuffer = texturebuffer;
1302 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1303 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1305 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1306 prevbuffer = resizebuffer;
1309 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1311 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1312 prevbuffer = resizebuffer;
1315 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1317 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1318 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1321 if (glt->flags & TEXF_MIPMAP)
1323 while (width > 1 || height > 1 || depth > 1)
1325 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1326 prevbuffer = resizebuffer;
1327 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1329 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1330 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1339 glt->d3daddressw = 0;
1340 if (glt->flags & TEXF_CLAMP)
1342 glt->d3daddressu = D3DTADDRESS_CLAMP;
1343 glt->d3daddressv = D3DTADDRESS_CLAMP;
1344 if (glt->tiledepth > 1)
1345 glt->d3daddressw = D3DTADDRESS_CLAMP;
1349 glt->d3daddressu = D3DTADDRESS_WRAP;
1350 glt->d3daddressv = D3DTADDRESS_WRAP;
1351 if (glt->tiledepth > 1)
1352 glt->d3daddressw = D3DTADDRESS_WRAP;
1354 glt->d3dmipmaplodbias = 0;
1355 glt->d3dmaxmiplevel = 0;
1356 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1357 if (glt->flags & TEXF_FORCELINEAR)
1359 glt->d3dminfilter = D3DTEXF_LINEAR;
1360 glt->d3dmagfilter = D3DTEXF_LINEAR;
1361 glt->d3dmipfilter = D3DTEXF_POINT;
1363 else if (glt->flags & TEXF_FORCENEAREST)
1365 glt->d3dminfilter = D3DTEXF_POINT;
1366 glt->d3dmagfilter = D3DTEXF_POINT;
1367 glt->d3dmipfilter = D3DTEXF_POINT;
1369 else if (glt->flags & TEXF_MIPMAP)
1371 glt->d3dminfilter = d3d_filter_mipmin;
1372 glt->d3dmagfilter = d3d_filter_mipmag;
1373 glt->d3dmipfilter = d3d_filter_mipmix;
1377 glt->d3dminfilter = d3d_filter_flatmin;
1378 glt->d3dmagfilter = d3d_filter_flatmag;
1379 glt->d3dmipfilter = d3d_filter_flatmix;
1383 case RENDERPATH_D3D10:
1384 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1386 case RENDERPATH_D3D11:
1387 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1392 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)
1396 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1397 textypeinfo_t *texinfo, *texinfo2;
1398 unsigned char *temppixels = NULL;
1400 if (cls.state == ca_dedicated)
1403 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1405 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1408 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1410 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1414 texinfo = R_GetTexTypeInfo(textype, flags);
1415 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1418 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1422 if (textype == TEXTYPE_RGBA)
1425 static int rgbaswapindices[4] = {2, 1, 0, 3};
1426 textype = TEXTYPE_BGRA;
1427 texinfo = R_GetTexTypeInfo(textype, flags);
1428 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1429 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1433 // clear the alpha flag if the texture has no transparent pixels
1436 case TEXTYPE_PALETTE:
1437 if (flags & TEXF_ALPHA)
1439 flags &= ~TEXF_ALPHA;
1442 for (i = 0;i < size;i++)
1444 if (((unsigned char *)&palette[data[i]])[3] < 255)
1446 flags |= TEXF_ALPHA;
1455 if (flags & TEXF_ALPHA)
1457 flags &= ~TEXF_ALPHA;
1460 for (i = 3;i < size;i += 4)
1464 flags |= TEXF_ALPHA;
1471 case TEXTYPE_SHADOWMAP:
1478 flags |= TEXF_ALPHA;
1481 flags |= TEXF_ALPHA;
1483 case TEXTYPE_COLORBUFFER:
1484 flags |= TEXF_ALPHA;
1487 Sys_Error("R_LoadTexture: unknown texture type");
1490 texinfo2 = R_GetTexTypeInfo(textype, flags);
1491 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1494 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1496 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1498 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1500 glt->chain = pool->gltchain;
1501 pool->gltchain = glt;
1502 glt->inputwidth = width;
1503 glt->inputheight = height;
1504 glt->inputdepth = depth;
1506 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
1507 glt->textype = texinfo;
1508 glt->texturetype = texturetype;
1509 glt->inputdatasize = size;
1510 glt->palette = palette;
1511 glt->glinternalformat = texinfo->glinternalformat;
1512 glt->glformat = texinfo->glformat;
1513 glt->gltype = texinfo->gltype;
1514 glt->bytesperpixel = texinfo->internalbytesperpixel;
1515 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1518 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1519 // init the dynamic texture attributes, too [11/22/2007 Black]
1520 glt->updatecallback = NULL;
1521 glt->updatacallback_data = NULL;
1523 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1525 // upload the texture
1526 // data may be NULL (blank texture for dynamic rendering)
1527 switch(vid.renderpath)
1529 case RENDERPATH_GL11:
1530 case RENDERPATH_GL13:
1531 case RENDERPATH_GL20:
1532 case RENDERPATH_CGGL:
1534 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1536 case RENDERPATH_D3D9:
1539 D3DFORMAT d3dformat;
1544 d3dpool = D3DPOOL_MANAGED;
1545 if (flags & TEXF_RENDERTARGET)
1547 d3dusage |= D3DUSAGE_RENDERTARGET;
1548 d3dpool = D3DPOOL_DEFAULT;
1552 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1553 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1554 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1555 case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1556 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1557 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1558 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1560 glt->d3dformat = d3dformat;
1561 glt->d3dusage = d3dusage;
1562 glt->d3dpool = d3dpool;
1563 glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1564 if (glt->d3disdepthsurface)
1566 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1567 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1569 else if (glt->tiledepth > 1)
1571 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)))
1572 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1574 else if (glt->sides == 6)
1576 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1577 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1581 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)))
1582 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1587 case RENDERPATH_D3D10:
1588 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1590 case RENDERPATH_D3D11:
1591 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1595 R_UploadFullTexture(glt, data);
1596 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1597 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1599 // free any temporary processing buffer we allocated...
1601 Mem_Free(temppixels);
1603 // texture converting and uploading can take a while, so make sure we're sending keepalives
1604 // FIXME: this causes rendering during R_Shadow_DrawLights
1605 // CL_KeepaliveMessage(false);
1607 return (rtexture_t *)glt;
1610 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)
1612 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1615 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)
1617 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1620 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)
1622 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1625 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1627 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1629 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1631 flags |= TEXF_FORCENEAREST;
1632 if (precision <= 16)
1633 flags |= TEXF_LOWPRECISION;
1637 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1639 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1642 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1644 gltexture_t *glt = (gltexture_t *)rt;
1647 int bytesperpixel = 0;
1648 int bytesperblock = 0;
1650 int dds_format_flags;
1658 GLint internalformat;
1659 const char *ddsfourcc;
1661 return -1; // NULL pointer
1662 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1663 return -2; // broken driver - crashes on reading internal format
1664 if (!qglGetTexLevelParameteriv)
1666 GL_ActiveTexture(0);
1667 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1668 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1669 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1670 switch(internalformat)
1672 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1673 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1674 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1675 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1676 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1678 // if premultiplied alpha, say so in the DDS file
1679 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1681 switch(internalformat)
1683 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1684 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1687 if (!bytesperblock && skipuncompressed)
1688 return -3; // skipped
1689 memset(mipinfo, 0, sizeof(mipinfo));
1690 mipinfo[0][0] = glt->tilewidth;
1691 mipinfo[0][1] = glt->tileheight;
1693 if (glt->flags & TEXF_MIPMAP)
1695 for (mip = 1;mip < 16;mip++)
1697 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1698 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1699 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1707 for (mip = 0;mip < mipmaps;mip++)
1709 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1710 mipinfo[mip][3] = ddssize;
1711 ddssize += mipinfo[mip][2];
1713 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1716 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1720 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1721 dds_format_flags = 0x4; // DDPF_FOURCC
1725 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1726 dds_format_flags = 0x40; // DDPF_RGB
1730 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1731 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1734 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1735 memcpy(dds, "DDS ", 4);
1736 StoreLittleLong(dds+4, ddssize);
1737 StoreLittleLong(dds+8, dds_flags);
1738 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1739 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1740 StoreLittleLong(dds+24, 1); // depth
1741 StoreLittleLong(dds+28, mipmaps); // mipmaps
1742 StoreLittleLong(dds+76, 32); // format size
1743 StoreLittleLong(dds+80, dds_format_flags);
1744 StoreLittleLong(dds+108, dds_caps1);
1745 StoreLittleLong(dds+112, dds_caps2);
1748 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1749 memcpy(dds+84, ddsfourcc, 4);
1750 for (mip = 0;mip < mipmaps;mip++)
1752 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1757 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1758 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1759 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1760 for (mip = 0;mip < mipmaps;mip++)
1762 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1765 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1766 ret = FS_WriteFile(filename, dds, ddssize);
1768 return ret ? ddssize : -5;
1771 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
1773 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1776 int bytesperblock, bytesperpixel;
1779 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1780 textypeinfo_t *texinfo;
1781 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1783 GLint oldbindtexnum = 0;
1784 const unsigned char *mippixels, *ddspixels, *mippixels_start;
1786 fs_offset_t ddsfilesize;
1787 unsigned int ddssize;
1788 qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
1790 if (cls.state == ca_dedicated)
1793 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1794 ddssize = ddsfilesize;
1798 if(r_texture_dds_load_logfailure.integer)
1799 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1800 return NULL; // not found
1803 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1806 Con_Printf("^1%s: not a DDS image\n", filename);
1810 //dds_flags = BuffLittleLong(dds+8);
1811 dds_format_flags = BuffLittleLong(dds+80);
1812 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1813 dds_width = BuffLittleLong(dds+16);
1814 dds_height = BuffLittleLong(dds+12);
1815 ddspixels = dds + 128;
1817 if(r_texture_dds_load_alphamode.integer == 0)
1818 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1819 flags &= ~TEXF_ALPHA;
1821 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1822 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1824 // very sloppy BGRA 32bit identification
1825 textype = TEXTYPE_BGRA;
1828 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1829 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1832 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1835 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1838 for (i = 3;i < size;i += 4)
1839 if (ddspixels[i] < 255)
1842 flags &= ~TEXF_ALPHA;
1845 else if (!memcmp(dds+84, "DXT1", 4))
1847 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1848 // LordHavoc: it is my belief that this does not infringe on the
1849 // patent because it is not decoding pixels...
1850 textype = TEXTYPE_DXT1;
1853 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1854 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1855 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1858 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1861 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1863 if(r_texture_dds_load_alphamode.integer == 1)
1866 for (i = 0;i < size;i += bytesperblock)
1867 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1869 // NOTE: this assumes sizeof(unsigned int) == 4
1870 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1871 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1872 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1876 textype = TEXTYPE_DXT1A;
1878 flags &= ~TEXF_ALPHA;
1882 flags &= ~TEXF_ALPHA;
1886 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
1888 if(!memcmp(dds+84, "DXT2", 4))
1890 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1892 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
1897 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1899 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
1902 textype = TEXTYPE_DXT3;
1905 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1906 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1909 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1912 // we currently always assume alpha
1914 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
1916 if(!memcmp(dds+84, "DXT4", 4))
1918 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1920 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
1925 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1927 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
1930 textype = TEXTYPE_DXT5;
1933 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1934 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1937 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1940 // we currently always assume alpha
1945 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1949 force_swdecode = false;
1952 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
1954 if(r_texture_dds_swdecode.integer > 1)
1955 force_swdecode = true;
1959 if(r_texture_dds_swdecode.integer < 1)
1965 force_swdecode = true;
1969 // return whether this texture is transparent
1971 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1973 // if we SW decode, choose 2 sizes bigger
1976 // this is quarter res, so do not scale down more than we have to
1980 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
1983 // this is where we apply gl_picmip
1984 mippixels_start = ddspixels;
1985 mipwidth = dds_width;
1986 mipheight = dds_height;
1987 while(miplevel >= 1 && dds_miplevels >= 1)
1989 if (mipwidth <= 1 && mipheight <= 1)
1991 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1992 mippixels_start += mipsize; // just skip
2000 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2001 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2003 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2005 // fake decode S3TC if needed
2008 int mipsize_new = mipsize_total / bytesperblock * 4;
2009 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2010 unsigned char *p = mipnewpixels;
2011 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2013 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2014 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2015 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2016 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2017 if(textype == TEXTYPE_DXT5)
2018 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2019 else if(textype == TEXTYPE_DXT3)
2021 (mippixels_start[i-8] & 0x0F)
2022 + (mippixels_start[i-8] >> 4)
2023 + (mippixels_start[i-7] & 0x0F)
2024 + (mippixels_start[i-7] >> 4)
2025 + (mippixels_start[i-6] & 0x0F)
2026 + (mippixels_start[i-6] >> 4)
2027 + (mippixels_start[i-5] & 0x0F)
2028 + (mippixels_start[i-5] >> 4)
2029 ) * (0.125f / 15.0f * 255.0f);
2034 textype = TEXTYPE_BGRA;
2038 // as each block becomes a pixel, we must use pixel count for this
2039 mipwidth = (mipwidth + 3) / 4;
2040 mipheight = (mipheight + 3) / 4;
2041 mipsize = bytesperpixel * mipwidth * mipheight;
2042 mippixels_start = mipnewpixels;
2043 mipsize_total = mipsize_new;
2046 // start mip counting
2047 mippixels = mippixels_start;
2049 // calculate average color if requested
2053 Vector4Clear(avgcolor);
2056 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2058 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2059 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2060 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2061 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2062 if(textype == TEXTYPE_DXT5)
2063 avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2064 else if(textype == TEXTYPE_DXT3)
2066 (mippixels_start[i-8] & 0x0F)
2067 + (mippixels_start[i-8] >> 4)
2068 + (mippixels_start[i-7] & 0x0F)
2069 + (mippixels_start[i-7] >> 4)
2070 + (mippixels_start[i-6] & 0x0F)
2071 + (mippixels_start[i-6] >> 4)
2072 + (mippixels_start[i-5] & 0x0F)
2073 + (mippixels_start[i-5] >> 4)
2074 ) * (0.125f / 15.0f * 255.0f);
2078 f = (float)bytesperblock / size;
2079 avgcolor[0] *= (0.5f / 31.0f) * f;
2080 avgcolor[1] *= (0.5f / 63.0f) * f;
2081 avgcolor[2] *= (0.5f / 31.0f) * f;
2086 for (i = 0;i < mipsize;i += 4)
2088 avgcolor[0] += mippixels[i+2];
2089 avgcolor[1] += mippixels[i+1];
2090 avgcolor[2] += mippixels[i];
2091 avgcolor[3] += mippixels[i+3];
2093 f = (1.0f / 255.0f) * bytesperpixel / size;
2101 // when not requesting mipmaps, do not load them
2102 if(!(flags & TEXF_MIPMAP))
2105 if (dds_miplevels >= 1)
2106 flags |= TEXF_MIPMAP;
2108 flags &= ~TEXF_MIPMAP;
2110 texinfo = R_GetTexTypeInfo(textype, flags);
2112 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2113 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2115 glt->chain = pool->gltchain;
2116 pool->gltchain = glt;
2117 glt->inputwidth = mipwidth;
2118 glt->inputheight = mipheight;
2119 glt->inputdepth = 1;
2121 glt->textype = texinfo;
2122 glt->texturetype = GLTEXTURETYPE_2D;
2123 glt->inputdatasize = ddssize;
2124 glt->glinternalformat = texinfo->glinternalformat;
2125 glt->glformat = texinfo->glformat;
2126 glt->gltype = texinfo->gltype;
2127 glt->bytesperpixel = texinfo->internalbytesperpixel;
2129 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2130 glt->tilewidth = mipwidth;
2131 glt->tileheight = mipheight;
2133 glt->miplevels = dds_miplevels;
2135 // texture uploading can take a while, so make sure we're sending keepalives
2136 CL_KeepaliveMessage(false);
2138 // create the texture object
2139 switch(vid.renderpath)
2141 case RENDERPATH_GL11:
2142 case RENDERPATH_GL13:
2143 case RENDERPATH_GL20:
2144 case RENDERPATH_CGGL:
2146 GL_ActiveTexture(0);
2147 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2148 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2149 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2151 case RENDERPATH_D3D9:
2154 D3DFORMAT d3dformat;
2159 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2160 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2161 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2162 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2163 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2166 d3dpool = D3DPOOL_MANAGED;
2167 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2171 case RENDERPATH_D3D10:
2172 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2174 case RENDERPATH_D3D11:
2175 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2179 // upload the texture
2180 // we need to restore the texture binding after finishing the upload
2181 mipcomplete = false;
2183 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2185 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2186 if (mippixels + mipsize > mippixels_start + mipsize_total)
2188 switch(vid.renderpath)
2190 case RENDERPATH_GL11:
2191 case RENDERPATH_GL13:
2192 case RENDERPATH_GL20:
2193 case RENDERPATH_CGGL:
2196 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2200 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2203 case RENDERPATH_D3D9:
2206 D3DLOCKED_RECT d3dlockedrect;
2207 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2209 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2210 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2216 case RENDERPATH_D3D10:
2217 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2219 case RENDERPATH_D3D11:
2220 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2223 mippixels += mipsize;
2224 if (mipwidth <= 1 && mipheight <= 1)
2235 // after upload we have to set some parameters...
2236 switch(vid.renderpath)
2238 case RENDERPATH_GL11:
2239 case RENDERPATH_GL13:
2240 case RENDERPATH_GL20:
2241 case RENDERPATH_CGGL:
2242 if (dds_miplevels >= 1 && !mipcomplete)
2244 // need to set GL_TEXTURE_MAX_LEVEL
2245 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2247 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2248 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2250 case RENDERPATH_D3D9:
2252 glt->d3daddressw = 0;
2253 if (glt->flags & TEXF_CLAMP)
2255 glt->d3daddressu = D3DTADDRESS_CLAMP;
2256 glt->d3daddressv = D3DTADDRESS_CLAMP;
2257 if (glt->tiledepth > 1)
2258 glt->d3daddressw = D3DTADDRESS_CLAMP;
2262 glt->d3daddressu = D3DTADDRESS_WRAP;
2263 glt->d3daddressv = D3DTADDRESS_WRAP;
2264 if (glt->tiledepth > 1)
2265 glt->d3daddressw = D3DTADDRESS_WRAP;
2267 glt->d3dmipmaplodbias = 0;
2268 glt->d3dmaxmiplevel = 0;
2269 glt->d3dmaxmiplevelfilter = 0;
2270 if (glt->flags & TEXF_MIPMAP)
2272 glt->d3dminfilter = d3d_filter_mipmin;
2273 glt->d3dmagfilter = d3d_filter_mipmag;
2274 glt->d3dmipfilter = d3d_filter_mipmix;
2278 glt->d3dminfilter = d3d_filter_flatmin;
2279 glt->d3dmagfilter = d3d_filter_flatmag;
2280 glt->d3dmipfilter = d3d_filter_flatmix;
2284 case RENDERPATH_D3D10:
2285 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2287 case RENDERPATH_D3D11:
2288 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2294 Mem_Free((unsigned char *) mippixels_start);
2295 return (rtexture_t *)glt;
2298 int R_TextureWidth(rtexture_t *rt)
2300 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2303 int R_TextureHeight(rtexture_t *rt)
2305 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2308 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
2310 gltexture_t *glt = (gltexture_t *)rt;
2312 Host_Error("R_UpdateTexture: no data supplied");
2314 Host_Error("R_UpdateTexture: no texture supplied");
2315 if (!glt->texnum && !glt->d3dtexture)
2317 Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", (void *)glt, glt->identifier, (void *)glt->pool);
2320 // update part of the texture
2321 if (glt->bufferpixels)
2324 int bpp = glt->bytesperpixel;
2325 int inputskip = width*bpp;
2326 int outputskip = glt->tilewidth*bpp;
2327 const unsigned char *input = data;
2328 unsigned char *output = glt->bufferpixels;
2338 input -= y*inputskip;
2341 if (width > glt->tilewidth - x)
2342 width = glt->tilewidth - x;
2343 if (height > glt->tileheight - y)
2344 height = glt->tileheight - y;
2345 if (width < 1 || height < 1)
2348 glt->buffermodified = true;
2349 output += y*outputskip + x*bpp;
2350 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2351 memcpy(output, input, width*bpp);
2353 else if (x || y || width != glt->inputwidth || height != glt->inputheight)
2354 R_UploadPartialTexture(glt, data, x, y, 0, width, height, 1);
2356 R_UploadFullTexture(glt, data);
2359 int R_RealGetTexture(rtexture_t *rt)
2364 glt = (gltexture_t *)rt;
2365 if (glt->flags & GLTEXF_DYNAMIC)
2366 R_UpdateDynamicTexture(glt);
2367 if (glt->buffermodified && glt->bufferpixels)
2369 glt->buffermodified = false;
2370 R_UploadFullTexture(glt, glt->bufferpixels);
2379 void R_ClearTexture (rtexture_t *rt)
2381 gltexture_t *glt = (gltexture_t *)rt;
2383 R_UploadFullTexture(glt, NULL);
2386 int R_PicmipForFlags(int flags)
2389 if(flags & TEXF_PICMIP)
2391 miplevel += gl_picmip.integer;
2392 if (flags & TEXF_ISWORLD)
2394 if (r_picmipworld.integer)
2395 miplevel += gl_picmip_world.integer;
2399 else if (flags & TEXF_ISSPRITE)
2401 if (r_picmipsprites.integer)
2402 miplevel += gl_picmip_sprites.integer;
2407 miplevel += gl_picmip_other.integer;
2409 return max(0, miplevel);