1
2 #include "quakedef.h"
3 #ifdef SUPPORTD3D
4 #include <d3d9.h>
5 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
6 #endif
7 #include "image.h"
8 #include "jpeg.h"
9 #include "image_png.h"
10 #include "intoverflow.h"
11 #include "dpsoftrast.h"
12
13 #ifndef GL_TEXTURE_3D
14 #define GL_TEXTURE_3D 0x806F
15 #endif
16
17 cvar_t gl_max_size = {CVAR_SAVE, "gl_max_size", "2048", "maximum allowed texture size, can be used to reduce video memory usage, limited by hardware capabilities (typically 2048, 4096, or 8192)"};
18 cvar_t gl_max_lightmapsize = {CVAR_SAVE, "gl_max_lightmapsize", "1024", "maximum allowed texture size for lightmap textures, use larger values to improve rendering speed, as long as there is enough video memory available (setting it too high for the hardware will cause very bad performance)"};
19 cvar_t gl_picmip = {CVAR_SAVE, "gl_picmip", "0", "reduces resolution of textures by powers of 2, for example 1 will halve width/height, reducing texture memory usage by 75%"};
20 cvar_t gl_picmip_world = {CVAR_SAVE, "gl_picmip_world", "0", "extra picmip level for world textures (may be negative, which will then reduce gl_picmip for these)"};
21 cvar_t r_picmipworld = {CVAR_SAVE, "r_picmipworld", "1", "whether gl_picmip shall apply to world textures too (setting this to 0 is a shorthand for gl_picmip_world -9999999)"};
22 cvar_t gl_picmip_sprites = {CVAR_SAVE, "gl_picmip_sprites", "0", "extra picmip level for sprite textures (may be negative, which will then reduce gl_picmip for these)"};
23 cvar_t r_picmipsprites = {CVAR_SAVE, "r_picmipsprites", "1", "make gl_picmip affect sprites too (saves some graphics memory in sprite heavy games) (setting this to 0 is a shorthand for gl_picmip_sprites -9999999)"};
24 cvar_t gl_picmip_other = {CVAR_SAVE, "gl_picmip_other", "0", "extra picmip level for other textures (may be negative, which will then reduce gl_picmip for these)"};
25 cvar_t r_lerpimages = {CVAR_SAVE, "r_lerpimages", "1", "bilinear filters images when scaling them up to power of 2 size (mode 1), looks better than glquake (mode 0)"};
26 cvar_t gl_texture_anisotropy = {CVAR_SAVE, "gl_texture_anisotropy", "1", "anisotropic filtering quality (if supported by hardware), 1 sample (no anisotropy) and 8 sample (8 tap anisotropy) are recommended values"};
27 cvar_t gl_texturecompression = {CVAR_SAVE, "gl_texturecompression", "0", "whether to compress textures, a value of 0 disables compression (even if the individual cvars are 1), 1 enables fast (low quality) compression at startup, 2 enables slow (high quality) compression at startup"};
28 cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
29 cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
30 cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
31 cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
32 cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
33 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
34 cvar_t gl_texturecompression_q3bspdeluxemaps = {CVAR_SAVE, "gl_texturecompression_q3bspdeluxemaps", "0", "whether to compress deluxemaps in q3bsp format levels (only levels compiled with q3map2 -deluxe have these)"};
35 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
36 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
37 cvar_t gl_texturecompression_reflectmask = {CVAR_SAVE, "gl_texturecompression_reflectmask", "1", "whether to compress reflection cubemap masks (mask of which areas of the texture should reflect the generic shiny cubemap)"};
38 cvar_t gl_texturecompression_sprites = {CVAR_SAVE, "gl_texturecompression_sprites", "1", "whether to compress sprites"};
39 cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "0", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"};
40 cvar_t r_texture_dds_load_alphamode = {0, "r_texture_dds_load_alphamode", "1", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambiguous, 2: texture format only"};
41 cvar_t r_texture_dds_load_logfailure = {0, "r_texture_dds_load_logfailure", "0", "log missing DDS textures to ddstexturefailures.log, 0: done log, 1: log with no optional textures (_norm, glow etc.). 2: log all"};
42 cvar_t r_texture_dds_swdecode = {0, "r_texture_dds_swdecode", "0", "0: don't software decode DDS, 1: software decode DDS if unsupported, 2: always software decode DDS"};
43
44 qboolean gl_filter_force = false;
45 int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
46 int gl_filter_mag = GL_LINEAR;
47 DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_mipmap = DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE;
48 DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_nomipmap = DPSOFTRAST_TEXTURE_FILTER_LINEAR;
49
50 #ifdef SUPPORTD3D
51 int d3d_filter_flatmin = D3DTEXF_LINEAR;
52 int d3d_filter_flatmag = D3DTEXF_LINEAR;
53 int d3d_filter_flatmix = D3DTEXF_POINT;
54 int d3d_filter_mipmin = D3DTEXF_LINEAR;
55 int d3d_filter_mipmag = D3DTEXF_LINEAR;
56 int d3d_filter_mipmix = D3DTEXF_LINEAR;
57 int d3d_filter_nomip = false;
58 #endif
59
60
61 static mempool_t *texturemempool;
62 static memexpandablearray_t texturearray;
63
64 // note: this must not conflict with TEXF_ flags in r_textures.h
65 // bitmask for mismatch checking
66 #define GLTEXF_IMPORTANTBITS (0)
67 // dynamic texture (treat texnum == 0 differently)
68 #define GLTEXF_DYNAMIC 0x00080000
69
70 typedef struct textypeinfo_s
71 {
72 const char *name;
73 textype_t textype;
74 int inputbytesperpixel;
75 int internalbytesperpixel;
76 float glinternalbytesperpixel;
77 int glinternalformat;
78 int glformat;
79 int gltype;
80 }
81 textypeinfo_t;
82
83 #ifdef USE_GLES2
84
85 // we use these internally even if we never deliver such data to the driver
86 #define GL_BGR 0x80E0
87 #define GL_BGRA 0x80E1
88
89 // framebuffer texture formats
90 // GLES2 devices rarely support depth textures, so we actually use a renderbuffer there
91 static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
92 static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
93 static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
94 static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
95 static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
96 static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
97 static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
98 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 2, 2, 2.0f, GL_RGB565 , GL_RGBA , GL_UNSIGNED_SHORT_5_6_5};
99 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 2, 2, 2.0f, GL_RGBA16F , GL_RGBA , GL_HALF_FLOAT_ARB};
100 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 2, 2, 2.0f, GL_RGBA32F , GL_RGBA , GL_FLOAT};
101
102 // image formats:
103 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
104 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
105 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
106 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
107 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
108 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
109 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
110 #ifdef __ANDROID__
111 static textypeinfo_t textype_etc1 = {"etc1", TEXTYPE_ETC1 , 1, 3, 0.5f, GL_ETC1_RGB8_OES , 0 , 0 };
112 #endif
113 #else
114 // framebuffer texture formats
115 static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
116 static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
117 static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
118 static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
119 static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
120 static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
121 static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 4, 4, 4.0f, GL_DEPTH24_STENCIL8_EXT , GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT};
122 static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
123 static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 8, 8, 8.0f, GL_RGBA16F_ARB , GL_RGBA , GL_HALF_FLOAT_ARB};
124 static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 16, 16, 16.0f, GL_RGBA32F_ARB , GL_RGBA , GL_FLOAT };
125
126 // image formats:
127 static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
128 static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
129 static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
130 static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE };
131 static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
132 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 };
133 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 };
134 static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE };
135 static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
136 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 };
137 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 };
138 static textypeinfo_t textype_dxt1 = {"dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 };
139 static textypeinfo_t textype_dxt1a = {"dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 };
140 static textypeinfo_t textype_dxt3 = {"dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 };
141 static textypeinfo_t textype_dxt5 = {"dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 };
142 static textypeinfo_t textype_sRGB_palette = {"sRGB_palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
143 static textypeinfo_t textype_sRGB_palette_alpha = {"sRGB_palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_ALPHA_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
144 static textypeinfo_t textype_sRGB_rgba = {"sRGB_rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
145 static textypeinfo_t textype_sRGB_rgba_alpha = {"sRGB_rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_ALPHA_EXT , GL_RGBA , GL_UNSIGNED_BYTE };
146 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 };
147 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 };
148 static textypeinfo_t textype_sRGB_bgra = {"sRGB_bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
149 static textypeinfo_t textype_sRGB_bgra_alpha = {"sRGB_bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_ALPHA_EXT , GL_BGRA , GL_UNSIGNED_BYTE };
150 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 };
151 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 };
152 static textypeinfo_t textype_sRGB_dxt1 = {"sRGB_dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , 0 , 0 };
153 static textypeinfo_t textype_sRGB_dxt1a = {"sRGB_dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 , 0 };
154 static textypeinfo_t textype_sRGB_dxt3 = {"sRGB_dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 , 0 };
155 static textypeinfo_t textype_sRGB_dxt5 = {"sRGB_dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 , 0 };
156 #endif
157
158 typedef enum gltexturetype_e
159 {
160 GLTEXTURETYPE_2D,
161 GLTEXTURETYPE_3D,
162 GLTEXTURETYPE_CUBEMAP,
163 GLTEXTURETYPE_TOTAL
164 }
165 gltexturetype_t;
166
167 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP};
168 #ifdef GL_TEXTURE_WRAP_R
169 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
170 #endif
171 static int cubemapside[6] =
172 {
173 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
174 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
175 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
176 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
177 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
178 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
179 };
180
181 typedef struct gltexture_s
182 {
183 // this portion of the struct is exposed to the R_GetTexture macro for
184 // speed reasons, must be identical in rtexture_t!
185 int texnum; // GL texture slot number
186 int renderbuffernum; // GL renderbuffer slot number
187 qboolean dirty; // indicates that R_RealGetTexture should be called
188 qboolean glisdepthstencil; // indicates that FBO attachment has to be GL_DEPTH_STENCIL_ATTACHMENT
189 int gltexturetypeenum; // used by R_Mesh_TexBind
190 // d3d stuff the backend needs
191 void *d3dtexture;
192 void *d3dsurface;
193 #ifdef SUPPORTD3D
194 qboolean d3disrendertargetsurface;
195 qboolean d3disdepthstencilsurface;
196 int d3dformat;
197 int d3dusage;
198 int d3dpool;
199 int d3daddressu;
200 int d3daddressv;
201 int d3daddressw;
202 int d3dmagfilter;
203 int d3dminfilter;
204 int d3dmipfilter;
205 int d3dmaxmiplevelfilter;
206 int d3dmipmaplodbias;
207 int d3dmaxmiplevel;
208 #endif
209
210 // dynamic texture stuff [11/22/2007 Black]
211 updatecallback_t updatecallback;
212 void *updatecallback_data;
213 // --- [11/22/2007 Black]
214
215 // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
216 unsigned char *bufferpixels;
217 qboolean buffermodified;
218
219 // pointer to texturepool (check this to see if the texture is allocated)
220 struct gltexturepool_s *pool;
221 // pointer to next texture in texturepool chain
222 struct gltexture_s *chain;
223 // name of the texture (this might be removed someday), no duplicates
224 char identifier[MAX_QPATH + 32];
225 // original data size in *inputtexels
226 int inputwidth, inputheight, inputdepth;
227 // copy of the original texture(s) supplied to the upload function, for
228 // delayed uploads (non-precached)
229 unsigned char *inputtexels;
230 // original data size in *inputtexels
231 int inputdatasize;
232 // flags supplied to the LoadTexture function
233 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
234 int flags;
235 // picmip level
236 int miplevel;
237 // pointer to one of the textype_ structs
238 textypeinfo_t *textype;
239 // one of the GLTEXTURETYPE_ values
240 int texturetype;
241 // palette if the texture is TEXTYPE_PALETTE
242 const unsigned int *palette;
243 // actual stored texture size after gl_picmip and gl_max_size are applied
244 // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
245 int tilewidth, tileheight, tiledepth;
246 // 1 or 6 depending on texturetype
247 int sides;
248 // how many mipmap levels in this texture
249 int miplevels;
250 // bytes per pixel
251 int bytesperpixel;
252 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
253 int glformat;
254 // 3 or 4
255 int glinternalformat;
256 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
257 int gltype;
258 }
259 gltexture_t;
260
261 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
262
263 typedef struct gltexturepool_s
264 {
265 unsigned int sentinel;
266 struct gltexture_s *gltchain;
267 struct gltexturepool_s *next;
268 }
269 gltexturepool_t;
270
271 static gltexturepool_t *gltexturepoolchain = NULL;
272
273 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
274 static int resizebuffersize = 0;
275 static const unsigned char *texturebuffer;
276
R_GetTexTypeInfo(textype_t textype,int flags)277 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
278 {
279 switch(textype)
280 {
281 #ifdef USE_GLES2
282 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
283 case TEXTYPE_RGBA: return ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba);
284 case TEXTYPE_BGRA: return ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra);
285 #ifdef __ANDROID__
286 case TEXTYPE_ETC1: return &textype_etc1;
287 #endif
288 case TEXTYPE_ALPHA: return &textype_alpha;
289 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
290 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
291 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
292 case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
293 case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
294 case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
295 case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
296 case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
297 case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
298 case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
299 #else
300 case TEXTYPE_DXT1: return &textype_dxt1;
301 case TEXTYPE_DXT1A: return &textype_dxt1a;
302 case TEXTYPE_DXT3: return &textype_dxt3;
303 case TEXTYPE_DXT5: return &textype_dxt5;
304 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
305 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);
306 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);
307 case TEXTYPE_ALPHA: return &textype_alpha;
308 case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
309 case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
310 case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
311 case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
312 case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
313 case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
314 case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
315 case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
316 case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
317 case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
318 case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1;
319 case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a;
320 case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
321 case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
322 case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
323 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);
324 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);
325 #endif
326 default:
327 Host_Error("R_GetTexTypeInfo: unknown texture format %i with flags %x", (int)textype, flags);
328 break;
329 }
330 return NULL;
331 }
332
333 // dynamic texture code [11/22/2007 Black]
R_MarkDirtyTexture(rtexture_t * rt)334 void R_MarkDirtyTexture(rtexture_t *rt) {
335 gltexture_t *glt = (gltexture_t*) rt;
336 if( !glt ) {
337 return;
338 }
339
340 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
341 if (glt->flags & GLTEXF_DYNAMIC)
342 {
343 // mark it as dirty, so R_RealGetTexture gets called
344 glt->dirty = true;
345 }
346 }
347
R_MakeTextureDynamic(rtexture_t * rt,updatecallback_t updatecallback,void * data)348 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
349 gltexture_t *glt = (gltexture_t*) rt;
350 if( !glt ) {
351 return;
352 }
353
354 glt->flags |= GLTEXF_DYNAMIC;
355 glt->updatecallback = updatecallback;
356 glt->updatecallback_data = data;
357 }
358
R_UpdateDynamicTexture(gltexture_t * glt)359 static void R_UpdateDynamicTexture(gltexture_t *glt) {
360 glt->dirty = false;
361 if( glt->updatecallback ) {
362 glt->updatecallback( (rtexture_t*) glt, glt->updatecallback_data );
363 }
364 }
365
R_PurgeTexture(rtexture_t * rt)366 void R_PurgeTexture(rtexture_t *rt)
367 {
368 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
369 R_FreeTexture(rt);
370 }
371 }
372
R_FreeTexture(rtexture_t * rt)373 void R_FreeTexture(rtexture_t *rt)
374 {
375 gltexture_t *glt, **gltpointer;
376
377 glt = (gltexture_t *)rt;
378 if (glt == NULL)
379 Host_Error("R_FreeTexture: texture == NULL");
380
381 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
382 if (*gltpointer == glt)
383 *gltpointer = glt->chain;
384 else
385 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
386
387 R_Mesh_ClearBindingsForTexture(glt->texnum);
388
389 switch(vid.renderpath)
390 {
391 case RENDERPATH_GL11:
392 case RENDERPATH_GL13:
393 case RENDERPATH_GL20:
394 case RENDERPATH_GLES1:
395 case RENDERPATH_GLES2:
396 if (glt->texnum)
397 {
398 CHECKGLERROR
399 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
400 }
401 if (glt->renderbuffernum)
402 {
403 CHECKGLERROR
404 qglDeleteRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
405 }
406 break;
407 case RENDERPATH_D3D9:
408 #ifdef SUPPORTD3D
409 if (glt->d3dsurface)
410 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dsurface);
411 else if (glt->tiledepth > 1)
412 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
413 else if (glt->sides == 6)
414 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
415 else
416 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
417 glt->d3dtexture = NULL;
418 glt->d3dsurface = NULL;
419 #endif
420 break;
421 case RENDERPATH_D3D10:
422 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
423 break;
424 case RENDERPATH_D3D11:
425 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
426 break;
427 case RENDERPATH_SOFT:
428 if (glt->texnum)
429 DPSOFTRAST_Texture_Free(glt->texnum);
430 break;
431 }
432
433 if (glt->inputtexels)
434 Mem_Free(glt->inputtexels);
435 Mem_ExpandableArray_FreeRecord(&texturearray, glt);
436 }
437
R_AllocTexturePool(void)438 rtexturepool_t *R_AllocTexturePool(void)
439 {
440 gltexturepool_t *pool;
441 if (texturemempool == NULL)
442 return NULL;
443 pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
444 if (pool == NULL)
445 return NULL;
446 pool->next = gltexturepoolchain;
447 gltexturepoolchain = pool;
448 pool->sentinel = TEXTUREPOOL_SENTINEL;
449 return (rtexturepool_t *)pool;
450 }
451
R_FreeTexturePool(rtexturepool_t ** rtexturepool)452 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
453 {
454 gltexturepool_t *pool, **poolpointer;
455 if (rtexturepool == NULL)
456 return;
457 if (*rtexturepool == NULL)
458 return;
459 pool = (gltexturepool_t *)(*rtexturepool);
460 *rtexturepool = NULL;
461 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
462 Host_Error("R_FreeTexturePool: pool already freed");
463 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
464 if (*poolpointer == pool)
465 *poolpointer = pool->next;
466 else
467 Host_Error("R_FreeTexturePool: pool not linked");
468 while (pool->gltchain)
469 R_FreeTexture((rtexture_t *)pool->gltchain);
470 Mem_Free(pool);
471 }
472
473
474 typedef struct glmode_s
475 {
476 const char *name;
477 int minification, magnification;
478 DPSOFTRAST_TEXTURE_FILTER dpsoftrastfilter_mipmap, dpsoftrastfilter_nomipmap;
479 }
480 glmode_t;
481
482 static glmode_t modes[6] =
483 {
484 {"GL_NEAREST", GL_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
485 {"GL_LINEAR", GL_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
486 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
487 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR},
488 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST},
489 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR}
490 };
491
492 #ifdef SUPPORTD3D
493 typedef struct d3dmode_s
494 {
495 const char *name;
496 int m1, m2;
497 }
498 d3dmode_t;
499
500 static d3dmode_t d3dmodes[6] =
501 {
502 {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
503 {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
504 {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
505 {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
506 {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
507 {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
508 };
509 #endif
510
GL_TextureMode_f(void)511 static void GL_TextureMode_f (void)
512 {
513 int i;
514 GLint oldbindtexnum;
515 gltexture_t *glt;
516 gltexturepool_t *pool;
517
518 if (Cmd_Argc() == 1)
519 {
520 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
521 for (i = 0;i < 6;i++)
522 {
523 if (gl_filter_min == modes[i].minification)
524 {
525 Con_Printf("%s\n", modes[i].name);
526 return;
527 }
528 }
529 Con_Print("current filter is unknown???\n");
530 return;
531 }
532
533 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
534 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
535 break;
536 if (i == 6)
537 {
538 Con_Print("bad filter name\n");
539 return;
540 }
541
542 gl_filter_min = modes[i].minification;
543 gl_filter_mag = modes[i].magnification;
544 gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
545
546 dpsoftrast_filter_mipmap = modes[i].dpsoftrastfilter_mipmap;
547 dpsoftrast_filter_nomipmap = modes[i].dpsoftrastfilter_nomipmap;
548
549 switch(vid.renderpath)
550 {
551 case RENDERPATH_GL11:
552 case RENDERPATH_GL13:
553 case RENDERPATH_GL20:
554 case RENDERPATH_GLES1:
555 case RENDERPATH_GLES2:
556 // change all the existing mipmap texture objects
557 // FIXME: force renderer(/client/something?) restart instead?
558 CHECKGLERROR
559 GL_ActiveTexture(0);
560 for (pool = gltexturepoolchain;pool;pool = pool->next)
561 {
562 for (glt = pool->gltchain;glt;glt = glt->chain)
563 {
564 // only update already uploaded images
565 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
566 {
567 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
568 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
569 if (glt->flags & TEXF_MIPMAP)
570 {
571 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
572 }
573 else
574 {
575 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
576 }
577 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
578 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
579 }
580 }
581 }
582 break;
583 case RENDERPATH_D3D9:
584 #ifdef SUPPORTD3D
585 d3d_filter_flatmin = d3dmodes[i].m1;
586 d3d_filter_flatmag = d3dmodes[i].m1;
587 d3d_filter_flatmix = D3DTEXF_POINT;
588 d3d_filter_mipmin = d3dmodes[i].m1;
589 d3d_filter_mipmag = d3dmodes[i].m1;
590 d3d_filter_mipmix = d3dmodes[i].m2;
591 d3d_filter_nomip = i < 2;
592 if (gl_texture_anisotropy.integer > 1 && i == 5)
593 d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
594 for (pool = gltexturepoolchain;pool;pool = pool->next)
595 {
596 for (glt = pool->gltchain;glt;glt = glt->chain)
597 {
598 // only update already uploaded images
599 if (glt->d3dtexture && !glt->d3dsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
600 {
601 if (glt->flags & TEXF_MIPMAP)
602 {
603 glt->d3dminfilter = d3d_filter_mipmin;
604 glt->d3dmagfilter = d3d_filter_mipmag;
605 glt->d3dmipfilter = d3d_filter_mipmix;
606 glt->d3dmaxmiplevelfilter = 0;
607 }
608 else
609 {
610 glt->d3dminfilter = d3d_filter_flatmin;
611 glt->d3dmagfilter = d3d_filter_flatmag;
612 glt->d3dmipfilter = d3d_filter_flatmix;
613 glt->d3dmaxmiplevelfilter = 0;
614 }
615 }
616 }
617 }
618 #endif
619 break;
620 case RENDERPATH_D3D10:
621 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
622 break;
623 case RENDERPATH_D3D11:
624 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
625 break;
626 case RENDERPATH_SOFT:
627 // change all the existing texture objects
628 for (pool = gltexturepoolchain;pool;pool = pool->next)
629 for (glt = pool->gltchain;glt;glt = glt->chain)
630 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
631 DPSOFTRAST_Texture_Filter(glt->texnum, (glt->flags & TEXF_MIPMAP) ? dpsoftrast_filter_mipmap : dpsoftrast_filter_nomipmap);
632 break;
633 }
634 }
635
GL_Texture_CalcImageSize(int texturetype,int flags,int miplevel,int inwidth,int inheight,int indepth,int * outwidth,int * outheight,int * outdepth,int * outmiplevels)636 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)
637 {
638 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
639
640 switch (texturetype)
641 {
642 default:
643 case GLTEXTURETYPE_2D:
644 maxsize = vid.maxtexturesize_2d;
645 if (flags & TEXF_PICMIP)
646 {
647 maxsize = bound(1, gl_max_size.integer, maxsize);
648 picmip = miplevel;
649 }
650 break;
651 case GLTEXTURETYPE_3D:
652 maxsize = vid.maxtexturesize_3d;
653 break;
654 case GLTEXTURETYPE_CUBEMAP:
655 maxsize = vid.maxtexturesize_cubemap;
656 break;
657 }
658
659 if (vid.support.arb_texture_non_power_of_two)
660 {
661 width2 = min(inwidth >> picmip, maxsize);
662 height2 = min(inheight >> picmip, maxsize);
663 depth2 = min(indepth >> picmip, maxsize);
664 }
665 else
666 {
667 for (width2 = 1;width2 < inwidth;width2 <<= 1);
668 for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
669 for (height2 = 1;height2 < inheight;height2 <<= 1);
670 for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
671 for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
672 for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
673 }
674
675 switch(vid.renderpath)
676 {
677 case RENDERPATH_GL11:
678 case RENDERPATH_GL13:
679 case RENDERPATH_GL20:
680 case RENDERPATH_D3D10:
681 case RENDERPATH_D3D11:
682 case RENDERPATH_SOFT:
683 case RENDERPATH_GLES1:
684 case RENDERPATH_GLES2:
685 break;
686 case RENDERPATH_D3D9:
687 #if 0
688 // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
689 if (texturetype == GLTEXTURETYPE_2D)
690 {
691 width2 = max(width2, 2);
692 height2 = max(height2, 2);
693 }
694 #endif
695 break;
696 }
697
698 miplevels = 1;
699 if (flags & TEXF_MIPMAP)
700 {
701 int extent = max(width2, max(height2, depth2));
702 while(extent >>= 1)
703 miplevels++;
704 }
705
706 if (outwidth)
707 *outwidth = max(1, width2);
708 if (outheight)
709 *outheight = max(1, height2);
710 if (outdepth)
711 *outdepth = max(1, depth2);
712 if (outmiplevels)
713 *outmiplevels = miplevels;
714 }
715
716
R_CalcTexelDataSize(gltexture_t * glt)717 static int R_CalcTexelDataSize (gltexture_t *glt)
718 {
719 int width2, height2, depth2, size;
720
721 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
722
723 size = width2 * height2 * depth2;
724
725 if (glt->flags & TEXF_MIPMAP)
726 {
727 while (width2 > 1 || height2 > 1 || depth2 > 1)
728 {
729 if (width2 > 1)
730 width2 >>= 1;
731 if (height2 > 1)
732 height2 >>= 1;
733 if (depth2 > 1)
734 depth2 >>= 1;
735 size += width2 * height2 * depth2;
736 }
737 }
738
739 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
740 }
741
R_TextureStats_Print(qboolean printeach,qboolean printpool,qboolean printtotal)742 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
743 {
744 int glsize;
745 int isloaded;
746 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
747 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
748 gltexture_t *glt;
749 gltexturepool_t *pool;
750 if (printeach)
751 Con_Print("glsize input loaded mip alpha name\n");
752 for (pool = gltexturepoolchain;pool;pool = pool->next)
753 {
754 pooltotal = 0;
755 pooltotalt = 0;
756 pooltotalp = 0;
757 poolloaded = 0;
758 poolloadedt = 0;
759 poolloadedp = 0;
760 for (glt = pool->gltchain;glt;glt = glt->chain)
761 {
762 glsize = R_CalcTexelDataSize(glt);
763 isloaded = glt->texnum != 0 || glt->renderbuffernum != 0 || glt->d3dtexture || glt->d3dsurface;
764 pooltotal++;
765 pooltotalt += glsize;
766 pooltotalp += glt->inputdatasize;
767 if (isloaded)
768 {
769 poolloaded++;
770 poolloadedt += glsize;
771 poolloadedp += glt->inputdatasize;
772 }
773 if (printeach)
774 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);
775 }
776 if (printpool)
777 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);
778 sumtotal += pooltotal;
779 sumtotalt += pooltotalt;
780 sumtotalp += pooltotalp;
781 sumloaded += poolloaded;
782 sumloadedt += poolloadedt;
783 sumloadedp += poolloadedp;
784 }
785 if (printtotal)
786 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);
787 }
788
R_TextureStats_f(void)789 static void R_TextureStats_f(void)
790 {
791 R_TextureStats_Print(true, true, true);
792 }
793
r_textures_start(void)794 static void r_textures_start(void)
795 {
796 switch(vid.renderpath)
797 {
798 case RENDERPATH_GL11:
799 case RENDERPATH_GL13:
800 case RENDERPATH_GL20:
801 case RENDERPATH_GLES1:
802 case RENDERPATH_GLES2:
803 // LordHavoc: allow any alignment
804 CHECKGLERROR
805 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
806 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
807 break;
808 case RENDERPATH_D3D9:
809 break;
810 case RENDERPATH_D3D10:
811 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
812 break;
813 case RENDERPATH_D3D11:
814 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
815 break;
816 case RENDERPATH_SOFT:
817 break;
818 }
819
820 texturemempool = Mem_AllocPool("texture management", 0, NULL);
821 Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
822
823 // Disable JPEG screenshots if the DLL isn't loaded
824 if (! JPEG_OpenLibrary ())
825 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
826 if (! PNG_OpenLibrary ())
827 Cvar_SetValueQuick (&scr_screenshot_png, 0);
828 }
829
r_textures_shutdown(void)830 static void r_textures_shutdown(void)
831 {
832 rtexturepool_t *temp;
833
834 JPEG_CloseLibrary ();
835
836 while(gltexturepoolchain)
837 {
838 temp = (rtexturepool_t *) gltexturepoolchain;
839 R_FreeTexturePool(&temp);
840 }
841
842 resizebuffersize = 0;
843 resizebuffer = NULL;
844 colorconvertbuffer = NULL;
845 texturebuffer = NULL;
846 Mem_ExpandableArray_FreeArray(&texturearray);
847 Mem_FreePool(&texturemempool);
848 }
849
r_textures_newmap(void)850 static void r_textures_newmap(void)
851 {
852 }
853
r_textures_devicelost(void)854 static void r_textures_devicelost(void)
855 {
856 int i, endindex;
857 gltexture_t *glt;
858 endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
859 for (i = 0;i < endindex;i++)
860 {
861 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
862 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
863 continue;
864 switch(vid.renderpath)
865 {
866 case RENDERPATH_GL11:
867 case RENDERPATH_GL13:
868 case RENDERPATH_GL20:
869 case RENDERPATH_GLES1:
870 case RENDERPATH_GLES2:
871 break;
872 case RENDERPATH_D3D9:
873 #ifdef SUPPORTD3D
874 if (glt->d3dsurface)
875 IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dsurface);
876 else if (glt->tiledepth > 1)
877 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
878 else if (glt->sides == 6)
879 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
880 else
881 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
882 glt->d3dtexture = NULL;
883 glt->d3dsurface = NULL;
884 #endif
885 break;
886 case RENDERPATH_D3D10:
887 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
888 break;
889 case RENDERPATH_D3D11:
890 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
891 break;
892 case RENDERPATH_SOFT:
893 break;
894 }
895 }
896 }
897
r_textures_devicerestored(void)898 static void r_textures_devicerestored(void)
899 {
900 int i, endindex;
901 gltexture_t *glt;
902 endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
903 for (i = 0;i < endindex;i++)
904 {
905 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
906 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
907 continue;
908 switch(vid.renderpath)
909 {
910 case RENDERPATH_GL11:
911 case RENDERPATH_GL13:
912 case RENDERPATH_GL20:
913 case RENDERPATH_GLES1:
914 case RENDERPATH_GLES2:
915 break;
916 case RENDERPATH_D3D9:
917 #ifdef SUPPORTD3D
918 {
919 HRESULT d3dresult;
920 if (glt->d3disrendertargetsurface)
921 {
922 if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
923 Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!");
924 }
925 else if (glt->d3disdepthstencilsurface)
926 {
927 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
928 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
929 }
930 else if (glt->tiledepth > 1)
931 {
932 if (FAILED(d3dresult = IDirect3DDevice9_CreateVolumeTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->tiledepth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DVolumeTexture9 **)&glt->d3dtexture, NULL)))
933 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
934 }
935 else if (glt->sides == 6)
936 {
937 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
938 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
939 }
940 else
941 {
942 if (FAILED(d3dresult = IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL)))
943 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
944 }
945 }
946 #endif
947 break;
948 case RENDERPATH_D3D10:
949 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
950 break;
951 case RENDERPATH_D3D11:
952 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
953 break;
954 case RENDERPATH_SOFT:
955 break;
956 }
957 }
958 }
959
960
R_Textures_Init(void)961 void R_Textures_Init (void)
962 {
963 Cmd_AddCommand("gl_texturemode", &GL_TextureMode_f, "set texture filtering mode (GL_NEAREST, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, etc); an additional argument 'force' forces the texture mode even in cases where it may not be appropriate");
964 Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
965 Cvar_RegisterVariable (&gl_max_size);
966 Cvar_RegisterVariable (&gl_picmip);
967 Cvar_RegisterVariable (&gl_picmip_world);
968 Cvar_RegisterVariable (&r_picmipworld);
969 Cvar_RegisterVariable (&gl_picmip_sprites);
970 Cvar_RegisterVariable (&r_picmipsprites);
971 Cvar_RegisterVariable (&gl_picmip_other);
972 Cvar_RegisterVariable (&gl_max_lightmapsize);
973 Cvar_RegisterVariable (&r_lerpimages);
974 Cvar_RegisterVariable (&gl_texture_anisotropy);
975 Cvar_RegisterVariable (&gl_texturecompression);
976 Cvar_RegisterVariable (&gl_texturecompression_color);
977 Cvar_RegisterVariable (&gl_texturecompression_normal);
978 Cvar_RegisterVariable (&gl_texturecompression_gloss);
979 Cvar_RegisterVariable (&gl_texturecompression_glow);
980 Cvar_RegisterVariable (&gl_texturecompression_2d);
981 Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
982 Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
983 Cvar_RegisterVariable (&gl_texturecompression_sky);
984 Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
985 Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
986 Cvar_RegisterVariable (&gl_texturecompression_sprites);
987 Cvar_RegisterVariable (&gl_nopartialtextureupdates);
988 Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
989 Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
990 Cvar_RegisterVariable (&r_texture_dds_swdecode);
991
992 R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
993 }
994
R_Textures_Frame(void)995 void R_Textures_Frame (void)
996 {
997 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
998 static int old_aniso = 0;
999 static qboolean first_time_aniso = true;
1000 #endif
1001
1002 // could do procedural texture animation here, if we keep track of which
1003 // textures were accessed this frame...
1004
1005 // free the resize buffers
1006 resizebuffersize = 0;
1007 if (resizebuffer)
1008 {
1009 Mem_Free(resizebuffer);
1010 resizebuffer = NULL;
1011 }
1012 if (colorconvertbuffer)
1013 {
1014 Mem_Free(colorconvertbuffer);
1015 colorconvertbuffer = NULL;
1016 }
1017
1018 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
1019 if (old_aniso != gl_texture_anisotropy.integer)
1020 {
1021 gltexture_t *glt;
1022 gltexturepool_t *pool;
1023 GLint oldbindtexnum;
1024
1025 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
1026
1027 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
1028
1029 switch(vid.renderpath)
1030 {
1031 case RENDERPATH_GL11:
1032 case RENDERPATH_GL13:
1033 case RENDERPATH_GL20:
1034 case RENDERPATH_GLES1:
1035 case RENDERPATH_GLES2:
1036 // ignore the first difference, any textures loaded by now probably had the same aniso value
1037 if (first_time_aniso)
1038 {
1039 first_time_aniso = false;
1040 break;
1041 }
1042 CHECKGLERROR
1043 GL_ActiveTexture(0);
1044 for (pool = gltexturepoolchain;pool;pool = pool->next)
1045 {
1046 for (glt = pool->gltchain;glt;glt = glt->chain)
1047 {
1048 // only update already uploaded images
1049 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
1050 {
1051 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1052
1053 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1054 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
1055
1056 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1057 }
1058 }
1059 }
1060 break;
1061 case RENDERPATH_D3D9:
1062 case RENDERPATH_D3D10:
1063 case RENDERPATH_D3D11:
1064 case RENDERPATH_SOFT:
1065 break;
1066 }
1067 }
1068 #endif
1069 }
1070
R_MakeResizeBufferBigger(int size)1071 static void R_MakeResizeBufferBigger(int size)
1072 {
1073 if (resizebuffersize < size)
1074 {
1075 resizebuffersize = size;
1076 if (resizebuffer)
1077 Mem_Free(resizebuffer);
1078 if (colorconvertbuffer)
1079 Mem_Free(colorconvertbuffer);
1080 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
1081 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
1082 if (!resizebuffer || !colorconvertbuffer)
1083 Host_Error("R_Upload: out of memory");
1084 }
1085 }
1086
GL_SetupTextureParameters(int flags,textype_t textype,int texturetype)1087 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
1088 {
1089 int textureenum = gltexturetypeenums[texturetype];
1090 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
1091
1092 CHECKGLERROR
1093
1094 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
1095 if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
1096 {
1097 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
1098 if (gl_texture_anisotropy.integer != aniso)
1099 Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
1100 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
1101 }
1102 #endif
1103 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
1104 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
1105 #ifdef GL_TEXTURE_WRAP_R
1106 if (gltexturetypedimensions[texturetype] >= 3)
1107 {
1108 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
1109 }
1110 #endif
1111
1112 CHECKGLERROR
1113 if (!gl_filter_force && flags & TEXF_FORCENEAREST)
1114 {
1115 if (flags & TEXF_MIPMAP)
1116 {
1117 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
1118 }
1119 else
1120 {
1121 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
1122 }
1123 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
1124 }
1125 else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
1126 {
1127 if (flags & TEXF_MIPMAP)
1128 {
1129 if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
1130 {
1131 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
1132 }
1133 else
1134 {
1135 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
1136 }
1137 }
1138 else
1139 {
1140 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
1141 }
1142 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
1143 }
1144 else
1145 {
1146 if (flags & TEXF_MIPMAP)
1147 {
1148 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
1149 }
1150 else
1151 {
1152 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
1153 }
1154 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
1155 }
1156
1157 #ifdef GL_TEXTURE_COMPARE_MODE_ARB
1158 switch(textype)
1159 {
1160 case TEXTYPE_SHADOWMAP16_COMP:
1161 case TEXTYPE_SHADOWMAP24_COMP:
1162 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
1163 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1164 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1165 break;
1166 case TEXTYPE_SHADOWMAP16_RAW:
1167 case TEXTYPE_SHADOWMAP24_RAW:
1168 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
1169 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
1170 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
1171 break;
1172 default:
1173 break;
1174 }
1175 #endif
1176
1177 CHECKGLERROR
1178 }
1179
R_UploadPartialTexture(gltexture_t * glt,const unsigned char * data,int fragx,int fragy,int fragz,int fragwidth,int fragheight,int fragdepth)1180 static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
1181 {
1182 if (data == NULL)
1183 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
1184
1185 if (glt->texturetype != GLTEXTURETYPE_2D)
1186 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
1187
1188 if (glt->textype->textype == TEXTYPE_PALETTE)
1189 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
1190
1191 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
1192 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
1193
1194 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
1195 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
1196
1197 // update a portion of the image
1198
1199 switch(vid.renderpath)
1200 {
1201 case RENDERPATH_GL11:
1202 case RENDERPATH_GL13:
1203 case RENDERPATH_GL20:
1204 case RENDERPATH_GLES1:
1205 case RENDERPATH_GLES2:
1206 {
1207 int oldbindtexnum;
1208 CHECKGLERROR
1209 // we need to restore the texture binding after finishing the upload
1210 GL_ActiveTexture(0);
1211 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1212 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1213 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
1214 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1215 }
1216 break;
1217 case RENDERPATH_D3D9:
1218 #ifdef SUPPORTD3D
1219 {
1220 RECT d3drect;
1221 D3DLOCKED_RECT d3dlockedrect;
1222 int y;
1223 memset(&d3drect, 0, sizeof(d3drect));
1224 d3drect.left = fragx;
1225 d3drect.top = fragy;
1226 d3drect.right = fragx+fragwidth;
1227 d3drect.bottom = fragy+fragheight;
1228 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1229 {
1230 for (y = 0;y < fragheight;y++)
1231 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1232 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1233 }
1234 }
1235 #endif
1236 break;
1237 case RENDERPATH_D3D10:
1238 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1239 break;
1240 case RENDERPATH_D3D11:
1241 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1242 break;
1243 case RENDERPATH_SOFT:
1244 DPSOFTRAST_Texture_UpdatePartial(glt->texnum, 0, data, fragx, fragy, fragwidth, fragheight);
1245 break;
1246 }
1247 }
1248
R_UploadFullTexture(gltexture_t * glt,const unsigned char * data)1249 static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
1250 {
1251 int i, mip = 0, width, height, depth;
1252 GLint oldbindtexnum = 0;
1253 const unsigned char *prevbuffer;
1254 prevbuffer = data;
1255
1256 // error out if a stretch is needed on special texture types
1257 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
1258 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
1259
1260 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
1261 // of the target size and then use the mipmap reduction function to get
1262 // high quality supersampled results
1263 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
1264 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
1265 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
1266
1267 if (prevbuffer == NULL)
1268 {
1269 width = glt->tilewidth;
1270 height = glt->tileheight;
1271 depth = glt->tiledepth;
1272 // R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1273 // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
1274 // prevbuffer = resizebuffer;
1275 }
1276 else
1277 {
1278 if (glt->textype->textype == TEXTYPE_PALETTE)
1279 {
1280 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1281 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1282 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
1283 prevbuffer = colorconvertbuffer;
1284 }
1285 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1286 {
1287 // multiply RGB channels by A channel before uploading
1288 int alpha;
1289 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1290 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1291 {
1292 alpha = prevbuffer[i+3];
1293 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1294 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1295 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1296 colorconvertbuffer[i+3] = alpha;
1297 }
1298 prevbuffer = colorconvertbuffer;
1299 }
1300 // scale up to a power of 2 size (if appropriate)
1301 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1302 {
1303 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1304 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1305 prevbuffer = resizebuffer;
1306 }
1307 // apply mipmap reduction algorithm to get down to picmip/max_size
1308 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1309 {
1310 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1311 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1312 prevbuffer = resizebuffer;
1313 }
1314 }
1315
1316 // do the appropriate upload type...
1317 switch(vid.renderpath)
1318 {
1319 case RENDERPATH_GL11:
1320 case RENDERPATH_GL13:
1321 case RENDERPATH_GL20:
1322 case RENDERPATH_GLES1:
1323 case RENDERPATH_GLES2:
1324 if (glt->texnum) // not renderbuffers
1325 {
1326 CHECKGLERROR
1327
1328 // we need to restore the texture binding after finishing the upload
1329 GL_ActiveTexture(0);
1330 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1331 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1332
1333 #ifndef USE_GLES2
1334 #ifdef GL_TEXTURE_COMPRESSION_HINT_ARB
1335 if (qglGetCompressedTexImageARB)
1336 {
1337 if (gl_texturecompression.integer >= 2)
1338 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1339 else
1340 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1341 CHECKGLERROR
1342 }
1343 #endif
1344 #endif
1345 switch(glt->texturetype)
1346 {
1347 case GLTEXTURETYPE_2D:
1348 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1349 if (glt->flags & TEXF_MIPMAP)
1350 {
1351 while (width > 1 || height > 1 || depth > 1)
1352 {
1353 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1354 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1355 prevbuffer = resizebuffer;
1356 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1357 }
1358 }
1359 break;
1360 case GLTEXTURETYPE_3D:
1361 #ifndef USE_GLES2
1362 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1363 if (glt->flags & TEXF_MIPMAP)
1364 {
1365 while (width > 1 || height > 1 || depth > 1)
1366 {
1367 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1368 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1369 prevbuffer = resizebuffer;
1370 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1371 }
1372 }
1373 #endif
1374 break;
1375 case GLTEXTURETYPE_CUBEMAP:
1376 // convert and upload each side in turn,
1377 // from a continuous block of input texels
1378 texturebuffer = (unsigned char *)prevbuffer;
1379 for (i = 0;i < 6;i++)
1380 {
1381 prevbuffer = texturebuffer;
1382 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1383 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1384 {
1385 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1386 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1387 prevbuffer = resizebuffer;
1388 }
1389 // picmip/max_size
1390 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1391 {
1392 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1393 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1394 prevbuffer = resizebuffer;
1395 }
1396 mip = 0;
1397 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1398 if (glt->flags & TEXF_MIPMAP)
1399 {
1400 while (width > 1 || height > 1 || depth > 1)
1401 {
1402 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1403 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1404 prevbuffer = resizebuffer;
1405 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1406 }
1407 }
1408 }
1409 break;
1410 }
1411 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1412 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1413 }
1414 break;
1415 case RENDERPATH_D3D9:
1416 #ifdef SUPPORTD3D
1417 if (!(glt->flags & TEXF_RENDERTARGET) && glt->d3dtexture && !glt->d3dsurface)
1418 {
1419 D3DLOCKED_RECT d3dlockedrect;
1420 D3DLOCKED_BOX d3dlockedbox;
1421 switch(glt->texturetype)
1422 {
1423 case GLTEXTURETYPE_2D:
1424 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1425 {
1426 if (prevbuffer)
1427 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1428 else
1429 memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1430 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1431 }
1432 mip++;
1433 if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1434 {
1435 while (width > 1 || height > 1 || depth > 1)
1436 {
1437 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1438 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1439 prevbuffer = resizebuffer;
1440 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1441 {
1442 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1443 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1444 }
1445 mip++;
1446 }
1447 }
1448 break;
1449 case GLTEXTURETYPE_3D:
1450 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1451 {
1452 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1453 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1454 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1455 }
1456 mip++;
1457 if (glt->flags & TEXF_MIPMAP)
1458 {
1459 while (width > 1 || height > 1 || depth > 1)
1460 {
1461 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1462 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1463 prevbuffer = resizebuffer;
1464 if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1465 {
1466 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1467 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1468 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1469 }
1470 mip++;
1471 }
1472 }
1473 break;
1474 case GLTEXTURETYPE_CUBEMAP:
1475 // convert and upload each side in turn,
1476 // from a continuous block of input texels
1477 texturebuffer = (unsigned char *)prevbuffer;
1478 for (i = 0;i < 6;i++)
1479 {
1480 prevbuffer = texturebuffer;
1481 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1482 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1483 {
1484 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1485 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1486 prevbuffer = resizebuffer;
1487 }
1488 // picmip/max_size
1489 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1490 {
1491 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1492 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1493 prevbuffer = resizebuffer;
1494 }
1495 mip = 0;
1496 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1497 {
1498 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1499 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1500 }
1501 mip++;
1502 if (glt->flags & TEXF_MIPMAP)
1503 {
1504 while (width > 1 || height > 1 || depth > 1)
1505 {
1506 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1507 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1508 prevbuffer = resizebuffer;
1509 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1510 {
1511 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1512 IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1513 }
1514 mip++;
1515 }
1516 }
1517 }
1518 break;
1519 }
1520 }
1521 glt->d3daddressw = 0;
1522 if (glt->flags & TEXF_CLAMP)
1523 {
1524 glt->d3daddressu = D3DTADDRESS_CLAMP;
1525 glt->d3daddressv = D3DTADDRESS_CLAMP;
1526 if (glt->tiledepth > 1)
1527 glt->d3daddressw = D3DTADDRESS_CLAMP;
1528 }
1529 else
1530 {
1531 glt->d3daddressu = D3DTADDRESS_WRAP;
1532 glt->d3daddressv = D3DTADDRESS_WRAP;
1533 if (glt->tiledepth > 1)
1534 glt->d3daddressw = D3DTADDRESS_WRAP;
1535 }
1536 glt->d3dmipmaplodbias = 0;
1537 glt->d3dmaxmiplevel = 0;
1538 glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1539 if (glt->flags & TEXF_FORCELINEAR)
1540 {
1541 glt->d3dminfilter = D3DTEXF_LINEAR;
1542 glt->d3dmagfilter = D3DTEXF_LINEAR;
1543 glt->d3dmipfilter = D3DTEXF_POINT;
1544 }
1545 else if (glt->flags & TEXF_FORCENEAREST)
1546 {
1547 glt->d3dminfilter = D3DTEXF_POINT;
1548 glt->d3dmagfilter = D3DTEXF_POINT;
1549 glt->d3dmipfilter = D3DTEXF_POINT;
1550 }
1551 else if (glt->flags & TEXF_MIPMAP)
1552 {
1553 glt->d3dminfilter = d3d_filter_mipmin;
1554 glt->d3dmagfilter = d3d_filter_mipmag;
1555 glt->d3dmipfilter = d3d_filter_mipmix;
1556 }
1557 else
1558 {
1559 glt->d3dminfilter = d3d_filter_flatmin;
1560 glt->d3dmagfilter = d3d_filter_flatmag;
1561 glt->d3dmipfilter = d3d_filter_flatmix;
1562 }
1563 #endif
1564 break;
1565 case RENDERPATH_D3D10:
1566 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1567 break;
1568 case RENDERPATH_D3D11:
1569 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1570 break;
1571 case RENDERPATH_SOFT:
1572 switch(glt->texturetype)
1573 {
1574 case GLTEXTURETYPE_2D:
1575 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1576 break;
1577 case GLTEXTURETYPE_3D:
1578 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1579 break;
1580 case GLTEXTURETYPE_CUBEMAP:
1581 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1582 {
1583 unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1584 // convert and upload each side in turn,
1585 // from a continuous block of input texels
1586 // copy the results into combinedbuffer
1587 texturebuffer = (unsigned char *)prevbuffer;
1588 for (i = 0;i < 6;i++)
1589 {
1590 prevbuffer = texturebuffer;
1591 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1592 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1593 {
1594 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1595 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1596 prevbuffer = resizebuffer;
1597 }
1598 // picmip/max_size
1599 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1600 {
1601 R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1602 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1603 prevbuffer = resizebuffer;
1604 }
1605 memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel);
1606 }
1607 DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer);
1608 Mem_Free(combinedbuffer);
1609 }
1610 else
1611 DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer);
1612 break;
1613 }
1614 if (glt->flags & TEXF_FORCELINEAR)
1615 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
1616 else if (glt->flags & TEXF_FORCENEAREST)
1617 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
1618 else if (glt->flags & TEXF_MIPMAP)
1619 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
1620 else
1621 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
1622 break;
1623 }
1624 }
1625
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)1626 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)
1627 {
1628 int i, size;
1629 gltexture_t *glt;
1630 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1631 textypeinfo_t *texinfo, *texinfo2;
1632 unsigned char *temppixels = NULL;
1633 qboolean swaprb;
1634
1635 if (cls.state == ca_dedicated)
1636 return NULL;
1637
1638 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1639 if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1640 {
1641 int numpixels = width * height * depth * sides;
1642 size = numpixels * 4;
1643 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1644 if (data)
1645 {
1646 const unsigned char *p;
1647 unsigned char *o = temppixels;
1648 for (i = 0;i < numpixels;i++, o += 4)
1649 {
1650 p = (const unsigned char *)palette + 4*data[i];
1651 o[0] = p[2];
1652 o[1] = p[1];
1653 o[2] = p[0];
1654 o[3] = p[3];
1655 }
1656 }
1657 data = temppixels;
1658 textype = TEXTYPE_RGBA;
1659 }
1660 swaprb = false;
1661 switch(textype)
1662 {
1663 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1664 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1665 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1666 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1667 default: break;
1668 }
1669 if (swaprb)
1670 {
1671 // swap bytes
1672 static int rgbaswapindices[4] = {2, 1, 0, 3};
1673 size = width * height * depth * sides * 4;
1674 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1675 if (data)
1676 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1677 data = temppixels;
1678 }
1679
1680 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1681 if (!vid.support.ext_texture_srgb)
1682 {
1683 qboolean convertsRGB = false;
1684 switch(textype)
1685 {
1686 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1687 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1688 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1689 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1690 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;/*convertsRGB = true;*/break;
1691 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1692 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1693 default:
1694 break;
1695 }
1696 if (convertsRGB && data)
1697 {
1698 size = width * height * depth * sides * 4;
1699 if (!temppixels)
1700 {
1701 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1702 memcpy(temppixels, data, size);
1703 data = temppixels;
1704 }
1705 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1706 }
1707 }
1708
1709 if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1710 {
1711 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1712 return NULL;
1713 }
1714 if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1715 {
1716 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1717 return NULL;
1718 }
1719
1720 texinfo = R_GetTexTypeInfo(textype, flags);
1721 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1722 if (size < 1)
1723 {
1724 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1725 return NULL;
1726 }
1727
1728 // clear the alpha flag if the texture has no transparent pixels
1729 switch(textype)
1730 {
1731 case TEXTYPE_PALETTE:
1732 case TEXTYPE_SRGB_PALETTE:
1733 if (flags & TEXF_ALPHA)
1734 {
1735 flags &= ~TEXF_ALPHA;
1736 if (data)
1737 {
1738 for (i = 0;i < size;i++)
1739 {
1740 if (((unsigned char *)&palette[data[i]])[3] < 255)
1741 {
1742 flags |= TEXF_ALPHA;
1743 break;
1744 }
1745 }
1746 }
1747 }
1748 break;
1749 case TEXTYPE_RGBA:
1750 case TEXTYPE_BGRA:
1751 case TEXTYPE_SRGB_RGBA:
1752 case TEXTYPE_SRGB_BGRA:
1753 if (flags & TEXF_ALPHA)
1754 {
1755 flags &= ~TEXF_ALPHA;
1756 if (data)
1757 {
1758 for (i = 3;i < size;i += 4)
1759 {
1760 if (data[i] < 255)
1761 {
1762 flags |= TEXF_ALPHA;
1763 break;
1764 }
1765 }
1766 }
1767 }
1768 break;
1769 case TEXTYPE_SHADOWMAP16_COMP:
1770 case TEXTYPE_SHADOWMAP16_RAW:
1771 case TEXTYPE_SHADOWMAP24_COMP:
1772 case TEXTYPE_SHADOWMAP24_RAW:
1773 break;
1774 case TEXTYPE_DXT1:
1775 case TEXTYPE_SRGB_DXT1:
1776 break;
1777 case TEXTYPE_DXT1A:
1778 case TEXTYPE_SRGB_DXT1A:
1779 case TEXTYPE_DXT3:
1780 case TEXTYPE_SRGB_DXT3:
1781 case TEXTYPE_DXT5:
1782 case TEXTYPE_SRGB_DXT5:
1783 flags |= TEXF_ALPHA;
1784 break;
1785 case TEXTYPE_ALPHA:
1786 flags |= TEXF_ALPHA;
1787 break;
1788 case TEXTYPE_COLORBUFFER:
1789 case TEXTYPE_COLORBUFFER16F:
1790 case TEXTYPE_COLORBUFFER32F:
1791 flags |= TEXF_ALPHA;
1792 break;
1793 default:
1794 Sys_Error("R_LoadTexture: unknown texture type");
1795 }
1796
1797 texinfo2 = R_GetTexTypeInfo(textype, flags);
1798 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1799 texinfo = texinfo2;
1800 else
1801 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1802
1803 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1804 if (identifier)
1805 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1806 glt->pool = pool;
1807 glt->chain = pool->gltchain;
1808 pool->gltchain = glt;
1809 glt->inputwidth = width;
1810 glt->inputheight = height;
1811 glt->inputdepth = depth;
1812 glt->flags = flags;
1813 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
1814 glt->textype = texinfo;
1815 glt->texturetype = texturetype;
1816 glt->inputdatasize = size;
1817 glt->palette = palette;
1818 glt->glinternalformat = texinfo->glinternalformat;
1819 glt->glformat = texinfo->glformat;
1820 glt->gltype = texinfo->gltype;
1821 glt->bytesperpixel = texinfo->internalbytesperpixel;
1822 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1823 glt->texnum = 0;
1824 glt->dirty = false;
1825 glt->glisdepthstencil = false;
1826 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1827 // init the dynamic texture attributes, too [11/22/2007 Black]
1828 glt->updatecallback = NULL;
1829 glt->updatecallback_data = NULL;
1830
1831 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1832
1833 // upload the texture
1834 // data may be NULL (blank texture for dynamic rendering)
1835 switch(vid.renderpath)
1836 {
1837 case RENDERPATH_GL11:
1838 case RENDERPATH_GL13:
1839 case RENDERPATH_GL20:
1840 case RENDERPATH_GLES1:
1841 case RENDERPATH_GLES2:
1842 CHECKGLERROR
1843 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1844 break;
1845 case RENDERPATH_D3D9:
1846 #ifdef SUPPORTD3D
1847 {
1848 D3DFORMAT d3dformat;
1849 D3DPOOL d3dpool;
1850 DWORD d3dusage;
1851 HRESULT d3dresult;
1852 d3dusage = 0;
1853 d3dpool = D3DPOOL_MANAGED;
1854 if (flags & TEXF_RENDERTARGET)
1855 {
1856 d3dusage |= D3DUSAGE_RENDERTARGET;
1857 d3dpool = D3DPOOL_DEFAULT;
1858 }
1859 switch(textype)
1860 {
1861 case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1862 case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1863 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1864 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
1865 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
1866 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
1867 case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1868 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1869 }
1870 glt->d3dformat = d3dformat;
1871 glt->d3dusage = d3dusage;
1872 glt->d3dpool = d3dpool;
1873 glt->d3disrendertargetsurface = false;
1874 glt->d3disdepthstencilsurface = false;
1875 if (glt->tiledepth > 1)
1876 {
1877 if (FAILED(d3dresult = IDirect3DDevice9_CreateVolumeTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->tiledepth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DVolumeTexture9 **)&glt->d3dtexture, NULL)))
1878 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1879 }
1880 else if (glt->sides == 6)
1881 {
1882 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1883 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1884 }
1885 else
1886 {
1887 if (FAILED(d3dresult = IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL)))
1888 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1889 }
1890 }
1891 #endif
1892 break;
1893 case RENDERPATH_D3D10:
1894 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1895 break;
1896 case RENDERPATH_D3D11:
1897 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1898 break;
1899 case RENDERPATH_SOFT:
1900 {
1901 int tflags = 0;
1902 switch(textype)
1903 {
1904 case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1905 case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
1906 case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1907 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
1908 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
1909 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
1910 case TEXTYPE_SHADOWMAP16_COMP:
1911 case TEXTYPE_SHADOWMAP16_RAW:
1912 case TEXTYPE_SHADOWMAP24_COMP:
1913 case TEXTYPE_SHADOWMAP24_RAW: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1914 case TEXTYPE_DEPTHBUFFER16:
1915 case TEXTYPE_DEPTHBUFFER24:
1916 case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
1917 case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
1918 default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
1919 }
1920 if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP;
1921 if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA;
1922 if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP;
1923 if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;
1924 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
1925 }
1926 break;
1927 }
1928
1929 R_UploadFullTexture(glt, data);
1930 if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1931 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1932
1933 // free any temporary processing buffer we allocated...
1934 if (temppixels)
1935 Mem_Free(temppixels);
1936
1937 // texture converting and uploading can take a while, so make sure we're sending keepalives
1938 // FIXME: this causes rendering during R_Shadow_DrawLights
1939 // CL_KeepaliveMessage(false);
1940
1941 return (rtexture_t *)glt;
1942 }
1943
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)1944 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)
1945 {
1946 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1947 }
1948
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)1949 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)
1950 {
1951 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1952 }
1953
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)1954 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)
1955 {
1956 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1957 }
1958
R_LoadTextureShadowMap2D(rtexturepool_t * rtexturepool,const char * identifier,int width,int height,textype_t textype,qboolean filter)1959 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter)
1960 {
1961 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL);
1962 }
1963
R_LoadTextureRenderBuffer(rtexturepool_t * rtexturepool,const char * identifier,int width,int height,textype_t textype)1964 rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
1965 {
1966 gltexture_t *glt;
1967 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1968 textypeinfo_t *texinfo;
1969
1970 if (cls.state == ca_dedicated)
1971 return NULL;
1972
1973 texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP);
1974
1975 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1976 if (identifier)
1977 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1978 glt->pool = pool;
1979 glt->chain = pool->gltchain;
1980 pool->gltchain = glt;
1981 glt->inputwidth = width;
1982 glt->inputheight = height;
1983 glt->inputdepth = 1;
1984 glt->flags = TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_FORCENEAREST;
1985 glt->miplevel = 0;
1986 glt->textype = texinfo;
1987 glt->texturetype = textype;
1988 glt->inputdatasize = width*height*texinfo->internalbytesperpixel;
1989 glt->palette = NULL;
1990 glt->glinternalformat = texinfo->glinternalformat;
1991 glt->glformat = texinfo->glformat;
1992 glt->gltype = texinfo->gltype;
1993 glt->bytesperpixel = texinfo->internalbytesperpixel;
1994 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1995 glt->texnum = 0;
1996 glt->dirty = false;
1997 glt->glisdepthstencil = textype == TEXTYPE_DEPTHBUFFER24STENCIL8;
1998 glt->gltexturetypeenum = GL_TEXTURE_2D;
1999 // init the dynamic texture attributes, too [11/22/2007 Black]
2000 glt->updatecallback = NULL;
2001 glt->updatecallback_data = NULL;
2002
2003 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
2004
2005 // upload the texture
2006 // data may be NULL (blank texture for dynamic rendering)
2007 switch(vid.renderpath)
2008 {
2009 case RENDERPATH_GL11:
2010 case RENDERPATH_GL13:
2011 case RENDERPATH_GL20:
2012 case RENDERPATH_GLES1:
2013 case RENDERPATH_GLES2:
2014 CHECKGLERROR
2015 qglGenRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
2016 qglBindRenderbuffer(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR
2017 qglRenderbufferStorage(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR
2018 // 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
2019 qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR
2020 break;
2021 case RENDERPATH_D3D9:
2022 #ifdef SUPPORTD3D
2023 {
2024 D3DFORMAT d3dformat;
2025 HRESULT d3dresult;
2026 glt->d3disrendertargetsurface = false;
2027 glt->d3disdepthstencilsurface = false;
2028 switch(textype)
2029 {
2030 case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;glt->d3disrendertargetsurface = true;break;
2031 case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;glt->d3disrendertargetsurface = true;break;
2032 case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;glt->d3disrendertargetsurface = true;break;
2033 case TEXTYPE_DEPTHBUFFER16: d3dformat = D3DFMT_D16;glt->d3disdepthstencilsurface = true;break;
2034 case TEXTYPE_DEPTHBUFFER24: d3dformat = D3DFMT_D24X8;glt->d3disdepthstencilsurface = true;break;
2035 case TEXTYPE_DEPTHBUFFER24STENCIL8: d3dformat = D3DFMT_D24S8;glt->d3disdepthstencilsurface = true;break;
2036 default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2037 }
2038 glt->d3dformat = d3dformat;
2039 glt->d3dusage = 0;
2040 glt->d3dpool = 0;
2041 if (glt->d3disrendertargetsurface)
2042 {
2043 if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
2044 Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!");
2045 }
2046 else if (glt->d3disdepthstencilsurface)
2047 {
2048 if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
2049 Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
2050 }
2051 }
2052 #endif
2053 break;
2054 case RENDERPATH_D3D10:
2055 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2056 break;
2057 case RENDERPATH_D3D11:
2058 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2059 break;
2060 case RENDERPATH_SOFT:
2061 {
2062 int tflags = 0;
2063 switch(textype)
2064 {
2065 case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8 | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2066 case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2067 case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2068 case TEXTYPE_DEPTHBUFFER16:
2069 case TEXTYPE_DEPTHBUFFER24:
2070 case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
2071 default: Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
2072 }
2073 glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
2074 }
2075 break;
2076 }
2077
2078 return (rtexture_t *)glt;
2079 }
2080
R_SaveTextureDDSFile(rtexture_t * rt,const char * filename,qboolean skipuncompressed,qboolean hasalpha)2081 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
2082 {
2083 #ifdef USE_GLES2
2084 return -1; // unsupported on this platform
2085 #else
2086 gltexture_t *glt = (gltexture_t *)rt;
2087 unsigned char *dds;
2088 int oldbindtexnum;
2089 int bytesperpixel = 0;
2090 int bytesperblock = 0;
2091 int dds_flags;
2092 int dds_format_flags;
2093 int dds_caps1;
2094 int dds_caps2;
2095 int ret;
2096 int mip;
2097 int mipmaps;
2098 int mipinfo[16][4];
2099 int ddssize = 128;
2100 GLint internalformat;
2101 const char *ddsfourcc;
2102 if (!rt)
2103 return -1; // NULL pointer
2104 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
2105 return -2; // broken driver - crashes on reading internal format
2106 if (!qglGetTexLevelParameteriv)
2107 return -2;
2108 GL_ActiveTexture(0);
2109 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2110 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2111 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
2112 switch(internalformat)
2113 {
2114 default: ddsfourcc = NULL;bytesperpixel = 4;break;
2115 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
2116 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
2117 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
2118 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
2119 }
2120 // if premultiplied alpha, say so in the DDS file
2121 if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
2122 {
2123 switch(internalformat)
2124 {
2125 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
2126 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
2127 }
2128 }
2129 if (!bytesperblock && skipuncompressed)
2130 return -3; // skipped
2131 memset(mipinfo, 0, sizeof(mipinfo));
2132 mipinfo[0][0] = glt->tilewidth;
2133 mipinfo[0][1] = glt->tileheight;
2134 mipmaps = 1;
2135 if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1))
2136 {
2137 for (mip = 1;mip < 16;mip++)
2138 {
2139 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
2140 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
2141 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
2142 {
2143 mip++;
2144 break;
2145 }
2146 }
2147 mipmaps = mip;
2148 }
2149 for (mip = 0;mip < mipmaps;mip++)
2150 {
2151 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
2152 mipinfo[mip][3] = ddssize;
2153 ddssize += mipinfo[mip][2];
2154 }
2155 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
2156 if (!dds)
2157 return -4;
2158 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
2159 dds_caps2 = 0;
2160 if (bytesperblock)
2161 {
2162 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
2163 dds_format_flags = 0x4; // DDPF_FOURCC
2164 }
2165 else
2166 {
2167 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
2168 dds_format_flags = 0x40; // DDPF_RGB
2169 }
2170 if (mipmaps)
2171 {
2172 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
2173 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
2174 }
2175 if(hasalpha)
2176 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
2177 memcpy(dds, "DDS ", 4);
2178 StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
2179 StoreLittleLong(dds+8, dds_flags);
2180 StoreLittleLong(dds+12, mipinfo[0][1]); // height
2181 StoreLittleLong(dds+16, mipinfo[0][0]); // width
2182 StoreLittleLong(dds+24, 0); // depth
2183 StoreLittleLong(dds+28, mipmaps); // mipmaps
2184 StoreLittleLong(dds+76, 32); // format size
2185 StoreLittleLong(dds+80, dds_format_flags);
2186 StoreLittleLong(dds+108, dds_caps1);
2187 StoreLittleLong(dds+112, dds_caps2);
2188 if (bytesperblock)
2189 {
2190 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
2191 memcpy(dds+84, ddsfourcc, 4);
2192 for (mip = 0;mip < mipmaps;mip++)
2193 {
2194 qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
2195 }
2196 }
2197 else
2198 {
2199 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
2200 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
2201 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
2202 for (mip = 0;mip < mipmaps;mip++)
2203 {
2204 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
2205 }
2206 }
2207 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2208 ret = FS_WriteFile(filename, dds, ddssize);
2209 Mem_Free(dds);
2210 return ret ? ddssize : -5;
2211 #endif
2212 }
2213
2214 #ifdef __ANDROID__
2215 // ELUAN: FIXME: separate this code
2216 #include "ktx10/include/ktx.h"
2217 #endif
2218
R_LoadTextureDDSFile(rtexturepool_t * rtexturepool,const char * filename,qboolean srgb,int flags,qboolean * hasalphaflag,float * avgcolor,int miplevel,qboolean optionaltexture)2219 rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qboolean srgb, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel, qboolean optionaltexture) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint
2220 {
2221 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
2222 //int dds_flags;
2223 textype_t textype;
2224 int bytesperblock, bytesperpixel;
2225 int mipcomplete;
2226 gltexture_t *glt;
2227 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
2228 textypeinfo_t *texinfo;
2229 int mip, mipwidth, mipheight, mipsize, mipsize_total;
2230 unsigned int c, r, g, b;
2231 GLint oldbindtexnum = 0;
2232 unsigned char *mippixels;
2233 unsigned char *mippixels_start;
2234 unsigned char *ddspixels;
2235 unsigned char *dds;
2236 fs_offset_t ddsfilesize;
2237 unsigned int ddssize;
2238 qboolean force_swdecode, npothack;
2239 #ifdef __ANDROID__
2240 // ELUAN: FIXME: separate this code
2241 char vabuf[1024];
2242 char vabuf2[1024];
2243 int strsize;
2244 KTX_dimensions sizes;
2245 #endif
2246
2247 if (cls.state == ca_dedicated)
2248 return NULL;
2249
2250 #ifdef __ANDROID__
2251 // ELUAN: FIXME: separate this code
2252 if (vid.renderpath != RENDERPATH_GLES2)
2253 {
2254 Con_DPrintf("KTX texture format is only supported on the GLES2 renderpath\n");
2255 return NULL;
2256 }
2257
2258 // some textures are specified with extensions, so it becomes .tga.dds
2259 FS_StripExtension (filename, vabuf2, sizeof(vabuf2));
2260 FS_StripExtension (vabuf2, vabuf, sizeof(vabuf));
2261 FS_DefaultExtension (vabuf, ".ktx", sizeof(vabuf));
2262 strsize = strlen(vabuf);
2263 if (strsize > 5)
2264 for (i = 0; i <= strsize - 4; i++) // copy null termination
2265 vabuf[i] = vabuf[i + 4];
2266
2267 Con_DPrintf("Loading %s...\n", vabuf);
2268 dds = FS_LoadFile(vabuf, tempmempool, true, &ddsfilesize);
2269 ddssize = ddsfilesize;
2270
2271 if (!dds)
2272 {
2273 Con_DPrintf("Not found!\n");
2274 return NULL; // not found
2275 }
2276 Con_DPrintf("Found!\n");
2277
2278 if (flags & TEXF_ALPHA)
2279 {
2280 Con_DPrintf("KTX texture with alpha not supported yet, disabling\n");
2281 flags &= ~TEXF_ALPHA;
2282 }
2283
2284 {
2285 GLenum target;
2286 GLenum glerror;
2287 GLboolean isMipmapped;
2288 KTX_error_code ktxerror;
2289
2290 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2291
2292 // texture uploading can take a while, so make sure we're sending keepalives
2293 CL_KeepaliveMessage(false);
2294
2295 // create the texture object
2296 CHECKGLERROR
2297 GL_ActiveTexture(0);
2298 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[GLTEXTURETYPE_2D]);
2299 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2300 qglBindTexture(gltexturetypeenums[GLTEXTURETYPE_2D], glt->texnum);CHECKGLERROR
2301
2302 // upload the texture
2303 // we need to restore the texture binding after finishing the upload
2304
2305 // NOTE: some drivers fail with ETC1 NPOT (only PowerVR?). This may make the driver crash later.
2306 ktxerror = ktxLoadTextureM(dds, ddssize, &glt->texnum, &target, &sizes, &isMipmapped, &glerror,
2307 0, NULL);// can't CHECKGLERROR, the lib catches it
2308
2309 // FIXME: delete texture if we fail here
2310 if (target != GL_TEXTURE_2D)
2311 {
2312 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2313 Mem_Free(dds);
2314 Con_DPrintf("%s target != GL_TEXTURE_2D, target == %x\n", vabuf, target);
2315 return NULL; // FIXME: delete the texture from memory
2316 }
2317
2318 if (KTX_SUCCESS == ktxerror)
2319 {
2320 textype = TEXTYPE_ETC1;
2321 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2322
2323 // return whether this texture is transparent
2324 if (hasalphaflag)
2325 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2326
2327 // TODO: apply gl_picmip
2328 // TODO: avgcolor
2329 // TODO: srgb
2330 // TODO: only load mipmaps if requested
2331
2332 if (isMipmapped)
2333 flags |= TEXF_MIPMAP;
2334 else
2335 flags &= ~TEXF_MIPMAP;
2336
2337 texinfo = R_GetTexTypeInfo(textype, flags);
2338
2339 strlcpy (glt->identifier, vabuf, sizeof(glt->identifier));
2340 glt->pool = pool;
2341 glt->chain = pool->gltchain;
2342 pool->gltchain = glt;
2343 glt->inputwidth = sizes.width;
2344 glt->inputheight = sizes.height;
2345 glt->inputdepth = 1;
2346 glt->flags = flags;
2347 glt->textype = texinfo;
2348 glt->texturetype = GLTEXTURETYPE_2D;
2349 glt->inputdatasize = ddssize;
2350 glt->glinternalformat = texinfo->glinternalformat;
2351 glt->glformat = texinfo->glformat;
2352 glt->gltype = texinfo->gltype;
2353 glt->bytesperpixel = texinfo->internalbytesperpixel;
2354 glt->sides = 1;
2355 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2356 glt->tilewidth = sizes.width;
2357 glt->tileheight = sizes.height;
2358 glt->tiledepth = 1;
2359 glt->miplevels = isMipmapped ? 1 : 0; // FIXME
2360
2361 // after upload we have to set some parameters...
2362 #ifdef GL_TEXTURE_MAX_LEVEL
2363 /* FIXME
2364 if (dds_miplevels >= 1 && !mipcomplete)
2365 {
2366 // need to set GL_TEXTURE_MAX_LEVEL
2367 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2368 }
2369 */
2370 #endif
2371 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2372
2373 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2374 Mem_Free(dds);
2375 return (rtexture_t *)glt;
2376 }
2377 else
2378 {
2379 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2380 Mem_Free(dds);
2381 Con_DPrintf("KTX texture %s failed to load: %x\n", vabuf, ktxerror);
2382 return NULL;
2383 }
2384 }
2385 #endif // __ANDROID__
2386
2387 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
2388 ddssize = ddsfilesize;
2389
2390 if (!dds)
2391 {
2392 if (r_texture_dds_load_logfailure.integer && (r_texture_dds_load_logfailure.integer >= 2 || !optionaltexture))
2393 Log_Printf("ddstexturefailures.log", "%s\n", filename);
2394 return NULL; // not found
2395 }
2396
2397 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
2398 {
2399 Mem_Free(dds);
2400 Con_Printf("^1%s: not a DDS image\n", filename);
2401 return NULL;
2402 }
2403
2404 //dds_flags = BuffLittleLong(dds+8);
2405 dds_format_flags = BuffLittleLong(dds+80);
2406 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
2407 dds_width = BuffLittleLong(dds+16);
2408 dds_height = BuffLittleLong(dds+12);
2409 ddspixels = dds + 128;
2410
2411 if(r_texture_dds_load_alphamode.integer == 0)
2412 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
2413 flags &= ~TEXF_ALPHA;
2414
2415 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
2416 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
2417 {
2418 // very sloppy BGRA 32bit identification
2419 textype = TEXTYPE_BGRA;
2420 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
2421 bytesperblock = 0;
2422 bytesperpixel = 4;
2423 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
2424 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2425 {
2426 Mem_Free(dds);
2427 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
2428 return NULL;
2429 }
2430 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
2431 {
2432 // check alpha
2433 for (i = 3;i < size;i += 4)
2434 if (ddspixels[i] < 255)
2435 break;
2436 if (i >= size)
2437 flags &= ~TEXF_ALPHA;
2438 }
2439 }
2440 else if (!memcmp(dds+84, "DXT1", 4))
2441 {
2442 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
2443 // LordHavoc: it is my belief that this does not infringe on the
2444 // patent because it is not decoding pixels...
2445 textype = TEXTYPE_DXT1;
2446 bytesperblock = 8;
2447 bytesperpixel = 0;
2448 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
2449 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2450 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2451 {
2452 Mem_Free(dds);
2453 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
2454 return NULL;
2455 }
2456 if (flags & TEXF_ALPHA)
2457 {
2458 if (r_texture_dds_load_alphamode.integer == 1)
2459 {
2460 // check alpha
2461 for (i = 0;i < size;i += bytesperblock)
2462 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
2463 {
2464 // NOTE: this assumes sizeof(unsigned int) == 4
2465 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
2466 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
2467 if(data & (data<<1) & 0xAAAAAAAA)//rgh
2468 break;
2469 }
2470 if (i < size)
2471 textype = TEXTYPE_DXT1A;
2472 else
2473 flags &= ~TEXF_ALPHA;
2474 }
2475 else if (r_texture_dds_load_alphamode.integer == 0)
2476 textype = TEXTYPE_DXT1A;
2477 else
2478 {
2479 flags &= ~TEXF_ALPHA;
2480 }
2481 }
2482 }
2483 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
2484 {
2485 if(!memcmp(dds+84, "DXT2", 4))
2486 {
2487 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2488 {
2489 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
2490 }
2491 }
2492 else
2493 {
2494 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2495 {
2496 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
2497 }
2498 }
2499 textype = TEXTYPE_DXT3;
2500 bytesperblock = 16;
2501 bytesperpixel = 0;
2502 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2503 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2504 {
2505 Mem_Free(dds);
2506 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
2507 return NULL;
2508 }
2509 // we currently always assume alpha
2510 }
2511 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
2512 {
2513 if(!memcmp(dds+84, "DXT4", 4))
2514 {
2515 if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
2516 {
2517 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
2518 }
2519 }
2520 else
2521 {
2522 if(flags & TEXF_RGBMULTIPLYBYALPHA)
2523 {
2524 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
2525 }
2526 }
2527 textype = TEXTYPE_DXT5;
2528 bytesperblock = 16;
2529 bytesperpixel = 0;
2530 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
2531 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
2532 {
2533 Mem_Free(dds);
2534 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
2535 return NULL;
2536 }
2537 // we currently always assume alpha
2538 }
2539 else
2540 {
2541 Mem_Free(dds);
2542 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
2543 return NULL;
2544 }
2545
2546 // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
2547 if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
2548 {
2549 textype = TEXTYPE_DXT1;
2550 bytesperblock = 8;
2551 ddssize -= 128;
2552 ddssize /= 2;
2553 for (i = 0;i < (int)ddssize;i += bytesperblock)
2554 memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
2555 ddssize += 128;
2556 }
2557
2558 force_swdecode = false;
2559 npothack =
2560 (!vid.support.arb_texture_non_power_of_two &&
2561 (
2562 (dds_width & (dds_width - 1))
2563 ||
2564 (dds_height & (dds_height - 1))
2565 )
2566 );
2567 if(bytesperblock)
2568 {
2569 if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && !npothack)
2570 {
2571 if(r_texture_dds_swdecode.integer > 1)
2572 force_swdecode = true;
2573 }
2574 else
2575 {
2576 if(r_texture_dds_swdecode.integer < 1)
2577 {
2578 // unsupported
2579 Mem_Free(dds);
2580 return NULL;
2581 }
2582 force_swdecode = true;
2583 }
2584 }
2585
2586 // return whether this texture is transparent
2587 if (hasalphaflag)
2588 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
2589
2590 // if we SW decode, choose 2 sizes bigger
2591 if(force_swdecode)
2592 {
2593 // this is quarter res, so do not scale down more than we have to
2594 miplevel -= 2;
2595
2596 if(miplevel < 0)
2597 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
2598 }
2599
2600 // this is where we apply gl_picmip
2601 mippixels_start = ddspixels;
2602 mipwidth = dds_width;
2603 mipheight = dds_height;
2604 while(miplevel >= 1 && dds_miplevels >= 1)
2605 {
2606 if (mipwidth <= 1 && mipheight <= 1)
2607 break;
2608 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2609 mippixels_start += mipsize; // just skip
2610 --dds_miplevels;
2611 --miplevel;
2612 if (mipwidth > 1)
2613 mipwidth >>= 1;
2614 if (mipheight > 1)
2615 mipheight >>= 1;
2616 }
2617 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
2618 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2619
2620 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
2621
2622 // fake decode S3TC if needed
2623 if(force_swdecode)
2624 {
2625 int mipsize_new = mipsize_total / bytesperblock * 4;
2626 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
2627 unsigned char *p = mipnewpixels;
2628 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
2629 {
2630 c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
2631 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2632 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
2633 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
2634 if(textype == TEXTYPE_DXT5)
2635 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
2636 else if(textype == TEXTYPE_DXT3)
2637 p[3] = (
2638 (mippixels_start[i-8] & 0x0F)
2639 + (mippixels_start[i-8] >> 4)
2640 + (mippixels_start[i-7] & 0x0F)
2641 + (mippixels_start[i-7] >> 4)
2642 + (mippixels_start[i-6] & 0x0F)
2643 + (mippixels_start[i-6] >> 4)
2644 + (mippixels_start[i-5] & 0x0F)
2645 + (mippixels_start[i-5] >> 4)
2646 ) * (0.125f / 15.0f * 255.0f);
2647 else
2648 p[3] = 255;
2649 }
2650
2651 textype = TEXTYPE_BGRA;
2652 bytesperblock = 0;
2653 bytesperpixel = 4;
2654
2655 // as each block becomes a pixel, we must use pixel count for this
2656 mipwidth = (mipwidth + 3) / 4;
2657 mipheight = (mipheight + 3) / 4;
2658 mipsize = bytesperpixel * mipwidth * mipheight;
2659 mippixels_start = mipnewpixels;
2660 mipsize_total = mipsize_new;
2661 }
2662
2663 // start mip counting
2664 mippixels = mippixels_start;
2665
2666 // calculate average color if requested
2667 if (avgcolor)
2668 {
2669 float f;
2670 Vector4Clear(avgcolor);
2671 if (bytesperblock)
2672 {
2673 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2674 {
2675 c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
2676 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2677 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2678 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2679 if(textype == TEXTYPE_DXT5)
2680 avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f);
2681 else if(textype == TEXTYPE_DXT3)
2682 avgcolor[3] += (
2683 (mippixels_start[i-8] & 0x0F)
2684 + (mippixels_start[i-8] >> 4)
2685 + (mippixels_start[i-7] & 0x0F)
2686 + (mippixels_start[i-7] >> 4)
2687 + (mippixels_start[i-6] & 0x0F)
2688 + (mippixels_start[i-6] >> 4)
2689 + (mippixels_start[i-5] & 0x0F)
2690 + (mippixels_start[i-5] >> 4)
2691 ) * (0.125f / 15.0f);
2692 else
2693 avgcolor[3] += 1.0f;
2694 }
2695 f = (float)bytesperblock / mipsize;
2696 avgcolor[0] *= (0.5f / 31.0f) * f;
2697 avgcolor[1] *= (0.5f / 63.0f) * f;
2698 avgcolor[2] *= (0.5f / 31.0f) * f;
2699 avgcolor[3] *= f;
2700 }
2701 else
2702 {
2703 for (i = 0;i < mipsize;i += 4)
2704 {
2705 avgcolor[0] += mippixels[i+2];
2706 avgcolor[1] += mippixels[i+1];
2707 avgcolor[2] += mippixels[i];
2708 avgcolor[3] += mippixels[i+3];
2709 }
2710 f = (1.0f / 255.0f) * bytesperpixel / mipsize;
2711 avgcolor[0] *= f;
2712 avgcolor[1] *= f;
2713 avgcolor[2] *= f;
2714 avgcolor[3] *= f;
2715 }
2716 }
2717
2718 // if we want sRGB, convert now
2719 if(srgb)
2720 {
2721 if (vid.support.ext_texture_srgb)
2722 {
2723 switch(textype)
2724 {
2725 case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break;
2726 case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break;
2727 case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break;
2728 case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break;
2729 case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break;
2730 default:
2731 break;
2732 }
2733 }
2734 else
2735 {
2736 switch(textype)
2737 {
2738 case TEXTYPE_DXT1:
2739 case TEXTYPE_DXT1A:
2740 case TEXTYPE_DXT3:
2741 case TEXTYPE_DXT5:
2742 {
2743 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2744 {
2745 int c0, c1, c0new, c1new;
2746 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2747 r = ((c0 >> 11) & 0x1F);
2748 g = ((c0 >> 5) & 0x3F);
2749 b = ((c0 ) & 0x1F);
2750 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2751 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2752 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2753 c0new = (r << 11) | (g << 5) | b;
2754 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2755 r = ((c1 >> 11) & 0x1F);
2756 g = ((c1 >> 5) & 0x3F);
2757 b = ((c1 ) & 0x1F);
2758 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2759 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2760 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2761 c1new = (r << 11) | (g << 5) | b;
2762 // swap the colors if needed to fix order
2763 if(c0 > c1) // thirds
2764 {
2765 if(c0new < c1new)
2766 {
2767 c = c0new;
2768 c0new = c1new;
2769 c1new = c;
2770 if(c0new == c1new)
2771 mippixels_start[i+4] ^= 0x55;
2772 mippixels_start[i+5] ^= 0x55;
2773 mippixels_start[i+6] ^= 0x55;
2774 mippixels_start[i+7] ^= 0x55;
2775 }
2776 else if(c0new == c1new)
2777 {
2778 mippixels_start[i+4] = 0x00;
2779 mippixels_start[i+5] = 0x00;
2780 mippixels_start[i+6] = 0x00;
2781 mippixels_start[i+7] = 0x00;
2782 }
2783 }
2784 else // half + transparent
2785 {
2786 if(c0new > c1new)
2787 {
2788 c = c0new;
2789 c0new = c1new;
2790 c1new = c;
2791 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2792 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2793 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2794 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2795 }
2796 }
2797 mippixels_start[i] = c0new & 255;
2798 mippixels_start[i+1] = c0new >> 8;
2799 mippixels_start[i+2] = c1new & 255;
2800 mippixels_start[i+3] = c1new >> 8;
2801 }
2802 }
2803 break;
2804 case TEXTYPE_RGBA:
2805 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2806 break;
2807 default:
2808 break;
2809 }
2810 }
2811 }
2812
2813 // when not requesting mipmaps, do not load them
2814 if(!(flags & TEXF_MIPMAP))
2815 dds_miplevels = 0;
2816
2817 if (dds_miplevels >= 1)
2818 flags |= TEXF_MIPMAP;
2819 else
2820 flags &= ~TEXF_MIPMAP;
2821
2822 texinfo = R_GetTexTypeInfo(textype, flags);
2823
2824 glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
2825 strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2826 glt->pool = pool;
2827 glt->chain = pool->gltchain;
2828 pool->gltchain = glt;
2829 glt->inputwidth = mipwidth;
2830 glt->inputheight = mipheight;
2831 glt->inputdepth = 1;
2832 glt->flags = flags;
2833 glt->textype = texinfo;
2834 glt->texturetype = GLTEXTURETYPE_2D;
2835 glt->inputdatasize = ddssize;
2836 glt->glinternalformat = texinfo->glinternalformat;
2837 glt->glformat = texinfo->glformat;
2838 glt->gltype = texinfo->gltype;
2839 glt->bytesperpixel = texinfo->internalbytesperpixel;
2840 glt->sides = 1;
2841 glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
2842 glt->tilewidth = mipwidth;
2843 glt->tileheight = mipheight;
2844 glt->tiledepth = 1;
2845 glt->miplevels = dds_miplevels;
2846
2847 if(npothack)
2848 {
2849 for (glt->tilewidth = 1;glt->tilewidth < mipwidth;glt->tilewidth <<= 1);
2850 for (glt->tileheight = 1;glt->tileheight < mipheight;glt->tileheight <<= 1);
2851 }
2852
2853 // texture uploading can take a while, so make sure we're sending keepalives
2854 CL_KeepaliveMessage(false);
2855
2856 // create the texture object
2857 switch(vid.renderpath)
2858 {
2859 case RENDERPATH_GL11:
2860 case RENDERPATH_GL13:
2861 case RENDERPATH_GL20:
2862 case RENDERPATH_GLES1:
2863 case RENDERPATH_GLES2:
2864 CHECKGLERROR
2865 GL_ActiveTexture(0);
2866 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2867 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2868 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2869 break;
2870 case RENDERPATH_D3D9:
2871 #ifdef SUPPORTD3D
2872 {
2873 D3DFORMAT d3dformat;
2874 D3DPOOL d3dpool;
2875 DWORD d3dusage;
2876 switch(textype)
2877 {
2878 case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2879 case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2880 case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2881 case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2882 default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2883 }
2884 d3dusage = 0;
2885 d3dpool = D3DPOOL_MANAGED;
2886 IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2887 }
2888 #endif
2889 break;
2890 case RENDERPATH_D3D10:
2891 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2892 break;
2893 case RENDERPATH_D3D11:
2894 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2895 break;
2896 case RENDERPATH_SOFT:
2897 glt->texnum = DPSOFTRAST_Texture_New(((glt->flags & TEXF_CLAMP) ? DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE : 0) | (dds_miplevels > 1 ? DPSOFTRAST_TEXTURE_FLAG_MIPMAP : 0), glt->tilewidth, glt->tileheight, glt->tiledepth);
2898 break;
2899 }
2900
2901 // upload the texture
2902 // we need to restore the texture binding after finishing the upload
2903 mipcomplete = false;
2904
2905 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2906 {
2907 unsigned char *upload_mippixels = mippixels;
2908 int upload_mipwidth = mipwidth;
2909 int upload_mipheight = mipheight;
2910 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2911 if (mippixels + mipsize > mippixels_start + mipsize_total)
2912 break;
2913 if(npothack)
2914 {
2915 upload_mipwidth = (glt->tilewidth >> mip);
2916 upload_mipheight = (glt->tileheight >> mip);
2917 if(upload_mipwidth != mipwidth || upload_mipheight != mipheight)
2918 // I _think_ they always mismatch, but I was too lazy
2919 // to properly check, and this test here is really
2920 // harmless
2921 {
2922 upload_mippixels = (unsigned char *) Mem_Alloc(tempmempool, 4 * upload_mipwidth * upload_mipheight);
2923 Image_Resample32(mippixels, mipwidth, mipheight, 1, upload_mippixels, upload_mipwidth, upload_mipheight, 1, r_lerpimages.integer);
2924 }
2925 }
2926 switch(vid.renderpath)
2927 {
2928 case RENDERPATH_GL11:
2929 case RENDERPATH_GL13:
2930 case RENDERPATH_GL20:
2931 case RENDERPATH_GLES1:
2932 case RENDERPATH_GLES2:
2933 if (bytesperblock)
2934 {
2935 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR
2936 }
2937 else
2938 {
2939 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR
2940 }
2941 break;
2942 case RENDERPATH_D3D9:
2943 #ifdef SUPPORTD3D
2944 {
2945 D3DLOCKED_RECT d3dlockedrect;
2946 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2947 {
2948 memcpy(d3dlockedrect.pBits, upload_mippixels, mipsize);
2949 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2950 }
2951 break;
2952 }
2953 #endif
2954 break;
2955 case RENDERPATH_D3D10:
2956 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2957 break;
2958 case RENDERPATH_D3D11:
2959 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2960 break;
2961 case RENDERPATH_SOFT:
2962 if (bytesperblock)
2963 Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2964 else
2965 DPSOFTRAST_Texture_UpdateFull(glt->texnum, upload_mippixels);
2966 // DPSOFTRAST calculates its own mipmaps
2967 mip = dds_miplevels;
2968 break;
2969 }
2970 if(upload_mippixels != mippixels)
2971 Mem_Free(upload_mippixels);
2972 mippixels += mipsize;
2973 if (mipwidth <= 1 && mipheight <= 1)
2974 {
2975 mipcomplete = true;
2976 break;
2977 }
2978 if (mipwidth > 1)
2979 mipwidth >>= 1;
2980 if (mipheight > 1)
2981 mipheight >>= 1;
2982 }
2983
2984 // after upload we have to set some parameters...
2985 switch(vid.renderpath)
2986 {
2987 case RENDERPATH_GL11:
2988 case RENDERPATH_GL13:
2989 case RENDERPATH_GL20:
2990 case RENDERPATH_GLES1:
2991 case RENDERPATH_GLES2:
2992 #ifdef GL_TEXTURE_MAX_LEVEL
2993 if (dds_miplevels >= 1 && !mipcomplete)
2994 {
2995 // need to set GL_TEXTURE_MAX_LEVEL
2996 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2997 }
2998 #endif
2999 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
3000 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
3001 break;
3002 case RENDERPATH_D3D9:
3003 #ifdef SUPPORTD3D
3004 glt->d3daddressw = 0;
3005 if (glt->flags & TEXF_CLAMP)
3006 {
3007 glt->d3daddressu = D3DTADDRESS_CLAMP;
3008 glt->d3daddressv = D3DTADDRESS_CLAMP;
3009 if (glt->tiledepth > 1)
3010 glt->d3daddressw = D3DTADDRESS_CLAMP;
3011 }
3012 else
3013 {
3014 glt->d3daddressu = D3DTADDRESS_WRAP;
3015 glt->d3daddressv = D3DTADDRESS_WRAP;
3016 if (glt->tiledepth > 1)
3017 glt->d3daddressw = D3DTADDRESS_WRAP;
3018 }
3019 glt->d3dmipmaplodbias = 0;
3020 glt->d3dmaxmiplevel = 0;
3021 glt->d3dmaxmiplevelfilter = 0;
3022 if (glt->flags & TEXF_MIPMAP)
3023 {
3024 glt->d3dminfilter = d3d_filter_mipmin;
3025 glt->d3dmagfilter = d3d_filter_mipmag;
3026 glt->d3dmipfilter = d3d_filter_mipmix;
3027 }
3028 else
3029 {
3030 glt->d3dminfilter = d3d_filter_flatmin;
3031 glt->d3dmagfilter = d3d_filter_flatmag;
3032 glt->d3dmipfilter = d3d_filter_flatmix;
3033 }
3034 #endif
3035 break;
3036 case RENDERPATH_D3D10:
3037 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3038 break;
3039 case RENDERPATH_D3D11:
3040 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3041 break;
3042 case RENDERPATH_SOFT:
3043 if (glt->flags & TEXF_FORCELINEAR)
3044 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR);
3045 else if (glt->flags & TEXF_FORCENEAREST)
3046 DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST);
3047 else if (glt->flags & TEXF_MIPMAP)
3048 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap);
3049 else
3050 DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap);
3051 break;
3052 }
3053
3054 Mem_Free(dds);
3055 if(force_swdecode)
3056 Mem_Free((unsigned char *) mippixels_start);
3057 return (rtexture_t *)glt;
3058 }
3059
R_TextureWidth(rtexture_t * rt)3060 int R_TextureWidth(rtexture_t *rt)
3061 {
3062 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
3063 }
3064
R_TextureHeight(rtexture_t * rt)3065 int R_TextureHeight(rtexture_t *rt)
3066 {
3067 return rt ? ((gltexture_t *)rt)->inputheight : 0;
3068 }
3069
R_TextureFlags(rtexture_t * rt)3070 int R_TextureFlags(rtexture_t *rt)
3071 {
3072 return rt ? ((gltexture_t *)rt)->flags : 0;
3073 }
3074
R_UpdateTexture(rtexture_t * rt,const unsigned char * data,int x,int y,int z,int width,int height,int depth)3075 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
3076 {
3077 gltexture_t *glt = (gltexture_t *)rt;
3078 if (data == NULL)
3079 Host_Error("R_UpdateTexture: no data supplied");
3080 if (glt == NULL)
3081 Host_Error("R_UpdateTexture: no texture supplied");
3082 if (!glt->texnum && !glt->d3dtexture)
3083 {
3084 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
3085 return;
3086 }
3087 // update part of the texture
3088 if (glt->bufferpixels)
3089 {
3090 int j;
3091 int bpp = glt->bytesperpixel;
3092 int inputskip = width*bpp;
3093 int outputskip = glt->tilewidth*bpp;
3094 const unsigned char *input = data;
3095 unsigned char *output = glt->bufferpixels;
3096 if (glt->inputdepth != 1 || glt->sides != 1)
3097 Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
3098 if (x < 0)
3099 {
3100 width += x;
3101 input -= x*bpp;
3102 x = 0;
3103 }
3104 if (y < 0)
3105 {
3106 height += y;
3107 input -= y*inputskip;
3108 y = 0;
3109 }
3110 if (width > glt->tilewidth - x)
3111 width = glt->tilewidth - x;
3112 if (height > glt->tileheight - y)
3113 height = glt->tileheight - y;
3114 if (width < 1 || height < 1)
3115 return;
3116 glt->dirty = true;
3117 glt->buffermodified = true;
3118 output += y*outputskip + x*bpp;
3119 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
3120 memcpy(output, input, width*bpp);
3121 }
3122 else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
3123 R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
3124 else
3125 R_UploadFullTexture(glt, data);
3126 }
3127
R_RealGetTexture(rtexture_t * rt)3128 int R_RealGetTexture(rtexture_t *rt)
3129 {
3130 if (rt)
3131 {
3132 gltexture_t *glt;
3133 glt = (gltexture_t *)rt;
3134 if (glt->flags & GLTEXF_DYNAMIC)
3135 R_UpdateDynamicTexture(glt);
3136 if (glt->buffermodified && glt->bufferpixels)
3137 {
3138 glt->buffermodified = false;
3139 R_UploadFullTexture(glt, glt->bufferpixels);
3140 }
3141 glt->dirty = false;
3142 return glt->texnum;
3143 }
3144 else
3145 return r_texture_white->texnum;
3146 }
3147
R_ClearTexture(rtexture_t * rt)3148 void R_ClearTexture (rtexture_t *rt)
3149 {
3150 gltexture_t *glt = (gltexture_t *)rt;
3151
3152 R_UploadFullTexture(glt, NULL);
3153 }
3154
R_PicmipForFlags(int flags)3155 int R_PicmipForFlags(int flags)
3156 {
3157 int miplevel = 0;
3158 if(flags & TEXF_PICMIP)
3159 {
3160 miplevel += gl_picmip.integer;
3161 if (flags & TEXF_ISWORLD)
3162 {
3163 if (r_picmipworld.integer)
3164 miplevel += gl_picmip_world.integer;
3165 else
3166 miplevel = 0;
3167 }
3168 else if (flags & TEXF_ISSPRITE)
3169 {
3170 if (r_picmipsprites.integer)
3171 miplevel += gl_picmip_sprites.integer;
3172 else
3173 miplevel = 0;
3174 }
3175 else
3176 miplevel += gl_picmip_other.integer;
3177 }
3178 return max(0, miplevel);
3179 }
3180