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_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
87 static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
88 static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
89 static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
90 static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
91 static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
92 static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
93 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 2, 2, 2.0f, GL_RGB565 , GL_RGBA , GL_UNSIGNED_SHORT_5_6_5};
94 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 2, 2, 2.0f, GL_RGB565 , GL_RGBA , GL_UNSIGNED_SHORT_5_6_5};
95 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 2, 2, 2.0f, GL_RGB565 , GL_RGBA , GL_UNSIGNED_SHORT_5_6_5};
98 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
99 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
100 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
101 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
102 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
103 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
104 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
106 // framebuffer texture formats
107 static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
108 static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
109 static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
110 static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
111 static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
112 static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
113 static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 4, 4, 4.0f, GL_DEPTH24_STENCIL8_EXT , GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT};
114 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
115 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 8, 8, 8.0f, GL_RGBA16F_ARB , GL_RGBA , GL_FLOAT };
116 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 16, 16, 16.0f, GL_RGBA32F_ARB , GL_RGBA , GL_FLOAT };
119 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
120 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
121 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
122 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE };
123 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
124 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 };
125 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 };
126 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
127 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
128 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 };
129 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 };
130 static textypeinfo_t textype_dxt1 = {"dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
131 static textypeinfo_t textype_dxt1a = {"dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 };
132 static textypeinfo_t textype_dxt3 = {"dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 };
133 static textypeinfo_t textype_dxt5 = {"dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 };
134 static textypeinfo_t textype_sRGB_palette = {"sRGB_palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
135 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 };
136 static textypeinfo_t textype_sRGB_rgba = {"sRGB_rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
137 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 };
138 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 };
139 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 };
140 static textypeinfo_t textype_sRGB_bgra = {"sRGB_bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
141 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 };
142 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 };
143 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 };
144 static textypeinfo_t textype_sRGB_dxt1 = {"sRGB_dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , 0 , 0 };
145 static textypeinfo_t textype_sRGB_dxt1a = {"sRGB_dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 , 0 };
146 static textypeinfo_t textype_sRGB_dxt3 = {"sRGB_dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 , 0 };
147 static textypeinfo_t textype_sRGB_dxt5 = {"sRGB_dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 , 0 };
150 typedef enum gltexturetype_e
154 GLTEXTURETYPE_CUBEMAP,
159 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP};
160 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
161 static int cubemapside[6] =
163 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
164 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
165 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
166 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
167 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
168 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
171 typedef struct gltexture_s
173 // this portion of the struct is exposed to the R_GetTexture macro for
174 // speed reasons, must be identical in rtexture_t!
175 int texnum; // GL texture slot number
176 int renderbuffernum; // GL renderbuffer slot number
177 qboolean dirty; // indicates that R_RealGetTexture should be called
178 int gltexturetypeenum; // used by R_Mesh_TexBind
179 // d3d stuff the backend needs
183 qboolean d3disrendertargetsurface;
184 qboolean d3disdepthstencilsurface;
194 int d3dmaxmiplevelfilter;
195 int d3dmipmaplodbias;
199 // dynamic texture stuff [11/22/2007 Black]
200 updatecallback_t updatecallback;
201 void *updatacallback_data;
202 // --- [11/22/2007 Black]
204 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
205 unsigned char *bufferpixels;
206 qboolean buffermodified;
208 // pointer to texturepool (check this to see if the texture is allocated)
209 struct gltexturepool_s *pool;
210 // pointer to next texture in texturepool chain
211 struct gltexture_s *chain;
212 // name of the texture (this might be removed someday), no duplicates
213 char identifier[MAX_QPATH + 32];
214 // original data size in *inputtexels
215 int inputwidth, inputheight, inputdepth;
216 // copy of the original texture(s) supplied to the upload function, for
217 // delayed uploads (non-precached)
218 unsigned char *inputtexels;
219 // original data size in *inputtexels
221 // flags supplied to the LoadTexture function
222 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
226 // pointer to one of the textype_ structs
227 textypeinfo_t *textype;
228 // one of the GLTEXTURETYPE_ values
230 // palette if the texture is TEXTYPE_PALETTE
231 const unsigned int *palette;
232 // actual stored texture size after gl_picmip and gl_max_size are applied
233 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
234 int tilewidth, tileheight, tiledepth;
235 // 1 or 6 depending on texturetype
237 // how many mipmap levels in this texture
241 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
244 int glinternalformat;
245 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
250 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
252 typedef struct gltexturepool_s
254 unsigned int sentinel;
255 struct gltexture_s *gltchain;
256 struct gltexturepool_s *next;
260 static gltexturepool_t *gltexturepoolchain = NULL;
262 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
263 static int resizebuffersize = 0;
264 static const unsigned char *texturebuffer;
266 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
270 case TEXTYPE_DXT1: return &textype_dxt1;
271 case TEXTYPE_DXT1A: return &textype_dxt1a;
272 case TEXTYPE_DXT3: return &textype_dxt3;
273 case TEXTYPE_DXT5: return &textype_dxt5;
274 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
275 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);
276 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);
277 case TEXTYPE_ALPHA: return &textype_alpha;
278 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
279 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
280 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
281 case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
282 case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
283 case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
284 case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
285 case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
286 case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
287 case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
288 case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1;
289 case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a;
290 case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
291 case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
292 case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
293 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);
294 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);
296 Host_Error("R_GetTexTypeInfo: unknown texture format");
302 // dynamic texture code [11/22/2007 Black]
303 void R_MarkDirtyTexture(rtexture_t *rt) {
304 gltexture_t *glt = (gltexture_t*) rt;
309 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
310 if (glt->flags & GLTEXF_DYNAMIC)
312 // mark it as dirty, so R_RealGetTexture gets called
317 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
318 gltexture_t *glt = (gltexture_t*) rt;
323 glt->flags |= GLTEXF_DYNAMIC;
324 glt->updatecallback = updatecallback;
325 glt->updatacallback_data = data;
328 static void R_UpdateDynamicTexture(gltexture_t *glt) {
330 if( glt->updatecallback ) {
331 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
335 void R_PurgeTexture(rtexture_t *rt)
337 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
342 void R_FreeTexture(rtexture_t *rt)
344 gltexture_t *glt, **gltpointer;
346 glt = (gltexture_t *)rt;
348 Host_Error("R_FreeTexture: texture == NULL");
350 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
351 if (*gltpointer == glt)
352 *gltpointer = glt->chain;
354 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
356 R_Mesh_ClearBindingsForTexture(glt->texnum);
358 switch(vid.renderpath)
360 case RENDERPATH_GL11:
361 case RENDERPATH_GL13:
362 case RENDERPATH_GL20:
363 case RENDERPATH_GLES1:
364 case RENDERPATH_GLES2:
368 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
370 if (glt->renderbuffernum)
373 qglDeleteRenderbuffersEXT(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
376 case RENDERPATH_D3D9:
379 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dsurface);
380 else if (glt->tiledepth > 1)
381 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
382 else if (glt->sides == 6)
383 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
385 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
386 glt->d3dtexture = NULL;
387 glt->d3dsurface = NULL;
390 case RENDERPATH_D3D10:
391 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
393 case RENDERPATH_D3D11:
394 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
396 case RENDERPATH_SOFT:
398 DPSOFTRAST_Texture_Free(glt->texnum);
402 if (glt->inputtexels)
403 Mem_Free(glt->inputtexels);
404 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
407 rtexturepool_t *R_AllocTexturePool(void)
409 gltexturepool_t *pool;
410 if (texturemempool == NULL)
412 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
415 pool->next = gltexturepoolchain;
416 gltexturepoolchain = pool;
417 pool->sentinel = TEXTUREPOOL_SENTINEL;
418 return (rtexturepool_t *)pool;
421 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
423 gltexturepool_t *pool, **poolpointer;
424 if (rtexturepool == NULL)
426 if (*rtexturepool == NULL)
428 pool = (gltexturepool_t *)(*rtexturepool);
429 *rtexturepool = NULL;
430 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
431 Host_Error("R_FreeTexturePool: pool already freed");
432 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
433 if (*poolpointer == pool)
434 *poolpointer = pool->next;
436 Host_Error("R_FreeTexturePool: pool not linked");
437 while (pool->gltchain)
438 R_FreeTexture((rtexture_t *)pool->gltchain);
443 typedef struct glmode_s
446 int minification, magnification;
447 DPSOFTRAST_TEXTURE_FILTER dpsoftrastfilter_mipmap, dpsoftrastfilter_nomipmap;
451 static glmode_t modes[6] =
453 {"GL_NEAREST", GL_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
454 {"GL_LINEAR", GL_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
455 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
456 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
457 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
458 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR}
462 typedef struct d3dmode_s
469 static d3dmode_t d3dmodes[6] =
471 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
472 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
473 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
474 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
475 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
476 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
480 static void GL_TextureMode_f (void)
485 gltexturepool_t *pool;
489 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
490 for (i = 0;i < 6;i++)
492 if (gl_filter_min == modes[i].minification)
494 Con_Printf("%s\n", modes[i].name);
498 Con_Print("current filter is unknown???\n");
502 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
503 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
507 Con_Print("bad filter name\n");
511 gl_filter_min = modes[i].minification;
512 gl_filter_mag = modes[i].magnification;
513 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
515 dpsoftrast_filter_mipmap = modes[i].dpsoftrastfilter_mipmap;
516 dpsoftrast_filter_nomipmap = modes[i].dpsoftrastfilter_nomipmap;
518 switch(vid.renderpath)
520 case RENDERPATH_GL11:
521 case RENDERPATH_GL13:
522 case RENDERPATH_GL20:
523 case RENDERPATH_GLES1:
524 case RENDERPATH_GLES2:
525 // change all the existing mipmap texture objects
526 // FIXME: force renderer(/client/something?) restart instead?
529 for (pool = gltexturepoolchain;pool;pool = pool->next)
531 for (glt = pool->gltchain;glt;glt = glt->chain)
533 // only update already uploaded images
534 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
536 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
537 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
538 if (glt->flags & TEXF_MIPMAP)
540 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
544 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
546 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
547 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
552 case RENDERPATH_D3D9:
554 d3d_filter_flatmin = d3dmodes[i].m1;
555 d3d_filter_flatmag = d3dmodes[i].m1;
556 d3d_filter_flatmix = D3DTEXF_POINT;
557 d3d_filter_mipmin = d3dmodes[i].m1;
558 d3d_filter_mipmag = d3dmodes[i].m1;
559 d3d_filter_mipmix = d3dmodes[i].m2;
560 d3d_filter_nomip = i < 2;
561 if (gl_texture_anisotropy.integer > 1 && i == 5)
562 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
563 for (pool = gltexturepoolchain;pool;pool = pool->next)
565 for (glt = pool->gltchain;glt;glt = glt->chain)
567 // only update already uploaded images
568 if (glt->d3dtexture && !glt->d3dsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
570 if (glt->flags & TEXF_MIPMAP)
572 glt->d3dminfilter = d3d_filter_mipmin;
573 glt->d3dmagfilter = d3d_filter_mipmag;
574 glt->d3dmipfilter = d3d_filter_mipmix;
575 glt->d3dmaxmiplevelfilter = 0;
579 glt->d3dminfilter = d3d_filter_flatmin;
580 glt->d3dmagfilter = d3d_filter_flatmag;
581 glt->d3dmipfilter = d3d_filter_flatmix;
582 glt->d3dmaxmiplevelfilter = 0;
589 case RENDERPATH_D3D10:
590 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
592 case RENDERPATH_D3D11:
593 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
595 case RENDERPATH_SOFT:
596 // change all the existing texture objects
597 for (pool = gltexturepoolchain;pool;pool = pool->next)
598 for (glt = pool->gltchain;glt;glt = glt->chain)
599 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
600 DPSOFTRAST_Texture_Filter(glt->texnum, (glt->flags & TEXF_MIPMAP) ? dpsoftrast_filter_mipmap : dpsoftrast_filter_nomipmap);
605 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)
607 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
612 case GLTEXTURETYPE_2D:
613 maxsize = vid.maxtexturesize_2d;
614 if (flags & TEXF_PICMIP)
616 maxsize = bound(1, gl_max_size.integer, maxsize);
620 case GLTEXTURETYPE_3D:
621 maxsize = vid.maxtexturesize_3d;
623 case GLTEXTURETYPE_CUBEMAP:
624 maxsize = vid.maxtexturesize_cubemap;
628 if (vid.support.arb_texture_non_power_of_two)
630 width2 = min(inwidth >> picmip, maxsize);
631 height2 = min(inheight >> picmip, maxsize);
632 depth2 = min(indepth >> picmip, maxsize);
636 for (width2 = 1;width2 < inwidth;width2 <<= 1);
637 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
638 for (height2 = 1;height2 < inheight;height2 <<= 1);
639 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
640 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
641 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
644 switch(vid.renderpath)
646 case RENDERPATH_GL11:
647 case RENDERPATH_GL13:
648 case RENDERPATH_GL20:
649 case RENDERPATH_D3D10:
650 case RENDERPATH_D3D11:
651 case RENDERPATH_SOFT:
652 case RENDERPATH_GLES1:
653 case RENDERPATH_GLES2:
655 case RENDERPATH_D3D9:
657 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
658 if (texturetype == GLTEXTURETYPE_2D)
660 width2 = max(width2, 2);
661 height2 = max(height2, 2);
668 if (flags & TEXF_MIPMAP)
670 int extent = max(width2, max(height2, depth2));
676 *outwidth = max(1, width2);
678 *outheight = max(1, height2);
680 *outdepth = max(1, depth2);
682 *outmiplevels = miplevels;
686 static int R_CalcTexelDataSize (gltexture_t *glt)
688 int width2, height2, depth2, size;
690 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
692 size = width2 * height2 * depth2;
694 if (glt->flags & TEXF_MIPMAP)
696 while (width2 > 1 || height2 > 1 || depth2 > 1)
704 size += width2 * height2 * depth2;
708 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
711 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
715 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
716 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
718 gltexturepool_t *pool;
720 Con_Print("glsize input loaded mip alpha name\n");
721 for (pool = gltexturepoolchain;pool;pool = pool->next)
729 for (glt = pool->gltchain;glt;glt = glt->chain)
731 glsize = R_CalcTexelDataSize(glt);
732 isloaded = glt->texnum != 0 || glt->renderbuffernum != 0 || glt->d3dtexture || glt->d3dsurface;
734 pooltotalt += glsize;
735 pooltotalp += glt->inputdatasize;
739 poolloadedt += glsize;
740 poolloadedp += glt->inputdatasize;
743 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);
746 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);
747 sumtotal += pooltotal;
748 sumtotalt += pooltotalt;
749 sumtotalp += pooltotalp;
750 sumloaded += poolloaded;
751 sumloadedt += poolloadedt;
752 sumloadedp += poolloadedp;
755 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);
758 static void R_TextureStats_f(void)
760 R_TextureStats_Print(true, true, true);
763 static void r_textures_start(void)
765 switch(vid.renderpath)
767 case RENDERPATH_GL11:
768 case RENDERPATH_GL13:
769 case RENDERPATH_GL20:
770 case RENDERPATH_GLES1:
771 case RENDERPATH_GLES2:
772 // LordHavoc: allow any alignment
774 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
775 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
777 case RENDERPATH_D3D9:
779 case RENDERPATH_D3D10:
780 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
782 case RENDERPATH_D3D11:
783 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
785 case RENDERPATH_SOFT:
789 texturemempool = Mem_AllocPool("texture management", 0, NULL);
790 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
792 // Disable JPEG screenshots if the DLL isn't loaded
793 if (! JPEG_OpenLibrary ())
794 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
795 if (! PNG_OpenLibrary ())
796 Cvar_SetValueQuick (&scr_screenshot_png, 0);
799 static void r_textures_shutdown(void)
801 rtexturepool_t *temp;
803 JPEG_CloseLibrary ();
805 while(gltexturepoolchain)
807 temp = (rtexturepool_t *) gltexturepoolchain;
808 R_FreeTexturePool(&temp);
811 resizebuffersize = 0;
813 colorconvertbuffer = NULL;
814 texturebuffer = NULL;
815 Mem_ExpandableArray_FreeArray(&texturearray);
816 Mem_FreePool(&texturemempool);
819 static void r_textures_newmap(void)
823 static void r_textures_devicelost(void)
827 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
828 for (i = 0;i < endindex;i++)
830 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
831 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
833 switch(vid.renderpath)
835 case RENDERPATH_GL11:
836 case RENDERPATH_GL13:
837 case RENDERPATH_GL20:
838 case RENDERPATH_GLES1:
839 case RENDERPATH_GLES2:
841 case RENDERPATH_D3D9:
844 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dsurface);
845 else if (glt->tiledepth > 1)
846 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
847 else if (glt->sides == 6)
848 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
850 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
851 glt->d3dtexture = NULL;
852 glt->d3dsurface = NULL;
855 case RENDERPATH_D3D10:
856 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
858 case RENDERPATH_D3D11:
859 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
861 case RENDERPATH_SOFT:
867 static void r_textures_devicerestored(void)
871 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
872 for (i = 0;i < endindex;i++)
874 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
875 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
877 switch(vid.renderpath)
879 case RENDERPATH_GL11:
880 case RENDERPATH_GL13:
881 case RENDERPATH_GL20:
882 case RENDERPATH_GLES1:
883 case RENDERPATH_GLES2:
885 case RENDERPATH_D3D9:
889 if (glt->d3disrendertargetsurface)
891 if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
892 Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!");
894 else if (glt->d3disdepthstencilsurface)
896 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
897 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
899 else if (glt->tiledepth > 1)
901 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)))
902 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
904 else if (glt->sides == 6)
906 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
907 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
911 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)))
912 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
917 case RENDERPATH_D3D10:
918 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
920 case RENDERPATH_D3D11:
921 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
923 case RENDERPATH_SOFT:
930 void R_Textures_Init (void)
932 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");
933 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
934 Cvar_RegisterVariable (&gl_max_size);
935 Cvar_RegisterVariable (&gl_picmip);
936 Cvar_RegisterVariable (&gl_picmip_world);
937 Cvar_RegisterVariable (&r_picmipworld);
938 Cvar_RegisterVariable (&gl_picmip_sprites);
939 Cvar_RegisterVariable (&r_picmipsprites);
940 Cvar_RegisterVariable (&gl_picmip_other);
941 Cvar_RegisterVariable (&gl_max_lightmapsize);
942 Cvar_RegisterVariable (&r_lerpimages);
943 Cvar_RegisterVariable (&gl_texture_anisotropy);
944 Cvar_RegisterVariable (&gl_texturecompression);
945 Cvar_RegisterVariable (&gl_texturecompression_color);
946 Cvar_RegisterVariable (&gl_texturecompression_normal);
947 Cvar_RegisterVariable (&gl_texturecompression_gloss);
948 Cvar_RegisterVariable (&gl_texturecompression_glow);
949 Cvar_RegisterVariable (&gl_texturecompression_2d);
950 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
951 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
952 Cvar_RegisterVariable (&gl_texturecompression_sky);
953 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
954 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
955 Cvar_RegisterVariable (&gl_texturecompression_sprites);
956 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
957 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
958 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
959 Cvar_RegisterVariable (&r_texture_dds_swdecode);
961 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
964 void R_Textures_Frame (void)
966 static int old_aniso = 0;
968 // could do procedural texture animation here, if we keep track of which
969 // textures were accessed this frame...
971 // free the resize buffers
972 resizebuffersize = 0;
975 Mem_Free(resizebuffer);
978 if (colorconvertbuffer)
980 Mem_Free(colorconvertbuffer);
981 colorconvertbuffer = NULL;
984 if (old_aniso != gl_texture_anisotropy.integer)
987 gltexturepool_t *pool;
990 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
992 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
994 switch(vid.renderpath)
996 case RENDERPATH_GL11:
997 case RENDERPATH_GL13:
998 case RENDERPATH_GL20:
999 case RENDERPATH_GLES1:
1000 case RENDERPATH_GLES2:
1002 GL_ActiveTexture(0);
1003 for (pool = gltexturepoolchain;pool;pool = pool->next)
1005 for (glt = pool->gltchain;glt;glt = glt->chain)
1007 // only update already uploaded images
1008 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
1010 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1012 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1013 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
1015 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1020 case RENDERPATH_D3D9:
1021 case RENDERPATH_D3D10:
1022 case RENDERPATH_D3D11:
1023 case RENDERPATH_SOFT:
1029 static void R_MakeResizeBufferBigger(int size)
1031 if (resizebuffersize < size)
1033 resizebuffersize = size;
1035 Mem_Free(resizebuffer);
1036 if (colorconvertbuffer)
1037 Mem_Free(colorconvertbuffer);
1038 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
1039 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
1040 if (!resizebuffer || !colorconvertbuffer)
1041 Host_Error("R_Upload: out of memory");
1045 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
1047 int textureenum = gltexturetypeenums[texturetype];
1048 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
1052 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
1054 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
1055 if (gl_texture_anisotropy.integer != aniso)
1056 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
1057 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
1059 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
1060 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
1061 #ifdef GL_TEXTURE_WRAP_R
1062 if (gltexturetypedimensions[texturetype] >= 3)
1064 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
1069 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
1071 if (flags & TEXF_MIPMAP)
1073 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
1077 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
1079 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
1081 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
1083 if (flags & TEXF_MIPMAP)
1085 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
1087 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
1091 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
1096 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
1098 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
1102 if (flags & TEXF_MIPMAP)
1104 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1108 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1110 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1115 case TEXTYPE_SHADOWMAP16_COMP:
1116 case TEXTYPE_SHADOWMAP24_COMP:
1117 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1118 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1119 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1121 case TEXTYPE_SHADOWMAP16_RAW:
1122 case TEXTYPE_SHADOWMAP24_RAW:
1123 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1124 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1125 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1134 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1137 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1139 if (glt->texturetype != GLTEXTURETYPE_2D)
1140 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1142 if (glt->textype->textype == TEXTYPE_PALETTE)
1143 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1145 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1146 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1148 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1149 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1151 // update a portion of the image
1153 switch(vid.renderpath)
1155 case RENDERPATH_GL11:
1156 case RENDERPATH_GL13:
1157 case RENDERPATH_GL20:
1158 case RENDERPATH_GLES1:
1159 case RENDERPATH_GLES2:
1163 // we need to restore the texture binding after finishing the upload
1164 GL_ActiveTexture(0);
1165 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1166 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1167 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1168 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1171 case RENDERPATH_D3D9:
1175 D3DLOCKED_RECT d3dlockedrect;
1177 memset(&d3drect, 0, sizeof(d3drect));
1178 d3drect.left = fragx;
1179 d3drect.top = fragy;
1180 d3drect.right = fragx+fragwidth;
1181 d3drect.bottom = fragy+fragheight;
1182 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1184 for (y = 0;y < fragheight;y++)
1185 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1186 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1191 case RENDERPATH_D3D10:
1192 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1194 case RENDERPATH_D3D11:
1195 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1197 case RENDERPATH_SOFT:
1198 DPSOFTRAST_Texture_UpdatePartial(glt->texnum, 0, data, fragx, fragy, fragwidth, fragheight);
1203 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1205 int i, mip = 0, width, height, depth;
1206 GLint oldbindtexnum = 0;
1207 const unsigned char *prevbuffer;
1210 // error out if a stretch is needed on special texture types
1211 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1212 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1214 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1215 // of the target size and then use the mipmap reduction function to get
1216 // high quality supersampled results
1217 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1218 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1219 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1220 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1222 if (prevbuffer == NULL)
1224 width = glt->tilewidth;
1225 height = glt->tileheight;
1226 depth = glt->tiledepth;
1227 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1228 // prevbuffer = resizebuffer;
1232 if (glt->textype->textype == TEXTYPE_PALETTE)
1234 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1235 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1236 prevbuffer = colorconvertbuffer;
1238 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1240 // multiply RGB channels by A channel before uploading
1242 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1244 alpha = prevbuffer[i+3];
1245 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1246 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1247 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1248 colorconvertbuffer[i+3] = alpha;
1250 prevbuffer = colorconvertbuffer;
1252 // scale up to a power of 2 size (if appropriate)
1253 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1255 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1256 prevbuffer = resizebuffer;
1258 // apply mipmap reduction algorithm to get down to picmip/max_size
1259 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1261 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1262 prevbuffer = resizebuffer;
1266 // do the appropriate upload type...
1267 switch(vid.renderpath)
1269 case RENDERPATH_GL11:
1270 case RENDERPATH_GL13:
1271 case RENDERPATH_GL20:
1272 case RENDERPATH_GLES1:
1273 case RENDERPATH_GLES2:
1274 if (glt->texnum) // not renderbuffers
1278 // we need to restore the texture binding after finishing the upload
1279 GL_ActiveTexture(0);
1280 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1281 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1283 #ifdef GL_TEXTURE_COMPRESSION_HINT_ARB
1284 if (qglGetCompressedTexImageARB)
1286 if (gl_texturecompression.integer >= 2)
1287 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1289 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1293 switch(glt->texturetype)
1295 case GLTEXTURETYPE_2D:
1296 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1297 if (glt->flags & TEXF_MIPMAP)
1299 while (width > 1 || height > 1 || depth > 1)
1301 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1302 prevbuffer = resizebuffer;
1303 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1307 case GLTEXTURETYPE_3D:
1309 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1310 if (glt->flags & TEXF_MIPMAP)
1312 while (width > 1 || height > 1 || depth > 1)
1314 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1315 prevbuffer = resizebuffer;
1316 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1321 case GLTEXTURETYPE_CUBEMAP:
1322 // convert and upload each side in turn,
1323 // from a continuous block of input texels
1324 texturebuffer = (unsigned char *)prevbuffer;
1325 for (i = 0;i < 6;i++)
1327 prevbuffer = texturebuffer;
1328 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1329 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1331 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1332 prevbuffer = resizebuffer;
1335 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1337 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1338 prevbuffer = resizebuffer;
1341 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1342 if (glt->flags & TEXF_MIPMAP)
1344 while (width > 1 || height > 1 || depth > 1)
1346 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1347 prevbuffer = resizebuffer;
1348 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1354 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1355 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1358 case RENDERPATH_D3D9:
1360 if (!(glt->flags & TEXF_RENDERTARGET) && glt->d3dtexture && !glt->d3dsurface)
1362 D3DLOCKED_RECT d3dlockedrect;
1363 D3DLOCKED_BOX d3dlockedbox;
1364 switch(glt->texturetype)
1366 case GLTEXTURETYPE_2D:
1367 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1370 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1372 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1373 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1376 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1378 while (width > 1 || height > 1 || depth > 1)
1380 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1381 prevbuffer = resizebuffer;
1382 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1384 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1385 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1391 case GLTEXTURETYPE_3D:
1392 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1394 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1395 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1396 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1399 if (glt->flags & TEXF_MIPMAP)
1401 while (width > 1 || height > 1 || depth > 1)
1403 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1404 prevbuffer = resizebuffer;
1405 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1407 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1408 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1409 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1415 case GLTEXTURETYPE_CUBEMAP:
1416 // convert and upload each side in turn,
1417 // from a continuous block of input texels
1418 texturebuffer = (unsigned char *)prevbuffer;
1419 for (i = 0;i < 6;i++)
1421 prevbuffer = texturebuffer;
1422 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1423 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1425 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1426 prevbuffer = resizebuffer;
1429 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1431 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1432 prevbuffer = resizebuffer;
1435 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1437 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1438 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1441 if (glt->flags & TEXF_MIPMAP)
1443 while (width > 1 || height > 1 || depth > 1)
1445 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1446 prevbuffer = resizebuffer;
1447 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1449 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1450 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1459 glt->d3daddressw = 0;
1460 if (glt->flags & TEXF_CLAMP)
1462 glt->d3daddressu = D3DTADDRESS_CLAMP;
1463 glt->d3daddressv = D3DTADDRESS_CLAMP;
1464 if (glt->tiledepth > 1)
1465 glt->d3daddressw = D3DTADDRESS_CLAMP;
1469 glt->d3daddressu = D3DTADDRESS_WRAP;
1470 glt->d3daddressv = D3DTADDRESS_WRAP;
1471 if (glt->tiledepth > 1)
1472 glt->d3daddressw = D3DTADDRESS_WRAP;
1474 glt->d3dmipmaplodbias = 0;
1475 glt->d3dmaxmiplevel = 0;
1476 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1477 if (glt->flags & TEXF_FORCELINEAR)
1479 glt->d3dminfilter = D3DTEXF_LINEAR;
1480 glt->d3dmagfilter = D3DTEXF_LINEAR;
1481 glt->d3dmipfilter = D3DTEXF_POINT;
1483 else if (glt->flags & TEXF_FORCENEAREST)
1485 glt->d3dminfilter = D3DTEXF_POINT;
1486 glt->d3dmagfilter = D3DTEXF_POINT;
1487 glt->d3dmipfilter = D3DTEXF_POINT;
1489 else if (glt->flags & TEXF_MIPMAP)
1491 glt->d3dminfilter = d3d_filter_mipmin;
1492 glt->d3dmagfilter = d3d_filter_mipmag;
1493 glt->d3dmipfilter = d3d_filter_mipmix;
1497 glt->d3dminfilter = d3d_filter_flatmin;
1498 glt->d3dmagfilter = d3d_filter_flatmag;
1499 glt->d3dmipfilter = d3d_filter_flatmix;
1503 case RENDERPATH_D3D10:
1504 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1506 case RENDERPATH_D3D11:
1507 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1509 case RENDERPATH_SOFT:
1510 switch(glt->texturetype)
1512 case GLTEXTURETYPE_2D:
1513 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1515 case GLTEXTURETYPE_3D:
1516 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1518 case GLTEXTURETYPE_CUBEMAP:
1519 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1521 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1522 // convert and upload each side in turn,
1523 // from a continuous block of input texels
1524 // copy the results into combinedbuffer
1525 texturebuffer = (unsigned char *)prevbuffer;
1526 for (i = 0;i < 6;i++)
1528 prevbuffer = texturebuffer;
1529 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1530 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1532 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1533 prevbuffer = resizebuffer;
1536 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1538 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1539 prevbuffer = resizebuffer;
1541 memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1543 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1544 Mem_Free(combinedbuffer);
1547 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1550 if (glt->flags & TEXF_FORCELINEAR)
1551 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1552 else if (glt->flags & TEXF_FORCENEAREST)
1553 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1554 else if (glt->flags & TEXF_MIPMAP)
1555 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1557 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1562 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)
1566 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1567 textypeinfo_t *texinfo, *texinfo2;
1568 unsigned char *temppixels = NULL;
1571 if (cls.state == ca_dedicated)
1574 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1575 if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1577 int numpixels = width * height * depth * sides;
1578 size = numpixels * 4;
1579 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1582 const unsigned char *p;
1583 unsigned char *o = temppixels;
1584 for (i = 0;i < numpixels;i++, o += 4)
1586 p = (const unsigned char *)palette + 4*data[i];
1594 textype = TEXTYPE_RGBA;
1599 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1600 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1601 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1602 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1608 static int rgbaswapindices[4] = {2, 1, 0, 3};
1609 size = width * height * depth * sides * 4;
1610 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1612 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1616 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1617 if (!vid.support.ext_texture_srgb)
1619 qboolean convertsRGB = false;
1622 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1623 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1624 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1625 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1626 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;convertsRGB = true;break;
1627 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1628 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1632 if (convertsRGB && data)
1634 size = width * height * depth * sides * 4;
1637 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1638 memcpy(temppixels, data, size);
1641 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1645 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1647 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1650 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1652 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1656 texinfo = R_GetTexTypeInfo(textype, flags);
1657 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1660 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1664 // clear the alpha flag if the texture has no transparent pixels
1667 case TEXTYPE_PALETTE:
1668 case TEXTYPE_SRGB_PALETTE:
1669 if (flags & TEXF_ALPHA)
1671 flags &= ~TEXF_ALPHA;
1674 for (i = 0;i < size;i++)
1676 if (((unsigned char *)&palette[data[i]])[3] < 255)
1678 flags |= TEXF_ALPHA;
1687 case TEXTYPE_SRGB_RGBA:
1688 case TEXTYPE_SRGB_BGRA:
1689 if (flags & TEXF_ALPHA)
1691 flags &= ~TEXF_ALPHA;
1694 for (i = 3;i < size;i += 4)
1698 flags |= TEXF_ALPHA;
1705 case TEXTYPE_SHADOWMAP16_COMP:
1706 case TEXTYPE_SHADOWMAP16_RAW:
1707 case TEXTYPE_SHADOWMAP24_COMP:
1708 case TEXTYPE_SHADOWMAP24_RAW:
1711 case TEXTYPE_SRGB_DXT1:
1714 case TEXTYPE_SRGB_DXT1A:
1716 case TEXTYPE_SRGB_DXT3:
1718 case TEXTYPE_SRGB_DXT5:
1719 flags |= TEXF_ALPHA;
1722 flags |= TEXF_ALPHA;
1724 case TEXTYPE_COLORBUFFER:
1725 case TEXTYPE_COLORBUFFER16F:
1726 case TEXTYPE_COLORBUFFER32F:
1727 flags |= TEXF_ALPHA;
1730 Sys_Error("R_LoadTexture: unknown texture type");
1733 texinfo2 = R_GetTexTypeInfo(textype, flags);
1734 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1737 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1739 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1741 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1743 glt->chain = pool->gltchain;
1744 pool->gltchain = glt;
1745 glt->inputwidth = width;
1746 glt->inputheight = height;
1747 glt->inputdepth = depth;
1749 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
1750 glt->textype = texinfo;
1751 glt->texturetype = texturetype;
1752 glt->inputdatasize = size;
1753 glt->palette = palette;
1754 glt->glinternalformat = texinfo->glinternalformat;
1755 glt->glformat = texinfo->glformat;
1756 glt->gltype = texinfo->gltype;
1757 glt->bytesperpixel = texinfo->internalbytesperpixel;
1758 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1761 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1762 // init the dynamic texture attributes, too [11/22/2007 Black]
1763 glt->updatecallback = NULL;
1764 glt->updatacallback_data = NULL;
1766 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1768 // upload the texture
1769 // data may be NULL (blank texture for dynamic rendering)
1770 switch(vid.renderpath)
1772 case RENDERPATH_GL11:
1773 case RENDERPATH_GL13:
1774 case RENDERPATH_GL20:
1775 case RENDERPATH_GLES1:
1776 case RENDERPATH_GLES2:
1778 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1780 case RENDERPATH_D3D9:
1783 D3DFORMAT d3dformat;
1788 d3dpool = D3DPOOL_MANAGED;
1789 if (flags & TEXF_RENDERTARGET)
1791 d3dusage |= D3DUSAGE_RENDERTARGET;
1792 d3dpool = D3DPOOL_DEFAULT;
1796 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1797 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1798 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1799 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
1800 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
1801 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
1802 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1803 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1805 glt->d3dformat = d3dformat;
1806 glt->d3dusage = d3dusage;
1807 glt->d3dpool = d3dpool;
1808 glt->d3disrendertargetsurface = false;
1809 glt->d3disdepthstencilsurface = false;
1810 if (glt->tiledepth > 1)
1812 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)))
1813 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1815 else if (glt->sides == 6)
1817 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1818 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1822 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)))
1823 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1828 case RENDERPATH_D3D10:
1829 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1831 case RENDERPATH_D3D11:
1832 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1834 case RENDERPATH_SOFT:
1839 case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1840 case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1841 case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1842 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1843 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
1844 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
1845 case TEXTYPE_SHADOWMAP16_COMP:
1846 case TEXTYPE_SHADOWMAP16_RAW:
1847 case TEXTYPE_SHADOWMAP24_COMP:
1848 case TEXTYPE_SHADOWMAP24_RAW: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1849 case TEXTYPE_DEPTHBUFFER16:
1850 case TEXTYPE_DEPTHBUFFER24:
1851 case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1852 case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1853 default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1855 if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1856 if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1857 if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1858 if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1859 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1864 R_UploadFullTexture(glt, data);
1865 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1866 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1868 // free any temporary processing buffer we allocated...
1870 Mem_Free(temppixels);
1872 // texture converting and uploading can take a while, so make sure we're sending keepalives
1873 // FIXME: this causes rendering during R_Shadow_DrawLights
1874 // CL_KeepaliveMessage(false);
1876 return (rtexture_t *)glt;
1879 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)
1881 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1884 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)
1886 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1889 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)
1891 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1894 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter)
1896 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL);
1899 rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
1902 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1903 textypeinfo_t *texinfo;
1905 if (cls.state == ca_dedicated)
1908 texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP);
1910 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1912 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1914 glt->chain = pool->gltchain;
1915 pool->gltchain = glt;
1916 glt->inputwidth = width;
1917 glt->inputheight = height;
1918 glt->inputdepth = 1;
1919 glt->flags = TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_FORCENEAREST;
1921 glt->textype = texinfo;
1922 glt->texturetype = textype;
1923 glt->inputdatasize = width*height*texinfo->internalbytesperpixel;
1924 glt->palette = NULL;
1925 glt->glinternalformat = texinfo->glinternalformat;
1926 glt->glformat = texinfo->glformat;
1927 glt->gltype = texinfo->gltype;
1928 glt->bytesperpixel = texinfo->internalbytesperpixel;
1929 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1932 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1933 // init the dynamic texture attributes, too [11/22/2007 Black]
1934 glt->updatecallback = NULL;
1935 glt->updatacallback_data = NULL;
1937 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1939 // upload the texture
1940 // data may be NULL (blank texture for dynamic rendering)
1941 switch(vid.renderpath)
1943 case RENDERPATH_GL11:
1944 case RENDERPATH_GL13:
1945 case RENDERPATH_GL20:
1946 case RENDERPATH_GLES1:
1947 case RENDERPATH_GLES2:
1949 qglGenRenderbuffersEXT(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
1950 qglBindRenderbufferEXT(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR
1951 qglRenderbufferStorageEXT(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR
1952 // note we can query the renderbuffer for info with glGetRenderbufferParameteriv for GL_WIDTH, GL_HEIGHt, GL_RED_SIZE, GL_GREEN_SIZE, GL_BLUE_SIZE, GL_GL_ALPHA_SIZE, GL_DEPTH_SIZE, GL_STENCIL_SIZE, GL_INTERNAL_FORMAT
1953 qglBindRenderbufferEXT(GL_RENDERBUFFER, 0);CHECKGLERROR
1955 case RENDERPATH_D3D9:
1958 D3DFORMAT d3dformat;
1960 glt->d3disrendertargetsurface = false;
1961 glt->d3disdepthstencilsurface = false;
1964 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;glt->d3disrendertargetsurface = true;break;
1965 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;glt->d3disrendertargetsurface = true;break;
1966 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;glt->d3disrendertargetsurface = true;break;
1967 case TEXTYPE_DEPTHBUFFER16: d3dformat = D3DFMT_D16;glt->d3disdepthstencilsurface = true;break;
1968 case TEXTYPE_DEPTHBUFFER24: d3dformat = D3DFMT_D24X8;glt->d3disdepthstencilsurface = true;break;
1969 case TEXTYPE_DEPTHBUFFER24STENCIL8: d3dformat = D3DFMT_D24S8;glt->d3disdepthstencilsurface = true;break;
1970 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1972 glt->d3dformat = d3dformat;
1975 if (glt->d3disrendertargetsurface)
1977 if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
1978 Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!");
1980 else if (glt->d3disdepthstencilsurface)
1982 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
1983 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1988 case RENDERPATH_D3D10:
1989 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1991 case RENDERPATH_D3D11:
1992 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1994 case RENDERPATH_SOFT:
1999 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8 | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2000 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2001 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2002 case TEXTYPE_DEPTHBUFFER16:
2003 case TEXTYPE_DEPTHBUFFER24:
2004 case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2005 default: Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
2007 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
2012 return (rtexture_t *)glt;
2015 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
2018 return -1; // unsupported on this platform
2020 gltexture_t *glt = (gltexture_t *)rt;
2023 int bytesperpixel = 0;
2024 int bytesperblock = 0;
2026 int dds_format_flags;
2034 GLint internalformat;
2035 const char *ddsfourcc;
2037 return -1; // NULL pointer
2038 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
2039 return -2; // broken driver - crashes on reading internal format
2040 if (!qglGetTexLevelParameteriv)
2042 GL_ActiveTexture(0);
2043 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2044 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2045 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
2046 switch(internalformat)
2048 default: ddsfourcc = NULL;bytesperpixel = 4;break;
2049 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
2050 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
2051 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
2052 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
2054 // if premultiplied alpha, say so in the DDS file
2055 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
2057 switch(internalformat)
2059 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
2060 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
2063 if (!bytesperblock && skipuncompressed)
2064 return -3; // skipped
2065 memset(mipinfo, 0, sizeof(mipinfo));
2066 mipinfo[0][0] = glt->tilewidth;
2067 mipinfo[0][1] = glt->tileheight;
2069 if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tilewidth == 1))
2071 for (mip = 1;mip < 16;mip++)
2073 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
2074 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
2075 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
2083 for (mip = 0;mip < mipmaps;mip++)
2085 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
2086 mipinfo[mip][3] = ddssize;
2087 ddssize += mipinfo[mip][2];
2089 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
2092 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
2096 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
2097 dds_format_flags = 0x4; // DDPF_FOURCC
2101 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
2102 dds_format_flags = 0x40; // DDPF_RGB
2106 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
2107 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
2110 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
2111 memcpy(dds, "DDS ", 4);
2112 StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
2113 StoreLittleLong(dds+8, dds_flags);
2114 StoreLittleLong(dds+12, mipinfo[0][1]); // height
2115 StoreLittleLong(dds+16, mipinfo[0][0]); // width
2116 StoreLittleLong(dds+24, 0); // depth
2117 StoreLittleLong(dds+28, mipmaps); // mipmaps
2118 StoreLittleLong(dds+76, 32); // format size
2119 StoreLittleLong(dds+80, dds_format_flags);
2120 StoreLittleLong(dds+108, dds_caps1);
2121 StoreLittleLong(dds+112, dds_caps2);
2124 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
2125 memcpy(dds+84, ddsfourcc, 4);
2126 for (mip = 0;mip < mipmaps;mip++)
2128 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
2133 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
2134 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
2135 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
2136 for (mip = 0;mip < mipmaps;mip++)
2138 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
2141 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2142 ret = FS_WriteFile(filename, dds, ddssize);
2144 return ret ? ddssize : -5;
2148 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
2150 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
2153 int bytesperblock, bytesperpixel;
2156 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
2157 textypeinfo_t *texinfo;
2158 int mip, mipwidth, mipheight, mipsize, mipsize_total;
2159 unsigned int c, r, g, b;
2160 GLint oldbindtexnum = 0;
2161 unsigned char *mippixels;
2162 unsigned char *mippixels_start;
2163 unsigned char *ddspixels;
2165 fs_offset_t ddsfilesize;
2166 unsigned int ddssize;
2167 qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
2169 if (cls.state == ca_dedicated)
2172 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
2173 ddssize = ddsfilesize;
2177 if(r_texture_dds_load_logfailure.integer)
2178 Log_Printf("ddstexturefailures.log", "%s\n", filename);
2179 return NULL; // not found
2182 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
2185 Con_Printf("^1%s: not a DDS image\n", filename);
2189 //dds_flags = BuffLittleLong(dds+8);
2190 dds_format_flags = BuffLittleLong(dds+80);
2191 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
2192 dds_width = BuffLittleLong(dds+16);
2193 dds_height = BuffLittleLong(dds+12);
2194 ddspixels = dds + 128;
2196 if(r_texture_dds_load_alphamode.integer == 0)
2197 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
2198 flags &= ~TEXF_ALPHA;
2200 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
2201 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
2203 // very sloppy BGRA 32bit identification
2204 textype = TEXTYPE_BGRA;
2205 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2208 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
2209 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2212 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
2215 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
2218 for (i = 3;i < size;i += 4)
2219 if (ddspixels[i] < 255)
2222 flags &= ~TEXF_ALPHA;
2225 else if (!memcmp(dds+84, "DXT1", 4))
2227 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
2228 // LordHavoc: it is my belief that this does not infringe on the
2229 // patent because it is not decoding pixels...
2230 textype = TEXTYPE_DXT1;
2233 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
2234 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2235 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2238 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
2241 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
2243 if(r_texture_dds_load_alphamode.integer == 1)
2246 for (i = 0;i < size;i += bytesperblock)
2247 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
2249 // NOTE: this assumes sizeof(unsigned int) == 4
2250 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
2251 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
2252 if(data & (data<<1) & 0xAAAAAAAA)//rgh
2256 textype = TEXTYPE_DXT1A;
2258 flags &= ~TEXF_ALPHA;
2262 flags &= ~TEXF_ALPHA;
2266 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2268 if(!memcmp(dds+84, "DXT2", 4))
2270 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2272 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2277 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2279 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2282 textype = TEXTYPE_DXT3;
2285 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2286 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2289 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2292 // we currently always assume alpha
2294 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2296 if(!memcmp(dds+84, "DXT4", 4))
2298 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2300 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2305 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2307 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2310 textype = TEXTYPE_DXT5;
2313 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2314 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2317 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2320 // we currently always assume alpha
2325 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2329 // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
2330 if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
2332 textype = TEXTYPE_DXT1;
2336 for (i = 0;i < (int)ddssize;i += bytesperblock)
2337 memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
2341 force_swdecode = false;
2344 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
2346 if(r_texture_dds_swdecode.integer > 1)
2347 force_swdecode = true;
2351 if(r_texture_dds_swdecode.integer < 1)
2357 force_swdecode = true;
2361 // return whether this texture is transparent
2363 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2365 // if we SW decode, choose 2 sizes bigger
2368 // this is quarter res, so do not scale down more than we have to
2372 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2375 // this is where we apply gl_picmip
2376 mippixels_start = ddspixels;
2377 mipwidth = dds_width;
2378 mipheight = dds_height;
2379 while(miplevel >= 1 && dds_miplevels >= 1)
2381 if (mipwidth <= 1 && mipheight <= 1)
2383 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2384 mippixels_start += mipsize; // just skip
2392 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2393 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2395 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2397 // fake decode S3TC if needed
2400 int mipsize_new = mipsize_total / bytesperblock * 4;
2401 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2402 unsigned char *p = mipnewpixels;
2403 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2405 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2406 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2407 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2408 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2409 if(textype == TEXTYPE_DXT5)
2410 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2411 else if(textype == TEXTYPE_DXT3)
2413 (mippixels_start[i-8] & 0x0F)
2414 + (mippixels_start[i-8] >> 4)
2415 + (mippixels_start[i-7] & 0x0F)
2416 + (mippixels_start[i-7] >> 4)
2417 + (mippixels_start[i-6] & 0x0F)
2418 + (mippixels_start[i-6] >> 4)
2419 + (mippixels_start[i-5] & 0x0F)
2420 + (mippixels_start[i-5] >> 4)
2421 ) * (0.125f / 15.0f * 255.0f);
2426 textype = TEXTYPE_BGRA;
2430 // as each block becomes a pixel, we must use pixel count for this
2431 mipwidth = (mipwidth + 3) / 4;
2432 mipheight = (mipheight + 3) / 4;
2433 mipsize = bytesperpixel * mipwidth * mipheight;
2434 mippixels_start = mipnewpixels;
2435 mipsize_total = mipsize_new;
2438 // start mip counting
2439 mippixels = mippixels_start;
2441 // calculate average color if requested
2445 Vector4Clear(avgcolor);
2448 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2450 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2451 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2452 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2453 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2454 if(textype == TEXTYPE_DXT5)
2455 avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2456 else if(textype == TEXTYPE_DXT3)
2458 (mippixels_start[i-8] & 0x0F)
2459 + (mippixels_start[i-8] >> 4)
2460 + (mippixels_start[i-7] & 0x0F)
2461 + (mippixels_start[i-7] >> 4)
2462 + (mippixels_start[i-6] & 0x0F)
2463 + (mippixels_start[i-6] >> 4)
2464 + (mippixels_start[i-5] & 0x0F)
2465 + (mippixels_start[i-5] >> 4)
2466 ) * (0.125f / 15.0f * 255.0f);
2470 f = (float)bytesperblock / size;
2471 avgcolor[0] *= (0.5f / 31.0f) * f;
2472 avgcolor[1] *= (0.5f / 63.0f) * f;
2473 avgcolor[2] *= (0.5f / 31.0f) * f;
2478 for (i = 0;i < mipsize;i += 4)
2480 avgcolor[0] += mippixels[i+2];
2481 avgcolor[1] += mippixels[i+1];
2482 avgcolor[2] += mippixels[i];
2483 avgcolor[3] += mippixels[i+3];
2485 f = (1.0f / 255.0f) * bytesperpixel / size;
2493 // if we want sRGB, convert now
2496 if (vid.support.ext_texture_srgb)
2500 case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break;
2501 case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break;
2502 case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break;
2503 case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break;
2504 case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break;
2518 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2520 int c0, c1, c0new, c1new;
2521 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2522 r = ((c0 >> 11) & 0x1F);
2523 g = ((c0 >> 5) & 0x3F);
2525 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2526 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2527 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2528 c0new = (r << 11) | (g << 5) | b;
2529 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2530 r = ((c1 >> 11) & 0x1F);
2531 g = ((c1 >> 5) & 0x3F);
2533 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2534 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2535 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2536 c1new = (r << 11) | (g << 5) | b;
2537 // swap the colors if needed to fix order
2538 if(c0 > c1) // thirds
2546 mippixels_start[i+4] ^= 0x55;
2547 mippixels_start[i+5] ^= 0x55;
2548 mippixels_start[i+6] ^= 0x55;
2549 mippixels_start[i+7] ^= 0x55;
2551 else if(c0new == c1new)
2553 mippixels_start[i+4] = 0x00;
2554 mippixels_start[i+5] = 0x00;
2555 mippixels_start[i+6] = 0x00;
2556 mippixels_start[i+7] = 0x00;
2559 else // half + transparent
2566 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2567 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2568 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2569 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2572 mippixels_start[i] = c0new & 255;
2573 mippixels_start[i+1] = c0new >> 8;
2574 mippixels_start[i+2] = c1new & 255;
2575 mippixels_start[i+3] = c1new >> 8;
2580 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2588 // when not requesting mipmaps, do not load them
2589 if(!(flags & TEXF_MIPMAP))
2592 if (dds_miplevels >= 1)
2593 flags |= TEXF_MIPMAP;
2595 flags &= ~TEXF_MIPMAP;
2597 texinfo = R_GetTexTypeInfo(textype, flags);
2599 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2600 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2602 glt->chain = pool->gltchain;
2603 pool->gltchain = glt;
2604 glt->inputwidth = mipwidth;
2605 glt->inputheight = mipheight;
2606 glt->inputdepth = 1;
2608 glt->textype = texinfo;
2609 glt->texturetype = GLTEXTURETYPE_2D;
2610 glt->inputdatasize = ddssize;
2611 glt->glinternalformat = texinfo->glinternalformat;
2612 glt->glformat = texinfo->glformat;
2613 glt->gltype = texinfo->gltype;
2614 glt->bytesperpixel = texinfo->internalbytesperpixel;
2616 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2617 glt->tilewidth = mipwidth;
2618 glt->tileheight = mipheight;
2620 glt->miplevels = dds_miplevels;
2622 // texture uploading can take a while, so make sure we're sending keepalives
2623 CL_KeepaliveMessage(false);
2625 // create the texture object
2626 switch(vid.renderpath)
2628 case RENDERPATH_GL11:
2629 case RENDERPATH_GL13:
2630 case RENDERPATH_GL20:
2631 case RENDERPATH_GLES1:
2632 case RENDERPATH_GLES2:
2634 GL_ActiveTexture(0);
2635 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2636 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2637 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2639 case RENDERPATH_D3D9:
2642 D3DFORMAT d3dformat;
2647 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2648 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2649 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2650 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2651 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2654 d3dpool = D3DPOOL_MANAGED;
2655 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2659 case RENDERPATH_D3D10:
2660 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2662 case RENDERPATH_D3D11:
2663 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2665 case RENDERPATH_SOFT:
2666 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);
2670 // upload the texture
2671 // we need to restore the texture binding after finishing the upload
2672 mipcomplete = false;
2674 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2676 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2677 if (mippixels + mipsize > mippixels_start + mipsize_total)
2679 switch(vid.renderpath)
2681 case RENDERPATH_GL11:
2682 case RENDERPATH_GL13:
2683 case RENDERPATH_GL20:
2684 case RENDERPATH_GLES1:
2685 case RENDERPATH_GLES2:
2688 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2692 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2695 case RENDERPATH_D3D9:
2698 D3DLOCKED_RECT d3dlockedrect;
2699 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2701 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2702 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2708 case RENDERPATH_D3D10:
2709 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2711 case RENDERPATH_D3D11:
2712 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2714 case RENDERPATH_SOFT:
2716 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2718 DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
2719 // DPSOFTRAST calculates its own mipmaps
2720 mip = dds_miplevels;
2723 mippixels += mipsize;
2724 if (mipwidth <= 1 && mipheight <= 1)
2735 // after upload we have to set some parameters...
2736 switch(vid.renderpath)
2738 case RENDERPATH_GL11:
2739 case RENDERPATH_GL13:
2740 case RENDERPATH_GL20:
2741 case RENDERPATH_GLES1:
2742 case RENDERPATH_GLES2:
2743 #ifdef GL_TEXTURE_MAX_LEVEL
2744 if (dds_miplevels >= 1 && !mipcomplete)
2746 // need to set GL_TEXTURE_MAX_LEVEL
2747 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2750 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2751 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2753 case RENDERPATH_D3D9:
2755 glt->d3daddressw = 0;
2756 if (glt->flags & TEXF_CLAMP)
2758 glt->d3daddressu = D3DTADDRESS_CLAMP;
2759 glt->d3daddressv = D3DTADDRESS_CLAMP;
2760 if (glt->tiledepth > 1)
2761 glt->d3daddressw = D3DTADDRESS_CLAMP;
2765 glt->d3daddressu = D3DTADDRESS_WRAP;
2766 glt->d3daddressv = D3DTADDRESS_WRAP;
2767 if (glt->tiledepth > 1)
2768 glt->d3daddressw = D3DTADDRESS_WRAP;
2770 glt->d3dmipmaplodbias = 0;
2771 glt->d3dmaxmiplevel = 0;
2772 glt->d3dmaxmiplevelfilter = 0;
2773 if (glt->flags & TEXF_MIPMAP)
2775 glt->d3dminfilter = d3d_filter_mipmin;
2776 glt->d3dmagfilter = d3d_filter_mipmag;
2777 glt->d3dmipfilter = d3d_filter_mipmix;
2781 glt->d3dminfilter = d3d_filter_flatmin;
2782 glt->d3dmagfilter = d3d_filter_flatmag;
2783 glt->d3dmipfilter = d3d_filter_flatmix;
2787 case RENDERPATH_D3D10:
2788 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2790 case RENDERPATH_D3D11:
2791 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2793 case RENDERPATH_SOFT:
2794 if (glt->flags & TEXF_FORCELINEAR)
2795 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2796 else if (glt->flags & TEXF_FORCENEAREST)
2797 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2798 else if (glt->flags & TEXF_MIPMAP)
2799 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2801 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2807 Mem_Free((unsigned char *) mippixels_start);
2808 return (rtexture_t *)glt;
2811 int R_TextureWidth(rtexture_t *rt)
2813 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2816 int R_TextureHeight(rtexture_t *rt)
2818 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2821 int R_TextureFlags(rtexture_t *rt)
2823 return rt ? ((gltexture_t *)rt)->flags : 0;
2826 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2828 gltexture_t *glt = (gltexture_t *)rt;
2830 Host_Error("R_UpdateTexture: no data supplied");
2832 Host_Error("R_UpdateTexture: no texture supplied");
2833 if (!glt->texnum && !glt->d3dtexture)
2835 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2838 // update part of the texture
2839 if (glt->bufferpixels)
2842 int bpp = glt->bytesperpixel;
2843 int inputskip = width*bpp;
2844 int outputskip = glt->tilewidth*bpp;
2845 const unsigned char *input = data;
2846 unsigned char *output = glt->bufferpixels;
2847 if (glt->inputdepth != 1 || glt->sides != 1)
2848 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2858 input -= y*inputskip;
2861 if (width > glt->tilewidth - x)
2862 width = glt->tilewidth - x;
2863 if (height > glt->tileheight - y)
2864 height = glt->tileheight - y;
2865 if (width < 1 || height < 1)
2868 glt->buffermodified = true;
2869 output += y*outputskip + x*bpp;
2870 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2871 memcpy(output, input, width*bpp);
2873 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2874 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2876 R_UploadFullTexture(glt, data);
2879 int R_RealGetTexture(rtexture_t *rt)
2884 glt = (gltexture_t *)rt;
2885 if (glt->flags & GLTEXF_DYNAMIC)
2886 R_UpdateDynamicTexture(glt);
2887 if (glt->buffermodified && glt->bufferpixels)
2889 glt->buffermodified = false;
2890 R_UploadFullTexture(glt, glt->bufferpixels);
2899 void R_ClearTexture (rtexture_t *rt)
2901 gltexture_t *glt = (gltexture_t *)rt;
2903 R_UploadFullTexture(glt, NULL);
2906 int R_PicmipForFlags(int flags)
2909 if(flags & TEXF_PICMIP)
2911 miplevel += gl_picmip.integer;
2912 if (flags & TEXF_ISWORLD)
2914 if (r_picmipworld.integer)
2915 miplevel += gl_picmip_world.integer;
2919 else if (flags & TEXF_ISSPRITE)
2921 if (r_picmipsprites.integer)
2922 miplevel += gl_picmip_sprites.integer;
2927 miplevel += gl_picmip_other.integer;
2929 return max(0, miplevel);