Fix engine not starting on Windows if linked against SDL > 2.0.5
[xonotic/darkplaces.git] / gl_textures.c
index d5685c3..c970f8c 100644 (file)
@@ -1,9 +1,5 @@
 
 #include "quakedef.h"
-#ifdef SUPPORTD3D
-#include <d3d9.h>
-extern LPDIRECT3DDEVICE9 vid_d3d9dev;
-#endif
 #include "image.h"
 #include "jpeg.h"
 #include "image_png.h"
@@ -30,22 +26,16 @@ cvar_t gl_texturecompression_q3bspdeluxemaps = {CVAR_SAVE, "gl_texturecompressio
 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_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)"};
-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"};
+cvar_t gl_texturecompression_sprites = {CVAR_SAVE, "gl_texturecompression_sprites", "1", "whether to compress sprites"};
+cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "0", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"};
+cvar_t r_texture_dds_load_alphamode = {0, "r_texture_dds_load_alphamode", "1", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambiguous, 2: texture format only"};
+cvar_t r_texture_dds_load_logfailure = {0, "r_texture_dds_load_logfailure", "0", "log missing DDS textures to ddstexturefailures.log, 0: done log, 1: log with no optional textures (_norm, glow etc.). 2: log all"};
+cvar_t r_texture_dds_swdecode = {0, "r_texture_dds_swdecode", "0", "0: don't software decode DDS, 1: software decode DDS if unsupported, 2: always software decode DDS"};
 
 qboolean       gl_filter_force = false;
 int            gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
 int            gl_filter_mag = GL_LINEAR;
 
-#ifdef SUPPORTD3D
-int d3d_filter_flatmin = D3DTEXF_LINEAR;
-int d3d_filter_flatmag = D3DTEXF_LINEAR;
-int d3d_filter_flatmix = D3DTEXF_POINT;
-int d3d_filter_mipmin = D3DTEXF_LINEAR;
-int d3d_filter_mipmag = D3DTEXF_LINEAR;
-int d3d_filter_mipmix = D3DTEXF_LINEAR;
-int d3d_filter_nomip = false;
-#endif
-
 
 static mempool_t *texturemempool;
 static memexpandablearray_t texturearray;
@@ -58,6 +48,7 @@ static memexpandablearray_t texturearray;
 
 typedef struct textypeinfo_s
 {
+       const char *name;
        textype_t textype;
        int inputbytesperpixel;
        int internalbytesperpixel;
@@ -68,47 +59,102 @@ typedef struct textypeinfo_s
 }
 textypeinfo_t;
 
-
-static textypeinfo_t textype_palette                = {TEXTYPE_PALETTE    , 1, 4, 4.0f, 3                               , GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_palette_alpha          = {TEXTYPE_PALETTE    , 1, 4, 4.0f, 4                               , GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_rgba                   = {TEXTYPE_RGBA       , 4, 4, 4.0f, 3                               , GL_RGBA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_rgba_alpha             = {TEXTYPE_RGBA       , 4, 4, 4.0f, 4                               , GL_RGBA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_rgba_compress          = {TEXTYPE_RGBA       , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_rgba_alpha_compress    = {TEXTYPE_RGBA       , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_bgra                   = {TEXTYPE_BGRA       , 4, 4, 4.0f, 3                               , GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_bgra_alpha             = {TEXTYPE_BGRA       , 4, 4, 4.0f, 4                               , GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_bgra_compress          = {TEXTYPE_BGRA       , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_bgra_alpha_compress    = {TEXTYPE_BGRA       , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_shadowmap16            = {TEXTYPE_SHADOWMAP  , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB        , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
-static textypeinfo_t textype_shadowmap24            = {TEXTYPE_SHADOWMAP  , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB        , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
-static textypeinfo_t textype_alpha                  = {TEXTYPE_ALPHA      , 1, 4, 4.0f, GL_ALPHA                        , GL_ALPHA          , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_dxt1                   = {TEXTYPE_DXT1       , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0                 , 0                };
-static textypeinfo_t textype_dxt1a                  = {TEXTYPE_DXT1A      , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0                 , 0                };
-static textypeinfo_t textype_dxt3                   = {TEXTYPE_DXT3       , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0                 , 0                };
-static textypeinfo_t textype_dxt5                   = {TEXTYPE_DXT5       , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0                 , 0                };
-static textypeinfo_t textype_colorbuffer            = {TEXTYPE_COLORBUFFER, 4, 4, 4.0f, 4                               , GL_BGRA           , GL_UNSIGNED_BYTE };
-
+#ifdef USE_GLES2
+
+// we use these internally even if we never deliver such data to the driver
+#define GL_BGR                                 0x80E0
+#define GL_BGRA                                        0x80E1
+
+// framebuffer texture formats
+// GLES2 devices rarely support depth textures, so we actually use a renderbuffer there
+static textypeinfo_t textype_shadowmap16_comp            = {"shadowmap16_comp",         TEXTYPE_SHADOWMAP16_COMP     ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_shadowmap16_raw             = {"shadowmap16_raw",          TEXTYPE_SHADOWMAP16_RAW      ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_shadowmap24_comp            = {"shadowmap24_comp",         TEXTYPE_SHADOWMAP24_COMP     ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_shadowmap24_raw             = {"shadowmap24_raw",          TEXTYPE_SHADOWMAP24_RAW      ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_depth16                     = {"depth16",                  TEXTYPE_DEPTHBUFFER16        ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_depth24                     = {"depth24",                  TEXTYPE_DEPTHBUFFER24        ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_depth24stencil8             = {"depth24stencil8",          TEXTYPE_DEPTHBUFFER24STENCIL8,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_colorbuffer                 = {"colorbuffer",              TEXTYPE_COLORBUFFER          ,  2,  2,  2.0f, GL_RGB565                         , GL_RGBA           , GL_UNSIGNED_SHORT_5_6_5};
+static textypeinfo_t textype_colorbuffer16f              = {"colorbuffer16f",           TEXTYPE_COLORBUFFER16F       ,  2,  2,  2.0f, GL_RGBA16F                        , GL_RGBA           , GL_HALF_FLOAT};
+static textypeinfo_t textype_colorbuffer32f              = {"colorbuffer32f",           TEXTYPE_COLORBUFFER32F       ,  2,  2,  2.0f, GL_RGBA32F                        , GL_RGBA           , GL_FLOAT};
+
+// image formats:
+static textypeinfo_t textype_alpha                       = {"alpha",                    TEXTYPE_ALPHA         ,  1,  4,  4.0f, GL_ALPHA                              , GL_ALPHA          , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_palette                     = {"palette",                  TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_palette_alpha               = {"palette_alpha",            TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_rgba                        = {"rgba",                     TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_RGBA                               , GL_RGBA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_rgba_alpha                  = {"rgba_alpha",               TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_RGBA                               , GL_RGBA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_bgra                        = {"bgra",                     TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_bgra_alpha                  = {"bgra_alpha",               TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
+#ifdef __ANDROID__
+static textypeinfo_t textype_etc1                        = {"etc1",                     TEXTYPE_ETC1          ,  1,  3,  0.5f, GL_ETC1_RGB8_OES                         , 0                 , 0                };
+#endif
+#else
+// framebuffer texture formats
+static textypeinfo_t textype_shadowmap16_comp            = {"shadowmap16_comp",         TEXTYPE_SHADOWMAP16_COMP     ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_shadowmap16_raw             = {"shadowmap16_raw",          TEXTYPE_SHADOWMAP16_RAW      ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_shadowmap24_comp            = {"shadowmap24_comp",         TEXTYPE_SHADOWMAP24_COMP     ,  4,  4,  4.0f, GL_DEPTH_COMPONENT24              , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
+static textypeinfo_t textype_shadowmap24_raw             = {"shadowmap24_raw",          TEXTYPE_SHADOWMAP24_RAW      ,  4,  4,  4.0f, GL_DEPTH_COMPONENT24              , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
+static textypeinfo_t textype_depth16                     = {"depth16",                  TEXTYPE_DEPTHBUFFER16        ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_depth24                     = {"depth24",                  TEXTYPE_DEPTHBUFFER24        ,  4,  4,  4.0f, GL_DEPTH_COMPONENT24              , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
+static textypeinfo_t textype_depth24stencil8             = {"depth24stencil8",          TEXTYPE_DEPTHBUFFER24STENCIL8,  4,  4,  4.0f, GL_DEPTH24_STENCIL8               , GL_DEPTH_STENCIL  , GL_UNSIGNED_INT_24_8};
+static textypeinfo_t textype_colorbuffer                 = {"colorbuffer",              TEXTYPE_COLORBUFFER          ,  4,  4,  4.0f, GL_RGBA                           , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_colorbuffer16f              = {"colorbuffer16f",           TEXTYPE_COLORBUFFER16F       ,  8,  8,  8.0f, GL_RGBA16F                        , GL_RGBA           , GL_HALF_FLOAT    };
+static textypeinfo_t textype_colorbuffer32f              = {"colorbuffer32f",           TEXTYPE_COLORBUFFER32F       , 16, 16, 16.0f, GL_RGBA32F                        , GL_RGBA           , GL_FLOAT         };
+
+// image formats:
+static textypeinfo_t textype_alpha                       = {"alpha",                    TEXTYPE_ALPHA         ,  1,  4,  4.0f, GL_ALPHA                              , GL_ALPHA          , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_palette                     = {"palette",                  TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_RGB                                , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_palette_alpha               = {"palette_alpha",            TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_rgba                        = {"rgba",                     TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_RGB                                , GL_RGBA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_rgba_alpha                  = {"rgba_alpha",               TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_RGBA                               , GL_RGBA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_rgba_compress               = {"rgba_compress",            TEXTYPE_RGBA          ,  4,  4,  0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT       , GL_RGBA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_rgba_alpha_compress         = {"rgba_alpha_compress",      TEXTYPE_RGBA          ,  4,  4,  1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT      , GL_RGBA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_bgra                        = {"bgra",                     TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_RGB                                , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_bgra_alpha                  = {"bgra_alpha",               TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_bgra_compress               = {"bgra_compress",            TEXTYPE_BGRA          ,  4,  4,  0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT       , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_bgra_alpha_compress         = {"bgra_alpha_compress",      TEXTYPE_BGRA          ,  4,  4,  1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT      , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_dxt1                        = {"dxt1",                     TEXTYPE_DXT1          ,  4,  0,  0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT       , 0                 , 0                };
+static textypeinfo_t textype_dxt1a                       = {"dxt1a",                    TEXTYPE_DXT1A         ,  4,  0,  0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT      , 0                 , 0                };
+static textypeinfo_t textype_dxt3                        = {"dxt3",                     TEXTYPE_DXT3          ,  4,  0,  1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT      , 0                 , 0                };
+static textypeinfo_t textype_dxt5                        = {"dxt5",                     TEXTYPE_DXT5          ,  4,  0,  1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT      , 0                 , 0                };
+static textypeinfo_t textype_sRGB_palette                = {"sRGB_palette",             TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_SRGB                               , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_palette_alpha          = {"sRGB_palette_alpha",       TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_SRGB_ALPHA                         , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_rgba                   = {"sRGB_rgba",                TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_SRGB                               , GL_RGBA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_rgba_alpha             = {"sRGB_rgba_alpha",          TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_SRGB_ALPHA                         , GL_RGBA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_rgba_compress          = {"sRGB_rgba_compress",       TEXTYPE_RGBA          ,  4,  4,  0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT      , GL_RGBA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_rgba_alpha_compress    = {"sRGB_rgba_alpha_compress", TEXTYPE_RGBA          ,  4,  4,  1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_bgra                   = {"sRGB_bgra",                TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_SRGB                               , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_bgra_alpha             = {"sRGB_bgra_alpha",          TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_SRGB_ALPHA                         , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_bgra_compress          = {"sRGB_bgra_compress",       TEXTYPE_BGRA          ,  4,  4,  0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT      , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_bgra_alpha_compress    = {"sRGB_bgra_alpha_compress", TEXTYPE_BGRA          ,  4,  4,  1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_dxt1                   = {"sRGB_dxt1",                TEXTYPE_DXT1          ,  4,  0,  0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT      , 0                 , 0                };
+static textypeinfo_t textype_sRGB_dxt1a                  = {"sRGB_dxt1a",               TEXTYPE_DXT1A         ,  4,  0,  0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0                 , 0                };
+static textypeinfo_t textype_sRGB_dxt3                   = {"sRGB_dxt3",                TEXTYPE_DXT3          ,  4,  0,  1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0                 , 0                };
+static textypeinfo_t textype_sRGB_dxt5                   = {"sRGB_dxt5",                TEXTYPE_DXT5          ,  4,  0,  1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0                 , 0                };
+#endif
 
 typedef enum gltexturetype_e
 {
        GLTEXTURETYPE_2D,
        GLTEXTURETYPE_3D,
        GLTEXTURETYPE_CUBEMAP,
-       GLTEXTURETYPE_RECTANGLE,
        GLTEXTURETYPE_TOTAL
 }
 gltexturetype_t;
 
-static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_RECTANGLE_ARB};
-static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2, 2};
+static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP};
+#ifdef GL_TEXTURE_WRAP_R
+static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
+#endif
 static int cubemapside[6] =
 {
-       GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
-       GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
-       GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
-       GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
-       GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
-       GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
+       GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+       GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+       GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+       GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+       GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+       GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
 };
 
 typedef struct gltexture_s
@@ -116,28 +162,14 @@ typedef struct gltexture_s
        // this portion of the struct is exposed to the R_GetTexture macro for
        // speed reasons, must be identical in rtexture_t!
        int texnum; // GL texture slot number
+       int renderbuffernum; // GL renderbuffer slot number
        qboolean dirty; // indicates that R_RealGetTexture should be called
+       qboolean glisdepthstencil; // indicates that FBO attachment has to be GL_DEPTH_STENCIL_ATTACHMENT
        int gltexturetypeenum; // used by R_Mesh_TexBind
-       // d3d stuff the backend needs
-       void *d3dtexture;
-#ifdef SUPPORTD3D
-       int d3dformat;
-       int d3dusage;
-       int d3dpool;
-       int d3daddressu;
-       int d3daddressv;
-       int d3daddressw;
-       int d3dmagfilter;
-       int d3dminfilter;
-       int d3dmipfilter;
-       int d3dmaxmiplevelfilter;
-       int d3dmipmaplodbias;
-       int d3dmaxmiplevel;
-#endif
 
        // dynamic texture stuff [11/22/2007 Black]
        updatecallback_t updatecallback;
-       void *updatacallback_data;
+       void *updatecallback_data;
        // --- [11/22/2007 Black]
 
        // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar)
@@ -169,7 +201,6 @@ typedef struct gltexture_s
        // palette if the texture is TEXTYPE_PALETTE
        const unsigned int *palette;
        // 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;
@@ -206,32 +237,53 @@ static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
 {
        switch(textype)
        {
-       case TEXTYPE_DXT1:
-               return &textype_dxt1;
-       case TEXTYPE_DXT1A:
-               return &textype_dxt1a;
-       case TEXTYPE_DXT3:
-               return &textype_dxt3;
-       case TEXTYPE_DXT5:
-               return &textype_dxt5;
-       case TEXTYPE_PALETTE:
-               return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
-       case TEXTYPE_RGBA:
-               if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.arb_texture_compression)
-                       return (flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress;
-               return (flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba;
-       case TEXTYPE_BGRA:
-               if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.arb_texture_compression)
-                       return (flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress;
-               return (flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra;
-       case TEXTYPE_ALPHA:
-               return &textype_alpha;
-       case TEXTYPE_SHADOWMAP:
-               return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
-       case TEXTYPE_COLORBUFFER:
-               return &textype_colorbuffer;
+#ifdef USE_GLES2
+       case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
+       case TEXTYPE_RGBA: return ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba);
+       case TEXTYPE_BGRA: return ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra);
+#ifdef __ANDROID__
+       case TEXTYPE_ETC1: return &textype_etc1;
+#endif
+       case TEXTYPE_ALPHA: return &textype_alpha;
+       case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
+       case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
+       case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
+       case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
+       case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
+       case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
+       case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
+       case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
+       case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
+       case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
+#else
+       case TEXTYPE_DXT1: return &textype_dxt1;
+       case TEXTYPE_DXT1A: return &textype_dxt1a;
+       case TEXTYPE_DXT3: return &textype_dxt3;
+       case TEXTYPE_DXT5: return &textype_dxt5;
+       case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
+       case TEXTYPE_RGBA: return ((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress) : ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba);
+       case TEXTYPE_BGRA: return ((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress) : ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra);
+       case TEXTYPE_ALPHA: return &textype_alpha;
+       case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
+       case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
+       case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
+       case TEXTYPE_DEPTHBUFFER16: return &textype_depth16;
+       case TEXTYPE_DEPTHBUFFER24: return &textype_depth24;
+       case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8;
+       case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp;
+       case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw;
+       case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp;
+       case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw;
+       case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1;
+       case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a;
+       case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
+       case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
+       case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
+       case TEXTYPE_SRGB_RGBA: return ((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_sRGB_rgba_alpha_compress : &textype_sRGB_rgba_compress) : ((flags & TEXF_ALPHA) ? &textype_sRGB_rgba_alpha : &textype_sRGB_rgba);
+       case TEXTYPE_SRGB_BGRA: return ((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_sRGB_bgra_alpha_compress : &textype_sRGB_bgra_compress) : ((flags & TEXF_ALPHA) ? &textype_sRGB_bgra_alpha : &textype_sRGB_bgra);
+#endif
        default:
-               Host_Error("R_GetTexTypeInfo: unknown texture format");
+               Host_Error("R_GetTexTypeInfo: unknown texture format %i with flags %x", (int)textype, flags);
                break;
        }
        return NULL;
@@ -260,13 +312,13 @@ void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void
 
        glt->flags |= GLTEXF_DYNAMIC;
        glt->updatecallback = updatecallback;
-       glt->updatacallback_data = data;
+       glt->updatecallback_data = data;
 }
 
 static void R_UpdateDynamicTexture(gltexture_t *glt) {
        glt->dirty = false;
        if( glt->updatecallback ) {
-               glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data );
+               glt->updatecallback( (rtexture_t*) glt, glt->updatecallback_data );
        }
 }
 
@@ -291,10 +343,23 @@ void R_FreeTexture(rtexture_t *rt)
        else
                Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
 
-       if (glt->texnum)
+       R_Mesh_ClearBindingsForTexture(glt->texnum);
+
+       switch(vid.renderpath)
        {
-               CHECKGLERROR
-               qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
+       case RENDERPATH_GL32:
+       case RENDERPATH_GLES2:
+               if (glt->texnum)
+               {
+                       CHECKGLERROR
+                       qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
+               }
+               if (glt->renderbuffernum)
+               {
+                       CHECKGLERROR
+                       qglDeleteRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
+               }
+               break;
        }
 
        if (glt->inputtexels)
@@ -340,7 +405,7 @@ void R_FreeTexturePool(rtexturepool_t **rtexturepool)
 
 typedef struct glmode_s
 {
-       char *name;
+       const char *name;
        int minification, magnification;
 }
 glmode_t;
@@ -355,25 +420,6 @@ static glmode_t modes[6] =
        {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
 };
 
-#ifdef SUPPORTD3D
-typedef struct d3dmode_s
-{
-       char *name;
-       int m1, m2;
-}
-d3dmode_t;
-
-static d3dmode_t d3dmodes[6] =
-{
-       {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
-       {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT},
-       {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT},
-       {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT},
-       {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR},
-       {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR}
-};
-#endif
-
 static void GL_TextureMode_f (void)
 {
        int i;
@@ -411,10 +457,8 @@ static void GL_TextureMode_f (void)
 
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL11:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
+       case RENDERPATH_GL32:
+       case RENDERPATH_GLES2:
                // change all the existing mipmap texture objects
                // FIXME: force renderer(/client/something?) restart instead?
                CHECKGLERROR
@@ -442,49 +486,6 @@ static void GL_TextureMode_f (void)
                        }
                }
                break;
-       case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
-               d3d_filter_flatmin = d3dmodes[i].m1;
-               d3d_filter_flatmag = d3dmodes[i].m1;
-               d3d_filter_flatmix = D3DTEXF_POINT;
-               d3d_filter_mipmin = d3dmodes[i].m1;
-               d3d_filter_mipmag = d3dmodes[i].m1;
-               d3d_filter_mipmix = d3dmodes[i].m2;
-               d3d_filter_nomip = i < 2;
-               if (gl_texture_anisotropy.integer > 1 && i == 5)
-                       d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC;
-               for (pool = gltexturepoolchain;pool;pool = pool->next)
-               {
-                       for (glt = pool->gltchain;glt;glt = glt->chain)
-                       {
-                               // only update already uploaded images
-                               if (glt->d3dtexture && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
-                               {
-                                       if (glt->flags & TEXF_MIPMAP)
-                                       {
-                                               glt->d3dminfilter = d3d_filter_mipmin;
-                                               glt->d3dmagfilter = d3d_filter_mipmag;
-                                               glt->d3dmipfilter = d3d_filter_mipmix;
-                                               glt->d3dmaxmiplevelfilter = 0;
-                                       }
-                                       else
-                                       {
-                                               glt->d3dminfilter = d3d_filter_flatmin;
-                                               glt->d3dmagfilter = d3d_filter_flatmag;
-                                               glt->d3dmipfilter = d3d_filter_flatmix;
-                                               glt->d3dmaxmiplevelfilter = 0;
-                                       }
-                               }
-                       }
-               }
-#endif
-               break;
-       case RENDERPATH_D3D10:
-               Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-               break;
-       case RENDERPATH_D3D11:
-               Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-               break;
        }
 }
 
@@ -511,39 +512,9 @@ static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, i
                break;
        }
 
-       if (outwidth)
-       {
-               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)
-       {
-               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)
-       {
-               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);
-       }
+       width2 = min(inwidth >> picmip, maxsize);
+       height2 = min(inheight >> picmip, maxsize);
+       depth2 = min(indepth >> picmip, maxsize);
 
        miplevels = 1;
        if (flags & TEXF_MIPMAP)
@@ -552,6 +523,13 @@ static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, i
                while(extent >>= 1)
                        miplevels++;
        }
+
+       if (outwidth)
+               *outwidth = max(1, width2);
+       if (outheight)
+               *outheight = max(1, height2);
+       if (outdepth)
+               *outdepth = max(1, depth2);
        if (outmiplevels)
                *outmiplevels = miplevels;
 }
@@ -603,7 +581,7 @@ void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean print
                for (glt = pool->gltchain;glt;glt = glt->chain)
                {
                        glsize = R_CalcTexelDataSize(glt);
-                       isloaded = glt->texnum != 0;
+                       isloaded = glt->texnum != 0 || glt->renderbuffernum != 0;
                        pooltotal++;
                        pooltotalt += glsize;
                        pooltotalp += glt->inputdatasize;
@@ -614,7 +592,7 @@ void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean print
                                poolloadedp += glt->inputdatasize;
                        }
                        if (printeach)
-                               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);
+                               Con_Printf("%c%4i%c%c%4i%c %-24s %s %s %s %s\n", isloaded ? '[' : ' ', (glsize + 1023) / 1024, isloaded ? ']' : ' ', glt->inputtexels ? '[' : ' ', (glt->inputdatasize + 1023) / 1024, glt->inputtexels ? ']' : ' ', glt->textype->name, isloaded ? "loaded" : "      ", (glt->flags & TEXF_MIPMAP) ? "mip" : "   ", (glt->flags & TEXF_ALPHA) ? "alpha" : "     ", glt->identifier);
                }
                if (printpool)
                        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);
@@ -638,23 +616,13 @@ static void r_textures_start(void)
 {
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL11:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
+       case RENDERPATH_GL32:
+       case RENDERPATH_GLES2:
                // LordHavoc: allow any alignment
                CHECKGLERROR
                qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
                qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
                break;
-       case RENDERPATH_D3D9:
-               break;
-       case RENDERPATH_D3D10:
-               Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-               break;
-       case RENDERPATH_D3D11:
-               Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-               break;
        }
 
        texturemempool = Mem_AllocPool("texture management", 0, NULL);
@@ -695,7 +663,7 @@ static void r_textures_devicelost(void)
 {
        int i, endindex;
        gltexture_t *glt;
-       endindex = Mem_ExpandableArray_IndexRange(&texturearray);
+       endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
        for (i = 0;i < endindex;i++)
        {
                glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
@@ -703,27 +671,8 @@ static void r_textures_devicelost(void)
                        continue;
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL11:
-               case RENDERPATH_GL13:
-               case RENDERPATH_GL20:
-               case RENDERPATH_CGGL:
-                       break;
-               case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
-                       if (glt->tiledepth > 1)
-                               IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
-                       else if (glt->sides == 6)
-                               IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
-                       else
-                               IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
-                       glt->d3dtexture = NULL;
-#endif
-                       break;
-               case RENDERPATH_D3D10:
-                       Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-                       break;
-               case RENDERPATH_D3D11:
-                       Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+               case RENDERPATH_GL32:
+               case RENDERPATH_GLES2:
                        break;
                }
        }
@@ -733,7 +682,7 @@ static void r_textures_devicerestored(void)
 {
        int i, endindex;
        gltexture_t *glt;
-       endindex = Mem_ExpandableArray_IndexRange(&texturearray);
+       endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray);
        for (i = 0;i < endindex;i++)
        {
                glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i);
@@ -741,38 +690,8 @@ static void r_textures_devicerestored(void)
                        continue;
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL11:
-               case RENDERPATH_GL13:
-               case RENDERPATH_GL20:
-               case RENDERPATH_CGGL:
-                       break;
-               case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
-                       {
-                               HRESULT d3dresult;
-                               if (glt->tiledepth > 1)
-                               {
-                                       if (FAILED(d3dresult = IDirect3DDevice9_CreateVolumeTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->tiledepth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DVolumeTexture9 **)&glt->d3dtexture, NULL)))
-                                               Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
-                               }
-                               else if (glt->sides == 6)
-                               {
-                                       if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
-                                               Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
-                               }
-                               else
-                               {
-                                       if (FAILED(d3dresult = IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL)))
-                                               Sys_Error("IDirect3DDevice9_CreateTexture failed!");
-                               }
-                       }
-#endif
-                       break;
-               case RENDERPATH_D3D10:
-                       Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-                       break;
-               case RENDERPATH_D3D11:
-                       Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+               case RENDERPATH_GL32:
+               case RENDERPATH_GLES2:
                        break;
                }
        }
@@ -804,14 +723,21 @@ void R_Textures_Init (void)
        Cvar_RegisterVariable (&gl_texturecompression_sky);
        Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
        Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
+       Cvar_RegisterVariable (&gl_texturecompression_sprites);
        Cvar_RegisterVariable (&gl_nopartialtextureupdates);
+       Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
+       Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
+       Cvar_RegisterVariable (&r_texture_dds_swdecode);
 
        R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
 }
 
 void R_Textures_Frame (void)
 {
+#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
        static int old_aniso = 0;
+       static qboolean first_time_aniso = true;
+#endif
 
        // could do procedural texture animation here, if we keep track of which
        // textures were accessed this frame...
@@ -829,6 +755,7 @@ void R_Textures_Frame (void)
                colorconvertbuffer = NULL;
        }
 
+#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
        if (old_aniso != gl_texture_anisotropy.integer)
        {
                gltexture_t *glt;
@@ -841,10 +768,14 @@ void R_Textures_Frame (void)
 
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL11:
-               case RENDERPATH_GL13:
-               case RENDERPATH_GL20:
-               case RENDERPATH_CGGL:
+               case RENDERPATH_GL32:
+               case RENDERPATH_GLES2:
+                       // ignore the first difference, any textures loaded by now probably had the same aniso value
+                       if (first_time_aniso)
+                       {
+                               first_time_aniso = false;
+                               break;
+                       }
                        CHECKGLERROR
                        GL_ActiveTexture(0);
                        for (pool = gltexturepoolchain;pool;pool = pool->next)
@@ -864,15 +795,12 @@ void R_Textures_Frame (void)
                                }
                        }
                        break;
-               case RENDERPATH_D3D9:
-               case RENDERPATH_D3D10:
-               case RENDERPATH_D3D11:
-                       break;
                }
        }
+#endif
 }
 
-void R_MakeResizeBufferBigger(int size)
+static void R_MakeResizeBufferBigger(int size)
 {
        if (resizebuffersize < size)
        {
@@ -895,6 +823,7 @@ static void GL_SetupTextureParameters(int flags, textype_t textype, int texturet
 
        CHECKGLERROR
 
+#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
        if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
        {
                int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
@@ -902,12 +831,15 @@ static void GL_SetupTextureParameters(int flags, textype_t textype, int texturet
                        Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
                qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
        }
+#endif
        qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
        qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
+#ifdef GL_TEXTURE_WRAP_R
        if (gltexturetypedimensions[texturetype] >= 3)
        {
                qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
        }
+#endif
 
        CHECKGLERROR
        if (!gl_filter_force && flags & TEXF_FORCENEAREST)
@@ -954,160 +886,152 @@ static void GL_SetupTextureParameters(int flags, textype_t textype, int texturet
                qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
        }
 
-       if (textype == TEXTYPE_SHADOWMAP)
+#ifndef USE_GLES2
+       switch(textype)
        {
-               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
+       case TEXTYPE_SHADOWMAP16_COMP:
+       case TEXTYPE_SHADOWMAP24_COMP:
+               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);CHECKGLERROR
+               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);CHECKGLERROR
+               break;
+       case TEXTYPE_SHADOWMAP16_RAW:
+       case TEXTYPE_SHADOWMAP24_RAW:
+               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE, GL_NONE);CHECKGLERROR
+               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);CHECKGLERROR
+               break;
+       default:
+               break;
        }
+#endif
 
        CHECKGLERROR
 }
 
-static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
+static void R_UploadPartialTexture(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 = 0;
-       const unsigned char *prevbuffer;
-       prevbuffer = data;
+       if (data == NULL)
+               Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
+
+       if (glt->texturetype != GLTEXTURETYPE_2D)
+               Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
+
+       if (glt->textype->textype == TEXTYPE_PALETTE)
+               Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
+
+       if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
+               Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
+
+       if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
+               Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
+
+       // update a portion of the image
 
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL11:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
-               CHECKGLERROR
-
-               // we need to restore the texture binding after finishing the upload
-               GL_ActiveTexture(0);
-               oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
-               qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
-               break;
-       case RENDERPATH_D3D9:
-       case RENDERPATH_D3D10:
-       case RENDERPATH_D3D11:
+       case RENDERPATH_GL32:
+       case RENDERPATH_GLES2:
+               {
+                       int oldbindtexnum;
+                       CHECKGLERROR
+                       // we need to restore the texture binding after finishing the upload
+                       GL_ActiveTexture(0);
+                       oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
+                       qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
+                       qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
+                       qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
+               }
                break;
        }
+}
 
-       // these are rounded up versions of the size to do better resampling
-       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);
-       }
+static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
+{
+       int i, mip = 0, width, height, depth;
+       GLint oldbindtexnum = 0;
+       const unsigned char *prevbuffer;
+       prevbuffer = data;
+
+       // error out if a stretch is needed on special texture types
+       if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
+               Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
 
-       R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
-       R_MakeResizeBufferBigger(fragwidth * fragheight * fragdepth * glt->sides * glt->bytesperpixel);
+       // when picmip or maxsize is applied, we scale up to a power of 2 multiple
+       // of the target size and then use the mipmap reduction function to get
+       // high quality supersampled results
+       for (width  = glt->tilewidth;width  < glt->inputwidth ;width  <<= 1);
+       for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
+       for (depth  = glt->tiledepth;depth  < glt->inputdepth ;depth  <<= 1);
 
        if (prevbuffer == NULL)
        {
-               memset(resizebuffer, 0, fragwidth * fragheight * fragdepth * glt->bytesperpixel);
-               prevbuffer = resizebuffer;
-       }
-       else if (glt->textype->textype == TEXTYPE_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;
+               width = glt->tilewidth;
+               height = glt->tileheight;
+               depth = glt->tiledepth;
+//             R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
+//             memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
+//             prevbuffer = resizebuffer;
        }
-
-       // upload the image - preferring to do only complete uploads (drivers do not really like partial updates)
-
-       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))
+       else
        {
-               // update a portion of the image
-               if (glt->texturetype != GLTEXTURETYPE_2D)
-                       Sys_Error("R_Upload: partial update of type other than 2D");
-               switch(vid.renderpath)
+               if (glt->textype->textype == TEXTYPE_PALETTE)
                {
-               case RENDERPATH_GL11:
-               case RENDERPATH_GL13:
-               case RENDERPATH_GL20:
-               case RENDERPATH_CGGL:
-                       qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
-                       qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
-                       break;
-               case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
-                       {
-                               RECT d3drect;
-                               D3DLOCKED_RECT d3dlockedrect;
-                               int y;
-                               memset(&d3drect, 0, sizeof(d3drect));
-                               d3drect.left = fragx;
-                               d3drect.top = fragy;
-                               d3drect.right = fragx+fragwidth;
-                               d3drect.bottom = fragy+fragheight;
-                               if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
-                               {
-                                       for (y = 0;y < fragheight;y++)
-                                               memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, (unsigned char *)prevbuffer + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
-                                       IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
-                               }
-                       }
-#endif
-                       break;
-               case RENDERPATH_D3D10:
-                       Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-                       break;
-               case RENDERPATH_D3D11:
-                       Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-                       break;
+                       // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
+                       R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
+                       Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
+                       prevbuffer = colorconvertbuffer;
                }
-       }
-       else
-       {
-               if (fragx || fragy || fragz || glt->inputwidth != fragwidth || glt->inputheight != fragheight || glt->inputdepth != fragdepth)
-                       Host_Error("R_Upload: partial update not allowed on initial upload or in combination with PICMIP or MIPMAP\n");
-
-               // cubemaps contain multiple images and thus get processed a bit differently
-               if (glt->texturetype != GLTEXTURETYPE_CUBEMAP)
+               if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
                {
-                       if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
-                       {
-                               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)
+                       // multiply RGB channels by A channel before uploading
+                       int alpha;
+                       R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
+                       for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
                        {
-                               Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
-                               prevbuffer = resizebuffer;
+                               alpha = prevbuffer[i+3];
+                               colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
+                               colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
+                               colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
+                               colorconvertbuffer[i+3] = alpha;
                        }
+                       prevbuffer = colorconvertbuffer;
                }
-               mip = 0;
-               switch(vid.renderpath)
+               // scale up to a power of 2 size (if appropriate)
+               if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
                {
-               case RENDERPATH_GL11:
-               case RENDERPATH_GL13:
-               case RENDERPATH_GL20:
-               case RENDERPATH_CGGL:
-                       if (qglGetCompressedTexImageARB)
-                       {
-                               if (gl_texturecompression.integer >= 2)
-                                       qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
-                               else
-                                       qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
-                               CHECKGLERROR
-                       }
+                       R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
+                       Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
+                       prevbuffer = resizebuffer;
+               }
+               // apply mipmap reduction algorithm to get down to picmip/max_size
+               while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
+               {
+                       R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
+                       Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
+                       prevbuffer = resizebuffer;
+               }
+       }
+
+       // do the appropriate upload type...
+       switch(vid.renderpath)
+       {
+       case RENDERPATH_GL32:
+       case RENDERPATH_GLES2:
+               if (glt->texnum) // not renderbuffers
+               {
+                       CHECKGLERROR
+
+                       // we need to restore the texture binding after finishing the upload
+                       GL_ActiveTexture(0);
+                       oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
+                       qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
+
+#ifndef USE_GLES2
+                       if (gl_texturecompression.integer >= 2)
+                               qglHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
+                       else
+                               qglHint(GL_TEXTURE_COMPRESSION_HINT, GL_FASTEST);
+                       CHECKGLERROR
+#endif
                        switch(glt->texturetype)
                        {
                        case GLTEXTURETYPE_2D:
@@ -1116,6 +1040,7 @@ static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int
                                {
                                        while (width > 1 || height > 1 || depth > 1)
                                        {
+                                               R_MakeResizeBufferBigger(width * height * depth * glt->sides * 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, glt->gltype, prevbuffer);CHECKGLERROR
@@ -1123,16 +1048,19 @@ static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int
                                }
                                break;
                        case GLTEXTURETYPE_3D:
+#ifndef USE_GLES2
                                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)
                                        {
+                                               R_MakeResizeBufferBigger(width * height * depth * glt->sides * 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, glt->gltype, prevbuffer);CHECKGLERROR
                                        }
                                }
+#endif
                                break;
                        case GLTEXTURETYPE_CUBEMAP:
                                // convert and upload each side in turn,
@@ -1144,12 +1072,14 @@ static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int
                                        texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
                                        if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
                                        {
+                                               R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
                                                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)
                                        {
+                                               R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
                                                Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
                                                prevbuffer = resizebuffer;
                                        }
@@ -1159,6 +1089,7 @@ static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int
                                        {
                                                while (width > 1 || height > 1 || depth > 1)
                                                {
+                                                       R_MakeResizeBufferBigger(width * height * depth * glt->sides * 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, glt->gltype, prevbuffer);CHECKGLERROR
@@ -1166,197 +1097,96 @@ static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int
                                        }
                                }
                                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->textype->textype, glt->texturetype);
                        qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
+               }
+               break;
+       }
+}
+
+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)
+{
+       int i, size;
+       gltexture_t *glt;
+       gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
+       textypeinfo_t *texinfo, *texinfo2;
+       unsigned char *temppixels = NULL;
+       qboolean swaprb;
+
+       if (cls.state == ca_dedicated)
+               return NULL;
+
+       // see if we need to swap red and blue (BGRA <-> RGBA conversion)
+       if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
+       {
+               int numpixels = width * height * depth * sides;
+               size = numpixels * 4;
+               temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
+               if (data)
+               {
+                       const unsigned char *p;
+                       unsigned char *o = temppixels;
+                       for (i = 0;i < numpixels;i++, o += 4)
+                       {
+                               p = (const unsigned char *)palette + 4*data[i];
+                               o[0] = p[2];
+                               o[1] = p[1];
+                               o[2] = p[0];
+                               o[3] = p[3];
+                       }
+               }
+               data = temppixels;
+               textype = TEXTYPE_RGBA;
+       }
+       swaprb = false;
+       switch(textype)
+       {
+       case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
+       case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
+       case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
+       case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
+       default: break;
+       }
+       if (swaprb)
+       {
+               // swap bytes
+               static int rgbaswapindices[4] = {2, 1, 0, 3};
+               size = width * height * depth * sides * 4;
+               temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
+               if (data)
+                       Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
+               data = temppixels;
+       }
+
+       // if sRGB texture formats are not supported, convert input to linear and upload as normal types
+       if (!vid.support.ext_texture_srgb)
+       {
+               qboolean convertsRGB = false;
+               switch(textype)
+               {
+               case TEXTYPE_SRGB_DXT1:    textype = TEXTYPE_DXT1   ;convertsRGB = true;break;
+               case TEXTYPE_SRGB_DXT1A:   textype = TEXTYPE_DXT1A  ;convertsRGB = true;break;
+               case TEXTYPE_SRGB_DXT3:    textype = TEXTYPE_DXT3   ;convertsRGB = true;break;
+               case TEXTYPE_SRGB_DXT5:    textype = TEXTYPE_DXT5   ;convertsRGB = true;break;
+               case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;/*convertsRGB = true;*/break;
+               case TEXTYPE_SRGB_RGBA:    textype = TEXTYPE_RGBA   ;convertsRGB = true;break;
+               case TEXTYPE_SRGB_BGRA:    textype = TEXTYPE_BGRA   ;convertsRGB = true;break;
+               default:
                        break;
-               case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
-                       if (!(glt->flags & TEXF_RENDERTARGET))
+               }
+               if (convertsRGB && data)
+               {
+                       size = width * height * depth * sides * 4;
+                       if (!temppixels)
                        {
-                               D3DLOCKED_RECT d3dlockedrect;
-                               D3DLOCKED_BOX d3dlockedbox;
-                               switch(glt->texturetype)
-                               {
-                               case GLTEXTURETYPE_2D:
-                                       if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
-                                       {
-                                               if (prevbuffer)
-                                                       memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
-                                               else
-                                                       memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
-                                               IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
-                                       }
-                                       mip++;
-                                       if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
-                                       {
-                                               while (width > 1 || height > 1 || depth > 1)
-                                               {
-                                                       Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
-                                                       prevbuffer = resizebuffer;
-                                                       if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
-                                                       {
-                                                               memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
-                                                               IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
-                                                       }
-                                                       mip++;
-                                               }
-                                       }
-                                       break;
-                               case GLTEXTURETYPE_3D:
-                                       if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
-                                       {
-                                               // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
-                                               memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
-                                               IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
-                                       }
-                                       mip++;
-                                       if (glt->flags & TEXF_MIPMAP)
-                                       {
-                                               while (width > 1 || height > 1 || depth > 1)
-                                               {
-                                                       Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
-                                                       prevbuffer = resizebuffer;
-                                                       if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
-                                                       {
-                                                               // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
-                                                               memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
-                                                               IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
-                                                       }
-                                                       mip++;
-                                               }
-                                       }
-                                       break;
-                               case GLTEXTURETYPE_CUBEMAP:
-                                       // convert and upload each side in turn,
-                                       // from a continuous block of input texels
-                                       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_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_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
-                                                       prevbuffer = resizebuffer;
-                                               }
-                                               mip = 0;
-                                               if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
-                                               {
-                                                       memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
-                                                       IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
-                                               }
-                                               mip++;
-                                               if (glt->flags & TEXF_MIPMAP)
-                                               {
-                                                       while (width > 1 || height > 1 || depth > 1)
-                                                       {
-                                                               Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
-                                                               prevbuffer = resizebuffer;
-                                                               if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
-                                                               {
-                                                                       memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
-                                                                       IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
-                                                               }
-                                                               mip++;
-                                                       }
-                                               }
-                                       }
-                                       break;
-                               case GLTEXTURETYPE_RECTANGLE:
-                                       Sys_Error("Direct3D does not have RECTANGLE textures\n");
-                                       break;
-                               }
-                       }
-                       glt->d3daddressw = 0;
-                       if (glt->flags & TEXF_CLAMP)
-                       {
-                               glt->d3daddressu = D3DTADDRESS_CLAMP;
-                               glt->d3daddressv = D3DTADDRESS_CLAMP;
-                               if (glt->tiledepth > 1)
-                                       glt->d3daddressw = D3DTADDRESS_CLAMP;
-                       }
-                       else
-                       {
-                               glt->d3daddressu = D3DTADDRESS_WRAP;
-                               glt->d3daddressv = D3DTADDRESS_WRAP;
-                               if (glt->tiledepth > 1)
-                                       glt->d3daddressw = D3DTADDRESS_WRAP;
-                       }
-                       glt->d3dmipmaplodbias = 0;
-                       glt->d3dmaxmiplevel = 0;
-                       glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
-                       if (glt->flags & TEXF_FORCELINEAR)
-                       {
-                               glt->d3dminfilter = D3DTEXF_LINEAR;
-                               glt->d3dmagfilter = D3DTEXF_LINEAR;
-                               glt->d3dmipfilter = D3DTEXF_POINT;
-                       }
-                       else if (glt->flags & TEXF_FORCENEAREST)
-                       {
-                               glt->d3dminfilter = D3DTEXF_POINT;
-                               glt->d3dmagfilter = D3DTEXF_POINT;
-                               glt->d3dmipfilter = D3DTEXF_POINT;
-                       }
-                       else if (glt->flags & TEXF_MIPMAP)
-                       {
-                               glt->d3dminfilter = d3d_filter_mipmin;
-                               glt->d3dmagfilter = d3d_filter_mipmag;
-                               glt->d3dmipfilter = d3d_filter_mipmix;
+                               temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
+                               memcpy(temppixels, data, size);
+                               data = temppixels;
                        }
-                       else
-                       {
-                               glt->d3dminfilter = d3d_filter_flatmin;
-                               glt->d3dmagfilter = d3d_filter_flatmag;
-                               glt->d3dmipfilter = d3d_filter_flatmix;
-                       }
-#endif
-                       break;
-               case RENDERPATH_D3D10:
-                       Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-                       break;
-               case RENDERPATH_D3D11:
-                       Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-                       break;
+                       Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
                }
        }
-}
-
-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)
-{
-       int i, size;
-       gltexture_t *glt;
-       gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
-       textypeinfo_t *texinfo, *texinfo2;
-       unsigned char *temppixels = NULL;
-
-       if (cls.state == ca_dedicated)
-               return NULL;
-
-       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 && !vid.support.ext_texture_3d)
-       {
-               Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
-               return NULL;
-       }
 
        texinfo = R_GetTexTypeInfo(textype, flags);
        size = width * height * depth * sides * texinfo->inputbytesperpixel;
@@ -1366,21 +1196,11 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
                return NULL;
        }
 
-       if (textype == TEXTYPE_RGBA)
-       {
-               // swap bytes
-               static int rgbaswapindices[4] = {2, 1, 0, 3};
-               textype = TEXTYPE_BGRA;
-               texinfo = R_GetTexTypeInfo(textype, flags);
-               temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4);
-               Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
-               data = temppixels;
-       }
-
        // clear the alpha flag if the texture has no transparent pixels
        switch(textype)
        {
        case TEXTYPE_PALETTE:
+       case TEXTYPE_SRGB_PALETTE:
                if (flags & TEXF_ALPHA)
                {
                        flags &= ~TEXF_ALPHA;
@@ -1399,6 +1219,8 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
                break;
        case TEXTYPE_RGBA:
        case TEXTYPE_BGRA:
+       case TEXTYPE_SRGB_RGBA:
+       case TEXTYPE_SRGB_BGRA:
                if (flags & TEXF_ALPHA)
                {
                        flags &= ~TEXF_ALPHA;
@@ -1415,19 +1237,28 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
                        }
                }
                break;
-       case TEXTYPE_SHADOWMAP:
+       case TEXTYPE_SHADOWMAP16_COMP:
+       case TEXTYPE_SHADOWMAP16_RAW:
+       case TEXTYPE_SHADOWMAP24_COMP:
+       case TEXTYPE_SHADOWMAP24_RAW:
                break;
        case TEXTYPE_DXT1:
+       case TEXTYPE_SRGB_DXT1:
                break;
        case TEXTYPE_DXT1A:
+       case TEXTYPE_SRGB_DXT1A:
        case TEXTYPE_DXT3:
+       case TEXTYPE_SRGB_DXT3:
        case TEXTYPE_DXT5:
+       case TEXTYPE_SRGB_DXT5:
                flags |= TEXF_ALPHA;
                break;
        case TEXTYPE_ALPHA:
                flags |= TEXF_ALPHA;
                break;
        case TEXTYPE_COLORBUFFER:
+       case TEXTYPE_COLORBUFFER16F:
+       case TEXTYPE_COLORBUFFER32F:
                flags |= TEXF_ALPHA;
                break;
        default:
@@ -1462,10 +1293,11 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
        glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
        glt->texnum = 0;
        glt->dirty = false;
+       glt->glisdepthstencil = false;
        glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
        // init the dynamic texture attributes, too [11/22/2007 Black]
        glt->updatecallback = NULL;
-       glt->updatacallback_data = NULL;
+       glt->updatecallback_data = NULL;
 
        GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
 
@@ -1473,67 +1305,14 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
        // data may be NULL (blank texture for dynamic rendering)
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL11:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
+       case RENDERPATH_GL32:
+       case RENDERPATH_GLES2:
                CHECKGLERROR
                qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
                break;
-       case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
-               {
-                       D3DFORMAT d3dformat;
-                       D3DPOOL d3dpool;
-                       DWORD d3dusage;
-                       HRESULT d3dresult;
-                       d3dusage = 0;
-                       d3dpool = D3DPOOL_MANAGED;
-                       if (flags & TEXF_RENDERTARGET)
-                       {
-                               d3dusage |= D3DUSAGE_RENDERTARGET;
-                               d3dpool = D3DPOOL_DEFAULT;
-                       }
-                       switch(textype)
-                       {
-                       case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
-                       case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
-                       case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
-                       case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
-                       case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
-                       case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
-                       default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
-                       }
-                       glt->d3dformat = d3dformat;
-                       glt->d3dusage = d3dusage;
-                       glt->d3dpool = d3dpool;
-                       if (glt->tiledepth > 1)
-                       {
-                               if (FAILED(d3dresult = IDirect3DDevice9_CreateVolumeTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->tiledepth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DVolumeTexture9 **)&glt->d3dtexture, NULL)))
-                                       Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
-                       }
-                       else if (glt->sides == 6)
-                       {
-                               if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL)))
-                                       Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!");
-                       }
-                       else
-                       {
-                               if (FAILED(d3dresult = IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL)))
-                                       Sys_Error("IDirect3DDevice9_CreateTexture failed!");
-                       }
-               }
-#endif
-               break;
-       case RENDERPATH_D3D10:
-               Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-               break;
-       case RENDERPATH_D3D11:
-               Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-               break;
        }
 
-       R_Upload(glt, data, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
+       R_UploadFullTexture(glt, data);
        if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
                glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
 
@@ -1563,40 +1342,75 @@ rtexture_t *R_LoadTextureCubeMap(rtexturepool_t *rtexturepool, const char *ident
        return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
 }
 
-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)
+rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter)
 {
-       return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_RECTANGLE, data, palette);
+       return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL);
 }
 
-static int R_ShadowMapTextureFlags(int precision, qboolean filter)
+rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
 {
-       int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
-       if (filter)
-               flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
-       else
-               flags |= TEXF_FORCENEAREST;
-       if (precision <= 16)
-               flags |= TEXF_LOWPRECISION;
-       return flags;
-}
+       gltexture_t *glt;
+       gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
+       textypeinfo_t *texinfo;
 
-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), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
-}
+       if (cls.state == ca_dedicated)
+               return NULL;
 
-rtexture_t *R_LoadTextureShadowMap2D(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), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
-}
+       texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP);
 
-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), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
+       glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
+       if (identifier)
+               strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
+       glt->pool = pool;
+       glt->chain = pool->gltchain;
+       pool->gltchain = glt;
+       glt->inputwidth = width;
+       glt->inputheight = height;
+       glt->inputdepth = 1;
+       glt->flags = TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_FORCENEAREST;
+       glt->miplevel = 0;
+       glt->textype = texinfo;
+       glt->texturetype = textype;
+       glt->inputdatasize = width*height*texinfo->internalbytesperpixel;
+       glt->palette = NULL;
+       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 = 0;
+       glt->dirty = false;
+       glt->glisdepthstencil = textype == TEXTYPE_DEPTHBUFFER24STENCIL8;
+       glt->gltexturetypeenum = GL_TEXTURE_2D;
+       // init the dynamic texture attributes, too [11/22/2007 Black]
+       glt->updatecallback = NULL;
+       glt->updatecallback_data = NULL;
+
+       GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
+
+       // upload the texture
+       // data may be NULL (blank texture for dynamic rendering)
+       switch(vid.renderpath)
+       {
+       case RENDERPATH_GL32:
+       case RENDERPATH_GLES2:
+               CHECKGLERROR
+               qglGenRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
+               qglBindRenderbuffer(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR
+               qglRenderbufferStorage(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR
+               // note we can query the renderbuffer for info with glGetRenderbufferParameteriv for GL_WIDTH, GL_HEIGHt, GL_RED_SIZE, GL_GREEN_SIZE, GL_BLUE_SIZE, GL_GL_ALPHA_SIZE, GL_DEPTH_SIZE, GL_STENCIL_SIZE, GL_INTERNAL_FORMAT
+               qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR
+               break;
+       }
+
+       return (rtexture_t *)glt;
 }
 
-int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed)
+int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
 {
+#ifdef USE_GLES2
+       return -1; // unsupported on this platform
+#else
        gltexture_t *glt = (gltexture_t *)rt;
        unsigned char *dds;
        int oldbindtexnum;
@@ -1631,13 +1445,22 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco
        case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
        case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
        }
+       // if premultiplied alpha, say so in the DDS file
+       if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
+       {
+               switch(internalformat)
+               {
+                       case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
+                       case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
+               }
+       }
        if (!bytesperblock && skipuncompressed)
                return -3; // skipped
        memset(mipinfo, 0, sizeof(mipinfo));
        mipinfo[0][0] = glt->tilewidth;
        mipinfo[0][1] = glt->tileheight;
        mipmaps = 1;
-       if (glt->flags & TEXF_MIPMAP)
+       if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1))
        {
                for (mip = 1;mip < 16;mip++)
                {
@@ -1670,19 +1493,21 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco
        else
        {
                dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
-               dds_format_flags = 0x41; // DDPF_RGB | DDPF_ALPHAPIXELS
+               dds_format_flags = 0x40; // DDPF_RGB
        }
        if (mipmaps)
        {
                dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
                dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
        }
+       if(hasalpha)
+               dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
        memcpy(dds, "DDS ", 4);
-       StoreLittleLong(dds+4, ddssize);
+       StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
        StoreLittleLong(dds+8, dds_flags);
        StoreLittleLong(dds+12, mipinfo[0][1]); // height
        StoreLittleLong(dds+16, mipinfo[0][0]); // width
-       StoreLittleLong(dds+24, 1); // depth
+       StoreLittleLong(dds+24, 0); // depth
        StoreLittleLong(dds+28, mipmaps); // mipmaps
        StoreLittleLong(dds+76, 32); // format size
        StoreLittleLong(dds+80, dds_format_flags);
@@ -1694,7 +1519,7 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco
                memcpy(dds+84, ddsfourcc, 4);
                for (mip = 0;mip < mipmaps;mip++)
                {
-                       qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
+                       qglGetCompressedTexImage(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
                }
        }
        else
@@ -1711,9 +1536,15 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco
        ret = FS_WriteFile(filename, dds, ddssize);
        Mem_Free(dds);
        return ret ? ddssize : -5;
+#endif
 }
 
-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
+#ifdef __ANDROID__
+// ELUAN: FIXME: separate this code
+#include "ktx10/include/ktx.h"
+#endif
+
+rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qboolean srgb, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel, qboolean optionaltexture) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint
 {
        int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
        //int dds_flags;
@@ -1723,23 +1554,171 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
        gltexture_t *glt;
        gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
        textypeinfo_t *texinfo;
-       int mip, mipwidth, mipheight, mipsize;
-       unsigned int c;
+       int mip, mipwidth, mipheight, mipsize, mipsize_total;
+       unsigned int c, r, g, b;
        GLint oldbindtexnum = 0;
-       const unsigned char *mippixels, *ddspixels;
+       unsigned char *mippixels;
+       unsigned char *mippixels_start;
+       unsigned char *ddspixels;
        unsigned char *dds;
        fs_offset_t ddsfilesize;
        unsigned int ddssize;
+       qboolean force_swdecode;
+#ifdef __ANDROID__
+       // ELUAN: FIXME: separate this code
+       char vabuf[1024];
+       char vabuf2[1024];
+       int strsize;
+       KTX_dimensions sizes;
+#endif
 
        if (cls.state == ca_dedicated)
                return NULL;
 
+#ifdef __ANDROID__
+       // ELUAN: FIXME: separate this code
+       if (vid.renderpath != RENDERPATH_GLES2)
+       {
+               Con_DPrintf("KTX texture format is only supported on the GLES2 renderpath\n");
+               return NULL;
+       }
+
+       // some textures are specified with extensions, so it becomes .tga.dds
+       FS_StripExtension (filename, vabuf2, sizeof(vabuf2));
+       FS_StripExtension (vabuf2, vabuf, sizeof(vabuf));
+       FS_DefaultExtension (vabuf, ".ktx", sizeof(vabuf));
+       strsize = strlen(vabuf);
+       if (strsize > 5)
+       for (i = 0; i <= strsize - 4; i++) // copy null termination
+               vabuf[i] = vabuf[i + 4];
+
+       Con_DPrintf("Loading %s...\n", vabuf);
+       dds = FS_LoadFile(vabuf, tempmempool, true, &ddsfilesize);
+       ddssize = ddsfilesize;
+
+       if (!dds)
+       {
+               Con_DPrintf("Not found!\n");
+               return NULL; // not found
+       }
+       Con_DPrintf("Found!\n");
+
+       if (flags & TEXF_ALPHA)
+       {
+               Con_DPrintf("KTX texture with alpha not supported yet, disabling\n");
+               flags &= ~TEXF_ALPHA;
+       }
+
+       {
+               GLenum target;
+               GLenum glerror;
+               GLboolean isMipmapped;
+               KTX_error_code ktxerror;
+
+               glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
+
+               // texture uploading can take a while, so make sure we're sending keepalives
+               CL_KeepaliveMessage(false);
+
+               // create the texture object
+               CHECKGLERROR
+               GL_ActiveTexture(0);
+               oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[GLTEXTURETYPE_2D]);
+               qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
+               qglBindTexture(gltexturetypeenums[GLTEXTURETYPE_2D], glt->texnum);CHECKGLERROR
+
+               // upload the texture
+               // we need to restore the texture binding after finishing the upload
+
+               // NOTE: some drivers fail with ETC1 NPOT (only PowerVR?). This may make the driver crash later.
+               ktxerror = ktxLoadTextureM(dds, ddssize, &glt->texnum, &target, &sizes, &isMipmapped, &glerror,
+                                                               0, NULL);// can't CHECKGLERROR, the lib catches it
+
+               // FIXME: delete texture if we fail here
+               if (target != GL_TEXTURE_2D)
+               {
+                       qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
+                       Mem_Free(dds);
+                       Con_DPrintf("%s target != GL_TEXTURE_2D, target == %x\n", vabuf, target);
+                       return NULL; // FIXME: delete the texture from memory
+               }
+
+               if (KTX_SUCCESS == ktxerror)
+               {
+                       textype = TEXTYPE_ETC1;
+                       flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
+
+                       // return whether this texture is transparent
+                       if (hasalphaflag)
+                               *hasalphaflag = (flags & TEXF_ALPHA) != 0;
+
+                       // TODO: apply gl_picmip
+                       // TODO: avgcolor
+                       // TODO: srgb
+                       // TODO: only load mipmaps if requested
+
+                       if (isMipmapped)
+                               flags |= TEXF_MIPMAP;
+                       else
+                               flags &= ~TEXF_MIPMAP;
+
+                       texinfo = R_GetTexTypeInfo(textype, flags);
+
+                       strlcpy (glt->identifier, vabuf, sizeof(glt->identifier));
+                       glt->pool = pool;
+                       glt->chain = pool->gltchain;
+                       pool->gltchain = glt;
+                       glt->inputwidth = sizes.width;
+                       glt->inputheight = sizes.height;
+                       glt->inputdepth = 1;
+                       glt->flags = flags;
+                       glt->textype = texinfo;
+                       glt->texturetype = GLTEXTURETYPE_2D;
+                       glt->inputdatasize = ddssize;
+                       glt->glinternalformat = texinfo->glinternalformat;
+                       glt->glformat = texinfo->glformat;
+                       glt->gltype = texinfo->gltype;
+                       glt->bytesperpixel = texinfo->internalbytesperpixel;
+                       glt->sides = 1;
+                       glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
+                       glt->tilewidth = sizes.width;
+                       glt->tileheight = sizes.height;
+                       glt->tiledepth = 1;
+                       glt->miplevels = isMipmapped ? 1 : 0; // FIXME
+
+                               // after upload we have to set some parameters...
+#ifdef GL_TEXTURE_MAX_LEVEL
+                       /* FIXME
+                               if (dds_miplevels >= 1 && !mipcomplete)
+                               {
+                                       // need to set GL_TEXTURE_MAX_LEVEL
+                                       qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
+                               }
+                       */
+#endif
+                               GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
+
+                               qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
+                               Mem_Free(dds);
+                               return (rtexture_t *)glt;
+               }
+               else
+               {
+                       qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
+                       Mem_Free(dds);
+                       Con_DPrintf("KTX texture %s failed to load: %x\n", vabuf, ktxerror);
+                       return NULL;
+               }
+       }
+#endif // __ANDROID__
+
        dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
        ddssize = ddsfilesize;
 
        if (!dds)
        {
-               Log_Printf("ddstexturefailures.log", "%s\n", filename);
+               if (r_texture_dds_load_logfailure.integer && (r_texture_dds_load_logfailure.integer >= 2 || !optionaltexture))
+                       Log_Printf("ddstexturefailures.log", "%s\n", filename);
                return NULL; // not found
        }
 
@@ -1757,11 +1736,16 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
        dds_height = BuffLittleLong(dds+12);
        ddspixels = dds + 128;
 
-       flags &= ~TEXF_ALPHA;
+       if(r_texture_dds_load_alphamode.integer == 0)
+               if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
+                       flags &= ~TEXF_ALPHA;
+
+       //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
        if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
        {
                // very sloppy BGRA 32bit identification
                textype = TEXTYPE_BGRA;
+               flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
                bytesperblock = 0;
                bytesperpixel = 4;
                size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
@@ -1771,12 +1755,15 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                        Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
                        return NULL;
                }
-               // check alpha
-               for (i = 3;i < size;i += 4)
-                       if (ddspixels[i] < 255)
-                               break;
-               if (i >= size)
-                       flags &= ~TEXF_ALPHA;
+               if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
+               {
+                       // check alpha
+                       for (i = 3;i < size;i += 4)
+                               if (ddspixels[i] < 255)
+                                       break;
+                       if (i >= size)
+                               flags &= ~TEXF_ALPHA;
+               }
        }
        else if (!memcmp(dds+84, "DXT1", 4))
        {
@@ -1794,16 +1781,49 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                        Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
                        return NULL;
                }
-               for (i = 0;i < size;i += bytesperblock)
-                       if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
-                               break;
-               if (i < size)
-                       textype = TEXTYPE_DXT1A;
-               else
-                       flags &= ~TEXF_ALPHA;
+               if (flags & TEXF_ALPHA)
+               {
+                       if (r_texture_dds_load_alphamode.integer == 1)
+                       {
+                               // check alpha
+                               for (i = 0;i < size;i += bytesperblock)
+                                       if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
+                                       {
+                                               // NOTE: this assumes sizeof(unsigned int) == 4
+                                               unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
+                                               // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
+                                               if(data & (data<<1) & 0xAAAAAAAA)//rgh
+                                                       break;
+                                       }
+                               if (i < size)
+                                       textype = TEXTYPE_DXT1A;
+                               else
+                                       flags &= ~TEXF_ALPHA;
+                       }
+                       else if (r_texture_dds_load_alphamode.integer == 0)
+                               textype = TEXTYPE_DXT1A;
+                       else
+                       {
+                               flags &= ~TEXF_ALPHA;
+                       }
+               }
        }
-       else if (!memcmp(dds+84, "DXT3", 4))
+       else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
        {
+               if(!memcmp(dds+84, "DXT2", 4))
+               {
+                       if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
+                       {
+                               Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
+                       }
+               }
+               else
+               {
+                       if(flags & TEXF_RGBMULTIPLYBYALPHA)
+                       {
+                               Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
+                       }
+               }
                textype = TEXTYPE_DXT3;
                bytesperblock = 16;
                bytesperpixel = 0;
@@ -1814,9 +1834,24 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                        Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
                        return NULL;
                }
+               // we currently always assume alpha
        }
-       else if (!memcmp(dds+84, "DXT5", 4))
+       else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
        {
+               if(!memcmp(dds+84, "DXT4", 4))
+               {
+                       if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
+                       {
+                               Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
+                       }
+               }
+               else
+               {
+                       if(flags & TEXF_RGBMULTIPLYBYALPHA)
+                       {
+                               Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
+                       }
+               }
                textype = TEXTYPE_DXT5;
                bytesperblock = 16;
                bytesperpixel = 0;
@@ -1827,6 +1862,7 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                        Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
                        return NULL;
                }
+               // we currently always assume alpha
        }
        else
        {
@@ -1835,10 +1871,118 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                return NULL;
        }
 
+       // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
+       if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
+       {
+               textype = TEXTYPE_DXT1;
+               bytesperblock = 8;
+               ddssize -= 128;
+               ddssize /= 2;
+               for (i = 0;i < (int)ddssize;i += bytesperblock)
+                       memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
+               ddssize += 128;
+       }
+
+       force_swdecode = false;
+       if(bytesperblock)
+       {
+               if(vid.support.ext_texture_compression_s3tc)
+               {
+                       if(r_texture_dds_swdecode.integer > 1)
+                               force_swdecode = true;
+               }
+               else
+               {
+                       if(r_texture_dds_swdecode.integer < 1)
+                       {
+                               // unsupported
+                               Mem_Free(dds);
+                               return NULL;
+                       }
+                       force_swdecode = true;
+               }
+       }
+
        // return whether this texture is transparent
        if (hasalphaflag)
                *hasalphaflag = (flags & TEXF_ALPHA) != 0;
 
+       // if we SW decode, choose 2 sizes bigger
+       if(force_swdecode)
+       {
+               // this is quarter res, so do not scale down more than we have to
+               miplevel -= 2;
+
+               if(miplevel < 0)
+                       Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
+       }
+
+       // this is where we apply gl_picmip
+       mippixels_start = ddspixels;
+       mipwidth = dds_width;
+       mipheight = dds_height;
+       while(miplevel >= 1 && dds_miplevels >= 1)
+       {
+               if (mipwidth <= 1 && mipheight <= 1)
+                       break;
+               mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
+               mippixels_start += mipsize; // just skip
+               --dds_miplevels;
+               --miplevel;
+               if (mipwidth > 1)
+                       mipwidth >>= 1;
+               if (mipheight > 1)
+                       mipheight >>= 1;
+       }
+       mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
+       mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
+
+       // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
+
+       // fake decode S3TC if needed
+       if(force_swdecode)
+       {
+               int mipsize_new = mipsize_total / bytesperblock * 4;
+               unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
+               unsigned char *p = mipnewpixels;
+               for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
+               {
+                       c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
+                       p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
+                       p[1] = (((c >>  5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
+                       p[0] = (((c      ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
+                       if(textype == TEXTYPE_DXT5)
+                               p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
+                       else if(textype == TEXTYPE_DXT3)
+                               p[3] = (
+                                         (mippixels_start[i-8] & 0x0F)
+                                       + (mippixels_start[i-8] >> 4)
+                                       + (mippixels_start[i-7] & 0x0F)
+                                       + (mippixels_start[i-7] >> 4)
+                                       + (mippixels_start[i-6] & 0x0F)
+                                       + (mippixels_start[i-6] >> 4)
+                                       + (mippixels_start[i-5] & 0x0F)
+                                       + (mippixels_start[i-5] >> 4)
+                                      ) * (0.125f / 15.0f * 255.0f);
+                       else
+                               p[3] = 255;
+               }
+
+               textype = TEXTYPE_BGRA;
+               bytesperblock = 0;
+               bytesperpixel = 4;
+
+               // as each block becomes a pixel, we must use pixel count for this
+               mipwidth = (mipwidth + 3) / 4;
+               mipheight = (mipheight + 3) / 4;
+               mipsize = bytesperpixel * mipwidth * mipheight;
+               mippixels_start = mipnewpixels;
+               mipsize_total = mipsize_new;
+       }
+
+       // start mip counting
+       mippixels = mippixels_start;
+
        // calculate average color if requested
        if (avgcolor)
        {
@@ -1846,29 +1990,44 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                Vector4Clear(avgcolor);
                if (bytesperblock)
                {
-                       for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
+                       for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
                        {
-                               c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
+                               c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3];
                                avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
                                avgcolor[1] += ((c >>  5) & 0x3F) + ((c >> 21) & 0x3F);
                                avgcolor[2] += ((c      ) & 0x1F) + ((c >> 16) & 0x1F);
+                               if(textype == TEXTYPE_DXT5)
+                                       avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f);
+                               else if(textype == TEXTYPE_DXT3)
+                                       avgcolor[3] += (
+                                                 (mippixels_start[i-8] & 0x0F)
+                                               + (mippixels_start[i-8] >> 4)
+                                               + (mippixels_start[i-7] & 0x0F)
+                                               + (mippixels_start[i-7] >> 4)
+                                               + (mippixels_start[i-6] & 0x0F)
+                                               + (mippixels_start[i-6] >> 4)
+                                               + (mippixels_start[i-5] & 0x0F)
+                                               + (mippixels_start[i-5] >> 4)
+                                              ) * (0.125f / 15.0f);
+                               else
+                                       avgcolor[3] += 1.0f;
                        }
-                       f = (float)bytesperblock / size;
+                       f = (float)bytesperblock / mipsize;
                        avgcolor[0] *= (0.5f / 31.0f) * f;
                        avgcolor[1] *= (0.5f / 63.0f) * f;
                        avgcolor[2] *= (0.5f / 31.0f) * f;
-                       avgcolor[3] = 1; // too hard to calculate
+                       avgcolor[3] *= f;
                }
                else
                {
-                       for (i = 0;i < size;i += 4)
+                       for (i = 0;i < mipsize;i += 4)
                        {
-                               avgcolor[0] += ddspixels[i+2];
-                               avgcolor[1] += ddspixels[i+1];
-                               avgcolor[2] += ddspixels[i];
-                               avgcolor[3] += ddspixels[i+3];
+                               avgcolor[0] += mippixels[i+2];
+                               avgcolor[1] += mippixels[i+1];
+                               avgcolor[2] += mippixels[i];
+                               avgcolor[3] += mippixels[i+3];
                        }
-                       f = (1.0f / 255.0f) * bytesperpixel / size;
+                       f = (1.0f / 255.0f) * bytesperpixel / mipsize;
                        avgcolor[0] *= f;
                        avgcolor[1] *= f;
                        avgcolor[2] *= f;
@@ -1876,37 +2035,110 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                }
        }
 
-       // this is where we apply gl_picmip
-       mippixels = ddspixels;
-       mipwidth = dds_width;
-       mipheight = dds_height;
-       while(miplevel >= 1 && dds_miplevels >= 1)
+       // if we want sRGB, convert now
+       if(srgb)
        {
-               if (mipwidth <= 1 && mipheight <= 1)
-                       break;
-               mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
-               mippixels += mipsize; // just skip
-               --dds_miplevels;
-               --miplevel;
-               if (mipwidth > 1)
-                       mipwidth >>= 1;
-               if (mipheight > 1)
-                       mipheight >>= 1;
+               if (vid.support.ext_texture_srgb)
+               {
+                       switch(textype)
+                       {
+                       case TEXTYPE_DXT1:    textype = TEXTYPE_SRGB_DXT1   ;break;
+                       case TEXTYPE_DXT1A:   textype = TEXTYPE_SRGB_DXT1A  ;break;
+                       case TEXTYPE_DXT3:    textype = TEXTYPE_SRGB_DXT3   ;break;
+                       case TEXTYPE_DXT5:    textype = TEXTYPE_SRGB_DXT5   ;break;
+                       case TEXTYPE_RGBA:    textype = TEXTYPE_SRGB_RGBA   ;break;
+                       default:
+                               break;
+                       }
+               }
+               else
+               {
+                       switch(textype)
+                       {
+                       case TEXTYPE_DXT1:
+                       case TEXTYPE_DXT1A:
+                       case TEXTYPE_DXT3:
+                       case TEXTYPE_DXT5:
+                               {
+                                       for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
+                                       {
+                                               int c0, c1, c0new, c1new;
+                                               c0 = mippixels_start[i] + 256*mippixels_start[i+1];
+                                               r = ((c0 >> 11) & 0x1F);
+                                               g = ((c0 >>  5) & 0x3F);
+                                               b = ((c0      ) & 0x1F);
+                                               r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
+                                               g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
+                                               b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
+                                               c0new = (r << 11) | (g << 5) | b;
+                                               c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
+                                               r = ((c1 >> 11) & 0x1F);
+                                               g = ((c1 >>  5) & 0x3F);
+                                               b = ((c1      ) & 0x1F);
+                                               r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
+                                               g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
+                                               b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
+                                               c1new = (r << 11) | (g << 5) | b;
+                                               // swap the colors if needed to fix order
+                                               if(c0 > c1) // thirds
+                                               {
+                                                       if(c0new < c1new)
+                                                       {
+                                                               c = c0new;
+                                                               c0new = c1new;
+                                                               c1new = c;
+                                                               if(c0new == c1new)
+                                                               mippixels_start[i+4] ^= 0x55;
+                                                               mippixels_start[i+5] ^= 0x55;
+                                                               mippixels_start[i+6] ^= 0x55;
+                                                               mippixels_start[i+7] ^= 0x55;
+                                                       }
+                                                       else if(c0new == c1new)
+                                                       {
+                                                               mippixels_start[i+4] = 0x00;
+                                                               mippixels_start[i+5] = 0x00;
+                                                               mippixels_start[i+6] = 0x00;
+                                                               mippixels_start[i+7] = 0x00;
+                                                       }
+                                               }
+                                               else // half + transparent
+                                               {
+                                                       if(c0new > c1new)
+                                                       {
+                                                               c = c0new;
+                                                               c0new = c1new;
+                                                               c1new = c;
+                                                               mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
+                                                               mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
+                                                               mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
+                                                               mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
+                                                       }
+                                               }
+                                               mippixels_start[i] = c0new & 255;
+                                               mippixels_start[i+1] = c0new >> 8;
+                                               mippixels_start[i+2] = c1new & 255;
+                                               mippixels_start[i+3] = c1new >> 8;
+                                       }
+                               }
+                               break;
+                       case TEXTYPE_RGBA:
+                               Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
+                               break;
+                       default:
+                               break;
+                       }
+               }
        }
 
-       if (dds_miplevels > 1)
+       // when not requesting mipmaps, do not load them
+       if(!(flags & TEXF_MIPMAP))
+               dds_miplevels = 0;
+
+       if (dds_miplevels >= 1)
                flags |= TEXF_MIPMAP;
        else
                flags &= ~TEXF_MIPMAP;
 
-       // if S3TC is not supported, there's very little we can do about it
-       if (bytesperblock && !vid.support.ext_texture_compression_s3tc)
-       {
-               Mem_Free(dds);
-               Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename);
-               return NULL;
-       }
-
        texinfo = R_GetTexTypeInfo(textype, flags);
 
        glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray);
@@ -1938,42 +2170,14 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
        // create the texture object
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL11:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
+       case RENDERPATH_GL32:
+       case RENDERPATH_GLES2:
                CHECKGLERROR
                GL_ActiveTexture(0);
                oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
                qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
                qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
                break;
-       case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
-               {
-                       D3DFORMAT d3dformat;
-                       D3DPOOL d3dpool;
-                       DWORD d3dusage;
-                       switch(textype)
-                       {
-                       case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
-                       case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break;
-                       case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break;
-                       case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break;
-                       default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break;
-                       }
-                       d3dusage = 0;
-                       d3dpool = D3DPOOL_MANAGED;
-                       IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL);
-               }
-#endif
-               break;
-       case RENDERPATH_D3D10:
-               Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-               break;
-       case RENDERPATH_D3D11:
-               Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-               break;
        }
 
        // upload the texture
@@ -1982,44 +2186,28 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
 
        for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
        {
+               unsigned char *upload_mippixels = mippixels;
+               int upload_mipwidth = mipwidth;
+               int upload_mipheight = mipheight;
                mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
-               if (mippixels + mipsize > dds + ddssize)
+               if (mippixels + mipsize > mippixels_start + mipsize_total)
                        break;
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL11:
-               case RENDERPATH_GL13:
-               case RENDERPATH_GL20:
-               case RENDERPATH_CGGL:
+               case RENDERPATH_GL32:
+               case RENDERPATH_GLES2:
                        if (bytesperblock)
                        {
-                               qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
+                               qglCompressedTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR
                        }
                        else
                        {
-                               qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR
+                               qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR
                        }
                        break;
-               case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
-                       {
-                               D3DLOCKED_RECT d3dlockedrect;
-                               if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
-                               {
-                                       memcpy(d3dlockedrect.pBits, mippixels, mipsize);
-                                       IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
-                               }
-                               break;
-                       }
-#endif
-                       break;
-               case RENDERPATH_D3D10:
-                       Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-                       break;
-               case RENDERPATH_D3D11:
-                       Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-                       break;
                }
+               if(upload_mippixels != mippixels)
+                       Mem_Free(upload_mippixels);
                mippixels += mipsize;
                if (mipwidth <= 1 && mipheight <= 1)
                {
@@ -2035,61 +2223,23 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
        // after upload we have to set some parameters...
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL11:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
+       case RENDERPATH_GL32:
+       case RENDERPATH_GLES2:
+#ifdef GL_TEXTURE_MAX_LEVEL
                if (dds_miplevels >= 1 && !mipcomplete)
                {
                        // need to set GL_TEXTURE_MAX_LEVEL
                        qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
                }
+#endif
                GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
                qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
                break;
-       case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
-               glt->d3daddressw = 0;
-               if (glt->flags & TEXF_CLAMP)
-               {
-                       glt->d3daddressu = D3DTADDRESS_CLAMP;
-                       glt->d3daddressv = D3DTADDRESS_CLAMP;
-                       if (glt->tiledepth > 1)
-                               glt->d3daddressw = D3DTADDRESS_CLAMP;
-               }
-               else
-               {
-                       glt->d3daddressu = D3DTADDRESS_WRAP;
-                       glt->d3daddressv = D3DTADDRESS_WRAP;
-                       if (glt->tiledepth > 1)
-                               glt->d3daddressw = D3DTADDRESS_WRAP;
-               }
-               glt->d3dmipmaplodbias = 0;
-               glt->d3dmaxmiplevel = 0;
-               glt->d3dmaxmiplevelfilter = 0;
-               if (glt->flags & TEXF_MIPMAP)
-               {
-                       glt->d3dminfilter = d3d_filter_mipmin;
-                       glt->d3dmagfilter = d3d_filter_mipmag;
-                       glt->d3dmipfilter = d3d_filter_mipmix;
-               }
-               else
-               {
-                       glt->d3dminfilter = d3d_filter_flatmin;
-                       glt->d3dmagfilter = d3d_filter_flatmag;
-                       glt->d3dmipfilter = d3d_filter_flatmix;
-               }
-#endif
-               break;
-       case RENDERPATH_D3D10:
-               Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-               break;
-       case RENDERPATH_D3D11:
-               Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-               break;
        }
 
        Mem_Free(dds);
+       if(force_swdecode)
+               Mem_Free((unsigned char *) mippixels_start);
        return (rtexture_t *)glt;
 }
 
@@ -2103,16 +2253,21 @@ int R_TextureHeight(rtexture_t *rt)
        return rt ? ((gltexture_t *)rt)->inputheight : 0;
 }
 
-void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
+int R_TextureFlags(rtexture_t *rt)
+{
+       return rt ? ((gltexture_t *)rt)->flags : 0;
+}
+
+void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
 {
        gltexture_t *glt = (gltexture_t *)rt;
        if (data == NULL)
                Host_Error("R_UpdateTexture: no data supplied");
        if (glt == NULL)
                Host_Error("R_UpdateTexture: no texture supplied");
-       if (!glt->texnum && !glt->d3dtexture)
+       if (!glt->texnum)
        {
-               Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", glt, glt->identifier, glt->pool);
+               Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
                return;
        }
        // update part of the texture
@@ -2124,6 +2279,8 @@ void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, in
                int outputskip = glt->tilewidth*bpp;
                const unsigned char *input = data;
                unsigned char *output = glt->bufferpixels;
+               if (glt->inputdepth != 1 || glt->sides != 1)
+                       Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
                if (x < 0)
                {
                        width += x;
@@ -2148,8 +2305,10 @@ void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, in
                for (j = 0;j < height;j++, output += outputskip, input += inputskip)
                        memcpy(output, input, width*bpp);
        }
+       else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
+               R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
        else
-               R_Upload(glt, data, x, y, 0, width, height, 1);
+               R_UploadFullTexture(glt, data);
 }
 
 int R_RealGetTexture(rtexture_t *rt)
@@ -2163,20 +2322,20 @@ int R_RealGetTexture(rtexture_t *rt)
                if (glt->buffermodified && glt->bufferpixels)
                {
                        glt->buffermodified = false;
-                       R_Upload(glt, glt->bufferpixels, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth);
+                       R_UploadFullTexture(glt, glt->bufferpixels);
                }
                glt->dirty = false;
                return glt->texnum;
        }
        else
-               return 0;
+               return r_texture_white->texnum;
 }
 
 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 );
+       R_UploadFullTexture(glt, NULL);
 }
 
 int R_PicmipForFlags(int flags)
@@ -2202,5 +2361,5 @@ int R_PicmipForFlags(int flags)
                else
                        miplevel += gl_picmip_other.integer;
        }
-       return miplevel;
+       return max(0, miplevel);
 }