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;
85 // we use these internally even if we never deliver such data to the driver
87 #define GL_BGRA 0x80E1
89 // framebuffer texture formats
90 // GLES2 devices rarely support depth textures, so we actually use a renderbuffer there
91 static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
92 static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
93 static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
94 static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
95 static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
96 static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
97 static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
98 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 2, 2, 2.0f, GL_RGB565 , GL_RGBA , GL_UNSIGNED_SHORT_5_6_5};
99 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 2, 2, 2.0f, GL_RGBA16F , GL_RGBA , GL_HALF_FLOAT_ARB};
100 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 2, 2, 2.0f, GL_RGBA32F , GL_RGBA , GL_FLOAT};
103 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
104 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
105 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
106 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
107 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
108 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
109 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
111 static textypeinfo_t textype_etc1 = {"etc1", TEXTYPE_ETC1 , 1, 3, 0.5f, GL_ETC1_RGB8_OES , 0 , 0 };
114 // framebuffer texture formats
115 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};
116 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};
117 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 };
118 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 };
119 static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
120 static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
121 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};
122 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
123 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 8, 8, 8.0f, GL_RGBA16F_ARB , GL_RGBA , GL_HALF_FLOAT_ARB};
124 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 16, 16, 16.0f, GL_RGBA32F_ARB , GL_RGBA , GL_FLOAT };
127 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
128 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
129 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
130 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE };
131 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
132 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 };
133 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 };
134 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
135 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
136 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 };
137 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 };
138 static textypeinfo_t textype_dxt1 = {"dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
139 static textypeinfo_t textype_dxt1a = {"dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 };
140 static textypeinfo_t textype_dxt3 = {"dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 };
141 static textypeinfo_t textype_dxt5 = {"dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 };
142 static textypeinfo_t textype_sRGB_palette = {"sRGB_palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
143 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 };
144 static textypeinfo_t textype_sRGB_rgba = {"sRGB_rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
145 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 };
146 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 };
147 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 };
148 static textypeinfo_t textype_sRGB_bgra = {"sRGB_bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
149 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 };
150 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 };
151 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 };
152 static textypeinfo_t textype_sRGB_dxt1 = {"sRGB_dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , 0 , 0 };
153 static textypeinfo_t textype_sRGB_dxt1a = {"sRGB_dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 , 0 };
154 static textypeinfo_t textype_sRGB_dxt3 = {"sRGB_dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 , 0 };
155 static textypeinfo_t textype_sRGB_dxt5 = {"sRGB_dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 , 0 };
158 typedef enum gltexturetype_e
162 GLTEXTURETYPE_CUBEMAP,
167 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP};
168 #ifdef GL_TEXTURE_WRAP_R
169 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
171 static int cubemapside[6] =
173 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
174 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
175 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
176 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
177 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
178 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
181 typedef struct gltexture_s
183 // this portion of the struct is exposed to the R_GetTexture macro for
184 // speed reasons, must be identical in rtexture_t!
185 int texnum; // GL texture slot number
186 int renderbuffernum; // GL renderbuffer slot number
187 qboolean dirty; // indicates that R_RealGetTexture should be called
188 qboolean glisdepthstencil; // indicates that FBO attachment has to be GL_DEPTH_STENCIL_ATTACHMENT
189 int gltexturetypeenum; // used by R_Mesh_TexBind
190 // d3d stuff the backend needs
194 qboolean d3disrendertargetsurface;
195 qboolean d3disdepthstencilsurface;
205 int d3dmaxmiplevelfilter;
206 int d3dmipmaplodbias;
210 // dynamic texture stuff [11/22/2007 Black]
211 updatecallback_t updatecallback;
212 void *updatecallback_data;
213 // --- [11/22/2007 Black]
215 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
216 unsigned char *bufferpixels;
217 qboolean buffermodified;
219 // pointer to texturepool (check this to see if the texture is allocated)
220 struct gltexturepool_s *pool;
221 // pointer to next texture in texturepool chain
222 struct gltexture_s *chain;
223 // name of the texture (this might be removed someday), no duplicates
224 char identifier[MAX_QPATH + 32];
225 // original data size in *inputtexels
226 int inputwidth, inputheight, inputdepth;
227 // copy of the original texture(s) supplied to the upload function, for
228 // delayed uploads (non-precached)
229 unsigned char *inputtexels;
230 // original data size in *inputtexels
232 // flags supplied to the LoadTexture function
233 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
237 // pointer to one of the textype_ structs
238 textypeinfo_t *textype;
239 // one of the GLTEXTURETYPE_ values
241 // palette if the texture is TEXTYPE_PALETTE
242 const unsigned int *palette;
243 // actual stored texture size after gl_picmip and gl_max_size are applied
244 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
245 int tilewidth, tileheight, tiledepth;
246 // 1 or 6 depending on texturetype
248 // how many mipmap levels in this texture
252 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
255 int glinternalformat;
256 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
261 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
263 typedef struct gltexturepool_s
265 unsigned int sentinel;
266 struct gltexture_s *gltchain;
267 struct gltexturepool_s *next;
271 static gltexturepool_t *gltexturepoolchain = NULL;
273 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
274 static int resizebuffersize = 0;
275 static const unsigned char *texturebuffer;
277 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
282 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
283 case TEXTYPE_RGBA: return ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba);
284 case TEXTYPE_BGRA: return ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra);
286 case TEXTYPE_ETC1: return &textype_etc1;
288 case TEXTYPE_ALPHA: return &textype_alpha;
289 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
290 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
291 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
292 case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
293 case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
294 case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
295 case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
296 case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
297 case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
298 case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
300 case TEXTYPE_DXT1: return &textype_dxt1;
301 case TEXTYPE_DXT1A: return &textype_dxt1a;
302 case TEXTYPE_DXT3: return &textype_dxt3;
303 case TEXTYPE_DXT5: return &textype_dxt5;
304 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
305 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);
306 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);
307 case TEXTYPE_ALPHA: return &textype_alpha;
308 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
309 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
310 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
311 case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
312 case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
313 case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
314 case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
315 case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
316 case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
317 case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
318 case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1;
319 case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a;
320 case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
321 case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
322 case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
323 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);
324 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);
327 Host_Error("R_GetTexTypeInfo: unknown texture format %i with flags %x", (int)textype, flags);
333 // dynamic texture code [11/22/2007 Black]
334 void R_MarkDirtyTexture(rtexture_t *rt) {
335 gltexture_t *glt = (gltexture_t*) rt;
340 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
341 if (glt->flags & GLTEXF_DYNAMIC)
343 // mark it as dirty, so R_RealGetTexture gets called
348 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
349 gltexture_t *glt = (gltexture_t*) rt;
354 glt->flags |= GLTEXF_DYNAMIC;
355 glt->updatecallback = updatecallback;
356 glt->updatecallback_data = data;
359 static void R_UpdateDynamicTexture(gltexture_t *glt) {
361 if( glt->updatecallback ) {
362 glt->updatecallback( (rtexture_t*) glt, glt->updatecallback_data );
366 void R_PurgeTexture(rtexture_t *rt)
368 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
373 void R_FreeTexture(rtexture_t *rt)
375 gltexture_t *glt, **gltpointer;
377 glt = (gltexture_t *)rt;
379 Host_Error("R_FreeTexture: texture == NULL");
381 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
382 if (*gltpointer == glt)
383 *gltpointer = glt->chain;
385 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
387 R_Mesh_ClearBindingsForTexture(glt->texnum);
389 switch(vid.renderpath)
391 case RENDERPATH_GL11:
392 case RENDERPATH_GL13:
393 case RENDERPATH_GL20:
394 case RENDERPATH_GLES1:
395 case RENDERPATH_GLES2:
399 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
401 if (glt->renderbuffernum)
404 qglDeleteRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
407 case RENDERPATH_D3D9:
410 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dsurface);
411 else if (glt->tiledepth > 1)
412 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
413 else if (glt->sides == 6)
414 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
416 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
417 glt->d3dtexture = NULL;
418 glt->d3dsurface = NULL;
421 case RENDERPATH_D3D10:
422 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
424 case RENDERPATH_D3D11:
425 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
427 case RENDERPATH_SOFT:
429 DPSOFTRAST_Texture_Free(glt->texnum);
433 if (glt->inputtexels)
434 Mem_Free(glt->inputtexels);
435 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
438 rtexturepool_t *R_AllocTexturePool(void)
440 gltexturepool_t *pool;
441 if (texturemempool == NULL)
443 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
446 pool->next = gltexturepoolchain;
447 gltexturepoolchain = pool;
448 pool->sentinel = TEXTUREPOOL_SENTINEL;
449 return (rtexturepool_t *)pool;
452 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
454 gltexturepool_t *pool, **poolpointer;
455 if (rtexturepool == NULL)
457 if (*rtexturepool == NULL)
459 pool = (gltexturepool_t *)(*rtexturepool);
460 *rtexturepool = NULL;
461 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
462 Host_Error("R_FreeTexturePool: pool already freed");
463 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
464 if (*poolpointer == pool)
465 *poolpointer = pool->next;
467 Host_Error("R_FreeTexturePool: pool not linked");
468 while (pool->gltchain)
469 R_FreeTexture((rtexture_t *)pool->gltchain);
474 typedef struct glmode_s
477 int minification, magnification;
478 DPSOFTRAST_TEXTURE_FILTER dpsoftrastfilter_mipmap, dpsoftrastfilter_nomipmap;
482 static glmode_t modes[6] =
484 {"GL_NEAREST", GL_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
485 {"GL_LINEAR", GL_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
486 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
487 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
488 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
489 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR}
493 typedef struct d3dmode_s
500 static d3dmode_t d3dmodes[6] =
502 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
503 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
504 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
505 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
506 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
507 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
511 static void GL_TextureMode_f (void)
516 gltexturepool_t *pool;
520 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
521 for (i = 0;i < 6;i++)
523 if (gl_filter_min == modes[i].minification)
525 Con_Printf("%s\n", modes[i].name);
529 Con_Print("current filter is unknown???\n");
533 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
534 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
538 Con_Print("bad filter name\n");
542 gl_filter_min = modes[i].minification;
543 gl_filter_mag = modes[i].magnification;
544 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
546 dpsoftrast_filter_mipmap = modes[i].dpsoftrastfilter_mipmap;
547 dpsoftrast_filter_nomipmap = modes[i].dpsoftrastfilter_nomipmap;
549 switch(vid.renderpath)
551 case RENDERPATH_GL11:
552 case RENDERPATH_GL13:
553 case RENDERPATH_GL20:
554 case RENDERPATH_GLES1:
555 case RENDERPATH_GLES2:
556 // change all the existing mipmap texture objects
557 // FIXME: force renderer(/client/something?) restart instead?
560 for (pool = gltexturepoolchain;pool;pool = pool->next)
562 for (glt = pool->gltchain;glt;glt = glt->chain)
564 // only update already uploaded images
565 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
567 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
568 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
569 if (glt->flags & TEXF_MIPMAP)
571 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
575 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
577 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
578 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
583 case RENDERPATH_D3D9:
585 d3d_filter_flatmin = d3dmodes[i].m1;
586 d3d_filter_flatmag = d3dmodes[i].m1;
587 d3d_filter_flatmix = D3DTEXF_POINT;
588 d3d_filter_mipmin = d3dmodes[i].m1;
589 d3d_filter_mipmag = d3dmodes[i].m1;
590 d3d_filter_mipmix = d3dmodes[i].m2;
591 d3d_filter_nomip = i < 2;
592 if (gl_texture_anisotropy.integer > 1 && i == 5)
593 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
594 for (pool = gltexturepoolchain;pool;pool = pool->next)
596 for (glt = pool->gltchain;glt;glt = glt->chain)
598 // only update already uploaded images
599 if (glt->d3dtexture && !glt->d3dsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
601 if (glt->flags & TEXF_MIPMAP)
603 glt->d3dminfilter = d3d_filter_mipmin;
604 glt->d3dmagfilter = d3d_filter_mipmag;
605 glt->d3dmipfilter = d3d_filter_mipmix;
606 glt->d3dmaxmiplevelfilter = 0;
610 glt->d3dminfilter = d3d_filter_flatmin;
611 glt->d3dmagfilter = d3d_filter_flatmag;
612 glt->d3dmipfilter = d3d_filter_flatmix;
613 glt->d3dmaxmiplevelfilter = 0;
620 case RENDERPATH_D3D10:
621 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
623 case RENDERPATH_D3D11:
624 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
626 case RENDERPATH_SOFT:
627 // change all the existing texture objects
628 for (pool = gltexturepoolchain;pool;pool = pool->next)
629 for (glt = pool->gltchain;glt;glt = glt->chain)
630 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
631 DPSOFTRAST_Texture_Filter(glt->texnum, (glt->flags & TEXF_MIPMAP) ? dpsoftrast_filter_mipmap : dpsoftrast_filter_nomipmap);
636 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)
638 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
643 case GLTEXTURETYPE_2D:
644 maxsize = vid.maxtexturesize_2d;
645 if (flags & TEXF_PICMIP)
647 maxsize = bound(1, gl_max_size.integer, maxsize);
651 case GLTEXTURETYPE_3D:
652 maxsize = vid.maxtexturesize_3d;
654 case GLTEXTURETYPE_CUBEMAP:
655 maxsize = vid.maxtexturesize_cubemap;
659 if (vid.support.arb_texture_non_power_of_two)
661 width2 = min(inwidth >> picmip, maxsize);
662 height2 = min(inheight >> picmip, maxsize);
663 depth2 = min(indepth >> picmip, maxsize);
667 for (width2 = 1;width2 < inwidth;width2 <<= 1);
668 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
669 for (height2 = 1;height2 < inheight;height2 <<= 1);
670 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
671 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
672 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
675 switch(vid.renderpath)
677 case RENDERPATH_GL11:
678 case RENDERPATH_GL13:
679 case RENDERPATH_GL20:
680 case RENDERPATH_D3D10:
681 case RENDERPATH_D3D11:
682 case RENDERPATH_SOFT:
683 case RENDERPATH_GLES1:
684 case RENDERPATH_GLES2:
686 case RENDERPATH_D3D9:
688 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
689 if (texturetype == GLTEXTURETYPE_2D)
691 width2 = max(width2, 2);
692 height2 = max(height2, 2);
699 if (flags & TEXF_MIPMAP)
701 int extent = max(width2, max(height2, depth2));
707 *outwidth = max(1, width2);
709 *outheight = max(1, height2);
711 *outdepth = max(1, depth2);
713 *outmiplevels = miplevels;
717 static int R_CalcTexelDataSize (gltexture_t *glt)
719 int width2, height2, depth2, size;
721 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
723 size = width2 * height2 * depth2;
725 if (glt->flags & TEXF_MIPMAP)
727 while (width2 > 1 || height2 > 1 || depth2 > 1)
735 size += width2 * height2 * depth2;
739 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
742 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
746 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
747 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
749 gltexturepool_t *pool;
751 Con_Print("glsize input loaded mip alpha name\n");
752 for (pool = gltexturepoolchain;pool;pool = pool->next)
760 for (glt = pool->gltchain;glt;glt = glt->chain)
762 glsize = R_CalcTexelDataSize(glt);
763 isloaded = glt->texnum != 0 || glt->renderbuffernum != 0 || glt->d3dtexture || glt->d3dsurface;
765 pooltotalt += glsize;
766 pooltotalp += glt->inputdatasize;
770 poolloadedt += glsize;
771 poolloadedp += glt->inputdatasize;
774 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);
777 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);
778 sumtotal += pooltotal;
779 sumtotalt += pooltotalt;
780 sumtotalp += pooltotalp;
781 sumloaded += poolloaded;
782 sumloadedt += poolloadedt;
783 sumloadedp += poolloadedp;
786 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);
789 static void R_TextureStats_f(void)
791 R_TextureStats_Print(true, true, true);
794 static void r_textures_start(void)
796 switch(vid.renderpath)
798 case RENDERPATH_GL11:
799 case RENDERPATH_GL13:
800 case RENDERPATH_GL20:
801 case RENDERPATH_GLES1:
802 case RENDERPATH_GLES2:
803 // LordHavoc: allow any alignment
805 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
806 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
808 case RENDERPATH_D3D9:
810 case RENDERPATH_D3D10:
811 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
813 case RENDERPATH_D3D11:
814 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
816 case RENDERPATH_SOFT:
820 texturemempool = Mem_AllocPool("texture management", 0, NULL);
821 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
823 // Disable JPEG screenshots if the DLL isn't loaded
824 if (! JPEG_OpenLibrary ())
825 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
826 if (! PNG_OpenLibrary ())
827 Cvar_SetValueQuick (&scr_screenshot_png, 0);
830 static void r_textures_shutdown(void)
832 rtexturepool_t *temp;
834 JPEG_CloseLibrary ();
836 while(gltexturepoolchain)
838 temp = (rtexturepool_t *) gltexturepoolchain;
839 R_FreeTexturePool(&temp);
842 resizebuffersize = 0;
844 colorconvertbuffer = NULL;
845 texturebuffer = NULL;
846 Mem_ExpandableArray_FreeArray(&texturearray);
847 Mem_FreePool(&texturemempool);
850 static void r_textures_newmap(void)
854 static void r_textures_devicelost(void)
858 endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
859 for (i = 0;i < endindex;i++)
861 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
862 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
864 switch(vid.renderpath)
866 case RENDERPATH_GL11:
867 case RENDERPATH_GL13:
868 case RENDERPATH_GL20:
869 case RENDERPATH_GLES1:
870 case RENDERPATH_GLES2:
872 case RENDERPATH_D3D9:
875 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dsurface);
876 else if (glt->tiledepth > 1)
877 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
878 else if (glt->sides == 6)
879 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
881 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
882 glt->d3dtexture = NULL;
883 glt->d3dsurface = NULL;
886 case RENDERPATH_D3D10:
887 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
889 case RENDERPATH_D3D11:
890 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
892 case RENDERPATH_SOFT:
898 static void r_textures_devicerestored(void)
902 endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
903 for (i = 0;i < endindex;i++)
905 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
906 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
908 switch(vid.renderpath)
910 case RENDERPATH_GL11:
911 case RENDERPATH_GL13:
912 case RENDERPATH_GL20:
913 case RENDERPATH_GLES1:
914 case RENDERPATH_GLES2:
916 case RENDERPATH_D3D9:
920 if (glt->d3disrendertargetsurface)
922 if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
923 Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!");
925 else if (glt->d3disdepthstencilsurface)
927 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
928 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
930 else if (glt->tiledepth > 1)
932 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)))
933 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
935 else if (glt->sides == 6)
937 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
938 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
942 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)))
943 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
948 case RENDERPATH_D3D10:
949 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
951 case RENDERPATH_D3D11:
952 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
954 case RENDERPATH_SOFT:
961 void R_Textures_Init (void)
963 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");
964 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
965 Cvar_RegisterVariable (&gl_max_size);
966 Cvar_RegisterVariable (&gl_picmip);
967 Cvar_RegisterVariable (&gl_picmip_world);
968 Cvar_RegisterVariable (&r_picmipworld);
969 Cvar_RegisterVariable (&gl_picmip_sprites);
970 Cvar_RegisterVariable (&r_picmipsprites);
971 Cvar_RegisterVariable (&gl_picmip_other);
972 Cvar_RegisterVariable (&gl_max_lightmapsize);
973 Cvar_RegisterVariable (&r_lerpimages);
974 Cvar_RegisterVariable (&gl_texture_anisotropy);
975 Cvar_RegisterVariable (&gl_texturecompression);
976 Cvar_RegisterVariable (&gl_texturecompression_color);
977 Cvar_RegisterVariable (&gl_texturecompression_normal);
978 Cvar_RegisterVariable (&gl_texturecompression_gloss);
979 Cvar_RegisterVariable (&gl_texturecompression_glow);
980 Cvar_RegisterVariable (&gl_texturecompression_2d);
981 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
982 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
983 Cvar_RegisterVariable (&gl_texturecompression_sky);
984 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
985 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
986 Cvar_RegisterVariable (&gl_texturecompression_sprites);
987 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
988 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
989 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
990 Cvar_RegisterVariable (&r_texture_dds_swdecode);
992 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
995 void R_Textures_Frame (void)
997 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
998 static int old_aniso = 0;
999 static qboolean first_time_aniso = true;
1002 // could do procedural texture animation here, if we keep track of which
1003 // textures were accessed this frame...
1005 // free the resize buffers
1006 resizebuffersize = 0;
1009 Mem_Free(resizebuffer);
1010 resizebuffer = NULL;
1012 if (colorconvertbuffer)
1014 Mem_Free(colorconvertbuffer);
1015 colorconvertbuffer = NULL;
1018 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
1019 if (old_aniso != gl_texture_anisotropy.integer)
1022 gltexturepool_t *pool;
1023 GLint oldbindtexnum;
1025 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
1027 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
1029 switch(vid.renderpath)
1031 case RENDERPATH_GL11:
1032 case RENDERPATH_GL13:
1033 case RENDERPATH_GL20:
1034 case RENDERPATH_GLES1:
1035 case RENDERPATH_GLES2:
1036 // ignore the first difference, any textures loaded by now probably had the same aniso value
1037 if (first_time_aniso)
1039 first_time_aniso = false;
1043 GL_ActiveTexture(0);
1044 for (pool = gltexturepoolchain;pool;pool = pool->next)
1046 for (glt = pool->gltchain;glt;glt = glt->chain)
1048 // only update already uploaded images
1049 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
1051 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1053 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1054 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
1056 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1061 case RENDERPATH_D3D9:
1062 case RENDERPATH_D3D10:
1063 case RENDERPATH_D3D11:
1064 case RENDERPATH_SOFT:
1071 static void R_MakeResizeBufferBigger(int size)
1073 if (resizebuffersize < size)
1075 resizebuffersize = size;
1077 Mem_Free(resizebuffer);
1078 if (colorconvertbuffer)
1079 Mem_Free(colorconvertbuffer);
1080 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
1081 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
1082 if (!resizebuffer || !colorconvertbuffer)
1083 Host_Error("R_Upload: out of memory");
1087 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
1089 int textureenum = gltexturetypeenums[texturetype];
1090 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
1094 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
1095 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
1097 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
1098 if (gl_texture_anisotropy.integer != aniso)
1099 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
1100 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
1103 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
1104 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
1105 #ifdef GL_TEXTURE_WRAP_R
1106 if (gltexturetypedimensions[texturetype] >= 3)
1108 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
1113 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
1115 if (flags & TEXF_MIPMAP)
1117 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
1121 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
1123 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
1125 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
1127 if (flags & TEXF_MIPMAP)
1129 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
1131 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
1135 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
1140 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
1142 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
1146 if (flags & TEXF_MIPMAP)
1148 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1152 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1154 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1157 #ifdef GL_TEXTURE_COMPARE_MODE_ARB
1160 case TEXTYPE_SHADOWMAP16_COMP:
1161 case TEXTYPE_SHADOWMAP24_COMP:
1162 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1163 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1164 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1166 case TEXTYPE_SHADOWMAP16_RAW:
1167 case TEXTYPE_SHADOWMAP24_RAW:
1168 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1169 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1170 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1180 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1183 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1185 if (glt->texturetype != GLTEXTURETYPE_2D)
1186 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1188 if (glt->textype->textype == TEXTYPE_PALETTE)
1189 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1191 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1192 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1194 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1195 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1197 // update a portion of the image
1199 switch(vid.renderpath)
1201 case RENDERPATH_GL11:
1202 case RENDERPATH_GL13:
1203 case RENDERPATH_GL20:
1204 case RENDERPATH_GLES1:
1205 case RENDERPATH_GLES2:
1209 // we need to restore the texture binding after finishing the upload
1210 GL_ActiveTexture(0);
1211 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1212 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1213 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1214 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1217 case RENDERPATH_D3D9:
1221 D3DLOCKED_RECT d3dlockedrect;
1223 memset(&d3drect, 0, sizeof(d3drect));
1224 d3drect.left = fragx;
1225 d3drect.top = fragy;
1226 d3drect.right = fragx+fragwidth;
1227 d3drect.bottom = fragy+fragheight;
1228 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1230 for (y = 0;y < fragheight;y++)
1231 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1232 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1237 case RENDERPATH_D3D10:
1238 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1240 case RENDERPATH_D3D11:
1241 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1243 case RENDERPATH_SOFT:
1244 DPSOFTRAST_Texture_UpdatePartial(glt->texnum, 0, data, fragx, fragy, fragwidth, fragheight);
1249 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1251 int i, mip = 0, width, height, depth;
1252 GLint oldbindtexnum = 0;
1253 const unsigned char *prevbuffer;
1256 // error out if a stretch is needed on special texture types
1257 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1258 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1260 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1261 // of the target size and then use the mipmap reduction function to get
1262 // high quality supersampled results
1263 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1264 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1265 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1267 if (prevbuffer == NULL)
1269 width = glt->tilewidth;
1270 height = glt->tileheight;
1271 depth = glt->tiledepth;
1272 // R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1273 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1274 // prevbuffer = resizebuffer;
1278 if (glt->textype->textype == TEXTYPE_PALETTE)
1280 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1281 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1282 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1283 prevbuffer = colorconvertbuffer;
1285 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1287 // multiply RGB channels by A channel before uploading
1289 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1290 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1292 alpha = prevbuffer[i+3];
1293 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1294 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1295 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1296 colorconvertbuffer[i+3] = alpha;
1298 prevbuffer = colorconvertbuffer;
1300 // scale up to a power of 2 size (if appropriate)
1301 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1303 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1304 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1305 prevbuffer = resizebuffer;
1307 // apply mipmap reduction algorithm to get down to picmip/max_size
1308 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1310 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1311 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1312 prevbuffer = resizebuffer;
1316 // do the appropriate upload type...
1317 switch(vid.renderpath)
1319 case RENDERPATH_GL11:
1320 case RENDERPATH_GL13:
1321 case RENDERPATH_GL20:
1322 case RENDERPATH_GLES1:
1323 case RENDERPATH_GLES2:
1324 if (glt->texnum) // not renderbuffers
1328 // we need to restore the texture binding after finishing the upload
1329 GL_ActiveTexture(0);
1330 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1331 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1334 #ifdef GL_TEXTURE_COMPRESSION_HINT_ARB
1335 if (qglGetCompressedTexImageARB)
1337 if (gl_texturecompression.integer >= 2)
1338 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1340 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1345 switch(glt->texturetype)
1347 case GLTEXTURETYPE_2D:
1348 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1349 if (glt->flags & TEXF_MIPMAP)
1351 while (width > 1 || height > 1 || depth > 1)
1353 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1354 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1355 prevbuffer = resizebuffer;
1356 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1360 case GLTEXTURETYPE_3D:
1362 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1363 if (glt->flags & TEXF_MIPMAP)
1365 while (width > 1 || height > 1 || depth > 1)
1367 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1368 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1369 prevbuffer = resizebuffer;
1370 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1375 case GLTEXTURETYPE_CUBEMAP:
1376 // convert and upload each side in turn,
1377 // from a continuous block of input texels
1378 texturebuffer = (unsigned char *)prevbuffer;
1379 for (i = 0;i < 6;i++)
1381 prevbuffer = texturebuffer;
1382 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1383 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1385 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1386 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1387 prevbuffer = resizebuffer;
1390 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1392 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1393 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1394 prevbuffer = resizebuffer;
1397 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1398 if (glt->flags & TEXF_MIPMAP)
1400 while (width > 1 || height > 1 || depth > 1)
1402 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1403 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1404 prevbuffer = resizebuffer;
1405 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1411 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1412 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1415 case RENDERPATH_D3D9:
1417 if (!(glt->flags & TEXF_RENDERTARGET) && glt->d3dtexture && !glt->d3dsurface)
1419 D3DLOCKED_RECT d3dlockedrect;
1420 D3DLOCKED_BOX d3dlockedbox;
1421 switch(glt->texturetype)
1423 case GLTEXTURETYPE_2D:
1424 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1427 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1429 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1430 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1433 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1435 while (width > 1 || height > 1 || depth > 1)
1437 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1438 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1439 prevbuffer = resizebuffer;
1440 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1442 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1443 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1449 case GLTEXTURETYPE_3D:
1450 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1452 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1453 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1454 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1457 if (glt->flags & TEXF_MIPMAP)
1459 while (width > 1 || height > 1 || depth > 1)
1461 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1462 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1463 prevbuffer = resizebuffer;
1464 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1466 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1467 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1468 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1474 case GLTEXTURETYPE_CUBEMAP:
1475 // convert and upload each side in turn,
1476 // from a continuous block of input texels
1477 texturebuffer = (unsigned char *)prevbuffer;
1478 for (i = 0;i < 6;i++)
1480 prevbuffer = texturebuffer;
1481 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1482 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1484 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1485 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1486 prevbuffer = resizebuffer;
1489 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1491 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1492 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1493 prevbuffer = resizebuffer;
1496 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1498 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1499 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1502 if (glt->flags & TEXF_MIPMAP)
1504 while (width > 1 || height > 1 || depth > 1)
1506 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1507 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1508 prevbuffer = resizebuffer;
1509 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1511 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1512 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1521 glt->d3daddressw = 0;
1522 if (glt->flags & TEXF_CLAMP)
1524 glt->d3daddressu = D3DTADDRESS_CLAMP;
1525 glt->d3daddressv = D3DTADDRESS_CLAMP;
1526 if (glt->tiledepth > 1)
1527 glt->d3daddressw = D3DTADDRESS_CLAMP;
1531 glt->d3daddressu = D3DTADDRESS_WRAP;
1532 glt->d3daddressv = D3DTADDRESS_WRAP;
1533 if (glt->tiledepth > 1)
1534 glt->d3daddressw = D3DTADDRESS_WRAP;
1536 glt->d3dmipmaplodbias = 0;
1537 glt->d3dmaxmiplevel = 0;
1538 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1539 if (glt->flags & TEXF_FORCELINEAR)
1541 glt->d3dminfilter = D3DTEXF_LINEAR;
1542 glt->d3dmagfilter = D3DTEXF_LINEAR;
1543 glt->d3dmipfilter = D3DTEXF_POINT;
1545 else if (glt->flags & TEXF_FORCENEAREST)
1547 glt->d3dminfilter = D3DTEXF_POINT;
1548 glt->d3dmagfilter = D3DTEXF_POINT;
1549 glt->d3dmipfilter = D3DTEXF_POINT;
1551 else if (glt->flags & TEXF_MIPMAP)
1553 glt->d3dminfilter = d3d_filter_mipmin;
1554 glt->d3dmagfilter = d3d_filter_mipmag;
1555 glt->d3dmipfilter = d3d_filter_mipmix;
1559 glt->d3dminfilter = d3d_filter_flatmin;
1560 glt->d3dmagfilter = d3d_filter_flatmag;
1561 glt->d3dmipfilter = d3d_filter_flatmix;
1565 case RENDERPATH_D3D10:
1566 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1568 case RENDERPATH_D3D11:
1569 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1571 case RENDERPATH_SOFT:
1572 switch(glt->texturetype)
1574 case GLTEXTURETYPE_2D:
1575 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1577 case GLTEXTURETYPE_3D:
1578 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1580 case GLTEXTURETYPE_CUBEMAP:
1581 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1583 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1584 // convert and upload each side in turn,
1585 // from a continuous block of input texels
1586 // copy the results into combinedbuffer
1587 texturebuffer = (unsigned char *)prevbuffer;
1588 for (i = 0;i < 6;i++)
1590 prevbuffer = texturebuffer;
1591 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1592 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1594 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1595 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1596 prevbuffer = resizebuffer;
1599 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1601 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1602 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1603 prevbuffer = resizebuffer;
1605 memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1607 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1608 Mem_Free(combinedbuffer);
1611 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1614 if (glt->flags & TEXF_FORCELINEAR)
1615 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1616 else if (glt->flags & TEXF_FORCENEAREST)
1617 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1618 else if (glt->flags & TEXF_MIPMAP)
1619 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1621 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1626 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)
1630 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1631 textypeinfo_t *texinfo, *texinfo2;
1632 unsigned char *temppixels = NULL;
1635 if (cls.state == ca_dedicated)
1638 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1639 if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1641 int numpixels = width * height * depth * sides;
1642 size = numpixels * 4;
1643 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1646 const unsigned char *p;
1647 unsigned char *o = temppixels;
1648 for (i = 0;i < numpixels;i++, o += 4)
1650 p = (const unsigned char *)palette + 4*data[i];
1658 textype = TEXTYPE_RGBA;
1663 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1664 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1665 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1666 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1672 static int rgbaswapindices[4] = {2, 1, 0, 3};
1673 size = width * height * depth * sides * 4;
1674 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1676 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1680 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1681 if (!vid.support.ext_texture_srgb)
1683 qboolean convertsRGB = false;
1686 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1687 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1688 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1689 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1690 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;/*convertsRGB = true;*/break;
1691 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1692 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1696 if (convertsRGB && data)
1698 size = width * height * depth * sides * 4;
1701 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1702 memcpy(temppixels, data, size);
1705 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1709 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1711 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1714 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1716 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1720 texinfo = R_GetTexTypeInfo(textype, flags);
1721 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1724 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1728 // clear the alpha flag if the texture has no transparent pixels
1731 case TEXTYPE_PALETTE:
1732 case TEXTYPE_SRGB_PALETTE:
1733 if (flags & TEXF_ALPHA)
1735 flags &= ~TEXF_ALPHA;
1738 for (i = 0;i < size;i++)
1740 if (((unsigned char *)&palette[data[i]])[3] < 255)
1742 flags |= TEXF_ALPHA;
1751 case TEXTYPE_SRGB_RGBA:
1752 case TEXTYPE_SRGB_BGRA:
1753 if (flags & TEXF_ALPHA)
1755 flags &= ~TEXF_ALPHA;
1758 for (i = 3;i < size;i += 4)
1762 flags |= TEXF_ALPHA;
1769 case TEXTYPE_SHADOWMAP16_COMP:
1770 case TEXTYPE_SHADOWMAP16_RAW:
1771 case TEXTYPE_SHADOWMAP24_COMP:
1772 case TEXTYPE_SHADOWMAP24_RAW:
1775 case TEXTYPE_SRGB_DXT1:
1778 case TEXTYPE_SRGB_DXT1A:
1780 case TEXTYPE_SRGB_DXT3:
1782 case TEXTYPE_SRGB_DXT5:
1783 flags |= TEXF_ALPHA;
1786 flags |= TEXF_ALPHA;
1788 case TEXTYPE_COLORBUFFER:
1789 case TEXTYPE_COLORBUFFER16F:
1790 case TEXTYPE_COLORBUFFER32F:
1791 flags |= TEXF_ALPHA;
1794 Sys_Error("R_LoadTexture: unknown texture type");
1797 texinfo2 = R_GetTexTypeInfo(textype, flags);
1798 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1801 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1803 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1805 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1807 glt->chain = pool->gltchain;
1808 pool->gltchain = glt;
1809 glt->inputwidth = width;
1810 glt->inputheight = height;
1811 glt->inputdepth = depth;
1813 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
1814 glt->textype = texinfo;
1815 glt->texturetype = texturetype;
1816 glt->inputdatasize = size;
1817 glt->palette = palette;
1818 glt->glinternalformat = texinfo->glinternalformat;
1819 glt->glformat = texinfo->glformat;
1820 glt->gltype = texinfo->gltype;
1821 glt->bytesperpixel = texinfo->internalbytesperpixel;
1822 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1825 glt->glisdepthstencil = false;
1826 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1827 // init the dynamic texture attributes, too [11/22/2007 Black]
1828 glt->updatecallback = NULL;
1829 glt->updatecallback_data = NULL;
1831 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1833 // upload the texture
1834 // data may be NULL (blank texture for dynamic rendering)
1835 switch(vid.renderpath)
1837 case RENDERPATH_GL11:
1838 case RENDERPATH_GL13:
1839 case RENDERPATH_GL20:
1840 case RENDERPATH_GLES1:
1841 case RENDERPATH_GLES2:
1843 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1845 case RENDERPATH_D3D9:
1848 D3DFORMAT d3dformat;
1853 d3dpool = D3DPOOL_MANAGED;
1854 if (flags & TEXF_RENDERTARGET)
1856 d3dusage |= D3DUSAGE_RENDERTARGET;
1857 d3dpool = D3DPOOL_DEFAULT;
1861 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1862 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1863 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1864 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
1865 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
1866 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
1867 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1868 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1870 glt->d3dformat = d3dformat;
1871 glt->d3dusage = d3dusage;
1872 glt->d3dpool = d3dpool;
1873 glt->d3disrendertargetsurface = false;
1874 glt->d3disdepthstencilsurface = false;
1875 if (glt->tiledepth > 1)
1877 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)))
1878 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1880 else if (glt->sides == 6)
1882 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1883 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1887 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)))
1888 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1893 case RENDERPATH_D3D10:
1894 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1896 case RENDERPATH_D3D11:
1897 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1899 case RENDERPATH_SOFT:
1904 case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1905 case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1906 case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1907 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1908 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
1909 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
1910 case TEXTYPE_SHADOWMAP16_COMP:
1911 case TEXTYPE_SHADOWMAP16_RAW:
1912 case TEXTYPE_SHADOWMAP24_COMP:
1913 case TEXTYPE_SHADOWMAP24_RAW: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1914 case TEXTYPE_DEPTHBUFFER16:
1915 case TEXTYPE_DEPTHBUFFER24:
1916 case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1917 case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1918 default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1920 if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1921 if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1922 if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1923 if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1924 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1929 R_UploadFullTexture(glt, data);
1930 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1931 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1933 // free any temporary processing buffer we allocated...
1935 Mem_Free(temppixels);
1937 // texture converting and uploading can take a while, so make sure we're sending keepalives
1938 // FIXME: this causes rendering during R_Shadow_DrawLights
1939 // CL_KeepaliveMessage(false);
1941 return (rtexture_t *)glt;
1944 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)
1946 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1949 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)
1951 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1954 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)
1956 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1959 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter)
1961 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL);
1964 rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
1967 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1968 textypeinfo_t *texinfo;
1970 if (cls.state == ca_dedicated)
1973 texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP);
1975 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1977 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1979 glt->chain = pool->gltchain;
1980 pool->gltchain = glt;
1981 glt->inputwidth = width;
1982 glt->inputheight = height;
1983 glt->inputdepth = 1;
1984 glt->flags = TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_FORCENEAREST;
1986 glt->textype = texinfo;
1987 glt->texturetype = textype;
1988 glt->inputdatasize = width*height*texinfo->internalbytesperpixel;
1989 glt->palette = NULL;
1990 glt->glinternalformat = texinfo->glinternalformat;
1991 glt->glformat = texinfo->glformat;
1992 glt->gltype = texinfo->gltype;
1993 glt->bytesperpixel = texinfo->internalbytesperpixel;
1994 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1997 glt->glisdepthstencil = textype == TEXTYPE_DEPTHBUFFER24STENCIL8;
1998 glt->gltexturetypeenum = GL_TEXTURE_2D;
1999 // init the dynamic texture attributes, too [11/22/2007 Black]
2000 glt->updatecallback = NULL;
2001 glt->updatecallback_data = NULL;
2003 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
2005 // upload the texture
2006 // data may be NULL (blank texture for dynamic rendering)
2007 switch(vid.renderpath)
2009 case RENDERPATH_GL11:
2010 case RENDERPATH_GL13:
2011 case RENDERPATH_GL20:
2012 case RENDERPATH_GLES1:
2013 case RENDERPATH_GLES2:
2015 qglGenRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
2016 qglBindRenderbuffer(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR
2017 qglRenderbufferStorage(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR
2018 // 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
2019 qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR
2021 case RENDERPATH_D3D9:
2024 D3DFORMAT d3dformat;
2026 glt->d3disrendertargetsurface = false;
2027 glt->d3disdepthstencilsurface = false;
2030 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;glt->d3disrendertargetsurface = true;break;
2031 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;glt->d3disrendertargetsurface = true;break;
2032 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;glt->d3disrendertargetsurface = true;break;
2033 case TEXTYPE_DEPTHBUFFER16: d3dformat = D3DFMT_D16;glt->d3disdepthstencilsurface = true;break;
2034 case TEXTYPE_DEPTHBUFFER24: d3dformat = D3DFMT_D24X8;glt->d3disdepthstencilsurface = true;break;
2035 case TEXTYPE_DEPTHBUFFER24STENCIL8: d3dformat = D3DFMT_D24S8;glt->d3disdepthstencilsurface = true;break;
2036 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2038 glt->d3dformat = d3dformat;
2041 if (glt->d3disrendertargetsurface)
2043 if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
2044 Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!");
2046 else if (glt->d3disdepthstencilsurface)
2048 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
2049 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
2054 case RENDERPATH_D3D10:
2055 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2057 case RENDERPATH_D3D11:
2058 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2060 case RENDERPATH_SOFT:
2065 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8 | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2066 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2067 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2068 case TEXTYPE_DEPTHBUFFER16:
2069 case TEXTYPE_DEPTHBUFFER24:
2070 case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2071 default: Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
2073 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
2078 return (rtexture_t *)glt;
2081 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
2084 return -1; // unsupported on this platform
2086 gltexture_t *glt = (gltexture_t *)rt;
2089 int bytesperpixel = 0;
2090 int bytesperblock = 0;
2092 int dds_format_flags;
2100 GLint internalformat;
2101 const char *ddsfourcc;
2103 return -1; // NULL pointer
2104 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
2105 return -2; // broken driver - crashes on reading internal format
2106 if (!qglGetTexLevelParameteriv)
2108 GL_ActiveTexture(0);
2109 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2110 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2111 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
2112 switch(internalformat)
2114 default: ddsfourcc = NULL;bytesperpixel = 4;break;
2115 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
2116 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
2117 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
2118 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
2120 // if premultiplied alpha, say so in the DDS file
2121 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
2123 switch(internalformat)
2125 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
2126 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
2129 if (!bytesperblock && skipuncompressed)
2130 return -3; // skipped
2131 memset(mipinfo, 0, sizeof(mipinfo));
2132 mipinfo[0][0] = glt->tilewidth;
2133 mipinfo[0][1] = glt->tileheight;
2135 if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1))
2137 for (mip = 1;mip < 16;mip++)
2139 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
2140 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
2141 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
2149 for (mip = 0;mip < mipmaps;mip++)
2151 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
2152 mipinfo[mip][3] = ddssize;
2153 ddssize += mipinfo[mip][2];
2155 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
2158 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
2162 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
2163 dds_format_flags = 0x4; // DDPF_FOURCC
2167 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
2168 dds_format_flags = 0x40; // DDPF_RGB
2172 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
2173 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
2176 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
2177 memcpy(dds, "DDS ", 4);
2178 StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
2179 StoreLittleLong(dds+8, dds_flags);
2180 StoreLittleLong(dds+12, mipinfo[0][1]); // height
2181 StoreLittleLong(dds+16, mipinfo[0][0]); // width
2182 StoreLittleLong(dds+24, 0); // depth
2183 StoreLittleLong(dds+28, mipmaps); // mipmaps
2184 StoreLittleLong(dds+76, 32); // format size
2185 StoreLittleLong(dds+80, dds_format_flags);
2186 StoreLittleLong(dds+108, dds_caps1);
2187 StoreLittleLong(dds+112, dds_caps2);
2190 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
2191 memcpy(dds+84, ddsfourcc, 4);
2192 for (mip = 0;mip < mipmaps;mip++)
2194 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
2199 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
2200 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
2201 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
2202 for (mip = 0;mip < mipmaps;mip++)
2204 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
2207 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2208 ret = FS_WriteFile(filename, dds, ddssize);
2210 return ret ? ddssize : -5;
2215 // ELUAN: FIXME: separate this code
2216 #include "ktx10/include/ktx.h"
2219 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
2221 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
2224 int bytesperblock, bytesperpixel;
2227 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
2228 textypeinfo_t *texinfo;
2229 int mip, mipwidth, mipheight, mipsize, mipsize_total;
2230 unsigned int c, r, g, b;
2231 GLint oldbindtexnum = 0;
2232 unsigned char *mippixels;
2233 unsigned char *mippixels_start;
2234 unsigned char *ddspixels;
2236 fs_offset_t ddsfilesize;
2237 unsigned int ddssize;
2238 qboolean force_swdecode, npothack;
2240 // ELUAN: FIXME: separate this code
2244 KTX_dimensions sizes;
2247 if (cls.state == ca_dedicated)
2251 // ELUAN: FIXME: separate this code
2252 if (vid.renderpath != RENDERPATH_GLES2)
2254 Con_DPrintf("KTX texture format is only supported on the GLES2 renderpath\n");
2258 // some textures are specified with extensions, so it becomes .tga.dds
2259 FS_StripExtension (filename, vabuf2, sizeof(vabuf2));
2260 FS_StripExtension (vabuf2, vabuf, sizeof(vabuf));
2261 FS_DefaultExtension (vabuf, ".ktx", sizeof(vabuf));
2262 strsize = strlen(vabuf);
2264 for (i = 0; i <= strsize - 4; i++) // copy null termination
2265 vabuf[i] = vabuf[i + 4];
2267 Con_DPrintf("Loading %s...\n", vabuf);
2268 dds = FS_LoadFile(vabuf, tempmempool, true, &ddsfilesize);
2269 ddssize = ddsfilesize;
2273 Con_DPrintf("Not found!\n");
2274 return NULL; // not found
2276 Con_DPrintf("Found!\n");
2278 if (flags & TEXF_ALPHA)
2280 Con_DPrintf("KTX texture with alpha not supported yet, disabling\n");
2281 flags &= ~TEXF_ALPHA;
2287 GLboolean isMipmapped;
2288 KTX_error_code ktxerror;
2290 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2292 // texture uploading can take a while, so make sure we're sending keepalives
2293 CL_KeepaliveMessage(false);
2295 // create the texture object
2297 GL_ActiveTexture(0);
2298 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[GLTEXTURETYPE_2D]);
2299 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2300 qglBindTexture(gltexturetypeenums[GLTEXTURETYPE_2D], glt->texnum);CHECKGLERROR
2302 // upload the texture
2303 // we need to restore the texture binding after finishing the upload
2305 // NOTE: some drivers fail with ETC1 NPOT (only PowerVR?). This may make the driver crash later.
2306 ktxerror = ktxLoadTextureM(dds, ddssize, &glt->texnum, &target, &sizes, &isMipmapped, &glerror,
2307 0, NULL);// can't CHECKGLERROR, the lib catches it
2309 // FIXME: delete texture if we fail here
2310 if (target != GL_TEXTURE_2D)
2312 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2314 Con_DPrintf("%s target != GL_TEXTURE_2D, target == %x\n", vabuf, target);
2315 return NULL; // FIXME: delete the texture from memory
2318 if (KTX_SUCCESS == ktxerror)
2320 textype = TEXTYPE_ETC1;
2321 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2323 // return whether this texture is transparent
2325 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2327 // TODO: apply gl_picmip
2330 // TODO: only load mipmaps if requested
2333 flags |= TEXF_MIPMAP;
2335 flags &= ~TEXF_MIPMAP;
2337 texinfo = R_GetTexTypeInfo(textype, flags);
2339 strlcpy (glt->identifier, vabuf, sizeof(glt->identifier));
2341 glt->chain = pool->gltchain;
2342 pool->gltchain = glt;
2343 glt->inputwidth = sizes.width;
2344 glt->inputheight = sizes.height;
2345 glt->inputdepth = 1;
2347 glt->textype = texinfo;
2348 glt->texturetype = GLTEXTURETYPE_2D;
2349 glt->inputdatasize = ddssize;
2350 glt->glinternalformat = texinfo->glinternalformat;
2351 glt->glformat = texinfo->glformat;
2352 glt->gltype = texinfo->gltype;
2353 glt->bytesperpixel = texinfo->internalbytesperpixel;
2355 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2356 glt->tilewidth = sizes.width;
2357 glt->tileheight = sizes.height;
2359 glt->miplevels = isMipmapped ? 1 : 0; // FIXME
2361 // after upload we have to set some parameters...
2362 #ifdef GL_TEXTURE_MAX_LEVEL
2364 if (dds_miplevels >= 1 && !mipcomplete)
2366 // need to set GL_TEXTURE_MAX_LEVEL
2367 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2371 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2373 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2375 return (rtexture_t *)glt;
2379 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2381 Con_DPrintf("KTX texture %s failed to load: %x\n", vabuf, ktxerror);
2385 #endif // __ANDROID__
2387 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
2388 ddssize = ddsfilesize;
2392 if (r_texture_dds_load_logfailure.integer && (r_texture_dds_load_logfailure.integer >= 2 || !optionaltexture))
2393 Log_Printf("ddstexturefailures.log", "%s\n", filename);
2394 return NULL; // not found
2397 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
2400 Con_Printf("^1%s: not a DDS image\n", filename);
2404 //dds_flags = BuffLittleLong(dds+8);
2405 dds_format_flags = BuffLittleLong(dds+80);
2406 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
2407 dds_width = BuffLittleLong(dds+16);
2408 dds_height = BuffLittleLong(dds+12);
2409 ddspixels = dds + 128;
2411 if(r_texture_dds_load_alphamode.integer == 0)
2412 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
2413 flags &= ~TEXF_ALPHA;
2415 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
2416 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
2418 // very sloppy BGRA 32bit identification
2419 textype = TEXTYPE_BGRA;
2420 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2423 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
2424 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2427 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
2430 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
2433 for (i = 3;i < size;i += 4)
2434 if (ddspixels[i] < 255)
2437 flags &= ~TEXF_ALPHA;
2440 else if (!memcmp(dds+84, "DXT1", 4))
2442 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
2443 // LordHavoc: it is my belief that this does not infringe on the
2444 // patent because it is not decoding pixels...
2445 textype = TEXTYPE_DXT1;
2448 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
2449 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2450 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2453 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
2456 if (flags & TEXF_ALPHA)
2458 if (r_texture_dds_load_alphamode.integer == 1)
2461 for (i = 0;i < size;i += bytesperblock)
2462 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
2464 // NOTE: this assumes sizeof(unsigned int) == 4
2465 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
2466 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
2467 if(data & (data<<1) & 0xAAAAAAAA)//rgh
2471 textype = TEXTYPE_DXT1A;
2473 flags &= ~TEXF_ALPHA;
2475 else if (r_texture_dds_load_alphamode.integer == 0)
2476 textype = TEXTYPE_DXT1A;
2479 flags &= ~TEXF_ALPHA;
2483 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2485 if(!memcmp(dds+84, "DXT2", 4))
2487 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2489 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2494 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2496 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2499 textype = TEXTYPE_DXT3;
2502 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2503 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2506 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2509 // we currently always assume alpha
2511 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2513 if(!memcmp(dds+84, "DXT4", 4))
2515 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2517 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2522 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2524 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2527 textype = TEXTYPE_DXT5;
2530 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2531 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2534 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2537 // we currently always assume alpha
2542 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2546 // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
2547 if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
2549 textype = TEXTYPE_DXT1;
2553 for (i = 0;i < (int)ddssize;i += bytesperblock)
2554 memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
2558 force_swdecode = false;
2560 (!vid.support.arb_texture_non_power_of_two &&
2562 (dds_width & (dds_width - 1))
2564 (dds_height & (dds_height - 1))
2569 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && !npothack)
2571 if(r_texture_dds_swdecode.integer > 1)
2572 force_swdecode = true;
2576 if(r_texture_dds_swdecode.integer < 1)
2582 force_swdecode = true;
2586 // return whether this texture is transparent
2588 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2590 // if we SW decode, choose 2 sizes bigger
2593 // this is quarter res, so do not scale down more than we have to
2597 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2600 // this is where we apply gl_picmip
2601 mippixels_start = ddspixels;
2602 mipwidth = dds_width;
2603 mipheight = dds_height;
2604 while(miplevel >= 1 && dds_miplevels >= 1)
2606 if (mipwidth <= 1 && mipheight <= 1)
2608 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2609 mippixels_start += mipsize; // just skip
2617 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2618 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2620 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2622 // fake decode S3TC if needed
2625 int mipsize_new = mipsize_total / bytesperblock * 4;
2626 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2627 unsigned char *p = mipnewpixels;
2628 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2630 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2631 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2632 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2633 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2634 if(textype == TEXTYPE_DXT5)
2635 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2636 else if(textype == TEXTYPE_DXT3)
2638 (mippixels_start[i-8] & 0x0F)
2639 + (mippixels_start[i-8] >> 4)
2640 + (mippixels_start[i-7] & 0x0F)
2641 + (mippixels_start[i-7] >> 4)
2642 + (mippixels_start[i-6] & 0x0F)
2643 + (mippixels_start[i-6] >> 4)
2644 + (mippixels_start[i-5] & 0x0F)
2645 + (mippixels_start[i-5] >> 4)
2646 ) * (0.125f / 15.0f * 255.0f);
2651 textype = TEXTYPE_BGRA;
2655 // as each block becomes a pixel, we must use pixel count for this
2656 mipwidth = (mipwidth + 3) / 4;
2657 mipheight = (mipheight + 3) / 4;
2658 mipsize = bytesperpixel * mipwidth * mipheight;
2659 mippixels_start = mipnewpixels;
2660 mipsize_total = mipsize_new;
2663 // start mip counting
2664 mippixels = mippixels_start;
2666 // calculate average color if requested
2670 Vector4Clear(avgcolor);
2673 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2675 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2676 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2677 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2678 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2679 if(textype == TEXTYPE_DXT5)
2680 avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f);
2681 else if(textype == TEXTYPE_DXT3)
2683 (mippixels_start[i-8] & 0x0F)
2684 + (mippixels_start[i-8] >> 4)
2685 + (mippixels_start[i-7] & 0x0F)
2686 + (mippixels_start[i-7] >> 4)
2687 + (mippixels_start[i-6] & 0x0F)
2688 + (mippixels_start[i-6] >> 4)
2689 + (mippixels_start[i-5] & 0x0F)
2690 + (mippixels_start[i-5] >> 4)
2691 ) * (0.125f / 15.0f);
2693 avgcolor[3] += 1.0f;
2695 f = (float)bytesperblock / mipsize;
2696 avgcolor[0] *= (0.5f / 31.0f) * f;
2697 avgcolor[1] *= (0.5f / 63.0f) * f;
2698 avgcolor[2] *= (0.5f / 31.0f) * f;
2703 for (i = 0;i < mipsize;i += 4)
2705 avgcolor[0] += mippixels[i+2];
2706 avgcolor[1] += mippixels[i+1];
2707 avgcolor[2] += mippixels[i];
2708 avgcolor[3] += mippixels[i+3];
2710 f = (1.0f / 255.0f) * bytesperpixel / mipsize;
2718 // if we want sRGB, convert now
2721 if (vid.support.ext_texture_srgb)
2725 case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break;
2726 case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break;
2727 case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break;
2728 case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break;
2729 case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break;
2743 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2745 int c0, c1, c0new, c1new;
2746 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2747 r = ((c0 >> 11) & 0x1F);
2748 g = ((c0 >> 5) & 0x3F);
2750 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2751 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2752 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2753 c0new = (r << 11) | (g << 5) | b;
2754 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2755 r = ((c1 >> 11) & 0x1F);
2756 g = ((c1 >> 5) & 0x3F);
2758 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2759 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2760 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2761 c1new = (r << 11) | (g << 5) | b;
2762 // swap the colors if needed to fix order
2763 if(c0 > c1) // thirds
2771 mippixels_start[i+4] ^= 0x55;
2772 mippixels_start[i+5] ^= 0x55;
2773 mippixels_start[i+6] ^= 0x55;
2774 mippixels_start[i+7] ^= 0x55;
2776 else if(c0new == c1new)
2778 mippixels_start[i+4] = 0x00;
2779 mippixels_start[i+5] = 0x00;
2780 mippixels_start[i+6] = 0x00;
2781 mippixels_start[i+7] = 0x00;
2784 else // half + transparent
2791 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2792 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2793 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2794 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2797 mippixels_start[i] = c0new & 255;
2798 mippixels_start[i+1] = c0new >> 8;
2799 mippixels_start[i+2] = c1new & 255;
2800 mippixels_start[i+3] = c1new >> 8;
2805 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2813 // when not requesting mipmaps, do not load them
2814 if(!(flags & TEXF_MIPMAP))
2817 if (dds_miplevels >= 1)
2818 flags |= TEXF_MIPMAP;
2820 flags &= ~TEXF_MIPMAP;
2822 texinfo = R_GetTexTypeInfo(textype, flags);
2824 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2825 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2827 glt->chain = pool->gltchain;
2828 pool->gltchain = glt;
2829 glt->inputwidth = mipwidth;
2830 glt->inputheight = mipheight;
2831 glt->inputdepth = 1;
2833 glt->textype = texinfo;
2834 glt->texturetype = GLTEXTURETYPE_2D;
2835 glt->inputdatasize = ddssize;
2836 glt->glinternalformat = texinfo->glinternalformat;
2837 glt->glformat = texinfo->glformat;
2838 glt->gltype = texinfo->gltype;
2839 glt->bytesperpixel = texinfo->internalbytesperpixel;
2841 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2842 glt->tilewidth = mipwidth;
2843 glt->tileheight = mipheight;
2845 glt->miplevels = dds_miplevels;
2849 for (glt->tilewidth = 1;glt->tilewidth < mipwidth;glt->tilewidth <<= 1);
2850 for (glt->tileheight = 1;glt->tileheight < mipheight;glt->tileheight <<= 1);
2853 // texture uploading can take a while, so make sure we're sending keepalives
2854 CL_KeepaliveMessage(false);
2856 // create the texture object
2857 switch(vid.renderpath)
2859 case RENDERPATH_GL11:
2860 case RENDERPATH_GL13:
2861 case RENDERPATH_GL20:
2862 case RENDERPATH_GLES1:
2863 case RENDERPATH_GLES2:
2865 GL_ActiveTexture(0);
2866 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2867 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2868 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2870 case RENDERPATH_D3D9:
2873 D3DFORMAT d3dformat;
2878 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2879 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2880 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2881 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2882 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2885 d3dpool = D3DPOOL_MANAGED;
2886 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2890 case RENDERPATH_D3D10:
2891 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2893 case RENDERPATH_D3D11:
2894 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2896 case RENDERPATH_SOFT:
2897 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);
2901 // upload the texture
2902 // we need to restore the texture binding after finishing the upload
2903 mipcomplete = false;
2905 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2907 unsigned char *upload_mippixels = mippixels;
2908 int upload_mipwidth = mipwidth;
2909 int upload_mipheight = mipheight;
2910 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2911 if (mippixels + mipsize > mippixels_start + mipsize_total)
2915 upload_mipwidth = (glt->tilewidth >> mip);
2916 upload_mipheight = (glt->tileheight >> mip);
2917 if(upload_mipwidth != mipwidth || upload_mipheight != mipheight)
2918 // I _think_ they always mismatch, but I was too lazy
2919 // to properly check, and this test here is really
2922 upload_mippixels = (unsigned char *) Mem_Alloc(tempmempool, 4 * upload_mipwidth * upload_mipheight);
2923 Image_Resample32(mippixels, mipwidth, mipheight, 1, upload_mippixels, upload_mipwidth, upload_mipheight, 1, r_lerpimages.integer);
2926 switch(vid.renderpath)
2928 case RENDERPATH_GL11:
2929 case RENDERPATH_GL13:
2930 case RENDERPATH_GL20:
2931 case RENDERPATH_GLES1:
2932 case RENDERPATH_GLES2:
2935 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR
2939 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR
2942 case RENDERPATH_D3D9:
2945 D3DLOCKED_RECT d3dlockedrect;
2946 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2948 memcpy(d3dlockedrect.pBits, upload_mippixels, mipsize);
2949 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2955 case RENDERPATH_D3D10:
2956 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2958 case RENDERPATH_D3D11:
2959 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2961 case RENDERPATH_SOFT:
2963 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2965 DPSOFTRAST_Texture_UpdateFull(glt->texnum, upload_mippixels);
2966 // DPSOFTRAST calculates its own mipmaps
2967 mip = dds_miplevels;
2970 if(upload_mippixels != mippixels)
2971 Mem_Free(upload_mippixels);
2972 mippixels += mipsize;
2973 if (mipwidth <= 1 && mipheight <= 1)
2984 // after upload we have to set some parameters...
2985 switch(vid.renderpath)
2987 case RENDERPATH_GL11:
2988 case RENDERPATH_GL13:
2989 case RENDERPATH_GL20:
2990 case RENDERPATH_GLES1:
2991 case RENDERPATH_GLES2:
2992 #ifdef GL_TEXTURE_MAX_LEVEL
2993 if (dds_miplevels >= 1 && !mipcomplete)
2995 // need to set GL_TEXTURE_MAX_LEVEL
2996 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2999 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
3000 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
3002 case RENDERPATH_D3D9:
3004 glt->d3daddressw = 0;
3005 if (glt->flags & TEXF_CLAMP)
3007 glt->d3daddressu = D3DTADDRESS_CLAMP;
3008 glt->d3daddressv = D3DTADDRESS_CLAMP;
3009 if (glt->tiledepth > 1)
3010 glt->d3daddressw = D3DTADDRESS_CLAMP;
3014 glt->d3daddressu = D3DTADDRESS_WRAP;
3015 glt->d3daddressv = D3DTADDRESS_WRAP;
3016 if (glt->tiledepth > 1)
3017 glt->d3daddressw = D3DTADDRESS_WRAP;
3019 glt->d3dmipmaplodbias = 0;
3020 glt->d3dmaxmiplevel = 0;
3021 glt->d3dmaxmiplevelfilter = 0;
3022 if (glt->flags & TEXF_MIPMAP)
3024 glt->d3dminfilter = d3d_filter_mipmin;
3025 glt->d3dmagfilter = d3d_filter_mipmag;
3026 glt->d3dmipfilter = d3d_filter_mipmix;
3030 glt->d3dminfilter = d3d_filter_flatmin;
3031 glt->d3dmagfilter = d3d_filter_flatmag;
3032 glt->d3dmipfilter = d3d_filter_flatmix;
3036 case RENDERPATH_D3D10:
3037 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3039 case RENDERPATH_D3D11:
3040 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3042 case RENDERPATH_SOFT:
3043 if (glt->flags & TEXF_FORCELINEAR)
3044 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
3045 else if (glt->flags & TEXF_FORCENEAREST)
3046 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
3047 else if (glt->flags & TEXF_MIPMAP)
3048 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
3050 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
3056 Mem_Free((unsigned char *) mippixels_start);
3057 return (rtexture_t *)glt;
3060 int R_TextureWidth(rtexture_t *rt)
3062 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
3065 int R_TextureHeight(rtexture_t *rt)
3067 return rt ? ((gltexture_t *)rt)->inputheight : 0;
3070 int R_TextureFlags(rtexture_t *rt)
3072 return rt ? ((gltexture_t *)rt)->flags : 0;
3075 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
3077 gltexture_t *glt = (gltexture_t *)rt;
3079 Host_Error("R_UpdateTexture: no data supplied");
3081 Host_Error("R_UpdateTexture: no texture supplied");
3082 if (!glt->texnum && !glt->d3dtexture)
3084 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
3087 // update part of the texture
3088 if (glt->bufferpixels)
3091 int bpp = glt->bytesperpixel;
3092 int inputskip = width*bpp;
3093 int outputskip = glt->tilewidth*bpp;
3094 const unsigned char *input = data;
3095 unsigned char *output = glt->bufferpixels;
3096 if (glt->inputdepth != 1 || glt->sides != 1)
3097 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
3107 input -= y*inputskip;
3110 if (width > glt->tilewidth - x)
3111 width = glt->tilewidth - x;
3112 if (height > glt->tileheight - y)
3113 height = glt->tileheight - y;
3114 if (width < 1 || height < 1)
3117 glt->buffermodified = true;
3118 output += y*outputskip + x*bpp;
3119 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
3120 memcpy(output, input, width*bpp);
3122 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
3123 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
3125 R_UploadFullTexture(glt, data);
3128 int R_RealGetTexture(rtexture_t *rt)
3133 glt = (gltexture_t *)rt;
3134 if (glt->flags & GLTEXF_DYNAMIC)
3135 R_UpdateDynamicTexture(glt);
3136 if (glt->buffermodified && glt->bufferpixels)
3138 glt->buffermodified = false;
3139 R_UploadFullTexture(glt, glt->bufferpixels);
3148 void R_ClearTexture (rtexture_t *rt)
3150 gltexture_t *glt = (gltexture_t *)rt;
3152 R_UploadFullTexture(glt, NULL);
3155 int R_PicmipForFlags(int flags)
3158 if(flags & TEXF_PICMIP)
3160 miplevel += gl_picmip.integer;
3161 if (flags & TEXF_ISWORLD)
3163 if (r_picmipworld.integer)
3164 miplevel += gl_picmip_world.integer;
3168 else if (flags & TEXF_ISSPRITE)
3170 if (r_picmipsprites.integer)
3171 miplevel += gl_picmip_sprites.integer;
3176 miplevel += gl_picmip_other.integer;
3178 return max(0, miplevel);