コード例 #1
0
ファイル: DDSLoader.cpp プロジェクト: souxiaosou/aether3d
DDSLoader::LoadResult DDSLoader::Load( const char* path, int cubeMapFace, int& outWidth, int& outHeight, bool& outOpaque )
{
    assert( cubeMapFace >= 0 && cubeMapFace < 7 );

    DDSHeader hdr;
    unsigned x = 0;
    unsigned y = 0;
    int mipMapCount = 0;
    std::ifstream ifs( path, std::ios::binary );

    if (!ifs)
    {
        outWidth = 512;
        outHeight = 512;
        return LoadResult::FileNotFound;
    }

    ifs.read((char*) &hdr, sizeof( hdr ) );
    assert( hdr.sHeader.dwMagic == DDS_MAGIC );
    assert( hdr.sHeader.dwSize == 124 );

    if (!(hdr.sHeader.dwFlags & DDSD_PIXELFORMAT) ||
            !(hdr.sHeader.dwFlags & DDSD_CAPS) )
    {
        std::cerr << "Error! Texture " << path << " doesn't have pixelformat or caps." << std::endl;
        outWidth    = 32;
        outHeight   = 32;
        outOpaque = true;
        return LoadResult::UnknownPixelFormat;
    }

    const uint32_t xSize = hdr.sHeader.dwWidth;
    const uint32_t ySize = hdr.sHeader.dwHeight;
    assert( !( xSize & (xSize - 1) ) );
    assert( !( ySize & (ySize - 1) ) );

    outWidth  = xSize;
    outHeight = ySize;
    DDSInfo* li = nullptr;

    if (PF_IS_DXT1( hdr.sHeader.sPixelFormat ))
    {
        li = &loadInfoDXT1;
        outOpaque = true;
    }
    else if (PF_IS_DXT3( hdr.sHeader.sPixelFormat ))
    {
        li = &loadInfoDXT3;
        outOpaque = false;
    }
    else if (PF_IS_DXT5( hdr.sHeader.sPixelFormat ))
    {
        li = &loadInfoDXT5;
        outOpaque = false;
    }
    else if (PF_IS_BGRA8( hdr.sHeader.sPixelFormat ))
    {
        li = &loadInfoBGRA8;
        outOpaque = false;
    }
    else if (PF_IS_BGR8( hdr.sHeader.sPixelFormat ))
    {
        li = &loadInfoBGR8;
        outOpaque = true;
    }
    else if (PF_IS_BGR5A1( hdr.sHeader.sPixelFormat ))
    {
        li = &loadInfoBGR5A1;
        outOpaque = false;
    }
    else if (PF_IS_BGR565( hdr.sHeader.sPixelFormat ))
    {
        li = &loadInfoBGR565;
        outOpaque = true;
    }
    else if (PF_IS_INDEX8( hdr.sHeader.sPixelFormat ))
    {
        li = &loadInfoIndex8;
        outOpaque = true;
    }
    else
    {
        std::cerr << "Error! Texture " << path << " has unknown pixel format." << std::endl;
        outWidth    = 32;
        outHeight   = 32;
        outOpaque = true;
        return LoadResult::UnknownPixelFormat;
    }

    x = xSize;
    y = ySize;
    std::size_t size;
    mipMapCount = (hdr.sHeader.dwFlags & DDSD_MIPMAPCOUNT) ? hdr.sHeader.dwMipMapCount : 1;

    if (mipMapCount == 0)
    {
        glTexParameteri( cubeMapFace > 0 ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    }

    if (li->isCompressed)
    {
        size = max( li->divSize, x ) / li->divSize * max( li->divSize, y ) / li->divSize * li->blockBytes;
        assert( size == hdr.sHeader.dwPitchOrLinearSize );
        assert( hdr.sHeader.dwFlags & DDSD_LINEARSIZE );

        std::vector< unsigned char > data( size );

        if (data.empty())
        {
            std::cerr << "Error loading texture " << path << std::endl;
            outWidth    = 32;
            outHeight   = 32;
            outOpaque = true;
            return LoadResult::FileNotFound;
        }

        for (int ix = 0; ix < mipMapCount; ++ix)
        {
            ifs.read( (char*) &data[0], size );
            glCompressedTexImage2D( cubeMapFace > 0 ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubeMapFace - 1 : GL_TEXTURE_2D, ix, li->internalFormat, x, y, 0, (GLsizei)size, &data[0] );
            x = (x + 1) >> 1;
            y = (y + 1) >> 1;
            size = max( li->divSize, x ) / li->divSize * max( li->divSize, y ) / li->divSize * li->blockBytes;
        }
    }
コード例 #2
0
ファイル: texture.c プロジェクト: marioux/Corange
texture* dds_load_file( char* filename ) {

	DdsLoadInfo loadInfoDXT1 =   { true,  false, false, 4, 8,  GL_COMPRESSED_RGBA_S3TC_DXT1 };
	DdsLoadInfo loadInfoDXT3 =   { true,  false, false, 4, 16, GL_COMPRESSED_RGBA_S3TC_DXT3 };
	DdsLoadInfo loadInfoDXT5 =   { true,  false, false, 4, 16, GL_COMPRESSED_RGBA_S3TC_DXT5 };
	DdsLoadInfo loadInfoBGRA8 =  { false, false, false, 1, 4,  GL_RGBA8,   GL_BGRA, GL_UNSIGNED_BYTE };
	DdsLoadInfo loadInfoBGR8 =   { false, false, false, 1, 3,  GL_RGB8,    GL_BGR,  GL_UNSIGNED_BYTE };
	DdsLoadInfo loadInfoBGR5A1 = { false, true,  false, 1, 2,  GL_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV };
	DdsLoadInfo loadInfoBGR565 = { false, true,  false, 1, 2,  GL_RGB5,    GL_RGB,  GL_UNSIGNED_SHORT_5_6_5 };
	DdsLoadInfo loadInfoIndex8 = { false, false, true,  1, 1,  GL_RGB8,    GL_BGRA, GL_UNSIGNED_BYTE };

	SDL_RWops* f = SDL_RWFromFile(filename, "rb");

	if (f == NULL) {
		error("Cannot load file %s", filename);
	}

	DDS_header hdr;
	SDL_RWread(f, &hdr, 1, sizeof(DDS_header));

	if( hdr.dwMagic != DDS_MAGIC || hdr.dwSize != 124 ||
			!(hdr.dwFlags & DDSD_PIXELFORMAT) || !(hdr.dwFlags & DDSD_CAPS) ) {
		error("Cannot Load File %s: Does not appear to be a .dds file.\n", filename);
	}

	int x = hdr.dwWidth;
	int y = hdr.dwHeight;
	int mip_map_num = (hdr.dwFlags & DDSD_MIPMAPCOUNT) ? hdr.dwMipMapCount : 1;

	if (!is_power_of_two(x)) { error("Texture %s with is %i pixels which is not a power of two!", filename, x); }
	if (!is_power_of_two(y)) { error("Texture %s height is %i pixels which is not a power of two!", filename, y); }

	DdsLoadInfo* li = &loadInfoDXT1;
	if      (PF_IS_DXT1(hdr.sPixelFormat  )) { li = &loadInfoDXT1;   }
	else if (PF_IS_DXT3(hdr.sPixelFormat  )) { li = &loadInfoDXT3;   }
	else if (PF_IS_DXT5(hdr.sPixelFormat  )) { li = &loadInfoDXT5;   }
	else if (PF_IS_BGRA8(hdr.sPixelFormat )) { li = &loadInfoBGRA8;  }
	else if (PF_IS_BGR8(hdr.sPixelFormat  )) { li = &loadInfoBGR8;   }
	else if (PF_IS_BGR5A1(hdr.sPixelFormat)) { li = &loadInfoBGR5A1; }
	else if (PF_IS_BGR565(hdr.sPixelFormat)) { li = &loadInfoBGR565; }
	else if (PF_IS_INDEX8(hdr.sPixelFormat)) { li = &loadInfoIndex8; }
	else { error("Cannot Load File %s: Unknown DDS File format type.", filename); }

	texture* t = texture_new();

	if (hdr.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP) {
		t->type = GL_TEXTURE_CUBE_MAP;
		glBindTexture(GL_TEXTURE_CUBE_MAP, texture_handle(t));
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_FALSE);
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, mip_map_num-1);
	} else {
		t->type = GL_TEXTURE_2D;
		glBindTexture(GL_TEXTURE_2D, texture_handle(t));
		glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mip_map_num-1);
		texture_set_filtering_anisotropic(t);
	}

	for (int i = 0; i < (t->type == GL_TEXTURE_CUBE_MAP ? 6 : 1); i++) {
		GLenum target = t->type;

		if (t->type == GL_TEXTURE_CUBE_MAP) {
			target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
		}

		int x = hdr.dwWidth;
		int y = hdr.dwHeight;
		int mip_map_num = (hdr.dwFlags & DDSD_MIPMAPCOUNT) ? hdr.dwMipMapCount : 1;

		if ( li->compressed ) {

			size_t size = max(li->div_size, x) / li->div_size * max(li->div_size, y) / li->div_size * li->block_bytes;
			char* data = malloc(size);

			for(int ix = 0; ix < mip_map_num; ix++) {

				SDL_RWread(f, data, 1, size);
				glCompressedTexImage2D(target, ix, li->internal_format, x, y, 0, size, data);

				x = (x+1)>>1;
				y = (y+1)>>1;

				size = max(li->div_size, x) / li->div_size * max(li->div_size, y) / li->div_size * li->block_bytes;
			}
			free(data);
		} else if ( li->palette ) {
コード例 #3
0
bool CDDSLoader::loadDDS( FILE * f )
{
	DDS_header hdr;
	size_t s = 0;
	unsigned int x = 0;
	unsigned int y = 0;
	unsigned int mipMapCount = 0;
	//  DDS is so simple to read, too
	fread( &hdr, sizeof( hdr ), 1, f );
	assert( hdr.dwMagic == DDS_MAGIC );
	assert( hdr.dwSize == 124 );

	if( hdr.dwMagic != DDS_MAGIC || hdr.dwSize != 124 || !(hdr.dwFlags & DDSD_PIXELFORMAT) || !(hdr.dwFlags & DDSD_CAPS) )
	{
		goto failure;
	}

	unsigned int xSize = hdr.dwWidth;
	unsigned int ySize = hdr.dwHeight;
	assert( !(xSize & (xSize-1)) );
	assert( !(ySize & (ySize-1)) );

	DdsLoadInfo * li;

	if( PF_IS_DXT1( hdr.sPixelFormat ) ) {
		li = &loadInfoDXT1;
	}
	else if( PF_IS_DXT3( hdr.sPixelFormat ) ) {
		li = &loadInfoDXT3;
	}
	else if( PF_IS_DXT5( hdr.sPixelFormat ) ) {
		li = &loadInfoDXT5;
	}
	else if( PF_IS_BGRA8( hdr.sPixelFormat ) ) {
		li = &loadInfoBGRA8;
	}
	else if( PF_IS_BGR8( hdr.sPixelFormat ) ) {
		li = &loadInfoBGR8;
	}
	else if( PF_IS_BGR5A1( hdr.sPixelFormat ) ) {
		li = &loadInfoBGR5A1;
	}
	else if( PF_IS_BGR565( hdr.sPixelFormat ) ) {
		li = &loadInfoBGR565;
	}
	else if( PF_IS_INDEX8( hdr.sPixelFormat ) ) {
		li = &loadInfoIndex8;
	}
	else {
		goto failure;
	}

	//fixme: do cube maps later
	//fixme: do 3d later
	bool hasMipmaps_=false;
	GLenum format,cFormat;
	unsigned int size;

	x = xSize;
	y = ySize;
	//  glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE );
	//  glGenerateMipmap( GL_TEXTURE_2D​ );
	mipMapCount = (hdr.dwFlags & DDSD_MIPMAPCOUNT) ? hdr.dwMipMapCount : 1;
	if( mipMapCount > 1 ) {
		hasMipmaps_ = true;
	}
	if( li->compressed ) {
		//1 block store 16pixel(4pixel by 4pixel), ie divSize=4
		//each block = 16Byte
		//therefore x/4 * y/4 * 16 = size of image
		size_t size = max( li->divSize, x )/li->divSize * max( li->divSize, y )/li->divSize * li->blockBytes;
		assert( size == hdr.dwPitchOrLinearSize );
		assert( hdr.dwFlags & DDSD_LINEARSIZE );
		unsigned char * data = (unsigned char *)malloc( size );
		if( !data ) {
			goto failure;
		}
		format = cFormat = li->internalFormat;
		for( unsigned int ix = 0; ix < mipMapCount; ++ix ) {
			fread( data, 1, size, f );
			glCompressedTexImage2D( GL_TEXTURE_2D, ix, li->internalFormat, x, y, 0, size, data );
			x = (x+1)>>1;
			y = (y+1)>>1;
			size = max( li->divSize, x )/li->divSize * max( li->divSize, y )/li->divSize * li->blockBytes;
		}
		free( data );
	}
コード例 #4
0
ファイル: texture.c プロジェクト: Bevilacqua/Corange
texture* dds_load_file( char* filename ){
  
  DdsLoadInfo loadInfoDXT1 = {
    1, 0, 0, 4, 8, GL_COMPRESSED_RGBA_S3TC_DXT1
  };
  DdsLoadInfo loadInfoDXT3 = {
    1, 0, 0, 4, 16, GL_COMPRESSED_RGBA_S3TC_DXT3
  };
  DdsLoadInfo loadInfoDXT5 = {
    1, 0, 0, 4, 16, GL_COMPRESSED_RGBA_S3TC_DXT5
  };
  DdsLoadInfo loadInfoBGRA8 = {
    0, 0, 0, 1, 4, GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE
  };
  DdsLoadInfo loadInfoBGR8 = {
    0, 0, 0, 1, 3, GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE
  };
  DdsLoadInfo loadInfoBGR5A1 = {
    0, 1, 0, 1, 2, GL_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV
  };
  DdsLoadInfo loadInfoBGR565 = {
    0, 1, 0, 1, 2, GL_RGB5, GL_RGB, GL_UNSIGNED_SHORT_5_6_5
  };
  DdsLoadInfo loadInfoIndex8 = {
    0, 0, 1, 1, 1, GL_RGB8, GL_BGRA, GL_UNSIGNED_BYTE
  };
  
  texture my_texture;
  glGenTextures(1, &my_texture);
  glBindTexture(GL_TEXTURE_2D, my_texture);

  DDS_header hdr;
  int x = 0;
  int y = 0;
  int mipMapCount = 0;
  
  SDL_RWops* f = SDL_RWFromFile(filename, "rb");
  if (f == NULL) {
    error("Cannot load file %s", filename);
  }
  SDL_RWread(f, &hdr, 1, sizeof(hdr));
  
  if( hdr.dwMagic != DDS_MAGIC || hdr.dwSize != 124 ||
    !(hdr.dwFlags & DDSD_PIXELFORMAT) || !(hdr.dwFlags & DDSD_CAPS) ) {
    
    error("Cannot Load File %s: Does not appear to be a .dds file.\n", filename);
  }

  x = hdr.dwWidth;
  y = hdr.dwHeight;
  
  if (!is_power_of_two(x)) {
    warning("Texture %s with is %i pixels which is not a power of two!", filename, x);
  }
  
  if (!is_power_of_two(y)) {
    warning("Texture %s height is %i pixels which is not a power of two!", filename, y);
  }
  
  DdsLoadInfo* li = &loadInfoDXT1;

  if( PF_IS_DXT1( hdr.sPixelFormat ) ) {
    li = &loadInfoDXT1;
  }
  else if( PF_IS_DXT3( hdr.sPixelFormat ) ) {
    li = &loadInfoDXT3;
  }
  else if( PF_IS_DXT5( hdr.sPixelFormat ) ) {
    li = &loadInfoDXT5;
  }
  else if( PF_IS_BGRA8( hdr.sPixelFormat ) ) {
    li = &loadInfoBGRA8;
  }
  else if( PF_IS_BGR8( hdr.sPixelFormat ) ) {
    li = &loadInfoBGR8;
  }
  else if( PF_IS_BGR5A1( hdr.sPixelFormat ) ) {
    li = &loadInfoBGR5A1;
  }
  else if( PF_IS_BGR565( hdr.sPixelFormat ) ) {
    li = &loadInfoBGR565;
  }
  else if( PF_IS_INDEX8( hdr.sPixelFormat ) ) {
    li = &loadInfoIndex8;
  } else {
    error("Cannot Load File %s: Unknown DDS File format type.", filename);
  }
  
  glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE );
  mipMapCount = (hdr.dwFlags & DDSD_MIPMAPCOUNT) ? hdr.dwMipMapCount : 1;
  
  int ix, zz;
  GLenum cFormat, format;
  
  if( li->compressed ) {
    size_t size = max( li->divSize, x )/li->divSize * max( li->divSize, y )/li->divSize * li->blockBytes;
    char* data = malloc( size );
    
    if( !data ) {
      error("Cannot Load File %s: Does not appear to contain any data.", filename);
    }
    
    cFormat = li->internalFormat;
    format = li->internalFormat;
    
    for( ix = 0; ix < mipMapCount; ++ix ) {
    
      SDL_RWread(f, data, 1, size);
      glCompressedTexImage2D( GL_TEXTURE_2D, ix, li->internalFormat, x, y, 0, size, data );
      
      x = (x+1)>>1;
      y = (y+1)>>1;
      
      size = max( li->divSize, x )/li->divSize * max( li->divSize, y )/li->divSize * li->blockBytes;
    }
    free( data );
    
  } else if( li->palette ) {
コード例 #5
0
ファイル: mtexture.c プロジェクト: bigml/emoon
NEOERR* mast_dds_load(char *dir, char *name, RendAsset **a)
{
    char fname[PATH_MAX], *buf, *pos;
    NEOERR *err;

    DdsLoadInfo loadInfoDXT1 = {
        1, 0, 0, 4, 8, GL_COMPRESSED_RGBA_S3TC_DXT1
    };
    DdsLoadInfo loadInfoDXT3 = {
        1, 0, 0, 4, 16, GL_COMPRESSED_RGBA_S3TC_DXT3
    };
    DdsLoadInfo loadInfoDXT5 = {
        1, 0, 0, 4, 16, GL_COMPRESSED_RGBA_S3TC_DXT5
    };
    DdsLoadInfo loadInfoBGRA8 = {
        0, 0, 0, 1, 4, GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE
    };
    DdsLoadInfo loadInfoBGR8 = {
        0, 0, 0, 1, 3, GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE
    };
    DdsLoadInfo loadInfoBGR5A1 = {
        0, 1, 0, 1, 2, GL_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV
    };
    DdsLoadInfo loadInfoBGR565 = {
        0, 1, 0, 1, 2, GL_RGB5, GL_RGB, GL_UNSIGNED_SHORT_5_6_5
    };
    DdsLoadInfo loadInfoIndex8 = {
        0, 0, 1, 1, 1, GL_RGB8, GL_BGRA, GL_UNSIGNED_BYTE
    };

    if (dir) snprintf(fname, sizeof(fname), "%s%s", dir, name);
    else strncpy(fname, name, sizeof(fname));

    TexAsset *tnode = mtex_node_new();
    if (!tnode) return nerr_raise(NERR_NOMEM, "alloc texture");

    DDS_header hdr;
    int x = 0;
    int y = 0;
    int mipMapCount = 0;
    int totallen = 0;

    err = ne_load_file_len(fname, &buf, &totallen);
    if (err != STATUS_OK) return nerr_pass(err);

    glEnable(GL_TEXTURE_2D);
    glGenTextures(1, &tnode->tex);
    glBindTexture(GL_TEXTURE_2D, tnode->tex);

    pos = buf;
    memcpy(&hdr, buf, sizeof(hdr));
    pos += sizeof(hdr);
    if (pos - buf > totallen) return nerr_raise(NERR_ASSERT, "file too short");

    if (hdr.dwMagic != DDS_MAGIC || hdr.dwSize != 124 ||
        !(hdr.dwFlags & DDSD_PIXELFORMAT) || !(hdr.dwFlags & DDSD_CAPS) )
        return nerr_raise(NERR_ASSERT, "%s Does not appear to be a .dds file", fname);

    x = hdr.dwWidth;
    y = hdr.dwHeight;

    if (!is_power_of_two(x)) {
        mtc_warn("Texture %s with is %i pixels which is not a power of two!", fname, x);
    }

    if (!is_power_of_two(y)) {
        mtc_warn("Texture %s height is %i pixels which is not a power of two!", fname, y);
    }

    DdsLoadInfo* li = &loadInfoDXT1;

    if (PF_IS_DXT1(hdr.sPixelFormat)) {
        li = &loadInfoDXT1;
    } else if (PF_IS_DXT3(hdr.sPixelFormat)) {
        li = &loadInfoDXT3;
    } else if (PF_IS_DXT5(hdr.sPixelFormat)) {
        li = &loadInfoDXT5;
    } else if (PF_IS_BGRA8(hdr.sPixelFormat)) {
        li = &loadInfoBGRA8;
    } else if (PF_IS_BGR8(hdr.sPixelFormat)) {
        li = &loadInfoBGR8;
    } else if (PF_IS_BGR5A1(hdr.sPixelFormat)) {
        li = &loadInfoBGR5A1;
    } else if (PF_IS_BGR565(hdr.sPixelFormat)) {
        li = &loadInfoBGR565;
    } else if (PF_IS_INDEX8(hdr.sPixelFormat)) {
        li = &loadInfoIndex8;
    } else {
        return nerr_raise(NERR_ASSERT, "%s: Unknown DDS File format type.", fname);
    }

    glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
    mipMapCount = (hdr.dwFlags & DDSD_MIPMAPCOUNT) ? hdr.dwMipMapCount : 1;

    int ix, zz;
    GLenum cFormat, format;

    if (li->compressed) {
        size_t size = max(li->divSize, x) / li->divSize *
                      max(li->divSize, y) / li->divSize * li->blockBytes;
        char *data = malloc(size);
        if (!data ) {
            return nerr_raise(NERR_ASSERT, "%s: not contain any data.", fname);
        }

        cFormat = li->internalFormat;
        format = li->internalFormat;

        for( ix = 0; ix < mipMapCount; ++ix ) {
            memcpy(data, pos, size);
            pos += size;
            if (pos - buf > totallen) return nerr_raise(NERR_ASSERT, "file too short");

            glCompressedTexImage2D(GL_TEXTURE_2D, ix, li->internalFormat,
                                   x, y, 0, size, data);
            x = (x+1)>>1;
            y = (y+1)>>1;
            size = max(li->divSize, x) / li->divSize *
                   max(li->divSize, y) / li->divSize * li->blockBytes;
        }
        free(data);
    } else if (li->palette) {