Introduction
This is a simple article on how to load textures from .ZIP files. I am using DirectX 9 (with the D3DX utility library) and unzip.h by Gilles Vollant (his work uses / is based on zlib). This code is for those programmers who might be interested in loading their images (or any file for that matter) from a .ZIP file for either compression or archival purposes (or both).
Why not just include the images as resources into your .EXE? Well, first of all, including many large images as resources can increase your .EXE size and compilation time. Plus, .ZIP files are cool and practically everyone already has a compression program that can create them. Just think of all the space you'll save.
The Code
Using D3DX and the included unzip code makes everything easy. The idea is to use the unzip functions to open the zip file, find which file we want, and load it into memory. After we have it in
memory, we can use D3DXCreateTextureFromFileInMemory() to load the image (which can be in .bmp, .dds, .dib, .jpg, .png, or .tga format). I do not claim that this code is the right way, nor the
fastest or best way to do this. That being said, here is a function that wraps up all the .ZIP handling and texture creation code into one little package:
// CreateTextureFromFileInZip()
// pDevice The D3D9 device
// szZip The .zip file
// szFile The image file within the .zip
// ppTexture A pointer to the newly created texture
//
// Return values:
// S_OK Everything went ok.
// E_FAIL Everything did not go ok. :-)
// E_OUTOFMEMORY I'll let you guess on this one.
HRESULT CreateTextureFromFileInZip( LPDIRECT3DDEVICE9 pDevice, LPCSTR szZip,
LPCSTR szFile, LPDIRECT3DTEXTURE9 *ppTexture )
{
// open ZIP
unzFile zip = unzOpen( szZip );
if( !zip )
return E_FAIL;
// locate the file and open it (1 means case sensitive comparison)
unzLocateFile( zip, szFile, 1 );
if( unzOpenCurrentFile( zip ) != UNZ_OK )
return E_FAIL;
// find current file info (we are looking for uncompressed file size)
unz_file_info info;
unzGetCurrentFileInfo( zip, &info, NULL, 0, NULL, 0, NULL, 0 );
// create a buffer big enough to hold uncompressed file in memory
void *buffer = malloc( info.uncompressed_size );
if( !buffer )
{
unzCloseCurrentFile( zip );
unzClose( zip );
return E_OUTOFMEMORY;
}
// load into memory
unzReadCurrentFile( zip, buffer, info.uncompressed_size );
unzCloseCurrentFile( zip );
unzClose( zip );
// use D3DX utility library to load our texture now.
if( FAILED( D3DXCreateTextureFromFileInMemory( pDevice, buffer,
info.uncompressed_size, ppTexture ) ) )
{
free( buffer );
return E_FAIL;
}
free( buffer );
return S_OK;
}
Notes & Improvements
The CreateTextureFromFileInZip() function (whew! long name!) is rather easy to use. However, it is not the most efficient thing in the world. You may want to modify the code so if you are loading multiple files from the same .ZIP, you only need to load the .ZIP once. As it is, opening and closing the .ZIP file for each image is rather redundant. And of course, the wonderful call to malloc is regarded by some as evil. You could perhaps create a static buffer that is big enough to hold your largest image (uncompressed) and just reuse the same buffer for all your image loading. This would eliminate the need for malloc()/free(). However, D3DXCreateTextureFromFileInMemory() probably uses malloc() anyways, right?
The included MSVC++ workspace and code demonstrate how to use this function. Nothing too fancy.
Conclusion
Thanks for reading and I hope somebody found this article to be of use.