5 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
10 #include "intoverflow.h"
11 #include "dpsoftrast.h"
14 #define GL_TEXTURE_3D 0x806F
17 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)"};
18 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)"};
19 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%"};
20 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)"};
21 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)"};
22 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)"};
23 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)"};
24 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)"};
25 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)"};
26 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"};
27 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"};
28 cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
29 cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
30 cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
31 cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
32 cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
33 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
34 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)"};
35 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
36 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
37 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)"};
38 cvar_t gl_texturecompression_sprites = {CVAR_SAVE, "gl_texturecompression_sprites", "1", "whether to compress sprites"};
39 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"};
40 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"};
41 cvar_t r_texture_dds_load_logfailure = {0, "r_texture_dds_load_logfailure", "0", "log missing DDS textures to ddstexturefailures.log"};
42 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"};
44 qboolean gl_filter_force = false;
45 int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
46 int gl_filter_mag = GL_LINEAR;
47 DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_mipmap = DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE;
48 DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_nomipmap = DPSOFTRAST_TEXTURE_FILTER_LINEAR;
51 int d3d_filter_flatmin = D3DTEXF_LINEAR;
52 int d3d_filter_flatmag = D3DTEXF_LINEAR;
53 int d3d_filter_flatmix = D3DTEXF_POINT;
54 int d3d_filter_mipmin = D3DTEXF_LINEAR;
55 int d3d_filter_mipmag = D3DTEXF_LINEAR;
56 int d3d_filter_mipmix = D3DTEXF_LINEAR;
57 int d3d_filter_nomip = false;
61 static mempool_t *texturemempool;
62 static memexpandablearray_t texturearray;
64 // note: this must not conflict with TEXF_ flags in r_textures.h
65 // bitmask for mismatch checking
66 #define GLTEXF_IMPORTANTBITS (0)
67 // dynamic texture (treat texnum == 0 differently)
68 #define GLTEXF_DYNAMIC 0x00080000
70 typedef struct textypeinfo_s
74 int inputbytesperpixel;
75 int internalbytesperpixel;
76 float glinternalbytesperpixel;
84 // framebuffer texture formats
85 // GLES2 devices rarely support depth textures, so we actually use a renderbuffer there
86 static textypeinfo_t textype_shadowmap16 = {"shadowmap16", TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
87 static textypeinfo_t textype_shadowmap24 = {"shadowmap24", TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
88 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
89 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F, 8, 8, 8.0f, GL_RGBA , GL_RGBA , GL_FLOAT };
90 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F, 16, 16, 16.0f, GL_RGBA , GL_RGBA , GL_FLOAT };
93 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
94 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
95 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
96 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
97 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
98 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
99 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
101 // framebuffer texture formats
102 static textypeinfo_t textype_shadowmap16 = {"shadowmap16", TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
103 static textypeinfo_t textype_shadowmap24 = {"shadowmap24", TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
104 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
105 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F, 8, 8, 8.0f, GL_RGBA16F_ARB , GL_RGBA , GL_FLOAT };
106 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F, 16, 16, 16.0f, GL_RGBA32F_ARB , GL_RGBA , GL_FLOAT };
109 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
110 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
111 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
112 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE };
113 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
114 static textypeinfo_t textype_rgba_compress = {"rgba_compress", TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
115 static textypeinfo_t textype_rgba_alpha_compress = {"rgba_alpha_compress", TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
116 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
117 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
118 static textypeinfo_t textype_bgra_compress = {"bgra_compress", TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
119 static textypeinfo_t textype_bgra_alpha_compress = {"bgra_alpha_compress", TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
120 static textypeinfo_t textype_dxt1 = {"dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
121 static textypeinfo_t textype_dxt1a = {"dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 };
122 static textypeinfo_t textype_dxt3 = {"dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 };
123 static textypeinfo_t textype_dxt5 = {"dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 };
124 static textypeinfo_t textype_sRGB_palette = {"sRGB_palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
125 static textypeinfo_t textype_sRGB_palette_alpha = {"sRGB_palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_ALPHA_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
126 static textypeinfo_t textype_sRGB_rgba = {"sRGB_rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
127 static textypeinfo_t textype_sRGB_rgba_alpha = {"sRGB_rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_ALPHA_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
128 static textypeinfo_t textype_sRGB_rgba_compress = {"sRGB_rgba_compress", TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
129 static textypeinfo_t textype_sRGB_rgba_alpha_compress = {"sRGB_rgba_alpha_compress", TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA , GL_UNSIGNED_BYTE };
130 static textypeinfo_t textype_sRGB_bgra = {"sRGB_bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
131 static textypeinfo_t textype_sRGB_bgra_alpha = {"sRGB_bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_ALPHA_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
132 static textypeinfo_t textype_sRGB_bgra_compress = {"sRGB_bgra_compress", TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
133 static textypeinfo_t textype_sRGB_bgra_alpha_compress = {"sRGB_bgra_alpha_compress", TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_BGRA , GL_UNSIGNED_BYTE };
134 static textypeinfo_t textype_sRGB_dxt1 = {"sRGB_dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , 0 , 0 };
135 static textypeinfo_t textype_sRGB_dxt1a = {"sRGB_dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 , 0 };
136 static textypeinfo_t textype_sRGB_dxt3 = {"sRGB_dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 , 0 };
137 static textypeinfo_t textype_sRGB_dxt5 = {"sRGB_dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 , 0 };
140 typedef enum gltexturetype_e
144 GLTEXTURETYPE_CUBEMAP,
149 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP};
150 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
151 static int cubemapside[6] =
153 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
154 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
155 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
156 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
157 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
158 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
161 typedef struct gltexture_s
163 // this portion of the struct is exposed to the R_GetTexture macro for
164 // speed reasons, must be identical in rtexture_t!
165 int texnum; // GL texture slot number
166 qboolean dirty; // indicates that R_RealGetTexture should be called
167 int gltexturetypeenum; // used by R_Mesh_TexBind
168 // d3d stuff the backend needs
171 qboolean d3disdepthsurface; // for depth/stencil surfaces
181 int d3dmaxmiplevelfilter;
182 int d3dmipmaplodbias;
186 // dynamic texture stuff [11/22/2007 Black]
187 updatecallback_t updatecallback;
188 void *updatacallback_data;
189 // --- [11/22/2007 Black]
191 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
192 unsigned char *bufferpixels;
193 qboolean buffermodified;
195 // pointer to texturepool (check this to see if the texture is allocated)
196 struct gltexturepool_s *pool;
197 // pointer to next texture in texturepool chain
198 struct gltexture_s *chain;
199 // name of the texture (this might be removed someday), no duplicates
200 char identifier[MAX_QPATH + 32];
201 // original data size in *inputtexels
202 int inputwidth, inputheight, inputdepth;
203 // copy of the original texture(s) supplied to the upload function, for
204 // delayed uploads (non-precached)
205 unsigned char *inputtexels;
206 // original data size in *inputtexels
208 // flags supplied to the LoadTexture function
209 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
213 // pointer to one of the textype_ structs
214 textypeinfo_t *textype;
215 // one of the GLTEXTURETYPE_ values
217 // palette if the texture is TEXTYPE_PALETTE
218 const unsigned int *palette;
219 // actual stored texture size after gl_picmip and gl_max_size are applied
220 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
221 int tilewidth, tileheight, tiledepth;
222 // 1 or 6 depending on texturetype
224 // how many mipmap levels in this texture
228 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
231 int glinternalformat;
232 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
237 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
239 typedef struct gltexturepool_s
241 unsigned int sentinel;
242 struct gltexture_s *gltchain;
243 struct gltexturepool_s *next;
247 static gltexturepool_t *gltexturepoolchain = NULL;
249 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
250 static int resizebuffersize = 0;
251 static const unsigned char *texturebuffer;
253 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
258 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
259 case TEXTYPE_RGBA: return ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba);
260 case TEXTYPE_BGRA: return ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra);
261 case TEXTYPE_ALPHA: return &textype_alpha;
262 case TEXTYPE_SHADOWMAP: return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
263 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
264 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
265 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
267 Host_Error("R_GetTexTypeInfo: unknown texture format");
273 case TEXTYPE_DXT1: return &textype_dxt1;
274 case TEXTYPE_DXT1A: return &textype_dxt1a;
275 case TEXTYPE_DXT3: return &textype_dxt3;
276 case TEXTYPE_DXT5: return &textype_dxt5;
277 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
278 case TEXTYPE_RGBA: return ((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress) : ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba);
279 case TEXTYPE_BGRA: return ((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress) : ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra);
280 case TEXTYPE_ALPHA: return &textype_alpha;
281 case TEXTYPE_SHADOWMAP: return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
282 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
283 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
284 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
285 case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1;
286 case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a;
287 case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
288 case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
289 case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
290 case TEXTYPE_SRGB_RGBA: return ((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_sRGB_rgba_alpha_compress : &textype_sRGB_rgba_compress) : ((flags & TEXF_ALPHA) ? &textype_sRGB_rgba_alpha : &textype_sRGB_rgba);
291 case TEXTYPE_SRGB_BGRA: return ((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_sRGB_bgra_alpha_compress : &textype_sRGB_bgra_compress) : ((flags & TEXF_ALPHA) ? &textype_sRGB_bgra_alpha : &textype_sRGB_bgra);
293 Host_Error("R_GetTexTypeInfo: unknown texture format");
300 // dynamic texture code [11/22/2007 Black]
301 void R_MarkDirtyTexture(rtexture_t *rt) {
302 gltexture_t *glt = (gltexture_t*) rt;
307 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
308 if (glt->flags & GLTEXF_DYNAMIC)
310 // mark it as dirty, so R_RealGetTexture gets called
315 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
316 gltexture_t *glt = (gltexture_t*) rt;
321 glt->flags |= GLTEXF_DYNAMIC;
322 glt->updatecallback = updatecallback;
323 glt->updatacallback_data = data;
326 static void R_UpdateDynamicTexture(gltexture_t *glt) {
328 if( glt->updatecallback ) {
329 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
333 void R_PurgeTexture(rtexture_t *rt)
335 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
340 void R_FreeTexture(rtexture_t *rt)
342 gltexture_t *glt, **gltpointer;
344 glt = (gltexture_t *)rt;
346 Host_Error("R_FreeTexture: texture == NULL");
348 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
349 if (*gltpointer == glt)
350 *gltpointer = glt->chain;
352 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
354 R_Mesh_ClearBindingsForTexture(glt->texnum);
356 switch(vid.renderpath)
358 case RENDERPATH_GL11:
359 case RENDERPATH_GL13:
360 case RENDERPATH_GL20:
361 case RENDERPATH_GLES1:
362 case RENDERPATH_GLES2:
366 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
369 case RENDERPATH_D3D9:
371 if (glt->d3disdepthsurface)
372 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
373 else if (glt->tiledepth > 1)
374 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
375 else if (glt->sides == 6)
376 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
378 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
379 glt->d3dtexture = NULL;
382 case RENDERPATH_D3D10:
383 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
385 case RENDERPATH_D3D11:
386 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
388 case RENDERPATH_SOFT:
390 DPSOFTRAST_Texture_Free(glt->texnum);
394 if (glt->inputtexels)
395 Mem_Free(glt->inputtexels);
396 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
399 rtexturepool_t *R_AllocTexturePool(void)
401 gltexturepool_t *pool;
402 if (texturemempool == NULL)
404 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
407 pool->next = gltexturepoolchain;
408 gltexturepoolchain = pool;
409 pool->sentinel = TEXTUREPOOL_SENTINEL;
410 return (rtexturepool_t *)pool;
413 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
415 gltexturepool_t *pool, **poolpointer;
416 if (rtexturepool == NULL)
418 if (*rtexturepool == NULL)
420 pool = (gltexturepool_t *)(*rtexturepool);
421 *rtexturepool = NULL;
422 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
423 Host_Error("R_FreeTexturePool: pool already freed");
424 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
425 if (*poolpointer == pool)
426 *poolpointer = pool->next;
428 Host_Error("R_FreeTexturePool: pool not linked");
429 while (pool->gltchain)
430 R_FreeTexture((rtexture_t *)pool->gltchain);
435 typedef struct glmode_s
438 int minification, magnification;
439 DPSOFTRAST_TEXTURE_FILTER dpsoftrastfilter_mipmap, dpsoftrastfilter_nomipmap;
443 static glmode_t modes[6] =
445 {"GL_NEAREST", GL_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
446 {"GL_LINEAR", GL_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
447 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
448 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
449 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
450 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR}
454 typedef struct d3dmode_s
461 static d3dmode_t d3dmodes[6] =
463 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
464 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
465 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
466 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
467 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
468 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
472 static void GL_TextureMode_f (void)
477 gltexturepool_t *pool;
481 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
482 for (i = 0;i < 6;i++)
484 if (gl_filter_min == modes[i].minification)
486 Con_Printf("%s\n", modes[i].name);
490 Con_Print("current filter is unknown???\n");
494 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
495 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
499 Con_Print("bad filter name\n");
503 gl_filter_min = modes[i].minification;
504 gl_filter_mag = modes[i].magnification;
505 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
507 dpsoftrast_filter_mipmap = modes[i].dpsoftrastfilter_mipmap;
508 dpsoftrast_filter_nomipmap = modes[i].dpsoftrastfilter_nomipmap;
510 switch(vid.renderpath)
512 case RENDERPATH_GL11:
513 case RENDERPATH_GL13:
514 case RENDERPATH_GL20:
515 case RENDERPATH_GLES1:
516 case RENDERPATH_GLES2:
517 // change all the existing mipmap texture objects
518 // FIXME: force renderer(/client/something?) restart instead?
521 for (pool = gltexturepoolchain;pool;pool = pool->next)
523 for (glt = pool->gltchain;glt;glt = glt->chain)
525 // only update already uploaded images
526 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
528 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
529 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
530 if (glt->flags & TEXF_MIPMAP)
532 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
536 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
538 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
539 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
544 case RENDERPATH_D3D9:
546 d3d_filter_flatmin = d3dmodes[i].m1;
547 d3d_filter_flatmag = d3dmodes[i].m1;
548 d3d_filter_flatmix = D3DTEXF_POINT;
549 d3d_filter_mipmin = d3dmodes[i].m1;
550 d3d_filter_mipmag = d3dmodes[i].m1;
551 d3d_filter_mipmix = d3dmodes[i].m2;
552 d3d_filter_nomip = i < 2;
553 if (gl_texture_anisotropy.integer > 1 && i == 5)
554 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
555 for (pool = gltexturepoolchain;pool;pool = pool->next)
557 for (glt = pool->gltchain;glt;glt = glt->chain)
559 // only update already uploaded images
560 if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
562 if (glt->flags & TEXF_MIPMAP)
564 glt->d3dminfilter = d3d_filter_mipmin;
565 glt->d3dmagfilter = d3d_filter_mipmag;
566 glt->d3dmipfilter = d3d_filter_mipmix;
567 glt->d3dmaxmiplevelfilter = 0;
571 glt->d3dminfilter = d3d_filter_flatmin;
572 glt->d3dmagfilter = d3d_filter_flatmag;
573 glt->d3dmipfilter = d3d_filter_flatmix;
574 glt->d3dmaxmiplevelfilter = 0;
581 case RENDERPATH_D3D10:
582 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
584 case RENDERPATH_D3D11:
585 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
587 case RENDERPATH_SOFT:
588 // change all the existing texture objects
589 for (pool = gltexturepoolchain;pool;pool = pool->next)
590 for (glt = pool->gltchain;glt;glt = glt->chain)
591 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
592 DPSOFTRAST_Texture_Filter(glt->texnum, (glt->flags & TEXF_MIPMAP) ? dpsoftrast_filter_mipmap : dpsoftrast_filter_nomipmap);
597 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)
599 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
604 case GLTEXTURETYPE_2D:
605 maxsize = vid.maxtexturesize_2d;
606 if (flags & TEXF_PICMIP)
608 maxsize = bound(1, gl_max_size.integer, maxsize);
612 case GLTEXTURETYPE_3D:
613 maxsize = vid.maxtexturesize_3d;
615 case GLTEXTURETYPE_CUBEMAP:
616 maxsize = vid.maxtexturesize_cubemap;
620 if (vid.support.arb_texture_non_power_of_two)
622 width2 = min(inwidth >> picmip, maxsize);
623 height2 = min(inheight >> picmip, maxsize);
624 depth2 = min(indepth >> picmip, maxsize);
628 for (width2 = 1;width2 < inwidth;width2 <<= 1);
629 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
630 for (height2 = 1;height2 < inheight;height2 <<= 1);
631 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
632 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
633 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
636 switch(vid.renderpath)
638 case RENDERPATH_GL11:
639 case RENDERPATH_GL13:
640 case RENDERPATH_GL20:
641 case RENDERPATH_D3D10:
642 case RENDERPATH_D3D11:
643 case RENDERPATH_SOFT:
644 case RENDERPATH_GLES1:
645 case RENDERPATH_GLES2:
647 case RENDERPATH_D3D9:
649 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
650 if (texturetype == GLTEXTURETYPE_2D)
652 width2 = max(width2, 2);
653 height2 = max(height2, 2);
660 if (flags & TEXF_MIPMAP)
662 int extent = max(width2, max(height2, depth2));
668 *outwidth = max(1, width2);
670 *outheight = max(1, height2);
672 *outdepth = max(1, depth2);
674 *outmiplevels = miplevels;
678 static int R_CalcTexelDataSize (gltexture_t *glt)
680 int width2, height2, depth2, size;
682 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
684 size = width2 * height2 * depth2;
686 if (glt->flags & TEXF_MIPMAP)
688 while (width2 > 1 || height2 > 1 || depth2 > 1)
696 size += width2 * height2 * depth2;
700 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
703 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
707 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
708 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
710 gltexturepool_t *pool;
712 Con_Print("glsize input loaded mip alpha name\n");
713 for (pool = gltexturepoolchain;pool;pool = pool->next)
721 for (glt = pool->gltchain;glt;glt = glt->chain)
723 glsize = R_CalcTexelDataSize(glt);
724 isloaded = glt->texnum != 0;
726 pooltotalt += glsize;
727 pooltotalp += glt->inputdatasize;
731 poolloadedt += glsize;
732 poolloadedp += glt->inputdatasize;
735 Con_Printf("%c%4i%c%c%4i%c %-24s %s %s %s %s\n", isloaded ? '[' : ' ', (glsize + 1023) / 1024, isloaded ? ']' : ' ', glt->inputtexels ? '[' : ' ', (glt->inputdatasize + 1023) / 1024, glt->inputtexels ? ']' : ' ', glt->textype->name, isloaded ? "loaded" : " ", (glt->flags & TEXF_MIPMAP) ? "mip" : " ", (glt->flags & TEXF_ALPHA) ? "alpha" : " ", glt->identifier);
738 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);
739 sumtotal += pooltotal;
740 sumtotalt += pooltotalt;
741 sumtotalp += pooltotalp;
742 sumloaded += poolloaded;
743 sumloadedt += poolloadedt;
744 sumloadedp += poolloadedp;
747 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);
750 static void R_TextureStats_f(void)
752 R_TextureStats_Print(true, true, true);
755 static void r_textures_start(void)
757 switch(vid.renderpath)
759 case RENDERPATH_GL11:
760 case RENDERPATH_GL13:
761 case RENDERPATH_GL20:
762 case RENDERPATH_GLES1:
763 case RENDERPATH_GLES2:
764 // LordHavoc: allow any alignment
766 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
767 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
769 case RENDERPATH_D3D9:
771 case RENDERPATH_D3D10:
772 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
774 case RENDERPATH_D3D11:
775 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
777 case RENDERPATH_SOFT:
781 texturemempool = Mem_AllocPool("texture management", 0, NULL);
782 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
784 // Disable JPEG screenshots if the DLL isn't loaded
785 if (! JPEG_OpenLibrary ())
786 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
787 if (! PNG_OpenLibrary ())
788 Cvar_SetValueQuick (&scr_screenshot_png, 0);
791 static void r_textures_shutdown(void)
793 rtexturepool_t *temp;
795 JPEG_CloseLibrary ();
797 while(gltexturepoolchain)
799 temp = (rtexturepool_t *) gltexturepoolchain;
800 R_FreeTexturePool(&temp);
803 resizebuffersize = 0;
805 colorconvertbuffer = NULL;
806 texturebuffer = NULL;
807 Mem_ExpandableArray_FreeArray(&texturearray);
808 Mem_FreePool(&texturemempool);
811 static void r_textures_newmap(void)
815 static void r_textures_devicelost(void)
819 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
820 for (i = 0;i < endindex;i++)
822 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
823 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
825 switch(vid.renderpath)
827 case RENDERPATH_GL11:
828 case RENDERPATH_GL13:
829 case RENDERPATH_GL20:
830 case RENDERPATH_GLES1:
831 case RENDERPATH_GLES2:
833 case RENDERPATH_D3D9:
835 if (glt->d3disdepthsurface)
836 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
837 else if (glt->tiledepth > 1)
838 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
839 else if (glt->sides == 6)
840 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
842 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
843 glt->d3dtexture = NULL;
846 case RENDERPATH_D3D10:
847 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
849 case RENDERPATH_D3D11:
850 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
852 case RENDERPATH_SOFT:
858 static void r_textures_devicerestored(void)
862 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
863 for (i = 0;i < endindex;i++)
865 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
866 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
868 switch(vid.renderpath)
870 case RENDERPATH_GL11:
871 case RENDERPATH_GL13:
872 case RENDERPATH_GL20:
873 case RENDERPATH_GLES1:
874 case RENDERPATH_GLES2:
876 case RENDERPATH_D3D9:
880 if (glt->d3disdepthsurface)
882 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
883 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
885 else if (glt->tiledepth > 1)
887 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)))
888 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
890 else if (glt->sides == 6)
892 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
893 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
897 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)))
898 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
903 case RENDERPATH_D3D10:
904 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
906 case RENDERPATH_D3D11:
907 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
909 case RENDERPATH_SOFT:
916 void R_Textures_Init (void)
918 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");
919 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
920 Cvar_RegisterVariable (&gl_max_size);
921 Cvar_RegisterVariable (&gl_picmip);
922 Cvar_RegisterVariable (&gl_picmip_world);
923 Cvar_RegisterVariable (&r_picmipworld);
924 Cvar_RegisterVariable (&gl_picmip_sprites);
925 Cvar_RegisterVariable (&r_picmipsprites);
926 Cvar_RegisterVariable (&gl_picmip_other);
927 Cvar_RegisterVariable (&gl_max_lightmapsize);
928 Cvar_RegisterVariable (&r_lerpimages);
929 Cvar_RegisterVariable (&gl_texture_anisotropy);
930 Cvar_RegisterVariable (&gl_texturecompression);
931 Cvar_RegisterVariable (&gl_texturecompression_color);
932 Cvar_RegisterVariable (&gl_texturecompression_normal);
933 Cvar_RegisterVariable (&gl_texturecompression_gloss);
934 Cvar_RegisterVariable (&gl_texturecompression_glow);
935 Cvar_RegisterVariable (&gl_texturecompression_2d);
936 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
937 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
938 Cvar_RegisterVariable (&gl_texturecompression_sky);
939 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
940 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
941 Cvar_RegisterVariable (&gl_texturecompression_sprites);
942 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
943 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
944 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
945 Cvar_RegisterVariable (&r_texture_dds_swdecode);
947 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
950 void R_Textures_Frame (void)
952 static int old_aniso = 0;
954 // could do procedural texture animation here, if we keep track of which
955 // textures were accessed this frame...
957 // free the resize buffers
958 resizebuffersize = 0;
961 Mem_Free(resizebuffer);
964 if (colorconvertbuffer)
966 Mem_Free(colorconvertbuffer);
967 colorconvertbuffer = NULL;
970 if (old_aniso != gl_texture_anisotropy.integer)
973 gltexturepool_t *pool;
976 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
978 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
980 switch(vid.renderpath)
982 case RENDERPATH_GL11:
983 case RENDERPATH_GL13:
984 case RENDERPATH_GL20:
985 case RENDERPATH_GLES1:
986 case RENDERPATH_GLES2:
989 for (pool = gltexturepoolchain;pool;pool = pool->next)
991 for (glt = pool->gltchain;glt;glt = glt->chain)
993 // only update already uploaded images
994 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
996 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
998 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
999 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
1001 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1006 case RENDERPATH_D3D9:
1007 case RENDERPATH_D3D10:
1008 case RENDERPATH_D3D11:
1009 case RENDERPATH_SOFT:
1015 static void R_MakeResizeBufferBigger(int size)
1017 if (resizebuffersize < size)
1019 resizebuffersize = size;
1021 Mem_Free(resizebuffer);
1022 if (colorconvertbuffer)
1023 Mem_Free(colorconvertbuffer);
1024 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
1025 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
1026 if (!resizebuffer || !colorconvertbuffer)
1027 Host_Error("R_Upload: out of memory");
1031 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
1033 int textureenum = gltexturetypeenums[texturetype];
1034 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
1038 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
1040 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
1041 if (gl_texture_anisotropy.integer != aniso)
1042 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
1043 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
1045 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
1046 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
1047 #ifdef GL_TEXTURE_WRAP_R
1048 if (gltexturetypedimensions[texturetype] >= 3)
1050 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
1055 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
1057 if (flags & TEXF_MIPMAP)
1059 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
1063 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
1065 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
1067 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
1069 if (flags & TEXF_MIPMAP)
1071 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
1073 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
1077 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
1082 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
1084 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
1088 if (flags & TEXF_MIPMAP)
1090 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1094 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1096 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1100 if (textype == TEXTYPE_SHADOWMAP)
1102 if (vid.support.arb_shadow)
1104 if (flags & TEXF_COMPARE)
1106 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1110 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1112 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1114 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1121 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1124 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1126 if (glt->texturetype != GLTEXTURETYPE_2D)
1127 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1129 if (glt->textype->textype == TEXTYPE_PALETTE)
1130 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1132 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1133 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1135 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1136 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1138 // update a portion of the image
1140 switch(vid.renderpath)
1142 case RENDERPATH_GL11:
1143 case RENDERPATH_GL13:
1144 case RENDERPATH_GL20:
1145 case RENDERPATH_GLES1:
1146 case RENDERPATH_GLES2:
1150 // we need to restore the texture binding after finishing the upload
1151 GL_ActiveTexture(0);
1152 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1153 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1154 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1155 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1158 case RENDERPATH_D3D9:
1162 D3DLOCKED_RECT d3dlockedrect;
1164 memset(&d3drect, 0, sizeof(d3drect));
1165 d3drect.left = fragx;
1166 d3drect.top = fragy;
1167 d3drect.right = fragx+fragwidth;
1168 d3drect.bottom = fragy+fragheight;
1169 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1171 for (y = 0;y < fragheight;y++)
1172 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1173 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1178 case RENDERPATH_D3D10:
1179 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1181 case RENDERPATH_D3D11:
1182 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1184 case RENDERPATH_SOFT:
1185 DPSOFTRAST_Texture_UpdatePartial(glt->texnum, 0, data, fragx, fragy, fragwidth, fragheight);
1190 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1192 int i, mip = 0, width, height, depth;
1193 GLint oldbindtexnum = 0;
1194 const unsigned char *prevbuffer;
1197 // error out if a stretch is needed on special texture types
1198 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1199 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1201 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1202 // of the target size and then use the mipmap reduction function to get
1203 // high quality supersampled results
1204 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1205 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1206 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1207 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1209 if (prevbuffer == NULL)
1211 width = glt->tilewidth;
1212 height = glt->tileheight;
1213 depth = glt->tiledepth;
1214 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1215 // prevbuffer = resizebuffer;
1219 if (glt->textype->textype == TEXTYPE_PALETTE)
1221 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1222 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1223 prevbuffer = colorconvertbuffer;
1225 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1227 // multiply RGB channels by A channel before uploading
1229 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1231 alpha = prevbuffer[i+3];
1232 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1233 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1234 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1235 colorconvertbuffer[i+3] = alpha;
1237 prevbuffer = colorconvertbuffer;
1239 // scale up to a power of 2 size (if appropriate)
1240 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1242 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1243 prevbuffer = resizebuffer;
1245 // apply mipmap reduction algorithm to get down to picmip/max_size
1246 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1248 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1249 prevbuffer = resizebuffer;
1253 // do the appropriate upload type...
1254 switch(vid.renderpath)
1256 case RENDERPATH_GL11:
1257 case RENDERPATH_GL13:
1258 case RENDERPATH_GL20:
1259 case RENDERPATH_GLES1:
1260 case RENDERPATH_GLES2:
1263 // we need to restore the texture binding after finishing the upload
1264 GL_ActiveTexture(0);
1265 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1266 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1268 #ifdef GL_TEXTURE_COMPRESSION_HINT_ARB
1269 if (qglGetCompressedTexImageARB)
1271 if (gl_texturecompression.integer >= 2)
1272 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1274 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1278 switch(glt->texturetype)
1280 case GLTEXTURETYPE_2D:
1281 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1282 if (glt->flags & TEXF_MIPMAP)
1284 while (width > 1 || height > 1 || depth > 1)
1286 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1287 prevbuffer = resizebuffer;
1288 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1292 case GLTEXTURETYPE_3D:
1294 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1295 if (glt->flags & TEXF_MIPMAP)
1297 while (width > 1 || height > 1 || depth > 1)
1299 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1300 prevbuffer = resizebuffer;
1301 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1306 case GLTEXTURETYPE_CUBEMAP:
1307 // convert and upload each side in turn,
1308 // from a continuous block of input texels
1309 texturebuffer = (unsigned char *)prevbuffer;
1310 for (i = 0;i < 6;i++)
1312 prevbuffer = texturebuffer;
1313 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1314 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1316 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1317 prevbuffer = resizebuffer;
1320 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1322 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1323 prevbuffer = resizebuffer;
1326 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1327 if (glt->flags & TEXF_MIPMAP)
1329 while (width > 1 || height > 1 || depth > 1)
1331 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1332 prevbuffer = resizebuffer;
1333 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1339 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1340 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1342 case RENDERPATH_D3D9:
1344 if (!(glt->flags & TEXF_RENDERTARGET))
1346 D3DLOCKED_RECT d3dlockedrect;
1347 D3DLOCKED_BOX d3dlockedbox;
1348 switch(glt->texturetype)
1350 case GLTEXTURETYPE_2D:
1351 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1354 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1356 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1357 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1360 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1362 while (width > 1 || height > 1 || depth > 1)
1364 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1365 prevbuffer = resizebuffer;
1366 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1368 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1369 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1375 case GLTEXTURETYPE_3D:
1376 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1378 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1379 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1380 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1383 if (glt->flags & TEXF_MIPMAP)
1385 while (width > 1 || height > 1 || depth > 1)
1387 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1388 prevbuffer = resizebuffer;
1389 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1391 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1392 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1393 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1399 case GLTEXTURETYPE_CUBEMAP:
1400 // convert and upload each side in turn,
1401 // from a continuous block of input texels
1402 texturebuffer = (unsigned char *)prevbuffer;
1403 for (i = 0;i < 6;i++)
1405 prevbuffer = texturebuffer;
1406 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1407 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1409 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1410 prevbuffer = resizebuffer;
1413 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1415 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1416 prevbuffer = resizebuffer;
1419 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1421 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1422 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1425 if (glt->flags & TEXF_MIPMAP)
1427 while (width > 1 || height > 1 || depth > 1)
1429 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1430 prevbuffer = resizebuffer;
1431 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1433 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1434 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1443 glt->d3daddressw = 0;
1444 if (glt->flags & TEXF_CLAMP)
1446 glt->d3daddressu = D3DTADDRESS_CLAMP;
1447 glt->d3daddressv = D3DTADDRESS_CLAMP;
1448 if (glt->tiledepth > 1)
1449 glt->d3daddressw = D3DTADDRESS_CLAMP;
1453 glt->d3daddressu = D3DTADDRESS_WRAP;
1454 glt->d3daddressv = D3DTADDRESS_WRAP;
1455 if (glt->tiledepth > 1)
1456 glt->d3daddressw = D3DTADDRESS_WRAP;
1458 glt->d3dmipmaplodbias = 0;
1459 glt->d3dmaxmiplevel = 0;
1460 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1461 if (glt->flags & TEXF_FORCELINEAR)
1463 glt->d3dminfilter = D3DTEXF_LINEAR;
1464 glt->d3dmagfilter = D3DTEXF_LINEAR;
1465 glt->d3dmipfilter = D3DTEXF_POINT;
1467 else if (glt->flags & TEXF_FORCENEAREST)
1469 glt->d3dminfilter = D3DTEXF_POINT;
1470 glt->d3dmagfilter = D3DTEXF_POINT;
1471 glt->d3dmipfilter = D3DTEXF_POINT;
1473 else if (glt->flags & TEXF_MIPMAP)
1475 glt->d3dminfilter = d3d_filter_mipmin;
1476 glt->d3dmagfilter = d3d_filter_mipmag;
1477 glt->d3dmipfilter = d3d_filter_mipmix;
1481 glt->d3dminfilter = d3d_filter_flatmin;
1482 glt->d3dmagfilter = d3d_filter_flatmag;
1483 glt->d3dmipfilter = d3d_filter_flatmix;
1487 case RENDERPATH_D3D10:
1488 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1490 case RENDERPATH_D3D11:
1491 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1493 case RENDERPATH_SOFT:
1494 switch(glt->texturetype)
1496 case GLTEXTURETYPE_2D:
1497 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1499 case GLTEXTURETYPE_3D:
1500 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1502 case GLTEXTURETYPE_CUBEMAP:
1503 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1505 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1506 // convert and upload each side in turn,
1507 // from a continuous block of input texels
1508 // copy the results into combinedbuffer
1509 texturebuffer = (unsigned char *)prevbuffer;
1510 for (i = 0;i < 6;i++)
1512 prevbuffer = texturebuffer;
1513 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1514 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1516 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1517 prevbuffer = resizebuffer;
1520 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1522 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1523 prevbuffer = resizebuffer;
1525 memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1527 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1528 Mem_Free(combinedbuffer);
1531 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1534 if (glt->flags & TEXF_FORCELINEAR)
1535 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1536 else if (glt->flags & TEXF_FORCENEAREST)
1537 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1538 else if (glt->flags & TEXF_MIPMAP)
1539 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1541 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1546 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)
1550 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1551 textypeinfo_t *texinfo, *texinfo2;
1552 unsigned char *temppixels = NULL;
1555 if (cls.state == ca_dedicated)
1558 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1559 if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1561 int numpixels = width * height * depth * sides;
1562 size = numpixels * 4;
1563 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1566 const unsigned char *p;
1567 unsigned char *o = temppixels;
1568 for (i = 0;i < numpixels;i++, o += 4)
1570 p = (const unsigned char *)palette + 4*data[i];
1578 textype = TEXTYPE_RGBA;
1583 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1584 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1585 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1586 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1592 static int rgbaswapindices[4] = {2, 1, 0, 3};
1593 size = width * height * depth * sides * 4;
1594 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1596 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1600 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1601 if (!vid.support.ext_texture_srgb)
1603 qboolean convertsRGB = false;
1606 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1607 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1608 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1609 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1610 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;convertsRGB = true;break;
1611 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1612 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1616 if (convertsRGB && data)
1618 size = width * height * depth * sides * 4;
1621 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1622 memcpy(temppixels, data, size);
1625 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1629 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1631 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1634 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1636 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1640 texinfo = R_GetTexTypeInfo(textype, flags);
1641 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1644 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1648 // clear the alpha flag if the texture has no transparent pixels
1651 case TEXTYPE_PALETTE:
1652 case TEXTYPE_SRGB_PALETTE:
1653 if (flags & TEXF_ALPHA)
1655 flags &= ~TEXF_ALPHA;
1658 for (i = 0;i < size;i++)
1660 if (((unsigned char *)&palette[data[i]])[3] < 255)
1662 flags |= TEXF_ALPHA;
1671 case TEXTYPE_SRGB_RGBA:
1672 case TEXTYPE_SRGB_BGRA:
1673 if (flags & TEXF_ALPHA)
1675 flags &= ~TEXF_ALPHA;
1678 for (i = 3;i < size;i += 4)
1682 flags |= TEXF_ALPHA;
1689 case TEXTYPE_SHADOWMAP:
1692 case TEXTYPE_SRGB_DXT1:
1695 case TEXTYPE_SRGB_DXT1A:
1697 case TEXTYPE_SRGB_DXT3:
1699 case TEXTYPE_SRGB_DXT5:
1700 flags |= TEXF_ALPHA;
1703 flags |= TEXF_ALPHA;
1705 case TEXTYPE_COLORBUFFER:
1706 case TEXTYPE_COLORBUFFER16F:
1707 case TEXTYPE_COLORBUFFER32F:
1708 flags |= TEXF_ALPHA;
1711 Sys_Error("R_LoadTexture: unknown texture type");
1714 texinfo2 = R_GetTexTypeInfo(textype, flags);
1715 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1718 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1720 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1722 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1724 glt->chain = pool->gltchain;
1725 pool->gltchain = glt;
1726 glt->inputwidth = width;
1727 glt->inputheight = height;
1728 glt->inputdepth = depth;
1730 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
1731 glt->textype = texinfo;
1732 glt->texturetype = texturetype;
1733 glt->inputdatasize = size;
1734 glt->palette = palette;
1735 glt->glinternalformat = texinfo->glinternalformat;
1736 glt->glformat = texinfo->glformat;
1737 glt->gltype = texinfo->gltype;
1738 glt->bytesperpixel = texinfo->internalbytesperpixel;
1739 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1742 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1743 // init the dynamic texture attributes, too [11/22/2007 Black]
1744 glt->updatecallback = NULL;
1745 glt->updatacallback_data = NULL;
1747 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1749 // upload the texture
1750 // data may be NULL (blank texture for dynamic rendering)
1751 switch(vid.renderpath)
1753 case RENDERPATH_GL11:
1754 case RENDERPATH_GL13:
1755 case RENDERPATH_GL20:
1756 case RENDERPATH_GLES1:
1757 case RENDERPATH_GLES2:
1759 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1761 case RENDERPATH_D3D9:
1764 D3DFORMAT d3dformat;
1769 d3dpool = D3DPOOL_MANAGED;
1770 if (flags & TEXF_RENDERTARGET)
1772 d3dusage |= D3DUSAGE_RENDERTARGET;
1773 d3dpool = D3DPOOL_DEFAULT;
1777 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1778 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1779 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1780 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
1781 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
1782 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
1783 case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1784 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1785 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1787 glt->d3dformat = d3dformat;
1788 glt->d3dusage = d3dusage;
1789 glt->d3dpool = d3dpool;
1790 glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
1791 if (glt->d3disdepthsurface)
1793 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
1794 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1796 else if (glt->tiledepth > 1)
1798 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)))
1799 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1801 else if (glt->sides == 6)
1803 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1804 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1808 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)))
1809 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1814 case RENDERPATH_D3D10:
1815 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1817 case RENDERPATH_D3D11:
1818 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1820 case RENDERPATH_SOFT:
1825 case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1826 case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1827 case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1828 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1829 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
1830 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
1831 case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1832 case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1833 default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1835 if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1836 if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1837 if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1838 if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1839 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1844 R_UploadFullTexture(glt, data);
1845 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1846 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1848 // free any temporary processing buffer we allocated...
1850 Mem_Free(temppixels);
1852 // texture converting and uploading can take a while, so make sure we're sending keepalives
1853 // FIXME: this causes rendering during R_Shadow_DrawLights
1854 // CL_KeepaliveMessage(false);
1856 return (rtexture_t *)glt;
1859 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)
1861 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1864 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)
1866 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1869 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)
1871 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1874 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1876 int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1878 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1880 flags |= TEXF_FORCENEAREST;
1881 if (precision <= 16)
1882 flags |= TEXF_LOWPRECISION;
1886 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1888 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1891 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1894 return -1; // unsupported on this platform
1896 gltexture_t *glt = (gltexture_t *)rt;
1899 int bytesperpixel = 0;
1900 int bytesperblock = 0;
1902 int dds_format_flags;
1910 GLint internalformat;
1911 const char *ddsfourcc;
1913 return -1; // NULL pointer
1914 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1915 return -2; // broken driver - crashes on reading internal format
1916 if (!qglGetTexLevelParameteriv)
1918 GL_ActiveTexture(0);
1919 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1920 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1921 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1922 switch(internalformat)
1924 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1925 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1926 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1927 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1928 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1930 // if premultiplied alpha, say so in the DDS file
1931 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1933 switch(internalformat)
1935 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1936 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1939 if (!bytesperblock && skipuncompressed)
1940 return -3; // skipped
1941 memset(mipinfo, 0, sizeof(mipinfo));
1942 mipinfo[0][0] = glt->tilewidth;
1943 mipinfo[0][1] = glt->tileheight;
1945 if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tilewidth == 1))
1947 for (mip = 1;mip < 16;mip++)
1949 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1950 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1951 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1959 for (mip = 0;mip < mipmaps;mip++)
1961 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1962 mipinfo[mip][3] = ddssize;
1963 ddssize += mipinfo[mip][2];
1965 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1968 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1972 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1973 dds_format_flags = 0x4; // DDPF_FOURCC
1977 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1978 dds_format_flags = 0x40; // DDPF_RGB
1982 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1983 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1986 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1987 memcpy(dds, "DDS ", 4);
1988 StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
1989 StoreLittleLong(dds+8, dds_flags);
1990 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1991 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1992 StoreLittleLong(dds+24, 0); // depth
1993 StoreLittleLong(dds+28, mipmaps); // mipmaps
1994 StoreLittleLong(dds+76, 32); // format size
1995 StoreLittleLong(dds+80, dds_format_flags);
1996 StoreLittleLong(dds+108, dds_caps1);
1997 StoreLittleLong(dds+112, dds_caps2);
2000 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
2001 memcpy(dds+84, ddsfourcc, 4);
2002 for (mip = 0;mip < mipmaps;mip++)
2004 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
2009 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
2010 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
2011 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
2012 for (mip = 0;mip < mipmaps;mip++)
2014 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
2017 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2018 ret = FS_WriteFile(filename, dds, ddssize);
2020 return ret ? ddssize : -5;
2024 rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qboolean srgb, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint
2026 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
2029 int bytesperblock, bytesperpixel;
2032 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
2033 textypeinfo_t *texinfo;
2034 int mip, mipwidth, mipheight, mipsize, mipsize_total;
2035 unsigned int c, r, g, b;
2036 GLint oldbindtexnum = 0;
2037 unsigned char *mippixels;
2038 unsigned char *mippixels_start;
2039 unsigned char *ddspixels;
2041 fs_offset_t ddsfilesize;
2042 unsigned int ddssize;
2043 qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
2045 if (cls.state == ca_dedicated)
2048 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
2049 ddssize = ddsfilesize;
2053 if(r_texture_dds_load_logfailure.integer)
2054 Log_Printf("ddstexturefailures.log", "%s\n", filename);
2055 return NULL; // not found
2058 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
2061 Con_Printf("^1%s: not a DDS image\n", filename);
2065 //dds_flags = BuffLittleLong(dds+8);
2066 dds_format_flags = BuffLittleLong(dds+80);
2067 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
2068 dds_width = BuffLittleLong(dds+16);
2069 dds_height = BuffLittleLong(dds+12);
2070 ddspixels = dds + 128;
2072 if(r_texture_dds_load_alphamode.integer == 0)
2073 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
2074 flags &= ~TEXF_ALPHA;
2076 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
2077 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
2079 // very sloppy BGRA 32bit identification
2080 textype = TEXTYPE_BGRA;
2081 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2084 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
2085 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2088 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
2091 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
2094 for (i = 3;i < size;i += 4)
2095 if (ddspixels[i] < 255)
2098 flags &= ~TEXF_ALPHA;
2101 else if (!memcmp(dds+84, "DXT1", 4))
2103 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
2104 // LordHavoc: it is my belief that this does not infringe on the
2105 // patent because it is not decoding pixels...
2106 textype = TEXTYPE_DXT1;
2109 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
2110 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2111 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2114 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
2117 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
2119 if(r_texture_dds_load_alphamode.integer == 1)
2122 for (i = 0;i < size;i += bytesperblock)
2123 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
2125 // NOTE: this assumes sizeof(unsigned int) == 4
2126 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
2127 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
2128 if(data & (data<<1) & 0xAAAAAAAA)//rgh
2132 textype = TEXTYPE_DXT1A;
2134 flags &= ~TEXF_ALPHA;
2138 flags &= ~TEXF_ALPHA;
2142 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2144 if(!memcmp(dds+84, "DXT2", 4))
2146 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2148 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2153 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2155 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2158 textype = TEXTYPE_DXT3;
2161 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2162 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2165 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2168 // we currently always assume alpha
2170 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2172 if(!memcmp(dds+84, "DXT4", 4))
2174 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2176 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2181 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2183 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2186 textype = TEXTYPE_DXT5;
2189 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2190 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2193 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2196 // we currently always assume alpha
2201 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2205 // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
2206 if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
2208 textype = TEXTYPE_DXT1;
2212 for (i = 0;i < (int)ddssize;i += bytesperblock)
2213 memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
2217 force_swdecode = false;
2220 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
2222 if(r_texture_dds_swdecode.integer > 1)
2223 force_swdecode = true;
2227 if(r_texture_dds_swdecode.integer < 1)
2233 force_swdecode = true;
2237 // return whether this texture is transparent
2239 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2241 // if we SW decode, choose 2 sizes bigger
2244 // this is quarter res, so do not scale down more than we have to
2248 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2251 // this is where we apply gl_picmip
2252 mippixels_start = ddspixels;
2253 mipwidth = dds_width;
2254 mipheight = dds_height;
2255 while(miplevel >= 1 && dds_miplevels >= 1)
2257 if (mipwidth <= 1 && mipheight <= 1)
2259 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2260 mippixels_start += mipsize; // just skip
2268 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2269 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2271 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2273 // fake decode S3TC if needed
2276 int mipsize_new = mipsize_total / bytesperblock * 4;
2277 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2278 unsigned char *p = mipnewpixels;
2279 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2281 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2282 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2283 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2284 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2285 if(textype == TEXTYPE_DXT5)
2286 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2287 else if(textype == TEXTYPE_DXT3)
2289 (mippixels_start[i-8] & 0x0F)
2290 + (mippixels_start[i-8] >> 4)
2291 + (mippixels_start[i-7] & 0x0F)
2292 + (mippixels_start[i-7] >> 4)
2293 + (mippixels_start[i-6] & 0x0F)
2294 + (mippixels_start[i-6] >> 4)
2295 + (mippixels_start[i-5] & 0x0F)
2296 + (mippixels_start[i-5] >> 4)
2297 ) * (0.125f / 15.0f * 255.0f);
2302 textype = TEXTYPE_BGRA;
2306 // as each block becomes a pixel, we must use pixel count for this
2307 mipwidth = (mipwidth + 3) / 4;
2308 mipheight = (mipheight + 3) / 4;
2309 mipsize = bytesperpixel * mipwidth * mipheight;
2310 mippixels_start = mipnewpixels;
2311 mipsize_total = mipsize_new;
2314 // start mip counting
2315 mippixels = mippixels_start;
2317 // calculate average color if requested
2321 Vector4Clear(avgcolor);
2324 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2326 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2327 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2328 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2329 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2330 if(textype == TEXTYPE_DXT5)
2331 avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2332 else if(textype == TEXTYPE_DXT3)
2334 (mippixels_start[i-8] & 0x0F)
2335 + (mippixels_start[i-8] >> 4)
2336 + (mippixels_start[i-7] & 0x0F)
2337 + (mippixels_start[i-7] >> 4)
2338 + (mippixels_start[i-6] & 0x0F)
2339 + (mippixels_start[i-6] >> 4)
2340 + (mippixels_start[i-5] & 0x0F)
2341 + (mippixels_start[i-5] >> 4)
2342 ) * (0.125f / 15.0f * 255.0f);
2346 f = (float)bytesperblock / size;
2347 avgcolor[0] *= (0.5f / 31.0f) * f;
2348 avgcolor[1] *= (0.5f / 63.0f) * f;
2349 avgcolor[2] *= (0.5f / 31.0f) * f;
2354 for (i = 0;i < mipsize;i += 4)
2356 avgcolor[0] += mippixels[i+2];
2357 avgcolor[1] += mippixels[i+1];
2358 avgcolor[2] += mippixels[i];
2359 avgcolor[3] += mippixels[i+3];
2361 f = (1.0f / 255.0f) * bytesperpixel / size;
2369 // if we want sRGB, convert now
2372 if (vid.support.ext_texture_srgb)
2376 case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break;
2377 case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break;
2378 case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break;
2379 case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break;
2380 case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break;
2394 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2396 int c0, c1, c0new, c1new;
2397 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2398 r = ((c0 >> 11) & 0x1F);
2399 g = ((c0 >> 5) & 0x3F);
2401 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2402 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2403 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2404 c0new = (r << 11) | (g << 5) | b;
2405 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2406 r = ((c1 >> 11) & 0x1F);
2407 g = ((c1 >> 5) & 0x3F);
2409 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2410 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2411 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2412 c1new = (r << 11) | (g << 5) | b;
2413 // swap the colors if needed to fix order
2414 if(c0 > c1) // thirds
2422 mippixels_start[i+4] ^= 0x55;
2423 mippixels_start[i+5] ^= 0x55;
2424 mippixels_start[i+6] ^= 0x55;
2425 mippixels_start[i+7] ^= 0x55;
2427 else if(c0new == c1new)
2429 mippixels_start[i+4] = 0x00;
2430 mippixels_start[i+5] = 0x00;
2431 mippixels_start[i+6] = 0x00;
2432 mippixels_start[i+7] = 0x00;
2435 else // half + transparent
2442 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2443 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2444 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2445 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2448 mippixels_start[i] = c0new & 255;
2449 mippixels_start[i+1] = c0new >> 8;
2450 mippixels_start[i+2] = c1new & 255;
2451 mippixels_start[i+3] = c1new >> 8;
2456 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2464 // when not requesting mipmaps, do not load them
2465 if(!(flags & TEXF_MIPMAP))
2468 if (dds_miplevels >= 1)
2469 flags |= TEXF_MIPMAP;
2471 flags &= ~TEXF_MIPMAP;
2473 texinfo = R_GetTexTypeInfo(textype, flags);
2475 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2476 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2478 glt->chain = pool->gltchain;
2479 pool->gltchain = glt;
2480 glt->inputwidth = mipwidth;
2481 glt->inputheight = mipheight;
2482 glt->inputdepth = 1;
2484 glt->textype = texinfo;
2485 glt->texturetype = GLTEXTURETYPE_2D;
2486 glt->inputdatasize = ddssize;
2487 glt->glinternalformat = texinfo->glinternalformat;
2488 glt->glformat = texinfo->glformat;
2489 glt->gltype = texinfo->gltype;
2490 glt->bytesperpixel = texinfo->internalbytesperpixel;
2492 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2493 glt->tilewidth = mipwidth;
2494 glt->tileheight = mipheight;
2496 glt->miplevels = dds_miplevels;
2498 // texture uploading can take a while, so make sure we're sending keepalives
2499 CL_KeepaliveMessage(false);
2501 // create the texture object
2502 switch(vid.renderpath)
2504 case RENDERPATH_GL11:
2505 case RENDERPATH_GL13:
2506 case RENDERPATH_GL20:
2507 case RENDERPATH_GLES1:
2508 case RENDERPATH_GLES2:
2510 GL_ActiveTexture(0);
2511 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2512 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2513 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2515 case RENDERPATH_D3D9:
2518 D3DFORMAT d3dformat;
2523 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2524 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2525 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2526 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2527 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2530 d3dpool = D3DPOOL_MANAGED;
2531 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2535 case RENDERPATH_D3D10:
2536 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2538 case RENDERPATH_D3D11:
2539 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2541 case RENDERPATH_SOFT:
2542 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);
2546 // upload the texture
2547 // we need to restore the texture binding after finishing the upload
2548 mipcomplete = false;
2550 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2552 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2553 if (mippixels + mipsize > mippixels_start + mipsize_total)
2555 switch(vid.renderpath)
2557 case RENDERPATH_GL11:
2558 case RENDERPATH_GL13:
2559 case RENDERPATH_GL20:
2560 case RENDERPATH_GLES1:
2561 case RENDERPATH_GLES2:
2564 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2568 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2571 case RENDERPATH_D3D9:
2574 D3DLOCKED_RECT d3dlockedrect;
2575 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2577 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2578 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2584 case RENDERPATH_D3D10:
2585 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2587 case RENDERPATH_D3D11:
2588 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2590 case RENDERPATH_SOFT:
2592 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2594 DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
2595 // DPSOFTRAST calculates its own mipmaps
2596 mip = dds_miplevels;
2599 mippixels += mipsize;
2600 if (mipwidth <= 1 && mipheight <= 1)
2611 // after upload we have to set some parameters...
2612 switch(vid.renderpath)
2614 case RENDERPATH_GL11:
2615 case RENDERPATH_GL13:
2616 case RENDERPATH_GL20:
2617 case RENDERPATH_GLES1:
2618 case RENDERPATH_GLES2:
2619 #ifdef GL_TEXTURE_MAX_LEVEL
2620 if (dds_miplevels >= 1 && !mipcomplete)
2622 // need to set GL_TEXTURE_MAX_LEVEL
2623 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2626 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2627 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2629 case RENDERPATH_D3D9:
2631 glt->d3daddressw = 0;
2632 if (glt->flags & TEXF_CLAMP)
2634 glt->d3daddressu = D3DTADDRESS_CLAMP;
2635 glt->d3daddressv = D3DTADDRESS_CLAMP;
2636 if (glt->tiledepth > 1)
2637 glt->d3daddressw = D3DTADDRESS_CLAMP;
2641 glt->d3daddressu = D3DTADDRESS_WRAP;
2642 glt->d3daddressv = D3DTADDRESS_WRAP;
2643 if (glt->tiledepth > 1)
2644 glt->d3daddressw = D3DTADDRESS_WRAP;
2646 glt->d3dmipmaplodbias = 0;
2647 glt->d3dmaxmiplevel = 0;
2648 glt->d3dmaxmiplevelfilter = 0;
2649 if (glt->flags & TEXF_MIPMAP)
2651 glt->d3dminfilter = d3d_filter_mipmin;
2652 glt->d3dmagfilter = d3d_filter_mipmag;
2653 glt->d3dmipfilter = d3d_filter_mipmix;
2657 glt->d3dminfilter = d3d_filter_flatmin;
2658 glt->d3dmagfilter = d3d_filter_flatmag;
2659 glt->d3dmipfilter = d3d_filter_flatmix;
2663 case RENDERPATH_D3D10:
2664 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2666 case RENDERPATH_D3D11:
2667 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2669 case RENDERPATH_SOFT:
2670 if (glt->flags & TEXF_FORCELINEAR)
2671 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2672 else if (glt->flags & TEXF_FORCENEAREST)
2673 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2674 else if (glt->flags & TEXF_MIPMAP)
2675 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2677 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2683 Mem_Free((unsigned char *) mippixels_start);
2684 return (rtexture_t *)glt;
2687 int R_TextureWidth(rtexture_t *rt)
2689 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2692 int R_TextureHeight(rtexture_t *rt)
2694 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2697 int R_TextureFlags(rtexture_t *rt)
2699 return rt ? ((gltexture_t *)rt)->flags : 0;
2702 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2704 gltexture_t *glt = (gltexture_t *)rt;
2706 Host_Error("R_UpdateTexture: no data supplied");
2708 Host_Error("R_UpdateTexture: no texture supplied");
2709 if (!glt->texnum && !glt->d3dtexture)
2711 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2714 // update part of the texture
2715 if (glt->bufferpixels)
2718 int bpp = glt->bytesperpixel;
2719 int inputskip = width*bpp;
2720 int outputskip = glt->tilewidth*bpp;
2721 const unsigned char *input = data;
2722 unsigned char *output = glt->bufferpixels;
2723 if (glt->inputdepth != 1 || glt->sides != 1)
2724 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2734 input -= y*inputskip;
2737 if (width > glt->tilewidth - x)
2738 width = glt->tilewidth - x;
2739 if (height > glt->tileheight - y)
2740 height = glt->tileheight - y;
2741 if (width < 1 || height < 1)
2744 glt->buffermodified = true;
2745 output += y*outputskip + x*bpp;
2746 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2747 memcpy(output, input, width*bpp);
2749 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2750 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2752 R_UploadFullTexture(glt, data);
2755 int R_RealGetTexture(rtexture_t *rt)
2760 glt = (gltexture_t *)rt;
2761 if (glt->flags & GLTEXF_DYNAMIC)
2762 R_UpdateDynamicTexture(glt);
2763 if (glt->buffermodified && glt->bufferpixels)
2765 glt->buffermodified = false;
2766 R_UploadFullTexture(glt, glt->bufferpixels);
2775 void R_ClearTexture (rtexture_t *rt)
2777 gltexture_t *glt = (gltexture_t *)rt;
2779 R_UploadFullTexture(glt, NULL);
2782 int R_PicmipForFlags(int flags)
2785 if(flags & TEXF_PICMIP)
2787 miplevel += gl_picmip.integer;
2788 if (flags & TEXF_ISWORLD)
2790 if (r_picmipworld.integer)
2791 miplevel += gl_picmip_world.integer;
2795 else if (flags & TEXF_ISSPRITE)
2797 if (r_picmipsprites.integer)
2798 miplevel += gl_picmip_sprites.integer;
2803 miplevel += gl_picmip_other.integer;
2805 return max(0, miplevel);