]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_textures.c
properly handle !vid.support.arb_texture_non_power_of_two in DDS upload (fixes segfau...
[xonotic/darkplaces.git] / gl_textures.c
index 180447ff6f74856896a0782ba4f816ad24ea721f..8dc1cae614acd384bfc5e48c9f53fc7a72008f17 100644 (file)
@@ -83,11 +83,16 @@ textypeinfo_t;
 #ifdef USE_GLES2
 // framebuffer texture formats
 // GLES2 devices rarely support depth textures, so we actually use a renderbuffer there
-static textypeinfo_t textype_shadowmap16                 = {"shadowmap16",              TEXTYPE_SHADOWMAP     ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16                  , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
-static textypeinfo_t textype_shadowmap24                 = {"shadowmap24",              TEXTYPE_SHADOWMAP     ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16                  , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
-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_RGBA                               , GL_RGBA           , GL_FLOAT         };
-static textypeinfo_t textype_colorbuffer32f              = {"colorbuffer32f",           TEXTYPE_COLORBUFFER32F, 16, 16, 16.0f, GL_RGBA                               , GL_RGBA           , GL_FLOAT         };
+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_RGB565                         , GL_RGBA           , GL_UNSIGNED_SHORT_5_6_5};
+static textypeinfo_t textype_colorbuffer32f              = {"colorbuffer32f",           TEXTYPE_COLORBUFFER32F       ,  2,  2,  2.0f, GL_RGB565                         , GL_RGBA           , GL_UNSIGNED_SHORT_5_6_5};
 
 // image formats:
 static textypeinfo_t textype_alpha                       = {"alpha",                    TEXTYPE_ALPHA         ,  1,  4,  4.0f, GL_ALPHA                              , GL_ALPHA          , GL_UNSIGNED_BYTE };
@@ -99,11 +104,16 @@ static textypeinfo_t textype_bgra                        = {"bgra",
 static textypeinfo_t textype_bgra_alpha                  = {"bgra_alpha",               TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
 #else
 // framebuffer texture formats
-static textypeinfo_t textype_shadowmap16                 = {"shadowmap16",              TEXTYPE_SHADOWMAP     ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16_ARB              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
-static textypeinfo_t textype_shadowmap24                 = {"shadowmap24",              TEXTYPE_SHADOWMAP     ,  4,  4,  4.0f, GL_DEPTH_COMPONENT24_ARB              , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
-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_ARB                        , GL_RGBA           , GL_FLOAT         };
-static textypeinfo_t textype_colorbuffer32f              = {"colorbuffer32f",           TEXTYPE_COLORBUFFER32F, 16, 16, 16.0f, GL_RGBA32F_ARB                        , GL_RGBA           , GL_FLOAT         };
+static textypeinfo_t textype_shadowmap16_comp            = {"shadowmap16_comp",         TEXTYPE_SHADOWMAP16_COMP     ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16_ARB          , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_shadowmap16_raw             = {"shadowmap16_raw",          TEXTYPE_SHADOWMAP16_RAW      ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16_ARB          , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_shadowmap24_comp            = {"shadowmap24_comp",         TEXTYPE_SHADOWMAP24_COMP     ,  4,  4,  4.0f, GL_DEPTH_COMPONENT24_ARB          , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
+static textypeinfo_t textype_shadowmap24_raw             = {"shadowmap24_raw",          TEXTYPE_SHADOWMAP24_RAW      ,  4,  4,  4.0f, GL_DEPTH_COMPONENT24_ARB          , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
+static textypeinfo_t textype_depth16                     = {"depth16",                  TEXTYPE_DEPTHBUFFER16        ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16_ARB          , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_depth24                     = {"depth24",                  TEXTYPE_DEPTHBUFFER24        ,  4,  4,  4.0f, GL_DEPTH_COMPONENT24_ARB          , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
+static textypeinfo_t textype_depth24stencil8             = {"depth24stencil8",          TEXTYPE_DEPTHBUFFER24STENCIL8,  4,  4,  4.0f, GL_DEPTH24_STENCIL8_EXT           , GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT};
+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_ARB                        , GL_RGBA           , GL_FLOAT         };
+static textypeinfo_t textype_colorbuffer32f              = {"colorbuffer32f",           TEXTYPE_COLORBUFFER32F       , 16, 16, 16.0f, GL_RGBA32F_ARB                        , 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 };
@@ -163,12 +173,16 @@ 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;
+       void *d3dsurface;
 #ifdef SUPPORTD3D
-       qboolean d3disdepthsurface; // for depth/stencil surfaces
+       qboolean d3disrendertargetsurface;
+       qboolean d3disdepthstencilsurface;
        int d3dformat;
        int d3dusage;
        int d3dpool;
@@ -252,22 +266,6 @@ static const unsigned char *texturebuffer;
 
 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
 {
-#ifdef USE_GLES2
-       switch(textype)
-       {
-       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);
-       case TEXTYPE_ALPHA: return &textype_alpha;
-       case TEXTYPE_SHADOWMAP: return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
-       case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
-       case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
-       case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
-       default:
-               Host_Error("R_GetTexTypeInfo: unknown texture format");
-               break;
-       }
-#else
        switch(textype)
        {
        case TEXTYPE_DXT1: return &textype_dxt1;
@@ -278,10 +276,16 @@ static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
        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_SHADOWMAP: return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
        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;
@@ -293,7 +297,6 @@ static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
                Host_Error("R_GetTexTypeInfo: unknown texture format");
                break;
        }
-#endif
        return NULL;
 }
 
@@ -365,11 +368,16 @@ void R_FreeTexture(rtexture_t *rt)
                        CHECKGLERROR
                        qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
                }
+               if (glt->renderbuffernum)
+               {
+                       CHECKGLERROR
+                       qglDeleteRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
+               }
                break;
        case RENDERPATH_D3D9:
 #ifdef SUPPORTD3D
-               if (glt->d3disdepthsurface)
-                       IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
+               if (glt->d3dsurface)
+                       IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dsurface);
                else if (glt->tiledepth > 1)
                        IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
                else if (glt->sides == 6)
@@ -377,6 +385,7 @@ void R_FreeTexture(rtexture_t *rt)
                else
                        IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
                glt->d3dtexture = NULL;
+               glt->d3dsurface = NULL;
 #endif
                break;
        case RENDERPATH_D3D10:
@@ -557,7 +566,7 @@ static void GL_TextureMode_f (void)
                        for (glt = pool->gltchain;glt;glt = glt->chain)
                        {
                                // only update already uploaded images
-                               if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
+                               if (glt->d3dtexture && !glt->d3dsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
                                {
                                        if (glt->flags & TEXF_MIPMAP)
                                        {
@@ -721,7 +730,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 || glt->d3dtexture || glt->d3dsurface;
                        pooltotal++;
                        pooltotalt += glsize;
                        pooltotalp += glt->inputdatasize;
@@ -832,8 +841,8 @@ static void r_textures_devicelost(void)
                        break;
                case RENDERPATH_D3D9:
 #ifdef SUPPORTD3D
-                       if (glt->d3disdepthsurface)
-                               IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
+                       if (glt->d3dsurface)
+                               IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dsurface);
                        else if (glt->tiledepth > 1)
                                IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
                        else if (glt->sides == 6)
@@ -841,6 +850,7 @@ static void r_textures_devicelost(void)
                        else
                                IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
                        glt->d3dtexture = NULL;
+                       glt->d3dsurface = NULL;
 #endif
                        break;
                case RENDERPATH_D3D10:
@@ -877,9 +887,14 @@ static void r_textures_devicerestored(void)
 #ifdef SUPPORTD3D
                        {
                                HRESULT d3dresult;
-                               if (glt->d3disdepthsurface)
+                               if (glt->d3disrendertargetsurface)
+                               {
+                                       if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
+                                               Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!");
+                               }
+                               else if (glt->d3disdepthstencilsurface)
                                {
-                                       if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
+                                       if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
                                                Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
                                }
                                else if (glt->tiledepth > 1)
@@ -1012,7 +1027,7 @@ void R_Textures_Frame (void)
        }
 }
 
-void R_MakeResizeBufferBigger(int size)
+static void R_MakeResizeBufferBigger(int size)
 {
        if (resizebuffersize < size)
        {
@@ -1096,24 +1111,23 @@ static void GL_SetupTextureParameters(int flags, textype_t textype, int texturet
                qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
        }
 
-#ifndef USE_GLES2
-       if (textype == TEXTYPE_SHADOWMAP)
+       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
-               }
+       case TEXTYPE_SHADOWMAP16_COMP:
+       case TEXTYPE_SHADOWMAP24_COMP:
+               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
+               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
                qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
+               break;
+       case TEXTYPE_SHADOWMAP16_RAW:
+       case TEXTYPE_SHADOWMAP24_RAW:
+               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
+               break;
+       default:
+               break;
        }
-#endif
 
        CHECKGLERROR
 }
@@ -1258,90 +1272,93 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
        case RENDERPATH_GL20:
        case RENDERPATH_GLES1:
        case RENDERPATH_GLES2:
-               CHECKGLERROR
+               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
+                       // 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
 
 #ifdef GL_TEXTURE_COMPRESSION_HINT_ARB
-               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
-               }
-#endif
-               switch(glt->texturetype)
-               {
-               case GLTEXTURETYPE_2D:
-                       qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
-                       if (glt->flags & TEXF_MIPMAP)
+                       if (qglGetCompressedTexImageARB)
                        {
-                               while (width > 1 || height > 1 || depth > 1)
-                               {
-                                       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
-                               }
-                       }
-                       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)
-                               {
-                                       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
-                               }
+                               if (gl_texturecompression.integer >= 2)
+                                       qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
+                               else
+                                       qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
+                               CHECKGLERROR
                        }
 #endif
-                       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++)
+                       switch(glt->texturetype)
                        {
-                               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)
+                       case GLTEXTURETYPE_2D:
+                               qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
+                               if (glt->flags & TEXF_MIPMAP)
                                {
-                                       Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
-                                       prevbuffer = resizebuffer;
+                                       while (width > 1 || height > 1 || depth > 1)
+                                       {
+                                               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
+                                       }
                                }
-                               mip = 0;
-                               qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
+                               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)
                                        {
                                                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
+                                               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,
+                               // 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;
+                                       qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
+                                       if (glt->flags & TEXF_MIPMAP)
+                                       {
+                                               while (width > 1 || height > 1 || depth > 1)
+                                               {
+                                                       Image_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
+                                               }
                                        }
                                }
+                               break;
                        }
-                       break;
+                       GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
+                       qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
                }
-               GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
-               qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
                break;
        case RENDERPATH_D3D9:
 #ifdef SUPPORTD3D
-               if (!(glt->flags & TEXF_RENDERTARGET))
+               if (!(glt->flags & TEXF_RENDERTARGET) && glt->d3dtexture && !glt->d3dsurface)
                {
                        D3DLOCKED_RECT d3dlockedrect;
                        D3DLOCKED_BOX d3dlockedbox;
@@ -1620,6 +1637,7 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
                        {
                                temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
                                memcpy(temppixels, data, size);
+                               data = temppixels;
                        }
                        Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
                }
@@ -1685,7 +1703,10 @@ 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:
@@ -1738,6 +1759,7 @@ 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;
@@ -1779,20 +1801,15 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
                        case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
                        case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
                        case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;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;
-                       glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
-                       if (glt->d3disdepthsurface)
-                       {
-                               if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
-                                       Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
-                       }
-                       else if (glt->tiledepth > 1)
+                       glt->d3disrendertargetsurface = false;
+                       glt->d3disdepthstencilsurface = false;
+                       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!");
@@ -1827,7 +1844,13 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
                        case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
                        case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
                        case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
-                       case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
+                       case TEXTYPE_SHADOWMAP16_COMP:
+                       case TEXTYPE_SHADOWMAP16_RAW:
+                       case TEXTYPE_SHADOWMAP24_COMP:
+                       case TEXTYPE_SHADOWMAP24_RAW: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
+                       case TEXTYPE_DEPTHBUFFER16:
+                       case TEXTYPE_DEPTHBUFFER24:
+                       case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
                        case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
                        default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
                        }
@@ -1870,21 +1893,126 @@ 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);
 }
 
-static int R_ShadowMapTextureFlags(int precision, qboolean filter)
+rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter)
 {
-       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;
+       return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL);
 }
 
-rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
+rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
 {
-       return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
+       gltexture_t *glt;
+       gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
+       textypeinfo_t *texinfo;
+
+       if (cls.state == ca_dedicated)
+               return NULL;
+
+       texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP);
+
+       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 = glt->texturetype == TEXTYPE_DEPTHBUFFER24STENCIL8;
+       glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
+       // init the dynamic texture attributes, too [11/22/2007 Black]
+       glt->updatecallback = NULL;
+       glt->updatacallback_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_GL11:
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL20:
+       case RENDERPATH_GLES1:
+       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;
+       case RENDERPATH_D3D9:
+#ifdef SUPPORTD3D
+               {
+                       D3DFORMAT d3dformat;
+                       HRESULT d3dresult;
+                       glt->d3disrendertargetsurface = false;
+                       glt->d3disdepthstencilsurface = false;
+                       switch(textype)
+                       {
+                       case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;glt->d3disrendertargetsurface = true;break;
+                       case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;glt->d3disrendertargetsurface = true;break;
+                       case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;glt->d3disrendertargetsurface = true;break;
+                       case TEXTYPE_DEPTHBUFFER16: d3dformat = D3DFMT_D16;glt->d3disdepthstencilsurface = true;break;
+                       case TEXTYPE_DEPTHBUFFER24: d3dformat = D3DFMT_D24X8;glt->d3disdepthstencilsurface = true;break;
+                       case TEXTYPE_DEPTHBUFFER24STENCIL8: d3dformat = D3DFMT_D24S8;glt->d3disdepthstencilsurface = true;break;
+                       default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking D3DFMT", (int)textype);break;
+                       }
+                       glt->d3dformat = d3dformat;
+                       glt->d3dusage = 0;
+                       glt->d3dpool = 0;
+                       if (glt->d3disrendertargetsurface)
+                       {
+                               if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
+                                       Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!");
+                       }
+                       else if (glt->d3disdepthstencilsurface)
+                       {
+                               if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL)))
+                                       Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface 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;
+       case RENDERPATH_SOFT:
+               {
+                       int tflags = 0;
+                       switch(textype)
+                       {
+                       case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8 | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
+                       case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
+                       case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
+                       case TEXTYPE_DEPTHBUFFER16:
+                       case TEXTYPE_DEPTHBUFFER24:
+                       case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break;
+                       default: Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
+                       }
+                       glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth);
+               }
+               break;
+       }
+
+       return (rtexture_t *)glt;
 }
 
 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
@@ -1941,7 +2069,7 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco
        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->tilewidth == 1))
        {
                for (mip = 1;mip < 16;mip++)
                {
@@ -2020,7 +2148,7 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco
 #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
+rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qboolean srgb, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel) // 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;
@@ -2031,13 +2159,15 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
        gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
        textypeinfo_t *texinfo;
        int mip, mipwidth, mipheight, mipsize, mipsize_total;
-       unsigned int c;
+       unsigned int c, r, g, b;
        GLint oldbindtexnum = 0;
-       const unsigned char *mippixels, *ddspixels, *mippixels_start;
+       unsigned char *mippixels;
+       unsigned char *mippixels_start;
+       unsigned char *ddspixels;
        unsigned char *dds;
        fs_offset_t ddsfilesize;
        unsigned int ddssize;
-       qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
+       qboolean force_swdecode, npothack;
 
        if (cls.state == ca_dedicated)
                return NULL;
@@ -2111,9 +2241,9 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                        Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
                        return NULL;
                }
-               if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
+               if (flags & TEXF_ALPHA)
                {
-                       if(r_texture_dds_load_alphamode.integer == 1)
+                       if (r_texture_dds_load_alphamode.integer == 1)
                        {
                                // check alpha
                                for (i = 0;i < size;i += bytesperblock)
@@ -2130,6 +2260,8 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                                else
                                        flags &= ~TEXF_ALPHA;
                        }
+                       else if (r_texture_dds_load_alphamode.integer == 0)
+                               textype = TEXTYPE_DXT1A;
                        else
                        {
                                flags &= ~TEXF_ALPHA;
@@ -2199,10 +2331,30 @@ 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;
+       npothack = 
+               (!vid.support.arb_texture_non_power_of_two &&
+                       (
+                               (dds_width & (dds_width - 1))
+                               ||
+                               (dds_height & (dds_height - 1))
+                       )
+               );
        if(bytesperblock)
        {
-               if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
+               if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && !npothack)
                {
                        if(r_texture_dds_swdecode.integer > 1)
                                force_swdecode = true;
@@ -2313,7 +2465,7 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                                avgcolor[1] += ((c >>  5) & 0x3F) + ((c >> 21) & 0x3F);
                                avgcolor[2] += ((c      ) & 0x1F) + ((c >> 16) & 0x1F);
                                if(textype == TEXTYPE_DXT5)
-                                       avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
+                                       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)
@@ -2324,11 +2476,11 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                                                + (mippixels_start[i-6] >> 4)
                                                + (mippixels_start[i-5] & 0x0F)
                                                + (mippixels_start[i-5] >> 4)
-                                              ) * (0.125f / 15.0f * 255.0f);
+                                              ) * (0.125f / 15.0f);
                                else
-                                       avgcolor[3] += 255;
+                                       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;
@@ -2343,7 +2495,7 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                                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;
@@ -2351,6 +2503,101 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                }
        }
 
+       // if we want sRGB, convert now
+       if(srgb)
+       {
+               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;
+                       }
+               }
+       }
+
        // when not requesting mipmaps, do not load them
        if(!(flags & TEXF_MIPMAP))
                dds_miplevels = 0;
@@ -2385,6 +2632,12 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
        glt->tiledepth = 1;
        glt->miplevels = dds_miplevels;
 
+       if(npothack)
+       {
+               for (glt->tilewidth = 1;glt->tilewidth < mipwidth;glt->tilewidth <<= 1);
+               for (glt->tileheight = 1;glt->tileheight < mipheight;glt->tileheight <<= 1);
+       }
+
        // texture uploading can take a while, so make sure we're sending keepalives
        CL_KeepaliveMessage(false);
 
@@ -2439,9 +2692,19 @@ 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 > mippixels_start + mipsize_total)
                        break;
+               if(npothack)
+               {
+                       upload_mipwidth = (glt->tilewidth >> mip);
+                       upload_mipheight = (glt->tileheight >> mip);
+                       upload_mippixels = Mem_Alloc(tempmempool, 4 * upload_mipwidth * upload_mipheight);
+                       Image_Resample32(mippixels, mipwidth, mipheight, 1, upload_mippixels, upload_mipwidth, upload_mipheight, 1, r_lerpimages.integer);
+               }
                switch(vid.renderpath)
                {
                case RENDERPATH_GL11:
@@ -2451,11 +2714,11 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                case RENDERPATH_GLES2:
                        if (bytesperblock)
                        {
-                               qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR
+                               qglCompressedTexImage2DARB(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:
@@ -2464,7 +2727,7 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                                D3DLOCKED_RECT d3dlockedrect;
                                if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
                                {
-                                       memcpy(d3dlockedrect.pBits, mippixels, mipsize);
+                                       memcpy(d3dlockedrect.pBits, upload_mippixels, mipsize);
                                        IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
                                }
                                break;
@@ -2481,11 +2744,13 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                        if (bytesperblock)
                                Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
                        else
-                               DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels);
+                               DPSOFTRAST_Texture_UpdateFull(glt->texnum, upload_mippixels);
                        // DPSOFTRAST calculates its own mipmaps
                        mip = dds_miplevels;
                        break;
                }
+               if(upload_mippixels != mippixels)
+                       Mem_Free(upload_mippixels);
                mippixels += mipsize;
                if (mipwidth <= 1 && mipheight <= 1)
                {