6 #include "intoverflow.h"
8 cvar_t gl_max_size = {CVAR_CLIENT | CVAR_SAVE, "gl_max_size", "2048", "maximum allowed texture size, can be used to reduce video memory usage, limited by hardware capabilities (typically 2048, 4096, or 8192)"};
9 cvar_t gl_max_lightmapsize = {CVAR_CLIENT | CVAR_SAVE, "gl_max_lightmapsize", "1024", "maximum allowed texture size for lightmap textures, use larger values to improve rendering speed, as long as there is enough video memory available (setting it too high for the hardware will cause very bad performance)"};
10 cvar_t gl_picmip = {CVAR_CLIENT | CVAR_SAVE, "gl_picmip", "0", "reduces resolution of textures by powers of 2, for example 1 will halve width/height, reducing texture memory usage by 75%"};
11 cvar_t gl_picmip_world = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "r_picmipworld", "1", "whether gl_picmip shall apply to world textures too (setting this to 0 is a shorthand for gl_picmip_world -9999999)"};
13 cvar_t gl_picmip_sprites = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "r_picmipsprites", "1", "make gl_picmip affect sprites too (saves some graphics memory in sprite heavy games) (setting this to 0 is a shorthand for gl_picmip_sprites -9999999)"};
15 cvar_t gl_picmip_other = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "r_lerpimages", "1", "bilinear filters images when scaling them up to power of 2 size (mode 1), looks better than glquake (mode 0)"};
17 cvar_t gl_texture_anisotropy = {CVAR_CLIENT | CVAR_SAVE, "gl_texture_anisotropy", "1", "anisotropic filtering quality (if supported by hardware), 1 sample (no anisotropy) and 8 sample (8 tap anisotropy) are recommended values"};
18 cvar_t gl_texturecompression = {CVAR_CLIENT | CVAR_SAVE, "gl_texturecompression", "0", "whether to compress textures, a value of 0 disables compression (even if the individual cvars are 1), 1 enables fast (low quality) compression at startup, 2 enables slow (high quality) compression at startup"};
19 cvar_t gl_texturecompression_color = {CVAR_CLIENT | CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
20 cvar_t gl_texturecompression_normal = {CVAR_CLIENT | CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
21 cvar_t gl_texturecompression_gloss = {CVAR_CLIENT | CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
22 cvar_t gl_texturecompression_glow = {CVAR_CLIENT | CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
23 cvar_t gl_texturecompression_2d = {CVAR_CLIENT | CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
24 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_CLIENT | CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
25 cvar_t gl_texturecompression_q3bspdeluxemaps = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
27 cvar_t gl_texturecompression_lightcubemaps = {CVAR_CLIENT | CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
28 cvar_t gl_texturecompression_reflectmask = {CVAR_CLIENT | CVAR_SAVE, "gl_texturecompression_reflectmask", "1", "whether to compress reflection cubemap masks (mask of which areas of the texture should reflect the generic shiny cubemap)"};
29 cvar_t gl_texturecompression_sprites = {CVAR_CLIENT | CVAR_SAVE, "gl_texturecompression_sprites", "1", "whether to compress sprites"};
30 cvar_t gl_nopartialtextureupdates = {CVAR_CLIENT | CVAR_SAVE, "gl_nopartialtextureupdates", "0", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"};
31 cvar_t r_texture_dds_load_alphamode = {CVAR_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"};
32 cvar_t r_texture_dds_load_logfailure = {CVAR_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"};
33 cvar_t r_texture_dds_swdecode = {CVAR_CLIENT, "r_texture_dds_swdecode", "0", "0: don't software decode DDS, 1: software decode DDS if unsupported, 2: always software decode DDS"};
35 qboolean gl_filter_force = false;
36 int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
37 int gl_filter_mag = GL_LINEAR;
40 static mempool_t *texturemempool;
41 static memexpandablearray_t texturearray;
43 // note: this must not conflict with TEXF_ flags in r_textures.h
44 // bitmask for mismatch checking
45 #define GLTEXF_IMPORTANTBITS (0)
46 // dynamic texture (treat texnum == 0 differently)
47 #define GLTEXF_DYNAMIC 0x00080000
49 typedef struct textypeinfo_s
53 int inputbytesperpixel;
54 int internalbytesperpixel;
55 float glinternalbytesperpixel;
64 // we use these internally even if we never deliver such data to the driver
66 #define GL_BGRA 0x80E1
68 // framebuffer texture formats
69 // GLES2 devices rarely support depth textures, so we actually use a renderbuffer there
70 static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
71 static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
72 static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
73 static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
74 static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
75 static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
76 static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
77 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 2, 2, 2.0f, GL_RGB565 , GL_RGBA , GL_UNSIGNED_SHORT_5_6_5};
78 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 2, 2, 2.0f, GL_RGBA16F , GL_RGBA , GL_HALF_FLOAT};
79 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 2, 2, 2.0f, GL_RGBA32F , GL_RGBA , GL_FLOAT};
82 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
83 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
84 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
85 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
86 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
87 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
88 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
90 static textypeinfo_t textype_etc1 = {"etc1", TEXTYPE_ETC1 , 1, 3, 0.5f, GL_ETC1_RGB8_OES , 0 , 0 };
93 // framebuffer texture formats
94 static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
95 static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
96 static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24 , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
97 static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 4, 4, 4.0f, GL_DEPTH_COMPONENT24 , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
98 static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
99 static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 4, 4, 4.0f, GL_DEPTH_COMPONENT24 , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
100 static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 4, 4, 4.0f, GL_DEPTH24_STENCIL8 , GL_DEPTH_STENCIL , GL_UNSIGNED_INT_24_8};
101 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
102 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 8, 8, 8.0f, GL_RGBA16F , GL_RGBA , GL_HALF_FLOAT };
103 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 16, 16, 16.0f, GL_RGBA32F , GL_RGBA , GL_FLOAT };
106 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
107 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
108 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
109 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE };
110 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
111 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 };
112 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 };
113 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
114 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
115 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 };
116 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 };
117 static textypeinfo_t textype_dxt1 = {"dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
118 static textypeinfo_t textype_dxt1a = {"dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 };
119 static textypeinfo_t textype_dxt3 = {"dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 };
120 static textypeinfo_t textype_dxt5 = {"dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 };
121 static textypeinfo_t textype_sRGB_palette = {"sRGB_palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB , GL_BGRA , GL_UNSIGNED_BYTE };
122 static textypeinfo_t textype_sRGB_palette_alpha = {"sRGB_palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_ALPHA , GL_BGRA , GL_UNSIGNED_BYTE };
123 static textypeinfo_t textype_sRGB_rgba = {"sRGB_rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB , GL_RGBA , GL_UNSIGNED_BYTE };
124 static textypeinfo_t textype_sRGB_rgba_alpha = {"sRGB_rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_ALPHA , GL_RGBA , GL_UNSIGNED_BYTE };
125 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 };
126 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 };
127 static textypeinfo_t textype_sRGB_bgra = {"sRGB_bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB , GL_BGRA , GL_UNSIGNED_BYTE };
128 static textypeinfo_t textype_sRGB_bgra_alpha = {"sRGB_bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_ALPHA , GL_BGRA , GL_UNSIGNED_BYTE };
129 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 };
130 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 };
131 static textypeinfo_t textype_sRGB_dxt1 = {"sRGB_dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , 0 , 0 };
132 static textypeinfo_t textype_sRGB_dxt1a = {"sRGB_dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 , 0 };
133 static textypeinfo_t textype_sRGB_dxt3 = {"sRGB_dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 , 0 };
134 static textypeinfo_t textype_sRGB_dxt5 = {"sRGB_dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 , 0 };
137 typedef enum gltexturetype_e
141 GLTEXTURETYPE_CUBEMAP,
146 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP};
147 #ifdef GL_TEXTURE_WRAP_R
148 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
150 static int cubemapside[6] =
152 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
153 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
154 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
155 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
156 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
157 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
160 typedef struct gltexture_s
162 // this portion of the struct is exposed to the R_GetTexture macro for
163 // speed reasons, must be identical in rtexture_t!
164 int texnum; // GL texture slot number
165 int renderbuffernum; // GL renderbuffer slot number
166 qboolean dirty; // indicates that R_RealGetTexture should be called
167 qboolean glisdepthstencil; // indicates that FBO attachment has to be GL_DEPTH_STENCIL_ATTACHMENT
168 int gltexturetypeenum; // used by R_Mesh_TexBind
170 // dynamic texture stuff [11/22/2007 Black]
171 updatecallback_t updatecallback;
172 void *updatecallback_data;
173 // --- [11/22/2007 Black]
175 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
176 unsigned char *bufferpixels;
177 qboolean 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(qboolean printeach, qboolean printpool, qboolean 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(CMD_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(CMD_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 (&gl_nopartialtextureupdates);
728 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
729 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
730 Cvar_RegisterVariable (&r_texture_dds_swdecode);
732 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
735 void R_Textures_Frame (void)
737 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
738 static int old_aniso = 0;
739 static qboolean first_time_aniso = true;
742 // could do procedural texture animation here, if we keep track of which
743 // textures were accessed this frame...
745 // free the resize buffers
746 resizebuffersize = 0;
749 Mem_Free(resizebuffer);
752 if (colorconvertbuffer)
754 Mem_Free(colorconvertbuffer);
755 colorconvertbuffer = NULL;
758 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
759 if (old_aniso != gl_texture_anisotropy.integer)
762 gltexturepool_t *pool;
765 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
767 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
769 switch(vid.renderpath)
771 case RENDERPATH_GL32:
772 case RENDERPATH_GLES2:
773 // ignore the first difference, any textures loaded by now probably had the same aniso value
774 if (first_time_aniso)
776 first_time_aniso = false;
781 for (pool = gltexturepoolchain;pool;pool = pool->next)
783 for (glt = pool->gltchain;glt;glt = glt->chain)
785 // only update already uploaded images
786 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
788 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
790 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
791 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
793 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
803 static void R_MakeResizeBufferBigger(int size)
805 if (resizebuffersize < size)
807 resizebuffersize = size;
809 Mem_Free(resizebuffer);
810 if (colorconvertbuffer)
811 Mem_Free(colorconvertbuffer);
812 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
813 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
814 if (!resizebuffer || !colorconvertbuffer)
815 Host_Error("R_Upload: out of memory");
819 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
821 int textureenum = gltexturetypeenums[texturetype];
822 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
826 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
827 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
829 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
830 if (gl_texture_anisotropy.integer != aniso)
831 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
832 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
835 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
836 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
837 #ifdef GL_TEXTURE_WRAP_R
838 if (gltexturetypedimensions[texturetype] >= 3)
840 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
845 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
847 if (flags & TEXF_MIPMAP)
849 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
853 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
855 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
857 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
859 if (flags & TEXF_MIPMAP)
861 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
863 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
867 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
872 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
874 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
878 if (flags & TEXF_MIPMAP)
880 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
884 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
886 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
892 case TEXTYPE_SHADOWMAP16_COMP:
893 case TEXTYPE_SHADOWMAP24_COMP:
894 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);CHECKGLERROR
895 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);CHECKGLERROR
897 case TEXTYPE_SHADOWMAP16_RAW:
898 case TEXTYPE_SHADOWMAP24_RAW:
899 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE, GL_NONE);CHECKGLERROR
900 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);CHECKGLERROR
910 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
913 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
915 if (glt->texturetype != GLTEXTURETYPE_2D)
916 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
918 if (glt->textype->textype == TEXTYPE_PALETTE)
919 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
921 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
922 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
924 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
925 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
927 // update a portion of the image
929 switch(vid.renderpath)
931 case RENDERPATH_GL32:
932 case RENDERPATH_GLES2:
936 // we need to restore the texture binding after finishing the upload
938 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
939 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
940 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
941 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
947 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
949 int i, mip = 0, width, height, depth;
950 GLint oldbindtexnum = 0;
951 const unsigned char *prevbuffer;
954 // error out if a stretch is needed on special texture types
955 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
956 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
958 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
959 // of the target size and then use the mipmap reduction function to get
960 // high quality supersampled results
961 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
962 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
963 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
965 if (prevbuffer == NULL)
967 width = glt->tilewidth;
968 height = glt->tileheight;
969 depth = glt->tiledepth;
970 // R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
971 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
972 // prevbuffer = resizebuffer;
976 if (glt->textype->textype == TEXTYPE_PALETTE)
978 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
979 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
980 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
981 prevbuffer = colorconvertbuffer;
983 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
985 // multiply RGB channels by A channel before uploading
987 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
988 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
990 alpha = prevbuffer[i+3];
991 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
992 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
993 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
994 colorconvertbuffer[i+3] = alpha;
996 prevbuffer = colorconvertbuffer;
998 // scale up to a power of 2 size (if appropriate)
999 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1001 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1002 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1003 prevbuffer = resizebuffer;
1005 // apply mipmap reduction algorithm to get down to picmip/max_size
1006 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1008 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1009 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1010 prevbuffer = resizebuffer;
1014 // do the appropriate upload type...
1015 switch(vid.renderpath)
1017 case RENDERPATH_GL32:
1018 case RENDERPATH_GLES2:
1019 if (glt->texnum) // not renderbuffers
1023 // we need to restore the texture binding after finishing the upload
1024 GL_ActiveTexture(0);
1025 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1026 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1029 if (gl_texturecompression.integer >= 2)
1030 qglHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
1032 qglHint(GL_TEXTURE_COMPRESSION_HINT, GL_FASTEST);
1035 switch(glt->texturetype)
1037 case GLTEXTURETYPE_2D:
1038 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1039 if (glt->flags & TEXF_MIPMAP)
1041 while (width > 1 || height > 1 || depth > 1)
1043 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1044 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1045 prevbuffer = resizebuffer;
1046 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1050 case GLTEXTURETYPE_3D:
1052 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1053 if (glt->flags & TEXF_MIPMAP)
1055 while (width > 1 || height > 1 || depth > 1)
1057 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1058 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1059 prevbuffer = resizebuffer;
1060 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1065 case GLTEXTURETYPE_CUBEMAP:
1066 // convert and upload each side in turn,
1067 // from a continuous block of input texels
1068 texturebuffer = (unsigned char *)prevbuffer;
1069 for (i = 0;i < 6;i++)
1071 prevbuffer = texturebuffer;
1072 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1073 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1075 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1076 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1077 prevbuffer = resizebuffer;
1080 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1082 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1083 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1084 prevbuffer = resizebuffer;
1087 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1088 if (glt->flags & TEXF_MIPMAP)
1090 while (width > 1 || height > 1 || depth > 1)
1092 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1093 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1094 prevbuffer = resizebuffer;
1095 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1101 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1102 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1108 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)
1112 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1113 textypeinfo_t *texinfo, *texinfo2;
1114 unsigned char *temppixels = NULL;
1117 if (cls.state == ca_dedicated)
1120 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1121 if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1123 int numpixels = width * height * depth * sides;
1124 size = numpixels * 4;
1125 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1128 const unsigned char *p;
1129 unsigned char *o = temppixels;
1130 for (i = 0;i < numpixels;i++, o += 4)
1132 p = (const unsigned char *)palette + 4*data[i];
1140 textype = TEXTYPE_RGBA;
1145 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1146 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1147 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1148 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1154 static int rgbaswapindices[4] = {2, 1, 0, 3};
1155 size = width * height * depth * sides * 4;
1156 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1158 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1162 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1163 if (!vid.support.ext_texture_srgb)
1165 qboolean convertsRGB = false;
1168 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1169 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1170 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1171 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1172 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;/*convertsRGB = true;*/break;
1173 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1174 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1178 if (convertsRGB && data)
1180 size = width * height * depth * sides * 4;
1183 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1184 memcpy(temppixels, data, size);
1187 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1191 texinfo = R_GetTexTypeInfo(textype, flags);
1192 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1195 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1199 // clear the alpha flag if the texture has no transparent pixels
1202 case TEXTYPE_PALETTE:
1203 case TEXTYPE_SRGB_PALETTE:
1204 if (flags & TEXF_ALPHA)
1206 flags &= ~TEXF_ALPHA;
1209 for (i = 0;i < size;i++)
1211 if (((unsigned char *)&palette[data[i]])[3] < 255)
1213 flags |= TEXF_ALPHA;
1222 case TEXTYPE_SRGB_RGBA:
1223 case TEXTYPE_SRGB_BGRA:
1224 if (flags & TEXF_ALPHA)
1226 flags &= ~TEXF_ALPHA;
1229 for (i = 3;i < size;i += 4)
1233 flags |= TEXF_ALPHA;
1240 case TEXTYPE_SHADOWMAP16_COMP:
1241 case TEXTYPE_SHADOWMAP16_RAW:
1242 case TEXTYPE_SHADOWMAP24_COMP:
1243 case TEXTYPE_SHADOWMAP24_RAW:
1246 case TEXTYPE_SRGB_DXT1:
1249 case TEXTYPE_SRGB_DXT1A:
1251 case TEXTYPE_SRGB_DXT3:
1253 case TEXTYPE_SRGB_DXT5:
1254 flags |= TEXF_ALPHA;
1257 flags |= TEXF_ALPHA;
1259 case TEXTYPE_COLORBUFFER:
1260 case TEXTYPE_COLORBUFFER16F:
1261 case TEXTYPE_COLORBUFFER32F:
1262 flags |= TEXF_ALPHA;
1265 Sys_Error("R_LoadTexture: unknown texture type");
1268 texinfo2 = R_GetTexTypeInfo(textype, flags);
1269 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1272 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1274 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1276 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1278 glt->chain = pool->gltchain;
1279 pool->gltchain = glt;
1280 glt->inputwidth = width;
1281 glt->inputheight = height;
1282 glt->inputdepth = depth;
1284 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
1285 glt->textype = texinfo;
1286 glt->texturetype = texturetype;
1287 glt->inputdatasize = size;
1288 glt->palette = palette;
1289 glt->glinternalformat = texinfo->glinternalformat;
1290 glt->glformat = texinfo->glformat;
1291 glt->gltype = texinfo->gltype;
1292 glt->bytesperpixel = texinfo->internalbytesperpixel;
1293 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1296 glt->glisdepthstencil = false;
1297 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1298 // init the dynamic texture attributes, too [11/22/2007 Black]
1299 glt->updatecallback = NULL;
1300 glt->updatecallback_data = NULL;
1302 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1304 // upload the texture
1305 // data may be NULL (blank texture for dynamic rendering)
1306 switch(vid.renderpath)
1308 case RENDERPATH_GL32:
1309 case RENDERPATH_GLES2:
1311 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1315 R_UploadFullTexture(glt, data);
1316 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1317 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1319 // free any temporary processing buffer we allocated...
1321 Mem_Free(temppixels);
1323 // texture converting and uploading can take a while, so make sure we're sending keepalives
1324 // FIXME: this causes rendering during R_Shadow_DrawLights
1325 // CL_KeepaliveMessage(false);
1327 return (rtexture_t *)glt;
1330 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)
1332 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1335 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)
1337 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1340 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)
1342 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1345 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter)
1347 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL);
1350 rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
1353 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1354 textypeinfo_t *texinfo;
1356 if (cls.state == ca_dedicated)
1359 texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP);
1361 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1363 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1365 glt->chain = pool->gltchain;
1366 pool->gltchain = glt;
1367 glt->inputwidth = width;
1368 glt->inputheight = height;
1369 glt->inputdepth = 1;
1370 glt->flags = TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_FORCENEAREST;
1372 glt->textype = texinfo;
1373 glt->texturetype = textype;
1374 glt->inputdatasize = width*height*texinfo->internalbytesperpixel;
1375 glt->palette = NULL;
1376 glt->glinternalformat = texinfo->glinternalformat;
1377 glt->glformat = texinfo->glformat;
1378 glt->gltype = texinfo->gltype;
1379 glt->bytesperpixel = texinfo->internalbytesperpixel;
1380 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1383 glt->glisdepthstencil = textype == TEXTYPE_DEPTHBUFFER24STENCIL8;
1384 glt->gltexturetypeenum = GL_TEXTURE_2D;
1385 // init the dynamic texture attributes, too [11/22/2007 Black]
1386 glt->updatecallback = NULL;
1387 glt->updatecallback_data = NULL;
1389 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1391 // upload the texture
1392 // data may be NULL (blank texture for dynamic rendering)
1393 switch(vid.renderpath)
1395 case RENDERPATH_GL32:
1396 case RENDERPATH_GLES2:
1398 qglGenRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
1399 qglBindRenderbuffer(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR
1400 qglRenderbufferStorage(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR
1401 // 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
1402 qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR
1406 return (rtexture_t *)glt;
1409 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1412 return -1; // unsupported on this platform
1414 gltexture_t *glt = (gltexture_t *)rt;
1417 int bytesperpixel = 0;
1418 int bytesperblock = 0;
1420 int dds_format_flags;
1428 GLint internalformat;
1429 const char *ddsfourcc;
1431 return -1; // NULL pointer
1432 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1433 return -2; // broken driver - crashes on reading internal format
1434 if (!qglGetTexLevelParameteriv)
1436 GL_ActiveTexture(0);
1437 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1438 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1439 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1440 switch(internalformat)
1442 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1443 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1444 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1445 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1446 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1448 // if premultiplied alpha, say so in the DDS file
1449 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1451 switch(internalformat)
1453 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1454 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1457 if (!bytesperblock && skipuncompressed)
1458 return -3; // skipped
1459 memset(mipinfo, 0, sizeof(mipinfo));
1460 mipinfo[0][0] = glt->tilewidth;
1461 mipinfo[0][1] = glt->tileheight;
1463 if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1))
1465 for (mip = 1;mip < 16;mip++)
1467 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1468 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1469 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1477 for (mip = 0;mip < mipmaps;mip++)
1479 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1480 mipinfo[mip][3] = ddssize;
1481 ddssize += mipinfo[mip][2];
1483 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1486 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1490 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1491 dds_format_flags = 0x4; // DDPF_FOURCC
1495 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1496 dds_format_flags = 0x40; // DDPF_RGB
1500 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1501 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1504 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1505 memcpy(dds, "DDS ", 4);
1506 StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
1507 StoreLittleLong(dds+8, dds_flags);
1508 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1509 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1510 StoreLittleLong(dds+24, 0); // depth
1511 StoreLittleLong(dds+28, mipmaps); // mipmaps
1512 StoreLittleLong(dds+76, 32); // format size
1513 StoreLittleLong(dds+80, dds_format_flags);
1514 StoreLittleLong(dds+108, dds_caps1);
1515 StoreLittleLong(dds+112, dds_caps2);
1518 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1519 memcpy(dds+84, ddsfourcc, 4);
1520 for (mip = 0;mip < mipmaps;mip++)
1522 qglGetCompressedTexImage(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1527 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1528 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1529 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1530 for (mip = 0;mip < mipmaps;mip++)
1532 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1535 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1536 ret = FS_WriteFile(filename, dds, ddssize);
1538 return ret ? ddssize : -5;
1543 // ELUAN: FIXME: separate this code
1544 #include "ktx10/include/ktx.h"
1547 rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qboolean srgb, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel, qboolean optionaltexture) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint
1549 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1552 int bytesperblock, bytesperpixel;
1555 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1556 textypeinfo_t *texinfo;
1557 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1558 unsigned int c, r, g, b;
1559 GLint oldbindtexnum = 0;
1560 unsigned char *mippixels;
1561 unsigned char *mippixels_start;
1562 unsigned char *ddspixels;
1564 fs_offset_t ddsfilesize;
1565 unsigned int ddssize;
1566 qboolean force_swdecode;
1568 // ELUAN: FIXME: separate this code
1572 KTX_dimensions sizes;
1575 if (cls.state == ca_dedicated)
1579 // ELUAN: FIXME: separate this code
1580 if (vid.renderpath != RENDERPATH_GLES2)
1582 Con_DPrintf("KTX texture format is only supported on the GLES2 renderpath\n");
1586 // some textures are specified with extensions, so it becomes .tga.dds
1587 FS_StripExtension (filename, vabuf2, sizeof(vabuf2));
1588 FS_StripExtension (vabuf2, vabuf, sizeof(vabuf));
1589 FS_DefaultExtension (vabuf, ".ktx", sizeof(vabuf));
1590 strsize = strlen(vabuf);
1592 for (i = 0; i <= strsize - 4; i++) // copy null termination
1593 vabuf[i] = vabuf[i + 4];
1595 Con_DPrintf("Loading %s...\n", vabuf);
1596 dds = FS_LoadFile(vabuf, tempmempool, true, &ddsfilesize);
1597 ddssize = ddsfilesize;
1601 Con_DPrintf("Not found!\n");
1602 return NULL; // not found
1604 Con_DPrintf("Found!\n");
1606 if (flags & TEXF_ALPHA)
1608 Con_DPrintf("KTX texture with alpha not supported yet, disabling\n");
1609 flags &= ~TEXF_ALPHA;
1615 GLboolean isMipmapped;
1616 KTX_error_code ktxerror;
1618 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1620 // texture uploading can take a while, so make sure we're sending keepalives
1621 CL_KeepaliveMessage(false);
1623 // create the texture object
1625 GL_ActiveTexture(0);
1626 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[GLTEXTURETYPE_2D]);
1627 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1628 qglBindTexture(gltexturetypeenums[GLTEXTURETYPE_2D], glt->texnum);CHECKGLERROR
1630 // upload the texture
1631 // we need to restore the texture binding after finishing the upload
1633 // NOTE: some drivers fail with ETC1 NPOT (only PowerVR?). This may make the driver crash later.
1634 ktxerror = ktxLoadTextureM(dds, ddssize, &glt->texnum, &target, &sizes, &isMipmapped, &glerror,
1635 0, NULL);// can't CHECKGLERROR, the lib catches it
1637 // FIXME: delete texture if we fail here
1638 if (target != GL_TEXTURE_2D)
1640 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1642 Con_DPrintf("%s target != GL_TEXTURE_2D, target == %x\n", vabuf, target);
1643 return NULL; // FIXME: delete the texture from memory
1646 if (KTX_SUCCESS == ktxerror)
1648 textype = TEXTYPE_ETC1;
1649 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
1651 // return whether this texture is transparent
1653 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1655 // TODO: apply gl_picmip
1658 // TODO: only load mipmaps if requested
1661 flags |= TEXF_MIPMAP;
1663 flags &= ~TEXF_MIPMAP;
1665 texinfo = R_GetTexTypeInfo(textype, flags);
1667 strlcpy (glt->identifier, vabuf, sizeof(glt->identifier));
1669 glt->chain = pool->gltchain;
1670 pool->gltchain = glt;
1671 glt->inputwidth = sizes.width;
1672 glt->inputheight = sizes.height;
1673 glt->inputdepth = 1;
1675 glt->textype = texinfo;
1676 glt->texturetype = GLTEXTURETYPE_2D;
1677 glt->inputdatasize = ddssize;
1678 glt->glinternalformat = texinfo->glinternalformat;
1679 glt->glformat = texinfo->glformat;
1680 glt->gltype = texinfo->gltype;
1681 glt->bytesperpixel = texinfo->internalbytesperpixel;
1683 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1684 glt->tilewidth = sizes.width;
1685 glt->tileheight = sizes.height;
1687 glt->miplevels = isMipmapped ? 1 : 0; // FIXME
1689 // after upload we have to set some parameters...
1690 #ifdef GL_TEXTURE_MAX_LEVEL
1692 if (dds_miplevels >= 1 && !mipcomplete)
1694 // need to set GL_TEXTURE_MAX_LEVEL
1695 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
1699 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1701 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1703 return (rtexture_t *)glt;
1707 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1709 Con_DPrintf("KTX texture %s failed to load: %x\n", vabuf, ktxerror);
1713 #endif // __ANDROID__
1715 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1716 ddssize = ddsfilesize;
1720 if (r_texture_dds_load_logfailure.integer && (r_texture_dds_load_logfailure.integer >= 2 || !optionaltexture))
1721 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1722 return NULL; // not found
1725 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1728 Con_Printf("^1%s: not a DDS image\n", filename);
1732 //dds_flags = BuffLittleLong(dds+8);
1733 dds_format_flags = BuffLittleLong(dds+80);
1734 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1735 dds_width = BuffLittleLong(dds+16);
1736 dds_height = BuffLittleLong(dds+12);
1737 ddspixels = dds + 128;
1739 if(r_texture_dds_load_alphamode.integer == 0)
1740 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1741 flags &= ~TEXF_ALPHA;
1743 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1744 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1746 // very sloppy BGRA 32bit identification
1747 textype = TEXTYPE_BGRA;
1748 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
1751 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1752 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1755 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1758 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1761 for (i = 3;i < size;i += 4)
1762 if (ddspixels[i] < 255)
1765 flags &= ~TEXF_ALPHA;
1768 else if (!memcmp(dds+84, "DXT1", 4))
1770 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1771 // LadyHavoc: it is my belief that this does not infringe on the
1772 // patent because it is not decoding pixels...
1773 textype = TEXTYPE_DXT1;
1776 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1777 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1778 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1781 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1784 if (flags & TEXF_ALPHA)
1786 if (r_texture_dds_load_alphamode.integer == 1)
1789 for (i = 0;i < size;i += bytesperblock)
1790 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1792 // NOTE: this assumes sizeof(unsigned int) == 4
1793 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1794 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1795 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1799 textype = TEXTYPE_DXT1A;
1801 flags &= ~TEXF_ALPHA;
1803 else if (r_texture_dds_load_alphamode.integer == 0)
1804 textype = TEXTYPE_DXT1A;
1807 flags &= ~TEXF_ALPHA;
1811 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
1813 if(!memcmp(dds+84, "DXT2", 4))
1815 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1817 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
1822 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1824 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
1827 textype = TEXTYPE_DXT3;
1830 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1831 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1834 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1837 // we currently always assume alpha
1839 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
1841 if(!memcmp(dds+84, "DXT4", 4))
1843 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1845 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
1850 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1852 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
1855 textype = TEXTYPE_DXT5;
1858 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1859 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1862 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1865 // we currently always assume alpha
1870 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1874 // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
1875 if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
1877 textype = TEXTYPE_DXT1;
1881 for (i = 0;i < (int)ddssize;i += bytesperblock)
1882 memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
1886 force_swdecode = false;
1889 if(vid.support.ext_texture_compression_s3tc)
1891 if(r_texture_dds_swdecode.integer > 1)
1892 force_swdecode = true;
1896 if(r_texture_dds_swdecode.integer < 1)
1902 force_swdecode = true;
1906 // return whether this texture is transparent
1908 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1910 // if we SW decode, choose 2 sizes bigger
1913 // this is quarter res, so do not scale down more than we have to
1917 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
1920 // this is where we apply gl_picmip
1921 mippixels_start = ddspixels;
1922 mipwidth = dds_width;
1923 mipheight = dds_height;
1924 while(miplevel >= 1 && dds_miplevels >= 1)
1926 if (mipwidth <= 1 && mipheight <= 1)
1928 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1929 mippixels_start += mipsize; // just skip
1937 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
1938 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1940 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
1942 // fake decode S3TC if needed
1945 int mipsize_new = mipsize_total / bytesperblock * 4;
1946 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
1947 unsigned char *p = mipnewpixels;
1948 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
1950 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
1951 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
1952 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
1953 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
1954 if(textype == TEXTYPE_DXT5)
1955 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
1956 else if(textype == TEXTYPE_DXT3)
1958 (mippixels_start[i-8] & 0x0F)
1959 + (mippixels_start[i-8] >> 4)
1960 + (mippixels_start[i-7] & 0x0F)
1961 + (mippixels_start[i-7] >> 4)
1962 + (mippixels_start[i-6] & 0x0F)
1963 + (mippixels_start[i-6] >> 4)
1964 + (mippixels_start[i-5] & 0x0F)
1965 + (mippixels_start[i-5] >> 4)
1966 ) * (0.125f / 15.0f * 255.0f);
1971 textype = TEXTYPE_BGRA;
1975 // as each block becomes a pixel, we must use pixel count for this
1976 mipwidth = (mipwidth + 3) / 4;
1977 mipheight = (mipheight + 3) / 4;
1978 mipsize = bytesperpixel * mipwidth * mipheight;
1979 mippixels_start = mipnewpixels;
1980 mipsize_total = mipsize_new;
1983 // start mip counting
1984 mippixels = mippixels_start;
1986 // calculate average color if requested
1990 Vector4Clear(avgcolor);
1993 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
1995 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
1996 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1997 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
1998 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
1999 if(textype == TEXTYPE_DXT5)
2000 avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f);
2001 else if(textype == TEXTYPE_DXT3)
2003 (mippixels_start[i-8] & 0x0F)
2004 + (mippixels_start[i-8] >> 4)
2005 + (mippixels_start[i-7] & 0x0F)
2006 + (mippixels_start[i-7] >> 4)
2007 + (mippixels_start[i-6] & 0x0F)
2008 + (mippixels_start[i-6] >> 4)
2009 + (mippixels_start[i-5] & 0x0F)
2010 + (mippixels_start[i-5] >> 4)
2011 ) * (0.125f / 15.0f);
2013 avgcolor[3] += 1.0f;
2015 f = (float)bytesperblock / mipsize;
2016 avgcolor[0] *= (0.5f / 31.0f) * f;
2017 avgcolor[1] *= (0.5f / 63.0f) * f;
2018 avgcolor[2] *= (0.5f / 31.0f) * f;
2023 for (i = 0;i < mipsize;i += 4)
2025 avgcolor[0] += mippixels[i+2];
2026 avgcolor[1] += mippixels[i+1];
2027 avgcolor[2] += mippixels[i];
2028 avgcolor[3] += mippixels[i+3];
2030 f = (1.0f / 255.0f) * bytesperpixel / mipsize;
2038 // if we want sRGB, convert now
2041 if (vid.support.ext_texture_srgb)
2045 case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break;
2046 case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break;
2047 case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break;
2048 case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break;
2049 case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break;
2063 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2065 int c0, c1, c0new, c1new;
2066 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2067 r = ((c0 >> 11) & 0x1F);
2068 g = ((c0 >> 5) & 0x3F);
2070 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2071 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2072 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2073 c0new = (r << 11) | (g << 5) | b;
2074 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2075 r = ((c1 >> 11) & 0x1F);
2076 g = ((c1 >> 5) & 0x3F);
2078 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2079 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2080 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2081 c1new = (r << 11) | (g << 5) | b;
2082 // swap the colors if needed to fix order
2083 if(c0 > c1) // thirds
2091 mippixels_start[i+4] ^= 0x55;
2092 mippixels_start[i+5] ^= 0x55;
2093 mippixels_start[i+6] ^= 0x55;
2094 mippixels_start[i+7] ^= 0x55;
2096 else if(c0new == c1new)
2098 mippixels_start[i+4] = 0x00;
2099 mippixels_start[i+5] = 0x00;
2100 mippixels_start[i+6] = 0x00;
2101 mippixels_start[i+7] = 0x00;
2104 else // half + transparent
2111 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2112 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2113 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2114 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2117 mippixels_start[i] = c0new & 255;
2118 mippixels_start[i+1] = c0new >> 8;
2119 mippixels_start[i+2] = c1new & 255;
2120 mippixels_start[i+3] = c1new >> 8;
2125 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2133 // when not requesting mipmaps, do not load them
2134 if(!(flags & TEXF_MIPMAP))
2137 if (dds_miplevels >= 1)
2138 flags |= TEXF_MIPMAP;
2140 flags &= ~TEXF_MIPMAP;
2142 texinfo = R_GetTexTypeInfo(textype, flags);
2144 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2145 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2147 glt->chain = pool->gltchain;
2148 pool->gltchain = glt;
2149 glt->inputwidth = mipwidth;
2150 glt->inputheight = mipheight;
2151 glt->inputdepth = 1;
2153 glt->textype = texinfo;
2154 glt->texturetype = GLTEXTURETYPE_2D;
2155 glt->inputdatasize = ddssize;
2156 glt->glinternalformat = texinfo->glinternalformat;
2157 glt->glformat = texinfo->glformat;
2158 glt->gltype = texinfo->gltype;
2159 glt->bytesperpixel = texinfo->internalbytesperpixel;
2161 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2162 glt->tilewidth = mipwidth;
2163 glt->tileheight = mipheight;
2165 glt->miplevels = dds_miplevels;
2167 // texture uploading can take a while, so make sure we're sending keepalives
2168 CL_KeepaliveMessage(false);
2170 // create the texture object
2171 switch(vid.renderpath)
2173 case RENDERPATH_GL32:
2174 case RENDERPATH_GLES2:
2176 GL_ActiveTexture(0);
2177 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2178 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2179 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2183 // upload the texture
2184 // we need to restore the texture binding after finishing the upload
2185 mipcomplete = false;
2187 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2189 unsigned char *upload_mippixels = mippixels;
2190 int upload_mipwidth = mipwidth;
2191 int upload_mipheight = mipheight;
2192 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2193 if (mippixels + mipsize > mippixels_start + mipsize_total)
2195 switch(vid.renderpath)
2197 case RENDERPATH_GL32:
2198 case RENDERPATH_GLES2:
2201 qglCompressedTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR
2205 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR
2209 if(upload_mippixels != mippixels)
2210 Mem_Free(upload_mippixels);
2211 mippixels += mipsize;
2212 if (mipwidth <= 1 && mipheight <= 1)
2223 // after upload we have to set some parameters...
2224 switch(vid.renderpath)
2226 case RENDERPATH_GL32:
2227 case RENDERPATH_GLES2:
2228 #ifdef GL_TEXTURE_MAX_LEVEL
2229 if (dds_miplevels >= 1 && !mipcomplete)
2231 // need to set GL_TEXTURE_MAX_LEVEL
2232 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2235 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2236 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2242 Mem_Free((unsigned char *) mippixels_start);
2243 return (rtexture_t *)glt;
2246 int R_TextureWidth(rtexture_t *rt)
2248 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2251 int R_TextureHeight(rtexture_t *rt)
2253 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2256 int R_TextureFlags(rtexture_t *rt)
2258 return rt ? ((gltexture_t *)rt)->flags : 0;
2261 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2263 gltexture_t *glt = (gltexture_t *)rt;
2265 Host_Error("R_UpdateTexture: no data supplied");
2267 Host_Error("R_UpdateTexture: no texture supplied");
2270 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2273 // update part of the texture
2274 if (glt->bufferpixels)
2277 int bpp = glt->bytesperpixel;
2278 int inputskip = width*bpp;
2279 int outputskip = glt->tilewidth*bpp;
2280 const unsigned char *input = data;
2281 unsigned char *output = glt->bufferpixels;
2282 if (glt->inputdepth != 1 || glt->sides != 1)
2283 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2293 input -= y*inputskip;
2296 if (width > glt->tilewidth - x)
2297 width = glt->tilewidth - x;
2298 if (height > glt->tileheight - y)
2299 height = glt->tileheight - y;
2300 if (width < 1 || height < 1)
2303 glt->buffermodified = true;
2304 output += y*outputskip + x*bpp;
2305 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2306 memcpy(output, input, width*bpp);
2308 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2309 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2311 R_UploadFullTexture(glt, data);
2314 int R_RealGetTexture(rtexture_t *rt)
2319 glt = (gltexture_t *)rt;
2320 if (glt->flags & GLTEXF_DYNAMIC)
2321 R_UpdateDynamicTexture(glt);
2322 if (glt->buffermodified && glt->bufferpixels)
2324 glt->buffermodified = false;
2325 R_UploadFullTexture(glt, glt->bufferpixels);
2331 return r_texture_white->texnum;
2334 void R_ClearTexture (rtexture_t *rt)
2336 gltexture_t *glt = (gltexture_t *)rt;
2338 R_UploadFullTexture(glt, NULL);
2341 int R_PicmipForFlags(int flags)
2344 if(flags & TEXF_PICMIP)
2346 miplevel += gl_picmip.integer;
2347 if (flags & TEXF_ISWORLD)
2349 if (r_picmipworld.integer)
2350 miplevel += gl_picmip_world.integer;
2354 else if (flags & TEXF_ISSPRITE)
2356 if (r_picmipsprites.integer)
2357 miplevel += gl_picmip_sprites.integer;
2362 miplevel += gl_picmip_other.integer;
2364 return max(0, miplevel);