2 Copyright (C) 2000-2020 DarkPlaces contributors
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #include "image_png.h"
27 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)"};
28 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)"};
29 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%"};
30 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)"};
31 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)"};
32 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)"};
33 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)"};
34 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)"};
35 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)"};
36 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"};
37 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"};
38 cvar_t gl_texturecompression_color = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
39 cvar_t gl_texturecompression_normal = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
40 cvar_t gl_texturecompression_gloss = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
41 cvar_t gl_texturecompression_glow = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
42 cvar_t gl_texturecompression_2d = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
43 cvar_t gl_texturecompression_q3bsplightmaps = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
44 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)"};
45 cvar_t gl_texturecompression_sky = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
46 cvar_t gl_texturecompression_lightcubemaps = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
47 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)"};
48 cvar_t gl_texturecompression_sprites = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_sprites", "1", "whether to compress sprites"};
49 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"};
50 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"};
51 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"};
53 qbool gl_filter_force = false;
54 int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
55 int gl_filter_mag = GL_LINEAR;
58 static mempool_t *texturemempool;
59 static memexpandablearray_t texturearray;
61 // note: this must not conflict with TEXF_ flags in r_textures.h
62 // bitmask for mismatch checking
63 #define GLTEXF_IMPORTANTBITS (0)
64 // dynamic texture (treat texnum == 0 differently)
65 #define GLTEXF_DYNAMIC 0x00080000
67 typedef struct textypeinfo_s
71 int inputbytesperpixel;
72 int internalbytesperpixel;
73 float glinternalbytesperpixel;
82 // we use these internally even if we never deliver such data to the driver
84 #define GL_BGRA 0x80E1
86 // framebuffer texture formats
87 // GLES2 devices rarely support depth textures, so we actually use a renderbuffer there
88 static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
89 static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
90 static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
91 static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
92 static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
93 static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
94 static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
95 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 2, 2, 2.0f, GL_RGB565 , GL_RGBA , GL_UNSIGNED_SHORT_5_6_5};
96 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 2, 2, 2.0f, GL_RGBA16F , GL_RGBA , GL_HALF_FLOAT};
97 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 2, 2, 2.0f, GL_RGBA32F , GL_RGBA , GL_FLOAT};
100 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
101 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
102 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
103 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
104 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
105 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
106 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
108 static textypeinfo_t textype_etc1 = {"etc1", TEXTYPE_ETC1 , 1, 3, 0.5f, GL_ETC1_RGB8_OES , 0 , 0 };
111 // framebuffer texture formats
112 static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
113 static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
114 static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24 , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
115 static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 4, 4, 4.0f, GL_DEPTH_COMPONENT24 , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
116 static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
117 static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 4, 4, 4.0f, GL_DEPTH_COMPONENT24 , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
118 static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 4, 4, 4.0f, GL_DEPTH24_STENCIL8 , GL_DEPTH_STENCIL , GL_UNSIGNED_INT_24_8};
119 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
120 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 8, 8, 8.0f, GL_RGBA16F , GL_RGBA , GL_HALF_FLOAT };
121 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 16, 16, 16.0f, GL_RGBA32F , GL_RGBA , GL_FLOAT };
124 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
125 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
126 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
127 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE };
128 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
129 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 };
130 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 };
131 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
132 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
133 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 };
134 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 };
135 static textypeinfo_t textype_dxt1 = {"dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
136 static textypeinfo_t textype_dxt1a = {"dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 };
137 static textypeinfo_t textype_dxt3 = {"dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 };
138 static textypeinfo_t textype_dxt5 = {"dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 };
139 static textypeinfo_t textype_sRGB_palette = {"sRGB_palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB , GL_BGRA , GL_UNSIGNED_BYTE };
140 static textypeinfo_t textype_sRGB_palette_alpha = {"sRGB_palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_ALPHA , GL_BGRA , GL_UNSIGNED_BYTE };
141 static textypeinfo_t textype_sRGB_rgba = {"sRGB_rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB , GL_RGBA , GL_UNSIGNED_BYTE };
142 static textypeinfo_t textype_sRGB_rgba_alpha = {"sRGB_rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_ALPHA , GL_RGBA , GL_UNSIGNED_BYTE };
143 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 };
144 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 };
145 static textypeinfo_t textype_sRGB_bgra = {"sRGB_bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB , GL_BGRA , GL_UNSIGNED_BYTE };
146 static textypeinfo_t textype_sRGB_bgra_alpha = {"sRGB_bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_ALPHA , GL_BGRA , GL_UNSIGNED_BYTE };
147 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 };
148 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 };
149 static textypeinfo_t textype_sRGB_dxt1 = {"sRGB_dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , 0 , 0 };
150 static textypeinfo_t textype_sRGB_dxt1a = {"sRGB_dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 , 0 };
151 static textypeinfo_t textype_sRGB_dxt3 = {"sRGB_dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 , 0 };
152 static textypeinfo_t textype_sRGB_dxt5 = {"sRGB_dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 , 0 };
155 typedef enum gltexturetype_e
159 GLTEXTURETYPE_CUBEMAP,
164 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP};
165 #ifdef GL_TEXTURE_WRAP_R
166 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
168 static int cubemapside[6] =
170 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
171 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
172 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
173 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
174 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
175 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
178 typedef struct gltexture_s
180 // this portion of the struct is exposed to the R_GetTexture macro for
181 // speed reasons, must be identical in rtexture_t!
182 int texnum; // GL texture slot number
183 int renderbuffernum; // GL renderbuffer slot number
184 qbool dirty; // indicates that R_RealGetTexture should be called
185 qbool glisdepthstencil; // indicates that FBO attachment has to be GL_DEPTH_STENCIL_ATTACHMENT
186 int gltexturetypeenum; // used by R_Mesh_TexBind
188 // dynamic texture stuff [11/22/2007 Black]
189 updatecallback_t updatecallback;
190 void *updatecallback_data;
191 // --- [11/22/2007 Black]
193 // stores backup copy of texture for deferred texture updates (R_UpdateTexture when combine = true)
194 unsigned char *bufferpixels;
195 int modified_mins[3], modified_maxs[3];
196 qbool buffermodified;
198 // pointer to texturepool (check this to see if the texture is allocated)
199 struct gltexturepool_s *pool;
200 // pointer to next texture in texturepool chain
201 struct gltexture_s *chain;
202 // name of the texture (this might be removed someday), no duplicates
203 char identifier[MAX_QPATH + 32];
204 // original data size in *inputtexels
205 int inputwidth, inputheight, inputdepth;
206 // copy of the original texture(s) supplied to the upload function, for
207 // delayed uploads (non-precached)
208 unsigned char *inputtexels;
209 // original data size in *inputtexels
211 // flags supplied to the LoadTexture function
212 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
216 // pointer to one of the textype_ structs
217 textypeinfo_t *textype;
218 // one of the GLTEXTURETYPE_ values
220 // palette if the texture is TEXTYPE_PALETTE
221 const unsigned int *palette;
222 // actual stored texture size after gl_picmip and gl_max_size are applied
223 int tilewidth, tileheight, tiledepth;
224 // 1 or 6 depending on texturetype
226 // how many mipmap levels in this texture
230 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
233 int glinternalformat;
234 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
239 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
241 typedef struct gltexturepool_s
243 unsigned int sentinel;
244 struct gltexture_s *gltchain;
245 struct gltexturepool_s *next;
249 static gltexturepool_t *gltexturepoolchain = NULL;
251 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
252 static int resizebuffersize = 0;
253 static const unsigned char *texturebuffer;
255 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
260 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
261 case TEXTYPE_RGBA: return ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba);
262 case TEXTYPE_BGRA: return ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra);
264 case TEXTYPE_ETC1: return &textype_etc1;
266 case TEXTYPE_ALPHA: return &textype_alpha;
267 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
268 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
269 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
270 case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
271 case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
272 case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
273 case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
274 case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
275 case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
276 case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
278 case TEXTYPE_DXT1: return &textype_dxt1;
279 case TEXTYPE_DXT1A: return &textype_dxt1a;
280 case TEXTYPE_DXT3: return &textype_dxt3;
281 case TEXTYPE_DXT5: return &textype_dxt5;
282 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
283 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);
284 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);
285 case TEXTYPE_ALPHA: return &textype_alpha;
286 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
287 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
288 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
289 case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
290 case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
291 case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
292 case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
293 case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
294 case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
295 case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
296 case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1;
297 case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a;
298 case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
299 case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
300 case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
301 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);
302 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);
305 Host_Error("R_GetTexTypeInfo: unknown texture format %i with flags %x", (int)textype, flags);
311 // dynamic texture code [11/22/2007 Black]
312 void R_MarkDirtyTexture(rtexture_t *rt) {
313 gltexture_t *glt = (gltexture_t*) rt;
318 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
319 if (glt->flags & GLTEXF_DYNAMIC)
321 // mark it as dirty, so R_RealGetTexture gets called
326 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
327 gltexture_t *glt = (gltexture_t*) rt;
332 glt->flags |= GLTEXF_DYNAMIC;
333 glt->updatecallback = updatecallback;
334 glt->updatecallback_data = data;
337 static void R_UpdateDynamicTexture(gltexture_t *glt) {
339 if( glt->updatecallback ) {
340 glt->updatecallback( (rtexture_t*) glt, glt->updatecallback_data );
344 void R_PurgeTexture(rtexture_t *rt)
346 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
351 void R_FreeTexture(rtexture_t *rt)
353 gltexture_t *glt, **gltpointer;
355 glt = (gltexture_t *)rt;
357 Host_Error("R_FreeTexture: texture == NULL");
359 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
360 if (*gltpointer == glt)
361 *gltpointer = glt->chain;
363 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
365 R_Mesh_ClearBindingsForTexture(glt->texnum);
367 switch(vid.renderpath)
369 case RENDERPATH_GL32:
370 case RENDERPATH_GLES2:
374 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
376 if (glt->renderbuffernum)
379 qglDeleteRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
384 if (glt->inputtexels)
385 Mem_Free(glt->inputtexels);
386 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
389 rtexturepool_t *R_AllocTexturePool(void)
391 gltexturepool_t *pool;
392 if (texturemempool == NULL)
394 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
397 pool->next = gltexturepoolchain;
398 gltexturepoolchain = pool;
399 pool->sentinel = TEXTUREPOOL_SENTINEL;
400 return (rtexturepool_t *)pool;
403 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
405 gltexturepool_t *pool, **poolpointer;
406 if (rtexturepool == NULL)
408 if (*rtexturepool == NULL)
410 pool = (gltexturepool_t *)(*rtexturepool);
411 *rtexturepool = NULL;
412 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
413 Host_Error("R_FreeTexturePool: pool already freed");
414 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
415 if (*poolpointer == pool)
416 *poolpointer = pool->next;
418 Host_Error("R_FreeTexturePool: pool not linked");
419 while (pool->gltchain)
420 R_FreeTexture((rtexture_t *)pool->gltchain);
425 typedef struct glmode_s
428 int minification, magnification;
432 static glmode_t modes[6] =
434 {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
435 {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
436 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
437 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
438 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
439 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
442 static void GL_TextureMode_f(cmd_state_t *cmd)
447 gltexturepool_t *pool;
449 if (Cmd_Argc(cmd) == 1)
451 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
452 for (i = 0;i < 6;i++)
454 if (gl_filter_min == modes[i].minification)
456 Con_Printf("%s\n", modes[i].name);
460 Con_Print("current filter is unknown???\n");
464 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
465 if (!strcasecmp (modes[i].name, Cmd_Argv(cmd, 1) ) )
469 Con_Print("bad filter name\n");
473 gl_filter_min = modes[i].minification;
474 gl_filter_mag = modes[i].magnification;
475 gl_filter_force = ((Cmd_Argc(cmd) > 2) && !strcasecmp(Cmd_Argv(cmd, 2), "force"));
477 switch(vid.renderpath)
479 case RENDERPATH_GL32:
480 case RENDERPATH_GLES2:
481 // change all the existing mipmap texture objects
482 // FIXME: force renderer(/client/something?) restart instead?
485 for (pool = gltexturepoolchain;pool;pool = pool->next)
487 for (glt = pool->gltchain;glt;glt = glt->chain)
489 // only update already uploaded images
490 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
492 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
493 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
494 if (glt->flags & TEXF_MIPMAP)
496 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
500 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
502 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
503 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
511 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)
513 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
518 case GLTEXTURETYPE_2D:
519 maxsize = vid.maxtexturesize_2d;
520 if (flags & TEXF_PICMIP)
522 maxsize = bound(1, gl_max_size.integer, maxsize);
526 case GLTEXTURETYPE_3D:
527 maxsize = vid.maxtexturesize_3d;
529 case GLTEXTURETYPE_CUBEMAP:
530 maxsize = vid.maxtexturesize_cubemap;
534 width2 = min(inwidth >> picmip, maxsize);
535 height2 = min(inheight >> picmip, maxsize);
536 depth2 = min(indepth >> picmip, maxsize);
539 if (flags & TEXF_MIPMAP)
541 int extent = max(width2, max(height2, depth2));
547 *outwidth = max(1, width2);
549 *outheight = max(1, height2);
551 *outdepth = max(1, depth2);
553 *outmiplevels = miplevels;
557 static int R_CalcTexelDataSize (gltexture_t *glt)
559 int width2, height2, depth2, size;
561 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
563 size = width2 * height2 * depth2;
565 if (glt->flags & TEXF_MIPMAP)
567 while (width2 > 1 || height2 > 1 || depth2 > 1)
575 size += width2 * height2 * depth2;
579 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
582 void R_TextureStats_Print(qbool printeach, qbool printpool, qbool printtotal)
586 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
587 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
589 gltexturepool_t *pool;
591 Con_Print("glsize input loaded mip alpha name\n");
592 for (pool = gltexturepoolchain;pool;pool = pool->next)
600 for (glt = pool->gltchain;glt;glt = glt->chain)
602 glsize = R_CalcTexelDataSize(glt);
603 isloaded = glt->texnum != 0 || glt->renderbuffernum != 0;
605 pooltotalt += glsize;
606 pooltotalp += glt->inputdatasize;
610 poolloadedt += glsize;
611 poolloadedp += glt->inputdatasize;
614 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);
617 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);
618 sumtotal += pooltotal;
619 sumtotalt += pooltotalt;
620 sumtotalp += pooltotalp;
621 sumloaded += poolloaded;
622 sumloadedt += poolloadedt;
623 sumloadedp += poolloadedp;
626 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);
629 static void R_TextureStats_f(cmd_state_t *cmd)
631 R_TextureStats_Print(true, true, true);
634 static void r_textures_start(void)
636 switch(vid.renderpath)
638 case RENDERPATH_GL32:
639 case RENDERPATH_GLES2:
640 // LadyHavoc: allow any alignment
642 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
643 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
647 texturemempool = Mem_AllocPool("texture management", 0, NULL);
648 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
650 // Disable JPEG screenshots if the DLL isn't loaded
651 if (! JPEG_OpenLibrary ())
652 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
653 if (! PNG_OpenLibrary ())
654 Cvar_SetValueQuick (&scr_screenshot_png, 0);
657 static void r_textures_shutdown(void)
659 rtexturepool_t *temp;
661 JPEG_CloseLibrary ();
663 while(gltexturepoolchain)
665 temp = (rtexturepool_t *) gltexturepoolchain;
666 R_FreeTexturePool(&temp);
669 resizebuffersize = 0;
671 colorconvertbuffer = NULL;
672 texturebuffer = NULL;
673 Mem_ExpandableArray_FreeArray(&texturearray);
674 Mem_FreePool(&texturemempool);
677 static void r_textures_newmap(void)
681 static void r_textures_devicelost(void)
685 endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
686 for (i = 0;i < endindex;i++)
688 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
689 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
691 switch(vid.renderpath)
693 case RENDERPATH_GL32:
694 case RENDERPATH_GLES2:
700 static void r_textures_devicerestored(void)
704 endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
705 for (i = 0;i < endindex;i++)
707 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
708 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
710 switch(vid.renderpath)
712 case RENDERPATH_GL32:
713 case RENDERPATH_GLES2:
720 void R_Textures_Init (void)
722 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");
723 Cmd_AddCommand(CF_CLIENT, "r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
724 Cvar_RegisterVariable (&gl_max_size);
725 Cvar_RegisterVariable (&gl_picmip);
726 Cvar_RegisterVariable (&gl_picmip_world);
727 Cvar_RegisterVariable (&r_picmipworld);
728 Cvar_RegisterVariable (&gl_picmip_sprites);
729 Cvar_RegisterVariable (&r_picmipsprites);
730 Cvar_RegisterVariable (&gl_picmip_other);
731 Cvar_RegisterVariable (&gl_max_lightmapsize);
732 Cvar_RegisterVariable (&r_lerpimages);
733 Cvar_RegisterVariable (&gl_texture_anisotropy);
734 Cvar_RegisterVariable (&gl_texturecompression);
735 Cvar_RegisterVariable (&gl_texturecompression_color);
736 Cvar_RegisterVariable (&gl_texturecompression_normal);
737 Cvar_RegisterVariable (&gl_texturecompression_gloss);
738 Cvar_RegisterVariable (&gl_texturecompression_glow);
739 Cvar_RegisterVariable (&gl_texturecompression_2d);
740 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
741 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
742 Cvar_RegisterVariable (&gl_texturecompression_sky);
743 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
744 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
745 Cvar_RegisterVariable (&gl_texturecompression_sprites);
746 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
747 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
748 Cvar_RegisterVariable (&r_texture_dds_swdecode);
750 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
753 void R_Textures_Frame (void)
755 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
756 static int old_aniso = 0;
757 static qbool first_time_aniso = true;
760 // could do procedural texture animation here, if we keep track of which
761 // textures were accessed this frame...
763 // free the resize buffers
764 resizebuffersize = 0;
767 Mem_Free(resizebuffer);
770 if (colorconvertbuffer)
772 Mem_Free(colorconvertbuffer);
773 colorconvertbuffer = NULL;
776 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
777 if (old_aniso != gl_texture_anisotropy.integer)
780 gltexturepool_t *pool;
783 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
785 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
787 switch(vid.renderpath)
789 case RENDERPATH_GL32:
790 case RENDERPATH_GLES2:
791 // ignore the first difference, any textures loaded by now probably had the same aniso value
792 if (first_time_aniso)
794 first_time_aniso = false;
799 for (pool = gltexturepoolchain;pool;pool = pool->next)
801 for (glt = pool->gltchain;glt;glt = glt->chain)
803 // only update already uploaded images
804 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
806 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
808 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
809 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
811 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
821 static void R_MakeResizeBufferBigger(int size)
823 if (resizebuffersize < size)
825 resizebuffersize = size;
827 Mem_Free(resizebuffer);
828 if (colorconvertbuffer)
829 Mem_Free(colorconvertbuffer);
830 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
831 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
832 if (!resizebuffer || !colorconvertbuffer)
833 Host_Error("R_Upload: out of memory");
837 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
839 int textureenum = gltexturetypeenums[texturetype];
840 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
844 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
845 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
847 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
848 if (gl_texture_anisotropy.integer != aniso)
849 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
850 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
853 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
854 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
855 #ifdef GL_TEXTURE_WRAP_R
856 if (gltexturetypedimensions[texturetype] >= 3)
858 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
863 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
865 if (flags & TEXF_MIPMAP)
867 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
871 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
873 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
875 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
877 if (flags & TEXF_MIPMAP)
879 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
881 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
885 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
890 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
892 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
896 if (flags & TEXF_MIPMAP)
898 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
902 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
904 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
910 case TEXTYPE_SHADOWMAP16_COMP:
911 case TEXTYPE_SHADOWMAP24_COMP:
912 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);CHECKGLERROR
913 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);CHECKGLERROR
915 case TEXTYPE_SHADOWMAP16_RAW:
916 case TEXTYPE_SHADOWMAP24_RAW:
917 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE, GL_NONE);CHECKGLERROR
918 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);CHECKGLERROR
928 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
931 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
933 if (glt->texturetype != GLTEXTURETYPE_2D)
934 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
936 if (glt->textype->textype == TEXTYPE_PALETTE)
937 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
939 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
940 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
942 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
943 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
945 // update a portion of the image
947 switch(vid.renderpath)
949 case RENDERPATH_GL32:
950 case RENDERPATH_GLES2:
954 // we need to restore the texture binding after finishing the upload
956 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
957 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
958 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
959 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
965 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
967 int i, mip = 0, width, height, depth;
968 GLint oldbindtexnum = 0;
969 const unsigned char *prevbuffer;
972 // error out if a stretch is needed on special texture types
973 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
974 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
976 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
977 // of the target size and then use the mipmap reduction function to get
978 // high quality supersampled results
979 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
980 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
981 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
983 if (prevbuffer == NULL)
985 width = glt->tilewidth;
986 height = glt->tileheight;
987 depth = glt->tiledepth;
988 // R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
989 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
990 // prevbuffer = resizebuffer;
994 if (glt->textype->textype == TEXTYPE_PALETTE)
996 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
997 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
998 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
999 prevbuffer = colorconvertbuffer;
1001 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1003 // multiply RGB channels by A channel before uploading
1005 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1006 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1008 alpha = prevbuffer[i+3];
1009 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1010 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1011 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1012 colorconvertbuffer[i+3] = alpha;
1014 prevbuffer = colorconvertbuffer;
1016 // scale up to a power of 2 size (if appropriate)
1017 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1019 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1020 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1021 prevbuffer = resizebuffer;
1023 // apply mipmap reduction algorithm to get down to picmip/max_size
1024 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1026 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1027 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1028 prevbuffer = resizebuffer;
1032 // do the appropriate upload type...
1033 switch(vid.renderpath)
1035 case RENDERPATH_GL32:
1036 case RENDERPATH_GLES2:
1037 if (glt->texnum) // not renderbuffers
1041 // we need to restore the texture binding after finishing the upload
1042 GL_ActiveTexture(0);
1043 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1044 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1047 if (gl_texturecompression.integer >= 2)
1048 qglHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
1050 qglHint(GL_TEXTURE_COMPRESSION_HINT, GL_FASTEST);
1053 switch(glt->texturetype)
1055 case GLTEXTURETYPE_2D:
1056 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1057 if (glt->flags & TEXF_MIPMAP)
1059 while (width > 1 || height > 1 || depth > 1)
1061 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1062 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1063 prevbuffer = resizebuffer;
1064 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1068 case GLTEXTURETYPE_3D:
1070 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1071 if (glt->flags & TEXF_MIPMAP)
1073 while (width > 1 || height > 1 || depth > 1)
1075 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1076 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1077 prevbuffer = resizebuffer;
1078 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1083 case GLTEXTURETYPE_CUBEMAP:
1084 // convert and upload each side in turn,
1085 // from a continuous block of input texels
1086 texturebuffer = (unsigned char *)prevbuffer;
1087 for (i = 0;i < 6;i++)
1089 prevbuffer = texturebuffer;
1090 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1091 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1093 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1094 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1095 prevbuffer = resizebuffer;
1098 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1100 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1101 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1102 prevbuffer = resizebuffer;
1105 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1106 if (glt->flags & TEXF_MIPMAP)
1108 while (width > 1 || height > 1 || depth > 1)
1110 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1111 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1112 prevbuffer = resizebuffer;
1113 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1119 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1120 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1126 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)
1130 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1131 textypeinfo_t *texinfo, *texinfo2;
1132 unsigned char *temppixels = NULL;
1135 if (cls.state == ca_dedicated)
1138 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1139 if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1141 int numpixels = width * height * depth * sides;
1142 size = numpixels * 4;
1143 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1146 const unsigned char *p;
1147 unsigned char *o = temppixels;
1148 for (i = 0;i < numpixels;i++, o += 4)
1150 p = (const unsigned char *)palette + 4*data[i];
1158 textype = TEXTYPE_RGBA;
1163 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1164 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1165 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1166 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1172 static int rgbaswapindices[4] = {2, 1, 0, 3};
1173 size = width * height * depth * sides * 4;
1174 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1176 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1180 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1181 if (!vid.support.ext_texture_srgb)
1183 qbool convertsRGB = false;
1186 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1187 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1188 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1189 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1190 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;/*convertsRGB = true;*/break;
1191 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1192 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1196 if (convertsRGB && data)
1198 size = width * height * depth * sides * 4;
1201 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1202 memcpy(temppixels, data, size);
1205 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1209 texinfo = R_GetTexTypeInfo(textype, flags);
1210 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1213 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1217 // clear the alpha flag if the texture has no transparent pixels
1220 case TEXTYPE_PALETTE:
1221 case TEXTYPE_SRGB_PALETTE:
1222 if (flags & TEXF_ALPHA)
1224 flags &= ~TEXF_ALPHA;
1227 for (i = 0;i < size;i++)
1229 if (((unsigned char *)&palette[data[i]])[3] < 255)
1231 flags |= TEXF_ALPHA;
1240 case TEXTYPE_SRGB_RGBA:
1241 case TEXTYPE_SRGB_BGRA:
1242 if (flags & TEXF_ALPHA)
1244 flags &= ~TEXF_ALPHA;
1247 for (i = 3;i < size;i += 4)
1251 flags |= TEXF_ALPHA;
1258 case TEXTYPE_SHADOWMAP16_COMP:
1259 case TEXTYPE_SHADOWMAP16_RAW:
1260 case TEXTYPE_SHADOWMAP24_COMP:
1261 case TEXTYPE_SHADOWMAP24_RAW:
1264 case TEXTYPE_SRGB_DXT1:
1267 case TEXTYPE_SRGB_DXT1A:
1269 case TEXTYPE_SRGB_DXT3:
1271 case TEXTYPE_SRGB_DXT5:
1272 flags |= TEXF_ALPHA;
1275 flags |= TEXF_ALPHA;
1277 case TEXTYPE_COLORBUFFER:
1278 case TEXTYPE_COLORBUFFER16F:
1279 case TEXTYPE_COLORBUFFER32F:
1280 flags |= TEXF_ALPHA;
1283 Sys_Error("R_LoadTexture: unknown texture type");
1286 texinfo2 = R_GetTexTypeInfo(textype, flags);
1287 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1290 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1292 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1294 dp_strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1296 glt->chain = pool->gltchain;
1297 pool->gltchain = glt;
1298 glt->inputwidth = width;
1299 glt->inputheight = height;
1300 glt->inputdepth = depth;
1302 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
1303 glt->textype = texinfo;
1304 glt->texturetype = texturetype;
1305 glt->inputdatasize = size;
1306 glt->palette = palette;
1307 glt->glinternalformat = texinfo->glinternalformat;
1308 glt->glformat = texinfo->glformat;
1309 glt->gltype = texinfo->gltype;
1310 glt->bytesperpixel = texinfo->internalbytesperpixel;
1311 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1314 glt->glisdepthstencil = false;
1315 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1316 // init the dynamic texture attributes, too [11/22/2007 Black]
1317 glt->updatecallback = NULL;
1318 glt->updatecallback_data = NULL;
1320 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1322 // upload the texture
1323 // data may be NULL (blank texture for dynamic rendering)
1324 switch(vid.renderpath)
1326 case RENDERPATH_GL32:
1327 case RENDERPATH_GLES2:
1329 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1333 R_UploadFullTexture(glt, data);
1334 if (glt->flags & TEXF_ALLOWUPDATES)
1335 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1337 glt->buffermodified = false;
1338 VectorClear(glt->modified_mins);
1339 VectorClear(glt->modified_maxs);
1341 // free any temporary processing buffer we allocated...
1343 Mem_Free(temppixels);
1345 // texture converting and uploading can take a while, so make sure we're sending keepalives
1346 // FIXME: this causes rendering during R_Shadow_DrawLights
1347 // CL_KeepaliveMessage(false);
1349 return (rtexture_t *)glt;
1352 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)
1354 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1357 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)
1359 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1362 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)
1364 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1367 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qbool filter)
1369 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL);
1372 rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
1375 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1376 textypeinfo_t *texinfo;
1378 if (cls.state == ca_dedicated)
1381 texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP);
1383 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1385 dp_strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1387 glt->chain = pool->gltchain;
1388 pool->gltchain = glt;
1389 glt->inputwidth = width;
1390 glt->inputheight = height;
1391 glt->inputdepth = 1;
1392 glt->flags = TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_FORCENEAREST;
1394 glt->textype = texinfo;
1395 glt->texturetype = textype;
1396 glt->inputdatasize = width*height*texinfo->internalbytesperpixel;
1397 glt->palette = NULL;
1398 glt->glinternalformat = texinfo->glinternalformat;
1399 glt->glformat = texinfo->glformat;
1400 glt->gltype = texinfo->gltype;
1401 glt->bytesperpixel = texinfo->internalbytesperpixel;
1402 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1405 glt->glisdepthstencil = textype == TEXTYPE_DEPTHBUFFER24STENCIL8;
1406 glt->gltexturetypeenum = GL_TEXTURE_2D;
1407 // init the dynamic texture attributes, too [11/22/2007 Black]
1408 glt->updatecallback = NULL;
1409 glt->updatecallback_data = NULL;
1411 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1413 // upload the texture
1414 // data may be NULL (blank texture for dynamic rendering)
1415 switch(vid.renderpath)
1417 case RENDERPATH_GL32:
1418 case RENDERPATH_GLES2:
1420 qglGenRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
1421 qglBindRenderbuffer(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR
1422 qglRenderbufferStorage(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR
1423 // 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
1424 qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR
1428 return (rtexture_t *)glt;
1431 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qbool skipuncompressed, qbool hasalpha)
1434 return -1; // unsupported on this platform
1436 gltexture_t *glt = (gltexture_t *)rt;
1439 int bytesperpixel = 0;
1440 int bytesperblock = 0;
1442 int dds_format_flags;
1450 GLint internalformat;
1451 const char *ddsfourcc;
1453 return -1; // NULL pointer
1454 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1455 return -2; // broken driver - crashes on reading internal format
1456 if (!qglGetTexLevelParameteriv)
1458 GL_ActiveTexture(0);
1459 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1460 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1461 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1462 switch(internalformat)
1464 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1465 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1466 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1467 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1468 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1470 // if premultiplied alpha, say so in the DDS file
1471 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1473 switch(internalformat)
1475 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1476 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1479 if (!bytesperblock && skipuncompressed)
1480 return -3; // skipped
1481 memset(mipinfo, 0, sizeof(mipinfo));
1482 mipinfo[0][0] = glt->tilewidth;
1483 mipinfo[0][1] = glt->tileheight;
1485 if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1))
1487 for (mip = 1;mip < 16;mip++)
1489 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1490 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1491 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1499 for (mip = 0;mip < mipmaps;mip++)
1501 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1502 mipinfo[mip][3] = ddssize;
1503 ddssize += mipinfo[mip][2];
1505 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1508 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1512 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1513 dds_format_flags = 0x4; // DDPF_FOURCC
1517 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1518 dds_format_flags = 0x40; // DDPF_RGB
1522 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1523 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1526 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1527 memcpy(dds, "DDS ", 4);
1528 StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
1529 StoreLittleLong(dds+8, dds_flags);
1530 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1531 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1532 StoreLittleLong(dds+24, 0); // depth
1533 StoreLittleLong(dds+28, mipmaps); // mipmaps
1534 StoreLittleLong(dds+76, 32); // format size
1535 StoreLittleLong(dds+80, dds_format_flags);
1536 StoreLittleLong(dds+108, dds_caps1);
1537 StoreLittleLong(dds+112, dds_caps2);
1540 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1541 memcpy(dds+84, ddsfourcc, 4);
1542 for (mip = 0;mip < mipmaps;mip++)
1544 qglGetCompressedTexImage(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1549 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1550 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1551 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1552 for (mip = 0;mip < mipmaps;mip++)
1554 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1557 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1558 ret = FS_WriteFile(filename, dds, ddssize);
1560 return ret ? ddssize : -5;
1565 // ELUAN: FIXME: separate this code
1566 #include "ktx10/include/ktx.h"
1569 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
1571 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1574 int bytesperblock, bytesperpixel;
1577 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1578 textypeinfo_t *texinfo;
1579 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1580 unsigned int c, r, g, b;
1581 GLint oldbindtexnum = 0;
1582 unsigned char *mippixels;
1583 unsigned char *mippixels_start;
1584 unsigned char *ddspixels;
1586 fs_offset_t ddsfilesize;
1587 unsigned int ddssize;
1588 qbool force_swdecode;
1590 // ELUAN: FIXME: separate this code
1594 KTX_dimensions sizes;
1597 if (cls.state == ca_dedicated)
1601 // ELUAN: FIXME: separate this code
1602 if (vid.renderpath != RENDERPATH_GLES2)
1604 Con_DPrintf("KTX texture format is only supported on the GLES2 renderpath\n");
1608 // some textures are specified with extensions, so it becomes .tga.dds
1609 FS_StripExtension (filename, vabuf2, sizeof(vabuf2));
1610 FS_StripExtension (vabuf2, vabuf, sizeof(vabuf));
1611 FS_DefaultExtension (vabuf, ".ktx", sizeof(vabuf));
1612 strsize = strlen(vabuf);
1614 for (i = 0; i <= strsize - 4; i++) // copy null termination
1615 vabuf[i] = vabuf[i + 4];
1617 Con_DPrintf("Loading %s...\n", vabuf);
1618 dds = FS_LoadFile(vabuf, tempmempool, true, &ddsfilesize);
1619 ddssize = ddsfilesize;
1623 Con_DPrintf("Not found!\n");
1624 return NULL; // not found
1626 Con_DPrintf("Found!\n");
1628 if (flags & TEXF_ALPHA)
1630 Con_DPrintf("KTX texture with alpha not supported yet, disabling\n");
1631 flags &= ~TEXF_ALPHA;
1637 GLboolean isMipmapped;
1638 KTX_error_code ktxerror;
1640 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1642 // texture uploading can take a while, so make sure we're sending keepalives
1643 CL_KeepaliveMessage(false);
1645 // create the texture object
1647 GL_ActiveTexture(0);
1648 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[GLTEXTURETYPE_2D]);
1649 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1650 qglBindTexture(gltexturetypeenums[GLTEXTURETYPE_2D], glt->texnum);CHECKGLERROR
1652 // upload the texture
1653 // we need to restore the texture binding after finishing the upload
1655 // NOTE: some drivers fail with ETC1 NPOT (only PowerVR?). This may make the driver crash later.
1656 ktxerror = ktxLoadTextureM(dds, ddssize, &glt->texnum, &target, &sizes, &isMipmapped, &glerror,
1657 0, NULL);// can't CHECKGLERROR, the lib catches it
1659 // FIXME: delete texture if we fail here
1660 if (target != GL_TEXTURE_2D)
1662 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1664 Con_DPrintf("%s target != GL_TEXTURE_2D, target == %x\n", vabuf, target);
1665 return NULL; // FIXME: delete the texture from memory
1668 if (KTX_SUCCESS == ktxerror)
1670 textype = TEXTYPE_ETC1;
1671 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
1673 // return whether this texture is transparent
1675 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1677 // TODO: apply gl_picmip
1680 // TODO: only load mipmaps if requested
1683 flags |= TEXF_MIPMAP;
1685 flags &= ~TEXF_MIPMAP;
1687 texinfo = R_GetTexTypeInfo(textype, flags);
1689 dp_strlcpy(glt->identifier, vabuf, sizeof(glt->identifier));
1691 glt->chain = pool->gltchain;
1692 pool->gltchain = glt;
1693 glt->inputwidth = sizes.width;
1694 glt->inputheight = sizes.height;
1695 glt->inputdepth = 1;
1697 glt->textype = texinfo;
1698 glt->texturetype = GLTEXTURETYPE_2D;
1699 glt->inputdatasize = ddssize;
1700 glt->glinternalformat = texinfo->glinternalformat;
1701 glt->glformat = texinfo->glformat;
1702 glt->gltype = texinfo->gltype;
1703 glt->bytesperpixel = texinfo->internalbytesperpixel;
1705 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1706 glt->tilewidth = sizes.width;
1707 glt->tileheight = sizes.height;
1709 glt->miplevels = isMipmapped ? 1 : 0; // FIXME
1711 // after upload we have to set some parameters...
1712 #ifdef GL_TEXTURE_MAX_LEVEL
1714 if (dds_miplevels >= 1 && !mipcomplete)
1716 // need to set GL_TEXTURE_MAX_LEVEL
1717 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
1721 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1723 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1725 return (rtexture_t *)glt;
1729 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1731 Con_DPrintf("KTX texture %s failed to load: %x\n", vabuf, ktxerror);
1735 #endif // __ANDROID__
1737 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1738 ddssize = ddsfilesize;
1742 if (r_texture_dds_load_logfailure.integer && (r_texture_dds_load_logfailure.integer >= 2 || !optionaltexture))
1743 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1744 return NULL; // not found
1747 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1750 Con_Printf("^1%s: not a DDS image\n", filename);
1754 //dds_flags = BuffLittleLong(dds+8);
1755 dds_format_flags = BuffLittleLong(dds+80);
1756 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1757 dds_width = BuffLittleLong(dds+16);
1758 dds_height = BuffLittleLong(dds+12);
1759 ddspixels = dds + 128;
1761 if(r_texture_dds_load_alphamode.integer == 0)
1762 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1763 flags &= ~TEXF_ALPHA;
1765 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1766 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1768 // very sloppy BGRA 32bit identification
1769 textype = TEXTYPE_BGRA;
1770 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
1773 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1774 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1777 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1780 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1783 for (i = 3;i < size;i += 4)
1784 if (ddspixels[i] < 255)
1787 flags &= ~TEXF_ALPHA;
1790 else if (!memcmp(dds+84, "DXT1", 4))
1792 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1793 // LadyHavoc: it is my belief that this does not infringe on the
1794 // patent because it is not decoding pixels...
1795 textype = TEXTYPE_DXT1;
1798 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1799 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1800 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1803 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1806 if (flags & TEXF_ALPHA)
1808 if (r_texture_dds_load_alphamode.integer == 1)
1811 for (i = 0;i < size;i += bytesperblock)
1812 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1814 // NOTE: this assumes sizeof(unsigned int) == 4
1815 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1816 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1817 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1821 textype = TEXTYPE_DXT1A;
1823 flags &= ~TEXF_ALPHA;
1825 else if (r_texture_dds_load_alphamode.integer == 0)
1826 textype = TEXTYPE_DXT1A;
1829 flags &= ~TEXF_ALPHA;
1833 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
1835 if(!memcmp(dds+84, "DXT2", 4))
1837 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1839 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
1844 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1846 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
1849 textype = TEXTYPE_DXT3;
1852 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1853 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1856 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1859 // we currently always assume alpha
1861 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
1863 if(!memcmp(dds+84, "DXT4", 4))
1865 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
1867 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
1872 if(flags & TEXF_RGBMULTIPLYBYALPHA)
1874 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
1877 textype = TEXTYPE_DXT5;
1880 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1881 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1884 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1887 // we currently always assume alpha
1892 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1896 // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
1897 if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
1899 textype = TEXTYPE_DXT1;
1903 for (i = 0;i < (int)ddssize;i += bytesperblock)
1904 memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
1908 force_swdecode = false;
1911 if(vid.support.ext_texture_compression_s3tc)
1913 if(r_texture_dds_swdecode.integer > 1)
1914 force_swdecode = true;
1918 if(r_texture_dds_swdecode.integer < 1)
1924 force_swdecode = true;
1928 // return whether this texture is transparent
1930 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1932 // if we SW decode, choose 2 sizes bigger
1935 // this is quarter res, so do not scale down more than we have to
1939 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
1942 // this is where we apply gl_picmip
1943 mippixels_start = ddspixels;
1944 mipwidth = dds_width;
1945 mipheight = dds_height;
1946 while(miplevel >= 1 && dds_miplevels >= 1)
1948 if (mipwidth <= 1 && mipheight <= 1)
1950 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1951 mippixels_start += mipsize; // just skip
1959 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
1960 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1962 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
1964 // fake decode S3TC if needed
1967 int mipsize_new = mipsize_total / bytesperblock * 4;
1968 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
1969 unsigned char *p = mipnewpixels;
1970 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
1972 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
1973 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
1974 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
1975 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
1976 if(textype == TEXTYPE_DXT5)
1977 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
1978 else if(textype == TEXTYPE_DXT3)
1980 (mippixels_start[i-8] & 0x0F)
1981 + (mippixels_start[i-8] >> 4)
1982 + (mippixels_start[i-7] & 0x0F)
1983 + (mippixels_start[i-7] >> 4)
1984 + (mippixels_start[i-6] & 0x0F)
1985 + (mippixels_start[i-6] >> 4)
1986 + (mippixels_start[i-5] & 0x0F)
1987 + (mippixels_start[i-5] >> 4)
1988 ) * (0.125f / 15.0f * 255.0f);
1993 textype = TEXTYPE_BGRA;
1997 // as each block becomes a pixel, we must use pixel count for this
1998 mipwidth = (mipwidth + 3) / 4;
1999 mipheight = (mipheight + 3) / 4;
2000 mipsize = bytesperpixel * mipwidth * mipheight;
2001 mippixels_start = mipnewpixels;
2002 mipsize_total = mipsize_new;
2005 // start mip counting
2006 mippixels = mippixels_start;
2008 // calculate average color if requested
2012 Vector4Clear(avgcolor);
2015 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2017 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2018 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2019 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2020 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2021 if(textype == TEXTYPE_DXT5)
2022 avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f);
2023 else if(textype == TEXTYPE_DXT3)
2025 (mippixels_start[i-8] & 0x0F)
2026 + (mippixels_start[i-8] >> 4)
2027 + (mippixels_start[i-7] & 0x0F)
2028 + (mippixels_start[i-7] >> 4)
2029 + (mippixels_start[i-6] & 0x0F)
2030 + (mippixels_start[i-6] >> 4)
2031 + (mippixels_start[i-5] & 0x0F)
2032 + (mippixels_start[i-5] >> 4)
2033 ) * (0.125f / 15.0f);
2035 avgcolor[3] += 1.0f;
2037 f = (float)bytesperblock / mipsize;
2038 avgcolor[0] *= (0.5f / 31.0f) * f;
2039 avgcolor[1] *= (0.5f / 63.0f) * f;
2040 avgcolor[2] *= (0.5f / 31.0f) * f;
2045 for (i = 0;i < mipsize;i += 4)
2047 avgcolor[0] += mippixels[i+2];
2048 avgcolor[1] += mippixels[i+1];
2049 avgcolor[2] += mippixels[i];
2050 avgcolor[3] += mippixels[i+3];
2052 f = (1.0f / 255.0f) * bytesperpixel / mipsize;
2060 // if we want sRGB, convert now
2063 if (vid.support.ext_texture_srgb)
2067 case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break;
2068 case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break;
2069 case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break;
2070 case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break;
2071 case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break;
2085 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2087 int c0, c1, c0new, c1new;
2088 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2089 r = ((c0 >> 11) & 0x1F);
2090 g = ((c0 >> 5) & 0x3F);
2092 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2093 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2094 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2095 c0new = (r << 11) | (g << 5) | b;
2096 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2097 r = ((c1 >> 11) & 0x1F);
2098 g = ((c1 >> 5) & 0x3F);
2100 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2101 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2102 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2103 c1new = (r << 11) | (g << 5) | b;
2104 // swap the colors if needed to fix order
2105 if(c0 > c1) // thirds
2113 mippixels_start[i+4] ^= 0x55;
2114 mippixels_start[i+5] ^= 0x55;
2115 mippixels_start[i+6] ^= 0x55;
2116 mippixels_start[i+7] ^= 0x55;
2118 else if(c0new == c1new)
2120 mippixels_start[i+4] = 0x00;
2121 mippixels_start[i+5] = 0x00;
2122 mippixels_start[i+6] = 0x00;
2123 mippixels_start[i+7] = 0x00;
2126 else // half + transparent
2133 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2134 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2135 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2136 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2139 mippixels_start[i] = c0new & 255;
2140 mippixels_start[i+1] = c0new >> 8;
2141 mippixels_start[i+2] = c1new & 255;
2142 mippixels_start[i+3] = c1new >> 8;
2147 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2155 // when not requesting mipmaps, do not load them
2156 if(!(flags & TEXF_MIPMAP))
2159 if (dds_miplevels >= 1)
2160 flags |= TEXF_MIPMAP;
2162 flags &= ~TEXF_MIPMAP;
2164 texinfo = R_GetTexTypeInfo(textype, flags);
2166 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2167 dp_strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2169 glt->chain = pool->gltchain;
2170 pool->gltchain = glt;
2171 glt->inputwidth = mipwidth;
2172 glt->inputheight = mipheight;
2173 glt->inputdepth = 1;
2175 glt->textype = texinfo;
2176 glt->texturetype = GLTEXTURETYPE_2D;
2177 glt->inputdatasize = ddssize;
2178 glt->glinternalformat = texinfo->glinternalformat;
2179 glt->glformat = texinfo->glformat;
2180 glt->gltype = texinfo->gltype;
2181 glt->bytesperpixel = texinfo->internalbytesperpixel;
2183 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2184 glt->tilewidth = mipwidth;
2185 glt->tileheight = mipheight;
2187 glt->miplevels = dds_miplevels;
2189 // texture uploading can take a while, so make sure we're sending keepalives
2190 CL_KeepaliveMessage(false);
2192 // create the texture object
2193 switch(vid.renderpath)
2195 case RENDERPATH_GL32:
2196 case RENDERPATH_GLES2:
2198 GL_ActiveTexture(0);
2199 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2200 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2201 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2205 // upload the texture
2206 // we need to restore the texture binding after finishing the upload
2207 mipcomplete = false;
2209 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2211 unsigned char *upload_mippixels = mippixels;
2212 int upload_mipwidth = mipwidth;
2213 int upload_mipheight = mipheight;
2214 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2215 if (mippixels + mipsize > mippixels_start + mipsize_total)
2217 switch(vid.renderpath)
2219 case RENDERPATH_GL32:
2220 case RENDERPATH_GLES2:
2223 qglCompressedTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR
2227 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR
2231 if(upload_mippixels != mippixels)
2232 Mem_Free(upload_mippixels);
2233 mippixels += mipsize;
2234 if (mipwidth <= 1 && mipheight <= 1)
2245 // after upload we have to set some parameters...
2246 switch(vid.renderpath)
2248 case RENDERPATH_GL32:
2249 case RENDERPATH_GLES2:
2250 #ifdef GL_TEXTURE_MAX_LEVEL
2251 if (dds_miplevels >= 1 && !mipcomplete)
2253 // need to set GL_TEXTURE_MAX_LEVEL
2254 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2257 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2258 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2264 Mem_Free((unsigned char *) mippixels_start);
2265 return (rtexture_t *)glt;
2268 int R_TextureWidth(rtexture_t *rt)
2270 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2273 int R_TextureHeight(rtexture_t *rt)
2275 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2278 int R_TextureFlags(rtexture_t *rt)
2280 return rt ? ((gltexture_t *)rt)->flags : 0;
2283 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth, int combine)
2285 gltexture_t *glt = (gltexture_t *)rt;
2287 Host_Error("R_UpdateTexture: no data supplied");
2289 Host_Error("R_UpdateTexture: no texture supplied");
2292 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2295 // update part of the texture
2296 if (glt->bufferpixels)
2298 size_t j, bpp = glt->bytesperpixel;
2300 // depth and sides are not fully implemented here - can still do full updates but not partial.
2301 if (glt->inputdepth != 1 || glt->sides != 1)
2302 Host_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2303 if (x < 0 || y < 0 || z < 0 || glt->tilewidth < x + width || glt->tileheight < y + height || glt->tiledepth < z + depth)
2304 Host_Error("R_UpdateTexture on buffered texture with out of bounds coordinates (%i %i %i to %i %i %i is not within 0 0 0 to %i %i %i)", x, y, z, x + width, y + height, z + depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
2306 for (j = 0; j < (size_t)height; j++)
2307 memcpy(glt->bufferpixels + ((y + j) * glt->tilewidth + x) * bpp, data + j * width * bpp, width * bpp);
2312 // immediately update the part of the texture, no combining
2313 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
2316 // keep track of the region that is modified, decide later how big the partial update area is
2317 if (glt->buffermodified)
2319 glt->modified_mins[0] = min(glt->modified_mins[0], x);
2320 glt->modified_mins[1] = min(glt->modified_mins[1], y);
2321 glt->modified_mins[2] = min(glt->modified_mins[2], z);
2322 glt->modified_maxs[0] = max(glt->modified_maxs[0], x + width);
2323 glt->modified_maxs[1] = max(glt->modified_maxs[1], y + height);
2324 glt->modified_maxs[2] = max(glt->modified_maxs[2], z + depth);
2328 glt->buffermodified = true;
2329 glt->modified_mins[0] = x;
2330 glt->modified_mins[1] = y;
2331 glt->modified_mins[2] = z;
2332 glt->modified_maxs[0] = x + width;
2333 glt->modified_maxs[1] = y + height;
2334 glt->modified_maxs[2] = z + depth;
2340 // mark the entire texture as dirty, it will be uploaded later
2341 glt->buffermodified = true;
2342 glt->modified_mins[0] = 0;
2343 glt->modified_mins[1] = 0;
2344 glt->modified_mins[2] = 0;
2345 glt->modified_maxs[0] = glt->tilewidth;
2346 glt->modified_maxs[1] = glt->tileheight;
2347 glt->modified_maxs[2] = glt->tiledepth;
2353 R_UploadFullTexture(glt, data);
2356 int R_RealGetTexture(rtexture_t *rt)
2361 glt = (gltexture_t *)rt;
2362 if (glt->flags & GLTEXF_DYNAMIC)
2363 R_UpdateDynamicTexture(glt);
2364 if (glt->buffermodified && glt->bufferpixels)
2366 glt->buffermodified = false;
2367 // Because we currently don't set the relevant upload stride parameters, just make it full width.
2368 glt->modified_mins[0] = 0;
2369 glt->modified_maxs[0] = glt->tilewidth;
2370 // Check also if it's updating at least half the height of the texture.
2371 if (glt->modified_maxs[1] - glt->modified_mins[1] > glt->tileheight / 2)
2372 R_UploadFullTexture(glt, glt->bufferpixels);
2374 R_UploadPartialTexture(glt, glt->bufferpixels + (size_t)glt->modified_mins[1] * glt->tilewidth * glt->bytesperpixel, glt->modified_mins[0], glt->modified_mins[1], glt->modified_mins[2], glt->modified_maxs[0] - glt->modified_mins[0], glt->modified_maxs[1] - glt->modified_mins[1], glt->modified_maxs[2] - glt->modified_mins[2]);
2376 VectorClear(glt->modified_mins);
2377 VectorClear(glt->modified_maxs);
2382 return r_texture_white->texnum;
2385 void R_ClearTexture (rtexture_t *rt)
2387 gltexture_t *glt = (gltexture_t *)rt;
2389 R_UploadFullTexture(glt, NULL);
2392 int R_PicmipForFlags(int flags)
2395 if(flags & TEXF_PICMIP)
2397 miplevel += gl_picmip.integer;
2398 if (flags & TEXF_ISWORLD)
2400 if (r_picmipworld.integer)
2401 miplevel += gl_picmip_world.integer;
2405 else if (flags & TEXF_ISSPRITE)
2407 if (r_picmipsprites.integer)
2408 miplevel += gl_picmip_sprites.integer;
2413 miplevel += gl_picmip_other.integer;
2415 return max(0, miplevel);