6 #include "intoverflow.h"
8 cvar_t gl_max_size = {CF_CLIENT | CF_ARCHIVE, "gl_max_size", "2048", "maximum allowed texture size, can be used to reduce video memory usage, limited by hardware capabilities (typically 2048, 4096, or 8192)"};
9 cvar_t gl_max_lightmapsize = {CF_CLIENT | CF_ARCHIVE, "gl_max_lightmapsize", "512", "maximum allowed texture size for lightmap textures, use larger values to improve rendering speed, as long as there is enough video memory available (setting it too high for the hardware will cause very bad performance)"};
10 cvar_t gl_picmip = {CF_CLIENT | CF_ARCHIVE, "gl_picmip", "0", "reduces resolution of textures by powers of 2, for example 1 will halve width/height, reducing texture memory usage by 75%"};
11 cvar_t gl_picmip_world = {CF_CLIENT | CF_ARCHIVE, "gl_picmip_world", "0", "extra picmip level for world textures (may be negative, which will then reduce gl_picmip for these)"};
12 cvar_t r_picmipworld = {CF_CLIENT | CF_ARCHIVE, "r_picmipworld", "1", "whether gl_picmip shall apply to world textures too (setting this to 0 is a shorthand for gl_picmip_world -9999999)"};
13 cvar_t gl_picmip_sprites = {CF_CLIENT | CF_ARCHIVE, "gl_picmip_sprites", "0", "extra picmip level for sprite textures (may be negative, which will then reduce gl_picmip for these)"};
14 cvar_t r_picmipsprites = {CF_CLIENT | CF_ARCHIVE, "r_picmipsprites", "1", "make gl_picmip affect sprites too (saves some graphics memory in sprite heavy games) (setting this to 0 is a shorthand for gl_picmip_sprites -9999999)"};
15 cvar_t gl_picmip_other = {CF_CLIENT | CF_ARCHIVE, "gl_picmip_other", "0", "extra picmip level for other textures (may be negative, which will then reduce gl_picmip for these)"};
16 cvar_t r_lerpimages = {CF_CLIENT | CF_ARCHIVE, "r_lerpimages", "1", "bilinear filters images when scaling them up to power of 2 size (mode 1), looks better than glquake (mode 0)"};
17 cvar_t gl_texture_anisotropy = {CF_CLIENT | CF_ARCHIVE, "gl_texture_anisotropy", "1", "anisotropic filtering quality (if supported by hardware), 1 sample (no anisotropy) and 8 sample (8 tap anisotropy) are recommended values"};
18 cvar_t gl_texturecompression = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression", "0", "whether to compress textures, a value of 0 disables compression (even if the individual cvars are 1), 1 enables fast (low quality) compression at startup, 2 enables slow (high quality) compression at startup"};
19 cvar_t gl_texturecompression_color = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
20 cvar_t gl_texturecompression_normal = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
21 cvar_t gl_texturecompression_gloss = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
22 cvar_t gl_texturecompression_glow = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
23 cvar_t gl_texturecompression_2d = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
24 cvar_t gl_texturecompression_q3bsplightmaps = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
25 cvar_t gl_texturecompression_q3bspdeluxemaps = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_q3bspdeluxemaps", "0", "whether to compress deluxemaps in q3bsp format levels (only levels compiled with q3map2 -deluxe have these)"};
26 cvar_t gl_texturecompression_sky = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
27 cvar_t gl_texturecompression_lightcubemaps = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
28 cvar_t gl_texturecompression_reflectmask = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_reflectmask", "1", "whether to compress reflection cubemap masks (mask of which areas of the texture should reflect the generic shiny cubemap)"};
29 cvar_t gl_texturecompression_sprites = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_sprites", "1", "whether to compress sprites"};
30 cvar_t gl_nopartialtextureupdates = {CF_CLIENT | CF_ARCHIVE, "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 = {CF_CLIENT, "r_texture_dds_load_alphamode", "1", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambiguous, 2: texture format only"};
32 cvar_t r_texture_dds_load_logfailure = {CF_CLIENT, "r_texture_dds_load_logfailure", "0", "log missing DDS textures to ddstexturefailures.log, 0: done log, 1: log with no optional textures (_norm, glow etc.). 2: log all"};
33 cvar_t r_texture_dds_swdecode = {CF_CLIENT, "r_texture_dds_swdecode", "0", "0: don't software decode DDS, 1: software decode DDS if unsupported, 2: always software decode DDS"};
35 qbool 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 qbool dirty; // indicates that R_RealGetTexture should be called
167 qbool 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 unsigned char *modifiedpixels;
178 int modified_width, modified_height, modified_depth;
179 int modified_offset_x, modified_offset_y, modified_offset_z;
180 qbool buffermodified;
182 // pointer to texturepool (check this to see if the texture is allocated)
183 struct gltexturepool_s *pool;
184 // pointer to next texture in texturepool chain
185 struct gltexture_s *chain;
186 // name of the texture (this might be removed someday), no duplicates
187 char identifier[MAX_QPATH + 32];
188 // original data size in *inputtexels
189 int inputwidth, inputheight, inputdepth;
190 // copy of the original texture(s) supplied to the upload function, for
191 // delayed uploads (non-precached)
192 unsigned char *inputtexels;
193 // original data size in *inputtexels
195 // flags supplied to the LoadTexture function
196 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
200 // pointer to one of the textype_ structs
201 textypeinfo_t *textype;
202 // one of the GLTEXTURETYPE_ values
204 // palette if the texture is TEXTYPE_PALETTE
205 const unsigned int *palette;
206 // actual stored texture size after gl_picmip and gl_max_size are applied
207 int tilewidth, tileheight, tiledepth;
208 // 1 or 6 depending on texturetype
210 // how many mipmap levels in this texture
214 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
217 int glinternalformat;
218 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
223 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
225 typedef struct gltexturepool_s
227 unsigned int sentinel;
228 struct gltexture_s *gltchain;
229 struct gltexturepool_s *next;
233 static gltexturepool_t *gltexturepoolchain = NULL;
235 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
236 static int resizebuffersize = 0;
237 static const unsigned char *texturebuffer;
239 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
244 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
245 case TEXTYPE_RGBA: return ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba);
246 case TEXTYPE_BGRA: return ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra);
248 case TEXTYPE_ETC1: return &textype_etc1;
250 case TEXTYPE_ALPHA: return &textype_alpha;
251 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
252 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
253 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
254 case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
255 case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
256 case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
257 case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
258 case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
259 case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
260 case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
262 case TEXTYPE_DXT1: return &textype_dxt1;
263 case TEXTYPE_DXT1A: return &textype_dxt1a;
264 case TEXTYPE_DXT3: return &textype_dxt3;
265 case TEXTYPE_DXT5: return &textype_dxt5;
266 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
267 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);
268 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);
269 case TEXTYPE_ALPHA: return &textype_alpha;
270 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
271 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
272 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
273 case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
274 case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
275 case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
276 case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
277 case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
278 case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
279 case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
280 case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1;
281 case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a;
282 case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
283 case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
284 case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
285 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);
286 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);
289 Host_Error("R_GetTexTypeInfo: unknown texture format %i with flags %x", (int)textype, flags);
295 // dynamic texture code [11/22/2007 Black]
296 void R_MarkDirtyTexture(rtexture_t *rt) {
297 gltexture_t *glt = (gltexture_t*) rt;
302 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
303 if (glt->flags & GLTEXF_DYNAMIC)
305 // mark it as dirty, so R_RealGetTexture gets called
310 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
311 gltexture_t *glt = (gltexture_t*) rt;
316 glt->flags |= GLTEXF_DYNAMIC;
317 glt->updatecallback = updatecallback;
318 glt->updatecallback_data = data;
321 static void R_UpdateDynamicTexture(gltexture_t *glt) {
323 if( glt->updatecallback ) {
324 glt->updatecallback( (rtexture_t*) glt, glt->updatecallback_data );
328 void R_PurgeTexture(rtexture_t *rt)
330 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
335 void R_FreeTexture(rtexture_t *rt)
337 gltexture_t *glt, **gltpointer;
339 glt = (gltexture_t *)rt;
341 Host_Error("R_FreeTexture: texture == NULL");
343 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
344 if (*gltpointer == glt)
345 *gltpointer = glt->chain;
347 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
349 R_Mesh_ClearBindingsForTexture(glt->texnum);
351 switch(vid.renderpath)
353 case RENDERPATH_GL32:
354 case RENDERPATH_GLES2:
358 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
360 if (glt->renderbuffernum)
363 qglDeleteRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
368 if (glt->inputtexels)
369 Mem_Free(glt->inputtexels);
370 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
373 rtexturepool_t *R_AllocTexturePool(void)
375 gltexturepool_t *pool;
376 if (texturemempool == NULL)
378 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
381 pool->next = gltexturepoolchain;
382 gltexturepoolchain = pool;
383 pool->sentinel = TEXTUREPOOL_SENTINEL;
384 return (rtexturepool_t *)pool;
387 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
389 gltexturepool_t *pool, **poolpointer;
390 if (rtexturepool == NULL)
392 if (*rtexturepool == NULL)
394 pool = (gltexturepool_t *)(*rtexturepool);
395 *rtexturepool = NULL;
396 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
397 Host_Error("R_FreeTexturePool: pool already freed");
398 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
399 if (*poolpointer == pool)
400 *poolpointer = pool->next;
402 Host_Error("R_FreeTexturePool: pool not linked");
403 while (pool->gltchain)
404 R_FreeTexture((rtexture_t *)pool->gltchain);
409 typedef struct glmode_s
412 int minification, magnification;
416 static glmode_t modes[6] =
418 {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
419 {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
420 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
421 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
422 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
423 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
426 static void GL_TextureMode_f(cmd_state_t *cmd)
431 gltexturepool_t *pool;
433 if (Cmd_Argc(cmd) == 1)
435 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
436 for (i = 0;i < 6;i++)
438 if (gl_filter_min == modes[i].minification)
440 Con_Printf("%s\n", modes[i].name);
444 Con_Print("current filter is unknown???\n");
448 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
449 if (!strcasecmp (modes[i].name, Cmd_Argv(cmd, 1) ) )
453 Con_Print("bad filter name\n");
457 gl_filter_min = modes[i].minification;
458 gl_filter_mag = modes[i].magnification;
459 gl_filter_force = ((Cmd_Argc(cmd) > 2) && !strcasecmp(Cmd_Argv(cmd, 2), "force"));
461 switch(vid.renderpath)
463 case RENDERPATH_GL32:
464 case RENDERPATH_GLES2:
465 // change all the existing mipmap texture objects
466 // FIXME: force renderer(/client/something?) restart instead?
469 for (pool = gltexturepoolchain;pool;pool = pool->next)
471 for (glt = pool->gltchain;glt;glt = glt->chain)
473 // only update already uploaded images
474 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
476 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
477 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
478 if (glt->flags & TEXF_MIPMAP)
480 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
484 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
486 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
487 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
495 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)
497 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
502 case GLTEXTURETYPE_2D:
503 maxsize = vid.maxtexturesize_2d;
504 if (flags & TEXF_PICMIP)
506 maxsize = bound(1, gl_max_size.integer, maxsize);
510 case GLTEXTURETYPE_3D:
511 maxsize = vid.maxtexturesize_3d;
513 case GLTEXTURETYPE_CUBEMAP:
514 maxsize = vid.maxtexturesize_cubemap;
518 width2 = min(inwidth >> picmip, maxsize);
519 height2 = min(inheight >> picmip, maxsize);
520 depth2 = min(indepth >> picmip, maxsize);
523 if (flags & TEXF_MIPMAP)
525 int extent = max(width2, max(height2, depth2));
531 *outwidth = max(1, width2);
533 *outheight = max(1, height2);
535 *outdepth = max(1, depth2);
537 *outmiplevels = miplevels;
541 static int R_CalcTexelDataSize (gltexture_t *glt)
543 int width2, height2, depth2, size;
545 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
547 size = width2 * height2 * depth2;
549 if (glt->flags & TEXF_MIPMAP)
551 while (width2 > 1 || height2 > 1 || depth2 > 1)
559 size += width2 * height2 * depth2;
563 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
566 void R_TextureStats_Print(qbool printeach, qbool printpool, qbool printtotal)
570 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
571 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
573 gltexturepool_t *pool;
575 Con_Print("glsize input loaded mip alpha name\n");
576 for (pool = gltexturepoolchain;pool;pool = pool->next)
584 for (glt = pool->gltchain;glt;glt = glt->chain)
586 glsize = R_CalcTexelDataSize(glt);
587 isloaded = glt->texnum != 0 || glt->renderbuffernum != 0;
589 pooltotalt += glsize;
590 pooltotalp += glt->inputdatasize;
594 poolloadedt += glsize;
595 poolloadedp += glt->inputdatasize;
598 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);
601 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);
602 sumtotal += pooltotal;
603 sumtotalt += pooltotalt;
604 sumtotalp += pooltotalp;
605 sumloaded += poolloaded;
606 sumloadedt += poolloadedt;
607 sumloadedp += poolloadedp;
610 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);
613 static void R_TextureStats_f(cmd_state_t *cmd)
615 R_TextureStats_Print(true, true, true);
618 static void r_textures_start(void)
620 switch(vid.renderpath)
622 case RENDERPATH_GL32:
623 case RENDERPATH_GLES2:
624 // LadyHavoc: allow any alignment
626 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
627 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
631 texturemempool = Mem_AllocPool("texture management", 0, NULL);
632 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
634 // Disable JPEG screenshots if the DLL isn't loaded
635 if (! JPEG_OpenLibrary ())
636 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
637 if (! PNG_OpenLibrary ())
638 Cvar_SetValueQuick (&scr_screenshot_png, 0);
641 static void r_textures_shutdown(void)
643 rtexturepool_t *temp;
645 JPEG_CloseLibrary ();
647 while(gltexturepoolchain)
649 temp = (rtexturepool_t *) gltexturepoolchain;
650 R_FreeTexturePool(&temp);
653 resizebuffersize = 0;
655 colorconvertbuffer = NULL;
656 texturebuffer = NULL;
657 Mem_ExpandableArray_FreeArray(&texturearray);
658 Mem_FreePool(&texturemempool);
661 static void r_textures_newmap(void)
665 static void r_textures_devicelost(void)
669 endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
670 for (i = 0;i < endindex;i++)
672 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
673 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
675 switch(vid.renderpath)
677 case RENDERPATH_GL32:
678 case RENDERPATH_GLES2:
684 static void r_textures_devicerestored(void)
688 endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
689 for (i = 0;i < endindex;i++)
691 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
692 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
694 switch(vid.renderpath)
696 case RENDERPATH_GL32:
697 case RENDERPATH_GLES2:
704 void R_Textures_Init (void)
706 Cmd_AddCommand(CF_CLIENT, "gl_texturemode", &GL_TextureMode_f, "set texture filtering mode (GL_NEAREST, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, etc); an additional argument 'force' forces the texture mode even in cases where it may not be appropriate");
707 Cmd_AddCommand(CF_CLIENT, "r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
708 Cvar_RegisterVariable (&gl_max_size);
709 Cvar_RegisterVariable (&gl_picmip);
710 Cvar_RegisterVariable (&gl_picmip_world);
711 Cvar_RegisterVariable (&r_picmipworld);
712 Cvar_RegisterVariable (&gl_picmip_sprites);
713 Cvar_RegisterVariable (&r_picmipsprites);
714 Cvar_RegisterVariable (&gl_picmip_other);
715 Cvar_RegisterVariable (&gl_max_lightmapsize);
716 Cvar_RegisterVariable (&r_lerpimages);
717 Cvar_RegisterVariable (&gl_texture_anisotropy);
718 Cvar_RegisterVariable (&gl_texturecompression);
719 Cvar_RegisterVariable (&gl_texturecompression_color);
720 Cvar_RegisterVariable (&gl_texturecompression_normal);
721 Cvar_RegisterVariable (&gl_texturecompression_gloss);
722 Cvar_RegisterVariable (&gl_texturecompression_glow);
723 Cvar_RegisterVariable (&gl_texturecompression_2d);
724 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
725 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
726 Cvar_RegisterVariable (&gl_texturecompression_sky);
727 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
728 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
729 Cvar_RegisterVariable (&gl_texturecompression_sprites);
730 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
731 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
732 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
733 Cvar_RegisterVariable (&r_texture_dds_swdecode);
735 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
738 void R_Textures_Frame (void)
740 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
741 static int old_aniso = 0;
742 static qbool first_time_aniso = true;
745 // could do procedural texture animation here, if we keep track of which
746 // textures were accessed this frame...
748 // free the resize buffers
749 resizebuffersize = 0;
752 Mem_Free(resizebuffer);
755 if (colorconvertbuffer)
757 Mem_Free(colorconvertbuffer);
758 colorconvertbuffer = NULL;
761 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
762 if (old_aniso != gl_texture_anisotropy.integer)
765 gltexturepool_t *pool;
768 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
770 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
772 switch(vid.renderpath)
774 case RENDERPATH_GL32:
775 case RENDERPATH_GLES2:
776 // ignore the first difference, any textures loaded by now probably had the same aniso value
777 if (first_time_aniso)
779 first_time_aniso = false;
784 for (pool = gltexturepoolchain;pool;pool = pool->next)
786 for (glt = pool->gltchain;glt;glt = glt->chain)
788 // only update already uploaded images
789 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
791 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
793 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
794 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
796 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
806 static void R_MakeResizeBufferBigger(int size)
808 if (resizebuffersize < size)
810 resizebuffersize = size;
812 Mem_Free(resizebuffer);
813 if (colorconvertbuffer)
814 Mem_Free(colorconvertbuffer);
815 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
816 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
817 if (!resizebuffer || !colorconvertbuffer)
818 Host_Error("R_Upload: out of memory");
822 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
824 int textureenum = gltexturetypeenums[texturetype];
825 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
829 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
830 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
832 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
833 if (gl_texture_anisotropy.integer != aniso)
834 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
835 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
838 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
839 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
840 #ifdef GL_TEXTURE_WRAP_R
841 if (gltexturetypedimensions[texturetype] >= 3)
843 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
848 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
850 if (flags & TEXF_MIPMAP)
852 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
856 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
858 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
860 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
862 if (flags & TEXF_MIPMAP)
864 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
866 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
870 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
875 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
877 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
881 if (flags & TEXF_MIPMAP)
883 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
887 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
889 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
895 case TEXTYPE_SHADOWMAP16_COMP:
896 case TEXTYPE_SHADOWMAP24_COMP:
897 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);CHECKGLERROR
898 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);CHECKGLERROR
900 case TEXTYPE_SHADOWMAP16_RAW:
901 case TEXTYPE_SHADOWMAP24_RAW:
902 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE, GL_NONE);CHECKGLERROR
903 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);CHECKGLERROR
913 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
916 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
918 if (glt->texturetype != GLTEXTURETYPE_2D)
919 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
921 if (glt->textype->textype == TEXTYPE_PALETTE)
922 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
924 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
925 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
927 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
928 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
930 // update a portion of the image
932 switch(vid.renderpath)
934 case RENDERPATH_GL32:
935 case RENDERPATH_GLES2:
939 // we need to restore the texture binding after finishing the upload
941 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
942 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
943 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
944 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
950 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
952 int i, mip = 0, width, height, depth;
953 GLint oldbindtexnum = 0;
954 const unsigned char *prevbuffer;
957 // error out if a stretch is needed on special texture types
958 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
959 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
961 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
962 // of the target size and then use the mipmap reduction function to get
963 // high quality supersampled results
964 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
965 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
966 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
968 if (prevbuffer == NULL)
970 width = glt->tilewidth;
971 height = glt->tileheight;
972 depth = glt->tiledepth;
973 // R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
974 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
975 // prevbuffer = resizebuffer;
979 if (glt->textype->textype == TEXTYPE_PALETTE)
981 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
982 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
983 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
984 prevbuffer = colorconvertbuffer;
986 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
988 // multiply RGB channels by A channel before uploading
990 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
991 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
993 alpha = prevbuffer[i+3];
994 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
995 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
996 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
997 colorconvertbuffer[i+3] = alpha;
999 prevbuffer = colorconvertbuffer;
1001 // scale up to a power of 2 size (if appropriate)
1002 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1004 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1005 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1006 prevbuffer = resizebuffer;
1008 // apply mipmap reduction algorithm to get down to picmip/max_size
1009 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1011 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1012 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1013 prevbuffer = resizebuffer;
1017 // do the appropriate upload type...
1018 switch(vid.renderpath)
1020 case RENDERPATH_GL32:
1021 case RENDERPATH_GLES2:
1022 if (glt->texnum) // not renderbuffers
1026 // we need to restore the texture binding after finishing the upload
1027 GL_ActiveTexture(0);
1028 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1029 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1032 if (gl_texturecompression.integer >= 2)
1033 qglHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
1035 qglHint(GL_TEXTURE_COMPRESSION_HINT, GL_FASTEST);
1038 switch(glt->texturetype)
1040 case GLTEXTURETYPE_2D:
1041 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1042 if (glt->flags & TEXF_MIPMAP)
1044 while (width > 1 || height > 1 || depth > 1)
1046 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1047 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1048 prevbuffer = resizebuffer;
1049 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1053 case GLTEXTURETYPE_3D:
1055 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1056 if (glt->flags & TEXF_MIPMAP)
1058 while (width > 1 || height > 1 || depth > 1)
1060 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1061 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1062 prevbuffer = resizebuffer;
1063 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1068 case GLTEXTURETYPE_CUBEMAP:
1069 // convert and upload each side in turn,
1070 // from a continuous block of input texels
1071 texturebuffer = (unsigned char *)prevbuffer;
1072 for (i = 0;i < 6;i++)
1074 prevbuffer = texturebuffer;
1075 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1076 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1078 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1079 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1080 prevbuffer = resizebuffer;
1083 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1085 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1086 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1087 prevbuffer = resizebuffer;
1090 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1091 if (glt->flags & TEXF_MIPMAP)
1093 while (width > 1 || height > 1 || depth > 1)
1095 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1096 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1097 prevbuffer = resizebuffer;
1098 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1104 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1105 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1111 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)
1115 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1116 textypeinfo_t *texinfo, *texinfo2;
1117 unsigned char *temppixels = NULL;
1120 if (cls.state == ca_dedicated)
1123 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1124 if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1126 int numpixels = width * height * depth * sides;
1127 size = numpixels * 4;
1128 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1131 const unsigned char *p;
1132 unsigned char *o = temppixels;
1133 for (i = 0;i < numpixels;i++, o += 4)
1135 p = (const unsigned char *)palette + 4*data[i];
1143 textype = TEXTYPE_RGBA;
1148 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1149 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1150 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1151 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1157 static int rgbaswapindices[4] = {2, 1, 0, 3};
1158 size = width * height * depth * sides * 4;
1159 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1161 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1165 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1166 if (!vid.support.ext_texture_srgb)
1168 qbool convertsRGB = false;
1171 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1172 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1173 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1174 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1175 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;/*convertsRGB = true;*/break;
1176 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1177 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1181 if (convertsRGB && data)
1183 size = width * height * depth * sides * 4;
1186 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1187 memcpy(temppixels, data, size);
1190 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1194 texinfo = R_GetTexTypeInfo(textype, flags);
1195 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1198 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1202 // clear the alpha flag if the texture has no transparent pixels
1205 case TEXTYPE_PALETTE:
1206 case TEXTYPE_SRGB_PALETTE:
1207 if (flags & TEXF_ALPHA)
1209 flags &= ~TEXF_ALPHA;
1212 for (i = 0;i < size;i++)
1214 if (((unsigned char *)&palette[data[i]])[3] < 255)
1216 flags |= TEXF_ALPHA;
1225 case TEXTYPE_SRGB_RGBA:
1226 case TEXTYPE_SRGB_BGRA:
1227 if (flags & TEXF_ALPHA)
1229 flags &= ~TEXF_ALPHA;
1232 for (i = 3;i < size;i += 4)
1236 flags |= TEXF_ALPHA;
1243 case TEXTYPE_SHADOWMAP16_COMP:
1244 case TEXTYPE_SHADOWMAP16_RAW:
1245 case TEXTYPE_SHADOWMAP24_COMP:
1246 case TEXTYPE_SHADOWMAP24_RAW:
1249 case TEXTYPE_SRGB_DXT1:
1252 case TEXTYPE_SRGB_DXT1A:
1254 case TEXTYPE_SRGB_DXT3:
1256 case TEXTYPE_SRGB_DXT5:
1257 flags |= TEXF_ALPHA;
1260 flags |= TEXF_ALPHA;
1262 case TEXTYPE_COLORBUFFER:
1263 case TEXTYPE_COLORBUFFER16F:
1264 case TEXTYPE_COLORBUFFER32F:
1265 flags |= TEXF_ALPHA;
1268 Sys_Error("R_LoadTexture: unknown texture type");
1271 texinfo2 = R_GetTexTypeInfo(textype, flags);
1272 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1275 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1277 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1279 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1281 glt->chain = pool->gltchain;
1282 pool->gltchain = glt;
1283 glt->inputwidth = width;
1284 glt->inputheight = height;
1285 glt->inputdepth = depth;
1287 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
1288 glt->textype = texinfo;
1289 glt->texturetype = texturetype;
1290 glt->inputdatasize = size;
1291 glt->palette = palette;
1292 glt->glinternalformat = texinfo->glinternalformat;
1293 glt->glformat = texinfo->glformat;
1294 glt->gltype = texinfo->gltype;
1295 glt->bytesperpixel = texinfo->internalbytesperpixel;
1296 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1299 glt->glisdepthstencil = false;
1300 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1301 // init the dynamic texture attributes, too [11/22/2007 Black]
1302 glt->updatecallback = NULL;
1303 glt->updatecallback_data = NULL;
1305 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1307 // upload the texture
1308 // data may be NULL (blank texture for dynamic rendering)
1309 switch(vid.renderpath)
1311 case RENDERPATH_GL32:
1312 case RENDERPATH_GLES2:
1314 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1318 R_UploadFullTexture(glt, data);
1319 if (glt->flags & TEXF_ALLOWUPDATES)
1320 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1322 glt->modifiedpixels = NULL;
1323 glt->modified_width = glt->modified_height = glt->modified_depth = glt->modified_offset_x = glt->modified_offset_y = glt->modified_offset_z = 0;
1325 // free any temporary processing buffer we allocated...
1327 Mem_Free(temppixels);
1329 // texture converting and uploading can take a while, so make sure we're sending keepalives
1330 // FIXME: this causes rendering during R_Shadow_DrawLights
1331 // CL_KeepaliveMessage(false);
1333 return (rtexture_t *)glt;
1336 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)
1338 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1341 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)
1343 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1346 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)
1348 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1351 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qbool filter)
1353 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL);
1356 rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
1359 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1360 textypeinfo_t *texinfo;
1362 if (cls.state == ca_dedicated)
1365 texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP);
1367 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1369 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1371 glt->chain = pool->gltchain;
1372 pool->gltchain = glt;
1373 glt->inputwidth = width;
1374 glt->inputheight = height;
1375 glt->inputdepth = 1;
1376 glt->flags = TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_FORCENEAREST;
1378 glt->textype = texinfo;
1379 glt->texturetype = textype;
1380 glt->inputdatasize = width*height*texinfo->internalbytesperpixel;
1381 glt->palette = NULL;
1382 glt->glinternalformat = texinfo->glinternalformat;
1383 glt->glformat = texinfo->glformat;
1384 glt->gltype = texinfo->gltype;
1385 glt->bytesperpixel = texinfo->internalbytesperpixel;
1386 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1389 glt->glisdepthstencil = textype == TEXTYPE_DEPTHBUFFER24STENCIL8;
1390 glt->gltexturetypeenum = GL_TEXTURE_2D;
1391 // init the dynamic texture attributes, too [11/22/2007 Black]
1392 glt->updatecallback = NULL;
1393 glt->updatecallback_data = NULL;
1395 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1397 // upload the texture
1398 // data may be NULL (blank texture for dynamic rendering)
1399 switch(vid.renderpath)
1401 case RENDERPATH_GL32:
1402 case RENDERPATH_GLES2:
1404 qglGenRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
1405 qglBindRenderbuffer(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR
1406 qglRenderbufferStorage(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR
1407 // 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
1408 qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR
1412 return (rtexture_t *)glt;
1415 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qbool skipuncompressed, qbool hasalpha)
1418 return -1; // unsupported on this platform
1420 gltexture_t *glt = (gltexture_t *)rt;
1423 int bytesperpixel = 0;
1424 int bytesperblock = 0;
1426 int dds_format_flags;
1434 GLint internalformat;
1435 const char *ddsfourcc;
1437 return -1; // NULL pointer
1438 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1439 return -2; // broken driver - crashes on reading internal format
1440 if (!qglGetTexLevelParameteriv)
1442 GL_ActiveTexture(0);
1443 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1444 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1445 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1446 switch(internalformat)
1448 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1449 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1450 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1451 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1452 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1454 // if premultiplied alpha, say so in the DDS file
1455 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1457 switch(internalformat)
1459 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1460 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1463 if (!bytesperblock && skipuncompressed)
1464 return -3; // skipped
1465 memset(mipinfo, 0, sizeof(mipinfo));
1466 mipinfo[0][0] = glt->tilewidth;
1467 mipinfo[0][1] = glt->tileheight;
1469 if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1))
1471 for (mip = 1;mip < 16;mip++)
1473 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1474 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1475 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1483 for (mip = 0;mip < mipmaps;mip++)
1485 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1486 mipinfo[mip][3] = ddssize;
1487 ddssize += mipinfo[mip][2];
1489 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1492 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1496 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1497 dds_format_flags = 0x4; // DDPF_FOURCC
1501 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1502 dds_format_flags = 0x40; // DDPF_RGB
1506 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1507 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1510 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1511 memcpy(dds, "DDS ", 4);
1512 StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
1513 StoreLittleLong(dds+8, dds_flags);
1514 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1515 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1516 StoreLittleLong(dds+24, 0); // depth
1517 StoreLittleLong(dds+28, mipmaps); // mipmaps
1518 StoreLittleLong(dds+76, 32); // format size
1519 StoreLittleLong(dds+80, dds_format_flags);
1520 StoreLittleLong(dds+108, dds_caps1);
1521 StoreLittleLong(dds+112, dds_caps2);
1524 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1525 memcpy(dds+84, ddsfourcc, 4);
1526 for (mip = 0;mip < mipmaps;mip++)
1528 qglGetCompressedTexImage(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1533 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1534 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1535 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1536 for (mip = 0;mip < mipmaps;mip++)
1538 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1541 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1542 ret = FS_WriteFile(filename, dds, ddssize);
1544 return ret ? ddssize : -5;
1549 // ELUAN: FIXME: separate this code
1550 #include "ktx10/include/ktx.h"
1553 rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qbool srgb, int flags, qbool *hasalphaflag, float *avgcolor, int miplevel, qbool optionaltexture) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint
1555 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1558 int bytesperblock, bytesperpixel;
1561 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1562 textypeinfo_t *texinfo;
1563 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1564 unsigned int c, r, g, b;
1565 GLint oldbindtexnum = 0;
1566 unsigned char *mippixels;
1567 unsigned char *mippixels_start;
1568 unsigned char *ddspixels;
1570 fs_offset_t ddsfilesize;
1571 unsigned int ddssize;
1572 qbool force_swdecode;
1574 // ELUAN: FIXME: separate this code
1578 KTX_dimensions sizes;
1581 if (cls.state == ca_dedicated)
1585 // ELUAN: FIXME: separate this code
1586 if (vid.renderpath != RENDERPATH_GLES2)
1588 Con_DPrintf("KTX texture format is only supported on the GLES2 renderpath\n");
1592 // some textures are specified with extensions, so it becomes .tga.dds
1593 FS_StripExtension (filename, vabuf2, sizeof(vabuf2));
1594 FS_StripExtension (vabuf2, vabuf, sizeof(vabuf));
1595 FS_DefaultExtension (vabuf, ".ktx", sizeof(vabuf));
1596 strsize = strlen(vabuf);
1598 for (i = 0; i <= strsize - 4; i++) // copy null termination
1599 vabuf[i] = vabuf[i + 4];
1601 Con_DPrintf("Loading %s...\n", vabuf);
1602 dds = FS_LoadFile(vabuf, tempmempool, true, &ddsfilesize);
1603 ddssize = ddsfilesize;
1607 Con_DPrintf("Not found!\n");
1608 return NULL; // not found
1610 Con_DPrintf("Found!\n");
1612 if (flags & TEXF_ALPHA)
1614 Con_DPrintf("KTX texture with alpha not supported yet, disabling\n");
1615 flags &= ~TEXF_ALPHA;
1621 GLboolean isMipmapped;
1622 KTX_error_code ktxerror;
1624 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1626 // texture uploading can take a while, so make sure we're sending keepalives
1627 CL_KeepaliveMessage(false);
1629 // create the texture object
1631 GL_ActiveTexture(0);
1632 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[GLTEXTURETYPE_2D]);
1633 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1634 qglBindTexture(gltexturetypeenums[GLTEXTURETYPE_2D], glt->texnum);CHECKGLERROR
1636 // upload the texture
1637 // we need to restore the texture binding after finishing the upload
1639 // NOTE: some drivers fail with ETC1 NPOT (only PowerVR?). This may make the driver crash later.
1640 ktxerror = ktxLoadTextureM(dds, ddssize, &glt->texnum, &target, &sizes, &isMipmapped, &glerror,
1641 0, NULL);// can't CHECKGLERROR, the lib catches it
1643 // FIXME: delete texture if we fail here
1644 if (target != GL_TEXTURE_2D)
1646 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1648 Con_DPrintf("%s target != GL_TEXTURE_2D, target == %x\n", vabuf, target);
1649 return NULL; // FIXME: delete the texture from memory
1652 if (KTX_SUCCESS == ktxerror)
1654 textype = TEXTYPE_ETC1;
1655 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
1657 // return whether this texture is transparent
1659 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1661 // TODO: apply gl_picmip
1664 // TODO: only load mipmaps if requested
1667 flags |= TEXF_MIPMAP;
1669 flags &= ~TEXF_MIPMAP;
1671 texinfo = R_GetTexTypeInfo(textype, flags);
1673 strlcpy (glt->identifier, vabuf, sizeof(glt->identifier));
1675 glt->chain = pool->gltchain;
1676 pool->gltchain = glt;
1677 glt->inputwidth = sizes.width;
1678 glt->inputheight = sizes.height;
1679 glt->inputdepth = 1;
1681 glt->textype = texinfo;
1682 glt->texturetype = GLTEXTURETYPE_2D;
1683 glt->inputdatasize = ddssize;
1684 glt->glinternalformat = texinfo->glinternalformat;
1685 glt->glformat = texinfo->glformat;
1686 glt->gltype = texinfo->gltype;
1687 glt->bytesperpixel = texinfo->internalbytesperpixel;
1689 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1690 glt->tilewidth = sizes.width;
1691 glt->tileheight = sizes.height;
1693 glt->miplevels = isMipmapped ? 1 : 0; // FIXME
1695 // after upload we have to set some parameters...
1696 #ifdef GL_TEXTURE_MAX_LEVEL
1698 if (dds_miplevels >= 1 && !mipcomplete)
1700 // need to set GL_TEXTURE_MAX_LEVEL
1701 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
1705 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1707 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1709 return (rtexture_t *)glt;
1713 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1715 Con_DPrintf("KTX texture %s failed to load: %x\n", vabuf, ktxerror);
1719 #endif // __ANDROID__
1721 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1722 ddssize = ddsfilesize;
1726 if (r_texture_dds_load_logfailure.integer && (r_texture_dds_load_logfailure.integer >= 2 || !optionaltexture))
1727 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1728 return NULL; // not found
1731 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1734 Con_Printf("^1%s: not a DDS image\n", filename);
1738 //dds_flags = BuffLittleLong(dds+8);
1739 dds_format_flags = BuffLittleLong(dds+80);
1740 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1741 dds_width = BuffLittleLong(dds+16);
1742 dds_height = BuffLittleLong(dds+12);
1743 ddspixels = dds + 128;
1745 if(r_texture_dds_load_alphamode.integer == 0)
1746 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1747 flags &= ~TEXF_ALPHA;
1749 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1750 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1752 // very sloppy BGRA 32bit identification
1753 textype = TEXTYPE_BGRA;
1754 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
1757 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1758 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1761 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1764 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1767 for (i = 3;i < size;i += 4)
1768 if (ddspixels[i] < 255)
1771 flags &= ~TEXF_ALPHA;
1774 else if (!memcmp(dds+84, "DXT1", 4))
1776 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1777 // LadyHavoc: it is my belief that this does not infringe on the
1778 // patent because it is not decoding pixels...
1779 textype = TEXTYPE_DXT1;
1782 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1783 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1784 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1787 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1790 if (flags & TEXF_ALPHA)
1792 if (r_texture_dds_load_alphamode.integer == 1)
1795 for (i = 0;i < size;i += bytesperblock)
1796 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1798 // NOTE: this assumes sizeof(unsigned int) == 4
1799 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1800 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1801 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1805 textype = TEXTYPE_DXT1A;
1807 flags &= ~TEXF_ALPHA;
1809 else if (r_texture_dds_load_alphamode.integer == 0)
1810 textype = TEXTYPE_DXT1A;
1813 flags &= ~TEXF_ALPHA;
1817 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
1819 if(!memcmp(dds+84, "DXT2", 4))
1821 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1823 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
1828 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1830 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
1833 textype = TEXTYPE_DXT3;
1836 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1837 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1840 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1843 // we currently always assume alpha
1845 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
1847 if(!memcmp(dds+84, "DXT4", 4))
1849 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1851 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
1856 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1858 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
1861 textype = TEXTYPE_DXT5;
1864 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1865 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1868 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1871 // we currently always assume alpha
1876 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1880 // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
1881 if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
1883 textype = TEXTYPE_DXT1;
1887 for (i = 0;i < (int)ddssize;i += bytesperblock)
1888 memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
1892 force_swdecode = false;
1895 if(vid.support.ext_texture_compression_s3tc)
1897 if(r_texture_dds_swdecode.integer > 1)
1898 force_swdecode = true;
1902 if(r_texture_dds_swdecode.integer < 1)
1908 force_swdecode = true;
1912 // return whether this texture is transparent
1914 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1916 // if we SW decode, choose 2 sizes bigger
1919 // this is quarter res, so do not scale down more than we have to
1923 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
1926 // this is where we apply gl_picmip
1927 mippixels_start = ddspixels;
1928 mipwidth = dds_width;
1929 mipheight = dds_height;
1930 while(miplevel >= 1 && dds_miplevels >= 1)
1932 if (mipwidth <= 1 && mipheight <= 1)
1934 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1935 mippixels_start += mipsize; // just skip
1943 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
1944 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1946 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
1948 // fake decode S3TC if needed
1951 int mipsize_new = mipsize_total / bytesperblock * 4;
1952 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
1953 unsigned char *p = mipnewpixels;
1954 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
1956 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
1957 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
1958 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
1959 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
1960 if(textype == TEXTYPE_DXT5)
1961 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
1962 else if(textype == TEXTYPE_DXT3)
1964 (mippixels_start[i-8] & 0x0F)
1965 + (mippixels_start[i-8] >> 4)
1966 + (mippixels_start[i-7] & 0x0F)
1967 + (mippixels_start[i-7] >> 4)
1968 + (mippixels_start[i-6] & 0x0F)
1969 + (mippixels_start[i-6] >> 4)
1970 + (mippixels_start[i-5] & 0x0F)
1971 + (mippixels_start[i-5] >> 4)
1972 ) * (0.125f / 15.0f * 255.0f);
1977 textype = TEXTYPE_BGRA;
1981 // as each block becomes a pixel, we must use pixel count for this
1982 mipwidth = (mipwidth + 3) / 4;
1983 mipheight = (mipheight + 3) / 4;
1984 mipsize = bytesperpixel * mipwidth * mipheight;
1985 mippixels_start = mipnewpixels;
1986 mipsize_total = mipsize_new;
1989 // start mip counting
1990 mippixels = mippixels_start;
1992 // calculate average color if requested
1996 Vector4Clear(avgcolor);
1999 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2001 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2002 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2003 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2004 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2005 if(textype == TEXTYPE_DXT5)
2006 avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f);
2007 else if(textype == TEXTYPE_DXT3)
2009 (mippixels_start[i-8] & 0x0F)
2010 + (mippixels_start[i-8] >> 4)
2011 + (mippixels_start[i-7] & 0x0F)
2012 + (mippixels_start[i-7] >> 4)
2013 + (mippixels_start[i-6] & 0x0F)
2014 + (mippixels_start[i-6] >> 4)
2015 + (mippixels_start[i-5] & 0x0F)
2016 + (mippixels_start[i-5] >> 4)
2017 ) * (0.125f / 15.0f);
2019 avgcolor[3] += 1.0f;
2021 f = (float)bytesperblock / mipsize;
2022 avgcolor[0] *= (0.5f / 31.0f) * f;
2023 avgcolor[1] *= (0.5f / 63.0f) * f;
2024 avgcolor[2] *= (0.5f / 31.0f) * f;
2029 for (i = 0;i < mipsize;i += 4)
2031 avgcolor[0] += mippixels[i+2];
2032 avgcolor[1] += mippixels[i+1];
2033 avgcolor[2] += mippixels[i];
2034 avgcolor[3] += mippixels[i+3];
2036 f = (1.0f / 255.0f) * bytesperpixel / mipsize;
2044 // if we want sRGB, convert now
2047 if (vid.support.ext_texture_srgb)
2051 case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break;
2052 case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break;
2053 case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break;
2054 case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break;
2055 case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break;
2069 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2071 int c0, c1, c0new, c1new;
2072 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2073 r = ((c0 >> 11) & 0x1F);
2074 g = ((c0 >> 5) & 0x3F);
2076 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2077 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2078 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2079 c0new = (r << 11) | (g << 5) | b;
2080 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2081 r = ((c1 >> 11) & 0x1F);
2082 g = ((c1 >> 5) & 0x3F);
2084 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2085 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2086 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2087 c1new = (r << 11) | (g << 5) | b;
2088 // swap the colors if needed to fix order
2089 if(c0 > c1) // thirds
2097 mippixels_start[i+4] ^= 0x55;
2098 mippixels_start[i+5] ^= 0x55;
2099 mippixels_start[i+6] ^= 0x55;
2100 mippixels_start[i+7] ^= 0x55;
2102 else if(c0new == c1new)
2104 mippixels_start[i+4] = 0x00;
2105 mippixels_start[i+5] = 0x00;
2106 mippixels_start[i+6] = 0x00;
2107 mippixels_start[i+7] = 0x00;
2110 else // half + transparent
2117 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2118 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2119 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2120 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2123 mippixels_start[i] = c0new & 255;
2124 mippixels_start[i+1] = c0new >> 8;
2125 mippixels_start[i+2] = c1new & 255;
2126 mippixels_start[i+3] = c1new >> 8;
2131 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2139 // when not requesting mipmaps, do not load them
2140 if(!(flags & TEXF_MIPMAP))
2143 if (dds_miplevels >= 1)
2144 flags |= TEXF_MIPMAP;
2146 flags &= ~TEXF_MIPMAP;
2148 texinfo = R_GetTexTypeInfo(textype, flags);
2150 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2151 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2153 glt->chain = pool->gltchain;
2154 pool->gltchain = glt;
2155 glt->inputwidth = mipwidth;
2156 glt->inputheight = mipheight;
2157 glt->inputdepth = 1;
2159 glt->textype = texinfo;
2160 glt->texturetype = GLTEXTURETYPE_2D;
2161 glt->inputdatasize = ddssize;
2162 glt->glinternalformat = texinfo->glinternalformat;
2163 glt->glformat = texinfo->glformat;
2164 glt->gltype = texinfo->gltype;
2165 glt->bytesperpixel = texinfo->internalbytesperpixel;
2167 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2168 glt->tilewidth = mipwidth;
2169 glt->tileheight = mipheight;
2171 glt->miplevels = dds_miplevels;
2173 // texture uploading can take a while, so make sure we're sending keepalives
2174 CL_KeepaliveMessage(false);
2176 // create the texture object
2177 switch(vid.renderpath)
2179 case RENDERPATH_GL32:
2180 case RENDERPATH_GLES2:
2182 GL_ActiveTexture(0);
2183 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2184 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2185 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2189 // upload the texture
2190 // we need to restore the texture binding after finishing the upload
2191 mipcomplete = false;
2193 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2195 unsigned char *upload_mippixels = mippixels;
2196 int upload_mipwidth = mipwidth;
2197 int upload_mipheight = mipheight;
2198 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2199 if (mippixels + mipsize > mippixels_start + mipsize_total)
2201 switch(vid.renderpath)
2203 case RENDERPATH_GL32:
2204 case RENDERPATH_GLES2:
2207 qglCompressedTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR
2211 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR
2215 if(upload_mippixels != mippixels)
2216 Mem_Free(upload_mippixels);
2217 mippixels += mipsize;
2218 if (mipwidth <= 1 && mipheight <= 1)
2229 // after upload we have to set some parameters...
2230 switch(vid.renderpath)
2232 case RENDERPATH_GL32:
2233 case RENDERPATH_GLES2:
2234 #ifdef GL_TEXTURE_MAX_LEVEL
2235 if (dds_miplevels >= 1 && !mipcomplete)
2237 // need to set GL_TEXTURE_MAX_LEVEL
2238 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2241 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2242 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2248 Mem_Free((unsigned char *) mippixels_start);
2249 return (rtexture_t *)glt;
2252 int R_TextureWidth(rtexture_t *rt)
2254 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2257 int R_TextureHeight(rtexture_t *rt)
2259 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2262 int R_TextureFlags(rtexture_t *rt)
2264 return rt ? ((gltexture_t *)rt)->flags : 0;
2267 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
2269 gltexture_t *glt = (gltexture_t *)rt;
2271 Host_Error("R_UpdateTexture: no data supplied");
2273 Host_Error("R_UpdateTexture: no texture supplied");
2276 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2279 // update part of the texture
2280 if (glt->bufferpixels || (glt->bufferpixels && (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)))
2283 int bpp = glt->bytesperpixel;
2284 int inputskip = width*bpp;
2285 int outputskip = glt->tilewidth*bpp;
2286 const unsigned char *input = data;
2287 unsigned char *output = glt->bufferpixels;
2288 if (glt->inputdepth != 1 || glt->sides != 1)
2289 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2299 input -= y*inputskip;
2302 if (width > glt->tilewidth - x)
2303 width = glt->tilewidth - x;
2304 if (height > glt->tileheight - y)
2305 height = glt->tileheight - y;
2306 if (width < 1 || height < 1)
2309 output += y*outputskip + x*bpp;
2310 /* Cloudwalk FIXME: Broken shit, disabled for now.
2311 // TODO: Optimize this further.
2312 if(!gl_nopartialtextureupdates.integer)
2314 // Calculate the modified region, and resize it as it gets bigger.
2315 if(!glt->buffermodified)
2317 glt->modified_offset_x = x;
2318 glt->modified_offset_y = y;
2319 glt->modified_offset_z = z;
2321 glt->modified_width = width;
2322 glt->modified_height = height;
2323 glt->modified_depth = depth;
2327 if(x < glt->modified_offset_x) glt->modified_offset_x = x;
2328 if(y < glt->modified_offset_y) glt->modified_offset_y = y;
2329 if(z < glt->modified_offset_z) glt->modified_offset_z = z;
2331 if(width + x > glt->modified_width) glt->modified_width = width + x;
2332 if(height + y > glt->modified_height) glt->modified_height = height + y;
2333 if(depth + z > glt->modified_depth) glt->modified_depth = depth + z;
2336 if(!&glt->modifiedpixels || &output < &glt->modifiedpixels)
2337 glt->modifiedpixels = output;
2341 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2342 memcpy(output, input, width*bpp);
2345 glt->buffermodified = true;
2348 R_UploadFullTexture(glt, data);
2351 int R_RealGetTexture(rtexture_t *rt)
2356 glt = (gltexture_t *)rt;
2357 if (glt->flags & GLTEXF_DYNAMIC)
2358 R_UpdateDynamicTexture(glt);
2359 if (glt->buffermodified && glt->bufferpixels)
2361 glt->buffermodified = false;
2362 if(!glt->modifiedpixels)
2363 R_UploadFullTexture(glt, glt->bufferpixels);
2365 R_UploadPartialTexture(glt, glt->modifiedpixels, glt->modified_offset_x, glt->modified_offset_y, glt->modified_offset_z, glt->modified_width, glt->modified_height, glt->modified_depth);
2367 glt->modified_offset_x = glt->modified_offset_y = glt->modified_offset_z = glt->modified_width = glt->modified_height = glt->modified_depth = 0;
2368 glt->modifiedpixels = NULL;
2373 return r_texture_white->texnum;
2376 void R_ClearTexture (rtexture_t *rt)
2378 gltexture_t *glt = (gltexture_t *)rt;
2380 R_UploadFullTexture(glt, NULL);
2383 int R_PicmipForFlags(int flags)
2386 if(flags & TEXF_PICMIP)
2388 miplevel += gl_picmip.integer;
2389 if (flags & TEXF_ISWORLD)
2391 if (r_picmipworld.integer)
2392 miplevel += gl_picmip_world.integer;
2396 else if (flags & TEXF_ISSPRITE)
2398 if (r_picmipsprites.integer)
2399 miplevel += gl_picmip_sprites.integer;
2404 miplevel += gl_picmip_other.integer;
2406 return max(0, miplevel);