2006-04-13 20:47:06 +00:00
//-------------------------------------------------------------------------
/*
Copyright ( C ) 1996 , 2003 - 3 D Realms Entertainment
This file is part of Duke Nukem 3 D version 1.5 - Atomic Edition
Duke Nukem 3 D is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program 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 General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
Original Source : 1996 - Todd Replogle
Prepared for public release : 03 / 21 / 2003 - Charlie Wiederhold , 3 D Realms
Modifications for JonoF ' s port by Jonathon Fowler ( jonof @ edgenetwk . com )
*/
//-------------------------------------------------------------------------
# include "compat.h"
# include "animlib.h"
//****************************************************************************
//
// LOCALS
//
//****************************************************************************
2010-03-17 07:40:13 +00:00
# pragma pack(push,1)
/* structure declarations for deluxe animate large page files, doesn't
need to be in the header because there are no exposed functions
that use any of this directly */
2006-04-13 20:47:06 +00:00
2010-03-17 07:40:13 +00:00
typedef struct lpfileheaderstruct
{
uint32_t id ; /* 4 uint8_tacter ID == "LPF " */
uint16_t maxLps ; /* max # largePages allowed. 256 FOR NOW. */
uint16_t nLps ; /* # largePages in this file. */
uint32_t nRecords ; /* # records in this file. 65534 is current limit + ring */
uint16_t maxRecsPerLp ; /* # records permitted in an lp. 256 FOR NOW. */
uint16_t lpfTableOffset ; /* Absolute Seek position of lpfTable. 1280 FOR NOW. */
uint32_t contentType ; /* 4 character ID == "ANIM" */
uint16_t width ; /* Width of screen in pixels. */
uint16_t height ; /* Height of screen in pixels. */
uint8_t variant ; /* 0==ANIM. */
uint8_t version ; /* 0==frame rate in 18/sec, 1= 70/sec */
uint8_t hasLastDelta ; /* 1==Last record is a delta from last-to-first frame. */
uint8_t lastDeltaValid ; /* 0==Ignore ring frame. */
uint8_t pixelType ; /* 0==256 color. */
uint8_t CompressionType ; /* 1==(RunSkipDump) Only one used FOR NOW. */
uint8_t otherRecsPerFrm ; /* 0 FOR NOW. */
uint8_t bitmaptype ; /* 1==320x200, 256-color. Only one implemented so far. */
uint8_t recordTypes [ 32 ] ; /* Not yet implemented. */
uint32_t nFrames ; /* Number of actual frames in the file, includes ring frame. */
uint16_t framesPerSecond ; /* Number of frames to play per second. */
uint16_t pad2 [ 29 ] ; /* 58 bytes of filler to round up to 128 bytes total. */
}
lpfileheader ; /* (comments from original source) */
// this is the format of a large page structure
typedef struct
2008-06-29 10:41:01 +00:00
{
2010-03-17 07:40:13 +00:00
uint16_t baseRecord ; // Number of first record in this large page.
uint16_t nRecords ; // Number of records in lp.
// bit 15 of "nRecords" == "has continuation from previous lp".
// bit 14 of "nRecords" == "final record continues on next lp".
uint16_t nBytes ; // Total number of bytes of contents, excluding header.
} lp_descriptor ;
# pragma pack(pop)
# define IMAGEBUFFERSIZE 0x10000
typedef struct
{
uint16_t framecount ; // current frame of anim
lpfileheader * lpheader ; // file header will be loaded into this structure
lp_descriptor * LpArray ; // arrays of large page structs used to find frames
uint16_t curlpnum ; // initialize to an invalid Large page number
lp_descriptor * curlp ; // header of large page currently in memory
uint16_t * thepage ; // buffer where current large page is loaded
uint8_t imagebuffer [ IMAGEBUFFERSIZE ] ; // buffer where anim frame is decoded
uint8_t * buffer ;
uint8_t pal [ 768 ] ;
int32_t currentframe ;
} anim_t ;
static anim_t * anim = NULL ;
2010-03-15 00:06:48 +00:00
2006-04-13 20:47:06 +00:00
//****************************************************************************
//
// findpage ()
2010-03-17 07:40:13 +00:00
// - return the large page number a given frame resides in
2006-04-13 20:47:06 +00:00
//
//****************************************************************************
2010-03-17 07:40:13 +00:00
static inline uint16_t findpage ( uint16_t framenumber )
2008-06-29 10:41:01 +00:00
{
2010-03-15 00:06:48 +00:00
// curlpnum is initialized to 0xffff, obviously
uint16_t i = ( uint16_t ) ( anim - > curlpnum & ~ 0xffff ) ;
2010-03-17 07:40:13 +00:00
int32_t j = 0 ;
2010-03-15 00:06:48 +00:00
if ( framenumber < anim - > currentframe )
2010-03-17 07:40:13 +00:00
i = 0 , j + + ;
2010-03-15 00:06:48 +00:00
2010-03-17 07:40:13 +00:00
// this scans the last used page and higher first and then scans the
// previously accessed pages afterwards if it doesn't find anything
do
{
for ( ; i < anim - > lpheader - > nLps ; i + + )
if ( anim - > LpArray [ i ] . baseRecord < = framenumber & &
2010-03-15 00:06:48 +00:00
anim - > LpArray [ i ] . baseRecord + anim - > LpArray [ i ] . nRecords > framenumber )
2010-03-17 07:40:13 +00:00
return i ;
2010-03-15 00:06:48 +00:00
2010-03-17 07:40:13 +00:00
if ( ! j & & i = = anim - > lpheader - > nLps )
{
// handle out of order pages... I don't think any Duke .ANM files
// have them, but they're part of the file spec
i = 0 , j + + ;
continue ;
}
}
while ( 0 ) ;
return i ;
2008-06-29 10:41:01 +00:00
}
2006-04-13 20:47:06 +00:00
//****************************************************************************
//
// loadpage ()
2010-03-17 07:40:13 +00:00
// - seek out and set pointers to the large page specified
2006-04-13 20:47:06 +00:00
//
//****************************************************************************
2010-03-17 07:40:13 +00:00
static inline void loadpage ( uint16_t pagenumber , uint16_t * * pagepointer )
2008-06-29 10:41:01 +00:00
{
2010-03-15 00:06:48 +00:00
if ( anim - > curlpnum = = pagenumber )
return ;
2010-03-14 11:15:53 +00:00
2010-03-15 00:06:48 +00:00
anim - > curlp = & anim - > LpArray [ ( anim - > curlpnum = pagenumber ) ] ;
* pagepointer = ( uint16_t * ) ( anim - > buffer + 0xb00 + ( pagenumber * IMAGEBUFFERSIZE ) +
sizeof ( lp_descriptor ) + sizeof ( uint16_t ) ) ;
2008-06-29 10:41:01 +00:00
}
2006-04-13 20:47:06 +00:00
//****************************************************************************
//
2010-03-17 07:40:13 +00:00
// decodeframe ()
// - I found this less obfuscated version of the .ANM "decompressor",
// (c) 1998 "Jari Komppa aka Sol/Trauma". This code is public domain
// but has been mostly rewritten by me.
2010-03-15 00:06:48 +00:00
//
// - As a side note, it looks like this format came about in 1989 and
// never went anywhere after that, and appears to have been the format
// used by Electronic Arts' DeluxePaint Animation, which never made it
// past version 1.0.
2006-04-13 20:47:06 +00:00
//
//****************************************************************************
2010-03-17 07:40:13 +00:00
static void decodeframe ( uint8_t * srcP , uint8_t * dstP )
2008-06-29 10:41:01 +00:00
{
do
{
2010-03-17 07:40:13 +00:00
int32_t count = * srcP + + ;
2010-03-15 00:06:48 +00:00
2010-03-17 07:40:13 +00:00
if ( ! count ) /* Short RLE */
2010-03-15 00:06:48 +00:00
{
2010-03-17 07:40:13 +00:00
int32_t color = * ( srcP + 1 ) ;
count = * ( uint8_t * ) ( ( srcP + = sizeof ( int16_t ) ) - sizeof ( int16_t ) ) ;
Bmemset ( ( dstP + = count ) - count , color , count ) ;
continue ;
2010-03-15 00:06:48 +00:00
}
2010-03-17 07:40:13 +00:00
else if ( ( count & 0x80 ) = = 0 ) /* Short copy */
2010-03-15 00:06:48 +00:00
{
2010-03-17 07:40:13 +00:00
Bmemcpy ( ( dstP + = count ) - count , ( srcP + = count ) - count , count ) ;
continue ;
2010-03-15 00:06:48 +00:00
}
2010-03-17 07:40:13 +00:00
else if ( ( count & = ~ 0x80 ) > 0 ) /* short skip */
2010-03-15 00:06:48 +00:00
{
2010-03-17 07:40:13 +00:00
dstP + = count ;
continue ;
2010-03-15 00:06:48 +00:00
}
2010-03-17 07:40:13 +00:00
/* long op */
count = B_LITTLE16 ( * ( ( uint16_t * ) ( ( srcP + = sizeof ( int16_t ) ) - sizeof ( int16_t ) ) ) ) ;
if ( ! count ) /* stop sign */
return ;
else if ( ( count & 0x8000 ) = = 0 ) /* long skip */
{
dstP + = count ;
continue ;
}
else if ( ( count & = ~ 0x8000 ) & 0x4000 ) /* long RLE */
{
int32_t color = * srcP + + ;
count & = ~ 0x4000 ;
Bmemset ( ( dstP + = count ) - count , color , count ) ;
continue ;
}
/* long copy */
Bmemcpy ( ( dstP + = count ) - count , ( srcP + = count ) - count , count ) ;
2008-06-29 10:41:01 +00:00
}
2010-03-15 00:06:48 +00:00
while ( 1 ) ;
2008-06-29 10:41:01 +00:00
}
2006-04-13 20:47:06 +00:00
//****************************************************************************
//
// renderframe ()
// - draw the frame sepcified from the large page in the buffer pointed to
//
//****************************************************************************
2010-03-17 07:40:13 +00:00
static void renderframe ( uint16_t framenumber , uint16_t * pagepointer )
2008-06-29 10:41:01 +00:00
{
2009-04-26 05:57:42 +00:00
uint8_t * ppointer ;
2010-03-17 07:40:13 +00:00
uint16_t offset = 0 ;
uint16_t frame = framenumber - anim - > curlp - > baseRecord ;
2006-04-13 20:47:06 +00:00
2010-03-17 07:40:13 +00:00
while ( frame - - ) offset + = B_LITTLE16 ( pagepointer [ frame ] ) ;
2010-03-14 11:15:53 +00:00
2010-03-17 07:40:13 +00:00
ppointer = ( uint8_t * ) ( pagepointer ) + anim - > curlp - > nRecords * 2 + offset + 4 ;
2006-04-13 20:47:06 +00:00
2010-03-17 07:40:13 +00:00
if ( ( ppointer - 4 ) [ 1 ] )
ppointer + = B_LITTLE16 ( ( ( uint16_t * ) ( ppointer - 4 ) ) [ 1 ] ) + ( B_LITTLE16 ( ( ( uint16_t * ) ( ppointer - 4 ) ) [ 1 ] ) & 1 ) ;
2006-04-13 20:47:06 +00:00
2010-03-17 07:40:13 +00:00
decodeframe ( ( uint8_t * ) ppointer , ( uint8_t * ) anim - > imagebuffer ) ;
2008-06-29 10:41:01 +00:00
}
2006-04-13 20:47:06 +00:00
//****************************************************************************
//
// drawframe ()
// - high level frame draw routine
//
//****************************************************************************
2010-03-17 07:40:13 +00:00
static inline void drawframe ( uint16_t framenumber )
2008-06-29 10:41:01 +00:00
{
2010-03-14 11:15:53 +00:00
loadpage ( findpage ( framenumber ) , & anim - > thepage ) ;
2008-06-29 10:41:01 +00:00
renderframe ( framenumber , anim - > thepage ) ;
}
2006-04-13 20:47:06 +00:00
2008-06-29 10:41:01 +00:00
void ANIM_LoadAnim ( char * buffer )
{
2009-04-26 05:57:42 +00:00
uint16_t i ;
2008-06-29 10:41:01 +00:00
2010-03-17 07:40:13 +00:00
anim = Brealloc ( anim , sizeof ( anim_t ) ) ;
2008-06-29 10:41:01 +00:00
anim - > curlpnum = 0xffff ;
anim - > currentframe = - 1 ;
2010-03-17 07:40:13 +00:00
// this just modifies the data in-place instead of copying it elsewhere now
anim - > lpheader = ( lpfileheader * ) ( anim - > buffer = ( uint8_t * ) buffer ) ;
anim - > lpheader - > id = B_LITTLE32 ( anim - > lpheader - > id ) ;
anim - > lpheader - > maxLps = B_LITTLE16 ( anim - > lpheader - > maxLps ) ;
anim - > lpheader - > nLps = B_LITTLE16 ( anim - > lpheader - > nLps ) ;
anim - > lpheader - > nRecords = B_LITTLE32 ( anim - > lpheader - > nRecords ) ;
anim - > lpheader - > maxRecsPerLp = B_LITTLE16 ( anim - > lpheader - > maxRecsPerLp ) ;
anim - > lpheader - > lpfTableOffset = B_LITTLE16 ( anim - > lpheader - > lpfTableOffset ) ;
anim - > lpheader - > contentType = B_LITTLE32 ( anim - > lpheader - > contentType ) ;
anim - > lpheader - > width = B_LITTLE16 ( anim - > lpheader - > width ) ;
anim - > lpheader - > height = B_LITTLE16 ( anim - > lpheader - > height ) ;
anim - > lpheader - > nFrames = B_LITTLE32 ( anim - > lpheader - > nFrames ) ;
anim - > lpheader - > framesPerSecond = B_LITTLE16 ( anim - > lpheader - > framesPerSecond ) ;
2008-06-29 10:41:01 +00:00
2010-03-14 11:42:13 +00:00
buffer + = sizeof ( lpfileheader ) + 128 ;
2010-03-17 07:40:13 +00:00
2008-06-29 10:41:01 +00:00
// load the color palette
for ( i = 0 ; i < 768 ; i + = 3 )
{
2010-03-14 11:42:13 +00:00
anim - > pal [ i + 2 ] = ( * buffer + + ) > > 2 ;
anim - > pal [ i + 1 ] = ( * buffer + + ) > > 2 ;
anim - > pal [ i ] = ( * buffer + + ) > > 2 ;
2008-06-29 10:41:01 +00:00
buffer + + ;
}
2010-03-15 00:06:48 +00:00
2010-03-17 07:40:13 +00:00
// set up large page descriptors
anim - > LpArray = ( lp_descriptor * ) buffer ;
2008-06-29 10:41:01 +00:00
2010-03-17 07:40:13 +00:00
// theoretically we should be able to play files with more than 256 frames now
// assuming the utilities to create them can make them that way
for ( i = anim - > lpheader - > nLps - 1 ; i ! = 0 ; i - - )
2008-06-29 10:41:01 +00:00
{
anim - > LpArray [ i ] . baseRecord = B_LITTLE16 ( anim - > LpArray [ i ] . baseRecord ) ;
anim - > LpArray [ i ] . nRecords = B_LITTLE16 ( anim - > LpArray [ i ] . nRecords ) ;
anim - > LpArray [ i ] . nBytes = B_LITTLE16 ( anim - > LpArray [ i ] . nBytes ) ;
}
}
2006-04-13 20:47:06 +00:00
2008-06-29 10:41:01 +00:00
void ANIM_FreeAnim ( void )
{
2010-03-17 07:40:13 +00:00
if ( anim ! = NULL )
2008-06-29 10:41:01 +00:00
{
2009-10-07 06:47:35 +00:00
Bfree ( anim ) ;
2010-03-17 07:40:13 +00:00
anim = NULL ;
2008-06-29 10:41:01 +00:00
}
}
2006-04-13 20:47:06 +00:00
2009-04-26 05:57:42 +00:00
int32_t ANIM_NumFrames ( void )
2008-06-29 10:41:01 +00:00
{
2010-03-17 07:40:13 +00:00
return anim - > lpheader - > nRecords ;
2008-06-29 10:41:01 +00:00
}
2006-04-13 20:47:06 +00:00
2009-04-26 05:57:42 +00:00
uint8_t * ANIM_DrawFrame ( int32_t framenumber )
2008-06-29 10:41:01 +00:00
{
2010-03-17 07:40:13 +00:00
int32_t cnt = anim - > currentframe ;
2008-06-29 10:41:01 +00:00
2010-03-17 07:40:13 +00:00
// handle first play and looping or rewinding
if ( cnt < 0 | | cnt > framenumber )
cnt = 0 ;
do drawframe ( cnt + + ) ;
while ( cnt < framenumber ) ;
2008-06-29 10:41:01 +00:00
anim - > currentframe = framenumber ;
return anim - > imagebuffer ;
}
2006-04-13 20:47:06 +00:00
2009-04-26 05:57:42 +00:00
uint8_t * ANIM_GetPalette ( void )
2008-06-29 10:41:01 +00:00
{
return anim - > pal ;
}