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, 0: done log, 1: log with no optional textures (_norm, glow etc.). 2: log all"};
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 qboolean glisdepthstencil; // indicates that FBO attachment has to be GL_DEPTH_STENCIL_ATTACHMENT
179 int gltexturetypeenum; // used by R_Mesh_TexBind
180 // d3d stuff the backend needs
184 qboolean d3disrendertargetsurface;
185 qboolean d3disdepthstencilsurface;
195 int d3dmaxmiplevelfilter;
196 int d3dmipmaplodbias;
200 // dynamic texture stuff [11/22/2007 Black]
201 updatecallback_t updatecallback;
202 void *updatacallback_data;
203 // --- [11/22/2007 Black]
205 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
206 unsigned char *bufferpixels;
207 qboolean buffermodified;
209 // pointer to texturepool (check this to see if the texture is allocated)
210 struct gltexturepool_s *pool;
211 // pointer to next texture in texturepool chain
212 struct gltexture_s *chain;
213 // name of the texture (this might be removed someday), no duplicates
214 char identifier[MAX_QPATH + 32];
215 // original data size in *inputtexels
216 int inputwidth, inputheight, inputdepth;
217 // copy of the original texture(s) supplied to the upload function, for
218 // delayed uploads (non-precached)
219 unsigned char *inputtexels;
220 // original data size in *inputtexels
222 // flags supplied to the LoadTexture function
223 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
227 // pointer to one of the textype_ structs
228 textypeinfo_t *textype;
229 // one of the GLTEXTURETYPE_ values
231 // palette if the texture is TEXTYPE_PALETTE
232 const unsigned int *palette;
233 // actual stored texture size after gl_picmip and gl_max_size are applied
234 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
235 int tilewidth, tileheight, tiledepth;
236 // 1 or 6 depending on texturetype
238 // how many mipmap levels in this texture
242 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
245 int glinternalformat;
246 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
251 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
253 typedef struct gltexturepool_s
255 unsigned int sentinel;
256 struct gltexture_s *gltchain;
257 struct gltexturepool_s *next;
261 static gltexturepool_t *gltexturepoolchain = NULL;
263 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
264 static int resizebuffersize = 0;
265 static const unsigned char *texturebuffer;
267 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
271 case TEXTYPE_DXT1: return &textype_dxt1;
272 case TEXTYPE_DXT1A: return &textype_dxt1a;
273 case TEXTYPE_DXT3: return &textype_dxt3;
274 case TEXTYPE_DXT5: return &textype_dxt5;
275 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
276 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);
277 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);
278 case TEXTYPE_ALPHA: return &textype_alpha;
279 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
280 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
281 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
282 case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
283 case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
284 case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
285 case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
286 case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
287 case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
288 case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
289 case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1;
290 case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a;
291 case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
292 case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
293 case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
294 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);
295 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);
297 Host_Error("R_GetTexTypeInfo: unknown texture format");
303 // dynamic texture code [11/22/2007 Black]
304 void R_MarkDirtyTexture(rtexture_t *rt) {
305 gltexture_t *glt = (gltexture_t*) rt;
310 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
311 if (glt->flags & GLTEXF_DYNAMIC)
313 // mark it as dirty, so R_RealGetTexture gets called
318 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
319 gltexture_t *glt = (gltexture_t*) rt;
324 glt->flags |= GLTEXF_DYNAMIC;
325 glt->updatecallback = updatecallback;
326 glt->updatacallback_data = data;
329 static void R_UpdateDynamicTexture(gltexture_t *glt) {
331 if( glt->updatecallback ) {
332 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
336 void R_PurgeTexture(rtexture_t *rt)
338 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
343 void R_FreeTexture(rtexture_t *rt)
345 gltexture_t *glt, **gltpointer;
347 glt = (gltexture_t *)rt;
349 Host_Error("R_FreeTexture: texture == NULL");
351 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
352 if (*gltpointer == glt)
353 *gltpointer = glt->chain;
355 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
357 R_Mesh_ClearBindingsForTexture(glt->texnum);
359 switch(vid.renderpath)
361 case RENDERPATH_GL11:
362 case RENDERPATH_GL13:
363 case RENDERPATH_GL20:
364 case RENDERPATH_GLES1:
365 case RENDERPATH_GLES2:
369 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
371 if (glt->renderbuffernum)
374 qglDeleteRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
377 case RENDERPATH_D3D9:
380 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dsurface);
381 else if (glt->tiledepth > 1)
382 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
383 else if (glt->sides == 6)
384 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
386 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
387 glt->d3dtexture = NULL;
388 glt->d3dsurface = NULL;
391 case RENDERPATH_D3D10:
392 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
394 case RENDERPATH_D3D11:
395 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
397 case RENDERPATH_SOFT:
399 DPSOFTRAST_Texture_Free(glt->texnum);
403 if (glt->inputtexels)
404 Mem_Free(glt->inputtexels);
405 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
408 rtexturepool_t *R_AllocTexturePool(void)
410 gltexturepool_t *pool;
411 if (texturemempool == NULL)
413 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
416 pool->next = gltexturepoolchain;
417 gltexturepoolchain = pool;
418 pool->sentinel = TEXTUREPOOL_SENTINEL;
419 return (rtexturepool_t *)pool;
422 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
424 gltexturepool_t *pool, **poolpointer;
425 if (rtexturepool == NULL)
427 if (*rtexturepool == NULL)
429 pool = (gltexturepool_t *)(*rtexturepool);
430 *rtexturepool = NULL;
431 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
432 Host_Error("R_FreeTexturePool: pool already freed");
433 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
434 if (*poolpointer == pool)
435 *poolpointer = pool->next;
437 Host_Error("R_FreeTexturePool: pool not linked");
438 while (pool->gltchain)
439 R_FreeTexture((rtexture_t *)pool->gltchain);
444 typedef struct glmode_s
447 int minification, magnification;
448 DPSOFTRAST_TEXTURE_FILTER dpsoftrastfilter_mipmap, dpsoftrastfilter_nomipmap;
452 static glmode_t modes[6] =
454 {"GL_NEAREST", GL_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
455 {"GL_LINEAR", GL_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
456 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
457 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
458 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
459 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR}
463 typedef struct d3dmode_s
470 static d3dmode_t d3dmodes[6] =
472 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
473 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
474 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
475 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
476 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
477 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
481 static void GL_TextureMode_f (void)
486 gltexturepool_t *pool;
490 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
491 for (i = 0;i < 6;i++)
493 if (gl_filter_min == modes[i].minification)
495 Con_Printf("%s\n", modes[i].name);
499 Con_Print("current filter is unknown???\n");
503 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
504 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
508 Con_Print("bad filter name\n");
512 gl_filter_min = modes[i].minification;
513 gl_filter_mag = modes[i].magnification;
514 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
516 dpsoftrast_filter_mipmap = modes[i].dpsoftrastfilter_mipmap;
517 dpsoftrast_filter_nomipmap = modes[i].dpsoftrastfilter_nomipmap;
519 switch(vid.renderpath)
521 case RENDERPATH_GL11:
522 case RENDERPATH_GL13:
523 case RENDERPATH_GL20:
524 case RENDERPATH_GLES1:
525 case RENDERPATH_GLES2:
526 // change all the existing mipmap texture objects
527 // FIXME: force renderer(/client/something?) restart instead?
530 for (pool = gltexturepoolchain;pool;pool = pool->next)
532 for (glt = pool->gltchain;glt;glt = glt->chain)
534 // only update already uploaded images
535 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
537 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
538 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
539 if (glt->flags & TEXF_MIPMAP)
541 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
545 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
547 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
548 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
553 case RENDERPATH_D3D9:
555 d3d_filter_flatmin = d3dmodes[i].m1;
556 d3d_filter_flatmag = d3dmodes[i].m1;
557 d3d_filter_flatmix = D3DTEXF_POINT;
558 d3d_filter_mipmin = d3dmodes[i].m1;
559 d3d_filter_mipmag = d3dmodes[i].m1;
560 d3d_filter_mipmix = d3dmodes[i].m2;
561 d3d_filter_nomip = i < 2;
562 if (gl_texture_anisotropy.integer > 1 && i == 5)
563 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
564 for (pool = gltexturepoolchain;pool;pool = pool->next)
566 for (glt = pool->gltchain;glt;glt = glt->chain)
568 // only update already uploaded images
569 if (glt->d3dtexture && !glt->d3dsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
571 if (glt->flags & TEXF_MIPMAP)
573 glt->d3dminfilter = d3d_filter_mipmin;
574 glt->d3dmagfilter = d3d_filter_mipmag;
575 glt->d3dmipfilter = d3d_filter_mipmix;
576 glt->d3dmaxmiplevelfilter = 0;
580 glt->d3dminfilter = d3d_filter_flatmin;
581 glt->d3dmagfilter = d3d_filter_flatmag;
582 glt->d3dmipfilter = d3d_filter_flatmix;
583 glt->d3dmaxmiplevelfilter = 0;
590 case RENDERPATH_D3D10:
591 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
593 case RENDERPATH_D3D11:
594 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
596 case RENDERPATH_SOFT:
597 // change all the existing texture objects
598 for (pool = gltexturepoolchain;pool;pool = pool->next)
599 for (glt = pool->gltchain;glt;glt = glt->chain)
600 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
601 DPSOFTRAST_Texture_Filter(glt->texnum, (glt->flags & TEXF_MIPMAP) ? dpsoftrast_filter_mipmap : dpsoftrast_filter_nomipmap);
606 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)
608 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
613 case GLTEXTURETYPE_2D:
614 maxsize = vid.maxtexturesize_2d;
615 if (flags & TEXF_PICMIP)
617 maxsize = bound(1, gl_max_size.integer, maxsize);
621 case GLTEXTURETYPE_3D:
622 maxsize = vid.maxtexturesize_3d;
624 case GLTEXTURETYPE_CUBEMAP:
625 maxsize = vid.maxtexturesize_cubemap;
629 if (vid.support.arb_texture_non_power_of_two)
631 width2 = min(inwidth >> picmip, maxsize);
632 height2 = min(inheight >> picmip, maxsize);
633 depth2 = min(indepth >> picmip, maxsize);
637 for (width2 = 1;width2 < inwidth;width2 <<= 1);
638 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
639 for (height2 = 1;height2 < inheight;height2 <<= 1);
640 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
641 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
642 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
645 switch(vid.renderpath)
647 case RENDERPATH_GL11:
648 case RENDERPATH_GL13:
649 case RENDERPATH_GL20:
650 case RENDERPATH_D3D10:
651 case RENDERPATH_D3D11:
652 case RENDERPATH_SOFT:
653 case RENDERPATH_GLES1:
654 case RENDERPATH_GLES2:
656 case RENDERPATH_D3D9:
658 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
659 if (texturetype == GLTEXTURETYPE_2D)
661 width2 = max(width2, 2);
662 height2 = max(height2, 2);
669 if (flags & TEXF_MIPMAP)
671 int extent = max(width2, max(height2, depth2));
677 *outwidth = max(1, width2);
679 *outheight = max(1, height2);
681 *outdepth = max(1, depth2);
683 *outmiplevels = miplevels;
687 static int R_CalcTexelDataSize (gltexture_t *glt)
689 int width2, height2, depth2, size;
691 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
693 size = width2 * height2 * depth2;
695 if (glt->flags & TEXF_MIPMAP)
697 while (width2 > 1 || height2 > 1 || depth2 > 1)
705 size += width2 * height2 * depth2;
709 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
712 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
716 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
717 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
719 gltexturepool_t *pool;
721 Con_Print("glsize input loaded mip alpha name\n");
722 for (pool = gltexturepoolchain;pool;pool = pool->next)
730 for (glt = pool->gltchain;glt;glt = glt->chain)
732 glsize = R_CalcTexelDataSize(glt);
733 isloaded = glt->texnum != 0 || glt->renderbuffernum != 0 || glt->d3dtexture || glt->d3dsurface;
735 pooltotalt += glsize;
736 pooltotalp += glt->inputdatasize;
740 poolloadedt += glsize;
741 poolloadedp += glt->inputdatasize;
744 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);
747 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);
748 sumtotal += pooltotal;
749 sumtotalt += pooltotalt;
750 sumtotalp += pooltotalp;
751 sumloaded += poolloaded;
752 sumloadedt += poolloadedt;
753 sumloadedp += poolloadedp;
756 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);
759 static void R_TextureStats_f(void)
761 R_TextureStats_Print(true, true, true);
764 static void r_textures_start(void)
766 switch(vid.renderpath)
768 case RENDERPATH_GL11:
769 case RENDERPATH_GL13:
770 case RENDERPATH_GL20:
771 case RENDERPATH_GLES1:
772 case RENDERPATH_GLES2:
773 // LordHavoc: allow any alignment
775 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
776 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
778 case RENDERPATH_D3D9:
780 case RENDERPATH_D3D10:
781 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
783 case RENDERPATH_D3D11:
784 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
786 case RENDERPATH_SOFT:
790 texturemempool = Mem_AllocPool("texture management", 0, NULL);
791 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
793 // Disable JPEG screenshots if the DLL isn't loaded
794 if (! JPEG_OpenLibrary ())
795 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
796 if (! PNG_OpenLibrary ())
797 Cvar_SetValueQuick (&scr_screenshot_png, 0);
800 static void r_textures_shutdown(void)
802 rtexturepool_t *temp;
804 JPEG_CloseLibrary ();
806 while(gltexturepoolchain)
808 temp = (rtexturepool_t *) gltexturepoolchain;
809 R_FreeTexturePool(&temp);
812 resizebuffersize = 0;
814 colorconvertbuffer = NULL;
815 texturebuffer = NULL;
816 Mem_ExpandableArray_FreeArray(&texturearray);
817 Mem_FreePool(&texturemempool);
820 static void r_textures_newmap(void)
824 static void r_textures_devicelost(void)
828 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
829 for (i = 0;i < endindex;i++)
831 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
832 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
834 switch(vid.renderpath)
836 case RENDERPATH_GL11:
837 case RENDERPATH_GL13:
838 case RENDERPATH_GL20:
839 case RENDERPATH_GLES1:
840 case RENDERPATH_GLES2:
842 case RENDERPATH_D3D9:
845 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dsurface);
846 else if (glt->tiledepth > 1)
847 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
848 else if (glt->sides == 6)
849 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
851 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
852 glt->d3dtexture = NULL;
853 glt->d3dsurface = NULL;
856 case RENDERPATH_D3D10:
857 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
859 case RENDERPATH_D3D11:
860 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
862 case RENDERPATH_SOFT:
868 static void r_textures_devicerestored(void)
872 endindex = Mem_ExpandableArray_IndexRange(&texturearray);
873 for (i = 0;i < endindex;i++)
875 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
876 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
878 switch(vid.renderpath)
880 case RENDERPATH_GL11:
881 case RENDERPATH_GL13:
882 case RENDERPATH_GL20:
883 case RENDERPATH_GLES1:
884 case RENDERPATH_GLES2:
886 case RENDERPATH_D3D9:
890 if (glt->d3disrendertargetsurface)
892 if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
893 Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!");
895 else if (glt->d3disdepthstencilsurface)
897 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
898 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
900 else if (glt->tiledepth > 1)
902 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)))
903 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
905 else if (glt->sides == 6)
907 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
908 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
912 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)))
913 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
918 case RENDERPATH_D3D10:
919 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
921 case RENDERPATH_D3D11:
922 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
924 case RENDERPATH_SOFT:
931 void R_Textures_Init (void)
933 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");
934 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
935 Cvar_RegisterVariable (&gl_max_size);
936 Cvar_RegisterVariable (&gl_picmip);
937 Cvar_RegisterVariable (&gl_picmip_world);
938 Cvar_RegisterVariable (&r_picmipworld);
939 Cvar_RegisterVariable (&gl_picmip_sprites);
940 Cvar_RegisterVariable (&r_picmipsprites);
941 Cvar_RegisterVariable (&gl_picmip_other);
942 Cvar_RegisterVariable (&gl_max_lightmapsize);
943 Cvar_RegisterVariable (&r_lerpimages);
944 Cvar_RegisterVariable (&gl_texture_anisotropy);
945 Cvar_RegisterVariable (&gl_texturecompression);
946 Cvar_RegisterVariable (&gl_texturecompression_color);
947 Cvar_RegisterVariable (&gl_texturecompression_normal);
948 Cvar_RegisterVariable (&gl_texturecompression_gloss);
949 Cvar_RegisterVariable (&gl_texturecompression_glow);
950 Cvar_RegisterVariable (&gl_texturecompression_2d);
951 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
952 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
953 Cvar_RegisterVariable (&gl_texturecompression_sky);
954 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
955 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
956 Cvar_RegisterVariable (&gl_texturecompression_sprites);
957 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
958 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
959 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
960 Cvar_RegisterVariable (&r_texture_dds_swdecode);
962 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
965 void R_Textures_Frame (void)
967 static int old_aniso = 0;
969 // could do procedural texture animation here, if we keep track of which
970 // textures were accessed this frame...
972 // free the resize buffers
973 resizebuffersize = 0;
976 Mem_Free(resizebuffer);
979 if (colorconvertbuffer)
981 Mem_Free(colorconvertbuffer);
982 colorconvertbuffer = NULL;
985 if (old_aniso != gl_texture_anisotropy.integer)
988 gltexturepool_t *pool;
991 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
993 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
995 switch(vid.renderpath)
997 case RENDERPATH_GL11:
998 case RENDERPATH_GL13:
999 case RENDERPATH_GL20:
1000 case RENDERPATH_GLES1:
1001 case RENDERPATH_GLES2:
1003 GL_ActiveTexture(0);
1004 for (pool = gltexturepoolchain;pool;pool = pool->next)
1006 for (glt = pool->gltchain;glt;glt = glt->chain)
1008 // only update already uploaded images
1009 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
1011 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1013 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1014 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
1016 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1021 case RENDERPATH_D3D9:
1022 case RENDERPATH_D3D10:
1023 case RENDERPATH_D3D11:
1024 case RENDERPATH_SOFT:
1030 static void R_MakeResizeBufferBigger(int size)
1032 if (resizebuffersize < size)
1034 resizebuffersize = size;
1036 Mem_Free(resizebuffer);
1037 if (colorconvertbuffer)
1038 Mem_Free(colorconvertbuffer);
1039 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
1040 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
1041 if (!resizebuffer || !colorconvertbuffer)
1042 Host_Error("R_Upload: out of memory");
1046 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
1048 int textureenum = gltexturetypeenums[texturetype];
1049 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
1053 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
1055 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
1056 if (gl_texture_anisotropy.integer != aniso)
1057 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
1058 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
1060 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
1061 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
1062 #ifdef GL_TEXTURE_WRAP_R
1063 if (gltexturetypedimensions[texturetype] >= 3)
1065 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
1070 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
1072 if (flags & TEXF_MIPMAP)
1074 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
1078 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
1080 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
1082 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
1084 if (flags & TEXF_MIPMAP)
1086 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
1088 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
1092 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
1097 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
1099 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
1103 if (flags & TEXF_MIPMAP)
1105 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1109 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1111 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1116 case TEXTYPE_SHADOWMAP16_COMP:
1117 case TEXTYPE_SHADOWMAP24_COMP:
1118 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1119 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1120 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1122 case TEXTYPE_SHADOWMAP16_RAW:
1123 case TEXTYPE_SHADOWMAP24_RAW:
1124 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1125 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1126 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1135 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1138 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1140 if (glt->texturetype != GLTEXTURETYPE_2D)
1141 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1143 if (glt->textype->textype == TEXTYPE_PALETTE)
1144 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1146 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1147 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1149 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1150 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1152 // update a portion of the image
1154 switch(vid.renderpath)
1156 case RENDERPATH_GL11:
1157 case RENDERPATH_GL13:
1158 case RENDERPATH_GL20:
1159 case RENDERPATH_GLES1:
1160 case RENDERPATH_GLES2:
1164 // we need to restore the texture binding after finishing the upload
1165 GL_ActiveTexture(0);
1166 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1167 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1168 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1169 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1172 case RENDERPATH_D3D9:
1176 D3DLOCKED_RECT d3dlockedrect;
1178 memset(&d3drect, 0, sizeof(d3drect));
1179 d3drect.left = fragx;
1180 d3drect.top = fragy;
1181 d3drect.right = fragx+fragwidth;
1182 d3drect.bottom = fragy+fragheight;
1183 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1185 for (y = 0;y < fragheight;y++)
1186 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1187 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1192 case RENDERPATH_D3D10:
1193 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1195 case RENDERPATH_D3D11:
1196 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1198 case RENDERPATH_SOFT:
1199 DPSOFTRAST_Texture_UpdatePartial(glt->texnum, 0, data, fragx, fragy, fragwidth, fragheight);
1204 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1206 int i, mip = 0, width, height, depth;
1207 GLint oldbindtexnum = 0;
1208 const unsigned char *prevbuffer;
1211 // error out if a stretch is needed on special texture types
1212 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1213 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1215 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1216 // of the target size and then use the mipmap reduction function to get
1217 // high quality supersampled results
1218 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1219 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1220 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1221 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1223 if (prevbuffer == NULL)
1225 width = glt->tilewidth;
1226 height = glt->tileheight;
1227 depth = glt->tiledepth;
1228 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1229 // prevbuffer = resizebuffer;
1233 if (glt->textype->textype == TEXTYPE_PALETTE)
1235 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1236 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1237 prevbuffer = colorconvertbuffer;
1239 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1241 // multiply RGB channels by A channel before uploading
1243 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1245 alpha = prevbuffer[i+3];
1246 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1247 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1248 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1249 colorconvertbuffer[i+3] = alpha;
1251 prevbuffer = colorconvertbuffer;
1253 // scale up to a power of 2 size (if appropriate)
1254 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1256 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1257 prevbuffer = resizebuffer;
1259 // apply mipmap reduction algorithm to get down to picmip/max_size
1260 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1262 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1263 prevbuffer = resizebuffer;
1267 // do the appropriate upload type...
1268 switch(vid.renderpath)
1270 case RENDERPATH_GL11:
1271 case RENDERPATH_GL13:
1272 case RENDERPATH_GL20:
1273 case RENDERPATH_GLES1:
1274 case RENDERPATH_GLES2:
1275 if (glt->texnum) // not renderbuffers
1279 // we need to restore the texture binding after finishing the upload
1280 GL_ActiveTexture(0);
1281 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1282 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1284 #ifdef GL_TEXTURE_COMPRESSION_HINT_ARB
1285 if (qglGetCompressedTexImageARB)
1287 if (gl_texturecompression.integer >= 2)
1288 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1290 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1294 switch(glt->texturetype)
1296 case GLTEXTURETYPE_2D:
1297 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1298 if (glt->flags & TEXF_MIPMAP)
1300 while (width > 1 || height > 1 || depth > 1)
1302 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1303 prevbuffer = resizebuffer;
1304 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1308 case GLTEXTURETYPE_3D:
1310 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1311 if (glt->flags & TEXF_MIPMAP)
1313 while (width > 1 || height > 1 || depth > 1)
1315 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1316 prevbuffer = resizebuffer;
1317 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1322 case GLTEXTURETYPE_CUBEMAP:
1323 // convert and upload each side in turn,
1324 // from a continuous block of input texels
1325 texturebuffer = (unsigned char *)prevbuffer;
1326 for (i = 0;i < 6;i++)
1328 prevbuffer = texturebuffer;
1329 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1330 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1332 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1333 prevbuffer = resizebuffer;
1336 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1338 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1339 prevbuffer = resizebuffer;
1342 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1343 if (glt->flags & TEXF_MIPMAP)
1345 while (width > 1 || height > 1 || depth > 1)
1347 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1348 prevbuffer = resizebuffer;
1349 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1355 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1356 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1359 case RENDERPATH_D3D9:
1361 if (!(glt->flags & TEXF_RENDERTARGET) && glt->d3dtexture && !glt->d3dsurface)
1363 D3DLOCKED_RECT d3dlockedrect;
1364 D3DLOCKED_BOX d3dlockedbox;
1365 switch(glt->texturetype)
1367 case GLTEXTURETYPE_2D:
1368 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1371 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1373 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1374 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1377 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1379 while (width > 1 || height > 1 || depth > 1)
1381 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1382 prevbuffer = resizebuffer;
1383 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1385 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1386 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1392 case GLTEXTURETYPE_3D:
1393 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1395 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1396 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1397 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1400 if (glt->flags & TEXF_MIPMAP)
1402 while (width > 1 || height > 1 || depth > 1)
1404 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1405 prevbuffer = resizebuffer;
1406 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1408 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1409 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1410 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1416 case GLTEXTURETYPE_CUBEMAP:
1417 // convert and upload each side in turn,
1418 // from a continuous block of input texels
1419 texturebuffer = (unsigned char *)prevbuffer;
1420 for (i = 0;i < 6;i++)
1422 prevbuffer = texturebuffer;
1423 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1424 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1426 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1427 prevbuffer = resizebuffer;
1430 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1432 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1433 prevbuffer = resizebuffer;
1436 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1438 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1439 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1442 if (glt->flags & TEXF_MIPMAP)
1444 while (width > 1 || height > 1 || depth > 1)
1446 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1447 prevbuffer = resizebuffer;
1448 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1450 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1451 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1460 glt->d3daddressw = 0;
1461 if (glt->flags & TEXF_CLAMP)
1463 glt->d3daddressu = D3DTADDRESS_CLAMP;
1464 glt->d3daddressv = D3DTADDRESS_CLAMP;
1465 if (glt->tiledepth > 1)
1466 glt->d3daddressw = D3DTADDRESS_CLAMP;
1470 glt->d3daddressu = D3DTADDRESS_WRAP;
1471 glt->d3daddressv = D3DTADDRESS_WRAP;
1472 if (glt->tiledepth > 1)
1473 glt->d3daddressw = D3DTADDRESS_WRAP;
1475 glt->d3dmipmaplodbias = 0;
1476 glt->d3dmaxmiplevel = 0;
1477 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1478 if (glt->flags & TEXF_FORCELINEAR)
1480 glt->d3dminfilter = D3DTEXF_LINEAR;
1481 glt->d3dmagfilter = D3DTEXF_LINEAR;
1482 glt->d3dmipfilter = D3DTEXF_POINT;
1484 else if (glt->flags & TEXF_FORCENEAREST)
1486 glt->d3dminfilter = D3DTEXF_POINT;
1487 glt->d3dmagfilter = D3DTEXF_POINT;
1488 glt->d3dmipfilter = D3DTEXF_POINT;
1490 else if (glt->flags & TEXF_MIPMAP)
1492 glt->d3dminfilter = d3d_filter_mipmin;
1493 glt->d3dmagfilter = d3d_filter_mipmag;
1494 glt->d3dmipfilter = d3d_filter_mipmix;
1498 glt->d3dminfilter = d3d_filter_flatmin;
1499 glt->d3dmagfilter = d3d_filter_flatmag;
1500 glt->d3dmipfilter = d3d_filter_flatmix;
1504 case RENDERPATH_D3D10:
1505 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1507 case RENDERPATH_D3D11:
1508 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1510 case RENDERPATH_SOFT:
1511 switch(glt->texturetype)
1513 case GLTEXTURETYPE_2D:
1514 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1516 case GLTEXTURETYPE_3D:
1517 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1519 case GLTEXTURETYPE_CUBEMAP:
1520 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1522 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1523 // convert and upload each side in turn,
1524 // from a continuous block of input texels
1525 // copy the results into combinedbuffer
1526 texturebuffer = (unsigned char *)prevbuffer;
1527 for (i = 0;i < 6;i++)
1529 prevbuffer = texturebuffer;
1530 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1531 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1533 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1534 prevbuffer = resizebuffer;
1537 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1539 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1540 prevbuffer = resizebuffer;
1542 memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1544 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1545 Mem_Free(combinedbuffer);
1548 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1551 if (glt->flags & TEXF_FORCELINEAR)
1552 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1553 else if (glt->flags & TEXF_FORCENEAREST)
1554 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1555 else if (glt->flags & TEXF_MIPMAP)
1556 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1558 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1563 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)
1567 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1568 textypeinfo_t *texinfo, *texinfo2;
1569 unsigned char *temppixels = NULL;
1572 if (cls.state == ca_dedicated)
1575 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1576 if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1578 int numpixels = width * height * depth * sides;
1579 size = numpixels * 4;
1580 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1583 const unsigned char *p;
1584 unsigned char *o = temppixels;
1585 for (i = 0;i < numpixels;i++, o += 4)
1587 p = (const unsigned char *)palette + 4*data[i];
1595 textype = TEXTYPE_RGBA;
1600 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1601 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1602 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1603 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1609 static int rgbaswapindices[4] = {2, 1, 0, 3};
1610 size = width * height * depth * sides * 4;
1611 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1613 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1617 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1618 if (!vid.support.ext_texture_srgb)
1620 qboolean convertsRGB = false;
1623 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1624 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1625 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1626 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1627 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;convertsRGB = true;break;
1628 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1629 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1633 if (convertsRGB && data)
1635 size = width * height * depth * sides * 4;
1638 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1639 memcpy(temppixels, data, size);
1642 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1646 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1648 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1651 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1653 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1657 texinfo = R_GetTexTypeInfo(textype, flags);
1658 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1661 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1665 // clear the alpha flag if the texture has no transparent pixels
1668 case TEXTYPE_PALETTE:
1669 case TEXTYPE_SRGB_PALETTE:
1670 if (flags & TEXF_ALPHA)
1672 flags &= ~TEXF_ALPHA;
1675 for (i = 0;i < size;i++)
1677 if (((unsigned char *)&palette[data[i]])[3] < 255)
1679 flags |= TEXF_ALPHA;
1688 case TEXTYPE_SRGB_RGBA:
1689 case TEXTYPE_SRGB_BGRA:
1690 if (flags & TEXF_ALPHA)
1692 flags &= ~TEXF_ALPHA;
1695 for (i = 3;i < size;i += 4)
1699 flags |= TEXF_ALPHA;
1706 case TEXTYPE_SHADOWMAP16_COMP:
1707 case TEXTYPE_SHADOWMAP16_RAW:
1708 case TEXTYPE_SHADOWMAP24_COMP:
1709 case TEXTYPE_SHADOWMAP24_RAW:
1712 case TEXTYPE_SRGB_DXT1:
1715 case TEXTYPE_SRGB_DXT1A:
1717 case TEXTYPE_SRGB_DXT3:
1719 case TEXTYPE_SRGB_DXT5:
1720 flags |= TEXF_ALPHA;
1723 flags |= TEXF_ALPHA;
1725 case TEXTYPE_COLORBUFFER:
1726 case TEXTYPE_COLORBUFFER16F:
1727 case TEXTYPE_COLORBUFFER32F:
1728 flags |= TEXF_ALPHA;
1731 Sys_Error("R_LoadTexture: unknown texture type");
1734 texinfo2 = R_GetTexTypeInfo(textype, flags);
1735 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1738 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1740 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1742 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1744 glt->chain = pool->gltchain;
1745 pool->gltchain = glt;
1746 glt->inputwidth = width;
1747 glt->inputheight = height;
1748 glt->inputdepth = depth;
1750 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
1751 glt->textype = texinfo;
1752 glt->texturetype = texturetype;
1753 glt->inputdatasize = size;
1754 glt->palette = palette;
1755 glt->glinternalformat = texinfo->glinternalformat;
1756 glt->glformat = texinfo->glformat;
1757 glt->gltype = texinfo->gltype;
1758 glt->bytesperpixel = texinfo->internalbytesperpixel;
1759 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1762 glt->glisdepthstencil = false;
1763 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1764 // init the dynamic texture attributes, too [11/22/2007 Black]
1765 glt->updatecallback = NULL;
1766 glt->updatacallback_data = NULL;
1768 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1770 // upload the texture
1771 // data may be NULL (blank texture for dynamic rendering)
1772 switch(vid.renderpath)
1774 case RENDERPATH_GL11:
1775 case RENDERPATH_GL13:
1776 case RENDERPATH_GL20:
1777 case RENDERPATH_GLES1:
1778 case RENDERPATH_GLES2:
1780 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1782 case RENDERPATH_D3D9:
1785 D3DFORMAT d3dformat;
1790 d3dpool = D3DPOOL_MANAGED;
1791 if (flags & TEXF_RENDERTARGET)
1793 d3dusage |= D3DUSAGE_RENDERTARGET;
1794 d3dpool = D3DPOOL_DEFAULT;
1798 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1799 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1800 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1801 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
1802 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
1803 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
1804 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1805 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1807 glt->d3dformat = d3dformat;
1808 glt->d3dusage = d3dusage;
1809 glt->d3dpool = d3dpool;
1810 glt->d3disrendertargetsurface = false;
1811 glt->d3disdepthstencilsurface = false;
1812 if (glt->tiledepth > 1)
1814 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)))
1815 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1817 else if (glt->sides == 6)
1819 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1820 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1824 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)))
1825 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1830 case RENDERPATH_D3D10:
1831 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1833 case RENDERPATH_D3D11:
1834 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1836 case RENDERPATH_SOFT:
1841 case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1842 case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1843 case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1844 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1845 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
1846 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
1847 case TEXTYPE_SHADOWMAP16_COMP:
1848 case TEXTYPE_SHADOWMAP16_RAW:
1849 case TEXTYPE_SHADOWMAP24_COMP:
1850 case TEXTYPE_SHADOWMAP24_RAW: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1851 case TEXTYPE_DEPTHBUFFER16:
1852 case TEXTYPE_DEPTHBUFFER24:
1853 case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1854 case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1855 default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1857 if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1858 if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1859 if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1860 if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1861 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1866 R_UploadFullTexture(glt, data);
1867 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1868 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1870 // free any temporary processing buffer we allocated...
1872 Mem_Free(temppixels);
1874 // texture converting and uploading can take a while, so make sure we're sending keepalives
1875 // FIXME: this causes rendering during R_Shadow_DrawLights
1876 // CL_KeepaliveMessage(false);
1878 return (rtexture_t *)glt;
1881 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)
1883 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1886 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)
1888 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1891 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)
1893 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1896 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter)
1898 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL);
1901 rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
1904 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1905 textypeinfo_t *texinfo;
1907 if (cls.state == ca_dedicated)
1910 texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP);
1912 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1914 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1916 glt->chain = pool->gltchain;
1917 pool->gltchain = glt;
1918 glt->inputwidth = width;
1919 glt->inputheight = height;
1920 glt->inputdepth = 1;
1921 glt->flags = TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_FORCENEAREST;
1923 glt->textype = texinfo;
1924 glt->texturetype = textype;
1925 glt->inputdatasize = width*height*texinfo->internalbytesperpixel;
1926 glt->palette = NULL;
1927 glt->glinternalformat = texinfo->glinternalformat;
1928 glt->glformat = texinfo->glformat;
1929 glt->gltype = texinfo->gltype;
1930 glt->bytesperpixel = texinfo->internalbytesperpixel;
1931 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1934 glt->glisdepthstencil = glt->texturetype == TEXTYPE_DEPTHBUFFER24STENCIL8;
1935 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1936 // init the dynamic texture attributes, too [11/22/2007 Black]
1937 glt->updatecallback = NULL;
1938 glt->updatacallback_data = NULL;
1940 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1942 // upload the texture
1943 // data may be NULL (blank texture for dynamic rendering)
1944 switch(vid.renderpath)
1946 case RENDERPATH_GL11:
1947 case RENDERPATH_GL13:
1948 case RENDERPATH_GL20:
1949 case RENDERPATH_GLES1:
1950 case RENDERPATH_GLES2:
1952 qglGenRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
1953 qglBindRenderbuffer(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR
1954 qglRenderbufferStorage(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR
1955 // 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
1956 qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR
1958 case RENDERPATH_D3D9:
1961 D3DFORMAT d3dformat;
1963 glt->d3disrendertargetsurface = false;
1964 glt->d3disdepthstencilsurface = false;
1967 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;glt->d3disrendertargetsurface = true;break;
1968 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;glt->d3disrendertargetsurface = true;break;
1969 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;glt->d3disrendertargetsurface = true;break;
1970 case TEXTYPE_DEPTHBUFFER16: d3dformat = D3DFMT_D16;glt->d3disdepthstencilsurface = true;break;
1971 case TEXTYPE_DEPTHBUFFER24: d3dformat = D3DFMT_D24X8;glt->d3disdepthstencilsurface = true;break;
1972 case TEXTYPE_DEPTHBUFFER24STENCIL8: d3dformat = D3DFMT_D24S8;glt->d3disdepthstencilsurface = true;break;
1973 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1975 glt->d3dformat = d3dformat;
1978 if (glt->d3disrendertargetsurface)
1980 if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
1981 Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!");
1983 else if (glt->d3disdepthstencilsurface)
1985 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
1986 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
1991 case RENDERPATH_D3D10:
1992 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1994 case RENDERPATH_D3D11:
1995 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1997 case RENDERPATH_SOFT:
2002 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8 | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2003 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2004 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2005 case TEXTYPE_DEPTHBUFFER16:
2006 case TEXTYPE_DEPTHBUFFER24:
2007 case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2008 default: Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
2010 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
2015 return (rtexture_t *)glt;
2018 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
2021 return -1; // unsupported on this platform
2023 gltexture_t *glt = (gltexture_t *)rt;
2026 int bytesperpixel = 0;
2027 int bytesperblock = 0;
2029 int dds_format_flags;
2037 GLint internalformat;
2038 const char *ddsfourcc;
2040 return -1; // NULL pointer
2041 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
2042 return -2; // broken driver - crashes on reading internal format
2043 if (!qglGetTexLevelParameteriv)
2045 GL_ActiveTexture(0);
2046 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2047 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2048 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
2049 switch(internalformat)
2051 default: ddsfourcc = NULL;bytesperpixel = 4;break;
2052 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
2053 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
2054 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
2055 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
2057 // if premultiplied alpha, say so in the DDS file
2058 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
2060 switch(internalformat)
2062 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
2063 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
2066 if (!bytesperblock && skipuncompressed)
2067 return -3; // skipped
2068 memset(mipinfo, 0, sizeof(mipinfo));
2069 mipinfo[0][0] = glt->tilewidth;
2070 mipinfo[0][1] = glt->tileheight;
2072 if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tilewidth == 1))
2074 for (mip = 1;mip < 16;mip++)
2076 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
2077 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
2078 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
2086 for (mip = 0;mip < mipmaps;mip++)
2088 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
2089 mipinfo[mip][3] = ddssize;
2090 ddssize += mipinfo[mip][2];
2092 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
2095 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
2099 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
2100 dds_format_flags = 0x4; // DDPF_FOURCC
2104 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
2105 dds_format_flags = 0x40; // DDPF_RGB
2109 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
2110 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
2113 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
2114 memcpy(dds, "DDS ", 4);
2115 StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
2116 StoreLittleLong(dds+8, dds_flags);
2117 StoreLittleLong(dds+12, mipinfo[0][1]); // height
2118 StoreLittleLong(dds+16, mipinfo[0][0]); // width
2119 StoreLittleLong(dds+24, 0); // depth
2120 StoreLittleLong(dds+28, mipmaps); // mipmaps
2121 StoreLittleLong(dds+76, 32); // format size
2122 StoreLittleLong(dds+80, dds_format_flags);
2123 StoreLittleLong(dds+108, dds_caps1);
2124 StoreLittleLong(dds+112, dds_caps2);
2127 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
2128 memcpy(dds+84, ddsfourcc, 4);
2129 for (mip = 0;mip < mipmaps;mip++)
2131 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
2136 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
2137 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
2138 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
2139 for (mip = 0;mip < mipmaps;mip++)
2141 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
2144 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2145 ret = FS_WriteFile(filename, dds, ddssize);
2147 return ret ? ddssize : -5;
2151 rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qboolean srgb, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel, qboolean optionaltexture) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint
2153 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
2156 int bytesperblock, bytesperpixel;
2159 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
2160 textypeinfo_t *texinfo;
2161 int mip, mipwidth, mipheight, mipsize, mipsize_total;
2162 unsigned int c, r, g, b;
2163 GLint oldbindtexnum = 0;
2164 unsigned char *mippixels;
2165 unsigned char *mippixels_start;
2166 unsigned char *ddspixels;
2168 fs_offset_t ddsfilesize;
2169 unsigned int ddssize;
2170 qboolean force_swdecode, npothack;
2172 if (cls.state == ca_dedicated)
2175 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
2176 ddssize = ddsfilesize;
2180 if (r_texture_dds_load_logfailure.integer && (r_texture_dds_load_logfailure.integer >= 2 || !optionaltexture))
2181 Log_Printf("ddstexturefailures.log", "%s\n", filename);
2182 return NULL; // not found
2185 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
2188 Con_Printf("^1%s: not a DDS image\n", filename);
2192 //dds_flags = BuffLittleLong(dds+8);
2193 dds_format_flags = BuffLittleLong(dds+80);
2194 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
2195 dds_width = BuffLittleLong(dds+16);
2196 dds_height = BuffLittleLong(dds+12);
2197 ddspixels = dds + 128;
2199 if(r_texture_dds_load_alphamode.integer == 0)
2200 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
2201 flags &= ~TEXF_ALPHA;
2203 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
2204 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
2206 // very sloppy BGRA 32bit identification
2207 textype = TEXTYPE_BGRA;
2208 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2211 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
2212 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2215 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
2218 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
2221 for (i = 3;i < size;i += 4)
2222 if (ddspixels[i] < 255)
2225 flags &= ~TEXF_ALPHA;
2228 else if (!memcmp(dds+84, "DXT1", 4))
2230 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
2231 // LordHavoc: it is my belief that this does not infringe on the
2232 // patent because it is not decoding pixels...
2233 textype = TEXTYPE_DXT1;
2236 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
2237 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2238 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2241 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
2244 if (flags & TEXF_ALPHA)
2246 if (r_texture_dds_load_alphamode.integer == 1)
2249 for (i = 0;i < size;i += bytesperblock)
2250 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
2252 // NOTE: this assumes sizeof(unsigned int) == 4
2253 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
2254 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
2255 if(data & (data<<1) & 0xAAAAAAAA)//rgh
2259 textype = TEXTYPE_DXT1A;
2261 flags &= ~TEXF_ALPHA;
2263 else if (r_texture_dds_load_alphamode.integer == 0)
2264 textype = TEXTYPE_DXT1A;
2267 flags &= ~TEXF_ALPHA;
2271 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2273 if(!memcmp(dds+84, "DXT2", 4))
2275 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2277 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2282 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2284 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2287 textype = TEXTYPE_DXT3;
2290 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2291 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2294 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2297 // we currently always assume alpha
2299 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2301 if(!memcmp(dds+84, "DXT4", 4))
2303 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2305 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2310 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2312 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2315 textype = TEXTYPE_DXT5;
2318 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2319 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2322 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2325 // we currently always assume alpha
2330 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2334 // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
2335 if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
2337 textype = TEXTYPE_DXT1;
2341 for (i = 0;i < (int)ddssize;i += bytesperblock)
2342 memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
2346 force_swdecode = false;
2348 (!vid.support.arb_texture_non_power_of_two &&
2350 (dds_width & (dds_width - 1))
2352 (dds_height & (dds_height - 1))
2357 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && !npothack)
2359 if(r_texture_dds_swdecode.integer > 1)
2360 force_swdecode = true;
2364 if(r_texture_dds_swdecode.integer < 1)
2370 force_swdecode = true;
2374 // return whether this texture is transparent
2376 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2378 // if we SW decode, choose 2 sizes bigger
2381 // this is quarter res, so do not scale down more than we have to
2385 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2388 // this is where we apply gl_picmip
2389 mippixels_start = ddspixels;
2390 mipwidth = dds_width;
2391 mipheight = dds_height;
2392 while(miplevel >= 1 && dds_miplevels >= 1)
2394 if (mipwidth <= 1 && mipheight <= 1)
2396 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2397 mippixels_start += mipsize; // just skip
2405 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2406 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2408 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2410 // fake decode S3TC if needed
2413 int mipsize_new = mipsize_total / bytesperblock * 4;
2414 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2415 unsigned char *p = mipnewpixels;
2416 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2418 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2419 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2420 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2421 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2422 if(textype == TEXTYPE_DXT5)
2423 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2424 else if(textype == TEXTYPE_DXT3)
2426 (mippixels_start[i-8] & 0x0F)
2427 + (mippixels_start[i-8] >> 4)
2428 + (mippixels_start[i-7] & 0x0F)
2429 + (mippixels_start[i-7] >> 4)
2430 + (mippixels_start[i-6] & 0x0F)
2431 + (mippixels_start[i-6] >> 4)
2432 + (mippixels_start[i-5] & 0x0F)
2433 + (mippixels_start[i-5] >> 4)
2434 ) * (0.125f / 15.0f * 255.0f);
2439 textype = TEXTYPE_BGRA;
2443 // as each block becomes a pixel, we must use pixel count for this
2444 mipwidth = (mipwidth + 3) / 4;
2445 mipheight = (mipheight + 3) / 4;
2446 mipsize = bytesperpixel * mipwidth * mipheight;
2447 mippixels_start = mipnewpixels;
2448 mipsize_total = mipsize_new;
2451 // start mip counting
2452 mippixels = mippixels_start;
2454 // calculate average color if requested
2458 Vector4Clear(avgcolor);
2461 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2463 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2464 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2465 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2466 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2467 if(textype == TEXTYPE_DXT5)
2468 avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f);
2469 else if(textype == TEXTYPE_DXT3)
2471 (mippixels_start[i-8] & 0x0F)
2472 + (mippixels_start[i-8] >> 4)
2473 + (mippixels_start[i-7] & 0x0F)
2474 + (mippixels_start[i-7] >> 4)
2475 + (mippixels_start[i-6] & 0x0F)
2476 + (mippixels_start[i-6] >> 4)
2477 + (mippixels_start[i-5] & 0x0F)
2478 + (mippixels_start[i-5] >> 4)
2479 ) * (0.125f / 15.0f);
2481 avgcolor[3] += 1.0f;
2483 f = (float)bytesperblock / mipsize;
2484 avgcolor[0] *= (0.5f / 31.0f) * f;
2485 avgcolor[1] *= (0.5f / 63.0f) * f;
2486 avgcolor[2] *= (0.5f / 31.0f) * f;
2491 for (i = 0;i < mipsize;i += 4)
2493 avgcolor[0] += mippixels[i+2];
2494 avgcolor[1] += mippixels[i+1];
2495 avgcolor[2] += mippixels[i];
2496 avgcolor[3] += mippixels[i+3];
2498 f = (1.0f / 255.0f) * bytesperpixel / mipsize;
2506 // if we want sRGB, convert now
2509 if (vid.support.ext_texture_srgb)
2513 case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break;
2514 case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break;
2515 case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break;
2516 case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break;
2517 case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break;
2531 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2533 int c0, c1, c0new, c1new;
2534 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2535 r = ((c0 >> 11) & 0x1F);
2536 g = ((c0 >> 5) & 0x3F);
2538 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2539 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2540 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2541 c0new = (r << 11) | (g << 5) | b;
2542 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2543 r = ((c1 >> 11) & 0x1F);
2544 g = ((c1 >> 5) & 0x3F);
2546 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2547 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2548 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2549 c1new = (r << 11) | (g << 5) | b;
2550 // swap the colors if needed to fix order
2551 if(c0 > c1) // thirds
2559 mippixels_start[i+4] ^= 0x55;
2560 mippixels_start[i+5] ^= 0x55;
2561 mippixels_start[i+6] ^= 0x55;
2562 mippixels_start[i+7] ^= 0x55;
2564 else if(c0new == c1new)
2566 mippixels_start[i+4] = 0x00;
2567 mippixels_start[i+5] = 0x00;
2568 mippixels_start[i+6] = 0x00;
2569 mippixels_start[i+7] = 0x00;
2572 else // half + transparent
2579 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2580 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2581 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2582 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2585 mippixels_start[i] = c0new & 255;
2586 mippixels_start[i+1] = c0new >> 8;
2587 mippixels_start[i+2] = c1new & 255;
2588 mippixels_start[i+3] = c1new >> 8;
2593 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2601 // when not requesting mipmaps, do not load them
2602 if(!(flags & TEXF_MIPMAP))
2605 if (dds_miplevels >= 1)
2606 flags |= TEXF_MIPMAP;
2608 flags &= ~TEXF_MIPMAP;
2610 texinfo = R_GetTexTypeInfo(textype, flags);
2612 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2613 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2615 glt->chain = pool->gltchain;
2616 pool->gltchain = glt;
2617 glt->inputwidth = mipwidth;
2618 glt->inputheight = mipheight;
2619 glt->inputdepth = 1;
2621 glt->textype = texinfo;
2622 glt->texturetype = GLTEXTURETYPE_2D;
2623 glt->inputdatasize = ddssize;
2624 glt->glinternalformat = texinfo->glinternalformat;
2625 glt->glformat = texinfo->glformat;
2626 glt->gltype = texinfo->gltype;
2627 glt->bytesperpixel = texinfo->internalbytesperpixel;
2629 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2630 glt->tilewidth = mipwidth;
2631 glt->tileheight = mipheight;
2633 glt->miplevels = dds_miplevels;
2637 for (glt->tilewidth = 1;glt->tilewidth < mipwidth;glt->tilewidth <<= 1);
2638 for (glt->tileheight = 1;glt->tileheight < mipheight;glt->tileheight <<= 1);
2641 // texture uploading can take a while, so make sure we're sending keepalives
2642 CL_KeepaliveMessage(false);
2644 // create the texture object
2645 switch(vid.renderpath)
2647 case RENDERPATH_GL11:
2648 case RENDERPATH_GL13:
2649 case RENDERPATH_GL20:
2650 case RENDERPATH_GLES1:
2651 case RENDERPATH_GLES2:
2653 GL_ActiveTexture(0);
2654 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2655 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2656 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2658 case RENDERPATH_D3D9:
2661 D3DFORMAT d3dformat;
2666 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2667 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2668 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2669 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2670 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2673 d3dpool = D3DPOOL_MANAGED;
2674 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2678 case RENDERPATH_D3D10:
2679 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2681 case RENDERPATH_D3D11:
2682 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2684 case RENDERPATH_SOFT:
2685 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);
2689 // upload the texture
2690 // we need to restore the texture binding after finishing the upload
2691 mipcomplete = false;
2693 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2695 unsigned char *upload_mippixels = mippixels;
2696 int upload_mipwidth = mipwidth;
2697 int upload_mipheight = mipheight;
2698 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2699 if (mippixels + mipsize > mippixels_start + mipsize_total)
2703 upload_mipwidth = (glt->tilewidth >> mip);
2704 upload_mipheight = (glt->tileheight >> mip);
2705 if(upload_mipwidth != mipwidth || upload_mipheight != mipheight)
2706 // I _think_ they always mismatch, but I was too lazy
2707 // to properly check, and this test here is really
2710 upload_mippixels = (unsigned char *) Mem_Alloc(tempmempool, 4 * upload_mipwidth * upload_mipheight);
2711 Image_Resample32(mippixels, mipwidth, mipheight, 1, upload_mippixels, upload_mipwidth, upload_mipheight, 1, r_lerpimages.integer);
2714 switch(vid.renderpath)
2716 case RENDERPATH_GL11:
2717 case RENDERPATH_GL13:
2718 case RENDERPATH_GL20:
2719 case RENDERPATH_GLES1:
2720 case RENDERPATH_GLES2:
2723 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR
2727 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR
2730 case RENDERPATH_D3D9:
2733 D3DLOCKED_RECT d3dlockedrect;
2734 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2736 memcpy(d3dlockedrect.pBits, upload_mippixels, mipsize);
2737 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2743 case RENDERPATH_D3D10:
2744 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2746 case RENDERPATH_D3D11:
2747 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2749 case RENDERPATH_SOFT:
2751 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2753 DPSOFTRAST_Texture_UpdateFull(glt->texnum, upload_mippixels);
2754 // DPSOFTRAST calculates its own mipmaps
2755 mip = dds_miplevels;
2758 if(upload_mippixels != mippixels)
2759 Mem_Free(upload_mippixels);
2760 mippixels += mipsize;
2761 if (mipwidth <= 1 && mipheight <= 1)
2772 // after upload we have to set some parameters...
2773 switch(vid.renderpath)
2775 case RENDERPATH_GL11:
2776 case RENDERPATH_GL13:
2777 case RENDERPATH_GL20:
2778 case RENDERPATH_GLES1:
2779 case RENDERPATH_GLES2:
2780 #ifdef GL_TEXTURE_MAX_LEVEL
2781 if (dds_miplevels >= 1 && !mipcomplete)
2783 // need to set GL_TEXTURE_MAX_LEVEL
2784 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2787 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2788 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2790 case RENDERPATH_D3D9:
2792 glt->d3daddressw = 0;
2793 if (glt->flags & TEXF_CLAMP)
2795 glt->d3daddressu = D3DTADDRESS_CLAMP;
2796 glt->d3daddressv = D3DTADDRESS_CLAMP;
2797 if (glt->tiledepth > 1)
2798 glt->d3daddressw = D3DTADDRESS_CLAMP;
2802 glt->d3daddressu = D3DTADDRESS_WRAP;
2803 glt->d3daddressv = D3DTADDRESS_WRAP;
2804 if (glt->tiledepth > 1)
2805 glt->d3daddressw = D3DTADDRESS_WRAP;
2807 glt->d3dmipmaplodbias = 0;
2808 glt->d3dmaxmiplevel = 0;
2809 glt->d3dmaxmiplevelfilter = 0;
2810 if (glt->flags & TEXF_MIPMAP)
2812 glt->d3dminfilter = d3d_filter_mipmin;
2813 glt->d3dmagfilter = d3d_filter_mipmag;
2814 glt->d3dmipfilter = d3d_filter_mipmix;
2818 glt->d3dminfilter = d3d_filter_flatmin;
2819 glt->d3dmagfilter = d3d_filter_flatmag;
2820 glt->d3dmipfilter = d3d_filter_flatmix;
2824 case RENDERPATH_D3D10:
2825 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2827 case RENDERPATH_D3D11:
2828 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2830 case RENDERPATH_SOFT:
2831 if (glt->flags & TEXF_FORCELINEAR)
2832 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
2833 else if (glt->flags & TEXF_FORCENEAREST)
2834 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
2835 else if (glt->flags & TEXF_MIPMAP)
2836 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
2838 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
2844 Mem_Free((unsigned char *) mippixels_start);
2845 return (rtexture_t *)glt;
2848 int R_TextureWidth(rtexture_t *rt)
2850 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2853 int R_TextureHeight(rtexture_t *rt)
2855 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2858 int R_TextureFlags(rtexture_t *rt)
2860 return rt ? ((gltexture_t *)rt)->flags : 0;
2863 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2865 gltexture_t *glt = (gltexture_t *)rt;
2867 Host_Error("R_UpdateTexture: no data supplied");
2869 Host_Error("R_UpdateTexture: no texture supplied");
2870 if (!glt->texnum && !glt->d3dtexture)
2872 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2875 // update part of the texture
2876 if (glt->bufferpixels)
2879 int bpp = glt->bytesperpixel;
2880 int inputskip = width*bpp;
2881 int outputskip = glt->tilewidth*bpp;
2882 const unsigned char *input = data;
2883 unsigned char *output = glt->bufferpixels;
2884 if (glt->inputdepth != 1 || glt->sides != 1)
2885 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2895 input -= y*inputskip;
2898 if (width > glt->tilewidth - x)
2899 width = glt->tilewidth - x;
2900 if (height > glt->tileheight - y)
2901 height = glt->tileheight - y;
2902 if (width < 1 || height < 1)
2905 glt->buffermodified = true;
2906 output += y*outputskip + x*bpp;
2907 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2908 memcpy(output, input, width*bpp);
2910 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2911 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2913 R_UploadFullTexture(glt, data);
2916 int R_RealGetTexture(rtexture_t *rt)
2921 glt = (gltexture_t *)rt;
2922 if (glt->flags & GLTEXF_DYNAMIC)
2923 R_UpdateDynamicTexture(glt);
2924 if (glt->buffermodified && glt->bufferpixels)
2926 glt->buffermodified = false;
2927 R_UploadFullTexture(glt, glt->bufferpixels);
2936 void R_ClearTexture (rtexture_t *rt)
2938 gltexture_t *glt = (gltexture_t *)rt;
2940 R_UploadFullTexture(glt, NULL);
2943 int R_PicmipForFlags(int flags)
2946 if(flags & TEXF_PICMIP)
2948 miplevel += gl_picmip.integer;
2949 if (flags & TEXF_ISWORLD)
2951 if (r_picmipworld.integer)
2952 miplevel += gl_picmip_world.integer;
2956 else if (flags & TEXF_ISSPRITE)
2958 if (r_picmipsprites.integer)
2959 miplevel += gl_picmip_sprites.integer;
2964 miplevel += gl_picmip_other.integer;
2966 return max(0, miplevel);