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;
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};
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 };
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};
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:
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,
// 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)
{
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;
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;
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 );
}
}
{
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);
{
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);
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...
colorconvertbuffer = NULL;
}
+#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
if (old_aniso != gl_texture_anisotropy.integer)
{
gltexture_t *glt;
break;
}
}
+#endif
}
static void R_MakeResizeBufferBigger(int size)
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);
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
qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
}
+#ifdef GL_TEXTURE_COMPARE_MODE_ARB
switch(textype)
{
case TEXTYPE_SHADOWMAP16_COMP:
default:
break;
}
+#endif
CHECKGLERROR
}
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;
}
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;
}
{
// 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];
// 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;
}
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)
{
qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
CHECKGLERROR
}
+#endif
#endif
switch(glt->texturetype)
{
{
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
{
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
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;
}
{
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
{
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)
{
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)
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;
}
{
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)
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;
}
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:
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);
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];
+ 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);
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++)
{
#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;
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
}
}
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;
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);
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:
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:
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;
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)
{