7 cvar_t gl_max_size = {CF_CLIENT | CF_ARCHIVE, "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)"};
8 cvar_t gl_max_lightmapsize = {CF_CLIENT | CF_ARCHIVE, "gl_max_lightmapsize", "512", "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)"};
9 cvar_t gl_picmip = {CF_CLIENT | CF_ARCHIVE, "gl_picmip", "0", "reduces resolution of textures by powers of 2, for example 1 will halve width/height, reducing texture memory usage by 75%"};
10 cvar_t gl_picmip_world = {CF_CLIENT | CF_ARCHIVE, "gl_picmip_world", "0", "extra picmip level for world textures (may be negative, which will then reduce gl_picmip for these)"};
11 cvar_t r_picmipworld = {CF_CLIENT | CF_ARCHIVE, "r_picmipworld", "1", "whether gl_picmip shall apply to world textures too (setting this to 0 is a shorthand for gl_picmip_world -9999999)"};
12 cvar_t gl_picmip_sprites = {CF_CLIENT | CF_ARCHIVE, "gl_picmip_sprites", "0", "extra picmip level for sprite textures (may be negative, which will then reduce gl_picmip for these)"};
13 cvar_t r_picmipsprites = {CF_CLIENT | CF_ARCHIVE, "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)"};
14 cvar_t gl_picmip_other = {CF_CLIENT | CF_ARCHIVE, "gl_picmip_other", "0", "extra picmip level for other textures (may be negative, which will then reduce gl_picmip for these)"};
15 cvar_t r_lerpimages = {CF_CLIENT | CF_ARCHIVE, "r_lerpimages", "1", "bilinear filters images when scaling them up to power of 2 size (mode 1), looks better than glquake (mode 0)"};
16 cvar_t gl_texture_anisotropy = {CF_CLIENT | CF_ARCHIVE, "gl_texture_anisotropy", "1", "anisotropic filtering quality (if supported by hardware), 1 sample (no anisotropy) and 8 sample (8 tap anisotropy) are recommended values"};
17 cvar_t gl_texturecompression = {CF_CLIENT | CF_ARCHIVE, "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"};
18 cvar_t gl_texturecompression_color = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
19 cvar_t gl_texturecompression_normal = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
20 cvar_t gl_texturecompression_gloss = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
21 cvar_t gl_texturecompression_glow = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
22 cvar_t gl_texturecompression_2d = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
23 cvar_t gl_texturecompression_q3bsplightmaps = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
24 cvar_t gl_texturecompression_q3bspdeluxemaps = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_q3bspdeluxemaps", "0", "whether to compress deluxemaps in q3bsp format levels (only levels compiled with q3map2 -deluxe have these)"};
25 cvar_t gl_texturecompression_sky = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
26 cvar_t gl_texturecompression_lightcubemaps = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
27 cvar_t gl_texturecompression_reflectmask = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_reflectmask", "1", "whether to compress reflection cubemap masks (mask of which areas of the texture should reflect the generic shiny cubemap)"};
28 cvar_t gl_texturecompression_sprites = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_sprites", "1", "whether to compress sprites"};
29 cvar_t r_texture_dds_load_alphamode = {CF_CLIENT, "r_texture_dds_load_alphamode", "1", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambiguous, 2: texture format only"};
30 cvar_t r_texture_dds_load_logfailure = {CF_CLIENT, "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"};
31 cvar_t r_texture_dds_swdecode = {CF_CLIENT, "r_texture_dds_swdecode", "0", "0: don't software decode DDS, 1: software decode DDS if unsupported, 2: always software decode DDS"};
33 qbool gl_filter_force = false;
34 int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
35 int gl_filter_mag = GL_LINEAR;
38 static mempool_t *texturemempool;
39 static memexpandablearray_t texturearray;
41 // note: this must not conflict with TEXF_ flags in r_textures.h
42 // bitmask for mismatch checking
43 #define GLTEXF_IMPORTANTBITS (0)
44 // dynamic texture (treat texnum == 0 differently)
45 #define GLTEXF_DYNAMIC 0x00080000
47 typedef struct textypeinfo_s
51 int inputbytesperpixel;
52 int internalbytesperpixel;
53 float glinternalbytesperpixel;
62 // we use these internally even if we never deliver such data to the driver
64 #define GL_BGRA 0x80E1
66 // framebuffer texture formats
67 // GLES2 devices rarely support depth textures, so we actually use a renderbuffer there
68 static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
69 static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
70 static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
71 static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
72 static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
73 static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
74 static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
75 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 2, 2, 2.0f, GL_RGB565 , GL_RGBA , GL_UNSIGNED_SHORT_5_6_5};
76 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 2, 2, 2.0f, GL_RGBA16F , GL_RGBA , GL_HALF_FLOAT};
77 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 2, 2, 2.0f, GL_RGBA32F , GL_RGBA , GL_FLOAT};
80 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
81 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
82 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
83 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
84 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
85 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
86 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
88 static textypeinfo_t textype_etc1 = {"etc1", TEXTYPE_ETC1 , 1, 3, 0.5f, GL_ETC1_RGB8_OES , 0 , 0 };
91 // framebuffer texture formats
92 static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
93 static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
94 static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24 , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
95 static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 4, 4, 4.0f, GL_DEPTH_COMPONENT24 , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
96 static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
97 static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 4, 4, 4.0f, GL_DEPTH_COMPONENT24 , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
98 static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 4, 4, 4.0f, GL_DEPTH24_STENCIL8 , GL_DEPTH_STENCIL , GL_UNSIGNED_INT_24_8};
99 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
100 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 8, 8, 8.0f, GL_RGBA16F , GL_RGBA , GL_HALF_FLOAT };
101 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 16, 16, 16.0f, GL_RGBA32F , GL_RGBA , GL_FLOAT };
104 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
105 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
106 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
107 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE };
108 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
109 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 };
110 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 };
111 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
112 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
113 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 };
114 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 };
115 static textypeinfo_t textype_dxt1 = {"dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
116 static textypeinfo_t textype_dxt1a = {"dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 };
117 static textypeinfo_t textype_dxt3 = {"dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 };
118 static textypeinfo_t textype_dxt5 = {"dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 };
119 static textypeinfo_t textype_sRGB_palette = {"sRGB_palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB , GL_BGRA , GL_UNSIGNED_BYTE };
120 static textypeinfo_t textype_sRGB_palette_alpha = {"sRGB_palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_ALPHA , GL_BGRA , GL_UNSIGNED_BYTE };
121 static textypeinfo_t textype_sRGB_rgba = {"sRGB_rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB , GL_RGBA , GL_UNSIGNED_BYTE };
122 static textypeinfo_t textype_sRGB_rgba_alpha = {"sRGB_rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_ALPHA , GL_RGBA , GL_UNSIGNED_BYTE };
123 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 };
124 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 };
125 static textypeinfo_t textype_sRGB_bgra = {"sRGB_bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB , GL_BGRA , GL_UNSIGNED_BYTE };
126 static textypeinfo_t textype_sRGB_bgra_alpha = {"sRGB_bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_ALPHA , GL_BGRA , GL_UNSIGNED_BYTE };
127 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 };
128 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 };
129 static textypeinfo_t textype_sRGB_dxt1 = {"sRGB_dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , 0 , 0 };
130 static textypeinfo_t textype_sRGB_dxt1a = {"sRGB_dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 , 0 };
131 static textypeinfo_t textype_sRGB_dxt3 = {"sRGB_dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 , 0 };
132 static textypeinfo_t textype_sRGB_dxt5 = {"sRGB_dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 , 0 };
135 typedef enum gltexturetype_e
139 GLTEXTURETYPE_CUBEMAP,
144 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP};
145 #ifdef GL_TEXTURE_WRAP_R
146 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
148 static int cubemapside[6] =
150 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
151 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
152 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
153 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
154 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
155 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
158 typedef struct gltexture_s
160 // this portion of the struct is exposed to the R_GetTexture macro for
161 // speed reasons, must be identical in rtexture_t!
162 int texnum; // GL texture slot number
163 int renderbuffernum; // GL renderbuffer slot number
164 qbool dirty; // indicates that R_RealGetTexture should be called
165 qbool glisdepthstencil; // indicates that FBO attachment has to be GL_DEPTH_STENCIL_ATTACHMENT
166 int gltexturetypeenum; // used by R_Mesh_TexBind
168 // dynamic texture stuff [11/22/2007 Black]
169 updatecallback_t updatecallback;
170 void *updatecallback_data;
171 // --- [11/22/2007 Black]
173 // stores backup copy of texture for deferred texture updates (R_UpdateTexture when combine = true)
174 unsigned char *bufferpixels;
175 int modified_mins[3], modified_maxs[3];
176 qbool buffermodified;
178 // pointer to texturepool (check this to see if the texture is allocated)
179 struct gltexturepool_s *pool;
180 // pointer to next texture in texturepool chain
181 struct gltexture_s *chain;
182 // name of the texture (this might be removed someday), no duplicates
183 char identifier[MAX_QPATH + 32];
184 // original data size in *inputtexels
185 int inputwidth, inputheight, inputdepth;
186 // copy of the original texture(s) supplied to the upload function, for
187 // delayed uploads (non-precached)
188 unsigned char *inputtexels;
189 // original data size in *inputtexels
191 // flags supplied to the LoadTexture function
192 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
196 // pointer to one of the textype_ structs
197 textypeinfo_t *textype;
198 // one of the GLTEXTURETYPE_ values
200 // palette if the texture is TEXTYPE_PALETTE
201 const unsigned int *palette;
202 // actual stored texture size after gl_picmip and gl_max_size are applied
203 int tilewidth, tileheight, tiledepth;
204 // 1 or 6 depending on texturetype
206 // how many mipmap levels in this texture
210 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
213 int glinternalformat;
214 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
219 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
221 typedef struct gltexturepool_s
223 unsigned int sentinel;
224 struct gltexture_s *gltchain;
225 struct gltexturepool_s *next;
229 static gltexturepool_t *gltexturepoolchain = NULL;
231 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
232 static int resizebuffersize = 0;
233 static const unsigned char *texturebuffer;
235 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
240 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
241 case TEXTYPE_RGBA: return ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba);
242 case TEXTYPE_BGRA: return ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra);
244 case TEXTYPE_ETC1: return &textype_etc1;
246 case TEXTYPE_ALPHA: return &textype_alpha;
247 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
248 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
249 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
250 case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
251 case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
252 case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
253 case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
254 case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
255 case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
256 case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
258 case TEXTYPE_DXT1: return &textype_dxt1;
259 case TEXTYPE_DXT1A: return &textype_dxt1a;
260 case TEXTYPE_DXT3: return &textype_dxt3;
261 case TEXTYPE_DXT5: return &textype_dxt5;
262 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
263 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);
264 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);
265 case TEXTYPE_ALPHA: return &textype_alpha;
266 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
267 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
268 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
269 case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
270 case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
271 case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
272 case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
273 case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
274 case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
275 case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
276 case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1;
277 case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a;
278 case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
279 case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
280 case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
281 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);
282 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);
285 Host_Error("R_GetTexTypeInfo: unknown texture format %i with flags %x", (int)textype, flags);
291 // dynamic texture code [11/22/2007 Black]
292 void R_MarkDirtyTexture(rtexture_t *rt) {
293 gltexture_t *glt = (gltexture_t*) rt;
298 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
299 if (glt->flags & GLTEXF_DYNAMIC)
301 // mark it as dirty, so R_RealGetTexture gets called
306 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
307 gltexture_t *glt = (gltexture_t*) rt;
312 glt->flags |= GLTEXF_DYNAMIC;
313 glt->updatecallback = updatecallback;
314 glt->updatecallback_data = data;
317 static void R_UpdateDynamicTexture(gltexture_t *glt) {
319 if( glt->updatecallback ) {
320 glt->updatecallback( (rtexture_t*) glt, glt->updatecallback_data );
324 void R_PurgeTexture(rtexture_t *rt)
326 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
331 void R_FreeTexture(rtexture_t *rt)
333 gltexture_t *glt, **gltpointer;
335 glt = (gltexture_t *)rt;
337 Host_Error("R_FreeTexture: texture == NULL");
339 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
340 if (*gltpointer == glt)
341 *gltpointer = glt->chain;
343 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
345 R_Mesh_ClearBindingsForTexture(glt->texnum);
347 switch(vid.renderpath)
349 case RENDERPATH_GL32:
350 case RENDERPATH_GLES2:
354 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
356 if (glt->renderbuffernum)
359 qglDeleteRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
364 if (glt->inputtexels)
365 Mem_Free(glt->inputtexels);
366 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
369 rtexturepool_t *R_AllocTexturePool(void)
371 gltexturepool_t *pool;
372 if (texturemempool == NULL)
374 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
377 pool->next = gltexturepoolchain;
378 gltexturepoolchain = pool;
379 pool->sentinel = TEXTUREPOOL_SENTINEL;
380 return (rtexturepool_t *)pool;
383 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
385 gltexturepool_t *pool, **poolpointer;
386 if (rtexturepool == NULL)
388 if (*rtexturepool == NULL)
390 pool = (gltexturepool_t *)(*rtexturepool);
391 *rtexturepool = NULL;
392 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
393 Host_Error("R_FreeTexturePool: pool already freed");
394 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
395 if (*poolpointer == pool)
396 *poolpointer = pool->next;
398 Host_Error("R_FreeTexturePool: pool not linked");
399 while (pool->gltchain)
400 R_FreeTexture((rtexture_t *)pool->gltchain);
405 typedef struct glmode_s
408 int minification, magnification;
412 static glmode_t modes[6] =
414 {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
415 {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
416 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
417 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
418 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
419 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
422 static void GL_TextureMode_f(cmd_state_t *cmd)
427 gltexturepool_t *pool;
429 if (Cmd_Argc(cmd) == 1)
431 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
432 for (i = 0;i < 6;i++)
434 if (gl_filter_min == modes[i].minification)
436 Con_Printf("%s\n", modes[i].name);
440 Con_Print("current filter is unknown???\n");
444 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
445 if (!strcasecmp (modes[i].name, Cmd_Argv(cmd, 1) ) )
449 Con_Print("bad filter name\n");
453 gl_filter_min = modes[i].minification;
454 gl_filter_mag = modes[i].magnification;
455 gl_filter_force = ((Cmd_Argc(cmd) > 2) && !strcasecmp(Cmd_Argv(cmd, 2), "force"));
457 switch(vid.renderpath)
459 case RENDERPATH_GL32:
460 case RENDERPATH_GLES2:
461 // change all the existing mipmap texture objects
462 // FIXME: force renderer(/client/something?) restart instead?
465 for (pool = gltexturepoolchain;pool;pool = pool->next)
467 for (glt = pool->gltchain;glt;glt = glt->chain)
469 // only update already uploaded images
470 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
472 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
473 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
474 if (glt->flags & TEXF_MIPMAP)
476 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
480 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
482 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
483 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
491 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)
493 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
498 case GLTEXTURETYPE_2D:
499 maxsize = vid.maxtexturesize_2d;
500 if (flags & TEXF_PICMIP)
502 maxsize = bound(1, gl_max_size.integer, maxsize);
506 case GLTEXTURETYPE_3D:
507 maxsize = vid.maxtexturesize_3d;
509 case GLTEXTURETYPE_CUBEMAP:
510 maxsize = vid.maxtexturesize_cubemap;
514 width2 = min(inwidth >> picmip, maxsize);
515 height2 = min(inheight >> picmip, maxsize);
516 depth2 = min(indepth >> picmip, maxsize);
519 if (flags & TEXF_MIPMAP)
521 int extent = max(width2, max(height2, depth2));
527 *outwidth = max(1, width2);
529 *outheight = max(1, height2);
531 *outdepth = max(1, depth2);
533 *outmiplevels = miplevels;
537 static int R_CalcTexelDataSize (gltexture_t *glt)
539 int width2, height2, depth2, size;
541 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
543 size = width2 * height2 * depth2;
545 if (glt->flags & TEXF_MIPMAP)
547 while (width2 > 1 || height2 > 1 || depth2 > 1)
555 size += width2 * height2 * depth2;
559 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
562 void R_TextureStats_Print(qbool printeach, qbool printpool, qbool printtotal)
566 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
567 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
569 gltexturepool_t *pool;
571 Con_Print("glsize input loaded mip alpha name\n");
572 for (pool = gltexturepoolchain;pool;pool = pool->next)
580 for (glt = pool->gltchain;glt;glt = glt->chain)
582 glsize = R_CalcTexelDataSize(glt);
583 isloaded = glt->texnum != 0 || glt->renderbuffernum != 0;
585 pooltotalt += glsize;
586 pooltotalp += glt->inputdatasize;
590 poolloadedt += glsize;
591 poolloadedp += glt->inputdatasize;
594 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);
597 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);
598 sumtotal += pooltotal;
599 sumtotalt += pooltotalt;
600 sumtotalp += pooltotalp;
601 sumloaded += poolloaded;
602 sumloadedt += poolloadedt;
603 sumloadedp += poolloadedp;
606 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);
609 static void R_TextureStats_f(cmd_state_t *cmd)
611 R_TextureStats_Print(true, true, true);
614 static void r_textures_start(void)
616 switch(vid.renderpath)
618 case RENDERPATH_GL32:
619 case RENDERPATH_GLES2:
620 // LadyHavoc: allow any alignment
622 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
623 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
627 texturemempool = Mem_AllocPool("texture management", 0, NULL);
628 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
630 // Disable JPEG screenshots if the DLL isn't loaded
631 if (! JPEG_OpenLibrary ())
632 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
633 if (! PNG_OpenLibrary ())
634 Cvar_SetValueQuick (&scr_screenshot_png, 0);
637 static void r_textures_shutdown(void)
639 rtexturepool_t *temp;
641 JPEG_CloseLibrary ();
643 while(gltexturepoolchain)
645 temp = (rtexturepool_t *) gltexturepoolchain;
646 R_FreeTexturePool(&temp);
649 resizebuffersize = 0;
651 colorconvertbuffer = NULL;
652 texturebuffer = NULL;
653 Mem_ExpandableArray_FreeArray(&texturearray);
654 Mem_FreePool(&texturemempool);
657 static void r_textures_newmap(void)
661 static void r_textures_devicelost(void)
665 endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
666 for (i = 0;i < endindex;i++)
668 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
669 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
671 switch(vid.renderpath)
673 case RENDERPATH_GL32:
674 case RENDERPATH_GLES2:
680 static void r_textures_devicerestored(void)
684 endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
685 for (i = 0;i < endindex;i++)
687 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
688 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
690 switch(vid.renderpath)
692 case RENDERPATH_GL32:
693 case RENDERPATH_GLES2:
700 void R_Textures_Init (void)
702 Cmd_AddCommand(CF_CLIENT, "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");
703 Cmd_AddCommand(CF_CLIENT, "r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
704 Cvar_RegisterVariable (&gl_max_size);
705 Cvar_RegisterVariable (&gl_picmip);
706 Cvar_RegisterVariable (&gl_picmip_world);
707 Cvar_RegisterVariable (&r_picmipworld);
708 Cvar_RegisterVariable (&gl_picmip_sprites);
709 Cvar_RegisterVariable (&r_picmipsprites);
710 Cvar_RegisterVariable (&gl_picmip_other);
711 Cvar_RegisterVariable (&gl_max_lightmapsize);
712 Cvar_RegisterVariable (&r_lerpimages);
713 Cvar_RegisterVariable (&gl_texture_anisotropy);
714 Cvar_RegisterVariable (&gl_texturecompression);
715 Cvar_RegisterVariable (&gl_texturecompression_color);
716 Cvar_RegisterVariable (&gl_texturecompression_normal);
717 Cvar_RegisterVariable (&gl_texturecompression_gloss);
718 Cvar_RegisterVariable (&gl_texturecompression_glow);
719 Cvar_RegisterVariable (&gl_texturecompression_2d);
720 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
721 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
722 Cvar_RegisterVariable (&gl_texturecompression_sky);
723 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
724 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
725 Cvar_RegisterVariable (&gl_texturecompression_sprites);
726 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
727 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
728 Cvar_RegisterVariable (&r_texture_dds_swdecode);
730 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
733 void R_Textures_Frame (void)
735 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
736 static int old_aniso = 0;
737 static qbool first_time_aniso = true;
740 // could do procedural texture animation here, if we keep track of which
741 // textures were accessed this frame...
743 // free the resize buffers
744 resizebuffersize = 0;
747 Mem_Free(resizebuffer);
750 if (colorconvertbuffer)
752 Mem_Free(colorconvertbuffer);
753 colorconvertbuffer = NULL;
756 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
757 if (old_aniso != gl_texture_anisotropy.integer)
760 gltexturepool_t *pool;
763 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
765 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
767 switch(vid.renderpath)
769 case RENDERPATH_GL32:
770 case RENDERPATH_GLES2:
771 // ignore the first difference, any textures loaded by now probably had the same aniso value
772 if (first_time_aniso)
774 first_time_aniso = false;
779 for (pool = gltexturepoolchain;pool;pool = pool->next)
781 for (glt = pool->gltchain;glt;glt = glt->chain)
783 // only update already uploaded images
784 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
786 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
788 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
789 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
791 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
801 static void R_MakeResizeBufferBigger(int size)
803 if (resizebuffersize < size)
805 resizebuffersize = size;
807 Mem_Free(resizebuffer);
808 if (colorconvertbuffer)
809 Mem_Free(colorconvertbuffer);
810 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
811 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
812 if (!resizebuffer || !colorconvertbuffer)
813 Host_Error("R_Upload: out of memory");
817 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
819 int textureenum = gltexturetypeenums[texturetype];
820 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
824 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
825 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
827 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
828 if (gl_texture_anisotropy.integer != aniso)
829 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
830 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
833 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
834 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
835 #ifdef GL_TEXTURE_WRAP_R
836 if (gltexturetypedimensions[texturetype] >= 3)
838 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
843 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
845 if (flags & TEXF_MIPMAP)
847 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
851 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
853 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
855 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
857 if (flags & TEXF_MIPMAP)
859 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
861 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
865 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
870 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
872 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
876 if (flags & TEXF_MIPMAP)
878 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
882 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
884 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
890 case TEXTYPE_SHADOWMAP16_COMP:
891 case TEXTYPE_SHADOWMAP24_COMP:
892 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);CHECKGLERROR
893 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);CHECKGLERROR
895 case TEXTYPE_SHADOWMAP16_RAW:
896 case TEXTYPE_SHADOWMAP24_RAW:
897 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE, GL_NONE);CHECKGLERROR
898 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);CHECKGLERROR
908 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
911 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
913 if (glt->texturetype != GLTEXTURETYPE_2D)
914 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
916 if (glt->textype->textype == TEXTYPE_PALETTE)
917 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
919 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
920 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
922 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
923 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
925 // update a portion of the image
927 switch(vid.renderpath)
929 case RENDERPATH_GL32:
930 case RENDERPATH_GLES2:
934 // we need to restore the texture binding after finishing the upload
936 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
937 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
938 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
939 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
945 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
947 int i, mip = 0, width, height, depth;
948 GLint oldbindtexnum = 0;
949 const unsigned char *prevbuffer;
952 // error out if a stretch is needed on special texture types
953 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
954 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
956 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
957 // of the target size and then use the mipmap reduction function to get
958 // high quality supersampled results
959 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
960 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
961 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
963 if (prevbuffer == NULL)
965 width = glt->tilewidth;
966 height = glt->tileheight;
967 depth = glt->tiledepth;
968 // R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
969 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
970 // prevbuffer = resizebuffer;
974 if (glt->textype->textype == TEXTYPE_PALETTE)
976 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
977 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
978 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
979 prevbuffer = colorconvertbuffer;
981 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
983 // multiply RGB channels by A channel before uploading
985 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
986 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
988 alpha = prevbuffer[i+3];
989 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
990 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
991 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
992 colorconvertbuffer[i+3] = alpha;
994 prevbuffer = colorconvertbuffer;
996 // scale up to a power of 2 size (if appropriate)
997 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
999 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1000 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1001 prevbuffer = resizebuffer;
1003 // apply mipmap reduction algorithm to get down to picmip/max_size
1004 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1006 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1007 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1008 prevbuffer = resizebuffer;
1012 // do the appropriate upload type...
1013 switch(vid.renderpath)
1015 case RENDERPATH_GL32:
1016 case RENDERPATH_GLES2:
1017 if (glt->texnum) // not renderbuffers
1021 // we need to restore the texture binding after finishing the upload
1022 GL_ActiveTexture(0);
1023 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1024 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1027 if (gl_texturecompression.integer >= 2)
1028 qglHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
1030 qglHint(GL_TEXTURE_COMPRESSION_HINT, GL_FASTEST);
1033 switch(glt->texturetype)
1035 case GLTEXTURETYPE_2D:
1036 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1037 if (glt->flags & TEXF_MIPMAP)
1039 while (width > 1 || height > 1 || depth > 1)
1041 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1042 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1043 prevbuffer = resizebuffer;
1044 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1048 case GLTEXTURETYPE_3D:
1050 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1051 if (glt->flags & TEXF_MIPMAP)
1053 while (width > 1 || height > 1 || depth > 1)
1055 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1056 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1057 prevbuffer = resizebuffer;
1058 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1063 case GLTEXTURETYPE_CUBEMAP:
1064 // convert and upload each side in turn,
1065 // from a continuous block of input texels
1066 texturebuffer = (unsigned char *)prevbuffer;
1067 for (i = 0;i < 6;i++)
1069 prevbuffer = texturebuffer;
1070 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1071 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1073 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1074 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1075 prevbuffer = resizebuffer;
1078 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1080 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1081 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1082 prevbuffer = resizebuffer;
1085 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1086 if (glt->flags & TEXF_MIPMAP)
1088 while (width > 1 || height > 1 || depth > 1)
1090 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1091 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1092 prevbuffer = resizebuffer;
1093 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1099 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1100 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1106 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)
1110 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1111 textypeinfo_t *texinfo, *texinfo2;
1112 unsigned char *temppixels = NULL;
1115 if (cls.state == ca_dedicated)
1118 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1119 if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1121 int numpixels = width * height * depth * sides;
1122 size = numpixels * 4;
1123 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1126 const unsigned char *p;
1127 unsigned char *o = temppixels;
1128 for (i = 0;i < numpixels;i++, o += 4)
1130 p = (const unsigned char *)palette + 4*data[i];
1138 textype = TEXTYPE_RGBA;
1143 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1144 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1145 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1146 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1152 static int rgbaswapindices[4] = {2, 1, 0, 3};
1153 size = width * height * depth * sides * 4;
1154 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1156 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1160 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1161 if (!vid.support.ext_texture_srgb)
1163 qbool convertsRGB = false;
1166 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1167 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1168 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1169 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1170 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;/*convertsRGB = true;*/break;
1171 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1172 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1176 if (convertsRGB && data)
1178 size = width * height * depth * sides * 4;
1181 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1182 memcpy(temppixels, data, size);
1185 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1189 texinfo = R_GetTexTypeInfo(textype, flags);
1190 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1193 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1197 // clear the alpha flag if the texture has no transparent pixels
1200 case TEXTYPE_PALETTE:
1201 case TEXTYPE_SRGB_PALETTE:
1202 if (flags & TEXF_ALPHA)
1204 flags &= ~TEXF_ALPHA;
1207 for (i = 0;i < size;i++)
1209 if (((unsigned char *)&palette[data[i]])[3] < 255)
1211 flags |= TEXF_ALPHA;
1220 case TEXTYPE_SRGB_RGBA:
1221 case TEXTYPE_SRGB_BGRA:
1222 if (flags & TEXF_ALPHA)
1224 flags &= ~TEXF_ALPHA;
1227 for (i = 3;i < size;i += 4)
1231 flags |= TEXF_ALPHA;
1238 case TEXTYPE_SHADOWMAP16_COMP:
1239 case TEXTYPE_SHADOWMAP16_RAW:
1240 case TEXTYPE_SHADOWMAP24_COMP:
1241 case TEXTYPE_SHADOWMAP24_RAW:
1244 case TEXTYPE_SRGB_DXT1:
1247 case TEXTYPE_SRGB_DXT1A:
1249 case TEXTYPE_SRGB_DXT3:
1251 case TEXTYPE_SRGB_DXT5:
1252 flags |= TEXF_ALPHA;
1255 flags |= TEXF_ALPHA;
1257 case TEXTYPE_COLORBUFFER:
1258 case TEXTYPE_COLORBUFFER16F:
1259 case TEXTYPE_COLORBUFFER32F:
1260 flags |= TEXF_ALPHA;
1263 Sys_Error("R_LoadTexture: unknown texture type");
1266 texinfo2 = R_GetTexTypeInfo(textype, flags);
1267 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1270 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1272 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1274 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1276 glt->chain = pool->gltchain;
1277 pool->gltchain = glt;
1278 glt->inputwidth = width;
1279 glt->inputheight = height;
1280 glt->inputdepth = depth;
1282 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
1283 glt->textype = texinfo;
1284 glt->texturetype = texturetype;
1285 glt->inputdatasize = size;
1286 glt->palette = palette;
1287 glt->glinternalformat = texinfo->glinternalformat;
1288 glt->glformat = texinfo->glformat;
1289 glt->gltype = texinfo->gltype;
1290 glt->bytesperpixel = texinfo->internalbytesperpixel;
1291 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1294 glt->glisdepthstencil = false;
1295 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1296 // init the dynamic texture attributes, too [11/22/2007 Black]
1297 glt->updatecallback = NULL;
1298 glt->updatecallback_data = NULL;
1300 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1302 // upload the texture
1303 // data may be NULL (blank texture for dynamic rendering)
1304 switch(vid.renderpath)
1306 case RENDERPATH_GL32:
1307 case RENDERPATH_GLES2:
1309 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1313 R_UploadFullTexture(glt, data);
1314 if (glt->flags & TEXF_ALLOWUPDATES)
1315 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1317 glt->buffermodified = false;
1318 VectorClear(glt->modified_mins);
1319 VectorClear(glt->modified_maxs);
1321 // free any temporary processing buffer we allocated...
1323 Mem_Free(temppixels);
1325 // texture converting and uploading can take a while, so make sure we're sending keepalives
1326 // FIXME: this causes rendering during R_Shadow_DrawLights
1327 // CL_KeepaliveMessage(false);
1329 return (rtexture_t *)glt;
1332 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)
1334 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1337 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)
1339 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1342 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)
1344 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1347 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qbool filter)
1349 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL);
1352 rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
1355 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1356 textypeinfo_t *texinfo;
1358 if (cls.state == ca_dedicated)
1361 texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP);
1363 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1365 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1367 glt->chain = pool->gltchain;
1368 pool->gltchain = glt;
1369 glt->inputwidth = width;
1370 glt->inputheight = height;
1371 glt->inputdepth = 1;
1372 glt->flags = TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_FORCENEAREST;
1374 glt->textype = texinfo;
1375 glt->texturetype = textype;
1376 glt->inputdatasize = width*height*texinfo->internalbytesperpixel;
1377 glt->palette = NULL;
1378 glt->glinternalformat = texinfo->glinternalformat;
1379 glt->glformat = texinfo->glformat;
1380 glt->gltype = texinfo->gltype;
1381 glt->bytesperpixel = texinfo->internalbytesperpixel;
1382 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1385 glt->glisdepthstencil = textype == TEXTYPE_DEPTHBUFFER24STENCIL8;
1386 glt->gltexturetypeenum = GL_TEXTURE_2D;
1387 // init the dynamic texture attributes, too [11/22/2007 Black]
1388 glt->updatecallback = NULL;
1389 glt->updatecallback_data = NULL;
1391 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1393 // upload the texture
1394 // data may be NULL (blank texture for dynamic rendering)
1395 switch(vid.renderpath)
1397 case RENDERPATH_GL32:
1398 case RENDERPATH_GLES2:
1400 qglGenRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
1401 qglBindRenderbuffer(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR
1402 qglRenderbufferStorage(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR
1403 // 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
1404 qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR
1408 return (rtexture_t *)glt;
1411 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qbool skipuncompressed, qbool hasalpha)
1414 return -1; // unsupported on this platform
1416 gltexture_t *glt = (gltexture_t *)rt;
1419 int bytesperpixel = 0;
1420 int bytesperblock = 0;
1422 int dds_format_flags;
1430 GLint internalformat;
1431 const char *ddsfourcc;
1433 return -1; // NULL pointer
1434 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1435 return -2; // broken driver - crashes on reading internal format
1436 if (!qglGetTexLevelParameteriv)
1438 GL_ActiveTexture(0);
1439 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1440 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1441 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1442 switch(internalformat)
1444 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1445 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1446 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1447 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1448 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1450 // if premultiplied alpha, say so in the DDS file
1451 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1453 switch(internalformat)
1455 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1456 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1459 if (!bytesperblock && skipuncompressed)
1460 return -3; // skipped
1461 memset(mipinfo, 0, sizeof(mipinfo));
1462 mipinfo[0][0] = glt->tilewidth;
1463 mipinfo[0][1] = glt->tileheight;
1465 if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1))
1467 for (mip = 1;mip < 16;mip++)
1469 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1470 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1471 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1479 for (mip = 0;mip < mipmaps;mip++)
1481 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1482 mipinfo[mip][3] = ddssize;
1483 ddssize += mipinfo[mip][2];
1485 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1488 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1492 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1493 dds_format_flags = 0x4; // DDPF_FOURCC
1497 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1498 dds_format_flags = 0x40; // DDPF_RGB
1502 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1503 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1506 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1507 memcpy(dds, "DDS ", 4);
1508 StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
1509 StoreLittleLong(dds+8, dds_flags);
1510 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1511 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1512 StoreLittleLong(dds+24, 0); // depth
1513 StoreLittleLong(dds+28, mipmaps); // mipmaps
1514 StoreLittleLong(dds+76, 32); // format size
1515 StoreLittleLong(dds+80, dds_format_flags);
1516 StoreLittleLong(dds+108, dds_caps1);
1517 StoreLittleLong(dds+112, dds_caps2);
1520 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1521 memcpy(dds+84, ddsfourcc, 4);
1522 for (mip = 0;mip < mipmaps;mip++)
1524 qglGetCompressedTexImage(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1529 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1530 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1531 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1532 for (mip = 0;mip < mipmaps;mip++)
1534 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1537 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1538 ret = FS_WriteFile(filename, dds, ddssize);
1540 return ret ? ddssize : -5;
1545 // ELUAN: FIXME: separate this code
1546 #include "ktx10/include/ktx.h"
1549 rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qbool srgb, int flags, qbool *hasalphaflag, float *avgcolor, int miplevel, qbool optionaltexture) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint
1551 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1554 int bytesperblock, bytesperpixel;
1557 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1558 textypeinfo_t *texinfo;
1559 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1560 unsigned int c, r, g, b;
1561 GLint oldbindtexnum = 0;
1562 unsigned char *mippixels;
1563 unsigned char *mippixels_start;
1564 unsigned char *ddspixels;
1566 fs_offset_t ddsfilesize;
1567 unsigned int ddssize;
1568 qbool force_swdecode;
1570 // ELUAN: FIXME: separate this code
1574 KTX_dimensions sizes;
1577 if (cls.state == ca_dedicated)
1581 // ELUAN: FIXME: separate this code
1582 if (vid.renderpath != RENDERPATH_GLES2)
1584 Con_DPrintf("KTX texture format is only supported on the GLES2 renderpath\n");
1588 // some textures are specified with extensions, so it becomes .tga.dds
1589 FS_StripExtension (filename, vabuf2, sizeof(vabuf2));
1590 FS_StripExtension (vabuf2, vabuf, sizeof(vabuf));
1591 FS_DefaultExtension (vabuf, ".ktx", sizeof(vabuf));
1592 strsize = strlen(vabuf);
1594 for (i = 0; i <= strsize - 4; i++) // copy null termination
1595 vabuf[i] = vabuf[i + 4];
1597 Con_DPrintf("Loading %s...\n", vabuf);
1598 dds = FS_LoadFile(vabuf, tempmempool, true, &ddsfilesize);
1599 ddssize = ddsfilesize;
1603 Con_DPrintf("Not found!\n");
1604 return NULL; // not found
1606 Con_DPrintf("Found!\n");
1608 if (flags & TEXF_ALPHA)
1610 Con_DPrintf("KTX texture with alpha not supported yet, disabling\n");
1611 flags &= ~TEXF_ALPHA;
1617 GLboolean isMipmapped;
1618 KTX_error_code ktxerror;
1620 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1622 // texture uploading can take a while, so make sure we're sending keepalives
1623 CL_KeepaliveMessage(false);
1625 // create the texture object
1627 GL_ActiveTexture(0);
1628 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[GLTEXTURETYPE_2D]);
1629 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1630 qglBindTexture(gltexturetypeenums[GLTEXTURETYPE_2D], glt->texnum);CHECKGLERROR
1632 // upload the texture
1633 // we need to restore the texture binding after finishing the upload
1635 // NOTE: some drivers fail with ETC1 NPOT (only PowerVR?). This may make the driver crash later.
1636 ktxerror = ktxLoadTextureM(dds, ddssize, &glt->texnum, &target, &sizes, &isMipmapped, &glerror,
1637 0, NULL);// can't CHECKGLERROR, the lib catches it
1639 // FIXME: delete texture if we fail here
1640 if (target != GL_TEXTURE_2D)
1642 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1644 Con_DPrintf("%s target != GL_TEXTURE_2D, target == %x\n", vabuf, target);
1645 return NULL; // FIXME: delete the texture from memory
1648 if (KTX_SUCCESS == ktxerror)
1650 textype = TEXTYPE_ETC1;
1651 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
1653 // return whether this texture is transparent
1655 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1657 // TODO: apply gl_picmip
1660 // TODO: only load mipmaps if requested
1663 flags |= TEXF_MIPMAP;
1665 flags &= ~TEXF_MIPMAP;
1667 texinfo = R_GetTexTypeInfo(textype, flags);
1669 strlcpy (glt->identifier, vabuf, sizeof(glt->identifier));
1671 glt->chain = pool->gltchain;
1672 pool->gltchain = glt;
1673 glt->inputwidth = sizes.width;
1674 glt->inputheight = sizes.height;
1675 glt->inputdepth = 1;
1677 glt->textype = texinfo;
1678 glt->texturetype = GLTEXTURETYPE_2D;
1679 glt->inputdatasize = ddssize;
1680 glt->glinternalformat = texinfo->glinternalformat;
1681 glt->glformat = texinfo->glformat;
1682 glt->gltype = texinfo->gltype;
1683 glt->bytesperpixel = texinfo->internalbytesperpixel;
1685 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1686 glt->tilewidth = sizes.width;
1687 glt->tileheight = sizes.height;
1689 glt->miplevels = isMipmapped ? 1 : 0; // FIXME
1691 // after upload we have to set some parameters...
1692 #ifdef GL_TEXTURE_MAX_LEVEL
1694 if (dds_miplevels >= 1 && !mipcomplete)
1696 // need to set GL_TEXTURE_MAX_LEVEL
1697 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
1701 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1703 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1705 return (rtexture_t *)glt;
1709 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1711 Con_DPrintf("KTX texture %s failed to load: %x\n", vabuf, ktxerror);
1715 #endif // __ANDROID__
1717 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1718 ddssize = ddsfilesize;
1722 if (r_texture_dds_load_logfailure.integer && (r_texture_dds_load_logfailure.integer >= 2 || !optionaltexture))
1723 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1724 return NULL; // not found
1727 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1730 Con_Printf("^1%s: not a DDS image\n", filename);
1734 //dds_flags = BuffLittleLong(dds+8);
1735 dds_format_flags = BuffLittleLong(dds+80);
1736 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1737 dds_width = BuffLittleLong(dds+16);
1738 dds_height = BuffLittleLong(dds+12);
1739 ddspixels = dds + 128;
1741 if(r_texture_dds_load_alphamode.integer == 0)
1742 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1743 flags &= ~TEXF_ALPHA;
1745 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1746 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1748 // very sloppy BGRA 32bit identification
1749 textype = TEXTYPE_BGRA;
1750 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
1753 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1754 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1757 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1760 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1763 for (i = 3;i < size;i += 4)
1764 if (ddspixels[i] < 255)
1767 flags &= ~TEXF_ALPHA;
1770 else if (!memcmp(dds+84, "DXT1", 4))
1772 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1773 // LadyHavoc: it is my belief that this does not infringe on the
1774 // patent because it is not decoding pixels...
1775 textype = TEXTYPE_DXT1;
1778 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1779 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1780 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1783 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1786 if (flags & TEXF_ALPHA)
1788 if (r_texture_dds_load_alphamode.integer == 1)
1791 for (i = 0;i < size;i += bytesperblock)
1792 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1794 // NOTE: this assumes sizeof(unsigned int) == 4
1795 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1796 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1797 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1801 textype = TEXTYPE_DXT1A;
1803 flags &= ~TEXF_ALPHA;
1805 else if (r_texture_dds_load_alphamode.integer == 0)
1806 textype = TEXTYPE_DXT1A;
1809 flags &= ~TEXF_ALPHA;
1813 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
1815 if(!memcmp(dds+84, "DXT2", 4))
1817 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1819 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
1824 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1826 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
1829 textype = TEXTYPE_DXT3;
1832 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1833 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1836 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1839 // we currently always assume alpha
1841 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
1843 if(!memcmp(dds+84, "DXT4", 4))
1845 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1847 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
1852 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1854 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
1857 textype = TEXTYPE_DXT5;
1860 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1861 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1864 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1867 // we currently always assume alpha
1872 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1876 // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
1877 if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
1879 textype = TEXTYPE_DXT1;
1883 for (i = 0;i < (int)ddssize;i += bytesperblock)
1884 memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
1888 force_swdecode = false;
1891 if(vid.support.ext_texture_compression_s3tc)
1893 if(r_texture_dds_swdecode.integer > 1)
1894 force_swdecode = true;
1898 if(r_texture_dds_swdecode.integer < 1)
1904 force_swdecode = true;
1908 // return whether this texture is transparent
1910 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1912 // if we SW decode, choose 2 sizes bigger
1915 // this is quarter res, so do not scale down more than we have to
1919 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
1922 // this is where we apply gl_picmip
1923 mippixels_start = ddspixels;
1924 mipwidth = dds_width;
1925 mipheight = dds_height;
1926 while(miplevel >= 1 && dds_miplevels >= 1)
1928 if (mipwidth <= 1 && mipheight <= 1)
1930 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1931 mippixels_start += mipsize; // just skip
1939 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
1940 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1942 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
1944 // fake decode S3TC if needed
1947 int mipsize_new = mipsize_total / bytesperblock * 4;
1948 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
1949 unsigned char *p = mipnewpixels;
1950 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
1952 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
1953 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
1954 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
1955 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
1956 if(textype == TEXTYPE_DXT5)
1957 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
1958 else if(textype == TEXTYPE_DXT3)
1960 (mippixels_start[i-8] & 0x0F)
1961 + (mippixels_start[i-8] >> 4)
1962 + (mippixels_start[i-7] & 0x0F)
1963 + (mippixels_start[i-7] >> 4)
1964 + (mippixels_start[i-6] & 0x0F)
1965 + (mippixels_start[i-6] >> 4)
1966 + (mippixels_start[i-5] & 0x0F)
1967 + (mippixels_start[i-5] >> 4)
1968 ) * (0.125f / 15.0f * 255.0f);
1973 textype = TEXTYPE_BGRA;
1977 // as each block becomes a pixel, we must use pixel count for this
1978 mipwidth = (mipwidth + 3) / 4;
1979 mipheight = (mipheight + 3) / 4;
1980 mipsize = bytesperpixel * mipwidth * mipheight;
1981 mippixels_start = mipnewpixels;
1982 mipsize_total = mipsize_new;
1985 // start mip counting
1986 mippixels = mippixels_start;
1988 // calculate average color if requested
1992 Vector4Clear(avgcolor);
1995 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
1997 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
1998 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1999 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2000 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2001 if(textype == TEXTYPE_DXT5)
2002 avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f);
2003 else if(textype == TEXTYPE_DXT3)
2005 (mippixels_start[i-8] & 0x0F)
2006 + (mippixels_start[i-8] >> 4)
2007 + (mippixels_start[i-7] & 0x0F)
2008 + (mippixels_start[i-7] >> 4)
2009 + (mippixels_start[i-6] & 0x0F)
2010 + (mippixels_start[i-6] >> 4)
2011 + (mippixels_start[i-5] & 0x0F)
2012 + (mippixels_start[i-5] >> 4)
2013 ) * (0.125f / 15.0f);
2015 avgcolor[3] += 1.0f;
2017 f = (float)bytesperblock / mipsize;
2018 avgcolor[0] *= (0.5f / 31.0f) * f;
2019 avgcolor[1] *= (0.5f / 63.0f) * f;
2020 avgcolor[2] *= (0.5f / 31.0f) * f;
2025 for (i = 0;i < mipsize;i += 4)
2027 avgcolor[0] += mippixels[i+2];
2028 avgcolor[1] += mippixels[i+1];
2029 avgcolor[2] += mippixels[i];
2030 avgcolor[3] += mippixels[i+3];
2032 f = (1.0f / 255.0f) * bytesperpixel / mipsize;
2040 // if we want sRGB, convert now
2043 if (vid.support.ext_texture_srgb)
2047 case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break;
2048 case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break;
2049 case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break;
2050 case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break;
2051 case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break;
2065 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2067 int c0, c1, c0new, c1new;
2068 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2069 r = ((c0 >> 11) & 0x1F);
2070 g = ((c0 >> 5) & 0x3F);
2072 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2073 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2074 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2075 c0new = (r << 11) | (g << 5) | b;
2076 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2077 r = ((c1 >> 11) & 0x1F);
2078 g = ((c1 >> 5) & 0x3F);
2080 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2081 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2082 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2083 c1new = (r << 11) | (g << 5) | b;
2084 // swap the colors if needed to fix order
2085 if(c0 > c1) // thirds
2093 mippixels_start[i+4] ^= 0x55;
2094 mippixels_start[i+5] ^= 0x55;
2095 mippixels_start[i+6] ^= 0x55;
2096 mippixels_start[i+7] ^= 0x55;
2098 else if(c0new == c1new)
2100 mippixels_start[i+4] = 0x00;
2101 mippixels_start[i+5] = 0x00;
2102 mippixels_start[i+6] = 0x00;
2103 mippixels_start[i+7] = 0x00;
2106 else // half + transparent
2113 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2114 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2115 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2116 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2119 mippixels_start[i] = c0new & 255;
2120 mippixels_start[i+1] = c0new >> 8;
2121 mippixels_start[i+2] = c1new & 255;
2122 mippixels_start[i+3] = c1new >> 8;
2127 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2135 // when not requesting mipmaps, do not load them
2136 if(!(flags & TEXF_MIPMAP))
2139 if (dds_miplevels >= 1)
2140 flags |= TEXF_MIPMAP;
2142 flags &= ~TEXF_MIPMAP;
2144 texinfo = R_GetTexTypeInfo(textype, flags);
2146 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2147 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2149 glt->chain = pool->gltchain;
2150 pool->gltchain = glt;
2151 glt->inputwidth = mipwidth;
2152 glt->inputheight = mipheight;
2153 glt->inputdepth = 1;
2155 glt->textype = texinfo;
2156 glt->texturetype = GLTEXTURETYPE_2D;
2157 glt->inputdatasize = ddssize;
2158 glt->glinternalformat = texinfo->glinternalformat;
2159 glt->glformat = texinfo->glformat;
2160 glt->gltype = texinfo->gltype;
2161 glt->bytesperpixel = texinfo->internalbytesperpixel;
2163 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2164 glt->tilewidth = mipwidth;
2165 glt->tileheight = mipheight;
2167 glt->miplevels = dds_miplevels;
2169 // texture uploading can take a while, so make sure we're sending keepalives
2170 CL_KeepaliveMessage(false);
2172 // create the texture object
2173 switch(vid.renderpath)
2175 case RENDERPATH_GL32:
2176 case RENDERPATH_GLES2:
2178 GL_ActiveTexture(0);
2179 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2180 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2181 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2185 // upload the texture
2186 // we need to restore the texture binding after finishing the upload
2187 mipcomplete = false;
2189 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2191 unsigned char *upload_mippixels = mippixels;
2192 int upload_mipwidth = mipwidth;
2193 int upload_mipheight = mipheight;
2194 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2195 if (mippixels + mipsize > mippixels_start + mipsize_total)
2197 switch(vid.renderpath)
2199 case RENDERPATH_GL32:
2200 case RENDERPATH_GLES2:
2203 qglCompressedTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR
2207 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR
2211 if(upload_mippixels != mippixels)
2212 Mem_Free(upload_mippixels);
2213 mippixels += mipsize;
2214 if (mipwidth <= 1 && mipheight <= 1)
2225 // after upload we have to set some parameters...
2226 switch(vid.renderpath)
2228 case RENDERPATH_GL32:
2229 case RENDERPATH_GLES2:
2230 #ifdef GL_TEXTURE_MAX_LEVEL
2231 if (dds_miplevels >= 1 && !mipcomplete)
2233 // need to set GL_TEXTURE_MAX_LEVEL
2234 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2237 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2238 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2244 Mem_Free((unsigned char *) mippixels_start);
2245 return (rtexture_t *)glt;
2248 int R_TextureWidth(rtexture_t *rt)
2250 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2253 int R_TextureHeight(rtexture_t *rt)
2255 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2258 int R_TextureFlags(rtexture_t *rt)
2260 return rt ? ((gltexture_t *)rt)->flags : 0;
2263 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth, int combine)
2265 gltexture_t *glt = (gltexture_t *)rt;
2267 Host_Error("R_UpdateTexture: no data supplied");
2269 Host_Error("R_UpdateTexture: no texture supplied");
2272 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2275 // update part of the texture
2276 if (glt->bufferpixels)
2278 size_t j, bpp = glt->bytesperpixel;
2280 // depth and sides are not fully implemented here - can still do full updates but not partial.
2281 if (glt->inputdepth != 1 || glt->sides != 1)
2282 Host_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2283 if (x < 0 || y < 0 || z < 0 || glt->tilewidth < x + width || glt->tileheight < y + height || glt->tiledepth < z + depth)
2284 Host_Error("R_UpdateTexture on buffered texture with out of bounds coordinates (%i %i %i to %i %i %i is not within 0 0 0 to %i %i %i)", x, y, z, x + width, y + height, z + depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
2286 for (j = 0; j < (size_t)height; j++)
2287 memcpy(glt->bufferpixels + ((y + j) * glt->tilewidth + x) * bpp, data + j * width * bpp, width * bpp);
2292 // immediately update the part of the texture, no combining
2293 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2296 // keep track of the region that is modified, decide later how big the partial update area is
2297 if (glt->buffermodified)
2299 glt->modified_mins[0] = min(glt->modified_mins[0], x);
2300 glt->modified_mins[1] = min(glt->modified_mins[1], y);
2301 glt->modified_mins[2] = min(glt->modified_mins[2], z);
2302 glt->modified_maxs[0] = max(glt->modified_maxs[0], x + width);
2303 glt->modified_maxs[1] = max(glt->modified_maxs[1], y + height);
2304 glt->modified_maxs[2] = max(glt->modified_maxs[2], z + depth);
2308 glt->buffermodified = true;
2309 glt->modified_mins[0] = x;
2310 glt->modified_mins[1] = y;
2311 glt->modified_mins[2] = z;
2312 glt->modified_maxs[0] = x + width;
2313 glt->modified_maxs[1] = y + height;
2314 glt->modified_maxs[2] = z + depth;
2320 // mark the entire texture as dirty, it will be uploaded later
2321 glt->buffermodified = true;
2322 glt->modified_mins[0] = 0;
2323 glt->modified_mins[1] = 0;
2324 glt->modified_mins[2] = 0;
2325 glt->modified_maxs[0] = glt->tilewidth;
2326 glt->modified_maxs[1] = glt->tileheight;
2327 glt->modified_maxs[2] = glt->tiledepth;
2333 R_UploadFullTexture(glt, data);
2336 int R_RealGetTexture(rtexture_t *rt)
2341 glt = (gltexture_t *)rt;
2342 if (glt->flags & GLTEXF_DYNAMIC)
2343 R_UpdateDynamicTexture(glt);
2344 if (glt->buffermodified && glt->bufferpixels)
2346 glt->buffermodified = false;
2347 // Because we currently don't set the relevant upload stride parameters, just make it full width.
2348 glt->modified_mins[0] = 0;
2349 glt->modified_maxs[0] = glt->tilewidth;
2350 // Check also if it's updating at least half the height of the texture.
2351 if (glt->modified_maxs[1] - glt->modified_mins[1] > glt->tileheight / 2)
2352 R_UploadFullTexture(glt, glt->bufferpixels);
2354 R_UploadPartialTexture(glt, glt->bufferpixels + (size_t)glt->modified_mins[1] * glt->tilewidth * glt->bytesperpixel, glt->modified_mins[0], glt->modified_mins[1], glt->modified_mins[2], glt->modified_maxs[0] - glt->modified_mins[0], glt->modified_maxs[1] - glt->modified_mins[1], glt->modified_maxs[2] - glt->modified_mins[2]);
2356 VectorClear(glt->modified_mins);
2357 VectorClear(glt->modified_maxs);
2362 return r_texture_white->texnum;
2365 void R_ClearTexture (rtexture_t *rt)
2367 gltexture_t *glt = (gltexture_t *)rt;
2369 R_UploadFullTexture(glt, NULL);
2372 int R_PicmipForFlags(int flags)
2375 if(flags & TEXF_PICMIP)
2377 miplevel += gl_picmip.integer;
2378 if (flags & TEXF_ISWORLD)
2380 if (r_picmipworld.integer)
2381 miplevel += gl_picmip_world.integer;
2385 else if (flags & TEXF_ISSPRITE)
2387 if (r_picmipsprites.integer)
2388 miplevel += gl_picmip_sprites.integer;
2393 miplevel += gl_picmip_other.integer;
2395 return max(0, miplevel);