6 #include "intoverflow.h"
9 #define GL_TEXTURE_3D 0x806F
12 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)"};
13 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)"};
14 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%"};
15 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)"};
16 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)"};
17 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)"};
18 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)"};
19 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)"};
20 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)"};
21 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"};
22 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"};
23 cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
24 cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
25 cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
26 cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
27 cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
28 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
29 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)"};
30 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
31 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
32 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)"};
33 cvar_t gl_texturecompression_sprites = {CVAR_SAVE, "gl_texturecompression_sprites", "1", "whether to compress sprites"};
34 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"};
35 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"};
36 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"};
37 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"};
39 qboolean gl_filter_force = false;
40 int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
41 int gl_filter_mag = GL_LINEAR;
44 static mempool_t *texturemempool;
45 static memexpandablearray_t texturearray;
47 // note: this must not conflict with TEXF_ flags in r_textures.h
48 // bitmask for mismatch checking
49 #define GLTEXF_IMPORTANTBITS (0)
50 // dynamic texture (treat texnum == 0 differently)
51 #define GLTEXF_DYNAMIC 0x00080000
53 typedef struct textypeinfo_s
57 int inputbytesperpixel;
58 int internalbytesperpixel;
59 float glinternalbytesperpixel;
68 // we use these internally even if we never deliver such data to the driver
70 #define GL_BGRA 0x80E1
72 // framebuffer texture formats
73 // GLES2 devices rarely support depth textures, so we actually use a renderbuffer there
74 static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
75 static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
76 static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
77 static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
78 static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
79 static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
80 static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
81 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 2, 2, 2.0f, GL_RGB565 , GL_RGBA , GL_UNSIGNED_SHORT_5_6_5};
82 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 2, 2, 2.0f, GL_RGBA16F , GL_RGBA , GL_HALF_FLOAT_ARB};
83 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 2, 2, 2.0f, GL_RGBA32F , GL_RGBA , GL_FLOAT};
86 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
87 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
88 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
89 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
90 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
91 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
92 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
94 static textypeinfo_t textype_etc1 = {"etc1", TEXTYPE_ETC1 , 1, 3, 0.5f, GL_ETC1_RGB8_OES , 0 , 0 };
97 // framebuffer texture formats
98 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};
99 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};
100 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 };
101 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 };
102 static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
103 static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
104 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};
105 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
106 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 8, 8, 8.0f, GL_RGBA16F_ARB , GL_RGBA , GL_HALF_FLOAT_ARB};
107 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 16, 16, 16.0f, GL_RGBA32F_ARB , GL_RGBA , GL_FLOAT };
110 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
111 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
112 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
113 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE };
114 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
115 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 };
116 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 };
117 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
118 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
119 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 };
120 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 };
121 static textypeinfo_t textype_dxt1 = {"dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
122 static textypeinfo_t textype_dxt1a = {"dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 };
123 static textypeinfo_t textype_dxt3 = {"dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 };
124 static textypeinfo_t textype_dxt5 = {"dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 };
125 static textypeinfo_t textype_sRGB_palette = {"sRGB_palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
126 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 };
127 static textypeinfo_t textype_sRGB_rgba = {"sRGB_rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
128 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 };
129 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 };
130 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 };
131 static textypeinfo_t textype_sRGB_bgra = {"sRGB_bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
132 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 };
133 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 };
134 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 };
135 static textypeinfo_t textype_sRGB_dxt1 = {"sRGB_dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , 0 , 0 };
136 static textypeinfo_t textype_sRGB_dxt1a = {"sRGB_dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 , 0 };
137 static textypeinfo_t textype_sRGB_dxt3 = {"sRGB_dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 , 0 };
138 static textypeinfo_t textype_sRGB_dxt5 = {"sRGB_dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 , 0 };
141 typedef enum gltexturetype_e
145 GLTEXTURETYPE_CUBEMAP,
150 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP};
151 #ifdef GL_TEXTURE_WRAP_R
152 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
154 static int cubemapside[6] =
156 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
157 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
158 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
159 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
160 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
161 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
164 typedef struct gltexture_s
166 // this portion of the struct is exposed to the R_GetTexture macro for
167 // speed reasons, must be identical in rtexture_t!
168 int texnum; // GL texture slot number
169 int renderbuffernum; // GL renderbuffer slot number
170 qboolean dirty; // indicates that R_RealGetTexture should be called
171 qboolean glisdepthstencil; // indicates that FBO attachment has to be GL_DEPTH_STENCIL_ATTACHMENT
172 int gltexturetypeenum; // used by R_Mesh_TexBind
174 // dynamic texture stuff [11/22/2007 Black]
175 updatecallback_t updatecallback;
176 void *updatecallback_data;
177 // --- [11/22/2007 Black]
179 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
180 unsigned char *bufferpixels;
181 qboolean buffermodified;
183 // pointer to texturepool (check this to see if the texture is allocated)
184 struct gltexturepool_s *pool;
185 // pointer to next texture in texturepool chain
186 struct gltexture_s *chain;
187 // name of the texture (this might be removed someday), no duplicates
188 char identifier[MAX_QPATH + 32];
189 // original data size in *inputtexels
190 int inputwidth, inputheight, inputdepth;
191 // copy of the original texture(s) supplied to the upload function, for
192 // delayed uploads (non-precached)
193 unsigned char *inputtexels;
194 // original data size in *inputtexels
196 // flags supplied to the LoadTexture function
197 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
201 // pointer to one of the textype_ structs
202 textypeinfo_t *textype;
203 // one of the GLTEXTURETYPE_ values
205 // palette if the texture is TEXTYPE_PALETTE
206 const unsigned int *palette;
207 // actual stored texture size after gl_picmip and gl_max_size are applied
208 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
209 int tilewidth, tileheight, tiledepth;
210 // 1 or 6 depending on texturetype
212 // how many mipmap levels in this texture
216 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
219 int glinternalformat;
220 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
225 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
227 typedef struct gltexturepool_s
229 unsigned int sentinel;
230 struct gltexture_s *gltchain;
231 struct gltexturepool_s *next;
235 static gltexturepool_t *gltexturepoolchain = NULL;
237 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
238 static int resizebuffersize = 0;
239 static const unsigned char *texturebuffer;
241 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
246 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
247 case TEXTYPE_RGBA: return ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba);
248 case TEXTYPE_BGRA: return ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra);
250 case TEXTYPE_ETC1: return &textype_etc1;
252 case TEXTYPE_ALPHA: return &textype_alpha;
253 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
254 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
255 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
256 case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
257 case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
258 case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
259 case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
260 case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
261 case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
262 case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
264 case TEXTYPE_DXT1: return &textype_dxt1;
265 case TEXTYPE_DXT1A: return &textype_dxt1a;
266 case TEXTYPE_DXT3: return &textype_dxt3;
267 case TEXTYPE_DXT5: return &textype_dxt5;
268 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
269 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);
270 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);
271 case TEXTYPE_ALPHA: return &textype_alpha;
272 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
273 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
274 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
275 case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
276 case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
277 case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
278 case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
279 case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
280 case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
281 case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
282 case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1;
283 case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a;
284 case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
285 case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
286 case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
287 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);
288 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);
291 Host_Error("R_GetTexTypeInfo: unknown texture format %i with flags %x", (int)textype, flags);
297 // dynamic texture code [11/22/2007 Black]
298 void R_MarkDirtyTexture(rtexture_t *rt) {
299 gltexture_t *glt = (gltexture_t*) rt;
304 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
305 if (glt->flags & GLTEXF_DYNAMIC)
307 // mark it as dirty, so R_RealGetTexture gets called
312 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
313 gltexture_t *glt = (gltexture_t*) rt;
318 glt->flags |= GLTEXF_DYNAMIC;
319 glt->updatecallback = updatecallback;
320 glt->updatecallback_data = data;
323 static void R_UpdateDynamicTexture(gltexture_t *glt) {
325 if( glt->updatecallback ) {
326 glt->updatecallback( (rtexture_t*) glt, glt->updatecallback_data );
330 void R_PurgeTexture(rtexture_t *rt)
332 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
337 void R_FreeTexture(rtexture_t *rt)
339 gltexture_t *glt, **gltpointer;
341 glt = (gltexture_t *)rt;
343 Host_Error("R_FreeTexture: texture == NULL");
345 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
346 if (*gltpointer == glt)
347 *gltpointer = glt->chain;
349 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
351 R_Mesh_ClearBindingsForTexture(glt->texnum);
353 switch(vid.renderpath)
355 case RENDERPATH_GL20:
356 case RENDERPATH_GLES2:
360 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
362 if (glt->renderbuffernum)
365 qglDeleteRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
370 if (glt->inputtexels)
371 Mem_Free(glt->inputtexels);
372 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
375 rtexturepool_t *R_AllocTexturePool(void)
377 gltexturepool_t *pool;
378 if (texturemempool == NULL)
380 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
383 pool->next = gltexturepoolchain;
384 gltexturepoolchain = pool;
385 pool->sentinel = TEXTUREPOOL_SENTINEL;
386 return (rtexturepool_t *)pool;
389 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
391 gltexturepool_t *pool, **poolpointer;
392 if (rtexturepool == NULL)
394 if (*rtexturepool == NULL)
396 pool = (gltexturepool_t *)(*rtexturepool);
397 *rtexturepool = NULL;
398 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
399 Host_Error("R_FreeTexturePool: pool already freed");
400 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
401 if (*poolpointer == pool)
402 *poolpointer = pool->next;
404 Host_Error("R_FreeTexturePool: pool not linked");
405 while (pool->gltchain)
406 R_FreeTexture((rtexture_t *)pool->gltchain);
411 typedef struct glmode_s
414 int minification, magnification;
418 static glmode_t modes[6] =
420 {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
421 {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
422 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
423 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
424 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
425 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
428 static void GL_TextureMode_f (void)
433 gltexturepool_t *pool;
437 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
438 for (i = 0;i < 6;i++)
440 if (gl_filter_min == modes[i].minification)
442 Con_Printf("%s\n", modes[i].name);
446 Con_Print("current filter is unknown???\n");
450 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
451 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
455 Con_Print("bad filter name\n");
459 gl_filter_min = modes[i].minification;
460 gl_filter_mag = modes[i].magnification;
461 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
463 switch(vid.renderpath)
465 case RENDERPATH_GL20:
466 case RENDERPATH_GLES2:
467 // change all the existing mipmap texture objects
468 // FIXME: force renderer(/client/something?) restart instead?
471 for (pool = gltexturepoolchain;pool;pool = pool->next)
473 for (glt = pool->gltchain;glt;glt = glt->chain)
475 // only update already uploaded images
476 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
478 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
479 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
480 if (glt->flags & TEXF_MIPMAP)
482 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
486 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
488 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
489 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
497 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)
499 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
504 case GLTEXTURETYPE_2D:
505 maxsize = vid.maxtexturesize_2d;
506 if (flags & TEXF_PICMIP)
508 maxsize = bound(1, gl_max_size.integer, maxsize);
512 case GLTEXTURETYPE_3D:
513 maxsize = vid.maxtexturesize_3d;
515 case GLTEXTURETYPE_CUBEMAP:
516 maxsize = vid.maxtexturesize_cubemap;
520 if (vid.support.arb_texture_non_power_of_two)
522 width2 = min(inwidth >> picmip, maxsize);
523 height2 = min(inheight >> picmip, maxsize);
524 depth2 = min(indepth >> picmip, maxsize);
528 for (width2 = 1;width2 < inwidth;width2 <<= 1);
529 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
530 for (height2 = 1;height2 < inheight;height2 <<= 1);
531 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
532 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
533 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
537 if (flags & TEXF_MIPMAP)
539 int extent = max(width2, max(height2, depth2));
545 *outwidth = max(1, width2);
547 *outheight = max(1, height2);
549 *outdepth = max(1, depth2);
551 *outmiplevels = miplevels;
555 static int R_CalcTexelDataSize (gltexture_t *glt)
557 int width2, height2, depth2, size;
559 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
561 size = width2 * height2 * depth2;
563 if (glt->flags & TEXF_MIPMAP)
565 while (width2 > 1 || height2 > 1 || depth2 > 1)
573 size += width2 * height2 * depth2;
577 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
580 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
584 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
585 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
587 gltexturepool_t *pool;
589 Con_Print("glsize input loaded mip alpha name\n");
590 for (pool = gltexturepoolchain;pool;pool = pool->next)
598 for (glt = pool->gltchain;glt;glt = glt->chain)
600 glsize = R_CalcTexelDataSize(glt);
601 isloaded = glt->texnum != 0 || glt->renderbuffernum != 0;
603 pooltotalt += glsize;
604 pooltotalp += glt->inputdatasize;
608 poolloadedt += glsize;
609 poolloadedp += glt->inputdatasize;
612 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);
615 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);
616 sumtotal += pooltotal;
617 sumtotalt += pooltotalt;
618 sumtotalp += pooltotalp;
619 sumloaded += poolloaded;
620 sumloadedt += poolloadedt;
621 sumloadedp += poolloadedp;
624 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);
627 static void R_TextureStats_f(void)
629 R_TextureStats_Print(true, true, true);
632 static void r_textures_start(void)
634 switch(vid.renderpath)
636 case RENDERPATH_GL20:
637 case RENDERPATH_GLES2:
638 // LordHavoc: allow any alignment
640 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
641 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
645 texturemempool = Mem_AllocPool("texture management", 0, NULL);
646 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
648 // Disable JPEG screenshots if the DLL isn't loaded
649 if (! JPEG_OpenLibrary ())
650 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
651 if (! PNG_OpenLibrary ())
652 Cvar_SetValueQuick (&scr_screenshot_png, 0);
655 static void r_textures_shutdown(void)
657 rtexturepool_t *temp;
659 JPEG_CloseLibrary ();
661 while(gltexturepoolchain)
663 temp = (rtexturepool_t *) gltexturepoolchain;
664 R_FreeTexturePool(&temp);
667 resizebuffersize = 0;
669 colorconvertbuffer = NULL;
670 texturebuffer = NULL;
671 Mem_ExpandableArray_FreeArray(&texturearray);
672 Mem_FreePool(&texturemempool);
675 static void r_textures_newmap(void)
679 static void r_textures_devicelost(void)
683 endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
684 for (i = 0;i < endindex;i++)
686 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
687 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
689 switch(vid.renderpath)
691 case RENDERPATH_GL20:
692 case RENDERPATH_GLES2:
698 static void r_textures_devicerestored(void)
702 endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
703 for (i = 0;i < endindex;i++)
705 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
706 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
708 switch(vid.renderpath)
710 case RENDERPATH_GL20:
711 case RENDERPATH_GLES2:
718 void R_Textures_Init (void)
720 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");
721 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
722 Cvar_RegisterVariable (&gl_max_size);
723 Cvar_RegisterVariable (&gl_picmip);
724 Cvar_RegisterVariable (&gl_picmip_world);
725 Cvar_RegisterVariable (&r_picmipworld);
726 Cvar_RegisterVariable (&gl_picmip_sprites);
727 Cvar_RegisterVariable (&r_picmipsprites);
728 Cvar_RegisterVariable (&gl_picmip_other);
729 Cvar_RegisterVariable (&gl_max_lightmapsize);
730 Cvar_RegisterVariable (&r_lerpimages);
731 Cvar_RegisterVariable (&gl_texture_anisotropy);
732 Cvar_RegisterVariable (&gl_texturecompression);
733 Cvar_RegisterVariable (&gl_texturecompression_color);
734 Cvar_RegisterVariable (&gl_texturecompression_normal);
735 Cvar_RegisterVariable (&gl_texturecompression_gloss);
736 Cvar_RegisterVariable (&gl_texturecompression_glow);
737 Cvar_RegisterVariable (&gl_texturecompression_2d);
738 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
739 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
740 Cvar_RegisterVariable (&gl_texturecompression_sky);
741 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
742 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
743 Cvar_RegisterVariable (&gl_texturecompression_sprites);
744 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
745 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
746 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
747 Cvar_RegisterVariable (&r_texture_dds_swdecode);
749 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
752 void R_Textures_Frame (void)
754 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
755 static int old_aniso = 0;
756 static qboolean first_time_aniso = true;
759 // could do procedural texture animation here, if we keep track of which
760 // textures were accessed this frame...
762 // free the resize buffers
763 resizebuffersize = 0;
766 Mem_Free(resizebuffer);
769 if (colorconvertbuffer)
771 Mem_Free(colorconvertbuffer);
772 colorconvertbuffer = NULL;
775 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
776 if (old_aniso != gl_texture_anisotropy.integer)
779 gltexturepool_t *pool;
782 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
784 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
786 switch(vid.renderpath)
788 case RENDERPATH_GL20:
789 case RENDERPATH_GLES2:
790 // ignore the first difference, any textures loaded by now probably had the same aniso value
791 if (first_time_aniso)
793 first_time_aniso = false;
798 for (pool = gltexturepoolchain;pool;pool = pool->next)
800 for (glt = pool->gltchain;glt;glt = glt->chain)
802 // only update already uploaded images
803 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
805 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
807 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
808 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
810 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
820 static void R_MakeResizeBufferBigger(int size)
822 if (resizebuffersize < size)
824 resizebuffersize = size;
826 Mem_Free(resizebuffer);
827 if (colorconvertbuffer)
828 Mem_Free(colorconvertbuffer);
829 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
830 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
831 if (!resizebuffer || !colorconvertbuffer)
832 Host_Error("R_Upload: out of memory");
836 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
838 int textureenum = gltexturetypeenums[texturetype];
839 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
843 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
844 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
846 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
847 if (gl_texture_anisotropy.integer != aniso)
848 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
849 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
852 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
853 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
854 #ifdef GL_TEXTURE_WRAP_R
855 if (gltexturetypedimensions[texturetype] >= 3)
857 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
862 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
864 if (flags & TEXF_MIPMAP)
866 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
870 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
872 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
874 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
876 if (flags & TEXF_MIPMAP)
878 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
880 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
884 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
889 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
891 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
895 if (flags & TEXF_MIPMAP)
897 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
901 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
903 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
906 #ifdef GL_TEXTURE_COMPARE_MODE_ARB
909 case TEXTYPE_SHADOWMAP16_COMP:
910 case TEXTYPE_SHADOWMAP24_COMP:
911 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
912 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
913 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
915 case TEXTYPE_SHADOWMAP16_RAW:
916 case TEXTYPE_SHADOWMAP24_RAW:
917 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
918 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
919 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
929 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
932 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
934 if (glt->texturetype != GLTEXTURETYPE_2D)
935 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
937 if (glt->textype->textype == TEXTYPE_PALETTE)
938 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
940 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
941 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
943 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
944 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
946 // update a portion of the image
948 switch(vid.renderpath)
950 case RENDERPATH_GL20:
951 case RENDERPATH_GLES2:
955 // we need to restore the texture binding after finishing the upload
957 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
958 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
959 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
960 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
966 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
968 int i, mip = 0, width, height, depth;
969 GLint oldbindtexnum = 0;
970 const unsigned char *prevbuffer;
973 // error out if a stretch is needed on special texture types
974 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
975 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
977 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
978 // of the target size and then use the mipmap reduction function to get
979 // high quality supersampled results
980 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
981 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
982 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
984 if (prevbuffer == NULL)
986 width = glt->tilewidth;
987 height = glt->tileheight;
988 depth = glt->tiledepth;
989 // R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
990 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
991 // prevbuffer = resizebuffer;
995 if (glt->textype->textype == TEXTYPE_PALETTE)
997 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
998 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
999 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1000 prevbuffer = colorconvertbuffer;
1002 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1004 // multiply RGB channels by A channel before uploading
1006 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1007 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1009 alpha = prevbuffer[i+3];
1010 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1011 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1012 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1013 colorconvertbuffer[i+3] = alpha;
1015 prevbuffer = colorconvertbuffer;
1017 // scale up to a power of 2 size (if appropriate)
1018 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1020 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1021 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1022 prevbuffer = resizebuffer;
1024 // apply mipmap reduction algorithm to get down to picmip/max_size
1025 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1027 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1028 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1029 prevbuffer = resizebuffer;
1033 // do the appropriate upload type...
1034 switch(vid.renderpath)
1036 case RENDERPATH_GL20:
1037 case RENDERPATH_GLES2:
1038 if (glt->texnum) // not renderbuffers
1042 // we need to restore the texture binding after finishing the upload
1043 GL_ActiveTexture(0);
1044 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1045 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1048 #ifdef GL_TEXTURE_COMPRESSION_HINT_ARB
1049 if (qglGetCompressedTexImageARB)
1051 if (gl_texturecompression.integer >= 2)
1052 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1054 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1059 switch(glt->texturetype)
1061 case GLTEXTURETYPE_2D:
1062 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1063 if (glt->flags & TEXF_MIPMAP)
1065 while (width > 1 || height > 1 || depth > 1)
1067 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1068 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1069 prevbuffer = resizebuffer;
1070 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1074 case GLTEXTURETYPE_3D:
1076 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1077 if (glt->flags & TEXF_MIPMAP)
1079 while (width > 1 || height > 1 || depth > 1)
1081 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1082 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1083 prevbuffer = resizebuffer;
1084 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1089 case GLTEXTURETYPE_CUBEMAP:
1090 // convert and upload each side in turn,
1091 // from a continuous block of input texels
1092 texturebuffer = (unsigned char *)prevbuffer;
1093 for (i = 0;i < 6;i++)
1095 prevbuffer = texturebuffer;
1096 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1097 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1099 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1100 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1101 prevbuffer = resizebuffer;
1104 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1106 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1107 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1108 prevbuffer = resizebuffer;
1111 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1112 if (glt->flags & TEXF_MIPMAP)
1114 while (width > 1 || height > 1 || depth > 1)
1116 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1117 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1118 prevbuffer = resizebuffer;
1119 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1125 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1126 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1132 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)
1136 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1137 textypeinfo_t *texinfo, *texinfo2;
1138 unsigned char *temppixels = NULL;
1141 if (cls.state == ca_dedicated)
1144 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1145 if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1147 int numpixels = width * height * depth * sides;
1148 size = numpixels * 4;
1149 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1152 const unsigned char *p;
1153 unsigned char *o = temppixels;
1154 for (i = 0;i < numpixels;i++, o += 4)
1156 p = (const unsigned char *)palette + 4*data[i];
1164 textype = TEXTYPE_RGBA;
1169 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1170 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1171 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1172 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1178 static int rgbaswapindices[4] = {2, 1, 0, 3};
1179 size = width * height * depth * sides * 4;
1180 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1182 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1186 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1187 if (!vid.support.ext_texture_srgb)
1189 qboolean convertsRGB = false;
1192 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1193 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1194 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1195 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1196 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;/*convertsRGB = true;*/break;
1197 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1198 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1202 if (convertsRGB && data)
1204 size = width * height * depth * sides * 4;
1207 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1208 memcpy(temppixels, data, size);
1211 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1215 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1217 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1220 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1222 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1226 texinfo = R_GetTexTypeInfo(textype, flags);
1227 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1230 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1234 // clear the alpha flag if the texture has no transparent pixels
1237 case TEXTYPE_PALETTE:
1238 case TEXTYPE_SRGB_PALETTE:
1239 if (flags & TEXF_ALPHA)
1241 flags &= ~TEXF_ALPHA;
1244 for (i = 0;i < size;i++)
1246 if (((unsigned char *)&palette[data[i]])[3] < 255)
1248 flags |= TEXF_ALPHA;
1257 case TEXTYPE_SRGB_RGBA:
1258 case TEXTYPE_SRGB_BGRA:
1259 if (flags & TEXF_ALPHA)
1261 flags &= ~TEXF_ALPHA;
1264 for (i = 3;i < size;i += 4)
1268 flags |= TEXF_ALPHA;
1275 case TEXTYPE_SHADOWMAP16_COMP:
1276 case TEXTYPE_SHADOWMAP16_RAW:
1277 case TEXTYPE_SHADOWMAP24_COMP:
1278 case TEXTYPE_SHADOWMAP24_RAW:
1281 case TEXTYPE_SRGB_DXT1:
1284 case TEXTYPE_SRGB_DXT1A:
1286 case TEXTYPE_SRGB_DXT3:
1288 case TEXTYPE_SRGB_DXT5:
1289 flags |= TEXF_ALPHA;
1292 flags |= TEXF_ALPHA;
1294 case TEXTYPE_COLORBUFFER:
1295 case TEXTYPE_COLORBUFFER16F:
1296 case TEXTYPE_COLORBUFFER32F:
1297 flags |= TEXF_ALPHA;
1300 Sys_Error("R_LoadTexture: unknown texture type");
1303 texinfo2 = R_GetTexTypeInfo(textype, flags);
1304 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1307 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1309 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1311 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1313 glt->chain = pool->gltchain;
1314 pool->gltchain = glt;
1315 glt->inputwidth = width;
1316 glt->inputheight = height;
1317 glt->inputdepth = depth;
1319 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
1320 glt->textype = texinfo;
1321 glt->texturetype = texturetype;
1322 glt->inputdatasize = size;
1323 glt->palette = palette;
1324 glt->glinternalformat = texinfo->glinternalformat;
1325 glt->glformat = texinfo->glformat;
1326 glt->gltype = texinfo->gltype;
1327 glt->bytesperpixel = texinfo->internalbytesperpixel;
1328 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1331 glt->glisdepthstencil = false;
1332 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1333 // init the dynamic texture attributes, too [11/22/2007 Black]
1334 glt->updatecallback = NULL;
1335 glt->updatecallback_data = NULL;
1337 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1339 // upload the texture
1340 // data may be NULL (blank texture for dynamic rendering)
1341 switch(vid.renderpath)
1343 case RENDERPATH_GL20:
1344 case RENDERPATH_GLES2:
1346 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1350 R_UploadFullTexture(glt, data);
1351 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1352 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1354 // free any temporary processing buffer we allocated...
1356 Mem_Free(temppixels);
1358 // texture converting and uploading can take a while, so make sure we're sending keepalives
1359 // FIXME: this causes rendering during R_Shadow_DrawLights
1360 // CL_KeepaliveMessage(false);
1362 return (rtexture_t *)glt;
1365 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)
1367 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1370 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)
1372 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1375 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)
1377 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1380 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter)
1382 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL);
1385 rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
1388 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1389 textypeinfo_t *texinfo;
1391 if (cls.state == ca_dedicated)
1394 texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP);
1396 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1398 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1400 glt->chain = pool->gltchain;
1401 pool->gltchain = glt;
1402 glt->inputwidth = width;
1403 glt->inputheight = height;
1404 glt->inputdepth = 1;
1405 glt->flags = TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_FORCENEAREST;
1407 glt->textype = texinfo;
1408 glt->texturetype = textype;
1409 glt->inputdatasize = width*height*texinfo->internalbytesperpixel;
1410 glt->palette = NULL;
1411 glt->glinternalformat = texinfo->glinternalformat;
1412 glt->glformat = texinfo->glformat;
1413 glt->gltype = texinfo->gltype;
1414 glt->bytesperpixel = texinfo->internalbytesperpixel;
1415 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1418 glt->glisdepthstencil = textype == TEXTYPE_DEPTHBUFFER24STENCIL8;
1419 glt->gltexturetypeenum = GL_TEXTURE_2D;
1420 // init the dynamic texture attributes, too [11/22/2007 Black]
1421 glt->updatecallback = NULL;
1422 glt->updatecallback_data = NULL;
1424 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1426 // upload the texture
1427 // data may be NULL (blank texture for dynamic rendering)
1428 switch(vid.renderpath)
1430 case RENDERPATH_GL20:
1431 case RENDERPATH_GLES2:
1433 qglGenRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
1434 qglBindRenderbuffer(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR
1435 qglRenderbufferStorage(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR
1436 // 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
1437 qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR
1441 return (rtexture_t *)glt;
1444 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1447 return -1; // unsupported on this platform
1449 gltexture_t *glt = (gltexture_t *)rt;
1452 int bytesperpixel = 0;
1453 int bytesperblock = 0;
1455 int dds_format_flags;
1463 GLint internalformat;
1464 const char *ddsfourcc;
1466 return -1; // NULL pointer
1467 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1468 return -2; // broken driver - crashes on reading internal format
1469 if (!qglGetTexLevelParameteriv)
1471 GL_ActiveTexture(0);
1472 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1473 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1474 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1475 switch(internalformat)
1477 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1478 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1479 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1480 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1481 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1483 // if premultiplied alpha, say so in the DDS file
1484 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1486 switch(internalformat)
1488 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1489 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1492 if (!bytesperblock && skipuncompressed)
1493 return -3; // skipped
1494 memset(mipinfo, 0, sizeof(mipinfo));
1495 mipinfo[0][0] = glt->tilewidth;
1496 mipinfo[0][1] = glt->tileheight;
1498 if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1))
1500 for (mip = 1;mip < 16;mip++)
1502 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1503 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1504 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1512 for (mip = 0;mip < mipmaps;mip++)
1514 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1515 mipinfo[mip][3] = ddssize;
1516 ddssize += mipinfo[mip][2];
1518 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1521 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1525 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1526 dds_format_flags = 0x4; // DDPF_FOURCC
1530 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1531 dds_format_flags = 0x40; // DDPF_RGB
1535 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1536 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1539 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1540 memcpy(dds, "DDS ", 4);
1541 StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
1542 StoreLittleLong(dds+8, dds_flags);
1543 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1544 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1545 StoreLittleLong(dds+24, 0); // depth
1546 StoreLittleLong(dds+28, mipmaps); // mipmaps
1547 StoreLittleLong(dds+76, 32); // format size
1548 StoreLittleLong(dds+80, dds_format_flags);
1549 StoreLittleLong(dds+108, dds_caps1);
1550 StoreLittleLong(dds+112, dds_caps2);
1553 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1554 memcpy(dds+84, ddsfourcc, 4);
1555 for (mip = 0;mip < mipmaps;mip++)
1557 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1562 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1563 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1564 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1565 for (mip = 0;mip < mipmaps;mip++)
1567 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1570 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1571 ret = FS_WriteFile(filename, dds, ddssize);
1573 return ret ? ddssize : -5;
1578 // ELUAN: FIXME: separate this code
1579 #include "ktx10/include/ktx.h"
1582 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
1584 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1587 int bytesperblock, bytesperpixel;
1590 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1591 textypeinfo_t *texinfo;
1592 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1593 unsigned int c, r, g, b;
1594 GLint oldbindtexnum = 0;
1595 unsigned char *mippixels;
1596 unsigned char *mippixels_start;
1597 unsigned char *ddspixels;
1599 fs_offset_t ddsfilesize;
1600 unsigned int ddssize;
1601 qboolean force_swdecode, npothack;
1603 // ELUAN: FIXME: separate this code
1607 KTX_dimensions sizes;
1610 if (cls.state == ca_dedicated)
1614 // ELUAN: FIXME: separate this code
1615 if (vid.renderpath != RENDERPATH_GLES2)
1617 Con_DPrintf("KTX texture format is only supported on the GLES2 renderpath\n");
1621 // some textures are specified with extensions, so it becomes .tga.dds
1622 FS_StripExtension (filename, vabuf2, sizeof(vabuf2));
1623 FS_StripExtension (vabuf2, vabuf, sizeof(vabuf));
1624 FS_DefaultExtension (vabuf, ".ktx", sizeof(vabuf));
1625 strsize = strlen(vabuf);
1627 for (i = 0; i <= strsize - 4; i++) // copy null termination
1628 vabuf[i] = vabuf[i + 4];
1630 Con_DPrintf("Loading %s...\n", vabuf);
1631 dds = FS_LoadFile(vabuf, tempmempool, true, &ddsfilesize);
1632 ddssize = ddsfilesize;
1636 Con_DPrintf("Not found!\n");
1637 return NULL; // not found
1639 Con_DPrintf("Found!\n");
1641 if (flags & TEXF_ALPHA)
1643 Con_DPrintf("KTX texture with alpha not supported yet, disabling\n");
1644 flags &= ~TEXF_ALPHA;
1650 GLboolean isMipmapped;
1651 KTX_error_code ktxerror;
1653 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1655 // texture uploading can take a while, so make sure we're sending keepalives
1656 CL_KeepaliveMessage(false);
1658 // create the texture object
1660 GL_ActiveTexture(0);
1661 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[GLTEXTURETYPE_2D]);
1662 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1663 qglBindTexture(gltexturetypeenums[GLTEXTURETYPE_2D], glt->texnum);CHECKGLERROR
1665 // upload the texture
1666 // we need to restore the texture binding after finishing the upload
1668 // NOTE: some drivers fail with ETC1 NPOT (only PowerVR?). This may make the driver crash later.
1669 ktxerror = ktxLoadTextureM(dds, ddssize, &glt->texnum, &target, &sizes, &isMipmapped, &glerror,
1670 0, NULL);// can't CHECKGLERROR, the lib catches it
1672 // FIXME: delete texture if we fail here
1673 if (target != GL_TEXTURE_2D)
1675 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1677 Con_DPrintf("%s target != GL_TEXTURE_2D, target == %x\n", vabuf, target);
1678 return NULL; // FIXME: delete the texture from memory
1681 if (KTX_SUCCESS == ktxerror)
1683 textype = TEXTYPE_ETC1;
1684 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
1686 // return whether this texture is transparent
1688 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1690 // TODO: apply gl_picmip
1693 // TODO: only load mipmaps if requested
1696 flags |= TEXF_MIPMAP;
1698 flags &= ~TEXF_MIPMAP;
1700 texinfo = R_GetTexTypeInfo(textype, flags);
1702 strlcpy (glt->identifier, vabuf, sizeof(glt->identifier));
1704 glt->chain = pool->gltchain;
1705 pool->gltchain = glt;
1706 glt->inputwidth = sizes.width;
1707 glt->inputheight = sizes.height;
1708 glt->inputdepth = 1;
1710 glt->textype = texinfo;
1711 glt->texturetype = GLTEXTURETYPE_2D;
1712 glt->inputdatasize = ddssize;
1713 glt->glinternalformat = texinfo->glinternalformat;
1714 glt->glformat = texinfo->glformat;
1715 glt->gltype = texinfo->gltype;
1716 glt->bytesperpixel = texinfo->internalbytesperpixel;
1718 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1719 glt->tilewidth = sizes.width;
1720 glt->tileheight = sizes.height;
1722 glt->miplevels = isMipmapped ? 1 : 0; // FIXME
1724 // after upload we have to set some parameters...
1725 #ifdef GL_TEXTURE_MAX_LEVEL
1727 if (dds_miplevels >= 1 && !mipcomplete)
1729 // need to set GL_TEXTURE_MAX_LEVEL
1730 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
1734 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1736 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1738 return (rtexture_t *)glt;
1742 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1744 Con_DPrintf("KTX texture %s failed to load: %x\n", vabuf, ktxerror);
1748 #endif // __ANDROID__
1750 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1751 ddssize = ddsfilesize;
1755 if (r_texture_dds_load_logfailure.integer && (r_texture_dds_load_logfailure.integer >= 2 || !optionaltexture))
1756 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1757 return NULL; // not found
1760 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1763 Con_Printf("^1%s: not a DDS image\n", filename);
1767 //dds_flags = BuffLittleLong(dds+8);
1768 dds_format_flags = BuffLittleLong(dds+80);
1769 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1770 dds_width = BuffLittleLong(dds+16);
1771 dds_height = BuffLittleLong(dds+12);
1772 ddspixels = dds + 128;
1774 if(r_texture_dds_load_alphamode.integer == 0)
1775 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1776 flags &= ~TEXF_ALPHA;
1778 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1779 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1781 // very sloppy BGRA 32bit identification
1782 textype = TEXTYPE_BGRA;
1783 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
1786 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1787 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1790 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1793 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1796 for (i = 3;i < size;i += 4)
1797 if (ddspixels[i] < 255)
1800 flags &= ~TEXF_ALPHA;
1803 else if (!memcmp(dds+84, "DXT1", 4))
1805 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1806 // LordHavoc: it is my belief that this does not infringe on the
1807 // patent because it is not decoding pixels...
1808 textype = TEXTYPE_DXT1;
1811 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1812 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1813 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1816 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1819 if (flags & TEXF_ALPHA)
1821 if (r_texture_dds_load_alphamode.integer == 1)
1824 for (i = 0;i < size;i += bytesperblock)
1825 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1827 // NOTE: this assumes sizeof(unsigned int) == 4
1828 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1829 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1830 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1834 textype = TEXTYPE_DXT1A;
1836 flags &= ~TEXF_ALPHA;
1838 else if (r_texture_dds_load_alphamode.integer == 0)
1839 textype = TEXTYPE_DXT1A;
1842 flags &= ~TEXF_ALPHA;
1846 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
1848 if(!memcmp(dds+84, "DXT2", 4))
1850 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1852 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
1857 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1859 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
1862 textype = TEXTYPE_DXT3;
1865 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1866 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1869 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1872 // we currently always assume alpha
1874 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
1876 if(!memcmp(dds+84, "DXT4", 4))
1878 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1880 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
1885 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1887 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
1890 textype = TEXTYPE_DXT5;
1893 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1894 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1897 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1900 // we currently always assume alpha
1905 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1909 // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
1910 if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
1912 textype = TEXTYPE_DXT1;
1916 for (i = 0;i < (int)ddssize;i += bytesperblock)
1917 memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
1921 force_swdecode = false;
1923 (!vid.support.arb_texture_non_power_of_two &&
1925 (dds_width & (dds_width - 1))
1927 (dds_height & (dds_height - 1))
1932 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && !npothack)
1934 if(r_texture_dds_swdecode.integer > 1)
1935 force_swdecode = true;
1939 if(r_texture_dds_swdecode.integer < 1)
1945 force_swdecode = true;
1949 // return whether this texture is transparent
1951 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1953 // if we SW decode, choose 2 sizes bigger
1956 // this is quarter res, so do not scale down more than we have to
1960 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
1963 // this is where we apply gl_picmip
1964 mippixels_start = ddspixels;
1965 mipwidth = dds_width;
1966 mipheight = dds_height;
1967 while(miplevel >= 1 && dds_miplevels >= 1)
1969 if (mipwidth <= 1 && mipheight <= 1)
1971 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1972 mippixels_start += mipsize; // just skip
1980 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
1981 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1983 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
1985 // fake decode S3TC if needed
1988 int mipsize_new = mipsize_total / bytesperblock * 4;
1989 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
1990 unsigned char *p = mipnewpixels;
1991 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
1993 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
1994 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
1995 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
1996 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
1997 if(textype == TEXTYPE_DXT5)
1998 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
1999 else if(textype == TEXTYPE_DXT3)
2001 (mippixels_start[i-8] & 0x0F)
2002 + (mippixels_start[i-8] >> 4)
2003 + (mippixels_start[i-7] & 0x0F)
2004 + (mippixels_start[i-7] >> 4)
2005 + (mippixels_start[i-6] & 0x0F)
2006 + (mippixels_start[i-6] >> 4)
2007 + (mippixels_start[i-5] & 0x0F)
2008 + (mippixels_start[i-5] >> 4)
2009 ) * (0.125f / 15.0f * 255.0f);
2014 textype = TEXTYPE_BGRA;
2018 // as each block becomes a pixel, we must use pixel count for this
2019 mipwidth = (mipwidth + 3) / 4;
2020 mipheight = (mipheight + 3) / 4;
2021 mipsize = bytesperpixel * mipwidth * mipheight;
2022 mippixels_start = mipnewpixels;
2023 mipsize_total = mipsize_new;
2026 // start mip counting
2027 mippixels = mippixels_start;
2029 // calculate average color if requested
2033 Vector4Clear(avgcolor);
2036 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2038 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2039 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2040 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2041 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2042 if(textype == TEXTYPE_DXT5)
2043 avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f);
2044 else if(textype == TEXTYPE_DXT3)
2046 (mippixels_start[i-8] & 0x0F)
2047 + (mippixels_start[i-8] >> 4)
2048 + (mippixels_start[i-7] & 0x0F)
2049 + (mippixels_start[i-7] >> 4)
2050 + (mippixels_start[i-6] & 0x0F)
2051 + (mippixels_start[i-6] >> 4)
2052 + (mippixels_start[i-5] & 0x0F)
2053 + (mippixels_start[i-5] >> 4)
2054 ) * (0.125f / 15.0f);
2056 avgcolor[3] += 1.0f;
2058 f = (float)bytesperblock / mipsize;
2059 avgcolor[0] *= (0.5f / 31.0f) * f;
2060 avgcolor[1] *= (0.5f / 63.0f) * f;
2061 avgcolor[2] *= (0.5f / 31.0f) * f;
2066 for (i = 0;i < mipsize;i += 4)
2068 avgcolor[0] += mippixels[i+2];
2069 avgcolor[1] += mippixels[i+1];
2070 avgcolor[2] += mippixels[i];
2071 avgcolor[3] += mippixels[i+3];
2073 f = (1.0f / 255.0f) * bytesperpixel / mipsize;
2081 // if we want sRGB, convert now
2084 if (vid.support.ext_texture_srgb)
2088 case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break;
2089 case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break;
2090 case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break;
2091 case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break;
2092 case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break;
2106 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2108 int c0, c1, c0new, c1new;
2109 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2110 r = ((c0 >> 11) & 0x1F);
2111 g = ((c0 >> 5) & 0x3F);
2113 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2114 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2115 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2116 c0new = (r << 11) | (g << 5) | b;
2117 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2118 r = ((c1 >> 11) & 0x1F);
2119 g = ((c1 >> 5) & 0x3F);
2121 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2122 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2123 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2124 c1new = (r << 11) | (g << 5) | b;
2125 // swap the colors if needed to fix order
2126 if(c0 > c1) // thirds
2134 mippixels_start[i+4] ^= 0x55;
2135 mippixels_start[i+5] ^= 0x55;
2136 mippixels_start[i+6] ^= 0x55;
2137 mippixels_start[i+7] ^= 0x55;
2139 else if(c0new == c1new)
2141 mippixels_start[i+4] = 0x00;
2142 mippixels_start[i+5] = 0x00;
2143 mippixels_start[i+6] = 0x00;
2144 mippixels_start[i+7] = 0x00;
2147 else // half + transparent
2154 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2155 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2156 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2157 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2160 mippixels_start[i] = c0new & 255;
2161 mippixels_start[i+1] = c0new >> 8;
2162 mippixels_start[i+2] = c1new & 255;
2163 mippixels_start[i+3] = c1new >> 8;
2168 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2176 // when not requesting mipmaps, do not load them
2177 if(!(flags & TEXF_MIPMAP))
2180 if (dds_miplevels >= 1)
2181 flags |= TEXF_MIPMAP;
2183 flags &= ~TEXF_MIPMAP;
2185 texinfo = R_GetTexTypeInfo(textype, flags);
2187 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2188 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2190 glt->chain = pool->gltchain;
2191 pool->gltchain = glt;
2192 glt->inputwidth = mipwidth;
2193 glt->inputheight = mipheight;
2194 glt->inputdepth = 1;
2196 glt->textype = texinfo;
2197 glt->texturetype = GLTEXTURETYPE_2D;
2198 glt->inputdatasize = ddssize;
2199 glt->glinternalformat = texinfo->glinternalformat;
2200 glt->glformat = texinfo->glformat;
2201 glt->gltype = texinfo->gltype;
2202 glt->bytesperpixel = texinfo->internalbytesperpixel;
2204 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2205 glt->tilewidth = mipwidth;
2206 glt->tileheight = mipheight;
2208 glt->miplevels = dds_miplevels;
2212 for (glt->tilewidth = 1;glt->tilewidth < mipwidth;glt->tilewidth <<= 1);
2213 for (glt->tileheight = 1;glt->tileheight < mipheight;glt->tileheight <<= 1);
2216 // texture uploading can take a while, so make sure we're sending keepalives
2217 CL_KeepaliveMessage(false);
2219 // create the texture object
2220 switch(vid.renderpath)
2222 case RENDERPATH_GL20:
2223 case RENDERPATH_GLES2:
2225 GL_ActiveTexture(0);
2226 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2227 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2228 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2232 // upload the texture
2233 // we need to restore the texture binding after finishing the upload
2234 mipcomplete = false;
2236 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2238 unsigned char *upload_mippixels = mippixels;
2239 int upload_mipwidth = mipwidth;
2240 int upload_mipheight = mipheight;
2241 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2242 if (mippixels + mipsize > mippixels_start + mipsize_total)
2246 upload_mipwidth = (glt->tilewidth >> mip);
2247 upload_mipheight = (glt->tileheight >> mip);
2248 if(upload_mipwidth != mipwidth || upload_mipheight != mipheight)
2249 // I _think_ they always mismatch, but I was too lazy
2250 // to properly check, and this test here is really
2253 upload_mippixels = (unsigned char *) Mem_Alloc(tempmempool, 4 * upload_mipwidth * upload_mipheight);
2254 Image_Resample32(mippixels, mipwidth, mipheight, 1, upload_mippixels, upload_mipwidth, upload_mipheight, 1, r_lerpimages.integer);
2257 switch(vid.renderpath)
2259 case RENDERPATH_GL20:
2260 case RENDERPATH_GLES2:
2263 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR
2267 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR
2271 if(upload_mippixels != mippixels)
2272 Mem_Free(upload_mippixels);
2273 mippixels += mipsize;
2274 if (mipwidth <= 1 && mipheight <= 1)
2285 // after upload we have to set some parameters...
2286 switch(vid.renderpath)
2288 case RENDERPATH_GL20:
2289 case RENDERPATH_GLES2:
2290 #ifdef GL_TEXTURE_MAX_LEVEL
2291 if (dds_miplevels >= 1 && !mipcomplete)
2293 // need to set GL_TEXTURE_MAX_LEVEL
2294 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2297 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2298 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2304 Mem_Free((unsigned char *) mippixels_start);
2305 return (rtexture_t *)glt;
2308 int R_TextureWidth(rtexture_t *rt)
2310 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2313 int R_TextureHeight(rtexture_t *rt)
2315 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2318 int R_TextureFlags(rtexture_t *rt)
2320 return rt ? ((gltexture_t *)rt)->flags : 0;
2323 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2325 gltexture_t *glt = (gltexture_t *)rt;
2327 Host_Error("R_UpdateTexture: no data supplied");
2329 Host_Error("R_UpdateTexture: no texture supplied");
2332 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2335 // update part of the texture
2336 if (glt->bufferpixels)
2339 int bpp = glt->bytesperpixel;
2340 int inputskip = width*bpp;
2341 int outputskip = glt->tilewidth*bpp;
2342 const unsigned char *input = data;
2343 unsigned char *output = glt->bufferpixels;
2344 if (glt->inputdepth != 1 || glt->sides != 1)
2345 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2355 input -= y*inputskip;
2358 if (width > glt->tilewidth - x)
2359 width = glt->tilewidth - x;
2360 if (height > glt->tileheight - y)
2361 height = glt->tileheight - y;
2362 if (width < 1 || height < 1)
2365 glt->buffermodified = true;
2366 output += y*outputskip + x*bpp;
2367 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2368 memcpy(output, input, width*bpp);
2370 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2371 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2373 R_UploadFullTexture(glt, data);
2376 int R_RealGetTexture(rtexture_t *rt)
2381 glt = (gltexture_t *)rt;
2382 if (glt->flags & GLTEXF_DYNAMIC)
2383 R_UpdateDynamicTexture(glt);
2384 if (glt->buffermodified && glt->bufferpixels)
2386 glt->buffermodified = false;
2387 R_UploadFullTexture(glt, glt->bufferpixels);
2393 return r_texture_white->texnum;
2396 void R_ClearTexture (rtexture_t *rt)
2398 gltexture_t *glt = (gltexture_t *)rt;
2400 R_UploadFullTexture(glt, NULL);
2403 int R_PicmipForFlags(int flags)
2406 if(flags & TEXF_PICMIP)
2408 miplevel += gl_picmip.integer;
2409 if (flags & TEXF_ISWORLD)
2411 if (r_picmipworld.integer)
2412 miplevel += gl_picmip_world.integer;
2416 else if (flags & TEXF_ISSPRITE)
2418 if (r_picmipsprites.integer)
2419 miplevel += gl_picmip_sprites.integer;
2424 miplevel += gl_picmip_other.integer;
2426 return max(0, miplevel);