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");
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;
1001 // could do procedural texture animation here, if we keep track of which
1002 // textures were accessed this frame...
1004 // free the resize buffers
1005 resizebuffersize = 0;
1008 Mem_Free(resizebuffer);
1009 resizebuffer = NULL;
1011 if (colorconvertbuffer)
1013 Mem_Free(colorconvertbuffer);
1014 colorconvertbuffer = NULL;
1017 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
1018 if (old_aniso != gl_texture_anisotropy.integer)
1021 gltexturepool_t *pool;
1022 GLint oldbindtexnum;
1024 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
1026 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
1028 switch(vid.renderpath)
1030 case RENDERPATH_GL11:
1031 case RENDERPATH_GL13:
1032 case RENDERPATH_GL20:
1033 case RENDERPATH_GLES1:
1034 case RENDERPATH_GLES2:
1036 GL_ActiveTexture(0);
1037 for (pool = gltexturepoolchain;pool;pool = pool->next)
1039 for (glt = pool->gltchain;glt;glt = glt->chain)
1041 // only update already uploaded images
1042 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
1044 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1046 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1047 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
1049 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1054 case RENDERPATH_D3D9:
1055 case RENDERPATH_D3D10:
1056 case RENDERPATH_D3D11:
1057 case RENDERPATH_SOFT:
1064 static void R_MakeResizeBufferBigger(int size)
1066 if (resizebuffersize < size)
1068 resizebuffersize = size;
1070 Mem_Free(resizebuffer);
1071 if (colorconvertbuffer)
1072 Mem_Free(colorconvertbuffer);
1073 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
1074 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
1075 if (!resizebuffer || !colorconvertbuffer)
1076 Host_Error("R_Upload: out of memory");
1080 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
1082 int textureenum = gltexturetypeenums[texturetype];
1083 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
1087 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
1088 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
1090 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
1091 if (gl_texture_anisotropy.integer != aniso)
1092 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
1093 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
1096 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
1097 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
1098 #ifdef GL_TEXTURE_WRAP_R
1099 if (gltexturetypedimensions[texturetype] >= 3)
1101 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
1106 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
1108 if (flags & TEXF_MIPMAP)
1110 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
1114 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
1116 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
1118 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
1120 if (flags & TEXF_MIPMAP)
1122 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
1124 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
1128 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
1133 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
1135 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
1139 if (flags & TEXF_MIPMAP)
1141 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1145 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1147 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1150 #ifdef GL_TEXTURE_COMPARE_MODE_ARB
1153 case TEXTYPE_SHADOWMAP16_COMP:
1154 case TEXTYPE_SHADOWMAP24_COMP:
1155 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1156 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1157 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1159 case TEXTYPE_SHADOWMAP16_RAW:
1160 case TEXTYPE_SHADOWMAP24_RAW:
1161 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1162 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1163 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1173 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1176 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1178 if (glt->texturetype != GLTEXTURETYPE_2D)
1179 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1181 if (glt->textype->textype == TEXTYPE_PALETTE)
1182 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1184 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1185 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1187 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1188 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1190 // update a portion of the image
1192 switch(vid.renderpath)
1194 case RENDERPATH_GL11:
1195 case RENDERPATH_GL13:
1196 case RENDERPATH_GL20:
1197 case RENDERPATH_GLES1:
1198 case RENDERPATH_GLES2:
1202 // we need to restore the texture binding after finishing the upload
1203 GL_ActiveTexture(0);
1204 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1205 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1206 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1207 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1210 case RENDERPATH_D3D9:
1214 D3DLOCKED_RECT d3dlockedrect;
1216 memset(&d3drect, 0, sizeof(d3drect));
1217 d3drect.left = fragx;
1218 d3drect.top = fragy;
1219 d3drect.right = fragx+fragwidth;
1220 d3drect.bottom = fragy+fragheight;
1221 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1223 for (y = 0;y < fragheight;y++)
1224 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1225 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1230 case RENDERPATH_D3D10:
1231 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1233 case RENDERPATH_D3D11:
1234 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1236 case RENDERPATH_SOFT:
1237 DPSOFTRAST_Texture_UpdatePartial(glt->texnum, 0, data, fragx, fragy, fragwidth, fragheight);
1242 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1244 int i, mip = 0, width, height, depth;
1245 GLint oldbindtexnum = 0;
1246 const unsigned char *prevbuffer;
1249 // error out if a stretch is needed on special texture types
1250 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1251 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1253 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1254 // of the target size and then use the mipmap reduction function to get
1255 // high quality supersampled results
1256 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1257 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1258 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1260 if (prevbuffer == NULL)
1262 width = glt->tilewidth;
1263 height = glt->tileheight;
1264 depth = glt->tiledepth;
1265 // R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1266 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1267 // prevbuffer = resizebuffer;
1271 if (glt->textype->textype == TEXTYPE_PALETTE)
1273 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1274 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1275 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1276 prevbuffer = colorconvertbuffer;
1278 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1280 // multiply RGB channels by A channel before uploading
1282 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1283 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1285 alpha = prevbuffer[i+3];
1286 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1287 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1288 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1289 colorconvertbuffer[i+3] = alpha;
1291 prevbuffer = colorconvertbuffer;
1293 // scale up to a power of 2 size (if appropriate)
1294 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1296 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1297 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1298 prevbuffer = resizebuffer;
1300 // apply mipmap reduction algorithm to get down to picmip/max_size
1301 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1303 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1304 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1305 prevbuffer = resizebuffer;
1309 // do the appropriate upload type...
1310 switch(vid.renderpath)
1312 case RENDERPATH_GL11:
1313 case RENDERPATH_GL13:
1314 case RENDERPATH_GL20:
1315 case RENDERPATH_GLES1:
1316 case RENDERPATH_GLES2:
1317 if (glt->texnum) // not renderbuffers
1321 // we need to restore the texture binding after finishing the upload
1322 GL_ActiveTexture(0);
1323 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1324 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1327 #ifdef GL_TEXTURE_COMPRESSION_HINT_ARB
1328 if (qglGetCompressedTexImageARB)
1330 if (gl_texturecompression.integer >= 2)
1331 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1333 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1338 switch(glt->texturetype)
1340 case GLTEXTURETYPE_2D:
1341 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1342 if (glt->flags & TEXF_MIPMAP)
1344 while (width > 1 || height > 1 || depth > 1)
1346 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1347 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1348 prevbuffer = resizebuffer;
1349 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1353 case GLTEXTURETYPE_3D:
1355 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1356 if (glt->flags & TEXF_MIPMAP)
1358 while (width > 1 || height > 1 || depth > 1)
1360 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1361 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1362 prevbuffer = resizebuffer;
1363 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1368 case GLTEXTURETYPE_CUBEMAP:
1369 // convert and upload each side in turn,
1370 // from a continuous block of input texels
1371 texturebuffer = (unsigned char *)prevbuffer;
1372 for (i = 0;i < 6;i++)
1374 prevbuffer = texturebuffer;
1375 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1376 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1378 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1379 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1380 prevbuffer = resizebuffer;
1383 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1385 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1386 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1387 prevbuffer = resizebuffer;
1390 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1391 if (glt->flags & TEXF_MIPMAP)
1393 while (width > 1 || height > 1 || depth > 1)
1395 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1396 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1397 prevbuffer = resizebuffer;
1398 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1404 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1405 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1408 case RENDERPATH_D3D9:
1410 if (!(glt->flags & TEXF_RENDERTARGET) && glt->d3dtexture && !glt->d3dsurface)
1412 D3DLOCKED_RECT d3dlockedrect;
1413 D3DLOCKED_BOX d3dlockedbox;
1414 switch(glt->texturetype)
1416 case GLTEXTURETYPE_2D:
1417 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1420 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1422 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1423 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1426 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1428 while (width > 1 || height > 1 || depth > 1)
1430 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1431 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1432 prevbuffer = resizebuffer;
1433 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1435 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1436 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1442 case GLTEXTURETYPE_3D:
1443 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1445 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1446 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1447 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1450 if (glt->flags & TEXF_MIPMAP)
1452 while (width > 1 || height > 1 || depth > 1)
1454 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1455 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1456 prevbuffer = resizebuffer;
1457 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1459 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1460 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1461 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1467 case GLTEXTURETYPE_CUBEMAP:
1468 // convert and upload each side in turn,
1469 // from a continuous block of input texels
1470 texturebuffer = (unsigned char *)prevbuffer;
1471 for (i = 0;i < 6;i++)
1473 prevbuffer = texturebuffer;
1474 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1475 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1477 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1478 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1479 prevbuffer = resizebuffer;
1482 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1484 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1485 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1486 prevbuffer = resizebuffer;
1489 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1491 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1492 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1495 if (glt->flags & TEXF_MIPMAP)
1497 while (width > 1 || height > 1 || depth > 1)
1499 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1500 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1501 prevbuffer = resizebuffer;
1502 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1504 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1505 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1514 glt->d3daddressw = 0;
1515 if (glt->flags & TEXF_CLAMP)
1517 glt->d3daddressu = D3DTADDRESS_CLAMP;
1518 glt->d3daddressv = D3DTADDRESS_CLAMP;
1519 if (glt->tiledepth > 1)
1520 glt->d3daddressw = D3DTADDRESS_CLAMP;
1524 glt->d3daddressu = D3DTADDRESS_WRAP;
1525 glt->d3daddressv = D3DTADDRESS_WRAP;
1526 if (glt->tiledepth > 1)
1527 glt->d3daddressw = D3DTADDRESS_WRAP;
1529 glt->d3dmipmaplodbias = 0;
1530 glt->d3dmaxmiplevel = 0;
1531 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1532 if (glt->flags & TEXF_FORCELINEAR)
1534 glt->d3dminfilter = D3DTEXF_LINEAR;
1535 glt->d3dmagfilter = D3DTEXF_LINEAR;
1536 glt->d3dmipfilter = D3DTEXF_POINT;
1538 else if (glt->flags & TEXF_FORCENEAREST)
1540 glt->d3dminfilter = D3DTEXF_POINT;
1541 glt->d3dmagfilter = D3DTEXF_POINT;
1542 glt->d3dmipfilter = D3DTEXF_POINT;
1544 else if (glt->flags & TEXF_MIPMAP)
1546 glt->d3dminfilter = d3d_filter_mipmin;
1547 glt->d3dmagfilter = d3d_filter_mipmag;
1548 glt->d3dmipfilter = d3d_filter_mipmix;
1552 glt->d3dminfilter = d3d_filter_flatmin;
1553 glt->d3dmagfilter = d3d_filter_flatmag;
1554 glt->d3dmipfilter = d3d_filter_flatmix;
1558 case RENDERPATH_D3D10:
1559 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1561 case RENDERPATH_D3D11:
1562 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1564 case RENDERPATH_SOFT:
1565 switch(glt->texturetype)
1567 case GLTEXTURETYPE_2D:
1568 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1570 case GLTEXTURETYPE_3D:
1571 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1573 case GLTEXTURETYPE_CUBEMAP:
1574 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1576 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1577 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1578 // convert and upload each side in turn,
1579 // from a continuous block of input texels
1580 // copy the results into combinedbuffer
1581 texturebuffer = (unsigned char *)prevbuffer;
1582 for (i = 0;i < 6;i++)
1584 prevbuffer = texturebuffer;
1585 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1586 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1588 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1589 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1590 prevbuffer = resizebuffer;
1593 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1595 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1596 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1597 prevbuffer = resizebuffer;
1599 memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1601 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1602 Mem_Free(combinedbuffer);
1605 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1608 if (glt->flags & TEXF_FORCELINEAR)
1609 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1610 else if (glt->flags & TEXF_FORCENEAREST)
1611 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1612 else if (glt->flags & TEXF_MIPMAP)
1613 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1615 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1620 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)
1624 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1625 textypeinfo_t *texinfo, *texinfo2;
1626 unsigned char *temppixels = NULL;
1629 if (cls.state == ca_dedicated)
1632 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1633 if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1635 int numpixels = width * height * depth * sides;
1636 size = numpixels * 4;
1637 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1640 const unsigned char *p;
1641 unsigned char *o = temppixels;
1642 for (i = 0;i < numpixels;i++, o += 4)
1644 p = (const unsigned char *)palette + 4*data[i];
1652 textype = TEXTYPE_RGBA;
1657 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1658 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1659 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1660 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1666 static int rgbaswapindices[4] = {2, 1, 0, 3};
1667 size = width * height * depth * sides * 4;
1668 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1670 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1674 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1675 if (!vid.support.ext_texture_srgb)
1677 qboolean convertsRGB = false;
1680 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1681 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1682 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1683 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1684 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;/*convertsRGB = true;*/break;
1685 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1686 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1690 if (convertsRGB && data)
1692 size = width * height * depth * sides * 4;
1695 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1696 memcpy(temppixels, data, size);
1699 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1703 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1705 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1708 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1710 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1714 texinfo = R_GetTexTypeInfo(textype, flags);
1715 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1718 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1722 // clear the alpha flag if the texture has no transparent pixels
1725 case TEXTYPE_PALETTE:
1726 case TEXTYPE_SRGB_PALETTE:
1727 if (flags & TEXF_ALPHA)
1729 flags &= ~TEXF_ALPHA;
1732 for (i = 0;i < size;i++)
1734 if (((unsigned char *)&palette[data[i]])[3] < 255)
1736 flags |= TEXF_ALPHA;
1745 case TEXTYPE_SRGB_RGBA:
1746 case TEXTYPE_SRGB_BGRA:
1747 if (flags & TEXF_ALPHA)
1749 flags &= ~TEXF_ALPHA;
1752 for (i = 3;i < size;i += 4)
1756 flags |= TEXF_ALPHA;
1763 case TEXTYPE_SHADOWMAP16_COMP:
1764 case TEXTYPE_SHADOWMAP16_RAW:
1765 case TEXTYPE_SHADOWMAP24_COMP:
1766 case TEXTYPE_SHADOWMAP24_RAW:
1769 case TEXTYPE_SRGB_DXT1:
1772 case TEXTYPE_SRGB_DXT1A:
1774 case TEXTYPE_SRGB_DXT3:
1776 case TEXTYPE_SRGB_DXT5:
1777 flags |= TEXF_ALPHA;
1780 flags |= TEXF_ALPHA;
1782 case TEXTYPE_COLORBUFFER:
1783 case TEXTYPE_COLORBUFFER16F:
1784 case TEXTYPE_COLORBUFFER32F:
1785 flags |= TEXF_ALPHA;
1788 Sys_Error("R_LoadTexture: unknown texture type");
1791 texinfo2 = R_GetTexTypeInfo(textype, flags);
1792 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1795 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1797 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1799 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1801 glt->chain = pool->gltchain;
1802 pool->gltchain = glt;
1803 glt->inputwidth = width;
1804 glt->inputheight = height;
1805 glt->inputdepth = depth;
1807 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
1808 glt->textype = texinfo;
1809 glt->texturetype = texturetype;
1810 glt->inputdatasize = size;
1811 glt->palette = palette;
1812 glt->glinternalformat = texinfo->glinternalformat;
1813 glt->glformat = texinfo->glformat;
1814 glt->gltype = texinfo->gltype;
1815 glt->bytesperpixel = texinfo->internalbytesperpixel;
1816 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1819 glt->glisdepthstencil = false;
1820 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1821 // init the dynamic texture attributes, too [11/22/2007 Black]
1822 glt->updatecallback = NULL;
1823 glt->updatecallback_data = NULL;
1825 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1827 // upload the texture
1828 // data may be NULL (blank texture for dynamic rendering)
1829 switch(vid.renderpath)
1831 case RENDERPATH_GL11:
1832 case RENDERPATH_GL13:
1833 case RENDERPATH_GL20:
1834 case RENDERPATH_GLES1:
1835 case RENDERPATH_GLES2:
1837 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1839 case RENDERPATH_D3D9:
1842 D3DFORMAT d3dformat;
1847 d3dpool = D3DPOOL_MANAGED;
1848 if (flags & TEXF_RENDERTARGET)
1850 d3dusage |= D3DUSAGE_RENDERTARGET;
1851 d3dpool = D3DPOOL_DEFAULT;
1855 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1856 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1857 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1858 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
1859 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
1860 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
1861 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1862 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1864 glt->d3dformat = d3dformat;
1865 glt->d3dusage = d3dusage;
1866 glt->d3dpool = d3dpool;
1867 glt->d3disrendertargetsurface = false;
1868 glt->d3disdepthstencilsurface = false;
1869 if (glt->tiledepth > 1)
1871 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)))
1872 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1874 else if (glt->sides == 6)
1876 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1877 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1881 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)))
1882 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1887 case RENDERPATH_D3D10:
1888 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1890 case RENDERPATH_D3D11:
1891 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1893 case RENDERPATH_SOFT:
1898 case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1899 case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1900 case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1901 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1902 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
1903 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
1904 case TEXTYPE_SHADOWMAP16_COMP:
1905 case TEXTYPE_SHADOWMAP16_RAW:
1906 case TEXTYPE_SHADOWMAP24_COMP:
1907 case TEXTYPE_SHADOWMAP24_RAW: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1908 case TEXTYPE_DEPTHBUFFER16:
1909 case TEXTYPE_DEPTHBUFFER24:
1910 case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1911 case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1912 default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1914 if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1915 if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1916 if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1917 if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1918 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1923 R_UploadFullTexture(glt, data);
1924 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1925 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1927 // free any temporary processing buffer we allocated...
1929 Mem_Free(temppixels);
1931 // texture converting and uploading can take a while, so make sure we're sending keepalives
1932 // FIXME: this causes rendering during R_Shadow_DrawLights
1933 // CL_KeepaliveMessage(false);
1935 return (rtexture_t *)glt;
1938 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)
1940 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1943 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)
1945 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1948 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)
1950 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1953 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter)
1955 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL);
1958 rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
1961 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1962 textypeinfo_t *texinfo;
1964 if (cls.state == ca_dedicated)
1967 texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP);
1969 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1971 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1973 glt->chain = pool->gltchain;
1974 pool->gltchain = glt;
1975 glt->inputwidth = width;
1976 glt->inputheight = height;
1977 glt->inputdepth = 1;
1978 glt->flags = TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_FORCENEAREST;
1980 glt->textype = texinfo;
1981 glt->texturetype = textype;
1982 glt->inputdatasize = width*height*texinfo->internalbytesperpixel;
1983 glt->palette = NULL;
1984 glt->glinternalformat = texinfo->glinternalformat;
1985 glt->glformat = texinfo->glformat;
1986 glt->gltype = texinfo->gltype;
1987 glt->bytesperpixel = texinfo->internalbytesperpixel;
1988 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1991 glt->glisdepthstencil = textype == TEXTYPE_DEPTHBUFFER24STENCIL8;
1992 glt->gltexturetypeenum = GL_TEXTURE_2D;
1993 // init the dynamic texture attributes, too [11/22/2007 Black]
1994 glt->updatecallback = NULL;
1995 glt->updatecallback_data = NULL;
1997 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1999 // upload the texture
2000 // data may be NULL (blank texture for dynamic rendering)
2001 switch(vid.renderpath)
2003 case RENDERPATH_GL11:
2004 case RENDERPATH_GL13:
2005 case RENDERPATH_GL20:
2006 case RENDERPATH_GLES1:
2007 case RENDERPATH_GLES2:
2009 qglGenRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
2010 qglBindRenderbuffer(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR
2011 qglRenderbufferStorage(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR
2012 // 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
2013 qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR
2015 case RENDERPATH_D3D9:
2018 D3DFORMAT d3dformat;
2020 glt->d3disrendertargetsurface = false;
2021 glt->d3disdepthstencilsurface = false;
2024 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;glt->d3disrendertargetsurface = true;break;
2025 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;glt->d3disrendertargetsurface = true;break;
2026 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;glt->d3disrendertargetsurface = true;break;
2027 case TEXTYPE_DEPTHBUFFER16: d3dformat = D3DFMT_D16;glt->d3disdepthstencilsurface = true;break;
2028 case TEXTYPE_DEPTHBUFFER24: d3dformat = D3DFMT_D24X8;glt->d3disdepthstencilsurface = true;break;
2029 case TEXTYPE_DEPTHBUFFER24STENCIL8: d3dformat = D3DFMT_D24S8;glt->d3disdepthstencilsurface = true;break;
2030 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2032 glt->d3dformat = d3dformat;
2035 if (glt->d3disrendertargetsurface)
2037 if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
2038 Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!");
2040 else if (glt->d3disdepthstencilsurface)
2042 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
2043 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
2048 case RENDERPATH_D3D10:
2049 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2051 case RENDERPATH_D3D11:
2052 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2054 case RENDERPATH_SOFT:
2059 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8 | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2060 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2061 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2062 case TEXTYPE_DEPTHBUFFER16:
2063 case TEXTYPE_DEPTHBUFFER24:
2064 case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2065 default: Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
2067 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
2072 return (rtexture_t *)glt;
2075 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
2078 return -1; // unsupported on this platform
2080 gltexture_t *glt = (gltexture_t *)rt;
2083 int bytesperpixel = 0;
2084 int bytesperblock = 0;
2086 int dds_format_flags;
2094 GLint internalformat;
2095 const char *ddsfourcc;
2097 return -1; // NULL pointer
2098 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
2099 return -2; // broken driver - crashes on reading internal format
2100 if (!qglGetTexLevelParameteriv)
2102 GL_ActiveTexture(0);
2103 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2104 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2105 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
2106 switch(internalformat)
2108 default: ddsfourcc = NULL;bytesperpixel = 4;break;
2109 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
2110 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
2111 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
2112 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
2114 // if premultiplied alpha, say so in the DDS file
2115 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
2117 switch(internalformat)
2119 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
2120 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
2123 if (!bytesperblock && skipuncompressed)
2124 return -3; // skipped
2125 memset(mipinfo, 0, sizeof(mipinfo));
2126 mipinfo[0][0] = glt->tilewidth;
2127 mipinfo[0][1] = glt->tileheight;
2129 if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1))
2131 for (mip = 1;mip < 16;mip++)
2133 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
2134 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
2135 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
2143 for (mip = 0;mip < mipmaps;mip++)
2145 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
2146 mipinfo[mip][3] = ddssize;
2147 ddssize += mipinfo[mip][2];
2149 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
2152 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
2156 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
2157 dds_format_flags = 0x4; // DDPF_FOURCC
2161 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
2162 dds_format_flags = 0x40; // DDPF_RGB
2166 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
2167 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
2170 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
2171 memcpy(dds, "DDS ", 4);
2172 StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
2173 StoreLittleLong(dds+8, dds_flags);
2174 StoreLittleLong(dds+12, mipinfo[0][1]); // height
2175 StoreLittleLong(dds+16, mipinfo[0][0]); // width
2176 StoreLittleLong(dds+24, 0); // depth
2177 StoreLittleLong(dds+28, mipmaps); // mipmaps
2178 StoreLittleLong(dds+76, 32); // format size
2179 StoreLittleLong(dds+80, dds_format_flags);
2180 StoreLittleLong(dds+108, dds_caps1);
2181 StoreLittleLong(dds+112, dds_caps2);
2184 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
2185 memcpy(dds+84, ddsfourcc, 4);
2186 for (mip = 0;mip < mipmaps;mip++)
2188 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
2193 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
2194 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
2195 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
2196 for (mip = 0;mip < mipmaps;mip++)
2198 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
2201 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2202 ret = FS_WriteFile(filename, dds, ddssize);
2204 return ret ? ddssize : -5;
2209 // ELUAN: FIXME: separate this code
2210 #include "ktx10/include/ktx.h"
2213 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
2215 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
2218 int bytesperblock, bytesperpixel;
2221 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
2222 textypeinfo_t *texinfo;
2223 int mip, mipwidth, mipheight, mipsize, mipsize_total;
2224 unsigned int c, r, g, b;
2225 GLint oldbindtexnum = 0;
2226 unsigned char *mippixels;
2227 unsigned char *mippixels_start;
2228 unsigned char *ddspixels;
2230 fs_offset_t ddsfilesize;
2231 unsigned int ddssize;
2232 qboolean force_swdecode, npothack;
2234 // ELUAN: FIXME: separate this code
2238 KTX_dimensions sizes;
2241 if (cls.state == ca_dedicated)
2245 // ELUAN: FIXME: separate this code
2246 if (vid.renderpath != RENDERPATH_GLES2)
2248 Con_DPrintf("KTX texture format is only supported on the GLES2 renderpath\n");
2252 // some textures are specified with extensions, so it becomes .tga.dds
2253 FS_StripExtension (filename, vabuf2, sizeof(vabuf2));
2254 FS_StripExtension (vabuf2, vabuf, sizeof(vabuf));
2255 FS_DefaultExtension (vabuf, ".ktx", sizeof(vabuf));
2256 strsize = strlen(vabuf);
2258 for (i = 0; i <= strsize - 4; i++) // copy null termination
2259 vabuf[i] = vabuf[i + 4];
2261 Con_DPrintf("Loading %s...\n", vabuf);
2262 dds = FS_LoadFile(vabuf, tempmempool, true, &ddsfilesize);
2263 ddssize = ddsfilesize;
2267 Con_DPrintf("Not found!\n");
2268 return NULL; // not found
2270 Con_DPrintf("Found!\n");
2272 if (flags & TEXF_ALPHA)
2274 Con_DPrintf("KTX texture with alpha not supported yet, disabling\n");
2275 flags &= ~TEXF_ALPHA;
2281 GLboolean isMipmapped;
2282 KTX_error_code ktxerror;
2284 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2286 // texture uploading can take a while, so make sure we're sending keepalives
2287 CL_KeepaliveMessage(false);
2289 // create the texture object
2291 GL_ActiveTexture(0);
2292 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[GLTEXTURETYPE_2D]);
2293 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2294 qglBindTexture(gltexturetypeenums[GLTEXTURETYPE_2D], glt->texnum);CHECKGLERROR
2296 // upload the texture
2297 // we need to restore the texture binding after finishing the upload
2299 // NOTE: some drivers fail with ETC1 NPOT (only PowerVR?). This may make the driver crash later.
2300 ktxerror = ktxLoadTextureM(dds, ddssize, &glt->texnum, &target, &sizes, &isMipmapped, &glerror,
2301 0, NULL);// can't CHECKGLERROR, the lib catches it
2303 // FIXME: delete texture if we fail here
2304 if (target != GL_TEXTURE_2D)
2306 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2308 Con_DPrintf("%s target != GL_TEXTURE_2D, target == %x\n", vabuf, target);
2309 return NULL; // FIXME: delete the texture from memory
2312 if (KTX_SUCCESS == ktxerror)
2314 textype = TEXTYPE_ETC1;
2315 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2317 // return whether this texture is transparent
2319 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2321 // TODO: apply gl_picmip
2324 // TODO: only load mipmaps if requested
2327 flags |= TEXF_MIPMAP;
2329 flags &= ~TEXF_MIPMAP;
2331 texinfo = R_GetTexTypeInfo(textype, flags);
2333 strlcpy (glt->identifier, vabuf, sizeof(glt->identifier));
2335 glt->chain = pool->gltchain;
2336 pool->gltchain = glt;
2337 glt->inputwidth = sizes.width;
2338 glt->inputheight = sizes.height;
2339 glt->inputdepth = 1;
2341 glt->textype = texinfo;
2342 glt->texturetype = GLTEXTURETYPE_2D;
2343 glt->inputdatasize = ddssize;
2344 glt->glinternalformat = texinfo->glinternalformat;
2345 glt->glformat = texinfo->glformat;
2346 glt->gltype = texinfo->gltype;
2347 glt->bytesperpixel = texinfo->internalbytesperpixel;
2349 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2350 glt->tilewidth = sizes.width;
2351 glt->tileheight = sizes.height;
2353 glt->miplevels = isMipmapped ? 1 : 0; // FIXME
2355 // after upload we have to set some parameters...
2356 #ifdef GL_TEXTURE_MAX_LEVEL
2358 if (dds_miplevels >= 1 && !mipcomplete)
2360 // need to set GL_TEXTURE_MAX_LEVEL
2361 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2365 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2367 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2369 return (rtexture_t *)glt;
2373 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2375 Con_DPrintf("KTX texture %s failed to load: %x\n", vabuf, ktxerror);
2379 #endif // __ANDROID__
2381 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
2382 ddssize = ddsfilesize;
2386 if (r_texture_dds_load_logfailure.integer && (r_texture_dds_load_logfailure.integer >= 2 || !optionaltexture))
2387 Log_Printf("ddstexturefailures.log", "%s\n", filename);
2388 return NULL; // not found
2391 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
2394 Con_Printf("^1%s: not a DDS image\n", filename);
2398 //dds_flags = BuffLittleLong(dds+8);
2399 dds_format_flags = BuffLittleLong(dds+80);
2400 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
2401 dds_width = BuffLittleLong(dds+16);
2402 dds_height = BuffLittleLong(dds+12);
2403 ddspixels = dds + 128;
2405 if(r_texture_dds_load_alphamode.integer == 0)
2406 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
2407 flags &= ~TEXF_ALPHA;
2409 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
2410 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
2412 // very sloppy BGRA 32bit identification
2413 textype = TEXTYPE_BGRA;
2414 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2417 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
2418 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2421 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
2424 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
2427 for (i = 3;i < size;i += 4)
2428 if (ddspixels[i] < 255)
2431 flags &= ~TEXF_ALPHA;
2434 else if (!memcmp(dds+84, "DXT1", 4))
2436 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
2437 // LordHavoc: it is my belief that this does not infringe on the
2438 // patent because it is not decoding pixels...
2439 textype = TEXTYPE_DXT1;
2442 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
2443 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2444 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2447 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
2450 if (flags & TEXF_ALPHA)
2452 if (r_texture_dds_load_alphamode.integer == 1)
2455 for (i = 0;i < size;i += bytesperblock)
2456 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
2458 // NOTE: this assumes sizeof(unsigned int) == 4
2459 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
2460 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
2461 if(data & (data<<1) & 0xAAAAAAAA)//rgh
2465 textype = TEXTYPE_DXT1A;
2467 flags &= ~TEXF_ALPHA;
2469 else if (r_texture_dds_load_alphamode.integer == 0)
2470 textype = TEXTYPE_DXT1A;
2473 flags &= ~TEXF_ALPHA;
2477 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2479 if(!memcmp(dds+84, "DXT2", 4))
2481 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2483 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2488 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2490 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2493 textype = TEXTYPE_DXT3;
2496 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2497 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2500 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2503 // we currently always assume alpha
2505 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2507 if(!memcmp(dds+84, "DXT4", 4))
2509 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2511 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2516 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2518 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2521 textype = TEXTYPE_DXT5;
2524 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2525 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2528 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2531 // we currently always assume alpha
2536 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2540 // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
2541 if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
2543 textype = TEXTYPE_DXT1;
2547 for (i = 0;i < (int)ddssize;i += bytesperblock)
2548 memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
2552 force_swdecode = false;
2554 (!vid.support.arb_texture_non_power_of_two &&
2556 (dds_width & (dds_width - 1))
2558 (dds_height & (dds_height - 1))
2563 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && !npothack)
2565 if(r_texture_dds_swdecode.integer > 1)
2566 force_swdecode = true;
2570 if(r_texture_dds_swdecode.integer < 1)
2576 force_swdecode = true;
2580 // return whether this texture is transparent
2582 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2584 // if we SW decode, choose 2 sizes bigger
2587 // this is quarter res, so do not scale down more than we have to
2591 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2594 // this is where we apply gl_picmip
2595 mippixels_start = ddspixels;
2596 mipwidth = dds_width;
2597 mipheight = dds_height;
2598 while(miplevel >= 1 && dds_miplevels >= 1)
2600 if (mipwidth <= 1 && mipheight <= 1)
2602 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2603 mippixels_start += mipsize; // just skip
2611 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2612 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2614 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2616 // fake decode S3TC if needed
2619 int mipsize_new = mipsize_total / bytesperblock * 4;
2620 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2621 unsigned char *p = mipnewpixels;
2622 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2624 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2625 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2626 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2627 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2628 if(textype == TEXTYPE_DXT5)
2629 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2630 else if(textype == TEXTYPE_DXT3)
2632 (mippixels_start[i-8] & 0x0F)
2633 + (mippixels_start[i-8] >> 4)
2634 + (mippixels_start[i-7] & 0x0F)
2635 + (mippixels_start[i-7] >> 4)
2636 + (mippixels_start[i-6] & 0x0F)
2637 + (mippixels_start[i-6] >> 4)
2638 + (mippixels_start[i-5] & 0x0F)
2639 + (mippixels_start[i-5] >> 4)
2640 ) * (0.125f / 15.0f * 255.0f);
2645 textype = TEXTYPE_BGRA;
2649 // as each block becomes a pixel, we must use pixel count for this
2650 mipwidth = (mipwidth + 3) / 4;
2651 mipheight = (mipheight + 3) / 4;
2652 mipsize = bytesperpixel * mipwidth * mipheight;
2653 mippixels_start = mipnewpixels;
2654 mipsize_total = mipsize_new;
2657 // start mip counting
2658 mippixels = mippixels_start;
2660 // calculate average color if requested
2664 Vector4Clear(avgcolor);
2667 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2669 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2670 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2671 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2672 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2673 if(textype == TEXTYPE_DXT5)
2674 avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f);
2675 else if(textype == TEXTYPE_DXT3)
2677 (mippixels_start[i-8] & 0x0F)
2678 + (mippixels_start[i-8] >> 4)
2679 + (mippixels_start[i-7] & 0x0F)
2680 + (mippixels_start[i-7] >> 4)
2681 + (mippixels_start[i-6] & 0x0F)
2682 + (mippixels_start[i-6] >> 4)
2683 + (mippixels_start[i-5] & 0x0F)
2684 + (mippixels_start[i-5] >> 4)
2685 ) * (0.125f / 15.0f);
2687 avgcolor[3] += 1.0f;
2689 f = (float)bytesperblock / mipsize;
2690 avgcolor[0] *= (0.5f / 31.0f) * f;
2691 avgcolor[1] *= (0.5f / 63.0f) * f;
2692 avgcolor[2] *= (0.5f / 31.0f) * f;
2697 for (i = 0;i < mipsize;i += 4)
2699 avgcolor[0] += mippixels[i+2];
2700 avgcolor[1] += mippixels[i+1];
2701 avgcolor[2] += mippixels[i];
2702 avgcolor[3] += mippixels[i+3];
2704 f = (1.0f / 255.0f) * bytesperpixel / mipsize;
2712 // if we want sRGB, convert now
2715 if (vid.support.ext_texture_srgb)
2719 case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break;
2720 case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break;
2721 case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break;
2722 case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break;
2723 case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break;
2737 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2739 int c0, c1, c0new, c1new;
2740 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2741 r = ((c0 >> 11) & 0x1F);
2742 g = ((c0 >> 5) & 0x3F);
2744 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2745 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2746 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2747 c0new = (r << 11) | (g << 5) | b;
2748 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2749 r = ((c1 >> 11) & 0x1F);
2750 g = ((c1 >> 5) & 0x3F);
2752 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2753 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2754 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2755 c1new = (r << 11) | (g << 5) | b;
2756 // swap the colors if needed to fix order
2757 if(c0 > c1) // thirds
2765 mippixels_start[i+4] ^= 0x55;
2766 mippixels_start[i+5] ^= 0x55;
2767 mippixels_start[i+6] ^= 0x55;
2768 mippixels_start[i+7] ^= 0x55;
2770 else if(c0new == c1new)
2772 mippixels_start[i+4] = 0x00;
2773 mippixels_start[i+5] = 0x00;
2774 mippixels_start[i+6] = 0x00;
2775 mippixels_start[i+7] = 0x00;
2778 else // half + transparent
2785 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2786 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2787 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2788 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2791 mippixels_start[i] = c0new & 255;
2792 mippixels_start[i+1] = c0new >> 8;
2793 mippixels_start[i+2] = c1new & 255;
2794 mippixels_start[i+3] = c1new >> 8;
2799 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2807 // when not requesting mipmaps, do not load them
2808 if(!(flags & TEXF_MIPMAP))
2811 if (dds_miplevels >= 1)
2812 flags |= TEXF_MIPMAP;
2814 flags &= ~TEXF_MIPMAP;
2816 texinfo = R_GetTexTypeInfo(textype, flags);
2818 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2819 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2821 glt->chain = pool->gltchain;
2822 pool->gltchain = glt;
2823 glt->inputwidth = mipwidth;
2824 glt->inputheight = mipheight;
2825 glt->inputdepth = 1;
2827 glt->textype = texinfo;
2828 glt->texturetype = GLTEXTURETYPE_2D;
2829 glt->inputdatasize = ddssize;
2830 glt->glinternalformat = texinfo->glinternalformat;
2831 glt->glformat = texinfo->glformat;
2832 glt->gltype = texinfo->gltype;
2833 glt->bytesperpixel = texinfo->internalbytesperpixel;
2835 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2836 glt->tilewidth = mipwidth;
2837 glt->tileheight = mipheight;
2839 glt->miplevels = dds_miplevels;
2843 for (glt->tilewidth = 1;glt->tilewidth < mipwidth;glt->tilewidth <<= 1);
2844 for (glt->tileheight = 1;glt->tileheight < mipheight;glt->tileheight <<= 1);
2847 // texture uploading can take a while, so make sure we're sending keepalives
2848 CL_KeepaliveMessage(false);
2850 // create the texture object
2851 switch(vid.renderpath)
2853 case RENDERPATH_GL11:
2854 case RENDERPATH_GL13:
2855 case RENDERPATH_GL20:
2856 case RENDERPATH_GLES1:
2857 case RENDERPATH_GLES2:
2859 GL_ActiveTexture(0);
2860 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2861 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2862 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2864 case RENDERPATH_D3D9:
2867 D3DFORMAT d3dformat;
2872 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2873 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2874 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2875 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2876 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2879 d3dpool = D3DPOOL_MANAGED;
2880 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2884 case RENDERPATH_D3D10:
2885 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2887 case RENDERPATH_D3D11:
2888 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2890 case RENDERPATH_SOFT:
2891 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);
2895 // upload the texture
2896 // we need to restore the texture binding after finishing the upload
2897 mipcomplete = false;
2899 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2901 unsigned char *upload_mippixels = mippixels;
2902 int upload_mipwidth = mipwidth;
2903 int upload_mipheight = mipheight;
2904 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2905 if (mippixels + mipsize > mippixels_start + mipsize_total)
2909 upload_mipwidth = (glt->tilewidth >> mip);
2910 upload_mipheight = (glt->tileheight >> mip);
2911 if(upload_mipwidth != mipwidth || upload_mipheight != mipheight)
2912 // I _think_ they always mismatch, but I was too lazy
2913 // to properly check, and this test here is really
2916 upload_mippixels = (unsigned char *) Mem_Alloc(tempmempool, 4 * upload_mipwidth * upload_mipheight);
2917 Image_Resample32(mippixels, mipwidth, mipheight, 1, upload_mippixels, upload_mipwidth, upload_mipheight, 1, r_lerpimages.integer);
2920 switch(vid.renderpath)
2922 case RENDERPATH_GL11:
2923 case RENDERPATH_GL13:
2924 case RENDERPATH_GL20:
2925 case RENDERPATH_GLES1:
2926 case RENDERPATH_GLES2:
2929 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR
2933 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR
2936 case RENDERPATH_D3D9:
2939 D3DLOCKED_RECT d3dlockedrect;
2940 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2942 memcpy(d3dlockedrect.pBits, upload_mippixels, mipsize);
2943 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2949 case RENDERPATH_D3D10:
2950 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2952 case RENDERPATH_D3D11:
2953 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2955 case RENDERPATH_SOFT:
2957 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2959 DPSOFTRAST_Texture_UpdateFull(glt->texnum, upload_mippixels);
2960 // DPSOFTRAST calculates its own mipmaps
2961 mip = dds_miplevels;
2964 if(upload_mippixels != mippixels)
2965 Mem_Free(upload_mippixels);
2966 mippixels += mipsize;
2967 if (mipwidth <= 1 && mipheight <= 1)
2978 // after upload we have to set some parameters...
2979 switch(vid.renderpath)
2981 case RENDERPATH_GL11:
2982 case RENDERPATH_GL13:
2983 case RENDERPATH_GL20:
2984 case RENDERPATH_GLES1:
2985 case RENDERPATH_GLES2:
2986 #ifdef GL_TEXTURE_MAX_LEVEL
2987 if (dds_miplevels >= 1 && !mipcomplete)
2989 // need to set GL_TEXTURE_MAX_LEVEL
2990 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2993 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2994 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2996 case RENDERPATH_D3D9:
2998 glt->d3daddressw = 0;
2999 if (glt->flags & TEXF_CLAMP)
3001 glt->d3daddressu = D3DTADDRESS_CLAMP;
3002 glt->d3daddressv = D3DTADDRESS_CLAMP;
3003 if (glt->tiledepth > 1)
3004 glt->d3daddressw = D3DTADDRESS_CLAMP;
3008 glt->d3daddressu = D3DTADDRESS_WRAP;
3009 glt->d3daddressv = D3DTADDRESS_WRAP;
3010 if (glt->tiledepth > 1)
3011 glt->d3daddressw = D3DTADDRESS_WRAP;
3013 glt->d3dmipmaplodbias = 0;
3014 glt->d3dmaxmiplevel = 0;
3015 glt->d3dmaxmiplevelfilter = 0;
3016 if (glt->flags & TEXF_MIPMAP)
3018 glt->d3dminfilter = d3d_filter_mipmin;
3019 glt->d3dmagfilter = d3d_filter_mipmag;
3020 glt->d3dmipfilter = d3d_filter_mipmix;
3024 glt->d3dminfilter = d3d_filter_flatmin;
3025 glt->d3dmagfilter = d3d_filter_flatmag;
3026 glt->d3dmipfilter = d3d_filter_flatmix;
3030 case RENDERPATH_D3D10:
3031 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3033 case RENDERPATH_D3D11:
3034 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3036 case RENDERPATH_SOFT:
3037 if (glt->flags & TEXF_FORCELINEAR)
3038 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
3039 else if (glt->flags & TEXF_FORCENEAREST)
3040 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
3041 else if (glt->flags & TEXF_MIPMAP)
3042 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
3044 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
3050 Mem_Free((unsigned char *) mippixels_start);
3051 return (rtexture_t *)glt;
3054 int R_TextureWidth(rtexture_t *rt)
3056 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
3059 int R_TextureHeight(rtexture_t *rt)
3061 return rt ? ((gltexture_t *)rt)->inputheight : 0;
3064 int R_TextureFlags(rtexture_t *rt)
3066 return rt ? ((gltexture_t *)rt)->flags : 0;
3069 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
3071 gltexture_t *glt = (gltexture_t *)rt;
3073 Host_Error("R_UpdateTexture: no data supplied");
3075 Host_Error("R_UpdateTexture: no texture supplied");
3076 if (!glt->texnum && !glt->d3dtexture)
3078 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
3081 // update part of the texture
3082 if (glt->bufferpixels)
3085 int bpp = glt->bytesperpixel;
3086 int inputskip = width*bpp;
3087 int outputskip = glt->tilewidth*bpp;
3088 const unsigned char *input = data;
3089 unsigned char *output = glt->bufferpixels;
3090 if (glt->inputdepth != 1 || glt->sides != 1)
3091 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
3101 input -= y*inputskip;
3104 if (width > glt->tilewidth - x)
3105 width = glt->tilewidth - x;
3106 if (height > glt->tileheight - y)
3107 height = glt->tileheight - y;
3108 if (width < 1 || height < 1)
3111 glt->buffermodified = true;
3112 output += y*outputskip + x*bpp;
3113 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
3114 memcpy(output, input, width*bpp);
3116 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
3117 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
3119 R_UploadFullTexture(glt, data);
3122 int R_RealGetTexture(rtexture_t *rt)
3127 glt = (gltexture_t *)rt;
3128 if (glt->flags & GLTEXF_DYNAMIC)
3129 R_UpdateDynamicTexture(glt);
3130 if (glt->buffermodified && glt->bufferpixels)
3132 glt->buffermodified = false;
3133 R_UploadFullTexture(glt, glt->bufferpixels);
3142 void R_ClearTexture (rtexture_t *rt)
3144 gltexture_t *glt = (gltexture_t *)rt;
3146 R_UploadFullTexture(glt, NULL);
3149 int R_PicmipForFlags(int flags)
3152 if(flags & TEXF_PICMIP)
3154 miplevel += gl_picmip.integer;
3155 if (flags & TEXF_ISWORLD)
3157 if (r_picmipworld.integer)
3158 miplevel += gl_picmip_world.integer;
3162 else if (flags & TEXF_ISSPRITE)
3164 if (r_picmipsprites.integer)
3165 miplevel += gl_picmip_sprites.integer;
3170 miplevel += gl_picmip_other.integer;
3172 return max(0, miplevel);