]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_textures.c
a44e3a29b948c73b536bdd660e62cade7600e7aa
[xonotic/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_dxt1_noalpha = {0, "r_texture_dds_load_dxt1_noalpha", "0", "if set, alpha detection on DXT1 is turned off, and DXT1 textures are assumed to never have alpha"};
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.arb_texture_compression)
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.arb_texture_compression)
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         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         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_dxt1_noalpha);
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                         Host_Error("R_Upload: partial update not allowed on initial upload or in combination with PICMIP or MIPMAP\n");
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)
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 = 0x41; // DDPF_RGB | DDPF_ALPHAPIXELS
1676         }
1677         if (mipmaps)
1678         {
1679                 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1680                 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1681         }
1682         memcpy(dds, "DDS ", 4);
1683         StoreLittleLong(dds+4, ddssize);
1684         StoreLittleLong(dds+8, dds_flags);
1685         StoreLittleLong(dds+12, mipinfo[0][1]); // height
1686         StoreLittleLong(dds+16, mipinfo[0][0]); // width
1687         StoreLittleLong(dds+24, 1); // depth
1688         StoreLittleLong(dds+28, mipmaps); // mipmaps
1689         StoreLittleLong(dds+76, 32); // format size
1690         StoreLittleLong(dds+80, dds_format_flags);
1691         StoreLittleLong(dds+108, dds_caps1);
1692         StoreLittleLong(dds+112, dds_caps2);
1693         if (bytesperblock)
1694         {
1695                 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1696                 memcpy(dds+84, ddsfourcc, 4);
1697                 for (mip = 0;mip < mipmaps;mip++)
1698                 {
1699                         qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1700                 }
1701         }
1702         else
1703         {
1704                 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1705                 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1706                 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1707                 for (mip = 0;mip < mipmaps;mip++)
1708                 {
1709                         qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1710                 }
1711         }
1712         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1713         ret = FS_WriteFile(filename, dds, ddssize);
1714         Mem_Free(dds);
1715         return ret ? ddssize : -5;
1716 }
1717
1718 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
1719 {
1720         int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1721         //int dds_flags;
1722         textype_t textype;
1723         int bytesperblock, bytesperpixel;
1724         int mipcomplete;
1725         gltexture_t *glt;
1726         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1727         textypeinfo_t *texinfo;
1728         int mip, mipwidth, mipheight, mipsize;
1729         unsigned int c;
1730         GLint oldbindtexnum = 0;
1731         const unsigned char *mippixels, *ddspixels;
1732         unsigned char *dds;
1733         fs_offset_t ddsfilesize;
1734         unsigned int ddssize;
1735
1736         if (cls.state == ca_dedicated)
1737                 return NULL;
1738
1739         dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1740         ddssize = ddsfilesize;
1741
1742         if (!dds)
1743         {
1744                 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1745                 return NULL; // not found
1746         }
1747
1748         if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1749         {
1750                 Mem_Free(dds);
1751                 Con_Printf("^1%s: not a DDS image\n", filename);
1752                 return NULL;
1753         }
1754
1755         //dds_flags = BuffLittleLong(dds+8);
1756         dds_format_flags = BuffLittleLong(dds+80);
1757         dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1758         dds_width = BuffLittleLong(dds+16);
1759         dds_height = BuffLittleLong(dds+12);
1760         ddspixels = dds + 128;
1761
1762         //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1763         if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1764         {
1765                 // very sloppy BGRA 32bit identification
1766                 textype = TEXTYPE_BGRA;
1767                 bytesperblock = 0;
1768                 bytesperpixel = 4;
1769                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1770                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1771                 {
1772                         Mem_Free(dds);
1773                         Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1774                         return NULL;
1775                 }
1776                 // check alpha
1777                 for (i = 3;i < size;i += 4)
1778                         if (ddspixels[i] < 255)
1779                                 break;
1780                 if (i >= size)
1781                         flags &= ~TEXF_ALPHA;
1782         }
1783         else if (!memcmp(dds+84, "DXT1", 4))
1784         {
1785                 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1786                 // LordHavoc: it is my belief that this does not infringe on the
1787                 // patent because it is not decoding pixels...
1788                 textype = TEXTYPE_DXT1;
1789                 bytesperblock = 8;
1790                 bytesperpixel = 0;
1791                 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1792                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1793                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1794                 {
1795                         Mem_Free(dds);
1796                         Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1797                         return NULL;
1798                 }
1799                 if(r_texture_dds_load_dxt1_noalpha.integer)
1800                 {
1801                         flags &= ~TEXF_ALPHA;
1802                 }
1803                 else
1804                 {
1805                         for (i = 0;i < size;i += bytesperblock)
1806                                 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1807                                         break;
1808                         if (i < size)
1809                                 textype = TEXTYPE_DXT1A;
1810                         else
1811                                 flags &= ~TEXF_ALPHA;
1812                 }
1813         }
1814         else if (!memcmp(dds+84, "DXT3", 4))
1815         {
1816                 textype = TEXTYPE_DXT3;
1817                 bytesperblock = 16;
1818                 bytesperpixel = 0;
1819                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1820                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1821                 {
1822                         Mem_Free(dds);
1823                         Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1824                         return NULL;
1825                 }
1826         }
1827         else if (!memcmp(dds+84, "DXT5", 4))
1828         {
1829                 textype = TEXTYPE_DXT5;
1830                 bytesperblock = 16;
1831                 bytesperpixel = 0;
1832                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1833                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1834                 {
1835                         Mem_Free(dds);
1836                         Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1837                         return NULL;
1838                 }
1839         }
1840         else
1841         {
1842                 Mem_Free(dds);
1843                 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1844                 return NULL;
1845         }
1846
1847         // return whether this texture is transparent
1848         if (hasalphaflag)
1849                 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1850
1851         // calculate average color if requested
1852         if (avgcolor)
1853         {
1854                 float f;
1855                 Vector4Clear(avgcolor);
1856                 if (bytesperblock)
1857                 {
1858                         for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
1859                         {
1860                                 c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
1861                                 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1862                                 avgcolor[1] += ((c >>  5) & 0x3F) + ((c >> 21) & 0x3F);
1863                                 avgcolor[2] += ((c      ) & 0x1F) + ((c >> 16) & 0x1F);
1864                         }
1865                         f = (float)bytesperblock / size;
1866                         avgcolor[0] *= (0.5f / 31.0f) * f;
1867                         avgcolor[1] *= (0.5f / 63.0f) * f;
1868                         avgcolor[2] *= (0.5f / 31.0f) * f;
1869                         avgcolor[3] = 1; // too hard to calculate
1870                 }
1871                 else
1872                 {
1873                         for (i = 0;i < size;i += 4)
1874                         {
1875                                 avgcolor[0] += ddspixels[i+2];
1876                                 avgcolor[1] += ddspixels[i+1];
1877                                 avgcolor[2] += ddspixels[i];
1878                                 avgcolor[3] += ddspixels[i+3];
1879                         }
1880                         f = (1.0f / 255.0f) * bytesperpixel / size;
1881                         avgcolor[0] *= f;
1882                         avgcolor[1] *= f;
1883                         avgcolor[2] *= f;
1884                         avgcolor[3] *= f;
1885                 }
1886         }
1887
1888         // this is where we apply gl_picmip
1889         mippixels = ddspixels;
1890         mipwidth = dds_width;
1891         mipheight = dds_height;
1892         while(miplevel >= 1 && dds_miplevels >= 1)
1893         {
1894                 if (mipwidth <= 1 && mipheight <= 1)
1895                         break;
1896                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1897                 mippixels += mipsize; // just skip
1898                 --dds_miplevels;
1899                 --miplevel;
1900                 if (mipwidth > 1)
1901                         mipwidth >>= 1;
1902                 if (mipheight > 1)
1903                         mipheight >>= 1;
1904         }
1905
1906         // when not requesting mipmaps, do not load them
1907         if(!(flags & TEXF_MIPMAP))
1908                 dds_miplevels = 0;
1909
1910         if (dds_miplevels >= 1)
1911                 flags |= TEXF_MIPMAP;
1912         else
1913                 flags &= ~TEXF_MIPMAP;
1914
1915         // if S3TC is not supported, there's very little we can do about it
1916         if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
1917         {
1918                 Mem_Free(dds);
1919                 Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
1920                 return NULL;
1921         }
1922
1923         texinfo = R_GetTexTypeInfo(textype, flags);
1924
1925         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1926         strlcpy (glt->identifier, filename, sizeof(glt->identifier));
1927         glt->pool = pool;
1928         glt->chain = pool->gltchain;
1929         pool->gltchain = glt;
1930         glt->inputwidth = mipwidth;
1931         glt->inputheight = mipheight;
1932         glt->inputdepth = 1;
1933         glt->flags = flags;
1934         glt->textype = texinfo;
1935         glt->texturetype = GLTEXTURETYPE_2D;
1936         glt->inputdatasize = ddssize;
1937         glt->glinternalformat = texinfo->glinternalformat;
1938         glt->glformat = texinfo->glformat;
1939         glt->gltype = texinfo->gltype;
1940         glt->bytesperpixel = texinfo->internalbytesperpixel;
1941         glt->sides = 1;
1942         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1943         glt->tilewidth = mipwidth;
1944         glt->tileheight = mipheight;
1945         glt->tiledepth = 1;
1946         glt->miplevels = dds_miplevels;
1947
1948         // texture uploading can take a while, so make sure we're sending keepalives
1949         CL_KeepaliveMessage(false);
1950
1951         // create the texture object
1952         switch(vid.renderpath)
1953         {
1954         case RENDERPATH_GL11:
1955         case RENDERPATH_GL13:
1956         case RENDERPATH_GL20:
1957         case RENDERPATH_CGGL:
1958                 CHECKGLERROR
1959                 GL_ActiveTexture(0);
1960                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1961                 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1962                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1963                 break;
1964         case RENDERPATH_D3D9:
1965 #ifdef SUPPORTD3D
1966                 {
1967                         D3DFORMAT d3dformat;
1968                         D3DPOOL d3dpool;
1969                         DWORD d3dusage;
1970                         switch(textype)
1971                         {
1972                         case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
1973                         case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
1974                         case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
1975                         case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
1976                         default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
1977                         }
1978                         d3dusage = 0;
1979                         d3dpool = D3DPOOL_MANAGED;
1980                         IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
1981                 }
1982 #endif
1983                 break;
1984         case RENDERPATH_D3D10:
1985                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1986                 break;
1987         case RENDERPATH_D3D11:
1988                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1989                 break;
1990         }
1991
1992         // upload the texture
1993         // we need to restore the texture binding after finishing the upload
1994         mipcomplete = false;
1995
1996         for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
1997         {
1998                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1999                 if (mippixels + mipsize > dds + ddssize)
2000                         break;
2001                 switch(vid.renderpath)
2002                 {
2003                 case RENDERPATH_GL11:
2004                 case RENDERPATH_GL13:
2005                 case RENDERPATH_GL20:
2006                 case RENDERPATH_CGGL:
2007                         if (bytesperblock)
2008                         {
2009                                 qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
2010                         }
2011                         else
2012                         {
2013                                 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
2014                         }
2015                         break;
2016                 case RENDERPATH_D3D9:
2017 #ifdef SUPPORTD3D
2018                         {
2019                                 D3DLOCKED_RECT d3dlockedrect;
2020                                 if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
2021                                 {
2022                                         memcpy(d3dlockedrect.pBits, mippixels, mipsize);
2023                                         IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
2024                                 }
2025                                 break;
2026                         }
2027 #endif
2028                         break;
2029                 case RENDERPATH_D3D10:
2030                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2031                         break;
2032                 case RENDERPATH_D3D11:
2033                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2034                         break;
2035                 }
2036                 mippixels += mipsize;
2037                 if (mipwidth <= 1 && mipheight <= 1)
2038                 {
2039                         mipcomplete = true;
2040                         break;
2041                 }
2042                 if (mipwidth > 1)
2043                         mipwidth >>= 1;
2044                 if (mipheight > 1)
2045                         mipheight >>= 1;
2046         }
2047
2048         // after upload we have to set some parameters...
2049         switch(vid.renderpath)
2050         {
2051         case RENDERPATH_GL11:
2052         case RENDERPATH_GL13:
2053         case RENDERPATH_GL20:
2054         case RENDERPATH_CGGL:
2055                 if (dds_miplevels >= 1 && !mipcomplete)
2056                 {
2057                         // need to set GL_TEXTURE_MAX_LEVEL
2058                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2059                 }
2060                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
2061                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2062                 break;
2063         case RENDERPATH_D3D9:
2064 #ifdef SUPPORTD3D
2065                 glt->d3daddressw = 0;
2066                 if (glt->flags & TEXF_CLAMP)
2067                 {
2068                         glt->d3daddressu = D3DTADDRESS_CLAMP;
2069                         glt->d3daddressv = D3DTADDRESS_CLAMP;
2070                         if (glt->tiledepth > 1)
2071                                 glt->d3daddressw = D3DTADDRESS_CLAMP;
2072                 }
2073                 else
2074                 {
2075                         glt->d3daddressu = D3DTADDRESS_WRAP;
2076                         glt->d3daddressv = D3DTADDRESS_WRAP;
2077                         if (glt->tiledepth > 1)
2078                                 glt->d3daddressw = D3DTADDRESS_WRAP;
2079                 }
2080                 glt->d3dmipmaplodbias = 0;
2081                 glt->d3dmaxmiplevel = 0;
2082                 glt->d3dmaxmiplevelfilter = 0;
2083                 if (glt->flags & TEXF_MIPMAP)
2084                 {
2085                         glt->d3dminfilter = d3d_filter_mipmin;
2086                         glt->d3dmagfilter = d3d_filter_mipmag;
2087                         glt->d3dmipfilter = d3d_filter_mipmix;
2088                 }
2089                 else
2090                 {
2091                         glt->d3dminfilter = d3d_filter_flatmin;
2092                         glt->d3dmagfilter = d3d_filter_flatmag;
2093                         glt->d3dmipfilter = d3d_filter_flatmix;
2094                 }
2095 #endif
2096                 break;
2097         case RENDERPATH_D3D10:
2098                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2099                 break;
2100         case RENDERPATH_D3D11:
2101                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2102                 break;
2103         }
2104
2105         Mem_Free(dds);
2106         return (rtexture_t *)glt;
2107 }
2108
2109 int R_TextureWidth(rtexture_t *rt)
2110 {
2111         return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2112 }
2113
2114 int R_TextureHeight(rtexture_t *rt)
2115 {
2116         return rt ? ((gltexture_t *)rt)->inputheight : 0;
2117 }
2118
2119 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
2120 {
2121         gltexture_t *glt = (gltexture_t *)rt;
2122         if (data == NULL)
2123                 Host_Error("R_UpdateTexture: no data supplied");
2124         if (glt == NULL)
2125                 Host_Error("R_UpdateTexture: no texture supplied");
2126         if (!glt->texnum && !glt->d3dtexture)
2127         {
2128                 Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", glt, glt->identifier, glt->pool);
2129                 return;
2130         }
2131         // update part of the texture
2132         if (glt->bufferpixels)
2133         {
2134                 int j;
2135                 int bpp = glt->bytesperpixel;
2136                 int inputskip = width*bpp;
2137                 int outputskip = glt->tilewidth*bpp;
2138                 const unsigned char *input = data;
2139                 unsigned char *output = glt->bufferpixels;
2140                 if (x < 0)
2141                 {
2142                         width += x;
2143                         input -= x*bpp;
2144                         x = 0;
2145                 }
2146                 if (y < 0)
2147                 {
2148                         height += y;
2149                         input -= y*inputskip;
2150                         y = 0;
2151                 }
2152                 if (width > glt->tilewidth - x)
2153                         width = glt->tilewidth - x;
2154                 if (height > glt->tileheight - y)
2155                         height = glt->tileheight - y;
2156                 if (width < 1 || height < 1)
2157                         return;
2158                 glt->dirty = true;
2159                 glt->buffermodified = true;
2160                 output += y*outputskip + x*bpp;
2161                 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
2162                         memcpy(output, input, width*bpp);
2163         }
2164         else
2165                 R_Upload(glt, data, x, y, 0, width, height, 1);
2166 }
2167
2168 int R_RealGetTexture(rtexture_t *rt)
2169 {
2170         if (rt)
2171         {
2172                 gltexture_t *glt;
2173                 glt = (gltexture_t *)rt;
2174                 if (glt->flags & GLTEXF_DYNAMIC)
2175                         R_UpdateDynamicTexture(glt);
2176                 if (glt->buffermodified && glt->bufferpixels)
2177                 {
2178                         glt->buffermodified = false;
2179                         R_Upload(glt, glt->bufferpixels, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth);
2180                 }
2181                 glt->dirty = false;
2182                 return glt->texnum;
2183         }
2184         else
2185                 return 0;
2186 }
2187
2188 void R_ClearTexture (rtexture_t *rt)
2189 {
2190         gltexture_t *glt = (gltexture_t *)rt;
2191
2192         R_Upload( glt, NULL, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth );
2193 }
2194
2195 int R_PicmipForFlags(int flags)
2196 {
2197         int miplevel = 0;
2198         if(flags & TEXF_PICMIP)
2199         {
2200                 miplevel += gl_picmip.integer;
2201                 if (flags & TEXF_ISWORLD)
2202                 {
2203                         if (r_picmipworld.integer)
2204                                 miplevel += gl_picmip_world.integer;
2205                         else
2206                                 miplevel = 0;
2207                 }
2208                 else if (flags & TEXF_ISSPRITE)
2209                 {
2210                         if (r_picmipsprites.integer)
2211                                 miplevel += gl_picmip_sprites.integer;
2212                         else
2213                                 miplevel = 0;
2214                 }
2215                 else
2216                         miplevel += gl_picmip_other.integer;
2217         }
2218         return max(0, miplevel);
2219 }