]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_textures.c
Configure all of the CL_MeshEntities* meshes the same, the material flags decide...
[xonotic/darkplaces.git] / gl_textures.c
index 37c135edc45807fd14b62908a691e65ae55fe7c4..14685e7949e1fe87a5b4fec166c3749f26bf6812 100644 (file)
@@ -38,7 +38,7 @@ cvar_t gl_texturecompression_reflectmask = {CVAR_SAVE, "gl_texturecompression_re
 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"};
+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;
@@ -81,6 +81,11 @@ typedef struct textypeinfo_s
 textypeinfo_t;
 
 #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};
@@ -91,8 +96,8 @@ static textypeinfo_t textype_depth16                     = {"depth16",
 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};
+static textypeinfo_t textype_colorbuffer16f              = {"colorbuffer16f",           TEXTYPE_COLORBUFFER16F       ,  2,  2,  2.0f, GL_RGBA16F                        , GL_RGBA           , GL_HALF_FLOAT_ARB};
+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 };
@@ -102,6 +107,9 @@ static textypeinfo_t textype_rgba                        = {"rgba",
 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_ARB          , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
@@ -112,7 +120,7 @@ static textypeinfo_t textype_depth16                     = {"depth16",
 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_colorbuffer16f              = {"colorbuffer16f",           TEXTYPE_COLORBUFFER16F       ,  8,  8,  8.0f, GL_RGBA16F_ARB                        , GL_RGBA           , GL_HALF_FLOAT_ARB};
 static textypeinfo_t textype_colorbuffer32f              = {"colorbuffer32f",           TEXTYPE_COLORBUFFER32F       , 16, 16, 16.0f, GL_RGBA32F_ARB                        , GL_RGBA           , GL_FLOAT         };
 
 // image formats:
@@ -157,7 +165,9 @@ typedef enum gltexturetype_e
 gltexturetype_t;
 
 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,
@@ -175,6 +185,7 @@ typedef struct gltexture_s
        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;
@@ -198,7 +209,7 @@ typedef struct gltexture_s
 
        // 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)
@@ -267,6 +278,25 @@ static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
 {
        switch(textype)
        {
+#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;
@@ -292,6 +322,7 @@ static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
        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");
                break;
@@ -322,13 +353,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 );
        }
 }
 
@@ -370,7 +401,7 @@ void R_FreeTexture(rtexture_t *rt)
                if (glt->renderbuffernum)
                {
                        CHECKGLERROR
-                       qglDeleteRenderbuffersEXT(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
+                       qglDeleteRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
                }
                break;
        case RENDERPATH_D3D9:
@@ -824,7 +855,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);
@@ -868,7 +899,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);
@@ -963,7 +994,9 @@ void R_Textures_Init (void)
 
 void R_Textures_Frame (void)
 {
+#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
        static int old_aniso = 0;
+#endif
 
        // could do procedural texture animation here, if we keep track of which
        // textures were accessed this frame...
@@ -981,6 +1014,7 @@ void R_Textures_Frame (void)
                colorconvertbuffer = NULL;
        }
 
+#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
        if (old_aniso != gl_texture_anisotropy.integer)
        {
                gltexture_t *glt;
@@ -1024,6 +1058,7 @@ void R_Textures_Frame (void)
                        break;
                }
        }
+#endif
 }
 
 static void R_MakeResizeBufferBigger(int size)
@@ -1049,6 +1084,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);
@@ -1056,6 +1092,7 @@ 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
@@ -1110,6 +1147,7 @@ static void GL_SetupTextureParameters(int flags, textype_t textype, int texturet
                qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
        }
 
+#ifdef GL_TEXTURE_COMPARE_MODE_ARB
        switch(textype)
        {
        case TEXTYPE_SHADOWMAP16_COMP:
@@ -1127,6 +1165,7 @@ static void GL_SetupTextureParameters(int flags, textype_t textype, int texturet
        default:
                break;
        }
+#endif
 
        CHECKGLERROR
 }
@@ -1217,13 +1256,13 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
        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);
-       R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
 
        if (prevbuffer == NULL)
        {
                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;
        }
@@ -1232,6 +1271,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                if (glt->textype->textype == TEXTYPE_PALETTE)
                {
                        // 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;
                }
@@ -1239,6 +1279,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                {
                        // 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)
                        {
                                alpha = prevbuffer[i+3];
@@ -1252,12 +1293,14 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                // scale up to a power of 2 size (if appropriate)
                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;
                }
                // 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;
                }
@@ -1280,6 +1323,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                        oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
                        qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
 
+#ifndef USE_GLES2
 #ifdef GL_TEXTURE_COMPRESSION_HINT_ARB
                        if (qglGetCompressedTexImageARB)
                        {
@@ -1289,6 +1333,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                                        qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
                                CHECKGLERROR
                        }
+#endif
 #endif
                        switch(glt->texturetype)
                        {
@@ -1298,6 +1343,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                                {
                                        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
@@ -1311,6 +1357,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                                {
                                        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
@@ -1328,12 +1375,14 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                                        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;
                                        }
@@ -1343,6 +1392,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                                        {
                                                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
@@ -1377,6 +1427,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                                {
                                        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;
                                                if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
@@ -1400,6 +1451,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                                {
                                        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;
                                                if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
@@ -1422,12 +1474,14 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                                        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;
                                        }
@@ -1442,6 +1496,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                                        {
                                                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;
                                                        if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
@@ -1529,12 +1584,14 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                                        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;
                                        }
@@ -1623,7 +1680,7 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
                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_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:
@@ -1758,10 +1815,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);
 
@@ -1929,10 +1987,11 @@ rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *
        glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
        glt->texnum = 0;
        glt->dirty = false;
-       glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype];
+       glt->glisdepthstencil = textype == TEXTYPE_DEPTHBUFFER24STENCIL8;
+       glt->gltexturetypeenum = GL_TEXTURE_2D;
        // 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);
 
@@ -1946,11 +2005,11 @@ rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *
        case RENDERPATH_GLES1:
        case RENDERPATH_GLES2:
                CHECKGLERROR
-               qglGenRenderbuffersEXT(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
-               qglBindRenderbufferEXT(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR
-               qglRenderbufferStorageEXT(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);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
-               qglBindRenderbufferEXT(GL_RENDERBUFFER, 0);CHECKGLERROR
+               qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR
                break;
        case RENDERPATH_D3D9:
 #ifdef SUPPORTD3D
@@ -2066,7 +2125,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) && !(glt->tilewidth == 1 && glt->tilewidth == 1))
+       if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1))
        {
                for (mip = 1;mip < 16;mip++)
                {
@@ -2145,7 +2204,12 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco
 #endif
 }
 
-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
+#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;
@@ -2164,17 +2228,161 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
        unsigned char *dds;
        fs_offset_t ddsfilesize;
        unsigned int ddssize;
-       qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
+       qboolean force_swdecode, npothack;
+#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)
        {
-               if(r_texture_dds_load_logfailure.integer)
+               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
        }
@@ -2238,9 +2446,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)
@@ -2257,6 +2465,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;
@@ -2339,9 +2549,17 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
        }
 
        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;
@@ -2452,7 +2670,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)
@@ -2463,11 +2681,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;
@@ -2482,7 +2700,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;
@@ -2619,6 +2837,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);
 
@@ -2673,9 +2897,25 @@ 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);
+                       if(upload_mipwidth != mipwidth || upload_mipheight != mipheight)
+                       // I _think_ they always mismatch, but I was too lazy
+                       // to properly check, and this test here is really
+                       // harmless
+                       {
+                               upload_mippixels = (unsigned char *) 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:
@@ -2685,11 +2925,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:
@@ -2698,7 +2938,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;
@@ -2715,11 +2955,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)
                {