]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_textures.c
change R_Upload error from Host_error to Sys_Error, added texture name
[divverent/darkplaces.git] / gl_textures.c
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
12 cvar_t gl_max_size = {CVAR_SAVE, "gl_max_size", "2048", "maximum allowed texture size, can be used to reduce video memory usage, limited by hardware capabilities (typically 2048, 4096, or 8192)"};
13 cvar_t gl_max_lightmapsize = {CVAR_SAVE, "gl_max_lightmapsize", "1024", "maximum allowed texture size for lightmap textures, use larger values to improve rendering speed, as long as there is enough video memory available (setting it too high for the hardware will cause very bad performance)"};
14 cvar_t gl_picmip = {CVAR_SAVE, "gl_picmip", "0", "reduces resolution of textures by powers of 2, for example 1 will halve width/height, reducing texture memory usage by 75%"};
15 cvar_t gl_picmip_world = {CVAR_SAVE, "gl_picmip_world", "0", "extra picmip level for world textures (may be negative, which will then reduce gl_picmip for these)"};
16 cvar_t r_picmipworld = {CVAR_SAVE, "r_picmipworld", "1", "whether gl_picmip shall apply to world textures too (setting this to 0 is a shorthand for gl_picmip_world -9999999)"};
17 cvar_t gl_picmip_sprites = {CVAR_SAVE, "gl_picmip_sprites", "0", "extra picmip level for sprite textures (may be negative, which will then reduce gl_picmip for these)"};
18 cvar_t r_picmipsprites = {CVAR_SAVE, "r_picmipsprites", "1", "make gl_picmip affect sprites too (saves some graphics memory in sprite heavy games) (setting this to 0 is a shorthand for gl_picmip_sprites -9999999)"};
19 cvar_t gl_picmip_other = {CVAR_SAVE, "gl_picmip_other", "0", "extra picmip level for other textures (may be negative, which will then reduce gl_picmip for these)"};
20 cvar_t r_lerpimages = {CVAR_SAVE, "r_lerpimages", "1", "bilinear filters images when scaling them up to power of 2 size (mode 1), looks better than glquake (mode 0)"};
21 cvar_t gl_texture_anisotropy = {CVAR_SAVE, "gl_texture_anisotropy", "1", "anisotropic filtering quality (if supported by hardware), 1 sample (no anisotropy) and 8 sample (8 tap anisotropy) are recommended values"};
22 cvar_t gl_texturecompression = {CVAR_SAVE, "gl_texturecompression", "0", "whether to compress textures, a value of 0 disables compression (even if the individual cvars are 1), 1 enables fast (low quality) compression at startup, 2 enables slow (high quality) compression at startup"};
23 cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
24 cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
25 cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
26 cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
27 cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
28 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
29 cvar_t gl_texturecompression_q3bspdeluxemaps = {CVAR_SAVE, "gl_texturecompression_q3bspdeluxemaps", "0", "whether to compress deluxemaps in q3bsp format levels (only levels compiled with q3map2 -deluxe have these)"};
30 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
31 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
32 cvar_t gl_texturecompression_reflectmask = {CVAR_SAVE, "gl_texturecompression_reflectmask", "1", "whether to compress reflection cubemap masks (mask of which areas of the texture should reflect the generic shiny cubemap)"};
33 cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "1", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"};
34 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 ambigous, 2: texture format only"};
35
36 qboolean        gl_filter_force = false;
37 int             gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
38 int             gl_filter_mag = GL_LINEAR;
39
40 #ifdef SUPPORTD3D
41 int d3d_filter_flatmin = D3DTEXF_LINEAR;
42 int d3d_filter_flatmag = D3DTEXF_LINEAR;
43 int d3d_filter_flatmix = D3DTEXF_POINT;
44 int d3d_filter_mipmin = D3DTEXF_LINEAR;
45 int d3d_filter_mipmag = D3DTEXF_LINEAR;
46 int d3d_filter_mipmix = D3DTEXF_LINEAR;
47 int d3d_filter_nomip = false;
48 #endif
49
50
51 static mempool_t *texturemempool;
52 static memexpandablearray_t texturearray;
53
54 // note: this must not conflict with TEXF_ flags in r_textures.h
55 // bitmask for mismatch checking
56 #define GLTEXF_IMPORTANTBITS (0)
57 // dynamic texture (treat texnum == 0 differently)
58 #define GLTEXF_DYNAMIC          0x00080000
59
60 typedef struct textypeinfo_s
61 {
62         textype_t textype;
63         int inputbytesperpixel;
64         int internalbytesperpixel;
65         float glinternalbytesperpixel;
66         int glinternalformat;
67         int glformat;
68         int gltype;
69 }
70 textypeinfo_t;
71
72
73 static textypeinfo_t textype_palette                = {TEXTYPE_PALETTE    , 1, 4, 4.0f, 3                               , GL_BGRA           , GL_UNSIGNED_BYTE };
74 static textypeinfo_t textype_palette_alpha          = {TEXTYPE_PALETTE    , 1, 4, 4.0f, 4                               , GL_BGRA           , GL_UNSIGNED_BYTE };
75 static textypeinfo_t textype_rgba                   = {TEXTYPE_RGBA       , 4, 4, 4.0f, 3                               , GL_RGBA           , GL_UNSIGNED_BYTE };
76 static textypeinfo_t textype_rgba_alpha             = {TEXTYPE_RGBA       , 4, 4, 4.0f, 4                               , GL_RGBA           , GL_UNSIGNED_BYTE };
77 static textypeinfo_t textype_rgba_compress          = {TEXTYPE_RGBA       , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA           , GL_UNSIGNED_BYTE };
78 static textypeinfo_t textype_rgba_alpha_compress    = {TEXTYPE_RGBA       , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA           , GL_UNSIGNED_BYTE };
79 static textypeinfo_t textype_bgra                   = {TEXTYPE_BGRA       , 4, 4, 4.0f, 3                               , GL_BGRA           , GL_UNSIGNED_BYTE };
80 static textypeinfo_t textype_bgra_alpha             = {TEXTYPE_BGRA       , 4, 4, 4.0f, 4                               , GL_BGRA           , GL_UNSIGNED_BYTE };
81 static textypeinfo_t textype_bgra_compress          = {TEXTYPE_BGRA       , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA           , GL_UNSIGNED_BYTE };
82 static textypeinfo_t textype_bgra_alpha_compress    = {TEXTYPE_BGRA       , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_BGRA           , GL_UNSIGNED_BYTE };
83 static textypeinfo_t textype_shadowmap16            = {TEXTYPE_SHADOWMAP  , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB        , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
84 static textypeinfo_t textype_shadowmap24            = {TEXTYPE_SHADOWMAP  , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB        , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
85 static textypeinfo_t textype_alpha                  = {TEXTYPE_ALPHA      , 1, 4, 4.0f, GL_ALPHA                        , GL_ALPHA          , GL_UNSIGNED_BYTE };
86 static textypeinfo_t textype_dxt1                   = {TEXTYPE_DXT1       , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0                 , 0                };
87 static textypeinfo_t textype_dxt1a                  = {TEXTYPE_DXT1A      , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0                 , 0                };
88 static textypeinfo_t textype_dxt3                   = {TEXTYPE_DXT3       , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0                 , 0                };
89 static textypeinfo_t textype_dxt5                   = {TEXTYPE_DXT5       , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0                 , 0                };
90 static textypeinfo_t textype_colorbuffer            = {TEXTYPE_COLORBUFFER, 4, 4, 4.0f, 4                               , GL_BGRA           , GL_UNSIGNED_BYTE };
91
92
93 typedef enum gltexturetype_e
94 {
95         GLTEXTURETYPE_2D,
96         GLTEXTURETYPE_3D,
97         GLTEXTURETYPE_CUBEMAP,
98         GLTEXTURETYPE_RECTANGLE,
99         GLTEXTURETYPE_TOTAL
100 }
101 gltexturetype_t;
102
103 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_RECTANGLE_ARB};
104 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2, 2};
105 static int cubemapside[6] =
106 {
107         GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
108         GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
109         GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
110         GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
111         GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
112         GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
113 };
114
115 typedef struct gltexture_s
116 {
117         // this portion of the struct is exposed to the R_GetTexture macro for
118         // speed reasons, must be identical in rtexture_t!
119         int texnum; // GL texture slot number
120         qboolean dirty; // indicates that R_RealGetTexture should be called
121         int gltexturetypeenum; // used by R_Mesh_TexBind
122         // d3d stuff the backend needs
123         void *d3dtexture;
124 #ifdef SUPPORTD3D
125         int d3dformat;
126         int d3dusage;
127         int d3dpool;
128         int d3daddressu;
129         int d3daddressv;
130         int d3daddressw;
131         int d3dmagfilter;
132         int d3dminfilter;
133         int d3dmipfilter;
134         int d3dmaxmiplevelfilter;
135         int d3dmipmaplodbias;
136         int d3dmaxmiplevel;
137 #endif
138
139         // dynamic texture stuff [11/22/2007 Black]
140         updatecallback_t updatecallback;
141         void *updatacallback_data;
142         // --- [11/22/2007 Black]
143
144         // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
145         unsigned char *bufferpixels;
146         qboolean buffermodified;
147
148         // pointer to texturepool (check this to see if the texture is allocated)
149         struct gltexturepool_s *pool;
150         // pointer to next texture in texturepool chain
151         struct gltexture_s *chain;
152         // name of the texture (this might be removed someday), no duplicates
153         char identifier[MAX_QPATH + 32];
154         // original data size in *inputtexels
155         int inputwidth, inputheight, inputdepth;
156         // copy of the original texture(s) supplied to the upload function, for
157         // delayed uploads (non-precached)
158         unsigned char *inputtexels;
159         // original data size in *inputtexels
160         int inputdatasize;
161         // flags supplied to the LoadTexture function
162         // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
163         int flags;
164         // picmip level
165         int miplevel;
166         // pointer to one of the textype_ structs
167         textypeinfo_t *textype;
168         // one of the GLTEXTURETYPE_ values
169         int texturetype;
170         // palette if the texture is TEXTYPE_PALETTE
171         const unsigned int *palette;
172         // actual stored texture size after gl_picmip and gl_max_size are applied
173         // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
174         int tilewidth, tileheight, tiledepth;
175         // 1 or 6 depending on texturetype
176         int sides;
177         // how many mipmap levels in this texture
178         int miplevels;
179         // bytes per pixel
180         int bytesperpixel;
181         // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
182         int glformat;
183         // 3 or 4
184         int glinternalformat;
185         // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
186         int gltype;
187 }
188 gltexture_t;
189
190 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
191
192 typedef struct gltexturepool_s
193 {
194         unsigned int sentinel;
195         struct gltexture_s *gltchain;
196         struct gltexturepool_s *next;
197 }
198 gltexturepool_t;
199
200 static gltexturepool_t *gltexturepoolchain = NULL;
201
202 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
203 static int resizebuffersize = 0;
204 static const unsigned char *texturebuffer;
205
206 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
207 {
208         switch(textype)
209         {
210         case TEXTYPE_DXT1:
211                 return &textype_dxt1;
212         case TEXTYPE_DXT1A:
213                 return &textype_dxt1a;
214         case TEXTYPE_DXT3:
215                 return &textype_dxt3;
216         case TEXTYPE_DXT5:
217                 return &textype_dxt5;
218         case TEXTYPE_PALETTE:
219                 return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
220         case TEXTYPE_RGBA:
221                 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
222                         return (flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress;
223                 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba;
224         case TEXTYPE_BGRA:
225                 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc)
226                         return (flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress;
227                 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra;
228         case TEXTYPE_ALPHA:
229                 return &textype_alpha;
230         case TEXTYPE_SHADOWMAP:
231                 return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
232         case TEXTYPE_COLORBUFFER:
233                 return &textype_colorbuffer;
234         default:
235                 Host_Error("R_GetTexTypeInfo: unknown texture format");
236                 break;
237         }
238         return NULL;
239 }
240
241 // dynamic texture code [11/22/2007 Black]
242 void R_MarkDirtyTexture(rtexture_t *rt) {
243         gltexture_t *glt = (gltexture_t*) rt;
244         if( !glt ) {
245                 return;
246         }
247
248         // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
249         if (glt->flags & GLTEXF_DYNAMIC)
250         {
251                 // mark it as dirty, so R_RealGetTexture gets called
252                 glt->dirty = true;
253         }
254 }
255
256 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
257         gltexture_t *glt = (gltexture_t*) rt;
258         if( !glt ) {
259                 return;
260         }
261
262         glt->flags |= GLTEXF_DYNAMIC;
263         glt->updatecallback = updatecallback;
264         glt->updatacallback_data = data;
265 }
266
267 static void R_UpdateDynamicTexture(gltexture_t *glt) {
268         glt->dirty = false;
269         if( glt->updatecallback ) {
270                 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
271         }
272 }
273
274 void R_PurgeTexture(rtexture_t *rt)
275 {
276         if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
277                 R_FreeTexture(rt);
278         }
279 }
280
281 void R_FreeTexture(rtexture_t *rt)
282 {
283         gltexture_t *glt, **gltpointer;
284
285         glt = (gltexture_t *)rt;
286         if (glt == NULL)
287                 Host_Error("R_FreeTexture: texture == NULL");
288
289         for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
290         if (*gltpointer == glt)
291                 *gltpointer = glt->chain;
292         else
293                 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
294
295         if (glt->texnum)
296         {
297                 CHECKGLERROR
298                 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
299         }
300
301         if (glt->inputtexels)
302                 Mem_Free(glt->inputtexels);
303         Mem_ExpandableArray_FreeRecord(&texturearray, glt);
304 }
305
306 rtexturepool_t *R_AllocTexturePool(void)
307 {
308         gltexturepool_t *pool;
309         if (texturemempool == NULL)
310                 return NULL;
311         pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
312         if (pool == NULL)
313                 return NULL;
314         pool->next = gltexturepoolchain;
315         gltexturepoolchain = pool;
316         pool->sentinel = TEXTUREPOOL_SENTINEL;
317         return (rtexturepool_t *)pool;
318 }
319
320 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
321 {
322         gltexturepool_t *pool, **poolpointer;
323         if (rtexturepool == NULL)
324                 return;
325         if (*rtexturepool == NULL)
326                 return;
327         pool = (gltexturepool_t *)(*rtexturepool);
328         *rtexturepool = NULL;
329         if (pool->sentinel != TEXTUREPOOL_SENTINEL)
330                 Host_Error("R_FreeTexturePool: pool already freed");
331         for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
332         if (*poolpointer == pool)
333                 *poolpointer = pool->next;
334         else
335                 Host_Error("R_FreeTexturePool: pool not linked");
336         while (pool->gltchain)
337                 R_FreeTexture((rtexture_t *)pool->gltchain);
338         Mem_Free(pool);
339 }
340
341
342 typedef struct glmode_s
343 {
344         const char *name;
345         int minification, magnification;
346 }
347 glmode_t;
348
349 static glmode_t modes[6] =
350 {
351         {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
352         {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
353         {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
354         {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
355         {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
356         {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
357 };
358
359 #ifdef SUPPORTD3D
360 typedef struct d3dmode_s
361 {
362         const char *name;
363         int m1, m2;
364 }
365 d3dmode_t;
366
367 static d3dmode_t d3dmodes[6] =
368 {
369         {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
370         {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
371         {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
372         {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
373         {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
374         {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
375 };
376 #endif
377
378 static void GL_TextureMode_f (void)
379 {
380         int i;
381         GLint oldbindtexnum;
382         gltexture_t *glt;
383         gltexturepool_t *pool;
384
385         if (Cmd_Argc() == 1)
386         {
387                 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
388                 for (i = 0;i < 6;i++)
389                 {
390                         if (gl_filter_min == modes[i].minification)
391                         {
392                                 Con_Printf("%s\n", modes[i].name);
393                                 return;
394                         }
395                 }
396                 Con_Print("current filter is unknown???\n");
397                 return;
398         }
399
400         for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
401                 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
402                         break;
403         if (i == 6)
404         {
405                 Con_Print("bad filter name\n");
406                 return;
407         }
408
409         gl_filter_min = modes[i].minification;
410         gl_filter_mag = modes[i].magnification;
411         gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
412
413         switch(vid.renderpath)
414         {
415         case RENDERPATH_GL11:
416         case RENDERPATH_GL13:
417         case RENDERPATH_GL20:
418         case RENDERPATH_CGGL:
419                 // change all the existing mipmap texture objects
420                 // FIXME: force renderer(/client/something?) restart instead?
421                 CHECKGLERROR
422                 GL_ActiveTexture(0);
423                 for (pool = gltexturepoolchain;pool;pool = pool->next)
424                 {
425                         for (glt = pool->gltchain;glt;glt = glt->chain)
426                         {
427                                 // only update already uploaded images
428                                 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
429                                 {
430                                         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
431                                         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
432                                         if (glt->flags & TEXF_MIPMAP)
433                                         {
434                                                 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
435                                         }
436                                         else
437                                         {
438                                                 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
439                                         }
440                                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
441                                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
442                                 }
443                         }
444                 }
445                 break;
446         case RENDERPATH_D3D9:
447 #ifdef SUPPORTD3D
448                 d3d_filter_flatmin = d3dmodes[i].m1;
449                 d3d_filter_flatmag = d3dmodes[i].m1;
450                 d3d_filter_flatmix = D3DTEXF_POINT;
451                 d3d_filter_mipmin = d3dmodes[i].m1;
452                 d3d_filter_mipmag = d3dmodes[i].m1;
453                 d3d_filter_mipmix = d3dmodes[i].m2;
454                 d3d_filter_nomip = i < 2;
455                 if (gl_texture_anisotropy.integer > 1 && i == 5)
456                         d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
457                 for (pool = gltexturepoolchain;pool;pool = pool->next)
458                 {
459                         for (glt = pool->gltchain;glt;glt = glt->chain)
460                         {
461                                 // only update already uploaded images
462                                 if (glt->d3dtexture && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
463                                 {
464                                         if (glt->flags & TEXF_MIPMAP)
465                                         {
466                                                 glt->d3dminfilter = d3d_filter_mipmin;
467                                                 glt->d3dmagfilter = d3d_filter_mipmag;
468                                                 glt->d3dmipfilter = d3d_filter_mipmix;
469                                                 glt->d3dmaxmiplevelfilter = 0;
470                                         }
471                                         else
472                                         {
473                                                 glt->d3dminfilter = d3d_filter_flatmin;
474                                                 glt->d3dmagfilter = d3d_filter_flatmag;
475                                                 glt->d3dmipfilter = d3d_filter_flatmix;
476                                                 glt->d3dmaxmiplevelfilter = 0;
477                                         }
478                                 }
479                         }
480                 }
481 #endif
482                 break;
483         case RENDERPATH_D3D10:
484                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
485                 break;
486         case RENDERPATH_D3D11:
487                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
488                 break;
489         }
490 }
491
492 static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, int inwidth, int inheight, int indepth, int *outwidth, int *outheight, int *outdepth, int *outmiplevels)
493 {
494         int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
495
496         switch (texturetype)
497         {
498         default:
499         case GLTEXTURETYPE_2D:
500                 maxsize = vid.maxtexturesize_2d;
501                 if (flags & TEXF_PICMIP)
502                 {
503                         maxsize = bound(1, gl_max_size.integer, maxsize);
504                         picmip = miplevel;
505                 }
506                 break;
507         case GLTEXTURETYPE_3D:
508                 maxsize = vid.maxtexturesize_3d;
509                 break;
510         case GLTEXTURETYPE_CUBEMAP:
511                 maxsize = vid.maxtexturesize_cubemap;
512                 break;
513         }
514
515         if (outwidth)
516         {
517                 if (vid.support.arb_texture_non_power_of_two)
518                         width2 = min(inwidth >> picmip, maxsize);
519                 else
520                 {
521                         for (width2 = 1;width2 < inwidth;width2 <<= 1);
522                         for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
523                 }
524                 *outwidth = max(1, width2);
525         }
526         if (outheight)
527         {
528                 if (vid.support.arb_texture_non_power_of_two)
529                         height2 = min(inheight >> picmip, maxsize);
530                 else
531                 {
532                         for (height2 = 1;height2 < inheight;height2 <<= 1);
533                         for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
534                 }
535                 *outheight = max(1, height2);
536         }
537         if (outdepth)
538         {
539                 if (vid.support.arb_texture_non_power_of_two)
540                         depth2 = min(indepth >> picmip, maxsize);
541                 else
542                 {
543                         for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
544                         for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
545                 }
546                 *outdepth = max(1, depth2);
547         }
548
549         miplevels = 1;
550         if (flags & TEXF_MIPMAP)
551         {
552                 int extent = max(width2, max(height2, depth2));
553                 while(extent >>= 1)
554                         miplevels++;
555         }
556         if (outmiplevels)
557                 *outmiplevels = miplevels;
558 }
559
560
561 static int R_CalcTexelDataSize (gltexture_t *glt)
562 {
563         int width2, height2, depth2, size;
564
565         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
566
567         size = width2 * height2 * depth2;
568
569         if (glt->flags & TEXF_MIPMAP)
570         {
571                 while (width2 > 1 || height2 > 1 || depth2 > 1)
572                 {
573                         if (width2 > 1)
574                                 width2 >>= 1;
575                         if (height2 > 1)
576                                 height2 >>= 1;
577                         if (depth2 > 1)
578                                 depth2 >>= 1;
579                         size += width2 * height2 * depth2;
580                 }
581         }
582
583         return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
584 }
585
586 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
587 {
588         int glsize;
589         int isloaded;
590         int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
591         int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
592         gltexture_t *glt;
593         gltexturepool_t *pool;
594         if (printeach)
595                 Con_Print("glsize input loaded mip alpha name\n");
596         for (pool = gltexturepoolchain;pool;pool = pool->next)
597         {
598                 pooltotal = 0;
599                 pooltotalt = 0;
600                 pooltotalp = 0;
601                 poolloaded = 0;
602                 poolloadedt = 0;
603                 poolloadedp = 0;
604                 for (glt = pool->gltchain;glt;glt = glt->chain)
605                 {
606                         glsize = R_CalcTexelDataSize(glt);
607                         isloaded = glt->texnum != 0;
608                         pooltotal++;
609                         pooltotalt += glsize;
610                         pooltotalp += glt->inputdatasize;
611                         if (isloaded)
612                         {
613                                 poolloaded++;
614                                 poolloadedt += glsize;
615                                 poolloadedp += glt->inputdatasize;
616                         }
617                         if (printeach)
618                                 Con_Printf("%c%4i%c%c%4i%c %s %s %s %s\n", isloaded ? '[' : ' ', (glsize + 1023) / 1024, isloaded ? ']' : ' ', glt->inputtexels ? '[' : ' ', (glt->inputdatasize + 1023) / 1024, glt->inputtexels ? ']' : ' ', isloaded ? "loaded" : "      ", (glt->flags & TEXF_MIPMAP) ? "mip" : "   ", (glt->flags & TEXF_ALPHA) ? "alpha" : "     ", glt->identifier);
619                 }
620                 if (printpool)
621                         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);
622                 sumtotal += pooltotal;
623                 sumtotalt += pooltotalt;
624                 sumtotalp += pooltotalp;
625                 sumloaded += poolloaded;
626                 sumloadedt += poolloadedt;
627                 sumloadedp += poolloadedp;
628         }
629         if (printtotal)
630                 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);
631 }
632
633 static void R_TextureStats_f(void)
634 {
635         R_TextureStats_Print(true, true, true);
636 }
637
638 static void r_textures_start(void)
639 {
640         switch(vid.renderpath)
641         {
642         case RENDERPATH_GL11:
643         case RENDERPATH_GL13:
644         case RENDERPATH_GL20:
645         case RENDERPATH_CGGL:
646                 // LordHavoc: allow any alignment
647                 CHECKGLERROR
648                 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
649                 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
650                 break;
651         case RENDERPATH_D3D9:
652                 break;
653         case RENDERPATH_D3D10:
654                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
655                 break;
656         case RENDERPATH_D3D11:
657                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
658                 break;
659         }
660
661         texturemempool = Mem_AllocPool("texture management", 0, NULL);
662         Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
663
664         // Disable JPEG screenshots if the DLL isn't loaded
665         if (! JPEG_OpenLibrary ())
666                 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
667         if (! PNG_OpenLibrary ())
668                 Cvar_SetValueQuick (&scr_screenshot_png, 0);
669 }
670
671 static void r_textures_shutdown(void)
672 {
673         rtexturepool_t *temp;
674
675         JPEG_CloseLibrary ();
676
677         while(gltexturepoolchain)
678         {
679                 temp = (rtexturepool_t *) gltexturepoolchain;
680                 R_FreeTexturePool(&temp);
681         }
682
683         resizebuffersize = 0;
684         resizebuffer = NULL;
685         colorconvertbuffer = NULL;
686         texturebuffer = NULL;
687         Mem_ExpandableArray_FreeArray(&texturearray);
688         Mem_FreePool(&texturemempool);
689 }
690
691 static void r_textures_newmap(void)
692 {
693 }
694
695 static void r_textures_devicelost(void)
696 {
697         int i, endindex;
698         gltexture_t *glt;
699         endindex = Mem_ExpandableArray_IndexRange(&texturearray);
700         for (i = 0;i < endindex;i++)
701         {
702                 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
703                 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
704                         continue;
705                 switch(vid.renderpath)
706                 {
707                 case RENDERPATH_GL11:
708                 case RENDERPATH_GL13:
709                 case RENDERPATH_GL20:
710                 case RENDERPATH_CGGL:
711                         break;
712                 case RENDERPATH_D3D9:
713 #ifdef SUPPORTD3D
714                         if (glt->tiledepth > 1)
715                                 IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
716                         else if (glt->sides == 6)
717                                 IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
718                         else
719                                 IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
720                         glt->d3dtexture = NULL;
721 #endif
722                         break;
723                 case RENDERPATH_D3D10:
724                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
725                         break;
726                 case RENDERPATH_D3D11:
727                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
728                         break;
729                 }
730         }
731 }
732
733 static void r_textures_devicerestored(void)
734 {
735         int i, endindex;
736         gltexture_t *glt;
737         endindex = Mem_ExpandableArray_IndexRange(&texturearray);
738         for (i = 0;i < endindex;i++)
739         {
740                 glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
741                 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
742                         continue;
743                 switch(vid.renderpath)
744                 {
745                 case RENDERPATH_GL11:
746                 case RENDERPATH_GL13:
747                 case RENDERPATH_GL20:
748                 case RENDERPATH_CGGL:
749                         break;
750                 case RENDERPATH_D3D9:
751 #ifdef SUPPORTD3D
752                         {
753                                 HRESULT d3dresult;
754                                 if (glt->tiledepth > 1)
755                                 {
756                                         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)))
757                                                 Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
758                                 }
759                                 else if (glt->sides == 6)
760                                 {
761                                         if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
762                                                 Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
763                                 }
764                                 else
765                                 {
766                                         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)))
767                                                 Sys_Error("IDirect3DDevice9_CreateTexture failed!");
768                                 }
769                         }
770 #endif
771                         break;
772                 case RENDERPATH_D3D10:
773                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
774                         break;
775                 case RENDERPATH_D3D11:
776                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
777                         break;
778                 }
779         }
780 }
781
782
783 void R_Textures_Init (void)
784 {
785         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");
786         Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
787         Cvar_RegisterVariable (&gl_max_size);
788         Cvar_RegisterVariable (&gl_picmip);
789         Cvar_RegisterVariable (&gl_picmip_world);
790         Cvar_RegisterVariable (&r_picmipworld);
791         Cvar_RegisterVariable (&gl_picmip_sprites);
792         Cvar_RegisterVariable (&r_picmipsprites);
793         Cvar_RegisterVariable (&gl_picmip_other);
794         Cvar_RegisterVariable (&gl_max_lightmapsize);
795         Cvar_RegisterVariable (&r_lerpimages);
796         Cvar_RegisterVariable (&gl_texture_anisotropy);
797         Cvar_RegisterVariable (&gl_texturecompression);
798         Cvar_RegisterVariable (&gl_texturecompression_color);
799         Cvar_RegisterVariable (&gl_texturecompression_normal);
800         Cvar_RegisterVariable (&gl_texturecompression_gloss);
801         Cvar_RegisterVariable (&gl_texturecompression_glow);
802         Cvar_RegisterVariable (&gl_texturecompression_2d);
803         Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
804         Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
805         Cvar_RegisterVariable (&gl_texturecompression_sky);
806         Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
807         Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
808         Cvar_RegisterVariable (&gl_nopartialtextureupdates);
809         Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
810
811         R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
812 }
813
814 void R_Textures_Frame (void)
815 {
816         static int old_aniso = 0;
817
818         // could do procedural texture animation here, if we keep track of which
819         // textures were accessed this frame...
820
821         // free the resize buffers
822         resizebuffersize = 0;
823         if (resizebuffer)
824         {
825                 Mem_Free(resizebuffer);
826                 resizebuffer = NULL;
827         }
828         if (colorconvertbuffer)
829         {
830                 Mem_Free(colorconvertbuffer);
831                 colorconvertbuffer = NULL;
832         }
833
834         if (old_aniso != gl_texture_anisotropy.integer)
835         {
836                 gltexture_t *glt;
837                 gltexturepool_t *pool;
838                 GLint oldbindtexnum;
839
840                 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
841
842                 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
843
844                 switch(vid.renderpath)
845                 {
846                 case RENDERPATH_GL11:
847                 case RENDERPATH_GL13:
848                 case RENDERPATH_GL20:
849                 case RENDERPATH_CGGL:
850                         CHECKGLERROR
851                         GL_ActiveTexture(0);
852                         for (pool = gltexturepoolchain;pool;pool = pool->next)
853                         {
854                                 for (glt = pool->gltchain;glt;glt = glt->chain)
855                                 {
856                                         // only update already uploaded images
857                                         if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
858                                         {
859                                                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
860
861                                                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
862                                                 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
863
864                                                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
865                                         }
866                                 }
867                         }
868                         break;
869                 case RENDERPATH_D3D9:
870                 case RENDERPATH_D3D10:
871                 case RENDERPATH_D3D11:
872                         break;
873                 }
874         }
875 }
876
877 void R_MakeResizeBufferBigger(int size)
878 {
879         if (resizebuffersize < size)
880         {
881                 resizebuffersize = size;
882                 if (resizebuffer)
883                         Mem_Free(resizebuffer);
884                 if (colorconvertbuffer)
885                         Mem_Free(colorconvertbuffer);
886                 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
887                 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
888                 if (!resizebuffer || !colorconvertbuffer)
889                         Host_Error("R_Upload: out of memory");
890         }
891 }
892
893 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
894 {
895         int textureenum = gltexturetypeenums[texturetype];
896         int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
897
898         CHECKGLERROR
899
900         if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
901         {
902                 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
903                 if (gl_texture_anisotropy.integer != aniso)
904                         Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
905                 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
906         }
907         qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
908         qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
909         if (gltexturetypedimensions[texturetype] >= 3)
910         {
911                 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
912         }
913
914         CHECKGLERROR
915         if (!gl_filter_force && flags & TEXF_FORCENEAREST)
916         {
917                 if (flags & TEXF_MIPMAP)
918                 {
919                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
920                 }
921                 else
922                 {
923                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
924                 }
925                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
926         }
927         else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
928         {
929                 if (flags & TEXF_MIPMAP)
930                 {
931                         if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
932                         {
933                                 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
934                         }
935                         else
936                         {
937                                 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
938                         }
939                 }
940                 else
941                 {
942                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
943                 }
944                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
945         }
946         else
947         {
948                 if (flags & TEXF_MIPMAP)
949                 {
950                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
951                 }
952                 else
953                 {
954                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
955                 }
956                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
957         }
958
959         if (textype == TEXTYPE_SHADOWMAP)
960         {
961                 if (vid.support.arb_shadow)
962                 {
963                         if (flags & TEXF_COMPARE)
964                         {
965                                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
966                         }
967                         else
968                         {
969                                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
970                         }
971                         qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
972                 }
973                 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
974         }
975
976         CHECKGLERROR
977 }
978
979 static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
980 {
981         int i, mip, width, height, depth;
982         GLint oldbindtexnum = 0;
983         const unsigned char *prevbuffer;
984         prevbuffer = data;
985
986         switch(vid.renderpath)
987         {
988         case RENDERPATH_GL11:
989         case RENDERPATH_GL13:
990         case RENDERPATH_GL20:
991         case RENDERPATH_CGGL:
992                 CHECKGLERROR
993
994                 // we need to restore the texture binding after finishing the upload
995                 GL_ActiveTexture(0);
996                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
997                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
998                 break;
999         case RENDERPATH_D3D9:
1000         case RENDERPATH_D3D10:
1001         case RENDERPATH_D3D11:
1002                 break;
1003         }
1004
1005         // these are rounded up versions of the size to do better resampling
1006         if (vid.support.arb_texture_non_power_of_two || glt->texturetype == GLTEXTURETYPE_RECTANGLE)
1007         {
1008                 width = glt->inputwidth;
1009                 height = glt->inputheight;
1010                 depth = glt->inputdepth;
1011         }
1012         else
1013         {
1014                 for (width  = 1;width  < glt->inputwidth ;width  <<= 1);
1015                 for (height = 1;height < glt->inputheight;height <<= 1);
1016                 for (depth  = 1;depth  < glt->inputdepth ;depth  <<= 1);
1017         }
1018
1019         R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
1020         R_MakeResizeBufferBigger(fragwidth * fragheight * fragdepth * glt->sides * glt->bytesperpixel);
1021
1022         if (prevbuffer == NULL)
1023         {
1024                 memset(resizebuffer, 0, fragwidth * fragheight * fragdepth * glt->bytesperpixel);
1025                 prevbuffer = resizebuffer;
1026         }
1027         else if (glt->textype->textype == TEXTYPE_PALETTE)
1028         {
1029                 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
1030                 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, fragwidth * fragheight * fragdepth * glt->sides, glt->palette);
1031                 prevbuffer = colorconvertbuffer;
1032         }
1033
1034         // upload the image - preferring to do only complete uploads (drivers do not really like partial updates)
1035
1036         if ((glt->flags & (TEXF_MIPMAP | TEXF_PICMIP)) == 0 && glt->inputwidth == glt->tilewidth && glt->inputheight == glt->tileheight && glt->inputdepth == glt->tiledepth && (fragx != 0 || fragy != 0 || fragwidth != glt->tilewidth || fragheight != glt->tileheight))
1037         {
1038                 // update a portion of the image
1039                 if (glt->texturetype != GLTEXTURETYPE_2D)
1040                         Sys_Error("R_Upload: partial update of type other than 2D");
1041                 switch(vid.renderpath)
1042                 {
1043                 case RENDERPATH_GL11:
1044                 case RENDERPATH_GL13:
1045                 case RENDERPATH_GL20:
1046                 case RENDERPATH_CGGL:
1047                         qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1048                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1049                         break;
1050                 case RENDERPATH_D3D9:
1051 #ifdef SUPPORTD3D
1052                         {
1053                                 RECT d3drect;
1054                                 D3DLOCKED_RECT d3dlockedrect;
1055                                 int y;
1056                                 memset(&d3drect, 0, sizeof(d3drect));
1057                                 d3drect.left = fragx;
1058                                 d3drect.top = fragy;
1059                                 d3drect.right = fragx+fragwidth;
1060                                 d3drect.bottom = fragy+fragheight;
1061                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
1062                                 {
1063                                         for (y = 0;y < fragheight;y++)
1064                                                 memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, (unsigned char *)prevbuffer + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
1065                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
1066                                 }
1067                         }
1068 #endif
1069                         break;
1070                 case RENDERPATH_D3D10:
1071                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1072                         break;
1073                 case RENDERPATH_D3D11:
1074                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1075                         break;
1076                 }
1077         }
1078         else
1079         {
1080                 if (fragx || fragy || fragz || glt->inputwidth != fragwidth || glt->inputheight != fragheight || glt->inputdepth != fragdepth)
1081                         Sys_Error("R_Upload \"%s\": partial update not allowed on initial upload or in combination with PICMIP or MIPMAP\n", glt->identifier);
1082
1083                 // cubemaps contain multiple images and thus get processed a bit differently
1084                 if (glt->texturetype != GLTEXTURETYPE_CUBEMAP)
1085                 {
1086                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1087                         {
1088                                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1089                                 prevbuffer = resizebuffer;
1090                         }
1091                         // picmip/max_size
1092                         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1093                         {
1094                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1095                                 prevbuffer = resizebuffer;
1096                         }
1097                 }
1098                 mip = 0;
1099                 switch(vid.renderpath)
1100                 {
1101                 case RENDERPATH_GL11:
1102                 case RENDERPATH_GL13:
1103                 case RENDERPATH_GL20:
1104                 case RENDERPATH_CGGL:
1105                         if (qglGetCompressedTexImageARB)
1106                         {
1107                                 if (gl_texturecompression.integer >= 2)
1108                                         qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
1109                                 else
1110                                         qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
1111                                 CHECKGLERROR
1112                         }
1113                         switch(glt->texturetype)
1114                         {
1115                         case GLTEXTURETYPE_2D:
1116                                 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1117                                 if (glt->flags & TEXF_MIPMAP)
1118                                 {
1119                                         while (width > 1 || height > 1 || depth > 1)
1120                                         {
1121                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1122                                                 prevbuffer = resizebuffer;
1123                                                 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1124                                         }
1125                                 }
1126                                 break;
1127                         case GLTEXTURETYPE_3D:
1128                                 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1129                                 if (glt->flags & TEXF_MIPMAP)
1130                                 {
1131                                         while (width > 1 || height > 1 || depth > 1)
1132                                         {
1133                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1134                                                 prevbuffer = resizebuffer;
1135                                                 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1136                                         }
1137                                 }
1138                                 break;
1139                         case GLTEXTURETYPE_CUBEMAP:
1140                                 // convert and upload each side in turn,
1141                                 // from a continuous block of input texels
1142                                 texturebuffer = (unsigned char *)prevbuffer;
1143                                 for (i = 0;i < 6;i++)
1144                                 {
1145                                         prevbuffer = texturebuffer;
1146                                         texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1147                                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1148                                         {
1149                                                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1150                                                 prevbuffer = resizebuffer;
1151                                         }
1152                                         // picmip/max_size
1153                                         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1154                                         {
1155                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1156                                                 prevbuffer = resizebuffer;
1157                                         }
1158                                         mip = 0;
1159                                         qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1160                                         if (glt->flags & TEXF_MIPMAP)
1161                                         {
1162                                                 while (width > 1 || height > 1 || depth > 1)
1163                                                 {
1164                                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1165                                                         prevbuffer = resizebuffer;
1166                                                         qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1167                                                 }
1168                                         }
1169                                 }
1170                                 break;
1171                         case GLTEXTURETYPE_RECTANGLE:
1172                                 qglTexImage2D(GL_TEXTURE_RECTANGLE_ARB, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, NULL);CHECKGLERROR
1173                                 break;
1174                         }
1175                         GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1176                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1177                         break;
1178                 case RENDERPATH_D3D9:
1179 #ifdef SUPPORTD3D
1180                         if (!(glt->flags & TEXF_RENDERTARGET))
1181                         {
1182                                 D3DLOCKED_RECT d3dlockedrect;
1183                                 D3DLOCKED_BOX d3dlockedbox;
1184                                 switch(glt->texturetype)
1185                                 {
1186                                 case GLTEXTURETYPE_2D:
1187                                         if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1188                                         {
1189                                                 if (prevbuffer)
1190                                                         memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1191                                                 else
1192                                                         memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
1193                                                 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1194                                         }
1195                                         mip++;
1196                                         if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
1197                                         {
1198                                                 while (width > 1 || height > 1 || depth > 1)
1199                                                 {
1200                                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1201                                                         prevbuffer = resizebuffer;
1202                                                         if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1203                                                         {
1204                                                                 memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1205                                                                 IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
1206                                                         }
1207                                                         mip++;
1208                                                 }
1209                                         }
1210                                         break;
1211                                 case GLTEXTURETYPE_3D:
1212                                         if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1213                                         {
1214                                                 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1215                                                 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1216                                                 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1217                                         }
1218                                         mip++;
1219                                         if (glt->flags & TEXF_MIPMAP)
1220                                         {
1221                                                 while (width > 1 || height > 1 || depth > 1)
1222                                                 {
1223                                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1224                                                         prevbuffer = resizebuffer;
1225                                                         if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
1226                                                         {
1227                                                                 // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
1228                                                                 memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
1229                                                                 IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
1230                                                         }
1231                                                         mip++;
1232                                                 }
1233                                         }
1234                                         break;
1235                                 case GLTEXTURETYPE_CUBEMAP:
1236                                         // convert and upload each side in turn,
1237                                         // from a continuous block of input texels
1238                                         texturebuffer = (unsigned char *)prevbuffer;
1239                                         for (i = 0;i < 6;i++)
1240                                         {
1241                                                 prevbuffer = texturebuffer;
1242                                                 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
1243                                                 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1244                                                 {
1245                                                         Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
1246                                                         prevbuffer = resizebuffer;
1247                                                 }
1248                                                 // picmip/max_size
1249                                                 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1250                                                 {
1251                                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1252                                                         prevbuffer = resizebuffer;
1253                                                 }
1254                                                 mip = 0;
1255                                                 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1256                                                 {
1257                                                         memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1258                                                         IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1259                                                 }
1260                                                 mip++;
1261                                                 if (glt->flags & TEXF_MIPMAP)
1262                                                 {
1263                                                         while (width > 1 || height > 1 || depth > 1)
1264                                                         {
1265                                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1266                                                                 prevbuffer = resizebuffer;
1267                                                                 if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
1268                                                                 {
1269                                                                         memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
1270                                                                         IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
1271                                                                 }
1272                                                                 mip++;
1273                                                         }
1274                                                 }
1275                                         }
1276                                         break;
1277                                 case GLTEXTURETYPE_RECTANGLE:
1278                                         Sys_Error("Direct3D does not have RECTANGLE textures\n");
1279                                         break;
1280                                 }
1281                         }
1282                         glt->d3daddressw = 0;
1283                         if (glt->flags & TEXF_CLAMP)
1284                         {
1285                                 glt->d3daddressu = D3DTADDRESS_CLAMP;
1286                                 glt->d3daddressv = D3DTADDRESS_CLAMP;
1287                                 if (glt->tiledepth > 1)
1288                                         glt->d3daddressw = D3DTADDRESS_CLAMP;
1289                         }
1290                         else
1291                         {
1292                                 glt->d3daddressu = D3DTADDRESS_WRAP;
1293                                 glt->d3daddressv = D3DTADDRESS_WRAP;
1294                                 if (glt->tiledepth > 1)
1295                                         glt->d3daddressw = D3DTADDRESS_WRAP;
1296                         }
1297                         glt->d3dmipmaplodbias = 0;
1298                         glt->d3dmaxmiplevel = 0;
1299                         glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
1300                         if (glt->flags & TEXF_FORCELINEAR)
1301                         {
1302                                 glt->d3dminfilter = D3DTEXF_LINEAR;
1303                                 glt->d3dmagfilter = D3DTEXF_LINEAR;
1304                                 glt->d3dmipfilter = D3DTEXF_POINT;
1305                         }
1306                         else if (glt->flags & TEXF_FORCENEAREST)
1307                         {
1308                                 glt->d3dminfilter = D3DTEXF_POINT;
1309                                 glt->d3dmagfilter = D3DTEXF_POINT;
1310                                 glt->d3dmipfilter = D3DTEXF_POINT;
1311                         }
1312                         else if (glt->flags & TEXF_MIPMAP)
1313                         {
1314                                 glt->d3dminfilter = d3d_filter_mipmin;
1315                                 glt->d3dmagfilter = d3d_filter_mipmag;
1316                                 glt->d3dmipfilter = d3d_filter_mipmix;
1317                         }
1318                         else
1319                         {
1320                                 glt->d3dminfilter = d3d_filter_flatmin;
1321                                 glt->d3dmagfilter = d3d_filter_flatmag;
1322                                 glt->d3dmipfilter = d3d_filter_flatmix;
1323                         }
1324 #endif
1325                         break;
1326                 case RENDERPATH_D3D10:
1327                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1328                         break;
1329                 case RENDERPATH_D3D11:
1330                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1331                         break;
1332                 }
1333         }
1334 }
1335
1336 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)
1337 {
1338         int i, size;
1339         gltexture_t *glt;
1340         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1341         textypeinfo_t *texinfo, *texinfo2;
1342         unsigned char *temppixels = NULL;
1343
1344         if (cls.state == ca_dedicated)
1345                 return NULL;
1346
1347         if (texturetype == GLTEXTURETYPE_RECTANGLE && !vid.support.arb_texture_rectangle)
1348         {
1349                 Con_Printf ("R_LoadTexture: rectangle texture not supported by driver\n");
1350                 return NULL;
1351         }
1352         if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
1353         {
1354                 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
1355                 return NULL;
1356         }
1357         if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
1358         {
1359                 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
1360                 return NULL;
1361         }
1362
1363         texinfo = R_GetTexTypeInfo(textype, flags);
1364         size = width * height * depth * sides * texinfo->inputbytesperpixel;
1365         if (size < 1)
1366         {
1367                 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1368                 return NULL;
1369         }
1370
1371         if (textype == TEXTYPE_RGBA)
1372         {
1373                 // swap bytes
1374                 static int rgbaswapindices[4] = {2, 1, 0, 3};
1375                 textype = TEXTYPE_BGRA;
1376                 texinfo = R_GetTexTypeInfo(textype, flags);
1377                 temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
1378                 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1379                 data = temppixels;
1380         }
1381
1382         // clear the alpha flag if the texture has no transparent pixels
1383         switch(textype)
1384         {
1385         case TEXTYPE_PALETTE:
1386                 if (flags & TEXF_ALPHA)
1387                 {
1388                         flags &= ~TEXF_ALPHA;
1389                         if (data)
1390                         {
1391                                 for (i = 0;i < size;i++)
1392                                 {
1393                                         if (((unsigned char *)&palette[data[i]])[3] < 255)
1394                                         {
1395                                                 flags |= TEXF_ALPHA;
1396                                                 break;
1397                                         }
1398                                 }
1399                         }
1400                 }
1401                 break;
1402         case TEXTYPE_RGBA:
1403         case TEXTYPE_BGRA:
1404                 if (flags & TEXF_ALPHA)
1405                 {
1406                         flags &= ~TEXF_ALPHA;
1407                         if (data)
1408                         {
1409                                 for (i = 3;i < size;i += 4)
1410                                 {
1411                                         if (data[i] < 255)
1412                                         {
1413                                                 flags |= TEXF_ALPHA;
1414                                                 break;
1415                                         }
1416                                 }
1417                         }
1418                 }
1419                 break;
1420         case TEXTYPE_SHADOWMAP:
1421                 break;
1422         case TEXTYPE_DXT1:
1423                 break;
1424         case TEXTYPE_DXT1A:
1425         case TEXTYPE_DXT3:
1426         case TEXTYPE_DXT5:
1427                 flags |= TEXF_ALPHA;
1428                 break;
1429         case TEXTYPE_ALPHA:
1430                 flags |= TEXF_ALPHA;
1431                 break;
1432         case TEXTYPE_COLORBUFFER:
1433                 flags |= TEXF_ALPHA;
1434                 break;
1435         default:
1436                 Sys_Error("R_LoadTexture: unknown texture type");
1437         }
1438
1439         texinfo2 = R_GetTexTypeInfo(textype, flags);
1440         if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1441                 texinfo = texinfo2;
1442         else
1443                 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1444
1445         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1446         if (identifier)
1447                 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1448         glt->pool = pool;
1449         glt->chain = pool->gltchain;
1450         pool->gltchain = glt;
1451         glt->inputwidth = width;
1452         glt->inputheight = height;
1453         glt->inputdepth = depth;
1454         glt->flags = flags;
1455         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
1456         glt->textype = texinfo;
1457         glt->texturetype = texturetype;
1458         glt->inputdatasize = size;
1459         glt->palette = palette;
1460         glt->glinternalformat = texinfo->glinternalformat;
1461         glt->glformat = texinfo->glformat;
1462         glt->gltype = texinfo->gltype;
1463         glt->bytesperpixel = texinfo->internalbytesperpixel;
1464         glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1465         glt->texnum = 0;
1466         glt->dirty = false;
1467         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1468         // init the dynamic texture attributes, too [11/22/2007 Black]
1469         glt->updatecallback = NULL;
1470         glt->updatacallback_data = NULL;
1471
1472         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1473
1474         // upload the texture
1475         // data may be NULL (blank texture for dynamic rendering)
1476         switch(vid.renderpath)
1477         {
1478         case RENDERPATH_GL11:
1479         case RENDERPATH_GL13:
1480         case RENDERPATH_GL20:
1481         case RENDERPATH_CGGL:
1482                 CHECKGLERROR
1483                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1484                 break;
1485         case RENDERPATH_D3D9:
1486 #ifdef SUPPORTD3D
1487                 {
1488                         D3DFORMAT d3dformat;
1489                         D3DPOOL d3dpool;
1490                         DWORD d3dusage;
1491                         HRESULT d3dresult;
1492                         d3dusage = 0;
1493                         d3dpool = D3DPOOL_MANAGED;
1494                         if (flags & TEXF_RENDERTARGET)
1495                         {
1496                                 d3dusage |= D3DUSAGE_RENDERTARGET;
1497                                 d3dpool = D3DPOOL_DEFAULT;
1498                         }
1499                         switch(textype)
1500                         {
1501                         case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1502                         case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
1503                         case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1504                         case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1505                         case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
1506                         case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
1507                         default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1508                         }
1509                         glt->d3dformat = d3dformat;
1510                         glt->d3dusage = d3dusage;
1511                         glt->d3dpool = d3dpool;
1512                         if (glt->tiledepth > 1)
1513                         {
1514                                 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)))
1515                                         Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
1516                         }
1517                         else if (glt->sides == 6)
1518                         {
1519                                 if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
1520                                         Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
1521                         }
1522                         else
1523                         {
1524                                 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)))
1525                                         Sys_Error("IDirect3DDevice9_CreateTexture failed!");
1526                         }
1527                 }
1528 #endif
1529                 break;
1530         case RENDERPATH_D3D10:
1531                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1532                 break;
1533         case RENDERPATH_D3D11:
1534                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1535                 break;
1536         }
1537
1538         R_Upload(glt, data, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
1539         if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1540                 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1541
1542         // free any temporary processing buffer we allocated...
1543         if (temppixels)
1544                 Mem_Free(temppixels);
1545
1546         // texture converting and uploading can take a while, so make sure we're sending keepalives
1547         // FIXME: this causes rendering during R_Shadow_DrawLights
1548 //      CL_KeepaliveMessage(false);
1549
1550         return (rtexture_t *)glt;
1551 }
1552
1553 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)
1554 {
1555         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1556 }
1557
1558 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)
1559 {
1560         return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1561 }
1562
1563 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)
1564 {
1565         return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1566 }
1567
1568 rtexture_t *R_LoadTextureRectangle(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)
1569 {
1570         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_RECTANGLE, data, palette);
1571 }
1572
1573 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1574 {
1575         int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
1576         if (filter)
1577                 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1578         else
1579                 flags |= TEXF_FORCENEAREST;
1580         if (precision <= 16)
1581                 flags |= TEXF_LOWPRECISION;
1582         return flags;
1583 }
1584
1585 rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1586 {
1587         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
1588 }
1589
1590 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1591 {
1592         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1593 }
1594
1595 rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter)
1596 {
1597     return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
1598 }
1599
1600 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
1601 {
1602         gltexture_t *glt = (gltexture_t *)rt;
1603         unsigned char *dds;
1604         int oldbindtexnum;
1605         int bytesperpixel = 0;
1606         int bytesperblock = 0;
1607         int dds_flags;
1608         int dds_format_flags;
1609         int dds_caps1;
1610         int dds_caps2;
1611         int ret;
1612         int mip;
1613         int mipmaps;
1614         int mipinfo[16][4];
1615         int ddssize = 128;
1616         GLint internalformat;
1617         const char *ddsfourcc;
1618         if (!rt)
1619                 return -1; // NULL pointer
1620         if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1621                 return -2; // broken driver - crashes on reading internal format
1622         if (!qglGetTexLevelParameteriv)
1623                 return -2;
1624         GL_ActiveTexture(0);
1625         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1626         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1627         qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1628         switch(internalformat)
1629         {
1630         default: ddsfourcc = NULL;bytesperpixel = 4;break;
1631         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1632         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1633         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1634         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1635         }
1636         if (!bytesperblock && skipuncompressed)
1637                 return -3; // skipped
1638         memset(mipinfo, 0, sizeof(mipinfo));
1639         mipinfo[0][0] = glt->tilewidth;
1640         mipinfo[0][1] = glt->tileheight;
1641         mipmaps = 1;
1642         if (glt->flags & TEXF_MIPMAP)
1643         {
1644                 for (mip = 1;mip < 16;mip++)
1645                 {
1646                         mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1647                         mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1648                         if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1649                         {
1650                                 mip++;
1651                                 break;
1652                         }
1653                 }
1654                 mipmaps = mip;
1655         }
1656         for (mip = 0;mip < mipmaps;mip++)
1657         {
1658                 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1659                 mipinfo[mip][3] = ddssize;
1660                 ddssize += mipinfo[mip][2];
1661         }
1662         dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1663         if (!dds)
1664                 return -4;
1665         dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1666         dds_caps2 = 0;
1667         if (bytesperblock)
1668         {
1669                 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1670                 dds_format_flags = 0x4; // DDPF_FOURCC
1671         }
1672         else
1673         {
1674                 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1675                 dds_format_flags = 0x40; // DDPF_RGB
1676         }
1677         if (mipmaps)
1678         {
1679                 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1680                 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1681         }
1682         if(hasalpha)
1683                 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1684         memcpy(dds, "DDS ", 4);
1685         StoreLittleLong(dds+4, ddssize);
1686         StoreLittleLong(dds+8, dds_flags);
1687         StoreLittleLong(dds+12, mipinfo[0][1]); // height
1688         StoreLittleLong(dds+16, mipinfo[0][0]); // width
1689         StoreLittleLong(dds+24, 1); // depth
1690         StoreLittleLong(dds+28, mipmaps); // mipmaps
1691         StoreLittleLong(dds+76, 32); // format size
1692         StoreLittleLong(dds+80, dds_format_flags);
1693         StoreLittleLong(dds+108, dds_caps1);
1694         StoreLittleLong(dds+112, dds_caps2);
1695         if (bytesperblock)
1696         {
1697                 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1698                 memcpy(dds+84, ddsfourcc, 4);
1699                 for (mip = 0;mip < mipmaps;mip++)
1700                 {
1701                         qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1702                 }
1703         }
1704         else
1705         {
1706                 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1707                 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1708                 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1709                 for (mip = 0;mip < mipmaps;mip++)
1710                 {
1711                         qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1712                 }
1713         }
1714         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1715         ret = FS_WriteFile(filename, dds, ddssize);
1716         Mem_Free(dds);
1717         return ret ? ddssize : -5;
1718 }
1719
1720 rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint
1721 {
1722         int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1723         //int dds_flags;
1724         textype_t textype;
1725         int bytesperblock, bytesperpixel;
1726         int mipcomplete;
1727         gltexture_t *glt;
1728         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1729         textypeinfo_t *texinfo;
1730         int mip, mipwidth, mipheight, mipsize;
1731         unsigned int c;
1732         GLint oldbindtexnum = 0;
1733         const unsigned char *mippixels, *ddspixels;
1734         unsigned char *dds;
1735         fs_offset_t ddsfilesize;
1736         unsigned int ddssize;
1737
1738         if (cls.state == ca_dedicated)
1739                 return NULL;
1740
1741         dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1742         ddssize = ddsfilesize;
1743
1744         if (!dds)
1745         {
1746                 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1747                 return NULL; // not found
1748         }
1749
1750         if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1751         {
1752                 Mem_Free(dds);
1753                 Con_Printf("^1%s: not a DDS image\n", filename);
1754                 return NULL;
1755         }
1756
1757         //dds_flags = BuffLittleLong(dds+8);
1758         dds_format_flags = BuffLittleLong(dds+80);
1759         dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1760         dds_width = BuffLittleLong(dds+16);
1761         dds_height = BuffLittleLong(dds+12);
1762         ddspixels = dds + 128;
1763
1764         if(r_texture_dds_load_alphamode.integer == 0)
1765                 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1766                         flags &= ~TEXF_ALPHA;
1767
1768         //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1769         if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1770         {
1771                 // very sloppy BGRA 32bit identification
1772                 textype = TEXTYPE_BGRA;
1773                 bytesperblock = 0;
1774                 bytesperpixel = 4;
1775                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1776                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1777                 {
1778                         Mem_Free(dds);
1779                         Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1780                         return NULL;
1781                 }
1782                 if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
1783                 {
1784                         // check alpha
1785                         for (i = 3;i < size;i += 4)
1786                                 if (ddspixels[i] < 255)
1787                                         break;
1788                         if (i >= size)
1789                                 flags &= ~TEXF_ALPHA;
1790                 }
1791         }
1792         else if (!memcmp(dds+84, "DXT1", 4))
1793         {
1794                 if(!vid.support.ext_texture_compression_s3tc)
1795                 {
1796                         Mem_Free(dds);
1797                         return NULL;
1798                 }
1799                 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1800                 // LordHavoc: it is my belief that this does not infringe on the
1801                 // patent because it is not decoding pixels...
1802                 textype = TEXTYPE_DXT1;
1803                 bytesperblock = 8;
1804                 bytesperpixel = 0;
1805                 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1806                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1807                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1808                 {
1809                         Mem_Free(dds);
1810                         Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1811                         return NULL;
1812                 }
1813                 if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
1814                 {
1815                         if(r_texture_dds_load_alphamode.integer == 1)
1816                         {
1817                                 // check alpha
1818                                 for (i = 0;i < size;i += bytesperblock)
1819                                         if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1820                                         {
1821                                                 // NOTE: this assumes sizeof(unsigned int) == 4
1822                                                 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1823                                                 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1824                                                 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1825                                                         break;
1826                                         }
1827                                 if (i < size)
1828                                         textype = TEXTYPE_DXT1A;
1829                                 else
1830                                         flags &= ~TEXF_ALPHA;
1831                         }
1832                         else
1833                         {
1834                                 flags &= ~TEXF_ALPHA;
1835                         }
1836                 }
1837         }
1838         else if (!memcmp(dds+84, "DXT3", 4))
1839         {
1840                 if(!vid.support.ext_texture_compression_s3tc)
1841                 {
1842                         Mem_Free(dds);
1843                         return NULL;
1844                 }
1845                 textype = TEXTYPE_DXT3;
1846                 bytesperblock = 16;
1847                 bytesperpixel = 0;
1848                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1849                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1850                 {
1851                         Mem_Free(dds);
1852                         Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1853                         return NULL;
1854                 }
1855                 // we currently always assume alpha
1856         }
1857         else if (!memcmp(dds+84, "DXT5", 4))
1858         {
1859                 if(!vid.support.ext_texture_compression_s3tc)
1860                 {
1861                         Mem_Free(dds);
1862                         return NULL;
1863                 }
1864                 textype = TEXTYPE_DXT5;
1865                 bytesperblock = 16;
1866                 bytesperpixel = 0;
1867                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1868                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1869                 {
1870                         Mem_Free(dds);
1871                         Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1872                         return NULL;
1873                 }
1874                 // we currently always assume alpha
1875         }
1876         else
1877         {
1878                 Mem_Free(dds);
1879                 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1880                 return NULL;
1881         }
1882
1883         // return whether this texture is transparent
1884         if (hasalphaflag)
1885                 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1886
1887         // calculate average color if requested
1888         if (avgcolor)
1889         {
1890                 float f;
1891                 Vector4Clear(avgcolor);
1892                 if (bytesperblock)
1893                 {
1894                         for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
1895                         {
1896                                 c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
1897                                 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1898                                 avgcolor[1] += ((c >>  5) & 0x3F) + ((c >> 21) & 0x3F);
1899                                 avgcolor[2] += ((c      ) & 0x1F) + ((c >> 16) & 0x1F);
1900                         }
1901                         f = (float)bytesperblock / size;
1902                         avgcolor[0] *= (0.5f / 31.0f) * f;
1903                         avgcolor[1] *= (0.5f / 63.0f) * f;
1904                         avgcolor[2] *= (0.5f / 31.0f) * f;
1905                         avgcolor[3] = 1; // too hard to calculate
1906                 }
1907                 else
1908                 {
1909                         for (i = 0;i < size;i += 4)
1910                         {
1911                                 avgcolor[0] += ddspixels[i+2];
1912                                 avgcolor[1] += ddspixels[i+1];
1913                                 avgcolor[2] += ddspixels[i];
1914                                 avgcolor[3] += ddspixels[i+3];
1915                         }
1916                         f = (1.0f / 255.0f) * bytesperpixel / size;
1917                         avgcolor[0] *= f;
1918                         avgcolor[1] *= f;
1919                         avgcolor[2] *= f;
1920                         avgcolor[3] *= f;
1921                 }
1922         }
1923
1924         // this is where we apply gl_picmip
1925         mippixels = ddspixels;
1926         mipwidth = dds_width;
1927         mipheight = dds_height;
1928         while(miplevel >= 1 && dds_miplevels >= 1)
1929         {
1930                 if (mipwidth <= 1 && mipheight <= 1)
1931                         break;
1932                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1933                 mippixels += mipsize; // just skip
1934                 --dds_miplevels;
1935                 --miplevel;
1936                 if (mipwidth > 1)
1937                         mipwidth >>= 1;
1938                 if (mipheight > 1)
1939                         mipheight >>= 1;
1940         }
1941
1942         // when not requesting mipmaps, do not load them
1943         if(!(flags & TEXF_MIPMAP))
1944                 dds_miplevels = 0;
1945
1946         if (dds_miplevels >= 1)
1947                 flags |= TEXF_MIPMAP;
1948         else
1949                 flags &= ~TEXF_MIPMAP;
1950
1951         // if S3TC is not supported, there's very little we can do about it
1952         if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
1953         {
1954                 Mem_Free(dds);
1955                 Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
1956                 return NULL;
1957         }
1958
1959         texinfo = R_GetTexTypeInfo(textype, flags);
1960
1961         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1962         strlcpy (glt->identifier, filename, sizeof(glt->identifier));
1963         glt->pool = pool;
1964         glt->chain = pool->gltchain;
1965         pool->gltchain = glt;
1966         glt->inputwidth = mipwidth;
1967         glt->inputheight = mipheight;
1968         glt->inputdepth = 1;
1969         glt->flags = flags;
1970         glt->textype = texinfo;
1971         glt->texturetype = GLTEXTURETYPE_2D;
1972         glt->inputdatasize = ddssize;
1973         glt->glinternalformat = texinfo->glinternalformat;
1974         glt->glformat = texinfo->glformat;
1975         glt->gltype = texinfo->gltype;
1976         glt->bytesperpixel = texinfo->internalbytesperpixel;
1977         glt->sides = 1;
1978         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1979         glt->tilewidth = mipwidth;
1980         glt->tileheight = mipheight;
1981         glt->tiledepth = 1;
1982         glt->miplevels = dds_miplevels;
1983
1984         // texture uploading can take a while, so make sure we're sending keepalives
1985         CL_KeepaliveMessage(false);
1986
1987         // create the texture object
1988         switch(vid.renderpath)
1989         {
1990         case RENDERPATH_GL11:
1991         case RENDERPATH_GL13:
1992         case RENDERPATH_GL20:
1993         case RENDERPATH_CGGL:
1994                 CHECKGLERROR
1995                 GL_ActiveTexture(0);
1996                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1997                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1998                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1999                 break;
2000         case RENDERPATH_D3D9:
2001 #ifdef SUPPORTD3D
2002                 {
2003                         D3DFORMAT d3dformat;
2004                         D3DPOOL d3dpool;
2005                         DWORD d3dusage;
2006                         switch(textype)
2007                         {
2008                         case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
2009                         case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
2010                         case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
2011                         case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
2012                         default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
2013                         }
2014                         d3dusage = 0;
2015                         d3dpool = D3DPOOL_MANAGED;
2016                         IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
2017                 }
2018 #endif
2019                 break;
2020         case RENDERPATH_D3D10:
2021                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2022                 break;
2023         case RENDERPATH_D3D11:
2024                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2025                 break;
2026         }
2027
2028         // upload the texture
2029         // we need to restore the texture binding after finishing the upload
2030         mipcomplete = false;
2031
2032         for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2033         {
2034                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2035                 if (mippixels + mipsize > dds + ddssize)
2036                         break;
2037                 switch(vid.renderpath)
2038                 {
2039                 case RENDERPATH_GL11:
2040                 case RENDERPATH_GL13:
2041                 case RENDERPATH_GL20:
2042                 case RENDERPATH_CGGL:
2043                         if (bytesperblock)
2044                         {
2045                                 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2046                         }
2047                         else
2048                         {
2049                                 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2050                         }
2051                         break;
2052                 case RENDERPATH_D3D9:
2053 #ifdef SUPPORTD3D
2054                         {
2055                                 D3DLOCKED_RECT d3dlockedrect;
2056                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2057                                 {
2058                                         memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2059                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2060                                 }
2061                                 break;
2062                         }
2063 #endif
2064                         break;
2065                 case RENDERPATH_D3D10:
2066                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2067                         break;
2068                 case RENDERPATH_D3D11:
2069                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2070                         break;
2071                 }
2072                 mippixels += mipsize;
2073                 if (mipwidth <= 1 && mipheight <= 1)
2074                 {
2075                         mipcomplete = true;
2076                         break;
2077                 }
2078                 if (mipwidth > 1)
2079                         mipwidth >>= 1;
2080                 if (mipheight > 1)
2081                         mipheight >>= 1;
2082         }
2083
2084         // after upload we have to set some parameters...
2085         switch(vid.renderpath)
2086         {
2087         case RENDERPATH_GL11:
2088         case RENDERPATH_GL13:
2089         case RENDERPATH_GL20:
2090         case RENDERPATH_CGGL:
2091                 if (dds_miplevels >= 1 && !mipcomplete)
2092                 {
2093                         // need to set GL_TEXTURE_MAX_LEVEL
2094                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2095                 }
2096                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2097                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2098                 break;
2099         case RENDERPATH_D3D9:
2100 #ifdef SUPPORTD3D
2101                 glt->d3daddressw = 0;
2102                 if (glt->flags & TEXF_CLAMP)
2103                 {
2104                         glt->d3daddressu = D3DTADDRESS_CLAMP;
2105                         glt->d3daddressv = D3DTADDRESS_CLAMP;
2106                         if (glt->tiledepth > 1)
2107                                 glt->d3daddressw = D3DTADDRESS_CLAMP;
2108                 }
2109                 else
2110                 {
2111                         glt->d3daddressu = D3DTADDRESS_WRAP;
2112                         glt->d3daddressv = D3DTADDRESS_WRAP;
2113                         if (glt->tiledepth > 1)
2114                                 glt->d3daddressw = D3DTADDRESS_WRAP;
2115                 }
2116                 glt->d3dmipmaplodbias = 0;
2117                 glt->d3dmaxmiplevel = 0;
2118                 glt->d3dmaxmiplevelfilter = 0;
2119                 if (glt->flags & TEXF_MIPMAP)
2120                 {
2121                         glt->d3dminfilter = d3d_filter_mipmin;
2122                         glt->d3dmagfilter = d3d_filter_mipmag;
2123                         glt->d3dmipfilter = d3d_filter_mipmix;
2124                 }
2125                 else
2126                 {
2127                         glt->d3dminfilter = d3d_filter_flatmin;
2128                         glt->d3dmagfilter = d3d_filter_flatmag;
2129                         glt->d3dmipfilter = d3d_filter_flatmix;
2130                 }
2131 #endif
2132                 break;
2133         case RENDERPATH_D3D10:
2134                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2135                 break;
2136         case RENDERPATH_D3D11:
2137                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2138                 break;
2139         }
2140
2141         Mem_Free(dds);
2142         return (rtexture_t *)glt;
2143 }
2144
2145 int R_TextureWidth(rtexture_t *rt)
2146 {
2147         return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2148 }
2149
2150 int R_TextureHeight(rtexture_t *rt)
2151 {
2152         return rt ? ((gltexture_t *)rt)->inputheight : 0;
2153 }
2154
2155 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
2156 {
2157         gltexture_t *glt = (gltexture_t *)rt;
2158         if (data == NULL)
2159                 Host_Error("R_UpdateTexture: no data supplied");
2160         if (glt == NULL)
2161                 Host_Error("R_UpdateTexture: no texture supplied");
2162         if (!glt->texnum && !glt->d3dtexture)
2163         {
2164                 Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", (void *)glt, glt->identifier, (void *)glt->pool);
2165                 return;
2166         }
2167         // update part of the texture
2168         if (glt->bufferpixels)
2169         {
2170                 int j;
2171                 int bpp = glt->bytesperpixel;
2172                 int inputskip = width*bpp;
2173                 int outputskip = glt->tilewidth*bpp;
2174                 const unsigned char *input = data;
2175                 unsigned char *output = glt->bufferpixels;
2176                 if (x < 0)
2177                 {
2178                         width += x;
2179                         input -= x*bpp;
2180                         x = 0;
2181                 }
2182                 if (y < 0)
2183                 {
2184                         height += y;
2185                         input -= y*inputskip;
2186                         y = 0;
2187                 }
2188                 if (width > glt->tilewidth - x)
2189                         width = glt->tilewidth - x;
2190                 if (height > glt->tileheight - y)
2191                         height = glt->tileheight - y;
2192                 if (width < 1 || height < 1)
2193                         return;
2194                 glt->dirty = true;
2195                 glt->buffermodified = true;
2196                 output += y*outputskip + x*bpp;
2197                 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2198                         memcpy(output, input, width*bpp);
2199         }
2200         else
2201                 R_Upload(glt, data, x, y, 0, width, height, 1);
2202 }
2203
2204 int R_RealGetTexture(rtexture_t *rt)
2205 {
2206         if (rt)
2207         {
2208                 gltexture_t *glt;
2209                 glt = (gltexture_t *)rt;
2210                 if (glt->flags & GLTEXF_DYNAMIC)
2211                         R_UpdateDynamicTexture(glt);
2212                 if (glt->buffermodified && glt->bufferpixels)
2213                 {
2214                         glt->buffermodified = false;
2215                         R_Upload(glt, glt->bufferpixels, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth);
2216                 }
2217                 glt->dirty = false;
2218                 return glt->texnum;
2219         }
2220         else
2221                 return 0;
2222 }
2223
2224 void R_ClearTexture (rtexture_t *rt)
2225 {
2226         gltexture_t *glt = (gltexture_t *)rt;
2227
2228         R_Upload( glt, NULL, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth );
2229 }
2230
2231 int R_PicmipForFlags(int flags)
2232 {
2233         int miplevel = 0;
2234         if(flags & TEXF_PICMIP)
2235         {
2236                 miplevel += gl_picmip.integer;
2237                 if (flags & TEXF_ISWORLD)
2238                 {
2239                         if (r_picmipworld.integer)
2240                                 miplevel += gl_picmip_world.integer;
2241                         else
2242                                 miplevel = 0;
2243                 }
2244                 else if (flags & TEXF_ISSPRITE)
2245                 {
2246                         if (r_picmipsprites.integer)
2247                                 miplevel += gl_picmip_sprites.integer;
2248                         else
2249                                 miplevel = 0;
2250                 }
2251                 else
2252                         miplevel += gl_picmip_other.integer;
2253         }
2254         return max(0, miplevel);
2255 }