add DeviceLost and DeviceRestored functions to R_Modules system
[divverent/darkplaces.git] / gl_textures.c
1
2 #include "quakedef.h"
3 #include "image.h"
4 #include "jpeg.h"
5 #include "image_png.h"
6 #include "intoverflow.h"
7
8 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)"};
9 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)"};
10 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%"};
11 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)"};
12 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)"};
13 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)"};
14 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)"};
15 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)"};
16 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)"};
17 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"};
18 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"};
19 cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
20 cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
21 cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
22 cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
23 cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
24 cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
25 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)"};
26 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
27 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
28 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)"};
29 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"};
30
31 qboolean        gl_filter_force = false;
32 int             gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
33 int             gl_filter_mag = GL_LINEAR;
34
35
36 static mempool_t *texturemempool;
37 static memexpandablearray_t texturearray;
38
39 // note: this must not conflict with TEXF_ flags in r_textures.h
40 // bitmask for mismatch checking
41 #define GLTEXF_IMPORTANTBITS (0)
42 // dynamic texture (treat texnum == 0 differently)
43 #define GLTEXF_DYNAMIC          0x00080000
44
45 typedef struct textypeinfo_s
46 {
47         textype_t textype;
48         int inputbytesperpixel;
49         int internalbytesperpixel;
50         float glinternalbytesperpixel;
51         int glinternalformat;
52         int glformat;
53         int gltype;
54 }
55 textypeinfo_t;
56
57
58 static textypeinfo_t textype_palette                = {TEXTYPE_PALETTE    , 1, 4, 4.0f, 3                               , GL_BGRA           , GL_UNSIGNED_BYTE };
59 static textypeinfo_t textype_palette_alpha          = {TEXTYPE_PALETTE    , 1, 4, 4.0f, 4                               , GL_BGRA           , GL_UNSIGNED_BYTE };
60 static textypeinfo_t textype_rgba                   = {TEXTYPE_RGBA       , 4, 4, 4.0f, 3                               , GL_RGBA           , GL_UNSIGNED_BYTE };
61 static textypeinfo_t textype_rgba_alpha             = {TEXTYPE_RGBA       , 4, 4, 4.0f, 4                               , GL_RGBA           , GL_UNSIGNED_BYTE };
62 static textypeinfo_t textype_rgba_compress          = {TEXTYPE_RGBA       , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA           , GL_UNSIGNED_BYTE };
63 static textypeinfo_t textype_rgba_alpha_compress    = {TEXTYPE_RGBA       , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA           , GL_UNSIGNED_BYTE };
64 static textypeinfo_t textype_bgra                   = {TEXTYPE_BGRA       , 4, 4, 4.0f, 3                               , GL_BGRA           , GL_UNSIGNED_BYTE };
65 static textypeinfo_t textype_bgra_alpha             = {TEXTYPE_BGRA       , 4, 4, 4.0f, 4                               , GL_BGRA           , GL_UNSIGNED_BYTE };
66 static textypeinfo_t textype_bgra_compress          = {TEXTYPE_BGRA       , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA           , GL_UNSIGNED_BYTE };
67 static textypeinfo_t textype_bgra_alpha_compress    = {TEXTYPE_BGRA       , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_BGRA           , GL_UNSIGNED_BYTE };
68 static textypeinfo_t textype_shadowmap16            = {TEXTYPE_SHADOWMAP  , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB        , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
69 static textypeinfo_t textype_shadowmap24            = {TEXTYPE_SHADOWMAP  , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB        , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
70 static textypeinfo_t textype_alpha                  = {TEXTYPE_ALPHA      , 1, 4, 4.0f, GL_ALPHA                        , GL_ALPHA          , GL_UNSIGNED_BYTE };
71 static textypeinfo_t textype_dxt1                   = {TEXTYPE_DXT1       , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0                 , 0                };
72 static textypeinfo_t textype_dxt1a                  = {TEXTYPE_DXT1A      , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0                 , 0                };
73 static textypeinfo_t textype_dxt3                   = {TEXTYPE_DXT3       , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0                 , 0                };
74 static textypeinfo_t textype_dxt5                   = {TEXTYPE_DXT5       , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0                 , 0                };
75 static textypeinfo_t textype_colorbuffer            = {TEXTYPE_COLORBUFFER, 4, 4, 4.0f, 4                               , GL_BGRA           , GL_UNSIGNED_BYTE };
76
77
78 typedef enum gltexturetype_e
79 {
80         GLTEXTURETYPE_2D,
81         GLTEXTURETYPE_3D,
82         GLTEXTURETYPE_CUBEMAP,
83         GLTEXTURETYPE_RECTANGLE,
84         GLTEXTURETYPE_TOTAL
85 }
86 gltexturetype_t;
87
88 static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_RECTANGLE_ARB};
89 static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2, 2};
90 static int cubemapside[6] =
91 {
92         GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
93         GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
94         GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
95         GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
96         GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
97         GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
98 };
99
100 typedef struct gltexture_s
101 {
102         // this portion of the struct is exposed to the R_GetTexture macro for
103         // speed reasons, must be identical in rtexture_t!
104         int texnum; // GL texture slot number
105         qboolean dirty; // indicates that R_RealGetTexture should be called
106         int gltexturetypeenum; // used by R_Mesh_TexBind
107
108         // dynamic texture stuff [11/22/2007 Black]
109         updatecallback_t updatecallback;
110         void *updatacallback_data;
111         // --- [11/22/2007 Black]
112
113         // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
114         unsigned char *bufferpixels;
115         qboolean buffermodified;
116
117         // pointer to texturepool (check this to see if the texture is allocated)
118         struct gltexturepool_s *pool;
119         // pointer to next texture in texturepool chain
120         struct gltexture_s *chain;
121         // name of the texture (this might be removed someday), no duplicates
122         char identifier[MAX_QPATH + 32];
123         // original data size in *inputtexels
124         int inputwidth, inputheight, inputdepth;
125         // copy of the original texture(s) supplied to the upload function, for
126         // delayed uploads (non-precached)
127         unsigned char *inputtexels;
128         // original data size in *inputtexels
129         int inputdatasize;
130         // flags supplied to the LoadTexture function
131         // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
132         int flags;
133         // picmip level
134         int miplevel;
135         // pointer to one of the textype_ structs
136         textypeinfo_t *textype;
137         // one of the GLTEXTURETYPE_ values
138         int texturetype;
139         // palette if the texture is TEXTYPE_PALETTE
140         const unsigned int *palette;
141         // actual stored texture size after gl_picmip and gl_max_size are applied
142         // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
143         int tilewidth, tileheight, tiledepth;
144         // 1 or 6 depending on texturetype
145         int sides;
146         // bytes per pixel
147         int bytesperpixel;
148         // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
149         int glformat;
150         // 3 or 4
151         int glinternalformat;
152         // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
153         int gltype;
154 }
155 gltexture_t;
156
157 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
158
159 typedef struct gltexturepool_s
160 {
161         unsigned int sentinel;
162         struct gltexture_s *gltchain;
163         struct gltexturepool_s *next;
164 }
165 gltexturepool_t;
166
167 static gltexturepool_t *gltexturepoolchain = NULL;
168
169 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
170 static int resizebuffersize = 0;
171 static const unsigned char *texturebuffer;
172
173 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
174 {
175         switch(textype)
176         {
177         case TEXTYPE_DXT1:
178                 return &textype_dxt1;
179         case TEXTYPE_DXT1A:
180                 return &textype_dxt1a;
181         case TEXTYPE_DXT3:
182                 return &textype_dxt3;
183         case TEXTYPE_DXT5:
184                 return &textype_dxt5;
185         case TEXTYPE_PALETTE:
186                 return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
187         case TEXTYPE_RGBA:
188                 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.arb_texture_compression)
189                         return (flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress;
190                 return (flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba;
191         case TEXTYPE_BGRA:
192                 if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.arb_texture_compression)
193                         return (flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress;
194                 return (flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra;
195         case TEXTYPE_ALPHA:
196                 return &textype_alpha;
197         case TEXTYPE_SHADOWMAP:
198                 return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
199         case TEXTYPE_COLORBUFFER:
200                 return &textype_colorbuffer;
201         default:
202                 Host_Error("R_GetTexTypeInfo: unknown texture format");
203                 break;
204         }
205         return NULL;
206 }
207
208 // dynamic texture code [11/22/2007 Black]
209 void R_MarkDirtyTexture(rtexture_t *rt) {
210         gltexture_t *glt = (gltexture_t*) rt;
211         if( !glt ) {
212                 return;
213         }
214
215         // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
216         if (glt->flags & GLTEXF_DYNAMIC)
217         {
218                 // mark it as dirty, so R_RealGetTexture gets called
219                 glt->dirty = true;
220         }
221 }
222
223 void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
224         gltexture_t *glt = (gltexture_t*) rt;
225         if( !glt ) {
226                 return;
227         }
228
229         glt->flags |= GLTEXF_DYNAMIC;
230         glt->updatecallback = updatecallback;
231         glt->updatacallback_data = data;
232 }
233
234 static void R_UpdateDynamicTexture(gltexture_t *glt) {
235         glt->dirty = false;
236         if( glt->updatecallback ) {
237                 glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
238         }
239 }
240
241 void R_PurgeTexture(rtexture_t *rt)
242 {
243         if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
244                 R_FreeTexture(rt);
245         }
246 }
247
248 void R_FreeTexture(rtexture_t *rt)
249 {
250         gltexture_t *glt, **gltpointer;
251
252         glt = (gltexture_t *)rt;
253         if (glt == NULL)
254                 Host_Error("R_FreeTexture: texture == NULL");
255
256         for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
257         if (*gltpointer == glt)
258                 *gltpointer = glt->chain;
259         else
260                 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
261
262         if (glt->texnum)
263         {
264                 CHECKGLERROR
265                 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
266         }
267
268         if (glt->inputtexels)
269                 Mem_Free(glt->inputtexels);
270         Mem_ExpandableArray_FreeRecord(&texturearray, glt);
271 }
272
273 rtexturepool_t *R_AllocTexturePool(void)
274 {
275         gltexturepool_t *pool;
276         if (texturemempool == NULL)
277                 return NULL;
278         pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
279         if (pool == NULL)
280                 return NULL;
281         pool->next = gltexturepoolchain;
282         gltexturepoolchain = pool;
283         pool->sentinel = TEXTUREPOOL_SENTINEL;
284         return (rtexturepool_t *)pool;
285 }
286
287 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
288 {
289         gltexturepool_t *pool, **poolpointer;
290         if (rtexturepool == NULL)
291                 return;
292         if (*rtexturepool == NULL)
293                 return;
294         pool = (gltexturepool_t *)(*rtexturepool);
295         *rtexturepool = NULL;
296         if (pool->sentinel != TEXTUREPOOL_SENTINEL)
297                 Host_Error("R_FreeTexturePool: pool already freed");
298         for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
299         if (*poolpointer == pool)
300                 *poolpointer = pool->next;
301         else
302                 Host_Error("R_FreeTexturePool: pool not linked");
303         while (pool->gltchain)
304                 R_FreeTexture((rtexture_t *)pool->gltchain);
305         Mem_Free(pool);
306 }
307
308
309 typedef struct glmode_s
310 {
311         char *name;
312         int minification, magnification;
313 }
314 glmode_t;
315
316 static glmode_t modes[6] =
317 {
318         {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
319         {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
320         {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
321         {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
322         {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
323         {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
324 };
325
326 static void GL_TextureMode_f (void)
327 {
328         int i;
329         GLint oldbindtexnum;
330         gltexture_t *glt;
331         gltexturepool_t *pool;
332
333         if (Cmd_Argc() == 1)
334         {
335                 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
336                 for (i = 0;i < 6;i++)
337                 {
338                         if (gl_filter_min == modes[i].minification)
339                         {
340                                 Con_Printf("%s\n", modes[i].name);
341                                 return;
342                         }
343                 }
344                 Con_Print("current filter is unknown???\n");
345                 return;
346         }
347
348         for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
349                 if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) )
350                         break;
351         if (i == 6)
352         {
353                 Con_Print("bad filter name\n");
354                 return;
355         }
356
357         gl_filter_min = modes[i].minification;
358         gl_filter_mag = modes[i].magnification;
359         gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force"));
360
361         // change all the existing mipmap texture objects
362         // FIXME: force renderer(/client/something?) restart instead?
363         CHECKGLERROR
364         GL_ActiveTexture(0);
365         for (pool = gltexturepoolchain;pool;pool = pool->next)
366         {
367                 for (glt = pool->gltchain;glt;glt = glt->chain)
368                 {
369                         // only update already uploaded images
370                         if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
371                         {
372                                 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
373                                 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
374                                 if (glt->flags & TEXF_MIPMAP)
375                                 {
376                                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
377                                 }
378                                 else
379                                 {
380                                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
381                                 }
382                                 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
383                                 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
384                         }
385                 }
386         }
387 }
388
389 static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, int inwidth, int inheight, int indepth, int *outwidth, int *outheight, int *outdepth)
390 {
391         int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1;
392
393         switch (texturetype)
394         {
395         default:
396         case GLTEXTURETYPE_2D:
397                 maxsize = vid.maxtexturesize_2d;
398                 if (flags & TEXF_PICMIP)
399                 {
400                         maxsize = bound(1, gl_max_size.integer, maxsize);
401                         picmip = miplevel;
402                 }
403                 break;
404         case GLTEXTURETYPE_3D:
405                 maxsize = vid.maxtexturesize_3d;
406                 break;
407         case GLTEXTURETYPE_CUBEMAP:
408                 maxsize = vid.maxtexturesize_cubemap;
409                 break;
410         }
411
412         if (outwidth)
413         {
414                 if (vid.support.arb_texture_non_power_of_two)
415                         width2 = min(inwidth >> picmip, maxsize);
416                 else
417                 {
418                         for (width2 = 1;width2 < inwidth;width2 <<= 1);
419                         for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
420                 }
421                 *outwidth = max(1, width2);
422         }
423         if (outheight)
424         {
425                 if (vid.support.arb_texture_non_power_of_two)
426                         height2 = min(inheight >> picmip, maxsize);
427                 else
428                 {
429                         for (height2 = 1;height2 < inheight;height2 <<= 1);
430                         for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
431                 }
432                 *outheight = max(1, height2);
433         }
434         if (outdepth)
435         {
436                 if (vid.support.arb_texture_non_power_of_two)
437                         depth2 = min(indepth >> picmip, maxsize);
438                 else
439                 {
440                         for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
441                         for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
442                 }
443                 *outdepth = max(1, depth2);
444         }
445 }
446
447
448 static int R_CalcTexelDataSize (gltexture_t *glt)
449 {
450         int width2, height2, depth2, size;
451
452         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2);
453
454         size = width2 * height2 * depth2;
455
456         if (glt->flags & TEXF_MIPMAP)
457         {
458                 while (width2 > 1 || height2 > 1 || depth2 > 1)
459                 {
460                         if (width2 > 1)
461                                 width2 >>= 1;
462                         if (height2 > 1)
463                                 height2 >>= 1;
464                         if (depth2 > 1)
465                                 depth2 >>= 1;
466                         size += width2 * height2 * depth2;
467                 }
468         }
469
470         return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
471 }
472
473 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
474 {
475         int glsize;
476         int isloaded;
477         int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
478         int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
479         gltexture_t *glt;
480         gltexturepool_t *pool;
481         if (printeach)
482                 Con_Print("glsize input loaded mip alpha name\n");
483         for (pool = gltexturepoolchain;pool;pool = pool->next)
484         {
485                 pooltotal = 0;
486                 pooltotalt = 0;
487                 pooltotalp = 0;
488                 poolloaded = 0;
489                 poolloadedt = 0;
490                 poolloadedp = 0;
491                 for (glt = pool->gltchain;glt;glt = glt->chain)
492                 {
493                         glsize = R_CalcTexelDataSize(glt);
494                         isloaded = glt->texnum != 0;
495                         pooltotal++;
496                         pooltotalt += glsize;
497                         pooltotalp += glt->inputdatasize;
498                         if (isloaded)
499                         {
500                                 poolloaded++;
501                                 poolloadedt += glsize;
502                                 poolloadedp += glt->inputdatasize;
503                         }
504                         if (printeach)
505                                 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);
506                 }
507                 if (printpool)
508                         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);
509                 sumtotal += pooltotal;
510                 sumtotalt += pooltotalt;
511                 sumtotalp += pooltotalp;
512                 sumloaded += poolloaded;
513                 sumloadedt += poolloadedt;
514                 sumloadedp += poolloadedp;
515         }
516         if (printtotal)
517                 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);
518 }
519
520 static void R_TextureStats_f(void)
521 {
522         R_TextureStats_Print(true, true, true);
523 }
524
525 static void r_textures_start(void)
526 {
527         // LordHavoc: allow any alignment
528         CHECKGLERROR
529         qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
530         qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
531
532         texturemempool = Mem_AllocPool("texture management", 0, NULL);
533         Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512);
534
535         // Disable JPEG screenshots if the DLL isn't loaded
536         if (! JPEG_OpenLibrary ())
537                 Cvar_SetValueQuick (&scr_screenshot_jpeg, 0);
538         if (! PNG_OpenLibrary ())
539                 Cvar_SetValueQuick (&scr_screenshot_png, 0);
540 }
541
542 static void r_textures_shutdown(void)
543 {
544         rtexturepool_t *temp;
545
546         JPEG_CloseLibrary ();
547
548         while(gltexturepoolchain)
549         {
550                 temp = (rtexturepool_t *) gltexturepoolchain;
551                 R_FreeTexturePool(&temp);
552         }
553
554         resizebuffersize = 0;
555         resizebuffer = NULL;
556         colorconvertbuffer = NULL;
557         texturebuffer = NULL;
558         Mem_ExpandableArray_FreeArray(&texturearray);
559         Mem_FreePool(&texturemempool);
560 }
561
562 static void r_textures_newmap(void)
563 {
564 }
565
566 void R_Textures_Init (void)
567 {
568         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");
569         Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
570         Cvar_RegisterVariable (&gl_max_size);
571         Cvar_RegisterVariable (&gl_picmip);
572         Cvar_RegisterVariable (&gl_picmip_world);
573         Cvar_RegisterVariable (&r_picmipworld);
574         Cvar_RegisterVariable (&gl_picmip_sprites);
575         Cvar_RegisterVariable (&r_picmipsprites);
576         Cvar_RegisterVariable (&gl_picmip_other);
577         Cvar_RegisterVariable (&gl_max_lightmapsize);
578         Cvar_RegisterVariable (&r_lerpimages);
579         Cvar_RegisterVariable (&gl_texture_anisotropy);
580         Cvar_RegisterVariable (&gl_texturecompression);
581         Cvar_RegisterVariable (&gl_texturecompression_color);
582         Cvar_RegisterVariable (&gl_texturecompression_normal);
583         Cvar_RegisterVariable (&gl_texturecompression_gloss);
584         Cvar_RegisterVariable (&gl_texturecompression_glow);
585         Cvar_RegisterVariable (&gl_texturecompression_2d);
586         Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
587         Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
588         Cvar_RegisterVariable (&gl_texturecompression_sky);
589         Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
590         Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
591         Cvar_RegisterVariable (&gl_nopartialtextureupdates);
592
593         R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, NULL, NULL);
594 }
595
596 void R_Textures_Frame (void)
597 {
598         static int old_aniso = 0;
599
600         // could do procedural texture animation here, if we keep track of which
601         // textures were accessed this frame...
602
603         // free the resize buffers
604         resizebuffersize = 0;
605         if (resizebuffer)
606         {
607                 Mem_Free(resizebuffer);
608                 resizebuffer = NULL;
609         }
610         if (colorconvertbuffer)
611         {
612                 Mem_Free(colorconvertbuffer);
613                 colorconvertbuffer = NULL;
614         }
615
616         if (old_aniso != gl_texture_anisotropy.integer)
617         {
618                 gltexture_t *glt;
619                 gltexturepool_t *pool;
620                 GLint oldbindtexnum;
621
622                 old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
623
624                 Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
625
626                 CHECKGLERROR
627                 GL_ActiveTexture(0);
628                 for (pool = gltexturepoolchain;pool;pool = pool->next)
629                 {
630                         for (glt = pool->gltchain;glt;glt = glt->chain)
631                         {
632                                 // only update already uploaded images
633                                 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
634                                 {
635                                         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
636
637                                         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
638                                         qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
639
640                                         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
641                                 }
642                         }
643                 }
644         }
645 }
646
647 void R_MakeResizeBufferBigger(int size)
648 {
649         if (resizebuffersize < size)
650         {
651                 resizebuffersize = size;
652                 if (resizebuffer)
653                         Mem_Free(resizebuffer);
654                 if (colorconvertbuffer)
655                         Mem_Free(colorconvertbuffer);
656                 resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
657                 colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize);
658                 if (!resizebuffer || !colorconvertbuffer)
659                         Host_Error("R_Upload: out of memory");
660         }
661 }
662
663 static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
664 {
665         int textureenum = gltexturetypeenums[texturetype];
666         int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
667
668         CHECKGLERROR
669
670         if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
671         {
672                 int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
673                 if (gl_texture_anisotropy.integer != aniso)
674                         Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
675                 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
676         }
677         qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
678         qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
679         if (gltexturetypedimensions[texturetype] >= 3)
680         {
681                 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
682         }
683
684         CHECKGLERROR
685         if (!gl_filter_force && flags & TEXF_FORCENEAREST)
686         {
687                 if (flags & TEXF_MIPMAP)
688                 {
689                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
690                 }
691                 else
692                 {
693                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
694                 }
695                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
696         }
697         else if (!gl_filter_force && flags & TEXF_FORCELINEAR)
698         {
699                 if (flags & TEXF_MIPMAP)
700                 {
701                         if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR)
702                         {
703                                 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
704                         }
705                         else
706                         {
707                                 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
708                         }
709                 }
710                 else
711                 {
712                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
713                 }
714                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
715         }
716         else
717         {
718                 if (flags & TEXF_MIPMAP)
719                 {
720                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
721                 }
722                 else
723                 {
724                         qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
725                 }
726                 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
727         }
728
729         if (textype == TEXTYPE_SHADOWMAP)
730         {
731                 if (vid.support.arb_shadow)
732                 {
733                         if (flags & TEXF_COMPARE)
734                         {
735                                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
736                         }
737                         else
738                         {
739                                 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
740                         }
741                         qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
742                 }
743                 qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
744         }
745
746         CHECKGLERROR
747 }
748
749 static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
750 {
751         int i, mip, width, height, depth;
752         GLint oldbindtexnum;
753         const unsigned char *prevbuffer;
754         prevbuffer = data;
755
756         CHECKGLERROR
757
758         // we need to restore the texture binding after finishing the upload
759         GL_ActiveTexture(0);
760         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
761         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
762
763         // these are rounded up versions of the size to do better resampling
764         if (vid.support.arb_texture_non_power_of_two || glt->texturetype == GLTEXTURETYPE_RECTANGLE)
765         {
766                 width = glt->inputwidth;
767                 height = glt->inputheight;
768                 depth = glt->inputdepth;
769         }
770         else
771         {
772                 for (width  = 1;width  < glt->inputwidth ;width  <<= 1);
773                 for (height = 1;height < glt->inputheight;height <<= 1);
774                 for (depth  = 1;depth  < glt->inputdepth ;depth  <<= 1);
775         }
776
777         R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
778         R_MakeResizeBufferBigger(fragwidth * fragheight * fragdepth * glt->sides * glt->bytesperpixel);
779
780         if (prevbuffer == NULL)
781         {
782                 memset(resizebuffer, 0, fragwidth * fragheight * fragdepth * glt->bytesperpixel);
783                 prevbuffer = resizebuffer;
784         }
785         else if (glt->textype->textype == TEXTYPE_PALETTE)
786         {
787                 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
788                 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, fragwidth * fragheight * fragdepth * glt->sides, glt->palette);
789                 prevbuffer = colorconvertbuffer;
790         }
791
792         // upload the image - preferring to do only complete uploads (drivers do not really like partial updates)
793
794         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))
795         {
796                 // update a portion of the image
797                 switch(glt->texturetype)
798                 {
799                 case GLTEXTURETYPE_2D:
800                         qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
801                         break;
802                 case GLTEXTURETYPE_3D:
803                         qglTexSubImage3D(GL_TEXTURE_3D, 0, fragx, fragy, fragz, fragwidth, fragheight, fragdepth, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
804                         break;
805                 default:
806                         Host_Error("R_Upload: partial update of type other than 2D");
807                         break;
808                 }
809         }
810         else
811         {
812                 if (fragx || fragy || fragz || glt->inputwidth != fragwidth || glt->inputheight != fragheight || glt->inputdepth != fragdepth)
813                         Host_Error("R_Upload: partial update not allowed on initial upload or in combination with PICMIP or MIPMAP\n");
814
815                 // cubemaps contain multiple images and thus get processed a bit differently
816                 if (glt->texturetype != GLTEXTURETYPE_CUBEMAP)
817                 {
818                         if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
819                         {
820                                 Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
821                                 prevbuffer = resizebuffer;
822                         }
823                         // picmip/max_size
824                         while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
825                         {
826                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
827                                 prevbuffer = resizebuffer;
828                         }
829                 }
830                 mip = 0;
831                 if (qglGetCompressedTexImageARB)
832                 {
833                         if (gl_texturecompression.integer >= 2)
834                                 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
835                         else
836                                 qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
837                         CHECKGLERROR
838                 }
839                 switch(glt->texturetype)
840                 {
841                 case GLTEXTURETYPE_2D:
842                         qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
843                         if (glt->flags & TEXF_MIPMAP)
844                         {
845                                 while (width > 1 || height > 1 || depth > 1)
846                                 {
847                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
848                                         prevbuffer = resizebuffer;
849                                         qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
850                                 }
851                         }
852                         break;
853                 case GLTEXTURETYPE_3D:
854                         qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
855                         if (glt->flags & TEXF_MIPMAP)
856                         {
857                                 while (width > 1 || height > 1 || depth > 1)
858                                 {
859                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
860                                         prevbuffer = resizebuffer;
861                                         qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
862                                 }
863                         }
864                         break;
865                 case GLTEXTURETYPE_CUBEMAP:
866                         // convert and upload each side in turn,
867                         // from a continuous block of input texels
868                         texturebuffer = (unsigned char *)prevbuffer;
869                         for (i = 0;i < 6;i++)
870                         {
871                                 prevbuffer = texturebuffer;
872                                 texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
873                                 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
874                                 {
875                                         Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
876                                         prevbuffer = resizebuffer;
877                                 }
878                                 // picmip/max_size
879                                 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
880                                 {
881                                         Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
882                                         prevbuffer = resizebuffer;
883                                 }
884                                 mip = 0;
885                                 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
886                                 if (glt->flags & TEXF_MIPMAP)
887                                 {
888                                         while (width > 1 || height > 1 || depth > 1)
889                                         {
890                                                 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
891                                                 prevbuffer = resizebuffer;
892                                                 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
893                                         }
894                                 }
895                         }
896                         break;
897                 case GLTEXTURETYPE_RECTANGLE:
898                         qglTexImage2D(GL_TEXTURE_RECTANGLE_ARB, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, NULL);CHECKGLERROR
899                         break;
900                 }
901                 GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
902         }
903         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
904 }
905
906 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)
907 {
908         int i, size;
909         gltexture_t *glt;
910         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
911         textypeinfo_t *texinfo, *texinfo2;
912
913         if (cls.state == ca_dedicated)
914                 return NULL;
915
916         if (texturetype == GLTEXTURETYPE_RECTANGLE && !vid.support.arb_texture_rectangle)
917         {
918                 Con_Printf ("R_LoadTexture: rectangle texture not supported by driver\n");
919                 return NULL;
920         }
921         if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
922         {
923                 Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
924                 return NULL;
925         }
926         if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
927         {
928                 Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
929                 return NULL;
930         }
931
932         texinfo = R_GetTexTypeInfo(textype, flags);
933         size = width * height * depth * sides * texinfo->inputbytesperpixel;
934         if (size < 1)
935         {
936                 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
937                 return NULL;
938         }
939
940         // clear the alpha flag if the texture has no transparent pixels
941         switch(textype)
942         {
943         case TEXTYPE_PALETTE:
944                 if (flags & TEXF_ALPHA)
945                 {
946                         flags &= ~TEXF_ALPHA;
947                         if (data)
948                         {
949                                 for (i = 0;i < size;i++)
950                                 {
951                                         if (((unsigned char *)&palette[data[i]])[3] < 255)
952                                         {
953                                                 flags |= TEXF_ALPHA;
954                                                 break;
955                                         }
956                                 }
957                         }
958                 }
959                 break;
960         case TEXTYPE_RGBA:
961         case TEXTYPE_BGRA:
962                 if (flags & TEXF_ALPHA)
963                 {
964                         flags &= ~TEXF_ALPHA;
965                         if (data)
966                         {
967                                 for (i = 3;i < size;i += 4)
968                                 {
969                                         if (data[i] < 255)
970                                         {
971                                                 flags |= TEXF_ALPHA;
972                                                 break;
973                                         }
974                                 }
975                         }
976                 }
977                 break;
978         case TEXTYPE_SHADOWMAP:
979                 break;
980         case TEXTYPE_DXT1:
981                 break;
982         case TEXTYPE_DXT1A:
983         case TEXTYPE_DXT3:
984         case TEXTYPE_DXT5:
985                 flags |= TEXF_ALPHA;
986                 break;
987         case TEXTYPE_ALPHA:
988                 flags |= TEXF_ALPHA;
989                 break;
990         case TEXTYPE_COLORBUFFER:
991                 flags |= TEXF_ALPHA;
992                 break;
993         default:
994                 Host_Error("R_LoadTexture: unknown texture type");
995         }
996
997         texinfo2 = R_GetTexTypeInfo(textype, flags);
998         if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
999                 texinfo = texinfo2;
1000         else
1001                 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1002
1003         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1004         if (identifier)
1005                 strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1006         glt->pool = pool;
1007         glt->chain = pool->gltchain;
1008         pool->gltchain = glt;
1009         glt->inputwidth = width;
1010         glt->inputheight = height;
1011         glt->inputdepth = depth;
1012         glt->flags = flags;
1013         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
1014         glt->textype = texinfo;
1015         glt->texturetype = texturetype;
1016         glt->inputdatasize = size;
1017         glt->palette = palette;
1018         glt->glinternalformat = texinfo->glinternalformat;
1019         glt->glformat = texinfo->glformat;
1020         glt->gltype = texinfo->gltype;
1021         glt->bytesperpixel = texinfo->internalbytesperpixel;
1022         glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1023         glt->texnum = 0;
1024         glt->dirty = false;
1025         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1026         // init the dynamic texture attributes, too [11/22/2007 Black]
1027         glt->updatecallback = NULL;
1028         glt->updatacallback_data = NULL;
1029
1030         GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth);
1031
1032         // upload the texture
1033         // data may be NULL (blank texture for dynamic rendering)
1034         CHECKGLERROR
1035         qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1036         R_Upload(glt, data, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
1037         if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
1038                 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1039
1040         // texture converting and uploading can take a while, so make sure we're sending keepalives
1041         CL_KeepaliveMessage(false);
1042
1043         return (rtexture_t *)glt;
1044 }
1045
1046 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)
1047 {
1048         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1049 }
1050
1051 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)
1052 {
1053         return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1054 }
1055
1056 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)
1057 {
1058         return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1059 }
1060
1061 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)
1062 {
1063         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_RECTANGLE, data, palette);
1064 }
1065
1066 static int R_ShadowMapTextureFlags(int precision, qboolean filter)
1067 {
1068         int flags = TEXF_CLAMP;
1069         if (filter)
1070                 flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
1071         else
1072                 flags |= TEXF_FORCENEAREST;
1073         if (precision <= 16)
1074                 flags |= TEXF_LOWPRECISION;
1075         return flags;
1076 }
1077
1078 rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1079 {
1080         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
1081 }
1082
1083 rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
1084 {
1085         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
1086 }
1087
1088 rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter)
1089 {
1090     return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
1091 }
1092
1093 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed)
1094 {
1095         gltexture_t *glt = (gltexture_t *)rt;
1096         unsigned char *dds;
1097         int oldbindtexnum;
1098         int bytesperpixel = 0;
1099         int bytesperblock = 0;
1100         int dds_flags;
1101         int dds_format_flags;
1102         int dds_caps1;
1103         int dds_caps2;
1104         int ret;
1105         int mip;
1106         int mipmaps;
1107         int mipinfo[16][4];
1108         int ddssize = 128;
1109         GLint internalformat;
1110         const char *ddsfourcc;
1111         if (!rt)
1112                 return -1; // NULL pointer
1113         if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1114                 return -2; // broken driver - crashes on reading internal format
1115         if (!qglGetTexLevelParameteriv)
1116                 return -2;
1117         GL_ActiveTexture(0);
1118         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1119         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1120         qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1121         switch(internalformat)
1122         {
1123         default: ddsfourcc = NULL;bytesperpixel = 4;break;
1124         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1125         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1126         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1127         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1128         }
1129         if (!bytesperblock && skipuncompressed)
1130                 return -3; // skipped
1131         memset(mipinfo, 0, sizeof(mipinfo));
1132         mipinfo[0][0] = glt->tilewidth;
1133         mipinfo[0][1] = glt->tileheight;
1134         mipmaps = 1;
1135         if (glt->flags & TEXF_MIPMAP)
1136         {
1137                 for (mip = 1;mip < 16;mip++)
1138                 {
1139                         mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1140                         mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1141                         if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1142                         {
1143                                 mip++;
1144                                 break;
1145                         }
1146                 }
1147                 mipmaps = mip;
1148         }
1149         for (mip = 0;mip < mipmaps;mip++)
1150         {
1151                 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1152                 mipinfo[mip][3] = ddssize;
1153                 ddssize += mipinfo[mip][2];
1154         }
1155         dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1156         if (!dds)
1157                 return -4;
1158         dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1159         dds_caps2 = 0;
1160         if (bytesperblock)
1161         {
1162                 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1163                 dds_format_flags = 0x4; // DDPF_FOURCC
1164         }
1165         else
1166         {
1167                 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1168                 dds_format_flags = 0x41; // DDPF_RGB | DDPF_ALPHAPIXELS
1169         }
1170         if (mipmaps)
1171         {
1172                 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1173                 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1174         }
1175         memcpy(dds, "DDS ", 4);
1176         StoreLittleLong(dds+4, ddssize);
1177         StoreLittleLong(dds+8, dds_flags);
1178         StoreLittleLong(dds+12, mipinfo[0][1]); // height
1179         StoreLittleLong(dds+16, mipinfo[0][0]); // width
1180         StoreLittleLong(dds+24, 1); // depth
1181         StoreLittleLong(dds+28, mipmaps); // mipmaps
1182         StoreLittleLong(dds+76, 32); // format size
1183         StoreLittleLong(dds+80, dds_format_flags);
1184         StoreLittleLong(dds+108, dds_caps1);
1185         StoreLittleLong(dds+112, dds_caps2);
1186         if (bytesperblock)
1187         {
1188                 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1189                 memcpy(dds+84, ddsfourcc, 4);
1190                 for (mip = 0;mip < mipmaps;mip++)
1191                 {
1192                         qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1193                 }
1194         }
1195         else
1196         {
1197                 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1198                 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1199                 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1200                 for (mip = 0;mip < mipmaps;mip++)
1201                 {
1202                         qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1203                 }
1204         }
1205         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1206         ret = FS_WriteFile(filename, dds, ddssize);
1207         Mem_Free(dds);
1208         return ret ? ddssize : -5;
1209 }
1210
1211 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
1212 {
1213         int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1214         //int dds_flags;
1215         textype_t textype;
1216         int bytesperblock, bytesperpixel;
1217         int mipcomplete;
1218         gltexture_t *glt;
1219         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1220         textypeinfo_t *texinfo;
1221         int mip, mipwidth, mipheight, mipsize;
1222         unsigned int c;
1223         GLint oldbindtexnum;
1224         const unsigned char *mippixels, *ddspixels;
1225         unsigned char *dds;
1226         fs_offset_t ddsfilesize;
1227         unsigned int ddssize;
1228
1229         if (cls.state == ca_dedicated)
1230                 return NULL;
1231
1232         dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1233         ddssize = ddsfilesize;
1234
1235         if (!dds)
1236         {
1237                 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1238                 return NULL; // not found
1239         }
1240
1241         if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1242         {
1243                 Mem_Free(dds);
1244                 Con_Printf("^1%s: not a DDS image\n", filename);
1245                 return NULL;
1246         }
1247
1248         //dds_flags = BuffLittleLong(dds+8);
1249         dds_format_flags = BuffLittleLong(dds+80);
1250         dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1251         dds_width = BuffLittleLong(dds+16);
1252         dds_height = BuffLittleLong(dds+12);
1253         ddspixels = dds + 128;
1254
1255         flags &= ~TEXF_ALPHA;
1256         if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1257         {
1258                 // very sloppy BGRA 32bit identification
1259                 textype = TEXTYPE_BGRA;
1260                 bytesperblock = 0;
1261                 bytesperpixel = 4;
1262                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1263                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1264                 {
1265                         Mem_Free(dds);
1266                         Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1267                         return NULL;
1268                 }
1269                 // check alpha
1270                 for (i = 3;i < size;i += 4)
1271                         if (ddspixels[i] < 255)
1272                                 break;
1273                 if (i >= size)
1274                         flags &= ~TEXF_ALPHA;
1275         }
1276         else if (!memcmp(dds+84, "DXT1", 4))
1277         {
1278                 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1279                 // LordHavoc: it is my belief that this does not infringe on the
1280                 // patent because it is not decoding pixels...
1281                 textype = TEXTYPE_DXT1;
1282                 bytesperblock = 8;
1283                 bytesperpixel = 0;
1284                 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1285                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1286                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1287                 {
1288                         Mem_Free(dds);
1289                         Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1290                         return NULL;
1291                 }
1292                 for (i = 0;i < size;i += bytesperblock)
1293                         if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1294                                 break;
1295                 if (i < size)
1296                         textype = TEXTYPE_DXT1A;
1297                 else
1298                         flags &= ~TEXF_ALPHA;
1299         }
1300         else if (!memcmp(dds+84, "DXT3", 4))
1301         {
1302                 textype = TEXTYPE_DXT3;
1303                 bytesperblock = 16;
1304                 bytesperpixel = 0;
1305                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1306                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1307                 {
1308                         Mem_Free(dds);
1309                         Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1310                         return NULL;
1311                 }
1312         }
1313         else if (!memcmp(dds+84, "DXT5", 4))
1314         {
1315                 textype = TEXTYPE_DXT5;
1316                 bytesperblock = 16;
1317                 bytesperpixel = 0;
1318                 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1319                 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1320                 {
1321                         Mem_Free(dds);
1322                         Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1323                         return NULL;
1324                 }
1325         }
1326         else
1327         {
1328                 Mem_Free(dds);
1329                 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1330                 return NULL;
1331         }
1332
1333         // return whether this texture is transparent
1334         if (hasalphaflag)
1335                 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1336
1337         // calculate average color if requested
1338         if (avgcolor)
1339         {
1340                 float f;
1341                 Vector4Clear(avgcolor);
1342                 if (bytesperblock)
1343                 {
1344                         for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
1345                         {
1346                                 c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
1347                                 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
1348                                 avgcolor[1] += ((c >>  5) & 0x3F) + ((c >> 21) & 0x3F);
1349                                 avgcolor[2] += ((c      ) & 0x1F) + ((c >> 16) & 0x1F);
1350                         }
1351                         f = (float)bytesperblock / size;
1352                         avgcolor[0] *= (0.5f / 31.0f) * f;
1353                         avgcolor[1] *= (0.5f / 63.0f) * f;
1354                         avgcolor[2] *= (0.5f / 31.0f) * f;
1355                         avgcolor[3] = 1; // too hard to calculate
1356                 }
1357                 else
1358                 {
1359                         for (i = 0;i < size;i += 4)
1360                         {
1361                                 avgcolor[0] += ddspixels[i+2];
1362                                 avgcolor[1] += ddspixels[i+1];
1363                                 avgcolor[2] += ddspixels[i];
1364                                 avgcolor[3] += ddspixels[i+3];
1365                         }
1366                         f = (1.0f / 255.0f) * bytesperpixel / size;
1367                         avgcolor[0] *= f;
1368                         avgcolor[1] *= f;
1369                         avgcolor[2] *= f;
1370                         avgcolor[3] *= f;
1371                 }
1372         }
1373
1374         // this is where we apply gl_picmip
1375         mippixels = ddspixels;
1376         mipwidth = dds_width;
1377         mipheight = dds_height;
1378         while(miplevel >= 1 && dds_miplevels >= 1)
1379         {
1380                 if (mipwidth <= 1 && mipheight <= 1)
1381                         break;
1382                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1383                 mippixels += mipsize; // just skip
1384                 --dds_miplevels;
1385                 --miplevel;
1386                 if (mipwidth > 1)
1387                         mipwidth >>= 1;
1388                 if (mipheight > 1)
1389                         mipheight >>= 1;
1390         }
1391
1392         if (dds_miplevels > 1)
1393                 flags |= TEXF_MIPMAP;
1394         else
1395                 flags &= ~TEXF_MIPMAP;
1396
1397         // if S3TC is not supported, there's very little we can do about it
1398         if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
1399         {
1400                 Mem_Free(dds);
1401                 Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
1402                 return NULL;
1403         }
1404
1405         texinfo = R_GetTexTypeInfo(textype, flags);
1406
1407         glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
1408         strlcpy (glt->identifier, filename, sizeof(glt->identifier));
1409         glt->pool = pool;
1410         glt->chain = pool->gltchain;
1411         pool->gltchain = glt;
1412         glt->inputwidth = mipwidth;
1413         glt->inputheight = mipheight;
1414         glt->inputdepth = 1;
1415         glt->flags = flags;
1416         glt->textype = texinfo;
1417         glt->texturetype = GLTEXTURETYPE_2D;
1418         glt->inputdatasize = ddssize;
1419         glt->glinternalformat = texinfo->glinternalformat;
1420         glt->glformat = texinfo->glformat;
1421         glt->gltype = texinfo->gltype;
1422         glt->bytesperpixel = texinfo->internalbytesperpixel;
1423         glt->sides = 1;
1424         glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
1425         glt->tilewidth = mipwidth;
1426         glt->tileheight = mipheight;
1427         glt->tiledepth = 1;
1428
1429         // texture uploading can take a while, so make sure we're sending keepalives
1430         CL_KeepaliveMessage(false);
1431
1432         // upload the texture
1433         // we need to restore the texture binding after finishing the upload
1434         CHECKGLERROR
1435         GL_ActiveTexture(0);
1436         oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1437         qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1438         qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1439         mipcomplete = false;
1440
1441         for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
1442         {
1443                 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1444                 if (mippixels + mipsize > dds + ddssize)
1445                         break;
1446                 if (bytesperblock)
1447                 {
1448                         qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
1449                 }
1450                 else
1451                 {
1452                         qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
1453                 }
1454                 mippixels += mipsize;
1455                 if (mipwidth <= 1 && mipheight <= 1)
1456                 {
1457                         mipcomplete = true;
1458                         break;
1459                 }
1460                 if (mipwidth > 1)
1461                         mipwidth >>= 1;
1462                 if (mipheight > 1)
1463                         mipheight >>= 1;
1464         }
1465         if (dds_miplevels >= 1 && !mipcomplete)
1466         {
1467                 // need to set GL_TEXTURE_MAX_LEVEL
1468                 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
1469         }
1470         GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
1471         qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1472
1473         Mem_Free(dds);
1474         return (rtexture_t *)glt;
1475 }
1476
1477 int R_TextureWidth(rtexture_t *rt)
1478 {
1479         return rt ? ((gltexture_t *)rt)->inputwidth : 0;
1480 }
1481
1482 int R_TextureHeight(rtexture_t *rt)
1483 {
1484         return rt ? ((gltexture_t *)rt)->inputheight : 0;
1485 }
1486
1487 void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
1488 {
1489         gltexture_t *glt = (gltexture_t *)rt;
1490         if (data == NULL)
1491                 Host_Error("R_UpdateTexture: no data supplied");
1492         if (glt == NULL)
1493                 Host_Error("R_UpdateTexture: no texture supplied");
1494         if (!glt->texnum)
1495                 Host_Error("R_UpdateTexture: texture has not been uploaded yet");
1496         // update part of the texture
1497         if (glt->bufferpixels)
1498         {
1499                 int j;
1500                 int bpp = glt->bytesperpixel;
1501                 int inputskip = width*bpp;
1502                 int outputskip = glt->tilewidth*bpp;
1503                 const unsigned char *input = data;
1504                 unsigned char *output = glt->bufferpixels;
1505                 if (x < 0)
1506                 {
1507                         width += x;
1508                         input -= x*bpp;
1509                         x = 0;
1510                 }
1511                 if (y < 0)
1512                 {
1513                         height += y;
1514                         input -= y*inputskip;
1515                         y = 0;
1516                 }
1517                 if (width > glt->tilewidth - x)
1518                         width = glt->tilewidth - x;
1519                 if (height > glt->tileheight - y)
1520                         height = glt->tileheight - y;
1521                 if (width < 1 || height < 1)
1522                         return;
1523                 glt->dirty = true;
1524                 glt->buffermodified = true;
1525                 output += y*outputskip + x*bpp;
1526                 for (j = 0;j < height;j++, output += outputskip, input += inputskip)
1527                         memcpy(output, input, width*bpp);
1528         }
1529         else
1530                 R_Upload(glt, data, x, y, 0, width, height, 1);
1531 }
1532
1533 int R_RealGetTexture(rtexture_t *rt)
1534 {
1535         if (rt)
1536         {
1537                 gltexture_t *glt;
1538                 glt = (gltexture_t *)rt;
1539                 if (glt->flags & GLTEXF_DYNAMIC)
1540                         R_UpdateDynamicTexture(glt);
1541                 if (glt->buffermodified && glt->bufferpixels)
1542                 {
1543                         glt->buffermodified = false;
1544                         R_Upload(glt, glt->bufferpixels, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth);
1545                 }
1546                 glt->dirty = false;
1547                 return glt->texnum;
1548         }
1549         else
1550                 return 0;
1551 }
1552
1553 void R_ClearTexture (rtexture_t *rt)
1554 {
1555         gltexture_t *glt = (gltexture_t *)rt;
1556
1557         R_Upload( glt, NULL, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth );
1558 }
1559
1560 int R_PicmipForFlags(int flags)
1561 {
1562         int miplevel = 0;
1563         if(flags & TEXF_PICMIP)
1564         {
1565                 miplevel += gl_picmip.integer;
1566                 if (flags & TEXF_ISWORLD)
1567                 {
1568                         if (r_picmipworld.integer)
1569                                 miplevel += gl_picmip_world.integer;
1570                         else
1571                                 miplevel = 0;
1572                 }
1573                 else if (flags & TEXF_ISSPRITE)
1574                 {
1575                         if (r_picmipsprites.integer)
1576                                 miplevel += gl_picmip_sprites.integer;
1577                         else
1578                                 miplevel = 0;
1579                 }
1580                 else
1581                         miplevel += gl_picmip_other.integer;
1582         }
1583         return miplevel;
1584 }