]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_textures.c
do not TOTALLY block translation with csprogs, but restrict it to globals named dotra...
[xonotic/darkplaces.git] / gl_textures.c
index cf4131c2e45477862048a77458d962364e6ee4f3..249ced51c2554b21b3793b4a3bcfd2fe86354565 100644 (file)
@@ -4,11 +4,22 @@
 #include "jpeg.h"
 #include "image_png.h"
 
-cvar_t gl_max_size = {CVAR_SAVE, "gl_max_size", "2048", "maximum allowed texture size, can be used to reduce video memory usage, note: this is automatically reduced to match video card capabilities (such as 256 on 3Dfx cards before Voodoo4/5)"};
+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)"};
+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)"};
 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%"};
 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)"};
-cvar_t r_precachetextures = {CVAR_SAVE, "r_precachetextures", "1", "0 = never upload textures until used, 1 = upload most textures before use (exceptions: rarely used skin colormap layers), 2 = upload all textures before use (can increase texture memory usage significantly)"};
 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"};
+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"};
+cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
+cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
+cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
+cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
+cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
+cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
+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)"};
+cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
+cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
+cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "0", "use alternate path for dynamic lightmap updates"};
 
 int            gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
 int            gl_filter_mag = GL_LINEAR;
@@ -18,36 +29,56 @@ static mempool_t *texturemempool;
 
 // note: this must not conflict with TEXF_ flags in r_textures.h
 // cleared when a texture is uploaded
-#define GLTEXF_UPLOAD 0x00010000
+#define GLTEXF_UPLOAD          0x00010000
 // bitmask for mismatch checking
 #define GLTEXF_IMPORTANTBITS (0)
 // set when image is uploaded and freed
-#define GLTEXF_DESTROYED 0x00040000
+#define GLTEXF_DESTROYED       0x00040000
+// dynamic texture (treat texnum == 0 differently)
+#define GLTEXF_DYNAMIC         0x00080000
 
 typedef struct textypeinfo_s
 {
-       int textype;
+       textype_t textype;
        int inputbytesperpixel;
        int internalbytesperpixel;
+       float glinternalbytesperpixel;
        int glformat;
        int glinternalformat;
+       int gltype;
 }
 textypeinfo_t;
 
-static textypeinfo_t textype_palette       = {TEXTYPE_PALETTE, 1, 4, GL_RGBA   , 3};
-static textypeinfo_t textype_rgb           = {TEXTYPE_RGB    , 3, 3, GL_RGB    , 3};
-static textypeinfo_t textype_rgba          = {TEXTYPE_RGBA   , 4, 4, GL_RGBA   , 3};
-static textypeinfo_t textype_palette_alpha = {TEXTYPE_PALETTE, 1, 4, GL_RGBA   , 4};
-static textypeinfo_t textype_rgba_alpha    = {TEXTYPE_RGBA   , 4, 4, GL_RGBA   , 4};
-
-#define GLTEXTURETYPE_1D 0
-#define GLTEXTURETYPE_2D 1
-#define GLTEXTURETYPE_3D 2
-#define GLTEXTURETYPE_CUBEMAP 3
+static textypeinfo_t textype_palette                = {TEXTYPE_PALETTE, 1, 4, 4.0f, GL_BGRA   , 3, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_palette_alpha          = {TEXTYPE_PALETTE, 1, 4, 4.0f, GL_BGRA   , 4, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_palette_compress       = {TEXTYPE_PALETTE, 1, 4, 0.5f, GL_BGRA   , GL_COMPRESSED_RGB_ARB, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_palette_alpha_compress = {TEXTYPE_PALETTE, 1, 4, 1.0f, GL_BGRA   , GL_COMPRESSED_RGBA_ARB, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_rgba                   = {TEXTYPE_RGBA   , 4, 4, 4.0f, GL_RGBA   , 3, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_rgba_alpha             = {TEXTYPE_RGBA   , 4, 4, 4.0f, GL_RGBA   , 4, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_rgba_compress          = {TEXTYPE_RGBA   , 4, 4, 0.5f, GL_RGBA   , GL_COMPRESSED_RGB_ARB, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_rgba_alpha_compress    = {TEXTYPE_RGBA   , 4, 4, 1.0f, GL_RGBA   , GL_COMPRESSED_RGBA_ARB, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_bgra                   = {TEXTYPE_BGRA   , 4, 4, 4.0f, GL_BGRA   , 3, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_bgra_alpha             = {TEXTYPE_BGRA   , 4, 4, 4.0f, GL_BGRA   , 4, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_bgra_compress          = {TEXTYPE_BGRA   , 4, 4, 0.5f, GL_BGRA   , GL_COMPRESSED_RGB_ARB, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_bgra_alpha_compress    = {TEXTYPE_BGRA   , 4, 4, 1.0f, GL_BGRA   , GL_COMPRESSED_RGBA_ARB, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_shadowmap16            = {TEXTYPE_SHADOWMAP,2,2, 2.0f, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT16_ARB, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_shadowmap24            = {TEXTYPE_SHADOWMAP,4,4, 4.0f, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT24_ARB, GL_UNSIGNED_INT};
+static textypeinfo_t textype_alpha                  = {TEXTYPE_ALPHA  , 1, 4, 4.0f, GL_ALPHA  , 4, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_alpha_compress         = {TEXTYPE_ALPHA  , 1, 4, 1.0f, GL_ALPHA  , GL_COMPRESSED_RGBA_ARB, GL_UNSIGNED_BYTE};
+
+typedef enum gltexturetype_e
+{
+       GLTEXTURETYPE_2D,
+       GLTEXTURETYPE_3D,
+       GLTEXTURETYPE_CUBEMAP,
+       GLTEXTURETYPE_RECTANGLE,
+       GLTEXTURETYPE_TOTAL
+}
+gltexturetype_t;
 
-static int gltexturetypeenums[4] = {GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB};
-static int gltexturetypebindingenums[4] = {GL_TEXTURE_BINDING_1D, GL_TEXTURE_BINDING_2D, GL_TEXTURE_BINDING_3D, GL_TEXTURE_BINDING_CUBE_MAP_ARB};
-static int gltexturetypedimensions[4] = {1, 2, 3, 2};
+static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_RECTANGLE_ARB};
+static int gltexturetypebindingenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_BINDING_2D, GL_TEXTURE_BINDING_3D, GL_TEXTURE_BINDING_CUBE_MAP_ARB, GL_TEXTURE_BINDING_RECTANGLE_ARB};
+static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2, 2};
 static int cubemapside[6] =
 {
        GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
@@ -64,12 +95,23 @@ typedef struct gltexture_s
        // (must be identical in rtexture_t)
        int texnum; // GL texture slot number
 
+       // dynamic texture stuff [11/22/2007 Black]
+       // used to hold the texture number of dirty textures   
+       int dirtytexnum;
+       updatecallback_t updatecallback;
+       void *updatacallback_data;
+       // --- [11/22/2007 Black]
+
+       // stores backup copy of texture for deferred texture updates (r_nopartialtextureupdates cvar)
+       unsigned char *bufferpixels;
+       qboolean buffermodified;
+
        // pointer to texturepool (check this to see if the texture is allocated)
        struct gltexturepool_s *pool;
        // pointer to next texture in texturepool chain
        struct gltexture_s *chain;
        // name of the texture (this might be removed someday), no duplicates
-       char identifier[32];
+       char identifier[MAX_QPATH + 32];
        // original data size in *inputtexels
        int inputwidth, inputheight, inputdepth;
        // copy of the original texture(s) supplied to the upload function, for
@@ -86,16 +128,19 @@ typedef struct gltexture_s
        int texturetype;
        // palette if the texture is TEXTYPE_PALETTE
        const unsigned int *palette;
-       // power of 2 size, after gl_picmip and gl_max_size are applied
+       // actual stored texture size after gl_picmip and gl_max_size are applied
+       // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported)
        int tilewidth, tileheight, tiledepth;
        // 1 or 6 depending on texturetype
        int sides;
        // bytes per pixel
        int bytesperpixel;
-       // GL_RGB or GL_RGBA
+       // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
        int glformat;
        // 3 or 4
        int glinternalformat;
+       // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
+       int gltype;
 }
 gltexture_t;
 
@@ -113,74 +158,132 @@ static gltexturepool_t *gltexturepoolchain = NULL;
 
 static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
 static int resizebuffersize = 0;
-static unsigned char *texturebuffer;
+static const unsigned char *texturebuffer;
 static int texturebuffersize = 0;
 
-static textypeinfo_t *R_GetTexTypeInfo(int textype, int flags)
+static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
 {
-       if (flags & TEXF_ALPHA)
+       if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.arb_texture_compression)
        {
-               switch(textype)
+               if (flags & TEXF_ALPHA)
                {
-               case TEXTYPE_PALETTE:
-                       return &textype_palette_alpha;
-               case TEXTYPE_RGB:
-                       Host_Error("R_GetTexTypeInfo: RGB format has no alpha, TEXF_ALPHA not allowed");
-                       return NULL;
-               case TEXTYPE_RGBA:
-                       return &textype_rgba_alpha;
-               default:
-                       Host_Error("R_GetTexTypeInfo: unknown texture format");
-                       return NULL;
+                       switch(textype)
+                       {
+                       case TEXTYPE_PALETTE:
+                               return &textype_palette_alpha_compress;
+                       case TEXTYPE_RGBA:
+                               return &textype_rgba_alpha_compress;
+                       case TEXTYPE_BGRA:
+                               return &textype_bgra_alpha_compress;
+                       case TEXTYPE_ALPHA:
+                               return &textype_alpha_compress;
+                       default:
+                               Host_Error("R_GetTexTypeInfo: unknown texture format");
+                               return NULL;
+                       }
+               }
+               else
+               {
+                       switch(textype)
+                       {
+                       case TEXTYPE_PALETTE:
+                               return &textype_palette_compress;
+                       case TEXTYPE_RGBA:
+                               return &textype_rgba_compress;
+                       case TEXTYPE_BGRA:
+                               return &textype_bgra_compress;
+                       case TEXTYPE_ALPHA:
+                               return &textype_alpha_compress;
+                       default:
+                               Host_Error("R_GetTexTypeInfo: unknown texture format");
+                               return NULL;
+                       }
                }
        }
        else
        {
-               switch(textype)
+               if (flags & TEXF_ALPHA)
                {
-               case TEXTYPE_PALETTE:
-                       return &textype_palette;
-               case TEXTYPE_RGB:
-                       return &textype_rgb;
-               case TEXTYPE_RGBA:
-                       return &textype_rgba;
-               default:
-                       Host_Error("R_GetTexTypeInfo: unknown texture format");
-                       return NULL;
+                       switch(textype)
+                       {
+                       case TEXTYPE_PALETTE:
+                               return &textype_palette_alpha;
+                       case TEXTYPE_RGBA:
+                               return &textype_rgba_alpha;
+                       case TEXTYPE_BGRA:
+                               return &textype_bgra_alpha;
+                       case TEXTYPE_ALPHA:
+                               return &textype_alpha;
+                       default:
+                               Host_Error("R_GetTexTypeInfo: unknown texture format");
+                               return NULL;
+                       }
+               }
+               else
+               {
+                       switch(textype)
+                       {
+                       case TEXTYPE_PALETTE:
+                               return &textype_palette;
+                       case TEXTYPE_RGBA:
+                               return &textype_rgba;
+                       case TEXTYPE_BGRA:
+                               return &textype_bgra;
+                       case TEXTYPE_SHADOWMAP:
+                               return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
+                       case TEXTYPE_ALPHA:
+                               return &textype_alpha;
+                       default:
+                               Host_Error("R_GetTexTypeInfo: unknown texture format");
+                               return NULL;
+                       }
                }
        }
+       return NULL; // this line only to hush compiler warnings
 }
 
-static void R_UploadTexture(gltexture_t *t);
+// dynamic texture code [11/22/2007 Black]
+void R_MarkDirtyTexture(rtexture_t *rt) {
+       gltexture_t *glt = (gltexture_t*) rt;
+       if( !glt ) {
+               return;
+       }
 
-static void R_PrecacheTexture(gltexture_t *glt)
-{
-       int precache;
-       precache = false;
-       if (glt->flags & TEXF_ALWAYSPRECACHE)
-               precache = true;
-       else if (r_precachetextures.integer >= 2)
-               precache = true;
-       else if (r_precachetextures.integer >= 1)
-               if (glt->flags & TEXF_PRECACHE)
-                       precache = true;
+       // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
+       if( !glt->dirtytexnum && glt->flags & GLTEXF_DYNAMIC ) {
+               glt->dirtytexnum = glt->texnum;
+               // mark it as dirty, so R_RealGetTexture gets called
+               glt->texnum = 0;
+       }
+}
 
-       if (precache)
-               R_UploadTexture(glt);
+void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
+       gltexture_t *glt = (gltexture_t*) rt;
+       if( !glt ) {
+               return;
+       }
+
+       glt->flags |= GLTEXF_DYNAMIC;
+       glt->updatecallback = updatecallback;
+       glt->updatacallback_data = data;
+       glt->dirtytexnum = 0;
 }
 
-int R_RealGetTexture(rtexture_t *rt)
+static void R_UpdateDynamicTexture(gltexture_t *glt) {
+       glt->texnum = glt->dirtytexnum;
+       // reset dirtytexnum again (not dirty anymore)
+       glt->dirtytexnum = 0;
+       // TODO: now assert that t->texnum != 0 ?
+       if( glt->updatecallback ) {
+               glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
+       }
+}
+
+void R_PurgeTexture(rtexture_t *rt)
 {
-       if (rt)
-       {
-               gltexture_t *glt;
-               glt = (gltexture_t *)rt;
-               if (glt->flags & GLTEXF_UPLOAD)
-                       R_UploadTexture(glt);
-               return glt->texnum;
+       if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
+               R_FreeTexture(rt);
        }
-       else
-               return 0;
 }
 
 void R_FreeTexture(rtexture_t *rt)
@@ -197,8 +300,11 @@ void R_FreeTexture(rtexture_t *rt)
        else
                Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
 
-       if (glt->texnum)
-               qglDeleteTextures(1, (GLuint *)&glt->texnum);
+       if (!(glt->flags & GLTEXF_UPLOAD))
+       {
+               CHECKGLERROR
+               qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
+       }
 
        if (glt->inputtexels)
                Mem_Free(glt->inputtexels);
@@ -293,6 +399,8 @@ static void GL_TextureMode_f (void)
 
        // change all the existing mipmap texture objects
        // FIXME: force renderer(/client/something?) restart instead?
+       CHECKGLERROR
+       GL_ActiveTexture(0);
        for (pool = gltexturepoolchain;pool;pool = pool->next)
        {
                for (glt = pool->gltchain;glt;glt = glt->chain)
@@ -300,14 +408,18 @@ static void GL_TextureMode_f (void)
                        // only update already uploaded images
                        if (!(glt->flags & (GLTEXF_UPLOAD | TEXF_FORCENEAREST | TEXF_FORCELINEAR)))
                        {
-                               qglGetIntegerv(gltexturetypebindingenums[glt->texturetype], &oldbindtexnum);
-                               qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);
+                               oldbindtexnum = R_Mesh_TexBound(0, gltexturetypebindingenums[glt->texturetype]);
+                               qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
                                if (glt->flags & TEXF_MIPMAP)
-                                       qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);
+                               {
+                                       qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
+                               }
                                else
-                                       qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);
-                               qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);
-                               qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);
+                               {
+                                       qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
+                               }
+                               qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
+                               qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
                        }
                }
        }
@@ -317,46 +429,56 @@ static void GL_Texture_CalcImageSize(int texturetype, int flags, int inwidth, in
 {
        int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1;
 
-       if (gl_max_size.integer > gl_max_texture_size)
-               Cvar_SetValue("gl_max_size", gl_max_texture_size);
-
        switch (texturetype)
        {
        default:
-       case GLTEXTURETYPE_1D:
        case GLTEXTURETYPE_2D:
-               maxsize = gl_max_texture_size;
+               maxsize = vid.maxtexturesize_2d;
+               if (flags & TEXF_PICMIP)
+               {
+                       maxsize = bound(1, gl_max_size.integer, maxsize);
+                       picmip = gl_picmip.integer;
+               }
                break;
        case GLTEXTURETYPE_3D:
-               maxsize = gl_max_3d_texture_size;
+               maxsize = vid.maxtexturesize_3d;
                break;
        case GLTEXTURETYPE_CUBEMAP:
-               maxsize = gl_max_cube_map_texture_size;
+               maxsize = vid.maxtexturesize_cubemap;
                break;
        }
 
-       if (flags & TEXF_PICMIP)
-       {
-               maxsize = min(maxsize, gl_max_size.integer);
-               picmip = gl_picmip.integer;
-       }
-
        if (outwidth)
        {
-               for (width2 = 1;width2 < inwidth;width2 <<= 1);
-               for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
+               if (vid.support.arb_texture_non_power_of_two)
+                       width2 = min(inwidth >> picmip, maxsize);
+               else
+               {
+                       for (width2 = 1;width2 < inwidth;width2 <<= 1);
+                       for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
+               }
                *outwidth = max(1, width2);
        }
        if (outheight)
        {
-               for (height2 = 1;height2 < inheight;height2 <<= 1);
-               for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
+               if (vid.support.arb_texture_non_power_of_two)
+                       height2 = min(inheight >> picmip, maxsize);
+               else
+               {
+                       for (height2 = 1;height2 < inheight;height2 <<= 1);
+                       for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
+               }
                *outheight = max(1, height2);
        }
        if (outdepth)
        {
-               for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
-               for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
+               if (vid.support.arb_texture_non_power_of_two)
+                       depth2 = min(indepth >> picmip, maxsize);
+               else
+               {
+                       for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
+                       for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
+               }
                *outdepth = max(1, depth2);
        }
 }
@@ -384,7 +506,7 @@ static int R_CalcTexelDataSize (gltexture_t *glt)
                }
        }
 
-       return size * glt->textype->internalbytesperpixel * glt->sides;
+       return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
 }
 
 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
@@ -422,7 +544,7 @@ void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean print
                                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);
                }
                if (printpool)
-                       Con_Printf("texturepool %10p total: %i (%.3fMB, %.3fMB original), uploaded %i (%.3fMB, %.3fMB original), upload on demand %i (%.3fMB, %.3fMB original)\n", 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);
+                       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);
                sumtotal += pooltotal;
                sumtotalt += pooltotalt;
                sumtotalp += pooltotalp;
@@ -442,8 +564,9 @@ static void R_TextureStats_f(void)
 static void r_textures_start(void)
 {
        // LordHavoc: allow any alignment
-       qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        CHECKGLERROR
+       qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
+       qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
 
        texturemempool = Mem_AllocPool("texture management", 0, NULL);
 
@@ -484,9 +607,20 @@ void R_Textures_Init (void)
        Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
        Cvar_RegisterVariable (&gl_max_size);
        Cvar_RegisterVariable (&gl_picmip);
+       Cvar_RegisterVariable (&gl_max_lightmapsize);
        Cvar_RegisterVariable (&r_lerpimages);
-       Cvar_RegisterVariable (&r_precachetextures);
        Cvar_RegisterVariable (&gl_texture_anisotropy);
+       Cvar_RegisterVariable (&gl_texturecompression);
+       Cvar_RegisterVariable (&gl_texturecompression_color);
+       Cvar_RegisterVariable (&gl_texturecompression_normal);
+       Cvar_RegisterVariable (&gl_texturecompression_gloss);
+       Cvar_RegisterVariable (&gl_texturecompression_glow);
+       Cvar_RegisterVariable (&gl_texturecompression_2d);
+       Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps);
+       Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
+       Cvar_RegisterVariable (&gl_texturecompression_sky);
+       Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
+       Cvar_RegisterVariable (&gl_nopartialtextureupdates);
 
        R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap);
 }
@@ -517,10 +651,12 @@ void R_Textures_Frame (void)
                gltexturepool_t *pool;
                GLint oldbindtexnum;
 
-               old_aniso = bound(1, gl_texture_anisotropy.integer, gl_max_anisotropy);
+               old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
 
                Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
 
+               CHECKGLERROR
+               GL_ActiveTexture(0);
                for (pool = gltexturepoolchain;pool;pool = pool->next)
                {
                        for (glt = pool->gltchain;glt;glt = glt->chain)
@@ -528,12 +664,12 @@ void R_Textures_Frame (void)
                                // only update already uploaded images
                                if ((glt->flags & (GLTEXF_UPLOAD | TEXF_MIPMAP)) == TEXF_MIPMAP)
                                {
-                                       qglGetIntegerv(gltexturetypebindingenums[glt->texturetype], &oldbindtexnum);
+                                       oldbindtexnum = R_Mesh_TexBound(0, gltexturetypebindingenums[glt->texturetype]);
 
-                                       qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);
+                                       qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
                                        qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
 
-                                       qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);
+                                       qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
                                }
                        }
                }
@@ -556,16 +692,16 @@ void R_MakeResizeBufferBigger(int size)
        }
 }
 
-static void GL_SetupTextureParameters(int flags, int texturetype)
+static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
 {
        int textureenum = gltexturetypeenums[texturetype];
-       int wrapmode = ((flags & TEXF_CLAMP) && gl_support_clamptoedge) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
+       int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
 
        CHECKGLERROR
 
-       if (gl_support_anisotropy && (flags & TEXF_MIPMAP))
+       if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
        {
-               int aniso = bound(1, gl_texture_anisotropy.integer, gl_max_anisotropy);
+               int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
                if (gl_texture_anisotropy.integer != aniso)
                        Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
                qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
@@ -622,27 +758,53 @@ static void GL_SetupTextureParameters(int flags, int texturetype)
                qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
        }
 
+       if (textype == TEXTYPE_SHADOWMAP)
+       {
+               if (vid.support.arb_shadow)
+               {
+                       if (flags & TEXF_COMPARE)
+                       {
+                               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
+                       }
+                       else
+                       {
+                               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
+                       }
+                       qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
+               }
+               qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
+       }
+
        CHECKGLERROR
 }
 
-static void R_Upload(gltexture_t *glt, unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
+static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
 {
        int i, mip, width, height, depth;
        GLint oldbindtexnum;
-       unsigned char *prevbuffer;
+       const unsigned char *prevbuffer;
        prevbuffer = data;
 
        CHECKGLERROR
 
        // we need to restore the texture binding after finishing the upload
-       qglGetIntegerv(gltexturetypebindingenums[glt->texturetype], &oldbindtexnum);
-       qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);
-       CHECKGLERROR
+       GL_ActiveTexture(0);
+       oldbindtexnum = R_Mesh_TexBound(0, gltexturetypebindingenums[glt->texturetype]);
+       qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
 
        // these are rounded up versions of the size to do better resampling
-       for (width  = 1;width  < glt->inputwidth ;width  <<= 1);
-       for (height = 1;height < glt->inputheight;height <<= 1);
-       for (depth  = 1;depth  < glt->inputdepth ;depth  <<= 1);
+       if (vid.support.arb_texture_non_power_of_two || glt->texturetype == GLTEXTURETYPE_RECTANGLE)
+       {
+               width = glt->inputwidth;
+               height = glt->inputheight;
+               depth = glt->inputdepth;
+       }
+       else
+       {
+               for (width  = 1;width  < glt->inputwidth ;width  <<= 1);
+               for (height = 1;height < glt->inputheight;height <<= 1);
+               for (depth  = 1;depth  < glt->inputdepth ;depth  <<= 1);
+       }
 
        R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
        R_MakeResizeBufferBigger(fragwidth * fragheight * fragdepth * glt->sides * glt->bytesperpixel);
@@ -654,31 +816,24 @@ static void R_Upload(gltexture_t *glt, unsigned char *data, int fragx, int fragy
        }
        else if (glt->textype->textype == TEXTYPE_PALETTE)
        {
-               // promote paletted to RGBA, so we only have to worry about RGB and
-               // RGBA in the rest of this code
-               Image_Copy8bitRGBA(prevbuffer, colorconvertbuffer, fragwidth * fragheight * fragdepth * glt->sides, glt->palette);
+               // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
+               Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, fragwidth * fragheight * fragdepth * glt->sides, glt->palette);
                prevbuffer = colorconvertbuffer;
        }
 
-       if ((glt->flags & (TEXF_MIPMAP | TEXF_PICMIP | GLTEXF_UPLOAD)) == 0 && glt->inputwidth == glt->tilewidth && glt->inputheight == glt->tileheight && glt->inputdepth == glt->tiledepth)
+       if ((glt->flags & (TEXF_MIPMAP | TEXF_PICMIP | GLTEXF_UPLOAD)) == 0 && glt->inputwidth == glt->tilewidth && glt->inputheight == glt->tileheight && glt->inputdepth == glt->tiledepth && (fragx != 0 || fragy != 0 || fragwidth != glt->tilewidth || fragheight != glt->tileheight))
        {
                // update a portion of the image
                switch(glt->texturetype)
                {
-               case GLTEXTURETYPE_1D:
-                       qglTexSubImage1D(GL_TEXTURE_1D, 0, fragx, fragwidth, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);
-                       CHECKGLERROR
-                       break;
                case GLTEXTURETYPE_2D:
-                       qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);
-                       CHECKGLERROR
+                       qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                        break;
                case GLTEXTURETYPE_3D:
-                       qglTexSubImage3D(GL_TEXTURE_3D, 0, fragx, fragy, fragz, fragwidth, fragheight, fragdepth, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);
-                       CHECKGLERROR
+                       qglTexSubImage3D(GL_TEXTURE_3D, 0, fragx, fragy, fragz, fragwidth, fragheight, fragdepth, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                        break;
                default:
-                       Host_Error("R_Upload: partial update of type other than 1D, 2D, or 3D");
+                       Host_Error("R_Upload: partial update of type other than 2D");
                        break;
                }
        }
@@ -695,119 +850,122 @@ static void R_Upload(gltexture_t *glt, unsigned char *data, int fragx, int fragy
                {
                        if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
                        {
-                               Image_Resample(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, glt->bytesperpixel, r_lerpimages.integer);
+                               Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
                                prevbuffer = resizebuffer;
                        }
                        // picmip/max_size
                        while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
                        {
-                               Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth, glt->bytesperpixel);
+                               Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
                                prevbuffer = resizebuffer;
                        }
                }
                mip = 0;
-               switch(glt->texturetype)
+               if (qglGetCompressedTexImageARB)
                {
-               case GLTEXTURETYPE_1D:
-                       qglTexImage1D(GL_TEXTURE_1D, mip++, glt->glinternalformat, width, 0, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);
+                       if (gl_texturecompression.integer >= 2)
+                               qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
+                       else
+                               qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
                        CHECKGLERROR
-                       if (glt->flags & TEXF_MIPMAP)
-                       {
-                               while (width > 1 || height > 1 || depth > 1)
-                               {
-                                       Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1, glt->bytesperpixel);
-                                       prevbuffer = resizebuffer;
-                                       qglTexImage1D(GL_TEXTURE_1D, mip++, glt->glinternalformat, width, 0, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);
-                                       CHECKGLERROR
-                               }
-                       }
-                       break;
+               }
+               switch(glt->texturetype)
+               {
                case GLTEXTURETYPE_2D:
-                       qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);
-                       CHECKGLERROR
+                       qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                        if (glt->flags & TEXF_MIPMAP)
                        {
                                while (width > 1 || height > 1 || depth > 1)
                                {
-                                       Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1, glt->bytesperpixel);
+                                       Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
                                        prevbuffer = resizebuffer;
-                                       qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);
-                                       CHECKGLERROR
+                                       qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                                }
                        }
                        break;
                case GLTEXTURETYPE_3D:
-                       qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);
-                       CHECKGLERROR
+                       qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                        if (glt->flags & TEXF_MIPMAP)
                        {
                                while (width > 1 || height > 1 || depth > 1)
                                {
-                                       Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1, glt->bytesperpixel);
+                                       Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
                                        prevbuffer = resizebuffer;
-                                       qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);
-                                       CHECKGLERROR
+                                       qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                                }
                        }
                        break;
                case GLTEXTURETYPE_CUBEMAP:
                        // convert and upload each side in turn,
                        // from a continuous block of input texels
-                       texturebuffer = prevbuffer;
+                       texturebuffer = (unsigned char *)prevbuffer;
                        for (i = 0;i < 6;i++)
                        {
                                prevbuffer = texturebuffer;
                                texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
                                if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
                                {
-                                       Image_Resample(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, glt->bytesperpixel, r_lerpimages.integer);
+                                       Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
                                        prevbuffer = resizebuffer;
                                }
                                // picmip/max_size
                                while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
                                {
-                                       Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth, glt->bytesperpixel);
+                                       Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
                                        prevbuffer = resizebuffer;
                                }
                                mip = 0;
-                               qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);
-                               CHECKGLERROR
+                               qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                                if (glt->flags & TEXF_MIPMAP)
                                {
                                        while (width > 1 || height > 1 || depth > 1)
                                        {
-                                               Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1, glt->bytesperpixel);
+                                               Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
                                                prevbuffer = resizebuffer;
-                                               qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);
-                                               CHECKGLERROR
+                                               qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                                        }
                                }
                        }
                        break;
+               case GLTEXTURETYPE_RECTANGLE:
+                       qglTexImage2D(GL_TEXTURE_RECTANGLE_ARB, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, NULL);CHECKGLERROR
+                       break;
                }
-               GL_SetupTextureParameters(glt->flags, glt->texturetype);
+               GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
        }
-       qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);
+       qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
 }
 
-static void R_UploadTexture (gltexture_t *glt)
+int R_RealGetTexture(rtexture_t *rt)
 {
-       if (!(glt->flags & GLTEXF_UPLOAD))
-               return;
-
-       qglGenTextures(1, (GLuint *)&glt->texnum);
-       R_Upload(glt, glt->inputtexels, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
-       if (glt->inputtexels)
+       if (rt)
        {
-               Mem_Free(glt->inputtexels);
-               glt->inputtexels = NULL;
-               glt->flags |= GLTEXF_DESTROYED;
+               gltexture_t *glt;
+               glt = (gltexture_t *)rt;
+               if (glt->flags & GLTEXF_DYNAMIC)
+                       R_UpdateDynamicTexture(glt);
+               if (glt->flags & GLTEXF_UPLOAD)
+               {
+                       CHECKGLERROR
+                       qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
+                       R_Upload(glt, glt->inputtexels, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
+                       if (glt->inputtexels)
+                       {
+                               Mem_Free(glt->inputtexels);
+                               glt->inputtexels = NULL;
+                               glt->flags |= GLTEXF_DESTROYED;
+                       }
+                       else if (glt->flags & GLTEXF_DESTROYED)
+                               Con_Printf("R_GetTexture: Texture %s already uploaded and destroyed.  Can not upload original image again.  Uploaded blank texture.\n", glt->identifier);
+               }
+
+               return glt->texnum;
        }
-       else if (glt->flags & GLTEXF_DESTROYED)
-               Con_Printf("R_UploadTexture: Texture %s already uploaded and destroyed.  Can not upload original image again.  Uploaded blank texture.\n", glt->identifier);
+       else
+               return 0;
 }
 
-static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int depth, int sides, int flags, int textype, int texturetype, const unsigned char *data, const unsigned int *palette)
+static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int depth, int sides, int flags, textype_t textype, int texturetype, const unsigned char *data, const unsigned int *palette)
 {
        int i, size;
        gltexture_t *glt;
@@ -817,12 +975,17 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
        if (cls.state == ca_dedicated)
                return NULL;
 
-       if (texturetype == GLTEXTURETYPE_CUBEMAP && !gl_texturecubemap)
+       if (texturetype == GLTEXTURETYPE_RECTANGLE && !vid.support.arb_texture_rectangle)
+       {
+               Con_Printf ("R_LoadTexture: rectangle texture not supported by driver\n");
+               return NULL;
+       }
+       if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
        {
                Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
                return NULL;
        }
-       if (texturetype == GLTEXTURETYPE_3D && !gl_texture3d)
+       if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
        {
                Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
                return NULL;
@@ -832,7 +995,7 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
        size = width * height * depth * sides * texinfo->inputbytesperpixel;
        if (size < 1)
        {
-               Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides);
+               Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
                return NULL;
        }
 
@@ -856,11 +1019,8 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
                        }
                }
                break;
-       case TEXTYPE_RGB:
-               if (flags & TEXF_ALPHA)
-                       Host_Error("R_LoadTexture: RGB has no alpha, don't specify TEXF_ALPHA");
-               break;
        case TEXTYPE_RGBA:
+       case TEXTYPE_BGRA:
                if (flags & TEXF_ALPHA)
                {
                        flags &= ~TEXF_ALPHA;
@@ -877,6 +1037,11 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
                        }
                }
                break;
+       case TEXTYPE_SHADOWMAP:
+               break;
+       case TEXTYPE_ALPHA:
+               flags |= TEXF_ALPHA;
+               break;
        default:
                Host_Error("R_LoadTexture: unknown texture type");
        }
@@ -897,47 +1062,76 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
        glt->palette = palette;
        glt->glinternalformat = texinfo->glinternalformat;
        glt->glformat = texinfo->glformat;
+       glt->gltype = texinfo->gltype;
        glt->bytesperpixel = texinfo->internalbytesperpixel;
        glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
-       glt->texnum = -1;
-
-       if (data)
-       {
-               glt->inputtexels = (unsigned char *)Mem_Alloc(texturemempool, size);
-               memcpy(glt->inputtexels, data, size);
-       }
-       else
-               glt->inputtexels = NULL;
+       glt->texnum = 0;
+       // init the dynamic texture attributes, too [11/22/2007 Black]
+       glt->dirtytexnum = 0;
+       glt->updatecallback = NULL;
+       glt->updatacallback_data = NULL;
 
        GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth);
-       R_PrecacheTexture(glt);
 
-       return (rtexture_t *)glt;
-}
+       // upload the texture
+       // data may be NULL (blank texture for dynamic rendering)
+       CHECKGLERROR
+       qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
+       R_Upload(glt, data, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
+       if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
+               glt->bufferpixels = Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
 
-rtexture_t *R_LoadTexture1D(rtexturepool_t *rtexturepool, const char *identifier, int width, const unsigned char *data, int textype, int flags, const unsigned int *palette)
-{
-       return R_SetupTexture(rtexturepool, identifier, width, 1, 1, 1, flags, textype, GLTEXTURETYPE_1D, data, palette);
+       // texture converting and uploading can take a while, so make sure we're sending keepalives
+       CL_KeepaliveMessage(false);
+
+       return (rtexture_t *)glt;
 }
 
-rtexture_t *R_LoadTexture2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, const unsigned char *data, int textype, int flags, const unsigned int *palette)
+rtexture_t *R_LoadTexture2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, const unsigned char *data, textype_t textype, int flags, const unsigned int *palette)
 {
        return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, textype, GLTEXTURETYPE_2D, data, palette);
 }
 
-rtexture_t *R_LoadTexture3D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int depth, const unsigned char *data, int textype, int flags, const unsigned int *palette)
+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, const unsigned int *palette)
 {
        return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, textype, GLTEXTURETYPE_3D, data, palette);
 }
 
-rtexture_t *R_LoadTextureCubeMap(rtexturepool_t *rtexturepool, const char *identifier, int width, const unsigned char *data, int textype, int flags, const unsigned int *palette)
+rtexture_t *R_LoadTextureCubeMap(rtexturepool_t *rtexturepool, const char *identifier, int width, const unsigned char *data, textype_t textype, int flags, const unsigned int *palette)
 {
        return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
 }
 
-int R_TextureHasAlpha(rtexture_t *rt)
+rtexture_t *R_LoadTextureRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, const unsigned char *data, textype_t textype, int flags, const unsigned int *palette)
+{
+       return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, textype, GLTEXTURETYPE_RECTANGLE, data, palette);
+}
+
+static int R_ShadowMapTextureFlags(int precision, qboolean filter)
+{
+       int flags = TEXF_CLAMP;
+       if (filter)
+               flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
+       else
+               flags |= TEXF_FORCENEAREST;
+       if (precision <= 16)
+               flags |= TEXF_LOWPRECISION;
+       return flags;
+}
+
+rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
+{
+       return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
+}
+
+rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
 {
-       return rt ? (((gltexture_t *)rt)->flags & TEXF_ALPHA) != 0 : false;
+       return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
+}
+
+rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter)
+{
+    return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
 }
 
 int R_TextureWidth(rtexture_t *rt)
@@ -950,20 +1144,71 @@ int R_TextureHeight(rtexture_t *rt)
        return rt ? ((gltexture_t *)rt)->inputheight : 0;
 }
 
-void R_UpdateTexture(rtexture_t *rt, unsigned char *data, int x, int y, int width, int height)
+void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
 {
-       gltexture_t *glt;
-       if (rt == NULL)
-               Host_Error("R_UpdateTexture: no texture supplied");
+       gltexture_t *glt = (gltexture_t *)rt;
        if (data == NULL)
                Host_Error("R_UpdateTexture: no data supplied");
-       glt = (gltexture_t *)rt;
+       if (glt == NULL)
+               Host_Error("R_UpdateTexture: no texture supplied");
+       if (!glt->texnum)
+               Host_Error("R_UpdateTexture: texture has not been uploaded yet");
+       // update part of the texture
+       if (glt->bufferpixels)
+       {
+               int j;
+               int bpp = glt->bytesperpixel;
+               int inputskip = width*bpp;
+               int outputskip = glt->tilewidth*bpp;
+               const unsigned char *input = data;
+               unsigned char *output = glt->bufferpixels;
+               if (x < 0)
+               {
+                       width += x;
+                       input -= x*bpp;
+                       x = 0;
+               }
+               if (y < 0)
+               {
+                       height += y;
+                       input -= y*inputskip;
+                       y = 0;
+               }
+               if (width > glt->tilewidth - x)
+                       width = glt->tilewidth - x;
+               if (height > glt->tileheight - y)
+                       height = glt->tileheight - y;
+               if (width < 1 || height < 1)
+                       return;
+               glt->buffermodified = true;
+               output += y*outputskip + x*bpp;
+               for (j = 0;j < height;j++, output += outputskip, input += inputskip)
+                       memcpy(output, input, width*bpp);
+               if (!(glt->flags & TEXF_MANUALFLUSHUPDATES))
+                       R_FlushTexture(rt);
+       }
+       else
+               R_Upload(glt, data, x, y, 0, width, height, 1);
+}
 
-       // we need it to be uploaded before we can update a part of it
-       if (glt->flags & GLTEXF_UPLOAD)
-               R_UploadTexture(glt);
+void R_FlushTexture(rtexture_t *rt)
+{
+       gltexture_t *glt;
+       if (rt == NULL)
+               Host_Error("R_FlushTexture: no texture supplied");
 
        // update part of the texture
-       R_Upload(glt, data, x, y, 0, width, height, 1);
+       glt = (gltexture_t *)rt;
+
+       if (!glt->buffermodified || !glt->bufferpixels)
+               return;
+       glt->buffermodified = false;
+       R_Upload(glt, glt->bufferpixels, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth);
 }
 
+void R_ClearTexture (rtexture_t *rt)
+{
+       gltexture_t *glt = (gltexture_t *)rt;
+
+       R_Upload( glt, NULL, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth );
+}