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_DEPTHBUFFER: d3dformat = D3DFMT_D24S8;glt->d3disdepthstencilsurface = true;break;
1968 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1970 glt->d3dformat = d3dformat;
1973 if (glt->d3disrendertargetsurface)
1975 if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
1976 Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!");
1978 else if (glt->d3disdepthstencilsurface)
1980 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
1981 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1986 case RENDERPATH_D3D10:
1987 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1989 case RENDERPATH_D3D11:
1990 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1992 case RENDERPATH_SOFT:
1997 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8 | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
1998 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
1999 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2000 case TEXTYPE_DEPTHBUFFER16:
2001 case TEXTYPE_DEPTHBUFFER24:
2002 case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2003 default: Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
2005 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
2010 return (rtexture_t *)glt;
2013 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
2016 return -1; // unsupported on this platform
2018 gltexture_t *glt = (gltexture_t *)rt;
2021 int bytesperpixel = 0;
2022 int bytesperblock = 0;
2024 int dds_format_flags;
2032 GLint internalformat;
2033 const char *ddsfourcc;
2035 return -1; // NULL pointer
2036 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
2037 return -2; // broken driver - crashes on reading internal format
2038 if (!qglGetTexLevelParameteriv)
2040 GL_ActiveTexture(0);
2041 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2042 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2043 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
2044 switch(internalformat)
2046 default: ddsfourcc = NULL;bytesperpixel = 4;break;
2047 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
2048 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
2049 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
2050 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
2052 // if premultiplied alpha, say so in the DDS file
2053 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
2055 switch(internalformat)
2057 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
2058 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
2061 if (!bytesperblock && skipuncompressed)
2062 return -3; // skipped
2063 memset(mipinfo, 0, sizeof(mipinfo));
2064 mipinfo[0][0] = glt->tilewidth;
2065 mipinfo[0][1] = glt->tileheight;
2067 if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tilewidth == 1))
2069 for (mip = 1;mip < 16;mip++)
2071 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
2072 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
2073 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
2081 for (mip = 0;mip < mipmaps;mip++)
2083 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
2084 mipinfo[mip][3] = ddssize;
2085 ddssize += mipinfo[mip][2];
2087 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
2090 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
2094 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
2095 dds_format_flags = 0x4; // DDPF_FOURCC
2099 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
2100 dds_format_flags = 0x40; // DDPF_RGB
2104 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
2105 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
2108 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
2109 memcpy(dds, "DDS ", 4);
2110 StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
2111 StoreLittleLong(dds+8, dds_flags);
2112 StoreLittleLong(dds+12, mipinfo[0][1]); // height
2113 StoreLittleLong(dds+16, mipinfo[0][0]); // width
2114 StoreLittleLong(dds+24, 0); // depth
2115 StoreLittleLong(dds+28, mipmaps); // mipmaps
2116 StoreLittleLong(dds+76, 32); // format size
2117 StoreLittleLong(dds+80, dds_format_flags);
2118 StoreLittleLong(dds+108, dds_caps1);
2119 StoreLittleLong(dds+112, dds_caps2);
2122 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
2123 memcpy(dds+84, ddsfourcc, 4);
2124 for (mip = 0;mip < mipmaps;mip++)
2126 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
2131 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
2132 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
2133 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
2134 for (mip = 0;mip < mipmaps;mip++)
2136 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
2139 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2140 ret = FS_WriteFile(filename, dds, ddssize);
2142 return ret ? ddssize : -5;
2146 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
2148 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
2151 int bytesperblock, bytesperpixel;
2154 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
2155 textypeinfo_t *texinfo;
2156 int mip, mipwidth, mipheight, mipsize, mipsize_total;
2157 unsigned int c, r, g, b;
2158 GLint oldbindtexnum = 0;
2159 unsigned char *mippixels;
2160 unsigned char *mippixels_start;
2161 unsigned char *ddspixels;
2163 fs_offset_t ddsfilesize;
2164 unsigned int ddssize;
2165 qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
2167 if (cls.state == ca_dedicated)
2170 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
2171 ddssize = ddsfilesize;
2175 if(r_texture_dds_load_logfailure.integer)
2176 Log_Printf("ddstexturefailures.log", "%s\n", filename);
2177 return NULL; // not found
2180 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
2183 Con_Printf("^1%s: not a DDS image\n", filename);
2187 //dds_flags = BuffLittleLong(dds+8);
2188 dds_format_flags = BuffLittleLong(dds+80);
2189 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
2190 dds_width = BuffLittleLong(dds+16);
2191 dds_height = BuffLittleLong(dds+12);
2192 ddspixels = dds + 128;
2194 if(r_texture_dds_load_alphamode.integer == 0)
2195 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
2196 flags &= ~TEXF_ALPHA;
2198 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
2199 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
2201 // very sloppy BGRA 32bit identification
2202 textype = TEXTYPE_BGRA;
2203 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2206 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
2207 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2210 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
2213 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
2216 for (i = 3;i < size;i += 4)
2217 if (ddspixels[i] < 255)
2220 flags &= ~TEXF_ALPHA;
2223 else if (!memcmp(dds+84, "DXT1", 4))
2225 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
2226 // LordHavoc: it is my belief that this does not infringe on the
2227 // patent because it is not decoding pixels...
2228 textype = TEXTYPE_DXT1;
2231 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
2232 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2233 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2236 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
2239 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
2241 if(r_texture_dds_load_alphamode.integer == 1)
2244 for (i = 0;i < size;i += bytesperblock)
2245 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
2247 // NOTE: this assumes sizeof(unsigned int) == 4
2248 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
2249 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
2250 if(data & (data<<1) & 0xAAAAAAAA)//rgh
2254 textype = TEXTYPE_DXT1A;
2256 flags &= ~TEXF_ALPHA;
2260 flags &= ~TEXF_ALPHA;
2264 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2266 if(!memcmp(dds+84, "DXT2", 4))
2268 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2270 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2275 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2277 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2280 textype = TEXTYPE_DXT3;
2283 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2284 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2287 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2290 // we currently always assume alpha
2292 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2294 if(!memcmp(dds+84, "DXT4", 4))
2296 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2298 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2303 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2305 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2308 textype = TEXTYPE_DXT5;
2311 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2312 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2315 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2318 // we currently always assume alpha
2323 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2327 // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
2328 if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
2330 textype = TEXTYPE_DXT1;
2334 for (i = 0;i < (int)ddssize;i += bytesperblock)
2335 memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
2339 force_swdecode = false;
2342 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
2344 if(r_texture_dds_swdecode.integer > 1)
2345 force_swdecode = true;
2349 if(r_texture_dds_swdecode.integer < 1)
2355 force_swdecode = true;
2359 // return whether this texture is transparent
2361 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2363 // if we SW decode, choose 2 sizes bigger
2366 // this is quarter res, so do not scale down more than we have to
2370 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2373 // this is where we apply gl_picmip
2374 mippixels_start = ddspixels;
2375 mipwidth = dds_width;
2376 mipheight = dds_height;
2377 while(miplevel >= 1 && dds_miplevels >= 1)
2379 if (mipwidth <= 1 && mipheight <= 1)
2381 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2382 mippixels_start += mipsize; // just skip
2390 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2391 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2393 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2395 // fake decode S3TC if needed
2398 int mipsize_new = mipsize_total / bytesperblock * 4;
2399 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2400 unsigned char *p = mipnewpixels;
2401 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2403 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2404 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2405 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2406 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2407 if(textype == TEXTYPE_DXT5)
2408 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2409 else if(textype == TEXTYPE_DXT3)
2411 (mippixels_start[i-8] & 0x0F)
2412 + (mippixels_start[i-8] >> 4)
2413 + (mippixels_start[i-7] & 0x0F)
2414 + (mippixels_start[i-7] >> 4)
2415 + (mippixels_start[i-6] & 0x0F)
2416 + (mippixels_start[i-6] >> 4)
2417 + (mippixels_start[i-5] & 0x0F)
2418 + (mippixels_start[i-5] >> 4)
2419 ) * (0.125f / 15.0f * 255.0f);
2424 textype = TEXTYPE_BGRA;
2428 // as each block becomes a pixel, we must use pixel count for this
2429 mipwidth = (mipwidth + 3) / 4;
2430 mipheight = (mipheight + 3) / 4;
2431 mipsize = bytesperpixel * mipwidth * mipheight;
2432 mippixels_start = mipnewpixels;
2433 mipsize_total = mipsize_new;
2436 // start mip counting
2437 mippixels = mippixels_start;
2439 // calculate average color if requested
2443 Vector4Clear(avgcolor);
2446 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2448 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2449 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2450 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2451 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2452 if(textype == TEXTYPE_DXT5)
2453 avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
2454 else if(textype == TEXTYPE_DXT3)
2456 (mippixels_start[i-8] & 0x0F)
2457 + (mippixels_start[i-8] >> 4)
2458 + (mippixels_start[i-7] & 0x0F)
2459 + (mippixels_start[i-7] >> 4)
2460 + (mippixels_start[i-6] & 0x0F)
2461 + (mippixels_start[i-6] >> 4)
2462 + (mippixels_start[i-5] & 0x0F)
2463 + (mippixels_start[i-5] >> 4)
2464 ) * (0.125f / 15.0f * 255.0f);
2468 f = (float)bytesperblock / size;
2469 avgcolor[0] *= (0.5f / 31.0f) * f;
2470 avgcolor[1] *= (0.5f / 63.0f) * f;
2471 avgcolor[2] *= (0.5f / 31.0f) * f;
2476 for (i = 0;i < mipsize;i += 4)
2478 avgcolor[0] += mippixels[i+2];
2479 avgcolor[1] += mippixels[i+1];
2480 avgcolor[2] += mippixels[i];
2481 avgcolor[3] += mippixels[i+3];
2483 f = (1.0f / 255.0f) * bytesperpixel / size;
2491 // if we want sRGB, convert now
2494 if (vid.support.ext_texture_srgb)
2498 case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break;
2499 case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break;
2500 case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break;
2501 case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break;
2502 case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break;
2516 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2518 int c0, c1, c0new, c1new;
2519 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2520 r = ((c0 >> 11) & 0x1F);
2521 g = ((c0 >> 5) & 0x3F);
2523 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2524 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2525 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2526 c0new = (r << 11) | (g << 5) | b;
2527 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2528 r = ((c1 >> 11) & 0x1F);
2529 g = ((c1 >> 5) & 0x3F);
2531 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2532 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2533 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2534 c1new = (r << 11) | (g << 5) | b;
2535 // swap the colors if needed to fix order
2536 if(c0 > c1) // thirds
2544 mippixels_start[i+4] ^= 0x55;
2545 mippixels_start[i+5] ^= 0x55;
2546 mippixels_start[i+6] ^= 0x55;
2547 mippixels_start[i+7] ^= 0x55;
2549 else if(c0new == c1new)
2551 mippixels_start[i+4] = 0x00;
2552 mippixels_start[i+5] = 0x00;
2553 mippixels_start[i+6] = 0x00;
2554 mippixels_start[i+7] = 0x00;
2557 else // half + transparent
2564 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2565 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2566 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2567 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2570 mippixels_start[i] = c0new & 255;
2571 mippixels_start[i+1] = c0new >> 8;
2572 mippixels_start[i+2] = c1new & 255;
2573 mippixels_start[i+3] = c1new >> 8;
2578 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2586 // when not requesting mipmaps, do not load them
2587 if(!(flags & TEXF_MIPMAP))
2590 if (dds_miplevels >= 1)
2591 flags |= TEXF_MIPMAP;
2593 flags &= ~TEXF_MIPMAP;
2595 texinfo = R_GetTexTypeInfo(textype, flags);
2597 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2598 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2600 glt->chain = pool->gltchain;
2601 pool->gltchain = glt;
2602 glt->inputwidth = mipwidth;
2603 glt->inputheight = mipheight;
2604 glt->inputdepth = 1;
2606 glt->textype = texinfo;
2607 glt->texturetype = GLTEXTURETYPE_2D;
2608 glt->inputdatasize = ddssize;
2609 glt->glinternalformat = texinfo->glinternalformat;
2610 glt->glformat = texinfo->glformat;
2611 glt->gltype = texinfo->gltype;
2612 glt->bytesperpixel = texinfo->internalbytesperpixel;
2614 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2615 glt->tilewidth = mipwidth;
2616 glt->tileheight = mipheight;
2618 glt->miplevels = dds_miplevels;
2620 // texture uploading can take a while, so make sure we're sending keepalives
2621 CL_KeepaliveMessage(false);
2623 // create the texture object
2624 switch(vid.renderpath)
2626 case RENDERPATH_GL11:
2627 case RENDERPATH_GL13:
2628 case RENDERPATH_GL20:
2629 case RENDERPATH_GLES1:
2630 case RENDERPATH_GLES2:
2632 GL_ActiveTexture(0);
2633 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2634 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2635 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2637 case RENDERPATH_D3D9:
2640 D3DFORMAT d3dformat;
2645 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2646 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2647 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2648 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2649 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2652 d3dpool = D3DPOOL_MANAGED;
2653 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2657 case RENDERPATH_D3D10:
2658 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2660 case RENDERPATH_D3D11:
2661 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2663 case RENDERPATH_SOFT:
2664 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);
2668 // upload the texture
2669 // we need to restore the texture binding after finishing the upload
2670 mipcomplete = false;
2672 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2674 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2675 if (mippixels + mipsize > mippixels_start + mipsize_total)
2677 switch(vid.renderpath)
2679 case RENDERPATH_GL11:
2680 case RENDERPATH_GL13:
2681 case RENDERPATH_GL20:
2682 case RENDERPATH_GLES1:
2683 case RENDERPATH_GLES2:
2686 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2690 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2693 case RENDERPATH_D3D9:
2696 D3DLOCKED_RECT d3dlockedrect;
2697 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2699 memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2700 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2706 case RENDERPATH_D3D10:
2707 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2709 case RENDERPATH_D3D11:
2710 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2712 case RENDERPATH_SOFT:
2714 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2716 DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
2717 // DPSOFTRAST calculates its own mipmaps
2718 mip = dds_miplevels;
2721 mippixels += mipsize;
2722 if (mipwidth <= 1 && mipheight <= 1)
2733 // after upload we have to set some parameters...
2734 switch(vid.renderpath)
2736 case RENDERPATH_GL11:
2737 case RENDERPATH_GL13:
2738 case RENDERPATH_GL20:
2739 case RENDERPATH_GLES1:
2740 case RENDERPATH_GLES2:
2741 #ifdef GL_TEXTURE_MAX_LEVEL
2742 if (dds_miplevels >= 1 && !mipcomplete)
2744 // need to set GL_TEXTURE_MAX_LEVEL
2745 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2748 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2749 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2751 case RENDERPATH_D3D9:
2753 glt->d3daddressw = 0;
2754 if (glt->flags & TEXF_CLAMP)
2756 glt->d3daddressu = D3DTADDRESS_CLAMP;
2757 glt->d3daddressv = D3DTADDRESS_CLAMP;
2758 if (glt->tiledepth > 1)
2759 glt->d3daddressw = D3DTADDRESS_CLAMP;
2763 glt->d3daddressu = D3DTADDRESS_WRAP;
2764 glt->d3daddressv = D3DTADDRESS_WRAP;
2765 if (glt->tiledepth > 1)
2766 glt->d3daddressw = D3DTADDRESS_WRAP;
2768 glt->d3dmipmaplodbias = 0;
2769 glt->d3dmaxmiplevel = 0;
2770 glt->d3dmaxmiplevelfilter = 0;
2771 if (glt->flags & TEXF_MIPMAP)
2773 glt->d3dminfilter = d3d_filter_mipmin;
2774 glt->d3dmagfilter = d3d_filter_mipmag;
2775 glt->d3dmipfilter = d3d_filter_mipmix;
2779 glt->d3dminfilter = d3d_filter_flatmin;
2780 glt->d3dmagfilter = d3d_filter_flatmag;
2781 glt->d3dmipfilter = d3d_filter_flatmix;
2785 case RENDERPATH_D3D10:
2786 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2788 case RENDERPATH_D3D11:
2789 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2791 case RENDERPATH_SOFT:
2792 if (glt->flags & TEXF_FORCELINEAR)
2793 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2794 else if (glt->flags & TEXF_FORCENEAREST)
2795 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2796 else if (glt->flags & TEXF_MIPMAP)
2797 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2799 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2805 Mem_Free((unsigned char *) mippixels_start);
2806 return (rtexture_t *)glt;
2809 int R_TextureWidth(rtexture_t *rt)
2811 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2814 int R_TextureHeight(rtexture_t *rt)
2816 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2819 int R_TextureFlags(rtexture_t *rt)
2821 return rt ? ((gltexture_t *)rt)->flags : 0;
2824 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2826 gltexture_t *glt = (gltexture_t *)rt;
2828 Host_Error("R_UpdateTexture: no data supplied");
2830 Host_Error("R_UpdateTexture: no texture supplied");
2831 if (!glt->texnum && !glt->d3dtexture)
2833 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2836 // update part of the texture
2837 if (glt->bufferpixels)
2840 int bpp = glt->bytesperpixel;
2841 int inputskip = width*bpp;
2842 int outputskip = glt->tilewidth*bpp;
2843 const unsigned char *input = data;
2844 unsigned char *output = glt->bufferpixels;
2845 if (glt->inputdepth != 1 || glt->sides != 1)
2846 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2856 input -= y*inputskip;
2859 if (width > glt->tilewidth - x)
2860 width = glt->tilewidth - x;
2861 if (height > glt->tileheight - y)
2862 height = glt->tileheight - y;
2863 if (width < 1 || height < 1)
2866 glt->buffermodified = true;
2867 output += y*outputskip + x*bpp;
2868 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2869 memcpy(output, input, width*bpp);
2871 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2872 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2874 R_UploadFullTexture(glt, data);
2877 int R_RealGetTexture(rtexture_t *rt)
2882 glt = (gltexture_t *)rt;
2883 if (glt->flags & GLTEXF_DYNAMIC)
2884 R_UpdateDynamicTexture(glt);
2885 if (glt->buffermodified && glt->bufferpixels)
2887 glt->buffermodified = false;
2888 R_UploadFullTexture(glt, glt->bufferpixels);
2897 void R_ClearTexture (rtexture_t *rt)
2899 gltexture_t *glt = (gltexture_t *)rt;
2901 R_UploadFullTexture(glt, NULL);
2904 int R_PicmipForFlags(int flags)
2907 if(flags & TEXF_PICMIP)
2909 miplevel += gl_picmip.integer;
2910 if (flags & TEXF_ISWORLD)
2912 if (r_picmipworld.integer)
2913 miplevel += gl_picmip_world.integer;
2917 else if (flags & TEXF_ISSPRITE)
2919 if (r_picmipsprites.integer)
2920 miplevel += gl_picmip_sprites.integer;
2925 miplevel += gl_picmip_other.integer;
2927 return max(0, miplevel);