2014-02-08 04:40:00 -08:00
# include "BitmapImage.h"
void * BI_def_bitmap_create ( int width , int height ) { return Allocate ( width * height * 4 ) ; }
void BI_def_bitmap_set_opaque ( void * bitmap , BOOL opaque ) { }
BOOL BI_def_bitmap_test_opaque ( void * bitmap ) { return false ; }
unsigned char * BI_def_bitmap_get_buffer ( void * bitmap ) { return ( unsigned char * ) bitmap ; }
void BI_def_bitmap_destroy ( void * bitmap ) { Free ( bitmap ) ; }
void BI_def_bitmap_modified ( void * bitmap ) { }
BitmapImage : : BitmapImage ( )
{
bitmap_callbacks . bitmap_create = BI_def_bitmap_create ;
bitmap_callbacks . bitmap_destroy = BI_def_bitmap_destroy ;
bitmap_callbacks . bitmap_get_buffer = BI_def_bitmap_get_buffer ;
bitmap_callbacks . bitmap_modified = BI_def_bitmap_modified ;
bitmap_callbacks . bitmap_set_opaque = BI_def_bitmap_set_opaque ;
bitmap_callbacks . bitmap_test_opaque = BI_def_bitmap_test_opaque ;
}
BitmapImage : : ~ BitmapImage ( )
{
if ( bIsAnimatedGif )
{
gif_finalise ( & gif ) ;
Free ( animationFrameCache ) ;
Free ( animationFrameData ) ;
}
if ( lpGifData )
Free ( lpGifData ) ;
EnableFileMonitor ( false ) ;
delete texture ;
}
//----------------------------------------------------------------------------
void BitmapImage : : CreateErrorTexture ( void )
{
LPBYTE textureData = ( LPBYTE ) Allocate ( 32 * 32 * 4 ) ;
msetd ( textureData , 0xFF0000FF , 32 * 32 * 4 ) ;
texture = CreateTexture ( 32 , 32 , GS_RGB , textureData , FALSE ) ;
fullSize . Set ( 32.0f , 32.0f ) ;
Free ( textureData ) ;
}
//----------------------------------------------------------------------------
void BitmapImage : : SetPath ( String path )
{
filePath = path ;
}
void BitmapImage : : EnableFileMonitor ( bool bMonitor )
{
if ( changeMonitor )
{
OSMonitorFileDestroy ( changeMonitor ) ;
changeMonitor = NULL ;
}
if ( bMonitor )
changeMonitor = OSMonitorFileStart ( filePath ) ;
}
void BitmapImage : : Init ( void )
{
if ( bIsAnimatedGif )
{
bIsAnimatedGif = false ;
gif_finalise ( & gif ) ;
Free ( animationFrameCache ) ;
animationFrameCache = NULL ;
Free ( animationFrameData ) ;
animationFrameData = NULL ;
}
if ( lpGifData )
{
Free ( lpGifData ) ;
lpGifData = NULL ;
}
animationTimes . Clear ( ) ;
delete texture ;
texture = NULL ;
CTSTR lpBitmap = filePath ;
if ( ! lpBitmap | | ! * lpBitmap )
{
AppWarning ( TEXT ( " BitmapImage::Init: Empty path " ) ) ;
CreateErrorTexture ( ) ;
return ;
}
//------------------------------------
if ( GetPathExtension ( lpBitmap ) . CompareI ( TEXT ( " gif " ) ) )
{
gif_create ( & gif , & bitmap_callbacks ) ;
XFile gifFile ;
if ( ! gifFile . Open ( lpBitmap , XFILE_READ , XFILE_OPENEXISTING ) )
{
AppWarning ( TEXT ( " BitmapImage::Init: could not open gif file '%s' " ) , lpBitmap ) ;
CreateErrorTexture ( ) ;
return ;
}
DWORD fileSize = ( DWORD ) gifFile . GetFileSize ( ) ;
lpGifData = ( LPBYTE ) Allocate ( fileSize ) ;
gifFile . Read ( lpGifData , fileSize ) ;
gif_result result ;
do
{
result = gif_initialise ( & gif , fileSize , lpGifData ) ;
if ( result ! = GIF_OK & & result ! = GIF_WORKING )
{
2015-01-31 06:41:55 -08:00
Log ( TEXT ( " BitmapImage: Warning, couldn't initialise gif %s, it is likely corrupt " ) , lpBitmap ) ;
CreateErrorTexture ( ) ;
return ;
2014-02-08 04:40:00 -08:00
}
} while ( result ! = GIF_OK ) ;
2015-01-31 06:41:55 -08:00
if ( gif . width > 4096 | | gif . height > 4096 )
{
Log ( TEXT ( " BitmapImage: Warning, bad texture dimensions %d x %d in %s " ) , gif . width , gif . height , lpBitmap ) ;
CreateErrorTexture ( ) ;
return ;
}
2015-05-23 09:48:24 -07:00
unsigned long long max_size = ( unsigned long long ) gif . width * ( unsigned long long ) gif . height * 4LLU * ( unsigned long long ) gif . frame_count ;
if ( gif . width * gif . height * 4 * gif . frame_count ! = max_size )
{
Log ( TEXT ( " BitmapImage: Warning, gif %s overflowed maximum pointer size and was not loaded (%llu > %u) " ) , lpBitmap , max_size , gif . width * gif . height * 4 * gif . frame_count ) ;
CreateErrorTexture ( ) ;
return ;
}
2015-05-23 09:43:46 -07:00
2014-02-08 04:40:00 -08:00
if ( gif . frame_count > 1 )
{
if ( result = = GIF_OK | | result = = GIF_WORKING )
bIsAnimatedGif = true ;
}
if ( bIsAnimatedGif )
{
gif_decode_frame ( & gif , 0 ) ;
texture = CreateTexture ( gif . width , gif . height , GS_RGBA , gif . frame_image , FALSE , FALSE ) ;
animationFrameCache = ( BYTE * * ) Allocate ( gif . frame_count * sizeof ( BYTE * ) ) ;
memset ( animationFrameCache , 0 , gif . frame_count * sizeof ( BYTE * ) ) ;
animationFrameData = ( BYTE * ) Allocate ( gif . frame_count * gif . width * gif . height * 4 ) ;
memset ( animationFrameData , 0 , gif . frame_count * gif . width * gif . height * 4 ) ;
for ( UINT i = 0 ; i < gif . frame_count ; i + + )
{
float frameTime = float ( gif . frames [ i ] . frame_delay ) * 0.01f ;
if ( frameTime = = 0.0f )
frameTime = 0.1f ;
animationTimes < < frameTime ;
if ( gif_decode_frame ( & gif , i ) ! = GIF_OK )
Log ( TEXT ( " BitmapImage: Warning, couldn't decode frame %d of %s " ) , i , lpBitmap ) ;
}
gif_decode_frame ( & gif , 0 ) ;
fullSize . x = float ( gif . width ) ;
fullSize . y = float ( gif . height ) ;
curTime = 0.0f ;
curFrame = 0 ;
lastDecodedFrame = 0 ;
}
else
{
gif_finalise ( & gif ) ;
Free ( lpGifData ) ;
lpGifData = NULL ;
}
}
if ( ! bIsAnimatedGif )
{
texture = GS - > CreateTextureFromFile ( lpBitmap , TRUE ) ;
if ( ! texture )
{
AppWarning ( TEXT ( " BitmapImage::Init: could not create texture '%s' " ) , lpBitmap ) ;
CreateErrorTexture ( ) ;
return ;
}
fullSize . x = float ( texture - > Width ( ) ) ;
fullSize . y = float ( texture - > Height ( ) ) ;
}
}
Vect2 BitmapImage : : GetSize ( void ) const
{
return fullSize ;
}
Texture * BitmapImage : : GetTexture ( void ) const
{
return texture ;
}
void BitmapImage : : Tick ( float fSeconds )
{
if ( bIsAnimatedGif )
{
UINT totalLoops = ( UINT ) gif . loop_count ;
if ( totalLoops > = 0xFFFF )
totalLoops = 0 ;
if ( ! totalLoops | | curLoop < totalLoops )
{
UINT newFrame = curFrame ;
curTime + = fSeconds ;
while ( curTime > animationTimes [ newFrame ] )
{
curTime - = animationTimes [ newFrame ] ;
if ( + + newFrame = = animationTimes . Num ( ) )
{
if ( ! totalLoops | | + + curLoop < totalLoops )
newFrame = 0 ;
else if ( curLoop = = totalLoops )
{
newFrame - - ;
break ;
}
}
}
if ( newFrame ! = curFrame )
{
UINT lastFrame ;
if ( ! animationFrameCache [ newFrame ] )
{
//animation might have looped, if so make sure we decode from frame 0
if ( newFrame < lastDecodedFrame )
lastFrame = 0 ;
else
lastFrame = lastDecodedFrame + 1 ;
//we need to decode any frames we missed for consistency
for ( UINT i = lastFrame ; i < newFrame ; i + + )
{
if ( gif_decode_frame ( & gif , i ) ! = GIF_OK )
return ;
}
//now decode and display the actual frame we want
int ret = gif_decode_frame ( & gif , newFrame ) ;
if ( ret = = GIF_OK )
{
animationFrameCache [ newFrame ] = animationFrameData + ( newFrame * ( gif . width * gif . height * 4 ) ) ;
memcpy ( animationFrameCache [ newFrame ] , gif . frame_image , gif . width * gif . height * 4 ) ;
}
lastDecodedFrame = newFrame ;
}
if ( animationFrameCache [ newFrame ] )
texture - > SetImage ( animationFrameCache [ newFrame ] , GS_IMAGEFORMAT_RGBA , gif . width * 4 ) ;
curFrame = newFrame ;
}
}
}
if ( updateImageTime )
{
updateImageTime - = fSeconds ;
if ( updateImageTime < = 0.0f )
{
updateImageTime = 0.0f ;
Init ( ) ;
}
}
if ( changeMonitor & & OSFileHasChanged ( changeMonitor ) )
updateImageTime = 1.0f ;
}