6 #include "intoverflow.h"
8 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)"};
9 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)"};
10 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%"};
11 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)"};
12 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)"};
13 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)"};
14 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)"};
15 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)"};
16 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)"};
17 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"};
18 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"};
19 cvar_t gl_texturecompression_color = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
20 cvar_t gl_texturecompression_normal = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
21 cvar_t gl_texturecompression_gloss = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
22 cvar_t gl_texturecompression_glow = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
23 cvar_t gl_texturecompression_2d = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
24 cvar_t gl_texturecompression_q3bsplightmaps = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
25 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)"};
26 cvar_t gl_texturecompression_sky = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
27 cvar_t gl_texturecompression_lightcubemaps = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
28 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)"};
29 cvar_t gl_texturecompression_sprites = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_sprites", "1", "whether to compress sprites"};
30 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"};
31 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"};
32 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"};
34 qbool gl_filter_force = false;
35 int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
36 int gl_filter_mag = GL_LINEAR;
39 static mempool_t *texturemempool;
40 static memexpandablearray_t texturearray;
42 // note: this must not conflict with TEXF_ flags in r_textures.h
43 // bitmask for mismatch checking
44 #define GLTEXF_IMPORTANTBITS (0)
45 // dynamic texture (treat texnum == 0 differently)
46 #define GLTEXF_DYNAMIC 0x00080000
48 typedef struct textypeinfo_s
52 int inputbytesperpixel;
53 int internalbytesperpixel;
54 float glinternalbytesperpixel;
63 // we use these internally even if we never deliver such data to the driver
65 #define GL_BGRA 0x80E1
67 // framebuffer texture formats
68 // GLES2 devices rarely support depth textures, so we actually use a renderbuffer there
69 static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
70 static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
71 static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
72 static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
73 static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
74 static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
75 static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
76 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 2, 2, 2.0f, GL_RGB565 , GL_RGBA , GL_UNSIGNED_SHORT_5_6_5};
77 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 2, 2, 2.0f, GL_RGBA16F , GL_RGBA , GL_HALF_FLOAT};
78 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 2, 2, 2.0f, GL_RGBA32F , GL_RGBA , GL_FLOAT};
81 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
82 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
83 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
84 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
85 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
86 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
87 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
89 static textypeinfo_t textype_etc1 = {"etc1", TEXTYPE_ETC1 , 1, 3, 0.5f, GL_ETC1_RGB8_OES , 0 , 0 };
92 // framebuffer texture formats
93 static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
94 static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
95 static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24 , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
96 static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 4, 4, 4.0f, GL_DEPTH_COMPONENT24 , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
97 static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
98 static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 4, 4, 4.0f, GL_DEPTH_COMPONENT24 , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
99 static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 4, 4, 4.0f, GL_DEPTH24_STENCIL8 , GL_DEPTH_STENCIL , GL_UNSIGNED_INT_24_8};
100 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
101 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 8, 8, 8.0f, GL_RGBA16F , GL_RGBA , GL_HALF_FLOAT };
102 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 16, 16, 16.0f, GL_RGBA32F , GL_RGBA , GL_FLOAT };
105 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
106 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
107 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
108 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE };
109 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
110 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 };
111 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 };
112 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
113 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
114 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 };
115 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 };
116 static textypeinfo_t textype_dxt1 = {"dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
117 static textypeinfo_t textype_dxt1a = {"dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 };
118 static textypeinfo_t textype_dxt3 = {"dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 };
119 static textypeinfo_t textype_dxt5 = {"dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 };
120 static textypeinfo_t textype_sRGB_palette = {"sRGB_palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB , GL_BGRA , GL_UNSIGNED_BYTE };
121 static textypeinfo_t textype_sRGB_palette_alpha = {"sRGB_palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_ALPHA , GL_BGRA , GL_UNSIGNED_BYTE };
122 static textypeinfo_t textype_sRGB_rgba = {"sRGB_rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB , GL_RGBA , GL_UNSIGNED_BYTE };
123 static textypeinfo_t textype_sRGB_rgba_alpha = {"sRGB_rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_ALPHA , GL_RGBA , GL_UNSIGNED_BYTE };
124 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 };
125 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 };
126 static textypeinfo_t textype_sRGB_bgra = {"sRGB_bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB , GL_BGRA , GL_UNSIGNED_BYTE };
127 static textypeinfo_t textype_sRGB_bgra_alpha = {"sRGB_bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_ALPHA , GL_BGRA , GL_UNSIGNED_BYTE };
128 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 };
129 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 };
130 static textypeinfo_t textype_sRGB_dxt1 = {"sRGB_dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , 0 , 0 };
131 static textypeinfo_t textype_sRGB_dxt1a = {"sRGB_dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 , 0 };
132 static textypeinfo_t textype_sRGB_dxt3 = {"sRGB_dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 , 0 };
133 static textypeinfo_t textype_sRGB_dxt5 = {"sRGB_dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 , 0 };
136 typedef enum gltexturetype_e
140 GLTEXTURETYPE_CUBEMAP,
145 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP};
146 #ifdef GL_TEXTURE_WRAP_R
147 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
149 static int cubemapside[6] =
151 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
152 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
153 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
154 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
155 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
156 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
159 typedef struct gltexture_s
161 // this portion of the struct is exposed to the R_GetTexture macro for
162 // speed reasons, must be identical in rtexture_t!
163 int texnum; // GL texture slot number
164 int renderbuffernum; // GL renderbuffer slot number
165 qbool dirty; // indicates that R_RealGetTexture should be called
166 qbool glisdepthstencil; // indicates that FBO attachment has to be GL_DEPTH_STENCIL_ATTACHMENT
167 int gltexturetypeenum; // used by R_Mesh_TexBind
169 // dynamic texture stuff [11/22/2007 Black]
170 updatecallback_t updatecallback;
171 void *updatecallback_data;
172 // --- [11/22/2007 Black]
174 // stores backup copy of texture for deferred texture updates (R_UpdateTexture when combine = true)
175 unsigned char *bufferpixels;
176 int modified_mins[3], modified_maxs[3];
177 qbool buffermodified;
179 // pointer to texturepool (check this to see if the texture is allocated)
180 struct gltexturepool_s *pool;
181 // pointer to next texture in texturepool chain
182 struct gltexture_s *chain;
183 // name of the texture (this might be removed someday), no duplicates
184 char identifier[MAX_QPATH + 32];
185 // original data size in *inputtexels
186 int inputwidth, inputheight, inputdepth;
187 // copy of the original texture(s) supplied to the upload function, for
188 // delayed uploads (non-precached)
189 unsigned char *inputtexels;
190 // original data size in *inputtexels
192 // flags supplied to the LoadTexture function
193 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
197 // pointer to one of the textype_ structs
198 textypeinfo_t *textype;
199 // one of the GLTEXTURETYPE_ values
201 // palette if the texture is TEXTYPE_PALETTE
202 const unsigned int *palette;
203 // actual stored texture size after gl_picmip and gl_max_size are applied
204 int tilewidth, tileheight, tiledepth;
205 // 1 or 6 depending on texturetype
207 // how many mipmap levels in this texture
211 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
214 int glinternalformat;
215 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
220 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
222 typedef struct gltexturepool_s
224 unsigned int sentinel;
225 struct gltexture_s *gltchain;
226 struct gltexturepool_s *next;
230 static gltexturepool_t *gltexturepoolchain = NULL;
232 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
233 static int resizebuffersize = 0;
234 static const unsigned char *texturebuffer;
236 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
241 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
242 case TEXTYPE_RGBA: return ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba);
243 case TEXTYPE_BGRA: return ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra);
245 case TEXTYPE_ETC1: return &textype_etc1;
247 case TEXTYPE_ALPHA: return &textype_alpha;
248 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
249 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
250 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
251 case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
252 case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
253 case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
254 case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
255 case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
256 case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
257 case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
259 case TEXTYPE_DXT1: return &textype_dxt1;
260 case TEXTYPE_DXT1A: return &textype_dxt1a;
261 case TEXTYPE_DXT3: return &textype_dxt3;
262 case TEXTYPE_DXT5: return &textype_dxt5;
263 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
264 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);
265 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);
266 case TEXTYPE_ALPHA: return &textype_alpha;
267 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
268 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
269 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
270 case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
271 case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
272 case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
273 case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
274 case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
275 case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
276 case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
277 case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1;
278 case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a;
279 case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
280 case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
281 case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
282 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);
283 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);
286 Host_Error("R_GetTexTypeInfo: unknown texture format %i with flags %x", (int)textype, flags);
292 // dynamic texture code [11/22/2007 Black]
293 void R_MarkDirtyTexture(rtexture_t *rt) {
294 gltexture_t *glt = (gltexture_t*) rt;
299 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
300 if (glt->flags & GLTEXF_DYNAMIC)
302 // mark it as dirty, so R_RealGetTexture gets called
307 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
308 gltexture_t *glt = (gltexture_t*) rt;
313 glt->flags |= GLTEXF_DYNAMIC;
314 glt->updatecallback = updatecallback;
315 glt->updatecallback_data = data;
318 static void R_UpdateDynamicTexture(gltexture_t *glt) {
320 if( glt->updatecallback ) {
321 glt->updatecallback( (rtexture_t*) glt, glt->updatecallback_data );
325 void R_PurgeTexture(rtexture_t *rt)
327 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
332 void R_FreeTexture(rtexture_t *rt)
334 gltexture_t *glt, **gltpointer;
336 glt = (gltexture_t *)rt;
338 Host_Error("R_FreeTexture: texture == NULL");
340 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
341 if (*gltpointer == glt)
342 *gltpointer = glt->chain;
344 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
346 R_Mesh_ClearBindingsForTexture(glt->texnum);
348 switch(vid.renderpath)
350 case RENDERPATH_GL32:
351 case RENDERPATH_GLES2:
355 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
357 if (glt->renderbuffernum)
360 qglDeleteRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
365 if (glt->inputtexels)
366 Mem_Free(glt->inputtexels);
367 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
370 rtexturepool_t *R_AllocTexturePool(void)
372 gltexturepool_t *pool;
373 if (texturemempool == NULL)
375 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
378 pool->next = gltexturepoolchain;
379 gltexturepoolchain = pool;
380 pool->sentinel = TEXTUREPOOL_SENTINEL;
381 return (rtexturepool_t *)pool;
384 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
386 gltexturepool_t *pool, **poolpointer;
387 if (rtexturepool == NULL)
389 if (*rtexturepool == NULL)
391 pool = (gltexturepool_t *)(*rtexturepool);
392 *rtexturepool = NULL;
393 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
394 Host_Error("R_FreeTexturePool: pool already freed");
395 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
396 if (*poolpointer == pool)
397 *poolpointer = pool->next;
399 Host_Error("R_FreeTexturePool: pool not linked");
400 while (pool->gltchain)
401 R_FreeTexture((rtexture_t *)pool->gltchain);
406 typedef struct glmode_s
409 int minification, magnification;
413 static glmode_t modes[6] =
415 {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
416 {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
417 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
418 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
419 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
420 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
423 static void GL_TextureMode_f(cmd_state_t *cmd)
428 gltexturepool_t *pool;
430 if (Cmd_Argc(cmd) == 1)
432 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
433 for (i = 0;i < 6;i++)
435 if (gl_filter_min == modes[i].minification)
437 Con_Printf("%s\n", modes[i].name);
441 Con_Print("current filter is unknown???\n");
445 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
446 if (!strcasecmp (modes[i].name, Cmd_Argv(cmd, 1) ) )
450 Con_Print("bad filter name\n");
454 gl_filter_min = modes[i].minification;
455 gl_filter_mag = modes[i].magnification;
456 gl_filter_force = ((Cmd_Argc(cmd) > 2) && !strcasecmp(Cmd_Argv(cmd, 2), "force"));
458 switch(vid.renderpath)
460 case RENDERPATH_GL32:
461 case RENDERPATH_GLES2:
462 // change all the existing mipmap texture objects
463 // FIXME: force renderer(/client/something?) restart instead?
466 for (pool = gltexturepoolchain;pool;pool = pool->next)
468 for (glt = pool->gltchain;glt;glt = glt->chain)
470 // only update already uploaded images
471 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
473 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
474 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
475 if (glt->flags & TEXF_MIPMAP)
477 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
481 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
483 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
484 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
492 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)
494 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
499 case GLTEXTURETYPE_2D:
500 maxsize = vid.maxtexturesize_2d;
501 if (flags & TEXF_PICMIP)
503 maxsize = bound(1, gl_max_size.integer, maxsize);
507 case GLTEXTURETYPE_3D:
508 maxsize = vid.maxtexturesize_3d;
510 case GLTEXTURETYPE_CUBEMAP:
511 maxsize = vid.maxtexturesize_cubemap;
515 width2 = min(inwidth >> picmip, maxsize);
516 height2 = min(inheight >> picmip, maxsize);
517 depth2 = min(indepth >> picmip, maxsize);
520 if (flags & TEXF_MIPMAP)
522 int extent = max(width2, max(height2, depth2));
528 *outwidth = max(1, width2);
530 *outheight = max(1, height2);
532 *outdepth = max(1, depth2);
534 *outmiplevels = miplevels;
538 static int R_CalcTexelDataSize (gltexture_t *glt)
540 int width2, height2, depth2, size;
542 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
544 size = width2 * height2 * depth2;
546 if (glt->flags & TEXF_MIPMAP)
548 while (width2 > 1 || height2 > 1 || depth2 > 1)
556 size += width2 * height2 * depth2;
560 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
563 void R_TextureStats_Print(qbool printeach, qbool printpool, qbool printtotal)
567 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
568 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
570 gltexturepool_t *pool;
572 Con_Print("glsize input loaded mip alpha name\n");
573 for (pool = gltexturepoolchain;pool;pool = pool->next)
581 for (glt = pool->gltchain;glt;glt = glt->chain)
583 glsize = R_CalcTexelDataSize(glt);
584 isloaded = glt->texnum != 0 || glt->renderbuffernum != 0;
586 pooltotalt += glsize;
587 pooltotalp += glt->inputdatasize;
591 poolloadedt += glsize;
592 poolloadedp += glt->inputdatasize;
595 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);
598 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);
599 sumtotal += pooltotal;
600 sumtotalt += pooltotalt;
601 sumtotalp += pooltotalp;
602 sumloaded += poolloaded;
603 sumloadedt += poolloadedt;
604 sumloadedp += poolloadedp;
607 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);
610 static void R_TextureStats_f(cmd_state_t *cmd)
612 R_TextureStats_Print(true, true, true);
615 static void r_textures_start(void)
617 switch(vid.renderpath)
619 case RENDERPATH_GL32:
620 case RENDERPATH_GLES2:
621 // LadyHavoc: allow any alignment
623 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
624 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
628 texturemempool = Mem_AllocPool("texture management", 0, NULL);
629 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
631 // Disable JPEG screenshots if the DLL isn't loaded
632 if (! JPEG_OpenLibrary ())
633 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
634 if (! PNG_OpenLibrary ())
635 Cvar_SetValueQuick (&scr_screenshot_png, 0);
638 static void r_textures_shutdown(void)
640 rtexturepool_t *temp;
642 JPEG_CloseLibrary ();
644 while(gltexturepoolchain)
646 temp = (rtexturepool_t *) gltexturepoolchain;
647 R_FreeTexturePool(&temp);
650 resizebuffersize = 0;
652 colorconvertbuffer = NULL;
653 texturebuffer = NULL;
654 Mem_ExpandableArray_FreeArray(&texturearray);
655 Mem_FreePool(&texturemempool);
658 static void r_textures_newmap(void)
662 static void r_textures_devicelost(void)
666 endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
667 for (i = 0;i < endindex;i++)
669 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
670 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
672 switch(vid.renderpath)
674 case RENDERPATH_GL32:
675 case RENDERPATH_GLES2:
681 static void r_textures_devicerestored(void)
685 endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
686 for (i = 0;i < endindex;i++)
688 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
689 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
691 switch(vid.renderpath)
693 case RENDERPATH_GL32:
694 case RENDERPATH_GLES2:
701 void R_Textures_Init (void)
703 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");
704 Cmd_AddCommand(CF_CLIENT, "r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
705 Cvar_RegisterVariable (&gl_max_size);
706 Cvar_RegisterVariable (&gl_picmip);
707 Cvar_RegisterVariable (&gl_picmip_world);
708 Cvar_RegisterVariable (&r_picmipworld);
709 Cvar_RegisterVariable (&gl_picmip_sprites);
710 Cvar_RegisterVariable (&r_picmipsprites);
711 Cvar_RegisterVariable (&gl_picmip_other);
712 Cvar_RegisterVariable (&gl_max_lightmapsize);
713 Cvar_RegisterVariable (&r_lerpimages);
714 Cvar_RegisterVariable (&gl_texture_anisotropy);
715 Cvar_RegisterVariable (&gl_texturecompression);
716 Cvar_RegisterVariable (&gl_texturecompression_color);
717 Cvar_RegisterVariable (&gl_texturecompression_normal);
718 Cvar_RegisterVariable (&gl_texturecompression_gloss);
719 Cvar_RegisterVariable (&gl_texturecompression_glow);
720 Cvar_RegisterVariable (&gl_texturecompression_2d);
721 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
722 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
723 Cvar_RegisterVariable (&gl_texturecompression_sky);
724 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
725 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
726 Cvar_RegisterVariable (&gl_texturecompression_sprites);
727 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
728 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
729 Cvar_RegisterVariable (&r_texture_dds_swdecode);
731 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
734 void R_Textures_Frame (void)
736 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
737 static int old_aniso = 0;
738 static qbool first_time_aniso = true;
741 // could do procedural texture animation here, if we keep track of which
742 // textures were accessed this frame...
744 // free the resize buffers
745 resizebuffersize = 0;
748 Mem_Free(resizebuffer);
751 if (colorconvertbuffer)
753 Mem_Free(colorconvertbuffer);
754 colorconvertbuffer = NULL;
757 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
758 if (old_aniso != gl_texture_anisotropy.integer)
761 gltexturepool_t *pool;
764 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
766 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
768 switch(vid.renderpath)
770 case RENDERPATH_GL32:
771 case RENDERPATH_GLES2:
772 // ignore the first difference, any textures loaded by now probably had the same aniso value
773 if (first_time_aniso)
775 first_time_aniso = false;
780 for (pool = gltexturepoolchain;pool;pool = pool->next)
782 for (glt = pool->gltchain;glt;glt = glt->chain)
784 // only update already uploaded images
785 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
787 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
789 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
790 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
792 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
802 static void R_MakeResizeBufferBigger(int size)
804 if (resizebuffersize < size)
806 resizebuffersize = size;
808 Mem_Free(resizebuffer);
809 if (colorconvertbuffer)
810 Mem_Free(colorconvertbuffer);
811 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
812 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
813 if (!resizebuffer || !colorconvertbuffer)
814 Host_Error("R_Upload: out of memory");
818 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
820 int textureenum = gltexturetypeenums[texturetype];
821 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
825 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
826 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
828 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
829 if (gl_texture_anisotropy.integer != aniso)
830 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
831 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
834 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
835 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
836 #ifdef GL_TEXTURE_WRAP_R
837 if (gltexturetypedimensions[texturetype] >= 3)
839 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
844 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
846 if (flags & TEXF_MIPMAP)
848 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
852 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
854 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
856 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
858 if (flags & TEXF_MIPMAP)
860 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
862 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
866 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
871 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
873 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
877 if (flags & TEXF_MIPMAP)
879 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
883 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
885 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
891 case TEXTYPE_SHADOWMAP16_COMP:
892 case TEXTYPE_SHADOWMAP24_COMP:
893 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);CHECKGLERROR
894 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);CHECKGLERROR
896 case TEXTYPE_SHADOWMAP16_RAW:
897 case TEXTYPE_SHADOWMAP24_RAW:
898 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE, GL_NONE);CHECKGLERROR
899 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);CHECKGLERROR
909 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
912 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
914 if (glt->texturetype != GLTEXTURETYPE_2D)
915 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
917 if (glt->textype->textype == TEXTYPE_PALETTE)
918 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
920 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
921 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
923 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
924 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
926 // update a portion of the image
928 switch(vid.renderpath)
930 case RENDERPATH_GL32:
931 case RENDERPATH_GLES2:
935 // we need to restore the texture binding after finishing the upload
937 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
938 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
939 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
940 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
946 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
948 int i, mip = 0, width, height, depth;
949 GLint oldbindtexnum = 0;
950 const unsigned char *prevbuffer;
953 // error out if a stretch is needed on special texture types
954 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
955 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
957 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
958 // of the target size and then use the mipmap reduction function to get
959 // high quality supersampled results
960 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
961 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
962 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
964 if (prevbuffer == NULL)
966 width = glt->tilewidth;
967 height = glt->tileheight;
968 depth = glt->tiledepth;
969 // R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
970 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
971 // prevbuffer = resizebuffer;
975 if (glt->textype->textype == TEXTYPE_PALETTE)
977 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
978 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
979 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
980 prevbuffer = colorconvertbuffer;
982 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
984 // multiply RGB channels by A channel before uploading
986 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
987 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
989 alpha = prevbuffer[i+3];
990 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
991 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
992 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
993 colorconvertbuffer[i+3] = alpha;
995 prevbuffer = colorconvertbuffer;
997 // scale up to a power of 2 size (if appropriate)
998 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1000 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1001 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1002 prevbuffer = resizebuffer;
1004 // apply mipmap reduction algorithm to get down to picmip/max_size
1005 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1007 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1008 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1009 prevbuffer = resizebuffer;
1013 // do the appropriate upload type...
1014 switch(vid.renderpath)
1016 case RENDERPATH_GL32:
1017 case RENDERPATH_GLES2:
1018 if (glt->texnum) // not renderbuffers
1022 // we need to restore the texture binding after finishing the upload
1023 GL_ActiveTexture(0);
1024 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1025 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1028 if (gl_texturecompression.integer >= 2)
1029 qglHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
1031 qglHint(GL_TEXTURE_COMPRESSION_HINT, GL_FASTEST);
1034 switch(glt->texturetype)
1036 case GLTEXTURETYPE_2D:
1037 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1038 if (glt->flags & TEXF_MIPMAP)
1040 while (width > 1 || height > 1 || depth > 1)
1042 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1043 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1044 prevbuffer = resizebuffer;
1045 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1049 case GLTEXTURETYPE_3D:
1051 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1052 if (glt->flags & TEXF_MIPMAP)
1054 while (width > 1 || height > 1 || depth > 1)
1056 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1057 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1058 prevbuffer = resizebuffer;
1059 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1064 case GLTEXTURETYPE_CUBEMAP:
1065 // convert and upload each side in turn,
1066 // from a continuous block of input texels
1067 texturebuffer = (unsigned char *)prevbuffer;
1068 for (i = 0;i < 6;i++)
1070 prevbuffer = texturebuffer;
1071 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1072 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1074 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1075 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1076 prevbuffer = resizebuffer;
1079 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1081 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1082 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1083 prevbuffer = resizebuffer;
1086 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1087 if (glt->flags & TEXF_MIPMAP)
1089 while (width > 1 || height > 1 || depth > 1)
1091 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1092 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1093 prevbuffer = resizebuffer;
1094 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1100 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1101 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1107 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)
1111 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1112 textypeinfo_t *texinfo, *texinfo2;
1113 unsigned char *temppixels = NULL;
1116 if (cls.state == ca_dedicated)
1119 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1120 if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1122 int numpixels = width * height * depth * sides;
1123 size = numpixels * 4;
1124 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1127 const unsigned char *p;
1128 unsigned char *o = temppixels;
1129 for (i = 0;i < numpixels;i++, o += 4)
1131 p = (const unsigned char *)palette + 4*data[i];
1139 textype = TEXTYPE_RGBA;
1144 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1145 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1146 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1147 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1153 static int rgbaswapindices[4] = {2, 1, 0, 3};
1154 size = width * height * depth * sides * 4;
1155 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1157 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1161 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1162 if (!vid.support.ext_texture_srgb)
1164 qbool convertsRGB = false;
1167 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1168 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1169 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1170 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1171 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;/*convertsRGB = true;*/break;
1172 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1173 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1177 if (convertsRGB && data)
1179 size = width * height * depth * sides * 4;
1182 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1183 memcpy(temppixels, data, size);
1186 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1190 texinfo = R_GetTexTypeInfo(textype, flags);
1191 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1194 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1198 // clear the alpha flag if the texture has no transparent pixels
1201 case TEXTYPE_PALETTE:
1202 case TEXTYPE_SRGB_PALETTE:
1203 if (flags & TEXF_ALPHA)
1205 flags &= ~TEXF_ALPHA;
1208 for (i = 0;i < size;i++)
1210 if (((unsigned char *)&palette[data[i]])[3] < 255)
1212 flags |= TEXF_ALPHA;
1221 case TEXTYPE_SRGB_RGBA:
1222 case TEXTYPE_SRGB_BGRA:
1223 if (flags & TEXF_ALPHA)
1225 flags &= ~TEXF_ALPHA;
1228 for (i = 3;i < size;i += 4)
1232 flags |= TEXF_ALPHA;
1239 case TEXTYPE_SHADOWMAP16_COMP:
1240 case TEXTYPE_SHADOWMAP16_RAW:
1241 case TEXTYPE_SHADOWMAP24_COMP:
1242 case TEXTYPE_SHADOWMAP24_RAW:
1245 case TEXTYPE_SRGB_DXT1:
1248 case TEXTYPE_SRGB_DXT1A:
1250 case TEXTYPE_SRGB_DXT3:
1252 case TEXTYPE_SRGB_DXT5:
1253 flags |= TEXF_ALPHA;
1256 flags |= TEXF_ALPHA;
1258 case TEXTYPE_COLORBUFFER:
1259 case TEXTYPE_COLORBUFFER16F:
1260 case TEXTYPE_COLORBUFFER32F:
1261 flags |= TEXF_ALPHA;
1264 Sys_Error("R_LoadTexture: unknown texture type");
1267 texinfo2 = R_GetTexTypeInfo(textype, flags);
1268 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1271 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1273 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1275 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1277 glt->chain = pool->gltchain;
1278 pool->gltchain = glt;
1279 glt->inputwidth = width;
1280 glt->inputheight = height;
1281 glt->inputdepth = depth;
1283 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
1284 glt->textype = texinfo;
1285 glt->texturetype = texturetype;
1286 glt->inputdatasize = size;
1287 glt->palette = palette;
1288 glt->glinternalformat = texinfo->glinternalformat;
1289 glt->glformat = texinfo->glformat;
1290 glt->gltype = texinfo->gltype;
1291 glt->bytesperpixel = texinfo->internalbytesperpixel;
1292 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1295 glt->glisdepthstencil = false;
1296 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1297 // init the dynamic texture attributes, too [11/22/2007 Black]
1298 glt->updatecallback = NULL;
1299 glt->updatecallback_data = NULL;
1301 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1303 // upload the texture
1304 // data may be NULL (blank texture for dynamic rendering)
1305 switch(vid.renderpath)
1307 case RENDERPATH_GL32:
1308 case RENDERPATH_GLES2:
1310 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1314 R_UploadFullTexture(glt, data);
1315 if (glt->flags & TEXF_ALLOWUPDATES)
1316 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1318 glt->buffermodified = false;
1319 VectorClear(glt->modified_mins);
1320 VectorClear(glt->modified_maxs);
1322 // free any temporary processing buffer we allocated...
1324 Mem_Free(temppixels);
1326 // texture converting and uploading can take a while, so make sure we're sending keepalives
1327 // FIXME: this causes rendering during R_Shadow_DrawLights
1328 // CL_KeepaliveMessage(false);
1330 return (rtexture_t *)glt;
1333 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)
1335 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1338 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)
1340 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1343 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)
1345 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1348 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qbool filter)
1350 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL);
1353 rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
1356 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1357 textypeinfo_t *texinfo;
1359 if (cls.state == ca_dedicated)
1362 texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP);
1364 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1366 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1368 glt->chain = pool->gltchain;
1369 pool->gltchain = glt;
1370 glt->inputwidth = width;
1371 glt->inputheight = height;
1372 glt->inputdepth = 1;
1373 glt->flags = TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_FORCENEAREST;
1375 glt->textype = texinfo;
1376 glt->texturetype = textype;
1377 glt->inputdatasize = width*height*texinfo->internalbytesperpixel;
1378 glt->palette = NULL;
1379 glt->glinternalformat = texinfo->glinternalformat;
1380 glt->glformat = texinfo->glformat;
1381 glt->gltype = texinfo->gltype;
1382 glt->bytesperpixel = texinfo->internalbytesperpixel;
1383 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1386 glt->glisdepthstencil = textype == TEXTYPE_DEPTHBUFFER24STENCIL8;
1387 glt->gltexturetypeenum = GL_TEXTURE_2D;
1388 // init the dynamic texture attributes, too [11/22/2007 Black]
1389 glt->updatecallback = NULL;
1390 glt->updatecallback_data = NULL;
1392 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1394 // upload the texture
1395 // data may be NULL (blank texture for dynamic rendering)
1396 switch(vid.renderpath)
1398 case RENDERPATH_GL32:
1399 case RENDERPATH_GLES2:
1401 qglGenRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
1402 qglBindRenderbuffer(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR
1403 qglRenderbufferStorage(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR
1404 // 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
1405 qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR
1409 return (rtexture_t *)glt;
1412 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qbool skipuncompressed, qbool hasalpha)
1415 return -1; // unsupported on this platform
1417 gltexture_t *glt = (gltexture_t *)rt;
1420 int bytesperpixel = 0;
1421 int bytesperblock = 0;
1423 int dds_format_flags;
1431 GLint internalformat;
1432 const char *ddsfourcc;
1434 return -1; // NULL pointer
1435 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1436 return -2; // broken driver - crashes on reading internal format
1437 if (!qglGetTexLevelParameteriv)
1439 GL_ActiveTexture(0);
1440 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1441 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1442 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1443 switch(internalformat)
1445 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1446 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1447 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1448 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1449 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1451 // if premultiplied alpha, say so in the DDS file
1452 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1454 switch(internalformat)
1456 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1457 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1460 if (!bytesperblock && skipuncompressed)
1461 return -3; // skipped
1462 memset(mipinfo, 0, sizeof(mipinfo));
1463 mipinfo[0][0] = glt->tilewidth;
1464 mipinfo[0][1] = glt->tileheight;
1466 if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1))
1468 for (mip = 1;mip < 16;mip++)
1470 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1471 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1472 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1480 for (mip = 0;mip < mipmaps;mip++)
1482 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1483 mipinfo[mip][3] = ddssize;
1484 ddssize += mipinfo[mip][2];
1486 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1489 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1493 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1494 dds_format_flags = 0x4; // DDPF_FOURCC
1498 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1499 dds_format_flags = 0x40; // DDPF_RGB
1503 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1504 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1507 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1508 memcpy(dds, "DDS ", 4);
1509 StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
1510 StoreLittleLong(dds+8, dds_flags);
1511 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1512 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1513 StoreLittleLong(dds+24, 0); // depth
1514 StoreLittleLong(dds+28, mipmaps); // mipmaps
1515 StoreLittleLong(dds+76, 32); // format size
1516 StoreLittleLong(dds+80, dds_format_flags);
1517 StoreLittleLong(dds+108, dds_caps1);
1518 StoreLittleLong(dds+112, dds_caps2);
1521 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1522 memcpy(dds+84, ddsfourcc, 4);
1523 for (mip = 0;mip < mipmaps;mip++)
1525 qglGetCompressedTexImage(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1530 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1531 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1532 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1533 for (mip = 0;mip < mipmaps;mip++)
1535 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1538 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1539 ret = FS_WriteFile(filename, dds, ddssize);
1541 return ret ? ddssize : -5;
1546 // ELUAN: FIXME: separate this code
1547 #include "ktx10/include/ktx.h"
1550 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
1552 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1555 int bytesperblock, bytesperpixel;
1558 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1559 textypeinfo_t *texinfo;
1560 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1561 unsigned int c, r, g, b;
1562 GLint oldbindtexnum = 0;
1563 unsigned char *mippixels;
1564 unsigned char *mippixels_start;
1565 unsigned char *ddspixels;
1567 fs_offset_t ddsfilesize;
1568 unsigned int ddssize;
1569 qbool force_swdecode;
1571 // ELUAN: FIXME: separate this code
1575 KTX_dimensions sizes;
1578 if (cls.state == ca_dedicated)
1582 // ELUAN: FIXME: separate this code
1583 if (vid.renderpath != RENDERPATH_GLES2)
1585 Con_DPrintf("KTX texture format is only supported on the GLES2 renderpath\n");
1589 // some textures are specified with extensions, so it becomes .tga.dds
1590 FS_StripExtension (filename, vabuf2, sizeof(vabuf2));
1591 FS_StripExtension (vabuf2, vabuf, sizeof(vabuf));
1592 FS_DefaultExtension (vabuf, ".ktx", sizeof(vabuf));
1593 strsize = strlen(vabuf);
1595 for (i = 0; i <= strsize - 4; i++) // copy null termination
1596 vabuf[i] = vabuf[i + 4];
1598 Con_DPrintf("Loading %s...\n", vabuf);
1599 dds = FS_LoadFile(vabuf, tempmempool, true, &ddsfilesize);
1600 ddssize = ddsfilesize;
1604 Con_DPrintf("Not found!\n");
1605 return NULL; // not found
1607 Con_DPrintf("Found!\n");
1609 if (flags & TEXF_ALPHA)
1611 Con_DPrintf("KTX texture with alpha not supported yet, disabling\n");
1612 flags &= ~TEXF_ALPHA;
1618 GLboolean isMipmapped;
1619 KTX_error_code ktxerror;
1621 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1623 // texture uploading can take a while, so make sure we're sending keepalives
1624 CL_KeepaliveMessage(false);
1626 // create the texture object
1628 GL_ActiveTexture(0);
1629 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[GLTEXTURETYPE_2D]);
1630 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1631 qglBindTexture(gltexturetypeenums[GLTEXTURETYPE_2D], glt->texnum);CHECKGLERROR
1633 // upload the texture
1634 // we need to restore the texture binding after finishing the upload
1636 // NOTE: some drivers fail with ETC1 NPOT (only PowerVR?). This may make the driver crash later.
1637 ktxerror = ktxLoadTextureM(dds, ddssize, &glt->texnum, &target, &sizes, &isMipmapped, &glerror,
1638 0, NULL);// can't CHECKGLERROR, the lib catches it
1640 // FIXME: delete texture if we fail here
1641 if (target != GL_TEXTURE_2D)
1643 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1645 Con_DPrintf("%s target != GL_TEXTURE_2D, target == %x\n", vabuf, target);
1646 return NULL; // FIXME: delete the texture from memory
1649 if (KTX_SUCCESS == ktxerror)
1651 textype = TEXTYPE_ETC1;
1652 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
1654 // return whether this texture is transparent
1656 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1658 // TODO: apply gl_picmip
1661 // TODO: only load mipmaps if requested
1664 flags |= TEXF_MIPMAP;
1666 flags &= ~TEXF_MIPMAP;
1668 texinfo = R_GetTexTypeInfo(textype, flags);
1670 strlcpy (glt->identifier, vabuf, sizeof(glt->identifier));
1672 glt->chain = pool->gltchain;
1673 pool->gltchain = glt;
1674 glt->inputwidth = sizes.width;
1675 glt->inputheight = sizes.height;
1676 glt->inputdepth = 1;
1678 glt->textype = texinfo;
1679 glt->texturetype = GLTEXTURETYPE_2D;
1680 glt->inputdatasize = ddssize;
1681 glt->glinternalformat = texinfo->glinternalformat;
1682 glt->glformat = texinfo->glformat;
1683 glt->gltype = texinfo->gltype;
1684 glt->bytesperpixel = texinfo->internalbytesperpixel;
1686 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1687 glt->tilewidth = sizes.width;
1688 glt->tileheight = sizes.height;
1690 glt->miplevels = isMipmapped ? 1 : 0; // FIXME
1692 // after upload we have to set some parameters...
1693 #ifdef GL_TEXTURE_MAX_LEVEL
1695 if (dds_miplevels >= 1 && !mipcomplete)
1697 // need to set GL_TEXTURE_MAX_LEVEL
1698 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
1702 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1704 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1706 return (rtexture_t *)glt;
1710 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1712 Con_DPrintf("KTX texture %s failed to load: %x\n", vabuf, ktxerror);
1716 #endif // __ANDROID__
1718 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1719 ddssize = ddsfilesize;
1723 if (r_texture_dds_load_logfailure.integer && (r_texture_dds_load_logfailure.integer >= 2 || !optionaltexture))
1724 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1725 return NULL; // not found
1728 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1731 Con_Printf("^1%s: not a DDS image\n", filename);
1735 //dds_flags = BuffLittleLong(dds+8);
1736 dds_format_flags = BuffLittleLong(dds+80);
1737 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1738 dds_width = BuffLittleLong(dds+16);
1739 dds_height = BuffLittleLong(dds+12);
1740 ddspixels = dds + 128;
1742 if(r_texture_dds_load_alphamode.integer == 0)
1743 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1744 flags &= ~TEXF_ALPHA;
1746 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1747 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1749 // very sloppy BGRA 32bit identification
1750 textype = TEXTYPE_BGRA;
1751 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
1754 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1755 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1758 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1761 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1764 for (i = 3;i < size;i += 4)
1765 if (ddspixels[i] < 255)
1768 flags &= ~TEXF_ALPHA;
1771 else if (!memcmp(dds+84, "DXT1", 4))
1773 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1774 // LadyHavoc: it is my belief that this does not infringe on the
1775 // patent because it is not decoding pixels...
1776 textype = TEXTYPE_DXT1;
1779 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1780 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1781 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1784 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1787 if (flags & TEXF_ALPHA)
1789 if (r_texture_dds_load_alphamode.integer == 1)
1792 for (i = 0;i < size;i += bytesperblock)
1793 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1795 // NOTE: this assumes sizeof(unsigned int) == 4
1796 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1797 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1798 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1802 textype = TEXTYPE_DXT1A;
1804 flags &= ~TEXF_ALPHA;
1806 else if (r_texture_dds_load_alphamode.integer == 0)
1807 textype = TEXTYPE_DXT1A;
1810 flags &= ~TEXF_ALPHA;
1814 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
1816 if(!memcmp(dds+84, "DXT2", 4))
1818 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1820 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
1825 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1827 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
1830 textype = TEXTYPE_DXT3;
1833 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1834 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1837 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1840 // we currently always assume alpha
1842 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
1844 if(!memcmp(dds+84, "DXT4", 4))
1846 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1848 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
1853 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1855 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
1858 textype = TEXTYPE_DXT5;
1861 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1862 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1865 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1868 // we currently always assume alpha
1873 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1877 // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
1878 if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
1880 textype = TEXTYPE_DXT1;
1884 for (i = 0;i < (int)ddssize;i += bytesperblock)
1885 memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
1889 force_swdecode = false;
1892 if(vid.support.ext_texture_compression_s3tc)
1894 if(r_texture_dds_swdecode.integer > 1)
1895 force_swdecode = true;
1899 if(r_texture_dds_swdecode.integer < 1)
1905 force_swdecode = true;
1909 // return whether this texture is transparent
1911 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1913 // if we SW decode, choose 2 sizes bigger
1916 // this is quarter res, so do not scale down more than we have to
1920 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
1923 // this is where we apply gl_picmip
1924 mippixels_start = ddspixels;
1925 mipwidth = dds_width;
1926 mipheight = dds_height;
1927 while(miplevel >= 1 && dds_miplevels >= 1)
1929 if (mipwidth <= 1 && mipheight <= 1)
1931 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1932 mippixels_start += mipsize; // just skip
1940 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
1941 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1943 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
1945 // fake decode S3TC if needed
1948 int mipsize_new = mipsize_total / bytesperblock * 4;
1949 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
1950 unsigned char *p = mipnewpixels;
1951 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
1953 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
1954 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
1955 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
1956 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
1957 if(textype == TEXTYPE_DXT5)
1958 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
1959 else if(textype == TEXTYPE_DXT3)
1961 (mippixels_start[i-8] & 0x0F)
1962 + (mippixels_start[i-8] >> 4)
1963 + (mippixels_start[i-7] & 0x0F)
1964 + (mippixels_start[i-7] >> 4)
1965 + (mippixels_start[i-6] & 0x0F)
1966 + (mippixels_start[i-6] >> 4)
1967 + (mippixels_start[i-5] & 0x0F)
1968 + (mippixels_start[i-5] >> 4)
1969 ) * (0.125f / 15.0f * 255.0f);
1974 textype = TEXTYPE_BGRA;
1978 // as each block becomes a pixel, we must use pixel count for this
1979 mipwidth = (mipwidth + 3) / 4;
1980 mipheight = (mipheight + 3) / 4;
1981 mipsize = bytesperpixel * mipwidth * mipheight;
1982 mippixels_start = mipnewpixels;
1983 mipsize_total = mipsize_new;
1986 // start mip counting
1987 mippixels = mippixels_start;
1989 // calculate average color if requested
1993 Vector4Clear(avgcolor);
1996 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
1998 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
1999 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2000 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2001 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2002 if(textype == TEXTYPE_DXT5)
2003 avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f);
2004 else if(textype == TEXTYPE_DXT3)
2006 (mippixels_start[i-8] & 0x0F)
2007 + (mippixels_start[i-8] >> 4)
2008 + (mippixels_start[i-7] & 0x0F)
2009 + (mippixels_start[i-7] >> 4)
2010 + (mippixels_start[i-6] & 0x0F)
2011 + (mippixels_start[i-6] >> 4)
2012 + (mippixels_start[i-5] & 0x0F)
2013 + (mippixels_start[i-5] >> 4)
2014 ) * (0.125f / 15.0f);
2016 avgcolor[3] += 1.0f;
2018 f = (float)bytesperblock / mipsize;
2019 avgcolor[0] *= (0.5f / 31.0f) * f;
2020 avgcolor[1] *= (0.5f / 63.0f) * f;
2021 avgcolor[2] *= (0.5f / 31.0f) * f;
2026 for (i = 0;i < mipsize;i += 4)
2028 avgcolor[0] += mippixels[i+2];
2029 avgcolor[1] += mippixels[i+1];
2030 avgcolor[2] += mippixels[i];
2031 avgcolor[3] += mippixels[i+3];
2033 f = (1.0f / 255.0f) * bytesperpixel / mipsize;
2041 // if we want sRGB, convert now
2044 if (vid.support.ext_texture_srgb)
2048 case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break;
2049 case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break;
2050 case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break;
2051 case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break;
2052 case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break;
2066 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2068 int c0, c1, c0new, c1new;
2069 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2070 r = ((c0 >> 11) & 0x1F);
2071 g = ((c0 >> 5) & 0x3F);
2073 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2074 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2075 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2076 c0new = (r << 11) | (g << 5) | b;
2077 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2078 r = ((c1 >> 11) & 0x1F);
2079 g = ((c1 >> 5) & 0x3F);
2081 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2082 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2083 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2084 c1new = (r << 11) | (g << 5) | b;
2085 // swap the colors if needed to fix order
2086 if(c0 > c1) // thirds
2094 mippixels_start[i+4] ^= 0x55;
2095 mippixels_start[i+5] ^= 0x55;
2096 mippixels_start[i+6] ^= 0x55;
2097 mippixels_start[i+7] ^= 0x55;
2099 else if(c0new == c1new)
2101 mippixels_start[i+4] = 0x00;
2102 mippixels_start[i+5] = 0x00;
2103 mippixels_start[i+6] = 0x00;
2104 mippixels_start[i+7] = 0x00;
2107 else // half + transparent
2114 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2115 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2116 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2117 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2120 mippixels_start[i] = c0new & 255;
2121 mippixels_start[i+1] = c0new >> 8;
2122 mippixels_start[i+2] = c1new & 255;
2123 mippixels_start[i+3] = c1new >> 8;
2128 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2136 // when not requesting mipmaps, do not load them
2137 if(!(flags & TEXF_MIPMAP))
2140 if (dds_miplevels >= 1)
2141 flags |= TEXF_MIPMAP;
2143 flags &= ~TEXF_MIPMAP;
2145 texinfo = R_GetTexTypeInfo(textype, flags);
2147 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2148 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2150 glt->chain = pool->gltchain;
2151 pool->gltchain = glt;
2152 glt->inputwidth = mipwidth;
2153 glt->inputheight = mipheight;
2154 glt->inputdepth = 1;
2156 glt->textype = texinfo;
2157 glt->texturetype = GLTEXTURETYPE_2D;
2158 glt->inputdatasize = ddssize;
2159 glt->glinternalformat = texinfo->glinternalformat;
2160 glt->glformat = texinfo->glformat;
2161 glt->gltype = texinfo->gltype;
2162 glt->bytesperpixel = texinfo->internalbytesperpixel;
2164 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2165 glt->tilewidth = mipwidth;
2166 glt->tileheight = mipheight;
2168 glt->miplevels = dds_miplevels;
2170 // texture uploading can take a while, so make sure we're sending keepalives
2171 CL_KeepaliveMessage(false);
2173 // create the texture object
2174 switch(vid.renderpath)
2176 case RENDERPATH_GL32:
2177 case RENDERPATH_GLES2:
2179 GL_ActiveTexture(0);
2180 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2181 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2182 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2186 // upload the texture
2187 // we need to restore the texture binding after finishing the upload
2188 mipcomplete = false;
2190 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2192 unsigned char *upload_mippixels = mippixels;
2193 int upload_mipwidth = mipwidth;
2194 int upload_mipheight = mipheight;
2195 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2196 if (mippixels + mipsize > mippixels_start + mipsize_total)
2198 switch(vid.renderpath)
2200 case RENDERPATH_GL32:
2201 case RENDERPATH_GLES2:
2204 qglCompressedTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR
2208 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR
2212 if(upload_mippixels != mippixels)
2213 Mem_Free(upload_mippixels);
2214 mippixels += mipsize;
2215 if (mipwidth <= 1 && mipheight <= 1)
2226 // after upload we have to set some parameters...
2227 switch(vid.renderpath)
2229 case RENDERPATH_GL32:
2230 case RENDERPATH_GLES2:
2231 #ifdef GL_TEXTURE_MAX_LEVEL
2232 if (dds_miplevels >= 1 && !mipcomplete)
2234 // need to set GL_TEXTURE_MAX_LEVEL
2235 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2238 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2239 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2245 Mem_Free((unsigned char *) mippixels_start);
2246 return (rtexture_t *)glt;
2249 int R_TextureWidth(rtexture_t *rt)
2251 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2254 int R_TextureHeight(rtexture_t *rt)
2256 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2259 int R_TextureFlags(rtexture_t *rt)
2261 return rt ? ((gltexture_t *)rt)->flags : 0;
2264 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth, int combine)
2266 gltexture_t *glt = (gltexture_t *)rt;
2268 Host_Error("R_UpdateTexture: no data supplied");
2270 Host_Error("R_UpdateTexture: no texture supplied");
2273 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2276 // update part of the texture
2277 if (glt->bufferpixels)
2279 size_t j, bpp = glt->bytesperpixel;
2281 // depth and sides are not fully implemented here - can still do full updates but not partial.
2282 if (glt->inputdepth != 1 || glt->sides != 1)
2283 Host_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2284 if (x < 0 || y < 0 || z < 0 || glt->tilewidth < x + width || glt->tileheight < y + height || glt->tiledepth < z + depth)
2285 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);
2287 for (j = 0; j < (size_t)height; j++)
2288 memcpy(glt->bufferpixels + ((y + j) * glt->tilewidth + x) * bpp, data + j * width * bpp, width * bpp);
2293 // immediately update the part of the texture, no combining
2294 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2297 // keep track of the region that is modified, decide later how big the partial update area is
2298 if (glt->buffermodified)
2300 glt->modified_mins[0] = min(glt->modified_mins[0], x);
2301 glt->modified_mins[1] = min(glt->modified_mins[1], y);
2302 glt->modified_mins[2] = min(glt->modified_mins[2], z);
2303 glt->modified_maxs[0] = max(glt->modified_maxs[0], x + width);
2304 glt->modified_maxs[1] = max(glt->modified_maxs[1], y + height);
2305 glt->modified_maxs[2] = max(glt->modified_maxs[2], z + depth);
2309 glt->buffermodified = true;
2310 glt->modified_mins[0] = x;
2311 glt->modified_mins[1] = y;
2312 glt->modified_mins[2] = z;
2313 glt->modified_maxs[0] = x + width;
2314 glt->modified_maxs[1] = y + height;
2315 glt->modified_maxs[2] = z + depth;
2321 // mark the entire texture as dirty, it will be uploaded later
2322 glt->buffermodified = true;
2323 glt->modified_mins[0] = 0;
2324 glt->modified_mins[1] = 0;
2325 glt->modified_mins[2] = 0;
2326 glt->modified_maxs[0] = glt->tilewidth;
2327 glt->modified_maxs[1] = glt->tileheight;
2328 glt->modified_maxs[2] = glt->tiledepth;
2334 R_UploadFullTexture(glt, data);
2337 int R_RealGetTexture(rtexture_t *rt)
2342 glt = (gltexture_t *)rt;
2343 if (glt->flags & GLTEXF_DYNAMIC)
2344 R_UpdateDynamicTexture(glt);
2345 if (glt->buffermodified && glt->bufferpixels)
2347 glt->buffermodified = false;
2348 // Because we currently don't set the relevant upload stride parameters, just make it full width.
2349 glt->modified_mins[0] = 0;
2350 glt->modified_maxs[0] = glt->tilewidth;
2351 // Check also if it's updating at least half the height of the texture.
2352 if (glt->modified_maxs[1] - glt->modified_mins[1] > glt->tileheight / 2)
2353 R_UploadFullTexture(glt, glt->bufferpixels);
2355 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]);
2357 VectorClear(glt->modified_mins);
2358 VectorClear(glt->modified_maxs);
2363 return r_texture_white->texnum;
2366 void R_ClearTexture (rtexture_t *rt)
2368 gltexture_t *glt = (gltexture_t *)rt;
2370 R_UploadFullTexture(glt, NULL);
2373 int R_PicmipForFlags(int flags)
2376 if(flags & TEXF_PICMIP)
2378 miplevel += gl_picmip.integer;
2379 if (flags & TEXF_ISWORLD)
2381 if (r_picmipworld.integer)
2382 miplevel += gl_picmip_world.integer;
2386 else if (flags & TEXF_ISSPRITE)
2388 if (r_picmipsprites.integer)
2389 miplevel += gl_picmip_sprites.integer;
2394 miplevel += gl_picmip_other.integer;
2396 return max(0, miplevel);