6 #include "intoverflow.h"
9 #define GL_TEXTURE_3D 0x806F
12 cvar_t gl_max_size = {CVAR_SAVE, "gl_max_size", "2048", "maximum allowed texture size, can be used to reduce video memory usage, limited by hardware capabilities (typically 2048, 4096, or 8192)"};
13 cvar_t gl_max_lightmapsize = {CVAR_SAVE, "gl_max_lightmapsize", "1024", "maximum allowed texture size for lightmap textures, use larger values to improve rendering speed, as long as there is enough video memory available (setting it too high for the hardware will cause very bad performance)"};
14 cvar_t gl_picmip = {CVAR_SAVE, "gl_picmip", "0", "reduces resolution of textures by powers of 2, for example 1 will halve width/height, reducing texture memory usage by 75%"};
15 cvar_t gl_picmip_world = {CVAR_SAVE, "gl_picmip_world", "0", "extra picmip level for world textures (may be negative, which will then reduce gl_picmip for these)"};
16 cvar_t r_picmipworld = {CVAR_SAVE, "r_picmipworld", "1", "whether gl_picmip shall apply to world textures too (setting this to 0 is a shorthand for gl_picmip_world -9999999)"};
17 cvar_t gl_picmip_sprites = {CVAR_SAVE, "gl_picmip_sprites", "0", "extra picmip level for sprite textures (may be negative, which will then reduce gl_picmip for these)"};
18 cvar_t r_picmipsprites = {CVAR_SAVE, "r_picmipsprites", "1", "make gl_picmip affect sprites too (saves some graphics memory in sprite heavy games) (setting this to 0 is a shorthand for gl_picmip_sprites -9999999)"};
19 cvar_t gl_picmip_other = {CVAR_SAVE, "gl_picmip_other", "0", "extra picmip level for other textures (may be negative, which will then reduce gl_picmip for these)"};
20 cvar_t r_lerpimages = {CVAR_SAVE, "r_lerpimages", "1", "bilinear filters images when scaling them up to power of 2 size (mode 1), looks better than glquake (mode 0)"};
21 cvar_t gl_texture_anisotropy = {CVAR_SAVE, "gl_texture_anisotropy", "1", "anisotropic filtering quality (if supported by hardware), 1 sample (no anisotropy) and 8 sample (8 tap anisotropy) are recommended values"};
22 cvar_t gl_texturecompression = {CVAR_SAVE, "gl_texturecompression", "0", "whether to compress textures, a value of 0 disables compression (even if the individual cvars are 1), 1 enables fast (low quality) compression at startup, 2 enables slow (high quality) compression at startup"};
23 cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
24 cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
25 cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
26 cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
27 cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
28 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
29 cvar_t gl_texturecompression_q3bspdeluxemaps = {CVAR_SAVE, "gl_texturecompression_q3bspdeluxemaps", "0", "whether to compress deluxemaps in q3bsp format levels (only levels compiled with q3map2 -deluxe have these)"};
30 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
31 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
32 cvar_t gl_texturecompression_reflectmask = {CVAR_SAVE, "gl_texturecompression_reflectmask", "1", "whether to compress reflection cubemap masks (mask of which areas of the texture should reflect the generic shiny cubemap)"};
33 cvar_t gl_texturecompression_sprites = {CVAR_SAVE, "gl_texturecompression_sprites", "1", "whether to compress sprites"};
34 cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "0", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"};
35 cvar_t r_texture_dds_load_alphamode = {0, "r_texture_dds_load_alphamode", "1", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambiguous, 2: texture format only"};
36 cvar_t r_texture_dds_load_logfailure = {0, "r_texture_dds_load_logfailure", "0", "log missing DDS textures to ddstexturefailures.log, 0: done log, 1: log with no optional textures (_norm, glow etc.). 2: log all"};
37 cvar_t r_texture_dds_swdecode = {0, "r_texture_dds_swdecode", "0", "0: don't software decode DDS, 1: software decode DDS if unsupported, 2: always software decode DDS"};
39 qboolean gl_filter_force = false;
40 int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
41 int gl_filter_mag = GL_LINEAR;
44 static mempool_t *texturemempool;
45 static memexpandablearray_t texturearray;
47 // note: this must not conflict with TEXF_ flags in r_textures.h
48 // bitmask for mismatch checking
49 #define GLTEXF_IMPORTANTBITS (0)
50 // dynamic texture (treat texnum == 0 differently)
51 #define GLTEXF_DYNAMIC 0x00080000
53 typedef struct textypeinfo_s
57 int inputbytesperpixel;
58 int internalbytesperpixel;
59 float glinternalbytesperpixel;
68 // we use these internally even if we never deliver such data to the driver
70 #define GL_BGRA 0x80E1
72 // framebuffer texture formats
73 // GLES2 devices rarely support depth textures, so we actually use a renderbuffer there
74 static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
75 static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
76 static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
77 static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
78 static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
79 static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
80 static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
81 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 2, 2, 2.0f, GL_RGB565 , GL_RGBA , GL_UNSIGNED_SHORT_5_6_5};
82 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 2, 2, 2.0f, GL_RGBA16F , GL_RGBA , GL_HALF_FLOAT_ARB};
83 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 2, 2, 2.0f, GL_RGBA32F , GL_RGBA , GL_FLOAT};
86 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
87 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
88 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
89 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
90 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
91 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
92 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
94 static textypeinfo_t textype_etc1 = {"etc1", TEXTYPE_ETC1 , 1, 3, 0.5f, GL_ETC1_RGB8_OES , 0 , 0 };
97 // framebuffer texture formats
98 static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
99 static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
100 static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
101 static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
102 static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
103 static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
104 static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 4, 4, 4.0f, GL_DEPTH24_STENCIL8_EXT , GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT};
105 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
106 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 8, 8, 8.0f, GL_RGBA16F_ARB , GL_RGBA , GL_HALF_FLOAT_ARB};
107 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 16, 16, 16.0f, GL_RGBA32F_ARB , GL_RGBA , GL_FLOAT };
110 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
111 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
112 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
113 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE };
114 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
115 static textypeinfo_t textype_rgba_compress = {"rgba_compress", TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
116 static textypeinfo_t textype_rgba_alpha_compress = {"rgba_alpha_compress", TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
117 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
118 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
119 static textypeinfo_t textype_bgra_compress = {"bgra_compress", TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
120 static textypeinfo_t textype_bgra_alpha_compress = {"bgra_alpha_compress", TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
121 static textypeinfo_t textype_dxt1 = {"dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
122 static textypeinfo_t textype_dxt1a = {"dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 };
123 static textypeinfo_t textype_dxt3 = {"dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 };
124 static textypeinfo_t textype_dxt5 = {"dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 };
125 static textypeinfo_t textype_sRGB_palette = {"sRGB_palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
126 static textypeinfo_t textype_sRGB_palette_alpha = {"sRGB_palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_ALPHA_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
127 static textypeinfo_t textype_sRGB_rgba = {"sRGB_rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
128 static textypeinfo_t textype_sRGB_rgba_alpha = {"sRGB_rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_ALPHA_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
129 static textypeinfo_t textype_sRGB_rgba_compress = {"sRGB_rgba_compress", TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
130 static textypeinfo_t textype_sRGB_rgba_alpha_compress = {"sRGB_rgba_alpha_compress", TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA , GL_UNSIGNED_BYTE };
131 static textypeinfo_t textype_sRGB_bgra = {"sRGB_bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
132 static textypeinfo_t textype_sRGB_bgra_alpha = {"sRGB_bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_ALPHA_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
133 static textypeinfo_t textype_sRGB_bgra_compress = {"sRGB_bgra_compress", TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
134 static textypeinfo_t textype_sRGB_bgra_alpha_compress = {"sRGB_bgra_alpha_compress", TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_BGRA , GL_UNSIGNED_BYTE };
135 static textypeinfo_t textype_sRGB_dxt1 = {"sRGB_dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , 0 , 0 };
136 static textypeinfo_t textype_sRGB_dxt1a = {"sRGB_dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 , 0 };
137 static textypeinfo_t textype_sRGB_dxt3 = {"sRGB_dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 , 0 };
138 static textypeinfo_t textype_sRGB_dxt5 = {"sRGB_dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 , 0 };
141 typedef enum gltexturetype_e
145 GLTEXTURETYPE_CUBEMAP,
150 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP};
151 #ifdef GL_TEXTURE_WRAP_R
152 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
154 static int cubemapside[6] =
156 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
157 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
158 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
159 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
160 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
161 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
164 typedef struct gltexture_s
166 // this portion of the struct is exposed to the R_GetTexture macro for
167 // speed reasons, must be identical in rtexture_t!
168 int texnum; // GL texture slot number
169 int renderbuffernum; // GL renderbuffer slot number
170 qboolean dirty; // indicates that R_RealGetTexture should be called
171 qboolean glisdepthstencil; // indicates that FBO attachment has to be GL_DEPTH_STENCIL_ATTACHMENT
172 int gltexturetypeenum; // used by R_Mesh_TexBind
174 // dynamic texture stuff [11/22/2007 Black]
175 updatecallback_t updatecallback;
176 void *updatecallback_data;
177 // --- [11/22/2007 Black]
179 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
180 unsigned char *bufferpixels;
181 qboolean buffermodified;
183 // pointer to texturepool (check this to see if the texture is allocated)
184 struct gltexturepool_s *pool;
185 // pointer to next texture in texturepool chain
186 struct gltexture_s *chain;
187 // name of the texture (this might be removed someday), no duplicates
188 char identifier[MAX_QPATH + 32];
189 // original data size in *inputtexels
190 int inputwidth, inputheight, inputdepth;
191 // copy of the original texture(s) supplied to the upload function, for
192 // delayed uploads (non-precached)
193 unsigned char *inputtexels;
194 // original data size in *inputtexels
196 // flags supplied to the LoadTexture function
197 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
201 // pointer to one of the textype_ structs
202 textypeinfo_t *textype;
203 // one of the GLTEXTURETYPE_ values
205 // palette if the texture is TEXTYPE_PALETTE
206 const unsigned int *palette;
207 // actual stored texture size after gl_picmip and gl_max_size are applied
208 int tilewidth, tileheight, tiledepth;
209 // 1 or 6 depending on texturetype
211 // how many mipmap levels in this texture
215 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
218 int glinternalformat;
219 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
224 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
226 typedef struct gltexturepool_s
228 unsigned int sentinel;
229 struct gltexture_s *gltchain;
230 struct gltexturepool_s *next;
234 static gltexturepool_t *gltexturepoolchain = NULL;
236 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
237 static int resizebuffersize = 0;
238 static const unsigned char *texturebuffer;
240 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
245 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
246 case TEXTYPE_RGBA: return ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba);
247 case TEXTYPE_BGRA: return ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra);
249 case TEXTYPE_ETC1: return &textype_etc1;
251 case TEXTYPE_ALPHA: return &textype_alpha;
252 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
253 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
254 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
255 case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
256 case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
257 case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
258 case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
259 case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
260 case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
261 case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
263 case TEXTYPE_DXT1: return &textype_dxt1;
264 case TEXTYPE_DXT1A: return &textype_dxt1a;
265 case TEXTYPE_DXT3: return &textype_dxt3;
266 case TEXTYPE_DXT5: return &textype_dxt5;
267 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
268 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);
269 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);
270 case TEXTYPE_ALPHA: return &textype_alpha;
271 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
272 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
273 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
274 case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
275 case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
276 case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
277 case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
278 case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
279 case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
280 case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
281 case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1;
282 case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a;
283 case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
284 case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
285 case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
286 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);
287 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);
290 Host_Error("R_GetTexTypeInfo: unknown texture format %i with flags %x", (int)textype, flags);
296 // dynamic texture code [11/22/2007 Black]
297 void R_MarkDirtyTexture(rtexture_t *rt) {
298 gltexture_t *glt = (gltexture_t*) rt;
303 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
304 if (glt->flags & GLTEXF_DYNAMIC)
306 // mark it as dirty, so R_RealGetTexture gets called
311 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
312 gltexture_t *glt = (gltexture_t*) rt;
317 glt->flags |= GLTEXF_DYNAMIC;
318 glt->updatecallback = updatecallback;
319 glt->updatecallback_data = data;
322 static void R_UpdateDynamicTexture(gltexture_t *glt) {
324 if( glt->updatecallback ) {
325 glt->updatecallback( (rtexture_t*) glt, glt->updatecallback_data );
329 void R_PurgeTexture(rtexture_t *rt)
331 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
336 void R_FreeTexture(rtexture_t *rt)
338 gltexture_t *glt, **gltpointer;
340 glt = (gltexture_t *)rt;
342 Host_Error("R_FreeTexture: texture == NULL");
344 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
345 if (*gltpointer == glt)
346 *gltpointer = glt->chain;
348 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
350 R_Mesh_ClearBindingsForTexture(glt->texnum);
352 switch(vid.renderpath)
354 case RENDERPATH_GL32:
355 case RENDERPATH_GLES2:
359 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
361 if (glt->renderbuffernum)
364 qglDeleteRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
369 if (glt->inputtexels)
370 Mem_Free(glt->inputtexels);
371 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
374 rtexturepool_t *R_AllocTexturePool(void)
376 gltexturepool_t *pool;
377 if (texturemempool == NULL)
379 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
382 pool->next = gltexturepoolchain;
383 gltexturepoolchain = pool;
384 pool->sentinel = TEXTUREPOOL_SENTINEL;
385 return (rtexturepool_t *)pool;
388 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
390 gltexturepool_t *pool, **poolpointer;
391 if (rtexturepool == NULL)
393 if (*rtexturepool == NULL)
395 pool = (gltexturepool_t *)(*rtexturepool);
396 *rtexturepool = NULL;
397 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
398 Host_Error("R_FreeTexturePool: pool already freed");
399 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
400 if (*poolpointer == pool)
401 *poolpointer = pool->next;
403 Host_Error("R_FreeTexturePool: pool not linked");
404 while (pool->gltchain)
405 R_FreeTexture((rtexture_t *)pool->gltchain);
410 typedef struct glmode_s
413 int minification, magnification;
417 static glmode_t modes[6] =
419 {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
420 {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
421 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
422 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
423 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
424 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
427 static void GL_TextureMode_f (void)
432 gltexturepool_t *pool;
436 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
437 for (i = 0;i < 6;i++)
439 if (gl_filter_min == modes[i].minification)
441 Con_Printf("%s\n", modes[i].name);
445 Con_Print("current filter is unknown???\n");
449 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
450 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
454 Con_Print("bad filter name\n");
458 gl_filter_min = modes[i].minification;
459 gl_filter_mag = modes[i].magnification;
460 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
462 switch(vid.renderpath)
464 case RENDERPATH_GL32:
465 case RENDERPATH_GLES2:
466 // change all the existing mipmap texture objects
467 // FIXME: force renderer(/client/something?) restart instead?
470 for (pool = gltexturepoolchain;pool;pool = pool->next)
472 for (glt = pool->gltchain;glt;glt = glt->chain)
474 // only update already uploaded images
475 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
477 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
478 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
479 if (glt->flags & TEXF_MIPMAP)
481 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
485 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
487 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
488 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
496 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)
498 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
503 case GLTEXTURETYPE_2D:
504 maxsize = vid.maxtexturesize_2d;
505 if (flags & TEXF_PICMIP)
507 maxsize = bound(1, gl_max_size.integer, maxsize);
511 case GLTEXTURETYPE_3D:
512 maxsize = vid.maxtexturesize_3d;
514 case GLTEXTURETYPE_CUBEMAP:
515 maxsize = vid.maxtexturesize_cubemap;
519 width2 = min(inwidth >> picmip, maxsize);
520 height2 = min(inheight >> picmip, maxsize);
521 depth2 = min(indepth >> picmip, maxsize);
524 if (flags & TEXF_MIPMAP)
526 int extent = max(width2, max(height2, depth2));
532 *outwidth = max(1, width2);
534 *outheight = max(1, height2);
536 *outdepth = max(1, depth2);
538 *outmiplevels = miplevels;
542 static int R_CalcTexelDataSize (gltexture_t *glt)
544 int width2, height2, depth2, size;
546 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
548 size = width2 * height2 * depth2;
550 if (glt->flags & TEXF_MIPMAP)
552 while (width2 > 1 || height2 > 1 || depth2 > 1)
560 size += width2 * height2 * depth2;
564 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
567 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
571 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
572 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
574 gltexturepool_t *pool;
576 Con_Print("glsize input loaded mip alpha name\n");
577 for (pool = gltexturepoolchain;pool;pool = pool->next)
585 for (glt = pool->gltchain;glt;glt = glt->chain)
587 glsize = R_CalcTexelDataSize(glt);
588 isloaded = glt->texnum != 0 || glt->renderbuffernum != 0;
590 pooltotalt += glsize;
591 pooltotalp += glt->inputdatasize;
595 poolloadedt += glsize;
596 poolloadedp += glt->inputdatasize;
599 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);
602 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);
603 sumtotal += pooltotal;
604 sumtotalt += pooltotalt;
605 sumtotalp += pooltotalp;
606 sumloaded += poolloaded;
607 sumloadedt += poolloadedt;
608 sumloadedp += poolloadedp;
611 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);
614 static void R_TextureStats_f(void)
616 R_TextureStats_Print(true, true, true);
619 static void r_textures_start(void)
621 switch(vid.renderpath)
623 case RENDERPATH_GL32:
624 case RENDERPATH_GLES2:
625 // LordHavoc: allow any alignment
627 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
628 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
632 texturemempool = Mem_AllocPool("texture management", 0, NULL);
633 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
635 // Disable JPEG screenshots if the DLL isn't loaded
636 if (! JPEG_OpenLibrary ())
637 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
638 if (! PNG_OpenLibrary ())
639 Cvar_SetValueQuick (&scr_screenshot_png, 0);
642 static void r_textures_shutdown(void)
644 rtexturepool_t *temp;
646 JPEG_CloseLibrary ();
648 while(gltexturepoolchain)
650 temp = (rtexturepool_t *) gltexturepoolchain;
651 R_FreeTexturePool(&temp);
654 resizebuffersize = 0;
656 colorconvertbuffer = NULL;
657 texturebuffer = NULL;
658 Mem_ExpandableArray_FreeArray(&texturearray);
659 Mem_FreePool(&texturemempool);
662 static void r_textures_newmap(void)
666 static void r_textures_devicelost(void)
670 endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
671 for (i = 0;i < endindex;i++)
673 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
674 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
676 switch(vid.renderpath)
678 case RENDERPATH_GL32:
679 case RENDERPATH_GLES2:
685 static void r_textures_devicerestored(void)
689 endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
690 for (i = 0;i < endindex;i++)
692 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
693 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
695 switch(vid.renderpath)
697 case RENDERPATH_GL32:
698 case RENDERPATH_GLES2:
705 void R_Textures_Init (void)
707 Cmd_AddCommand("gl_texturemode", &GL_TextureMode_f, "set texture filtering mode (GL_NEAREST, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, etc); an additional argument 'force' forces the texture mode even in cases where it may not be appropriate");
708 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
709 Cvar_RegisterVariable (&gl_max_size);
710 Cvar_RegisterVariable (&gl_picmip);
711 Cvar_RegisterVariable (&gl_picmip_world);
712 Cvar_RegisterVariable (&r_picmipworld);
713 Cvar_RegisterVariable (&gl_picmip_sprites);
714 Cvar_RegisterVariable (&r_picmipsprites);
715 Cvar_RegisterVariable (&gl_picmip_other);
716 Cvar_RegisterVariable (&gl_max_lightmapsize);
717 Cvar_RegisterVariable (&r_lerpimages);
718 Cvar_RegisterVariable (&gl_texture_anisotropy);
719 Cvar_RegisterVariable (&gl_texturecompression);
720 Cvar_RegisterVariable (&gl_texturecompression_color);
721 Cvar_RegisterVariable (&gl_texturecompression_normal);
722 Cvar_RegisterVariable (&gl_texturecompression_gloss);
723 Cvar_RegisterVariable (&gl_texturecompression_glow);
724 Cvar_RegisterVariable (&gl_texturecompression_2d);
725 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
726 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
727 Cvar_RegisterVariable (&gl_texturecompression_sky);
728 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
729 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
730 Cvar_RegisterVariable (&gl_texturecompression_sprites);
731 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
732 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
733 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
734 Cvar_RegisterVariable (&r_texture_dds_swdecode);
736 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
739 void R_Textures_Frame (void)
741 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
742 static int old_aniso = 0;
743 static qboolean first_time_aniso = true;
746 // could do procedural texture animation here, if we keep track of which
747 // textures were accessed this frame...
749 // free the resize buffers
750 resizebuffersize = 0;
753 Mem_Free(resizebuffer);
756 if (colorconvertbuffer)
758 Mem_Free(colorconvertbuffer);
759 colorconvertbuffer = NULL;
762 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
763 if (old_aniso != gl_texture_anisotropy.integer)
766 gltexturepool_t *pool;
769 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
771 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
773 switch(vid.renderpath)
775 case RENDERPATH_GL32:
776 case RENDERPATH_GLES2:
777 // ignore the first difference, any textures loaded by now probably had the same aniso value
778 if (first_time_aniso)
780 first_time_aniso = false;
785 for (pool = gltexturepoolchain;pool;pool = pool->next)
787 for (glt = pool->gltchain;glt;glt = glt->chain)
789 // only update already uploaded images
790 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
792 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
794 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
795 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
797 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
807 static void R_MakeResizeBufferBigger(int size)
809 if (resizebuffersize < size)
811 resizebuffersize = size;
813 Mem_Free(resizebuffer);
814 if (colorconvertbuffer)
815 Mem_Free(colorconvertbuffer);
816 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
817 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
818 if (!resizebuffer || !colorconvertbuffer)
819 Host_Error("R_Upload: out of memory");
823 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
825 int textureenum = gltexturetypeenums[texturetype];
826 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
830 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
831 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
833 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
834 if (gl_texture_anisotropy.integer != aniso)
835 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
836 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
839 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
840 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
841 #ifdef GL_TEXTURE_WRAP_R
842 if (gltexturetypedimensions[texturetype] >= 3)
844 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
849 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
851 if (flags & TEXF_MIPMAP)
853 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
857 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
859 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
861 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
863 if (flags & TEXF_MIPMAP)
865 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
867 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
871 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
876 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
878 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
882 if (flags & TEXF_MIPMAP)
884 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
888 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
890 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
893 #ifdef GL_TEXTURE_COMPARE_MODE_ARB
896 case TEXTYPE_SHADOWMAP16_COMP:
897 case TEXTYPE_SHADOWMAP24_COMP:
898 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
899 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
900 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
902 case TEXTYPE_SHADOWMAP16_RAW:
903 case TEXTYPE_SHADOWMAP24_RAW:
904 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
905 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
906 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
916 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
919 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
921 if (glt->texturetype != GLTEXTURETYPE_2D)
922 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
924 if (glt->textype->textype == TEXTYPE_PALETTE)
925 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
927 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
928 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
930 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
931 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
933 // update a portion of the image
935 switch(vid.renderpath)
937 case RENDERPATH_GL32:
938 case RENDERPATH_GLES2:
942 // we need to restore the texture binding after finishing the upload
944 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
945 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
946 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
947 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
953 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
955 int i, mip = 0, width, height, depth;
956 GLint oldbindtexnum = 0;
957 const unsigned char *prevbuffer;
960 // error out if a stretch is needed on special texture types
961 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
962 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
964 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
965 // of the target size and then use the mipmap reduction function to get
966 // high quality supersampled results
967 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
968 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
969 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
971 if (prevbuffer == NULL)
973 width = glt->tilewidth;
974 height = glt->tileheight;
975 depth = glt->tiledepth;
976 // R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
977 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
978 // prevbuffer = resizebuffer;
982 if (glt->textype->textype == TEXTYPE_PALETTE)
984 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
985 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
986 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
987 prevbuffer = colorconvertbuffer;
989 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
991 // multiply RGB channels by A channel before uploading
993 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
994 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
996 alpha = prevbuffer[i+3];
997 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
998 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
999 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1000 colorconvertbuffer[i+3] = alpha;
1002 prevbuffer = colorconvertbuffer;
1004 // scale up to a power of 2 size (if appropriate)
1005 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1007 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1008 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1009 prevbuffer = resizebuffer;
1011 // apply mipmap reduction algorithm to get down to picmip/max_size
1012 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1014 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1015 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1016 prevbuffer = resizebuffer;
1020 // do the appropriate upload type...
1021 switch(vid.renderpath)
1023 case RENDERPATH_GL32:
1024 case RENDERPATH_GLES2:
1025 if (glt->texnum) // not renderbuffers
1029 // we need to restore the texture binding after finishing the upload
1030 GL_ActiveTexture(0);
1031 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1032 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1035 #ifdef GL_TEXTURE_COMPRESSION_HINT_ARB
1036 if (qglGetCompressedTexImageARB)
1038 if (gl_texturecompression.integer >= 2)
1039 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1041 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1046 switch(glt->texturetype)
1048 case GLTEXTURETYPE_2D:
1049 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1050 if (glt->flags & TEXF_MIPMAP)
1052 while (width > 1 || height > 1 || depth > 1)
1054 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1055 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1056 prevbuffer = resizebuffer;
1057 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1061 case GLTEXTURETYPE_3D:
1063 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1064 if (glt->flags & TEXF_MIPMAP)
1066 while (width > 1 || height > 1 || depth > 1)
1068 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1069 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1070 prevbuffer = resizebuffer;
1071 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1076 case GLTEXTURETYPE_CUBEMAP:
1077 // convert and upload each side in turn,
1078 // from a continuous block of input texels
1079 texturebuffer = (unsigned char *)prevbuffer;
1080 for (i = 0;i < 6;i++)
1082 prevbuffer = texturebuffer;
1083 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1084 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1086 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1087 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1088 prevbuffer = resizebuffer;
1091 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1093 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1094 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1095 prevbuffer = resizebuffer;
1098 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1099 if (glt->flags & TEXF_MIPMAP)
1101 while (width > 1 || height > 1 || depth > 1)
1103 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1104 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1105 prevbuffer = resizebuffer;
1106 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1112 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1113 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1119 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)
1123 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1124 textypeinfo_t *texinfo, *texinfo2;
1125 unsigned char *temppixels = NULL;
1128 if (cls.state == ca_dedicated)
1131 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1132 if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1134 int numpixels = width * height * depth * sides;
1135 size = numpixels * 4;
1136 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1139 const unsigned char *p;
1140 unsigned char *o = temppixels;
1141 for (i = 0;i < numpixels;i++, o += 4)
1143 p = (const unsigned char *)palette + 4*data[i];
1151 textype = TEXTYPE_RGBA;
1156 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1157 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1158 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1159 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1165 static int rgbaswapindices[4] = {2, 1, 0, 3};
1166 size = width * height * depth * sides * 4;
1167 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1169 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1173 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1174 if (!vid.support.ext_texture_srgb)
1176 qboolean convertsRGB = false;
1179 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1180 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1181 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1182 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1183 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;/*convertsRGB = true;*/break;
1184 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1185 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1189 if (convertsRGB && data)
1191 size = width * height * depth * sides * 4;
1194 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1195 memcpy(temppixels, data, size);
1198 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1202 texinfo = R_GetTexTypeInfo(textype, flags);
1203 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1206 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1210 // clear the alpha flag if the texture has no transparent pixels
1213 case TEXTYPE_PALETTE:
1214 case TEXTYPE_SRGB_PALETTE:
1215 if (flags & TEXF_ALPHA)
1217 flags &= ~TEXF_ALPHA;
1220 for (i = 0;i < size;i++)
1222 if (((unsigned char *)&palette[data[i]])[3] < 255)
1224 flags |= TEXF_ALPHA;
1233 case TEXTYPE_SRGB_RGBA:
1234 case TEXTYPE_SRGB_BGRA:
1235 if (flags & TEXF_ALPHA)
1237 flags &= ~TEXF_ALPHA;
1240 for (i = 3;i < size;i += 4)
1244 flags |= TEXF_ALPHA;
1251 case TEXTYPE_SHADOWMAP16_COMP:
1252 case TEXTYPE_SHADOWMAP16_RAW:
1253 case TEXTYPE_SHADOWMAP24_COMP:
1254 case TEXTYPE_SHADOWMAP24_RAW:
1257 case TEXTYPE_SRGB_DXT1:
1260 case TEXTYPE_SRGB_DXT1A:
1262 case TEXTYPE_SRGB_DXT3:
1264 case TEXTYPE_SRGB_DXT5:
1265 flags |= TEXF_ALPHA;
1268 flags |= TEXF_ALPHA;
1270 case TEXTYPE_COLORBUFFER:
1271 case TEXTYPE_COLORBUFFER16F:
1272 case TEXTYPE_COLORBUFFER32F:
1273 flags |= TEXF_ALPHA;
1276 Sys_Error("R_LoadTexture: unknown texture type");
1279 texinfo2 = R_GetTexTypeInfo(textype, flags);
1280 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1283 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1285 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1287 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1289 glt->chain = pool->gltchain;
1290 pool->gltchain = glt;
1291 glt->inputwidth = width;
1292 glt->inputheight = height;
1293 glt->inputdepth = depth;
1295 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
1296 glt->textype = texinfo;
1297 glt->texturetype = texturetype;
1298 glt->inputdatasize = size;
1299 glt->palette = palette;
1300 glt->glinternalformat = texinfo->glinternalformat;
1301 glt->glformat = texinfo->glformat;
1302 glt->gltype = texinfo->gltype;
1303 glt->bytesperpixel = texinfo->internalbytesperpixel;
1304 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1307 glt->glisdepthstencil = false;
1308 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1309 // init the dynamic texture attributes, too [11/22/2007 Black]
1310 glt->updatecallback = NULL;
1311 glt->updatecallback_data = NULL;
1313 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1315 // upload the texture
1316 // data may be NULL (blank texture for dynamic rendering)
1317 switch(vid.renderpath)
1319 case RENDERPATH_GL32:
1320 case RENDERPATH_GLES2:
1322 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1326 R_UploadFullTexture(glt, data);
1327 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1328 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1330 // free any temporary processing buffer we allocated...
1332 Mem_Free(temppixels);
1334 // texture converting and uploading can take a while, so make sure we're sending keepalives
1335 // FIXME: this causes rendering during R_Shadow_DrawLights
1336 // CL_KeepaliveMessage(false);
1338 return (rtexture_t *)glt;
1341 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)
1343 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1346 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)
1348 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1351 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)
1353 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1356 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter)
1358 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL);
1361 rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
1364 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1365 textypeinfo_t *texinfo;
1367 if (cls.state == ca_dedicated)
1370 texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP);
1372 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1374 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1376 glt->chain = pool->gltchain;
1377 pool->gltchain = glt;
1378 glt->inputwidth = width;
1379 glt->inputheight = height;
1380 glt->inputdepth = 1;
1381 glt->flags = TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_FORCENEAREST;
1383 glt->textype = texinfo;
1384 glt->texturetype = textype;
1385 glt->inputdatasize = width*height*texinfo->internalbytesperpixel;
1386 glt->palette = NULL;
1387 glt->glinternalformat = texinfo->glinternalformat;
1388 glt->glformat = texinfo->glformat;
1389 glt->gltype = texinfo->gltype;
1390 glt->bytesperpixel = texinfo->internalbytesperpixel;
1391 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1394 glt->glisdepthstencil = textype == TEXTYPE_DEPTHBUFFER24STENCIL8;
1395 glt->gltexturetypeenum = GL_TEXTURE_2D;
1396 // init the dynamic texture attributes, too [11/22/2007 Black]
1397 glt->updatecallback = NULL;
1398 glt->updatecallback_data = NULL;
1400 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1402 // upload the texture
1403 // data may be NULL (blank texture for dynamic rendering)
1404 switch(vid.renderpath)
1406 case RENDERPATH_GL32:
1407 case RENDERPATH_GLES2:
1409 qglGenRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
1410 qglBindRenderbuffer(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR
1411 qglRenderbufferStorage(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR
1412 // 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
1413 qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR
1417 return (rtexture_t *)glt;
1420 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1423 return -1; // unsupported on this platform
1425 gltexture_t *glt = (gltexture_t *)rt;
1428 int bytesperpixel = 0;
1429 int bytesperblock = 0;
1431 int dds_format_flags;
1439 GLint internalformat;
1440 const char *ddsfourcc;
1442 return -1; // NULL pointer
1443 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1444 return -2; // broken driver - crashes on reading internal format
1445 if (!qglGetTexLevelParameteriv)
1447 GL_ActiveTexture(0);
1448 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1449 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1450 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1451 switch(internalformat)
1453 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1454 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1455 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1456 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1457 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1459 // if premultiplied alpha, say so in the DDS file
1460 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1462 switch(internalformat)
1464 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1465 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1468 if (!bytesperblock && skipuncompressed)
1469 return -3; // skipped
1470 memset(mipinfo, 0, sizeof(mipinfo));
1471 mipinfo[0][0] = glt->tilewidth;
1472 mipinfo[0][1] = glt->tileheight;
1474 if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1))
1476 for (mip = 1;mip < 16;mip++)
1478 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1479 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1480 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1488 for (mip = 0;mip < mipmaps;mip++)
1490 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1491 mipinfo[mip][3] = ddssize;
1492 ddssize += mipinfo[mip][2];
1494 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1497 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1501 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1502 dds_format_flags = 0x4; // DDPF_FOURCC
1506 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1507 dds_format_flags = 0x40; // DDPF_RGB
1511 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1512 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1515 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1516 memcpy(dds, "DDS ", 4);
1517 StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
1518 StoreLittleLong(dds+8, dds_flags);
1519 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1520 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1521 StoreLittleLong(dds+24, 0); // depth
1522 StoreLittleLong(dds+28, mipmaps); // mipmaps
1523 StoreLittleLong(dds+76, 32); // format size
1524 StoreLittleLong(dds+80, dds_format_flags);
1525 StoreLittleLong(dds+108, dds_caps1);
1526 StoreLittleLong(dds+112, dds_caps2);
1529 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1530 memcpy(dds+84, ddsfourcc, 4);
1531 for (mip = 0;mip < mipmaps;mip++)
1533 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1538 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1539 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1540 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1541 for (mip = 0;mip < mipmaps;mip++)
1543 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1546 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1547 ret = FS_WriteFile(filename, dds, ddssize);
1549 return ret ? ddssize : -5;
1554 // ELUAN: FIXME: separate this code
1555 #include "ktx10/include/ktx.h"
1558 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
1560 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1563 int bytesperblock, bytesperpixel;
1566 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1567 textypeinfo_t *texinfo;
1568 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1569 unsigned int c, r, g, b;
1570 GLint oldbindtexnum = 0;
1571 unsigned char *mippixels;
1572 unsigned char *mippixels_start;
1573 unsigned char *ddspixels;
1575 fs_offset_t ddsfilesize;
1576 unsigned int ddssize;
1577 qboolean force_swdecode;
1579 // ELUAN: FIXME: separate this code
1583 KTX_dimensions sizes;
1586 if (cls.state == ca_dedicated)
1590 // ELUAN: FIXME: separate this code
1591 if (vid.renderpath != RENDERPATH_GLES2)
1593 Con_DPrintf("KTX texture format is only supported on the GLES2 renderpath\n");
1597 // some textures are specified with extensions, so it becomes .tga.dds
1598 FS_StripExtension (filename, vabuf2, sizeof(vabuf2));
1599 FS_StripExtension (vabuf2, vabuf, sizeof(vabuf));
1600 FS_DefaultExtension (vabuf, ".ktx", sizeof(vabuf));
1601 strsize = strlen(vabuf);
1603 for (i = 0; i <= strsize - 4; i++) // copy null termination
1604 vabuf[i] = vabuf[i + 4];
1606 Con_DPrintf("Loading %s...\n", vabuf);
1607 dds = FS_LoadFile(vabuf, tempmempool, true, &ddsfilesize);
1608 ddssize = ddsfilesize;
1612 Con_DPrintf("Not found!\n");
1613 return NULL; // not found
1615 Con_DPrintf("Found!\n");
1617 if (flags & TEXF_ALPHA)
1619 Con_DPrintf("KTX texture with alpha not supported yet, disabling\n");
1620 flags &= ~TEXF_ALPHA;
1626 GLboolean isMipmapped;
1627 KTX_error_code ktxerror;
1629 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1631 // texture uploading can take a while, so make sure we're sending keepalives
1632 CL_KeepaliveMessage(false);
1634 // create the texture object
1636 GL_ActiveTexture(0);
1637 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[GLTEXTURETYPE_2D]);
1638 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1639 qglBindTexture(gltexturetypeenums[GLTEXTURETYPE_2D], glt->texnum);CHECKGLERROR
1641 // upload the texture
1642 // we need to restore the texture binding after finishing the upload
1644 // NOTE: some drivers fail with ETC1 NPOT (only PowerVR?). This may make the driver crash later.
1645 ktxerror = ktxLoadTextureM(dds, ddssize, &glt->texnum, &target, &sizes, &isMipmapped, &glerror,
1646 0, NULL);// can't CHECKGLERROR, the lib catches it
1648 // FIXME: delete texture if we fail here
1649 if (target != GL_TEXTURE_2D)
1651 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1653 Con_DPrintf("%s target != GL_TEXTURE_2D, target == %x\n", vabuf, target);
1654 return NULL; // FIXME: delete the texture from memory
1657 if (KTX_SUCCESS == ktxerror)
1659 textype = TEXTYPE_ETC1;
1660 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
1662 // return whether this texture is transparent
1664 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1666 // TODO: apply gl_picmip
1669 // TODO: only load mipmaps if requested
1672 flags |= TEXF_MIPMAP;
1674 flags &= ~TEXF_MIPMAP;
1676 texinfo = R_GetTexTypeInfo(textype, flags);
1678 strlcpy (glt->identifier, vabuf, sizeof(glt->identifier));
1680 glt->chain = pool->gltchain;
1681 pool->gltchain = glt;
1682 glt->inputwidth = sizes.width;
1683 glt->inputheight = sizes.height;
1684 glt->inputdepth = 1;
1686 glt->textype = texinfo;
1687 glt->texturetype = GLTEXTURETYPE_2D;
1688 glt->inputdatasize = ddssize;
1689 glt->glinternalformat = texinfo->glinternalformat;
1690 glt->glformat = texinfo->glformat;
1691 glt->gltype = texinfo->gltype;
1692 glt->bytesperpixel = texinfo->internalbytesperpixel;
1694 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1695 glt->tilewidth = sizes.width;
1696 glt->tileheight = sizes.height;
1698 glt->miplevels = isMipmapped ? 1 : 0; // FIXME
1700 // after upload we have to set some parameters...
1701 #ifdef GL_TEXTURE_MAX_LEVEL
1703 if (dds_miplevels >= 1 && !mipcomplete)
1705 // need to set GL_TEXTURE_MAX_LEVEL
1706 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
1710 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1712 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1714 return (rtexture_t *)glt;
1718 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1720 Con_DPrintf("KTX texture %s failed to load: %x\n", vabuf, ktxerror);
1724 #endif // __ANDROID__
1726 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1727 ddssize = ddsfilesize;
1731 if (r_texture_dds_load_logfailure.integer && (r_texture_dds_load_logfailure.integer >= 2 || !optionaltexture))
1732 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1733 return NULL; // not found
1736 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1739 Con_Printf("^1%s: not a DDS image\n", filename);
1743 //dds_flags = BuffLittleLong(dds+8);
1744 dds_format_flags = BuffLittleLong(dds+80);
1745 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1746 dds_width = BuffLittleLong(dds+16);
1747 dds_height = BuffLittleLong(dds+12);
1748 ddspixels = dds + 128;
1750 if(r_texture_dds_load_alphamode.integer == 0)
1751 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1752 flags &= ~TEXF_ALPHA;
1754 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1755 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1757 // very sloppy BGRA 32bit identification
1758 textype = TEXTYPE_BGRA;
1759 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
1762 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1763 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1766 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1769 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1772 for (i = 3;i < size;i += 4)
1773 if (ddspixels[i] < 255)
1776 flags &= ~TEXF_ALPHA;
1779 else if (!memcmp(dds+84, "DXT1", 4))
1781 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1782 // LordHavoc: it is my belief that this does not infringe on the
1783 // patent because it is not decoding pixels...
1784 textype = TEXTYPE_DXT1;
1787 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1788 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1789 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1792 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1795 if (flags & TEXF_ALPHA)
1797 if (r_texture_dds_load_alphamode.integer == 1)
1800 for (i = 0;i < size;i += bytesperblock)
1801 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1803 // NOTE: this assumes sizeof(unsigned int) == 4
1804 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1805 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1806 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1810 textype = TEXTYPE_DXT1A;
1812 flags &= ~TEXF_ALPHA;
1814 else if (r_texture_dds_load_alphamode.integer == 0)
1815 textype = TEXTYPE_DXT1A;
1818 flags &= ~TEXF_ALPHA;
1822 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
1824 if(!memcmp(dds+84, "DXT2", 4))
1826 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1828 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
1833 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1835 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
1838 textype = TEXTYPE_DXT3;
1841 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1842 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1845 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1848 // we currently always assume alpha
1850 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
1852 if(!memcmp(dds+84, "DXT4", 4))
1854 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1856 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
1861 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1863 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
1866 textype = TEXTYPE_DXT5;
1869 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1870 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1873 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1876 // we currently always assume alpha
1881 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1885 // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
1886 if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
1888 textype = TEXTYPE_DXT1;
1892 for (i = 0;i < (int)ddssize;i += bytesperblock)
1893 memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
1897 force_swdecode = false;
1900 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
1902 if(r_texture_dds_swdecode.integer > 1)
1903 force_swdecode = true;
1907 if(r_texture_dds_swdecode.integer < 1)
1913 force_swdecode = true;
1917 // return whether this texture is transparent
1919 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1921 // if we SW decode, choose 2 sizes bigger
1924 // this is quarter res, so do not scale down more than we have to
1928 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
1931 // this is where we apply gl_picmip
1932 mippixels_start = ddspixels;
1933 mipwidth = dds_width;
1934 mipheight = dds_height;
1935 while(miplevel >= 1 && dds_miplevels >= 1)
1937 if (mipwidth <= 1 && mipheight <= 1)
1939 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1940 mippixels_start += mipsize; // just skip
1948 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
1949 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1951 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
1953 // fake decode S3TC if needed
1956 int mipsize_new = mipsize_total / bytesperblock * 4;
1957 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
1958 unsigned char *p = mipnewpixels;
1959 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
1961 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
1962 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
1963 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
1964 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
1965 if(textype == TEXTYPE_DXT5)
1966 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
1967 else if(textype == TEXTYPE_DXT3)
1969 (mippixels_start[i-8] & 0x0F)
1970 + (mippixels_start[i-8] >> 4)
1971 + (mippixels_start[i-7] & 0x0F)
1972 + (mippixels_start[i-7] >> 4)
1973 + (mippixels_start[i-6] & 0x0F)
1974 + (mippixels_start[i-6] >> 4)
1975 + (mippixels_start[i-5] & 0x0F)
1976 + (mippixels_start[i-5] >> 4)
1977 ) * (0.125f / 15.0f * 255.0f);
1982 textype = TEXTYPE_BGRA;
1986 // as each block becomes a pixel, we must use pixel count for this
1987 mipwidth = (mipwidth + 3) / 4;
1988 mipheight = (mipheight + 3) / 4;
1989 mipsize = bytesperpixel * mipwidth * mipheight;
1990 mippixels_start = mipnewpixels;
1991 mipsize_total = mipsize_new;
1994 // start mip counting
1995 mippixels = mippixels_start;
1997 // calculate average color if requested
2001 Vector4Clear(avgcolor);
2004 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2006 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2007 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2008 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2009 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2010 if(textype == TEXTYPE_DXT5)
2011 avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f);
2012 else if(textype == TEXTYPE_DXT3)
2014 (mippixels_start[i-8] & 0x0F)
2015 + (mippixels_start[i-8] >> 4)
2016 + (mippixels_start[i-7] & 0x0F)
2017 + (mippixels_start[i-7] >> 4)
2018 + (mippixels_start[i-6] & 0x0F)
2019 + (mippixels_start[i-6] >> 4)
2020 + (mippixels_start[i-5] & 0x0F)
2021 + (mippixels_start[i-5] >> 4)
2022 ) * (0.125f / 15.0f);
2024 avgcolor[3] += 1.0f;
2026 f = (float)bytesperblock / mipsize;
2027 avgcolor[0] *= (0.5f / 31.0f) * f;
2028 avgcolor[1] *= (0.5f / 63.0f) * f;
2029 avgcolor[2] *= (0.5f / 31.0f) * f;
2034 for (i = 0;i < mipsize;i += 4)
2036 avgcolor[0] += mippixels[i+2];
2037 avgcolor[1] += mippixels[i+1];
2038 avgcolor[2] += mippixels[i];
2039 avgcolor[3] += mippixels[i+3];
2041 f = (1.0f / 255.0f) * bytesperpixel / mipsize;
2049 // if we want sRGB, convert now
2052 if (vid.support.ext_texture_srgb)
2056 case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break;
2057 case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break;
2058 case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break;
2059 case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break;
2060 case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break;
2074 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2076 int c0, c1, c0new, c1new;
2077 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2078 r = ((c0 >> 11) & 0x1F);
2079 g = ((c0 >> 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 c0new = (r << 11) | (g << 5) | b;
2085 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2086 r = ((c1 >> 11) & 0x1F);
2087 g = ((c1 >> 5) & 0x3F);
2089 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2090 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2091 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2092 c1new = (r << 11) | (g << 5) | b;
2093 // swap the colors if needed to fix order
2094 if(c0 > c1) // thirds
2102 mippixels_start[i+4] ^= 0x55;
2103 mippixels_start[i+5] ^= 0x55;
2104 mippixels_start[i+6] ^= 0x55;
2105 mippixels_start[i+7] ^= 0x55;
2107 else if(c0new == c1new)
2109 mippixels_start[i+4] = 0x00;
2110 mippixels_start[i+5] = 0x00;
2111 mippixels_start[i+6] = 0x00;
2112 mippixels_start[i+7] = 0x00;
2115 else // half + transparent
2122 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2123 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2124 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2125 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2128 mippixels_start[i] = c0new & 255;
2129 mippixels_start[i+1] = c0new >> 8;
2130 mippixels_start[i+2] = c1new & 255;
2131 mippixels_start[i+3] = c1new >> 8;
2136 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2144 // when not requesting mipmaps, do not load them
2145 if(!(flags & TEXF_MIPMAP))
2148 if (dds_miplevels >= 1)
2149 flags |= TEXF_MIPMAP;
2151 flags &= ~TEXF_MIPMAP;
2153 texinfo = R_GetTexTypeInfo(textype, flags);
2155 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2156 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2158 glt->chain = pool->gltchain;
2159 pool->gltchain = glt;
2160 glt->inputwidth = mipwidth;
2161 glt->inputheight = mipheight;
2162 glt->inputdepth = 1;
2164 glt->textype = texinfo;
2165 glt->texturetype = GLTEXTURETYPE_2D;
2166 glt->inputdatasize = ddssize;
2167 glt->glinternalformat = texinfo->glinternalformat;
2168 glt->glformat = texinfo->glformat;
2169 glt->gltype = texinfo->gltype;
2170 glt->bytesperpixel = texinfo->internalbytesperpixel;
2172 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2173 glt->tilewidth = mipwidth;
2174 glt->tileheight = mipheight;
2176 glt->miplevels = dds_miplevels;
2178 // texture uploading can take a while, so make sure we're sending keepalives
2179 CL_KeepaliveMessage(false);
2181 // create the texture object
2182 switch(vid.renderpath)
2184 case RENDERPATH_GL32:
2185 case RENDERPATH_GLES2:
2187 GL_ActiveTexture(0);
2188 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2189 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2190 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2194 // upload the texture
2195 // we need to restore the texture binding after finishing the upload
2196 mipcomplete = false;
2198 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2200 unsigned char *upload_mippixels = mippixels;
2201 int upload_mipwidth = mipwidth;
2202 int upload_mipheight = mipheight;
2203 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2204 if (mippixels + mipsize > mippixels_start + mipsize_total)
2206 switch(vid.renderpath)
2208 case RENDERPATH_GL32:
2209 case RENDERPATH_GLES2:
2212 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR
2216 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR
2220 if(upload_mippixels != mippixels)
2221 Mem_Free(upload_mippixels);
2222 mippixels += mipsize;
2223 if (mipwidth <= 1 && mipheight <= 1)
2234 // after upload we have to set some parameters...
2235 switch(vid.renderpath)
2237 case RENDERPATH_GL32:
2238 case RENDERPATH_GLES2:
2239 #ifdef GL_TEXTURE_MAX_LEVEL
2240 if (dds_miplevels >= 1 && !mipcomplete)
2242 // need to set GL_TEXTURE_MAX_LEVEL
2243 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2246 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2247 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2253 Mem_Free((unsigned char *) mippixels_start);
2254 return (rtexture_t *)glt;
2257 int R_TextureWidth(rtexture_t *rt)
2259 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2262 int R_TextureHeight(rtexture_t *rt)
2264 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2267 int R_TextureFlags(rtexture_t *rt)
2269 return rt ? ((gltexture_t *)rt)->flags : 0;
2272 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2274 gltexture_t *glt = (gltexture_t *)rt;
2276 Host_Error("R_UpdateTexture: no data supplied");
2278 Host_Error("R_UpdateTexture: no texture supplied");
2281 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2284 // update part of the texture
2285 if (glt->bufferpixels)
2288 int bpp = glt->bytesperpixel;
2289 int inputskip = width*bpp;
2290 int outputskip = glt->tilewidth*bpp;
2291 const unsigned char *input = data;
2292 unsigned char *output = glt->bufferpixels;
2293 if (glt->inputdepth != 1 || glt->sides != 1)
2294 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2304 input -= y*inputskip;
2307 if (width > glt->tilewidth - x)
2308 width = glt->tilewidth - x;
2309 if (height > glt->tileheight - y)
2310 height = glt->tileheight - y;
2311 if (width < 1 || height < 1)
2314 glt->buffermodified = true;
2315 output += y*outputskip + x*bpp;
2316 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2317 memcpy(output, input, width*bpp);
2319 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
2320 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2322 R_UploadFullTexture(glt, data);
2325 int R_RealGetTexture(rtexture_t *rt)
2330 glt = (gltexture_t *)rt;
2331 if (glt->flags & GLTEXF_DYNAMIC)
2332 R_UpdateDynamicTexture(glt);
2333 if (glt->buffermodified && glt->bufferpixels)
2335 glt->buffermodified = false;
2336 R_UploadFullTexture(glt, glt->bufferpixels);
2342 return r_texture_white->texnum;
2345 void R_ClearTexture (rtexture_t *rt)
2347 gltexture_t *glt = (gltexture_t *)rt;
2349 R_UploadFullTexture(glt, NULL);
2352 int R_PicmipForFlags(int flags)
2355 if(flags & TEXF_PICMIP)
2357 miplevel += gl_picmip.integer;
2358 if (flags & TEXF_ISWORLD)
2360 if (r_picmipworld.integer)
2361 miplevel += gl_picmip_world.integer;
2365 else if (flags & TEXF_ISSPRITE)
2367 if (r_picmipsprites.integer)
2368 miplevel += gl_picmip_sprites.integer;
2373 miplevel += gl_picmip_other.integer;
2375 return max(0, miplevel);