749 lines
16 KiB
C
749 lines
16 KiB
C
/*
|
|
SDL_anigif: An example animated GIF image loading library for use with SDL
|
|
SDL_image Copyright (C) 1997-2006 Sam Lantinga
|
|
Animated GIF "derived work" Copyright (C) 2006 Doug McFadyen
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "SDL_anigif.h"
|
|
#include "sdl_idf.h"
|
|
|
|
extern idf_t game_idf;
|
|
|
|
/* Code from here to end of file has been adapted from XPaint: */
|
|
/* +-------------------------------------------------------------------+ */
|
|
/* | Copyright 1990, 1991, 1993 David Koblas. | */
|
|
/* | Copyright 1996 Torsten Martinsen. | */
|
|
/* | Permission to use, copy, modify, and distribute this software | */
|
|
/* | and its documentation for any purpose and without fee is hereby | */
|
|
/* | granted, provided that the above copyright notice appear in all | */
|
|
/* | copies and that both that copyright notice and this permission | */
|
|
/* | notice appear in supporting documentation. This software is | */
|
|
/* | provided "as is" without express or implied warranty. | */
|
|
/* +-------------------------------------------------------------------+ */
|
|
/* Adapted for use in SDL by Sam Lantinga -- 7/20/98 */
|
|
/* Animated GIF support by Doug McFadyen -- 10/19/06 */
|
|
|
|
#define MAXCOLORMAPSIZE 256
|
|
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
|
|
#define CM_RED 0
|
|
#define CM_GREEN 1
|
|
#define CM_BLUE 2
|
|
|
|
#define MAX_LWZ_BITS 12
|
|
|
|
#define INTERLACE 0x40
|
|
#define LOCALCOLORMAP 0x80
|
|
#define BitSet(byte,bit) (((byte) & (bit)) == (bit))
|
|
#define LM_to_uint(a,b) (((b)<<8)|(a))
|
|
|
|
#define SDL_SetError(t) ((void)0) /* We're not SDL so ignore error reporting */
|
|
|
|
|
|
typedef struct
|
|
{
|
|
unsigned int Width;
|
|
unsigned int Height;
|
|
unsigned char ColorMap[3][MAXCOLORMAPSIZE];
|
|
unsigned int BitPixel;
|
|
unsigned int ColorResolution;
|
|
unsigned int Background;
|
|
unsigned int AspectRatio;
|
|
} gifscreen;
|
|
|
|
typedef struct
|
|
{
|
|
int transparent;
|
|
int delayTime;
|
|
int inputFlag;
|
|
int disposal;
|
|
} gif89;
|
|
|
|
typedef struct
|
|
{
|
|
/* global data */
|
|
SDL_RWops* src;
|
|
int loop;
|
|
gifscreen gs;
|
|
gif89 g89;
|
|
int zerodatablock;
|
|
/* AG_LoadGIF_RW data */
|
|
unsigned char localColorMap[3][MAXCOLORMAPSIZE];
|
|
/* GetCode data */
|
|
unsigned char buf[280];
|
|
int curbit, lastbit, done, lastbyte;
|
|
/* LWZReadByte data */
|
|
int fresh, code, incode;
|
|
int codesize, setcodesize;
|
|
int maxcode, maxcodesize;
|
|
int firstcode, oldcode;
|
|
int clearcode, endcode;
|
|
int table[2][(1 << MAX_LWZ_BITS)];
|
|
int stack[(1 << (MAX_LWZ_BITS))*2], *sp;
|
|
} gifdata;
|
|
|
|
|
|
|
|
static int ReadColorMap( gifdata* gd, int number, unsigned char buffer[3][MAXCOLORMAPSIZE] );
|
|
static int DoExtension( gifdata* gd, int label );
|
|
static int GetDataBlock( gifdata* gd, unsigned char* buf );
|
|
static int GetCode( gifdata* gd, int code_size, int flag );
|
|
static int LWZReadByte( gifdata* gd, int flag, int input_code_size );
|
|
static SDL_Surface* ReadImage( gifdata* gd, int len, int height, int, unsigned char cmap[3][MAXCOLORMAPSIZE], int interlace, int ignore );
|
|
|
|
|
|
|
|
int AG_isGIF( SDL_RWops* src )
|
|
{
|
|
int isGIF = FALSE;
|
|
|
|
if ( src )
|
|
{
|
|
int start = SDL_RWtell( src );
|
|
char magic[6];
|
|
|
|
if ( SDL_RWread(src,magic,sizeof(magic),1) )
|
|
{
|
|
if ( (strncmp(magic,"GIF",3) == 0) && ((memcmp(magic+3,"87a",3) == 0) || (memcmp(magic+3,"89a",3) == 0)) )
|
|
{
|
|
isGIF = TRUE;
|
|
}
|
|
}
|
|
|
|
SDL_RWseek( src, start, SEEK_SET );
|
|
}
|
|
|
|
return isGIF;
|
|
}
|
|
|
|
int AG_LoadGIF( const char* file, AG_Frame* frames, int size, int *loop )
|
|
{
|
|
int n = 0;
|
|
|
|
SDL_RWops* src = RWFromIdf(game_idf, file);
|
|
|
|
if ( src )
|
|
{
|
|
n = AG_LoadGIF_RW( src, frames, size, loop );
|
|
SDL_RWclose( src );
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
|
|
|
|
void AG_FreeSurfaces( AG_Frame* frames, int nFrames )
|
|
{
|
|
int i;
|
|
|
|
if ( frames )
|
|
{
|
|
for ( i = 0; i < nFrames; i++ )
|
|
{
|
|
if ( frames[i].surface )
|
|
{
|
|
SDL_FreeSurface( frames[i].surface );
|
|
frames[i].surface = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int AG_ConvertSurfacesToDisplayFormat( AG_Frame* frames, int nFrames )
|
|
{
|
|
int i;
|
|
int n = 0;
|
|
|
|
if ( frames )
|
|
{
|
|
for ( i = 0; i < nFrames; i++ )
|
|
{
|
|
if ( frames[i].surface )
|
|
{
|
|
SDL_Surface* surface = (frames[i].surface->flags & SDL_SRCCOLORKEY) ? SDL_DisplayFormatAlpha(frames[i].surface) : SDL_DisplayFormat(frames[i].surface);
|
|
|
|
if ( surface )
|
|
{
|
|
SDL_FreeSurface( frames[i].surface );
|
|
frames[i].surface = surface;
|
|
n++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
|
|
|
|
int AG_NormalizeSurfacesToDisplayFormat( AG_Frame* frames, int nFrames )
|
|
{
|
|
int n = 0;
|
|
|
|
if ( nFrames > 0 && frames && frames[0].surface )
|
|
{
|
|
SDL_Surface* mainSurface = (frames[0].surface->flags & SDL_SRCCOLORKEY) ? SDL_DisplayFormatAlpha(frames[0].surface) : SDL_DisplayFormat(frames[0].surface);
|
|
const int newDispose = (frames[0].surface->flags & SDL_SRCCOLORKEY) ? AG_DISPOSE_RESTORE_BACKGROUND : AG_DISPOSE_NONE;
|
|
|
|
if ( mainSurface )
|
|
{
|
|
int i;
|
|
int lastDispose = AG_DISPOSE_NA;
|
|
int iRestore = 0;
|
|
const Uint8 alpha = (frames[0].disposal == AG_DISPOSE_NONE ||
|
|
frames[0].disposal == AG_DISPOSE_NA) ? SDL_ALPHA_OPAQUE : SDL_ALPHA_TRANSPARENT;
|
|
|
|
SDL_FillRect( mainSurface, NULL, SDL_MapRGBA(mainSurface->format,0,0,0,alpha) );
|
|
|
|
for ( i = 0; i < nFrames; i++ )
|
|
{
|
|
if ( frames[i].surface )
|
|
{
|
|
SDL_Surface* surface = SDL_ConvertSurface( mainSurface, mainSurface->format, mainSurface->flags );
|
|
|
|
if ( surface )
|
|
{
|
|
SDL_Rect r;
|
|
|
|
if ( lastDispose == AG_DISPOSE_NONE )
|
|
SDL_BlitSurface( frames[i-1].surface, NULL, surface, NULL );
|
|
|
|
if ( lastDispose == AG_DISPOSE_RESTORE_PREVIOUS )
|
|
SDL_BlitSurface( frames[iRestore].surface, NULL, surface, NULL );
|
|
if ( frames[i].disposal != AG_DISPOSE_RESTORE_PREVIOUS )
|
|
iRestore = i;
|
|
|
|
r.x = (Sint16)frames[i].x;
|
|
r.y = (Sint16)frames[i].y;
|
|
SDL_BlitSurface( frames[i].surface, NULL, surface, &r );
|
|
|
|
SDL_FreeSurface( frames[i].surface );
|
|
frames[i].surface = surface;
|
|
frames[i].x = frames[i].y = 0;
|
|
lastDispose = frames[i].disposal;
|
|
frames[i].disposal = newDispose;
|
|
n++;
|
|
}
|
|
}
|
|
}
|
|
|
|
SDL_FreeSurface( mainSurface );
|
|
}
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
|
|
|
|
int AG_LoadGIF_RW( SDL_RWops* src, AG_Frame* frames, int maxFrames, int *loop)
|
|
{
|
|
int start;
|
|
unsigned char buf[16];
|
|
unsigned char c;
|
|
int useGlobalColormap;
|
|
int bitPixel;
|
|
int iFrame = 0;
|
|
char version[4];
|
|
SDL_Surface* image = NULL;
|
|
gifdata* gd;
|
|
|
|
if ( src == NULL )
|
|
return 0;
|
|
|
|
gd = malloc( sizeof(*gd) );
|
|
memset( gd, 0, sizeof(*gd) );
|
|
gd->src = src;
|
|
gd->loop = 1;
|
|
start = SDL_RWtell( src );
|
|
|
|
if ( !SDL_RWread(src,buf,6,1) )
|
|
{
|
|
SDL_SetError( "error reading magic number" );
|
|
goto done;
|
|
}
|
|
|
|
if ( strncmp((char*)buf,"GIF",3) != 0 )
|
|
{
|
|
SDL_SetError( "not a GIF file" );
|
|
goto done;
|
|
}
|
|
|
|
strncpy( version, (char*)buf+3, 3 );
|
|
version[3] = '\0';
|
|
|
|
if ( (strcmp(version,"87a") != 0) && (strcmp(version,"89a") != 0) )
|
|
{
|
|
SDL_SetError( "bad version number, not '87a' or '89a'" );
|
|
goto done;
|
|
}
|
|
|
|
gd->g89.transparent = -1;
|
|
gd->g89.delayTime = -1;
|
|
gd->g89.inputFlag = -1;
|
|
gd->g89.disposal = AG_DISPOSE_NA;
|
|
|
|
if ( !SDL_RWread(src,buf,7,1) )
|
|
{
|
|
SDL_SetError( "failed to read screen descriptor" );
|
|
goto done;
|
|
}
|
|
|
|
gd->gs.Width = LM_to_uint(buf[0],buf[1]);
|
|
gd->gs.Height = LM_to_uint(buf[2],buf[3]);
|
|
gd->gs.BitPixel = 2 << (buf[4] & 0x07);
|
|
gd->gs.ColorResolution = (((buf[4] & 0x70) >> 3) + 1);
|
|
gd->gs.Background = buf[5];
|
|
gd->gs.AspectRatio = buf[6];
|
|
|
|
if ( BitSet(buf[4],LOCALCOLORMAP) ) /* Global Colormap */
|
|
{
|
|
if ( ReadColorMap(gd,gd->gs.BitPixel,gd->gs.ColorMap) )
|
|
{
|
|
SDL_SetError( "error reading global colormap" );
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
do
|
|
{
|
|
if ( !SDL_RWread(src,&c,1,1) )
|
|
{
|
|
SDL_SetError( "EOF / read error on image data" );
|
|
goto done;
|
|
}
|
|
|
|
if ( c == ';' ) /* GIF terminator */
|
|
goto done;
|
|
|
|
if ( c == '!' ) /* Extension */
|
|
{
|
|
if ( !SDL_RWread(src,&c,1,1) )
|
|
{
|
|
SDL_SetError( "EOF / read error on extention function code" );
|
|
goto done;
|
|
}
|
|
DoExtension( gd, c );
|
|
continue;
|
|
}
|
|
|
|
if ( c != ',' ) /* Not a valid start character */
|
|
continue;
|
|
|
|
if ( !SDL_RWread(src,buf,9,1) )
|
|
{
|
|
SDL_SetError( "couldn't read left/top/width/height" );
|
|
goto done;
|
|
}
|
|
|
|
useGlobalColormap = !BitSet(buf[8],LOCALCOLORMAP);
|
|
bitPixel = 1 << ((buf[8] & 0x07) + 1);
|
|
|
|
if ( !useGlobalColormap )
|
|
{
|
|
if ( ReadColorMap(gd,bitPixel,gd->localColorMap) )
|
|
{
|
|
SDL_SetError( "error reading local colormap" );
|
|
goto done;
|
|
}
|
|
image = ReadImage( gd, LM_to_uint(buf[4],buf[5]), LM_to_uint(buf[6],buf[7]), bitPixel, gd->localColorMap, BitSet(buf[8],INTERLACE), (frames==NULL) );
|
|
}
|
|
else
|
|
{
|
|
image = ReadImage( gd, LM_to_uint(buf[4],buf[5]), LM_to_uint(buf[6],buf[7]), gd->gs.BitPixel, gd->gs.ColorMap, BitSet(buf[8],INTERLACE), (frames==NULL) );
|
|
}
|
|
|
|
if ( frames )
|
|
{
|
|
if ( image == NULL )
|
|
goto done;
|
|
|
|
if ( gd->g89.transparent >= 0 )
|
|
SDL_SetColorKey( image, SDL_SRCCOLORKEY, gd->g89.transparent );
|
|
|
|
frames[iFrame].surface = image;
|
|
frames[iFrame].x = LM_to_uint(buf[0], buf[1]);
|
|
frames[iFrame].y = LM_to_uint(buf[2], buf[3]);
|
|
frames[iFrame].disposal = gd->g89.disposal;
|
|
frames[iFrame].delay = gd->g89.delayTime*10;
|
|
/* gd->g89.transparent = -1; ** Hmmm, not sure if this should be reset for each frame? */
|
|
}
|
|
|
|
iFrame++;
|
|
} while ( iFrame < maxFrames || frames == NULL );
|
|
|
|
done:
|
|
if ( image == NULL )
|
|
SDL_RWseek( src, start, SEEK_SET );
|
|
if (loop)
|
|
*loop = gd->loop;
|
|
free( gd );
|
|
|
|
return iFrame;
|
|
}
|
|
|
|
|
|
|
|
static int ReadColorMap( gifdata* gd, int number, unsigned char buffer[3][MAXCOLORMAPSIZE] )
|
|
{
|
|
int i;
|
|
unsigned char rgb[3];
|
|
int flag;
|
|
|
|
flag = TRUE;
|
|
|
|
for ( i = 0; i < number; ++i )
|
|
{
|
|
if ( !SDL_RWread(gd->src,rgb,sizeof(rgb),1) )
|
|
{
|
|
SDL_SetError( "bad colormap" );
|
|
return 1;
|
|
}
|
|
|
|
buffer[CM_RED][i] = rgb[0];
|
|
buffer[CM_GREEN][i] = rgb[1];
|
|
buffer[CM_BLUE][i] = rgb[2];
|
|
flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
static int DoExtension( gifdata* gd, int label )
|
|
{
|
|
unsigned char buf[256];
|
|
switch ( label )
|
|
{
|
|
case 0x01: /* Plain Text Extension */
|
|
break;
|
|
case 0xff: /* Application Extension */
|
|
if (GetDataBlock( gd, buf ) != 11)
|
|
break;
|
|
if (strncmp((char*)buf, "NETSCAPE2.0", 11))
|
|
break;
|
|
if (GetDataBlock( gd, buf ) != 3)
|
|
break;
|
|
if (buf[0] != 1)
|
|
break;
|
|
gd->loop = (unsigned int)buf[1] | (((unsigned int)buf[2]) << 8);
|
|
break;
|
|
case 0xfe: /* Comment Extension */
|
|
while ( GetDataBlock(gd,buf) != 0 )
|
|
;
|
|
return FALSE;
|
|
|
|
case 0xf9: /* Graphic Control Extension */
|
|
(void)GetDataBlock( gd, buf );
|
|
gd->g89.disposal = (buf[0] >> 2) & 0x7;
|
|
gd->g89.inputFlag = (buf[0] >> 1) & 0x1;
|
|
gd->g89.delayTime = LM_to_uint(buf[1],buf[2]);
|
|
if ( (buf[0] & 0x1) != 0 )
|
|
gd->g89.transparent = buf[3];
|
|
|
|
while ( GetDataBlock(gd,buf) != 0 )
|
|
;
|
|
return FALSE;
|
|
}
|
|
|
|
while ( GetDataBlock(gd,buf) != 0 )
|
|
;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
static int GetDataBlock( gifdata* gd, unsigned char* buf )
|
|
{
|
|
unsigned char count;
|
|
|
|
if ( !SDL_RWread(gd->src,&count,1,1) )
|
|
{
|
|
/* pm_message("error in getting DataBlock size" ); */
|
|
return -1;
|
|
}
|
|
|
|
gd->zerodatablock = count == 0;
|
|
|
|
if ( (count != 0) && !SDL_RWread(gd->src,buf,count,1) )
|
|
{
|
|
/* pm_message("error in reading DataBlock" ); */
|
|
return -1;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
|
|
static int GetCode( gifdata* gd, int code_size, int flag )
|
|
{
|
|
int i, j, ret;
|
|
int count;
|
|
|
|
if ( flag )
|
|
{
|
|
gd->curbit = 0;
|
|
gd->lastbit = 0;
|
|
gd->done = FALSE;
|
|
return 0;
|
|
}
|
|
|
|
if ( (gd->curbit + code_size) >= gd->lastbit )
|
|
{
|
|
if ( gd->done )
|
|
{
|
|
if ( gd->curbit >= gd->lastbit )
|
|
SDL_SetError( "ran off the end of my bits" );
|
|
return -1;
|
|
}
|
|
|
|
gd->buf[0] = gd->buf[gd->lastbyte - 2];
|
|
gd->buf[1] = gd->buf[gd->lastbyte - 1];
|
|
|
|
if ( (count = GetDataBlock(gd, &gd->buf[2])) == 0 )
|
|
gd->done = TRUE;
|
|
|
|
gd->lastbyte = 2 + count;
|
|
gd->curbit = (gd->curbit - gd->lastbit) + 16;
|
|
gd->lastbit = (2 + count)*8;
|
|
}
|
|
|
|
ret = 0;
|
|
for ( i = gd->curbit, j = 0; j < code_size; ++i, ++j )
|
|
ret |= ((gd->buf[i / 8] & (1 << (i % 8))) != 0) << j;
|
|
|
|
gd->curbit += code_size;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
static int LWZReadByte( gifdata* gd, int flag, int input_code_size )
|
|
{
|
|
int i, code, incode;
|
|
|
|
if ( flag )
|
|
{
|
|
gd->setcodesize = input_code_size;
|
|
gd->codesize = gd->setcodesize + 1;
|
|
gd->clearcode = 1 << gd->setcodesize;
|
|
gd->endcode = gd->clearcode + 1;
|
|
gd->maxcodesize = gd->clearcode*2;
|
|
gd->maxcode = gd->clearcode + 2;
|
|
|
|
GetCode( gd, 0, TRUE );
|
|
|
|
gd->fresh = TRUE;
|
|
|
|
for ( i = 0; i < gd->clearcode; ++i )
|
|
{
|
|
gd->table[0][i] = 0;
|
|
gd->table[1][i] = i;
|
|
}
|
|
|
|
for ( ; i < (1 << MAX_LWZ_BITS); ++i )
|
|
gd->table[0][i] = gd->table[1][0] = 0;
|
|
|
|
gd->sp = gd->stack;
|
|
return 0;
|
|
}
|
|
else if ( gd->fresh )
|
|
{
|
|
gd->fresh = FALSE;
|
|
do
|
|
{
|
|
gd->firstcode = gd->oldcode = GetCode( gd, gd->codesize, FALSE );
|
|
} while ( gd->firstcode == gd->clearcode );
|
|
return gd->firstcode;
|
|
}
|
|
|
|
if ( gd->sp > gd->stack )
|
|
return *--gd->sp;
|
|
|
|
while ( (code = GetCode(gd,gd->codesize,FALSE)) >= 0 )
|
|
{
|
|
if ( code == gd->clearcode )
|
|
{
|
|
for ( i = 0; i < gd->clearcode; ++i )
|
|
{
|
|
gd->table[0][i] = 0;
|
|
gd->table[1][i] = i;
|
|
}
|
|
|
|
for ( ; i < (1 << MAX_LWZ_BITS); ++i )
|
|
gd->table[0][i] = gd->table[1][i] = 0;
|
|
|
|
gd->codesize = gd->setcodesize + 1;
|
|
gd->maxcodesize = gd->clearcode*2;
|
|
gd->maxcode = gd->clearcode + 2;
|
|
gd->sp = gd->stack;
|
|
gd->firstcode = gd->oldcode = GetCode( gd, gd->codesize, FALSE );
|
|
return gd->firstcode;
|
|
}
|
|
else if ( code == gd->endcode )
|
|
{
|
|
int count;
|
|
unsigned char buf[260];
|
|
|
|
if ( gd->zerodatablock )
|
|
return -2;
|
|
|
|
while ( (count = GetDataBlock(gd,buf)) > 0 )
|
|
;
|
|
|
|
if ( count != 0 )
|
|
{
|
|
/* pm_message("missing EOD in data stream (common occurence)"); */
|
|
}
|
|
return -2;
|
|
}
|
|
|
|
incode = code;
|
|
|
|
if ( code >= gd->maxcode )
|
|
{
|
|
*gd->sp++ = gd->firstcode;
|
|
code = gd->oldcode;
|
|
}
|
|
|
|
while ( code >= gd->clearcode )
|
|
{
|
|
*gd->sp++ = gd->table[1][code];
|
|
if ( code == gd->table[0][code] )
|
|
SDL_SetError( "circular table entry BIG ERROR" );
|
|
code = gd->table[0][code];
|
|
}
|
|
|
|
*gd->sp++ = gd->firstcode = gd->table[1][code];
|
|
|
|
if ( (code = gd->maxcode) < (1 << MAX_LWZ_BITS) )
|
|
{
|
|
gd->table[0][code] = gd->oldcode;
|
|
gd->table[1][code] = gd->firstcode;
|
|
++gd->maxcode;
|
|
if ( (gd->maxcode >= gd->maxcodesize) && (gd->maxcodesize < (1 << MAX_LWZ_BITS)) )
|
|
{
|
|
gd->maxcodesize *= 2;
|
|
++gd->codesize;
|
|
}
|
|
}
|
|
|
|
gd->oldcode = incode;
|
|
|
|
if ( gd->sp > gd->stack )
|
|
return *--gd->sp;
|
|
}
|
|
|
|
return code;
|
|
}
|
|
|
|
|
|
|
|
static SDL_Surface* ReadImage( gifdata* gd, int len, int height, int cmapSize, unsigned char cmap[3][MAXCOLORMAPSIZE], int interlace, int ignore )
|
|
{
|
|
SDL_Surface* image;
|
|
unsigned char c;
|
|
int i, v;
|
|
int xpos = 0, ypos = 0, pass = 0;
|
|
|
|
/* Initialize the compression routines */
|
|
if ( !SDL_RWread(gd->src,&c,1,1) )
|
|
{
|
|
SDL_SetError( "EOF / read error on image data" );
|
|
return NULL;
|
|
}
|
|
|
|
if ( LWZReadByte(gd,TRUE,c) < 0 )
|
|
{
|
|
SDL_SetError( "error reading image" );
|
|
return NULL;
|
|
}
|
|
|
|
/* If this is an "uninteresting picture" ignore it. */
|
|
if ( ignore )
|
|
{
|
|
while ( LWZReadByte(gd,FALSE,c) >= 0 )
|
|
;
|
|
return NULL;
|
|
}
|
|
|
|
image = SDL_AllocSurface( SDL_SWSURFACE, len, height, 8, 0, 0, 0, 0 );
|
|
|
|
for ( i = 0; i < cmapSize; i++ )
|
|
{
|
|
image->format->palette->colors[i].r = cmap[CM_RED][i];
|
|
image->format->palette->colors[i].g = cmap[CM_GREEN][i];
|
|
image->format->palette->colors[i].b = cmap[CM_BLUE][i];
|
|
}
|
|
|
|
while ( (v = LWZReadByte(gd,FALSE,c)) >= 0 )
|
|
{
|
|
((Uint8*)image->pixels)[xpos + ypos*image->pitch] = (Uint8)v;
|
|
++xpos;
|
|
|
|
if ( xpos == len )
|
|
{
|
|
xpos = 0;
|
|
if ( interlace )
|
|
{
|
|
switch ( pass )
|
|
{
|
|
case 0:
|
|
case 1: ypos += 8; break;
|
|
case 2: ypos += 4; break;
|
|
case 3: ypos += 2; break;
|
|
}
|
|
|
|
if ( ypos >= height )
|
|
{
|
|
++pass;
|
|
switch ( pass )
|
|
{
|
|
case 1: ypos = 4; break;
|
|
case 2: ypos = 2; break;
|
|
case 3: ypos = 1; break;
|
|
default: goto fini;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
++ypos;
|
|
}
|
|
}
|
|
|
|
if ( ypos >= height )
|
|
break;
|
|
}
|
|
|
|
fini:
|
|
return image;
|
|
}
|
|
|