2011-12-29 20:06:31 -06:00
# include <bzlib.h>
# include "defines.h"
# include "powder.h"
# include "save.h"
# include "gravity.h"
# include "BSON.h"
2011-12-30 13:48:11 -06:00
//Pop
pixel * prerender_save ( void * save , int size , int * width , int * height )
{
unsigned char * saveData = save ;
2012-01-04 07:45:36 -06:00
if ( size < 16 )
{
return NULL ;
}
2011-12-30 13:48:11 -06:00
if ( saveData [ 0 ] = = ' O ' & & saveData [ 1 ] = = ' P ' & & saveData [ 2 ] = = ' S ' )
{
return prerender_save_OPS ( save , size , width , height ) ;
}
else if ( ( saveData [ 0 ] = = 0x66 & & saveData [ 1 ] = = 0x75 & & saveData [ 2 ] = = 0x43 ) | | ( saveData [ 0 ] = = 0x50 & & saveData [ 1 ] = = 0x53 & & saveData [ 2 ] = = 0x76 ) )
{
return prerender_save_PSv ( save , size , width , height ) ;
}
}
2011-12-29 20:06:31 -06:00
void * build_save ( int * size , int orig_x0 , int orig_y0 , int orig_w , int orig_h , unsigned char bmap [ YRES / CELL ] [ XRES / CELL ] , float vx [ YRES / CELL ] [ XRES / CELL ] , float vy [ YRES / CELL ] [ XRES / CELL ] , float pv [ YRES / CELL ] [ XRES / CELL ] , float fvx [ YRES / CELL ] [ XRES / CELL ] , float fvy [ YRES / CELL ] [ XRES / CELL ] , sign signs [ MAXSIGNS ] , void * partsptr )
{
2011-12-29 20:10:27 -06:00
# ifdef SAVE_OPS
2011-12-29 20:06:31 -06:00
return build_save_OPS ( size , orig_x0 , orig_y0 , orig_w , orig_h , bmap , vx , vy , pv , fvx , fvy , signs , partsptr ) ;
2011-12-29 20:10:27 -06:00
# else
return build_save_PSv ( size , orig_x0 , orig_y0 , orig_w , orig_h , bmap , fvx , fvy , signs , partsptr ) ;
# endif
2011-12-29 20:06:31 -06:00
}
int parse_save ( void * save , int size , int replace , int x0 , int y0 , unsigned char bmap [ YRES / CELL ] [ XRES / CELL ] , float vx [ YRES / CELL ] [ XRES / CELL ] , float vy [ YRES / CELL ] [ XRES / CELL ] , float pv [ YRES / CELL ] [ XRES / CELL ] , float fvx [ YRES / CELL ] [ XRES / CELL ] , float fvy [ YRES / CELL ] [ XRES / CELL ] , sign signs [ MAXSIGNS ] , void * partsptr , unsigned pmap [ YRES ] [ XRES ] )
{
unsigned char * saveData = save ;
2012-01-04 07:45:36 -06:00
if ( size < 16 )
{
return 1 ;
}
2011-12-29 20:06:31 -06:00
if ( saveData [ 0 ] = = ' O ' & & saveData [ 1 ] = = ' P ' & & saveData [ 2 ] = = ' S ' )
{
return parse_save_OPS ( save , size , replace , x0 , y0 , bmap , vx , vy , pv , fvx , fvy , signs , partsptr , pmap ) ;
}
else if ( ( saveData [ 0 ] = = 0x66 & & saveData [ 1 ] = = 0x75 & & saveData [ 2 ] = = 0x43 ) | | ( saveData [ 0 ] = = 0x50 & & saveData [ 1 ] = = 0x53 & & saveData [ 2 ] = = 0x76 ) )
{
return parse_save_PSv ( save , size , replace , x0 , y0 , bmap , fvx , fvy , signs , partsptr , pmap ) ;
}
}
2011-12-30 13:48:11 -06:00
pixel * prerender_save_OPS ( void * save , int size , int * width , int * height )
{
2012-01-01 08:35:37 -06:00
unsigned char * inputData = save , * bsonData = NULL , * partsData = NULL , * partsPosData = NULL , * wallData = NULL ;
int inputDataLen = size , bsonDataLen = 0 , partsDataLen , partsPosDataLen , wallDataLen ;
int i , x , y , j ;
int blockX , blockY , blockW , blockH , fullX , fullY , fullW , fullH ;
pixel * vidBuf = NULL ;
2011-12-30 13:48:11 -06:00
//Block sizes
2012-01-01 08:35:37 -06:00
blockX = 0 ;
blockY = 0 ;
2011-12-30 13:48:11 -06:00
blockW = inputData [ 6 ] ;
blockH = inputData [ 7 ] ;
//Full size, normalised
2012-01-01 08:35:37 -06:00
fullX = 0 ;
fullY = 0 ;
2011-12-30 13:48:11 -06:00
fullW = blockW * CELL ;
fullH = blockH * CELL ;
2012-01-01 08:35:37 -06:00
//
* width = fullW ;
* height = fullH ;
2011-12-30 13:48:11 -06:00
//From newer version
if ( inputData [ 4 ] > SAVE_VERSION )
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Save from newer version \n " ) ;
goto fail ;
2011-12-30 13:48:11 -06:00
}
//Incompatible cell size
if ( inputData [ 5 ] > CELL )
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Cell size mismatch \n " ) ;
goto fail ;
2011-12-30 13:48:11 -06:00
}
//Too large/off screen
2012-01-01 08:35:37 -06:00
if ( blockX + blockW > XRES / CELL | | blockY + blockH > YRES / CELL )
2011-12-30 13:48:11 -06:00
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Save too large \n " ) ;
goto fail ;
}
bsonDataLen = ( ( unsigned ) inputData [ 8 ] ) ;
bsonDataLen | = ( ( unsigned ) inputData [ 9 ] ) < < 8 ;
bsonDataLen | = ( ( unsigned ) inputData [ 10 ] ) < < 16 ;
bsonDataLen | = ( ( unsigned ) inputData [ 11 ] ) < < 24 ;
bsonData = malloc ( bsonDataLen + 1 ) ;
if ( ! bsonData )
{
fprintf ( stderr , " Internal error while parsing save: could not allocate buffer \n " ) ;
goto fail ;
}
//Make sure bsonData is null terminated, since all string functions need null terminated strings
//(bson_iterator_key returns a pointer into bsonData, which is then used with strcmp)
bsonData [ bsonDataLen ] = 0 ;
if ( BZ2_bzBuffToBuffDecompress ( bsonData , & bsonDataLen , inputData + 12 , inputDataLen - 12 , 0 , 0 ) )
{
fprintf ( stderr , " Unable to decompress \n " ) ;
goto fail ;
2011-12-30 13:48:11 -06:00
}
2012-01-01 08:35:37 -06:00
bson b ;
bson_iterator iter ;
bson_init_data ( & b , bsonData ) ;
bson_iterator_init ( & iter , & b ) ;
while ( bson_iterator_next ( & iter ) )
{
if ( strcmp ( bson_iterator_key ( & iter ) , " parts " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_BINDATA & & ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER & & ( partsDataLen = bson_iterator_bin_len ( & iter ) ) > 0 )
{
partsData = bson_iterator_bin_data ( & iter ) ;
}
else
{
fprintf ( stderr , " Invalid datatype of particle data: %d[%d] %d[%d] %d[%d] \n " , bson_iterator_type ( & iter ) , bson_iterator_type ( & iter ) = = BSON_BINDATA , ( unsigned char ) bson_iterator_bin_type ( & iter ) , ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER , bson_iterator_bin_len ( & iter ) , bson_iterator_bin_len ( & iter ) > 0 ) ;
}
}
if ( strcmp ( bson_iterator_key ( & iter ) , " partsPos " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_BINDATA & & ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER & & ( partsPosDataLen = bson_iterator_bin_len ( & iter ) ) > 0 )
{
partsPosData = bson_iterator_bin_data ( & iter ) ;
}
else
{
fprintf ( stderr , " Invalid datatype of particle position data: %d[%d] %d[%d] %d[%d] \n " , bson_iterator_type ( & iter ) , bson_iterator_type ( & iter ) = = BSON_BINDATA , ( unsigned char ) bson_iterator_bin_type ( & iter ) , ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER , bson_iterator_bin_len ( & iter ) , bson_iterator_bin_len ( & iter ) > 0 ) ;
}
}
else if ( strcmp ( bson_iterator_key ( & iter ) , " wallMap " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_BINDATA & & ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER & & ( wallDataLen = bson_iterator_bin_len ( & iter ) ) > 0 )
{
wallData = bson_iterator_bin_data ( & iter ) ;
}
else
{
fprintf ( stderr , " Invalid datatype of wall data: %d[%d] %d[%d] %d[%d] \n " , bson_iterator_type ( & iter ) , bson_iterator_type ( & iter ) = = BSON_BINDATA , ( unsigned char ) bson_iterator_bin_type ( & iter ) , ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER , bson_iterator_bin_len ( & iter ) , bson_iterator_bin_len ( & iter ) > 0 ) ;
}
}
}
vidBuf = calloc ( fullW * fullH , PIXELSIZE ) ;
//Read wall and fan data
if ( wallData )
{
if ( blockW * blockH > wallDataLen )
{
fprintf ( stderr , " Not enough wall data \n " ) ;
goto fail ;
}
for ( x = 0 ; x < blockW ; x + + )
{
for ( y = 0 ; y < blockH ; y + + )
{
if ( wallData [ y * blockW + x ] )
{
for ( i = 0 ; i < CELL ; i + + )
{
for ( j = 0 ; j < CELL ; j + + )
{
vidBuf [ ( fullY + i + ( y * CELL ) ) * fullW + ( fullX + j + ( x * CELL ) ) ] = PIXPACK ( 0xCCCCCC ) ;
}
}
} ;
}
}
}
2011-12-30 13:48:11 -06:00
2012-01-01 08:35:37 -06:00
//Read particle data
if ( partsData & & partsPosData )
{
int fieldDescriptor ;
int posCount , posTotal , partsPosDataIndex = 0 ;
int saved_x , saved_y ;
if ( fullW * fullH * 3 > partsPosDataLen )
{
fprintf ( stderr , " Not enough particle position data \n " ) ;
goto fail ;
}
i = 0 ;
for ( saved_y = 0 ; saved_y < fullH ; saved_y + + )
{
for ( saved_x = 0 ; saved_x < fullW ; saved_x + + )
{
//Read total number of particles at this position
posTotal = 0 ;
posTotal | = partsPosData [ partsPosDataIndex + + ] < < 16 ;
posTotal | = partsPosData [ partsPosDataIndex + + ] < < 8 ;
posTotal | = partsPosData [ partsPosDataIndex + + ] ;
//Put the next posTotal particles at this position
for ( posCount = 0 ; posCount < posTotal ; posCount + + )
{
//i+3 because we have 4 bytes of required fields (type (1), descriptor (2), temp (1))
if ( i + 3 > = partsDataLen )
goto fail ;
x = saved_x + fullX ;
y = saved_y + fullY ;
fieldDescriptor = partsData [ i + 1 ] ;
fieldDescriptor | = partsData [ i + 2 ] < < 8 ;
if ( x > = XRES | | x < 0 | | y > = YRES | | y < 0 )
{
fprintf ( stderr , " Out of range [%d]: %d %d, [%d, %d], [%d, %d] \n " , i , x , y , ( unsigned ) partsData [ i + 1 ] , ( unsigned ) partsData [ i + 2 ] , ( unsigned ) partsData [ i + 3 ] , ( unsigned ) partsData [ i + 4 ] ) ;
goto fail ;
}
if ( partsData [ i ] > = PT_NUM )
partsData [ i ] = PT_DMND ; //Replace all invalid powders with diamond
//Draw type
vidBuf [ ( fullY + y ) * fullW + ( fullX + x ) ] = ptypes [ partsData [ i ] ] . pcolors ;
i + = 3 ; //Skip Type an Descriptor
//Skip temp
if ( fieldDescriptor & 0x01 )
{
i + = 2 ;
}
else
{
i + + ;
}
//Skip life
if ( fieldDescriptor & 0x02 )
{
if ( i + + > = partsDataLen ) goto fail ;
if ( fieldDescriptor & 0x04 )
{
if ( i + + > = partsDataLen ) goto fail ;
}
}
//Skip tmp
if ( fieldDescriptor & 0x08 )
{
if ( i + + > = partsDataLen ) goto fail ;
if ( fieldDescriptor & 0x10 )
{
if ( i + + > = partsDataLen ) goto fail ;
}
}
//Skip ctype
if ( fieldDescriptor & 0x20 )
{
if ( i + + > = partsDataLen ) goto fail ;
2012-01-04 08:29:22 -06:00
if ( fieldDescriptor & 0x200 )
{
if ( i + 2 > = partsDataLen ) goto fail ;
i + = 3 ;
}
2012-01-01 08:35:37 -06:00
}
//Skip dcolour
if ( fieldDescriptor & 0x40 )
{
if ( i + 3 > = partsDataLen ) goto fail ;
i + = 4 ;
}
//Read vx
if ( fieldDescriptor & 0x80 )
{
if ( i + + > = partsDataLen ) goto fail ;
}
//Read vy
if ( fieldDescriptor & 0x100 )
{
if ( i + + > = partsDataLen ) goto fail ;
}
}
}
}
}
goto fin ;
fail :
if ( vidBuf )
{
free ( vidBuf ) ;
vidBuf = NULL ;
}
fin :
bson_destroy ( & b ) ;
return vidBuf ;
2011-12-30 13:48:11 -06:00
}
2011-12-29 20:06:31 -06:00
void * build_save_OPS ( int * size , int orig_x0 , int orig_y0 , int orig_w , int orig_h , unsigned char bmap [ YRES / CELL ] [ XRES / CELL ] , float vx [ YRES / CELL ] [ XRES / CELL ] , float vy [ YRES / CELL ] [ XRES / CELL ] , float pv [ YRES / CELL ] [ XRES / CELL ] , float fvx [ YRES / CELL ] [ XRES / CELL ] , float fvy [ YRES / CELL ] [ XRES / CELL ] , sign signs [ MAXSIGNS ] , void * o_partsptr )
{
particle * partsptr = o_partsptr ;
2011-12-31 10:49:18 -06:00
unsigned char * partsData = NULL , * partsPosData = NULL , * fanData = NULL , * wallData = NULL , * finalData = NULL , * outputData = NULL ;
unsigned * partsPosLink = NULL , * partsPosFirstMap = NULL , * partsPosCount = NULL , * partsPosLastMap = NULL ;
int partsDataLen , partsPosDataLen , fanDataLen , wallDataLen , finalDataLen , outputDataLen ;
2011-12-29 20:06:31 -06:00
int blockX , blockY , blockW , blockH , fullX , fullY , fullW , fullH ;
int x , y , i , wallDataFound = 0 ;
2011-12-31 12:57:42 -06:00
int posCount , signsCount ;
2011-12-29 20:06:31 -06:00
//Get coords in blocks
blockX = orig_x0 / CELL ;
blockY = orig_y0 / CELL ;
2011-12-31 10:49:18 -06:00
2011-12-29 20:06:31 -06:00
//Snap full coords to block size
fullX = blockX * CELL ;
fullY = blockY * CELL ;
2011-12-31 10:49:18 -06:00
//Original size + offset of original corner from snapped corner, rounded up by adding CELL-1
blockW = ( orig_w + orig_x0 - fullX + CELL - 1 ) / CELL ;
blockH = ( orig_h + orig_y0 - fullY + CELL - 1 ) / CELL ;
2011-12-29 20:06:31 -06:00
fullW = blockW * CELL ;
fullH = blockH * CELL ;
//Copy fan and wall data
wallData = malloc ( blockW * blockH ) ;
wallDataLen = blockW * blockH ;
2011-12-30 13:48:11 -06:00
fanData = malloc ( ( blockW * blockH ) * 2 ) ;
2011-12-29 20:06:31 -06:00
fanDataLen = 0 ;
for ( x = blockX ; x < blockX + blockW ; x + + )
{
for ( y = blockY ; y < blockY + blockH ; y + + )
{
2011-12-30 13:48:11 -06:00
wallData [ ( y - blockY ) * blockW + ( x - blockX ) ] = bmap [ y ] [ x ] ;
2011-12-29 20:06:31 -06:00
if ( bmap [ y ] [ x ] & & ! wallDataFound )
wallDataFound = 1 ;
if ( bmap [ y ] [ x ] = = WL_FAN | | bmap [ y ] [ x ] = = 4 )
{
2011-12-30 13:48:11 -06:00
i = ( int ) ( fvx [ y ] [ x ] * 64.0f + 127.5f ) ;
if ( i < 0 ) i = 0 ;
if ( i > 255 ) i = 255 ;
fanData [ fanDataLen + + ] = i ;
2011-12-29 20:06:31 -06:00
i = ( int ) ( fvy [ y ] [ x ] * 64.0f + 127.5f ) ;
if ( i < 0 ) i = 0 ;
if ( i > 255 ) i = 255 ;
fanData [ fanDataLen + + ] = i ;
}
}
}
if ( ! fanDataLen )
{
free ( fanData ) ;
fanData = NULL ;
}
if ( ! wallDataFound )
{
free ( wallData ) ;
wallData = NULL ;
}
2011-12-31 10:49:18 -06:00
//Index positions of all particles, using linked lists
//partsPosFirstMap is pmap for the first particle in each position
//partsPosLastMap is pmap for the last particle in each position
//partsPosCount is the number of particles in each position
//partsPosLink contains, for each particle, (i<<8)|1 of the next particle in the same position
partsPosFirstMap = calloc ( fullW * fullH , sizeof ( unsigned ) ) ;
partsPosLastMap = calloc ( fullW * fullH , sizeof ( unsigned ) ) ;
partsPosCount = calloc ( fullW * fullH , sizeof ( unsigned ) ) ;
partsPosLink = calloc ( NPART , sizeof ( unsigned ) ) ;
for ( i = 0 ; i < NPART ; i + + )
{
if ( partsptr [ i ] . type )
{
x = ( int ) ( partsptr [ i ] . x + 0.5f ) ;
y = ( int ) ( partsptr [ i ] . y + 0.5f ) ;
if ( x > = orig_x0 & & x < orig_x0 + orig_w & & y > = orig_y0 & & y < orig_y0 + orig_h )
{
//Coordinates relative to top left corner of saved area
x - = fullX ;
y - = fullY ;
if ( ! partsPosFirstMap [ y * fullW + x ] )
{
//First entry in list
partsPosFirstMap [ y * fullW + x ] = ( i < < 8 ) | 1 ;
partsPosLastMap [ y * fullW + x ] = ( i < < 8 ) | 1 ;
}
else
{
//Add to end of list
partsPosLink [ partsPosLastMap [ y * fullW + x ] > > 8 ] = ( i < < 8 ) | 1 ; //link to current end of list
partsPosLastMap [ y * fullW + x ] = ( i < < 8 ) | 1 ; //set as new end of list
}
partsPosCount [ y * fullW + x ] + + ;
}
}
}
//Store number of particles in each position
partsPosData = malloc ( fullW * fullH * 3 ) ;
partsPosDataLen = 0 ;
for ( y = 0 ; y < fullH ; y + + )
{
for ( x = 0 ; x < fullW ; x + + )
{
posCount = partsPosCount [ y * fullW + x ] ;
partsPosData [ partsPosDataLen + + ] = ( posCount & 0x00FF0000 ) > > 16 ;
partsPosData [ partsPosDataLen + + ] = ( posCount & 0x0000FF00 ) > > 8 ;
partsPosData [ partsPosDataLen + + ] = ( posCount & 0x000000FF ) ;
}
}
2011-12-29 20:06:31 -06:00
//Copy parts data
/* Field descriptor format:
2011-12-31 12:57:42 -06:00
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| vy | vx | dcololour | ctype | tmp [ 2 ] | tmp [ 1 ] | life [ 2 ] | life [ 1 ] | temp dbl len |
2011-12-29 20:06:31 -06:00
life [ 2 ] means a second byte ( for a 16 bit field ) if life [ 1 ] is present
*/
partsData = malloc ( NPART * ( sizeof ( particle ) + 1 ) ) ;
partsDataLen = 0 ;
2011-12-31 10:49:18 -06:00
for ( y = 0 ; y < fullH ; y + + )
2011-12-29 20:06:31 -06:00
{
2011-12-31 10:49:18 -06:00
for ( x = 0 ; x < fullW ; x + + )
2011-12-29 20:06:31 -06:00
{
2011-12-31 10:49:18 -06:00
//Find the first particle in this position
i = partsPosFirstMap [ y * fullW + x ] ;
//Loop while there is a pmap entry
while ( i )
2011-12-29 20:06:31 -06:00
{
2011-12-31 12:57:42 -06:00
unsigned short fieldDesc = 0 ;
2011-12-29 20:06:31 -06:00
int fieldDescLoc = 0 , tempTemp , vTemp ;
2011-12-31 10:49:18 -06:00
//Turn pmap entry into a partsptr index
i = i > > 8 ;
2011-12-29 20:06:31 -06:00
//Type (required)
partsData [ partsDataLen + + ] = partsptr [ i ] . type ;
//Location of the field descriptor
fieldDescLoc = partsDataLen + + ;
2011-12-31 12:57:42 -06:00
partsDataLen + + ;
//Extra Temperature (2nd byte optional, 1st required), 1 to 2 bytes
//Store temperature as an offset of 21C(294.15K) or go into a 16byte int and store the whole thing
if ( fabs ( partsptr [ i ] . temp - 294.15f ) < 127 )
{
tempTemp = ( partsptr [ i ] . temp - 294.15f ) ;
partsData [ partsDataLen + + ] = tempTemp ;
}
else
{
fieldDesc | = 1 ;
tempTemp = partsptr [ i ] . temp ;
partsData [ partsDataLen + + ] = tempTemp ;
partsData [ partsDataLen + + ] = tempTemp > > 8 ;
}
2011-12-29 20:06:31 -06:00
//Life (optional), 1 to 2 bytes
if ( partsptr [ i ] . life )
{
2011-12-31 12:57:42 -06:00
fieldDesc | = 1 < < 1 ;
2011-12-29 20:06:31 -06:00
partsData [ partsDataLen + + ] = partsptr [ i ] . life ;
if ( partsptr [ i ] . life > 255 )
{
2011-12-31 12:57:42 -06:00
fieldDesc | = 1 < < 2 ;
2011-12-29 20:06:31 -06:00
partsData [ partsDataLen + + ] = partsptr [ i ] . life > > 8 ;
}
}
//Tmp (optional), 1 to 2 bytes
if ( partsptr [ i ] . tmp )
{
2011-12-31 12:57:42 -06:00
fieldDesc | = 1 < < 3 ;
2011-12-29 20:06:31 -06:00
partsData [ partsDataLen + + ] = partsptr [ i ] . tmp ;
if ( partsptr [ i ] . tmp > 255 )
{
2011-12-31 12:57:42 -06:00
fieldDesc | = 1 < < 4 ;
2011-12-29 20:06:31 -06:00
partsData [ partsDataLen + + ] = partsptr [ i ] . tmp > > 8 ;
}
}
2012-01-04 08:29:22 -06:00
//Ctype (optional), 1 or 4 bytes
2011-12-29 20:06:31 -06:00
if ( partsptr [ i ] . ctype )
{
2011-12-31 12:57:42 -06:00
fieldDesc | = 1 < < 5 ;
2011-12-29 20:06:31 -06:00
partsData [ partsDataLen + + ] = partsptr [ i ] . ctype ;
2012-01-04 08:29:22 -06:00
if ( partsptr [ i ] . ctype > 255 )
{
fieldDesc | = 1 < < 9 ;
partsData [ partsDataLen + + ] = ( partsptr [ i ] . ctype & 0xFF000000 ) > > 24 ;
partsData [ partsDataLen + + ] = ( partsptr [ i ] . ctype & 0x00FF0000 ) > > 16 ;
partsData [ partsDataLen + + ] = ( partsptr [ i ] . ctype & 0x0000FF00 ) > > 8 ;
}
2011-12-29 20:06:31 -06:00
}
//Dcolour (optional), 4 bytes
if ( partsptr [ i ] . dcolour & & ( partsptr [ i ] . dcolour & 0xFF000000 ) )
{
2011-12-31 12:57:42 -06:00
fieldDesc | = 1 < < 6 ;
2011-12-29 20:06:31 -06:00
partsData [ partsDataLen + + ] = ( partsptr [ i ] . dcolour & 0xFF000000 ) > > 24 ;
partsData [ partsDataLen + + ] = ( partsptr [ i ] . dcolour & 0x00FF0000 ) > > 16 ;
partsData [ partsDataLen + + ] = ( partsptr [ i ] . dcolour & 0x0000FF00 ) > > 8 ;
partsData [ partsDataLen + + ] = ( partsptr [ i ] . dcolour & 0x000000FF ) ;
}
//VX (optional), 1 byte
if ( fabs ( partsptr [ i ] . vx ) > 0.001f )
{
2011-12-31 12:57:42 -06:00
fieldDesc | = 1 < < 7 ;
2011-12-29 20:06:31 -06:00
vTemp = ( int ) ( partsptr [ i ] . vx * 16.0f + 127.5f ) ;
if ( vTemp < 0 ) vTemp = 0 ;
if ( vTemp > 255 ) vTemp = 255 ;
partsData [ partsDataLen + + ] = vTemp ;
}
//VY (optional), 1 byte
if ( fabs ( partsptr [ i ] . vy ) > 0.001f )
{
2011-12-31 12:57:42 -06:00
fieldDesc | = 1 < < 8 ;
2011-12-29 20:06:31 -06:00
vTemp = ( int ) ( partsptr [ i ] . vy * 16.0f + 127.5f ) ;
if ( vTemp < 0 ) vTemp = 0 ;
if ( vTemp > 255 ) vTemp = 255 ;
partsData [ partsDataLen + + ] = vTemp ;
}
//Write the field descriptor;
partsData [ fieldDescLoc ] = fieldDesc ;
2011-12-31 12:57:42 -06:00
partsData [ fieldDescLoc + 1 ] = fieldDesc > > 8 ;
2011-12-31 10:49:18 -06:00
//Get the pmap entry for the next particle in the same position
i = partsPosLink [ i ] ;
2011-12-29 20:06:31 -06:00
}
}
}
2011-12-30 13:48:11 -06:00
if ( ! partsDataLen )
{
free ( partsData ) ;
partsData = NULL ;
}
2011-12-29 20:06:31 -06:00
bson b ;
bson_init ( & b ) ;
2012-01-01 12:32:07 -06:00
bson_append_bool ( & b , " waterEEnabled " , water_equal_test ) ;
2011-12-30 13:48:11 -06:00
bson_append_bool ( & b , " legacyEnable " , legacy_enable ) ;
bson_append_bool ( & b , " gravityEnable " , ngrav_enable ) ;
bson_append_bool ( & b , " paused " , sys_pause ) ;
bson_append_int ( & b , " gravityMode " , gravityMode ) ;
bson_append_int ( & b , " airMode " , airMode ) ;
2012-01-02 07:59:28 -06:00
//bson_append_int(&b, "leftSelectedElement", sl);
//bson_append_int(&b, "rightSelectedElement", sr);
bson_append_int ( & b , " activeMenu " , active_menu ) ;
2011-12-29 20:06:31 -06:00
if ( partsData )
bson_append_binary ( & b , " parts " , BSON_BIN_USER , partsData , partsDataLen ) ;
2011-12-31 10:49:18 -06:00
if ( partsPosData )
bson_append_binary ( & b , " partsPos " , BSON_BIN_USER , partsPosData , partsPosDataLen ) ;
2011-12-29 20:06:31 -06:00
if ( wallData )
bson_append_binary ( & b , " wallMap " , BSON_BIN_USER , wallData , wallDataLen ) ;
if ( fanData )
bson_append_binary ( & b , " fanMap " , BSON_BIN_USER , fanData , fanDataLen ) ;
2011-12-31 12:57:42 -06:00
signsCount = 0 ;
for ( i = 0 ; i < MAXSIGNS ; i + + )
{
if ( signs [ i ] . text [ 0 ] & & signs [ i ] . x > = fullX & & signs [ i ] . x < = fullX + fullW & & signs [ i ] . y > = fullY & & signs [ i ] . y < = fullY + fullH )
{
signsCount + + ;
}
}
if ( signsCount )
{
bson_append_start_array ( & b , " signs " ) ;
for ( i = 0 ; i < MAXSIGNS ; i + + )
{
if ( signs [ i ] . text [ 0 ] & & signs [ i ] . x > = fullX & & signs [ i ] . x < = fullX + fullW & & signs [ i ] . y > = fullY & & signs [ i ] . y < = fullY + fullH )
{
bson_append_start_object ( & b , " sign " ) ;
bson_append_string ( & b , " text " , signs [ i ] . text ) ;
bson_append_int ( & b , " justification " , signs [ i ] . ju ) ;
bson_append_int ( & b , " x " , signs [ i ] . x - fullX ) ;
bson_append_int ( & b , " y " , signs [ i ] . y - fullY ) ;
bson_append_finish_object ( & b ) ;
}
}
}
bson_append_finish_array ( & b ) ;
2011-12-29 20:06:31 -06:00
bson_finish ( & b ) ;
bson_print ( & b ) ;
finalData = bson_data ( & b ) ;
finalDataLen = bson_size ( & b ) ;
outputDataLen = finalDataLen * 2 + 12 ;
outputData = malloc ( outputDataLen ) ;
outputData [ 0 ] = ' O ' ;
outputData [ 1 ] = ' P ' ;
outputData [ 2 ] = ' S ' ;
outputData [ 3 ] = ' 1 ' ;
outputData [ 4 ] = SAVE_VERSION ;
outputData [ 5 ] = CELL ;
outputData [ 6 ] = blockW ;
outputData [ 7 ] = blockH ;
outputData [ 8 ] = finalDataLen ;
outputData [ 9 ] = finalDataLen > > 8 ;
outputData [ 10 ] = finalDataLen > > 16 ;
outputData [ 11 ] = finalDataLen > > 24 ;
if ( BZ2_bzBuffToBuffCompress ( outputData + 12 , & outputDataLen , finalData , bson_size ( & b ) , 9 , 0 , 0 ) ! = BZ_OK )
{
puts ( " Save Error \n " ) ;
free ( outputData ) ;
* size = 0 ;
outputData = NULL ;
goto fin ;
}
2011-12-31 10:49:18 -06:00
printf ( " compressed data: %d \n " , outputDataLen ) ;
2011-12-29 20:06:31 -06:00
* size = outputDataLen + 12 ;
fin :
bson_destroy ( & b ) ;
if ( partsData )
free ( partsData ) ;
if ( wallData )
free ( wallData ) ;
if ( fanData )
free ( fanData ) ;
return outputData ;
}
int parse_save_OPS ( void * save , int size , int replace , int x0 , int y0 , unsigned char bmap [ YRES / CELL ] [ XRES / CELL ] , float vx [ YRES / CELL ] [ XRES / CELL ] , float vy [ YRES / CELL ] [ XRES / CELL ] , float pv [ YRES / CELL ] [ XRES / CELL ] , float fvx [ YRES / CELL ] [ XRES / CELL ] , float fvy [ YRES / CELL ] [ XRES / CELL ] , sign signs [ MAXSIGNS ] , void * o_partsptr , unsigned pmap [ YRES ] [ XRES ] )
{
particle * partsptr = o_partsptr ;
2011-12-31 10:49:18 -06:00
unsigned char * inputData = save , * bsonData = NULL , * partsData = NULL , * partsPosData = NULL , * fanData = NULL , * wallData = NULL ;
int inputDataLen = size , bsonDataLen = 0 , partsDataLen , partsPosDataLen , fanDataLen , wallDataLen ;
2011-12-30 13:48:11 -06:00
int i , freeIndicesCount , x , y , returnCode = 0 , j ;
2011-12-29 20:06:31 -06:00
int * freeIndices = NULL ;
2011-12-30 13:48:11 -06:00
int blockX , blockY , blockW , blockH , fullX , fullY , fullW , fullH ;
//Block sizes
blockX = x0 / CELL ;
blockY = y0 / CELL ;
blockW = inputData [ 6 ] ;
blockH = inputData [ 7 ] ;
//Full size, normalised
fullX = blockX * CELL ;
fullY = blockY * CELL ;
fullW = blockW * CELL ;
fullH = blockH * CELL ;
//From newer version
if ( inputData [ 4 ] > SAVE_VERSION )
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Save from newer version \n " ) ;
2011-12-30 13:48:11 -06:00
return 2 ;
}
//Incompatible cell size
if ( inputData [ 5 ] > CELL )
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Cell size mismatch \n " ) ;
2011-12-30 13:48:11 -06:00
return 1 ;
}
//Too large/off screen
if ( blockX + blockW > XRES / CELL | | blockY + blockH > YRES / CELL )
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Save too large \n " ) ;
2011-12-30 13:48:11 -06:00
return 1 ;
}
2011-12-29 20:06:31 -06:00
bsonDataLen = ( ( unsigned ) inputData [ 8 ] ) ;
bsonDataLen | = ( ( unsigned ) inputData [ 9 ] ) < < 8 ;
bsonDataLen | = ( ( unsigned ) inputData [ 10 ] ) < < 16 ;
bsonDataLen | = ( ( unsigned ) inputData [ 11 ] ) < < 24 ;
2011-12-31 10:49:18 -06:00
bsonData = malloc ( bsonDataLen + 1 ) ;
2011-12-29 20:06:31 -06:00
if ( ! bsonData )
{
fprintf ( stderr , " Internal error while parsing save: could not allocate buffer \n " ) ;
return 3 ;
}
2011-12-31 10:49:18 -06:00
//Make sure bsonData is null terminated, since all string functions need null terminated strings
//(bson_iterator_key returns a pointer into bsonData, which is then used with strcmp)
bsonData [ bsonDataLen ] = 0 ;
2011-12-29 20:06:31 -06:00
if ( BZ2_bzBuffToBuffDecompress ( bsonData , & bsonDataLen , inputData + 12 , inputDataLen - 12 , 0 , 0 ) )
2011-12-30 13:48:11 -06:00
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Unable to decompress \n " ) ;
2011-12-29 20:06:31 -06:00
return 1 ;
2011-12-30 13:48:11 -06:00
}
2011-12-29 20:06:31 -06:00
2011-12-31 12:57:42 -06:00
if ( replace )
{
//Remove everything
clear_sim ( ) ;
}
2011-12-29 20:06:31 -06:00
bson b ;
bson_iterator iter ;
bson_init_data ( & b , bsonData ) ;
bson_iterator_init ( & iter , & b ) ;
2011-12-31 12:57:42 -06:00
while ( bson_iterator_next ( & iter ) )
2011-12-29 20:06:31 -06:00
{
2011-12-31 12:57:42 -06:00
if ( strcmp ( bson_iterator_key ( & iter ) , " signs " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_ARRAY )
{
bson_iterator subiter ;
bson_iterator_subiterator ( & iter , & subiter ) ;
while ( bson_iterator_next ( & subiter ) )
{
if ( strcmp ( bson_iterator_key ( & subiter ) , " sign " ) = = 0 )
{
if ( bson_iterator_type ( & subiter ) = = BSON_OBJECT )
{
bson_iterator signiter ;
bson_iterator_subiterator ( & subiter , & signiter ) ;
//Find a free sign ID
for ( i = 0 ; i < MAXSIGNS ; i + + )
if ( ! signs [ i ] . text [ 0 ] )
break ;
//Stop reading signs if we have no free spaces
if ( i > = MAXSIGNS )
break ;
while ( bson_iterator_next ( & signiter ) )
{
if ( strcmp ( bson_iterator_key ( & signiter ) , " text " ) = = 0 & & bson_iterator_type ( & signiter ) = = BSON_STRING )
{
strcpy ( signs [ i ] . text , bson_iterator_string ( & signiter ) ) ;
clean_text ( signs [ i ] . text , 158 - 14 ) ;
}
else if ( strcmp ( bson_iterator_key ( & signiter ) , " justification " ) = = 0 & & bson_iterator_type ( & signiter ) = = BSON_INT )
{
signs [ i ] . ju = bson_iterator_int ( & signiter ) ;
}
else if ( strcmp ( bson_iterator_key ( & signiter ) , " x " ) = = 0 & & bson_iterator_type ( & signiter ) = = BSON_INT )
{
signs [ i ] . x = bson_iterator_int ( & signiter ) + fullX ;
}
else if ( strcmp ( bson_iterator_key ( & signiter ) , " y " ) = = 0 & & bson_iterator_type ( & signiter ) = = BSON_INT )
{
signs [ i ] . y = bson_iterator_int ( & signiter ) + fullY ;
}
else
{
fprintf ( stderr , " Unknown sign property %s \n " , bson_iterator_key ( & signiter ) ) ;
}
}
}
else
{
fprintf ( stderr , " Wrong type for \n " , bson_iterator_key ( & subiter ) ) ;
}
}
}
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
else if ( strcmp ( bson_iterator_key ( & iter ) , " parts " ) = = 0 )
2011-12-29 20:06:31 -06:00
{
if ( bson_iterator_type ( & iter ) = = BSON_BINDATA & & ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER & & ( partsDataLen = bson_iterator_bin_len ( & iter ) ) > 0 )
{
partsData = bson_iterator_bin_data ( & iter ) ;
}
else
{
fprintf ( stderr , " Invalid datatype of particle data: %d[%d] %d[%d] %d[%d] \n " , bson_iterator_type ( & iter ) , bson_iterator_type ( & iter ) = = BSON_BINDATA , ( unsigned char ) bson_iterator_bin_type ( & iter ) , ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER , bson_iterator_bin_len ( & iter ) , bson_iterator_bin_len ( & iter ) > 0 ) ;
}
}
2011-12-31 10:49:18 -06:00
if ( strcmp ( bson_iterator_key ( & iter ) , " partsPos " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_BINDATA & & ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER & & ( partsPosDataLen = bson_iterator_bin_len ( & iter ) ) > 0 )
{
partsPosData = bson_iterator_bin_data ( & iter ) ;
}
else
{
fprintf ( stderr , " Invalid datatype of particle position data: %d[%d] %d[%d] %d[%d] \n " , bson_iterator_type ( & iter ) , bson_iterator_type ( & iter ) = = BSON_BINDATA , ( unsigned char ) bson_iterator_bin_type ( & iter ) , ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER , bson_iterator_bin_len ( & iter ) , bson_iterator_bin_len ( & iter ) > 0 ) ;
}
}
2011-12-30 13:48:11 -06:00
else if ( strcmp ( bson_iterator_key ( & iter ) , " wallMap " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_BINDATA & & ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER & & ( wallDataLen = bson_iterator_bin_len ( & iter ) ) > 0 )
{
wallData = bson_iterator_bin_data ( & iter ) ;
}
else
{
fprintf ( stderr , " Invalid datatype of wall data: %d[%d] %d[%d] %d[%d] \n " , bson_iterator_type ( & iter ) , bson_iterator_type ( & iter ) = = BSON_BINDATA , ( unsigned char ) bson_iterator_bin_type ( & iter ) , ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER , bson_iterator_bin_len ( & iter ) , bson_iterator_bin_len ( & iter ) > 0 ) ;
}
}
else if ( strcmp ( bson_iterator_key ( & iter ) , " fanMap " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_BINDATA & & ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER & & ( fanDataLen = bson_iterator_bin_len ( & iter ) ) > 0 )
{
fanData = bson_iterator_bin_data ( & iter ) ;
}
else
{
fprintf ( stderr , " Invalid datatype of fan data: %d[%d] %d[%d] %d[%d] \n " , bson_iterator_type ( & iter ) , bson_iterator_type ( & iter ) = = BSON_BINDATA , ( unsigned char ) bson_iterator_bin_type ( & iter ) , ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER , bson_iterator_bin_len ( & iter ) , bson_iterator_bin_len ( & iter ) > 0 ) ;
}
}
else if ( strcmp ( bson_iterator_key ( & iter ) , " legacyEnable " ) = = 0 & & replace )
{
if ( bson_iterator_type ( & iter ) = = BSON_BOOL )
{
legacy_enable = ( ( int ) bson_iterator_bool ( & iter ) ) ? 1 : 0 ;
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
else if ( strcmp ( bson_iterator_key ( & iter ) , " gravityEnable " ) = = 0 & & replace )
{
if ( bson_iterator_type ( & iter ) = = BSON_BOOL )
{
int tempGrav = ngrav_enable ;
tempGrav = ( ( int ) bson_iterator_bool ( & iter ) ) ? 1 : 0 ;
# ifndef RENDERER
//Change the gravity state
if ( ngrav_enable ! = tempGrav )
{
if ( tempGrav )
start_grav_async ( ) ;
else
stop_grav_async ( ) ;
}
# endif
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
2012-01-01 12:32:07 -06:00
else if ( strcmp ( bson_iterator_key ( & iter ) , " waterEEnabled " ) = = 0 & & replace )
{
if ( bson_iterator_type ( & iter ) = = BSON_BOOL )
{
water_equal_test = ( ( int ) bson_iterator_bool ( & iter ) ) ? 1 : 0 ;
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
2011-12-30 13:48:11 -06:00
else if ( strcmp ( bson_iterator_key ( & iter ) , " paused " ) = = 0 & & ! sys_pause )
{
if ( bson_iterator_type ( & iter ) = = BSON_BOOL )
{
sys_pause = ( ( int ) bson_iterator_bool ( & iter ) ) ? 1 : 0 ;
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
else if ( strcmp ( bson_iterator_key ( & iter ) , " gravityMode " ) = = 0 & & replace )
{
if ( bson_iterator_type ( & iter ) = = BSON_INT )
{
gravityMode = bson_iterator_int ( & iter ) ;
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
else if ( strcmp ( bson_iterator_key ( & iter ) , " airMode " ) = = 0 & & replace )
{
if ( bson_iterator_type ( & iter ) = = BSON_INT )
{
airMode = bson_iterator_int ( & iter ) ;
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
2012-01-02 07:59:28 -06:00
/*else if((strcmp(bson_iterator_key(&iter), "leftSelectedElement")==0 || strcmp(bson_iterator_key(&iter), "rightSelectedElement")) && replace)
{
if ( bson_iterator_type ( & iter ) = = BSON_INT & & bson_iterator_int ( & iter ) > 0 & & bson_iterator_int ( & iter ) < PT_NUM )
{
if ( bson_iterator_key ( & iter ) [ 0 ] = = ' l ' )
{
sl = bson_iterator_int ( & iter ) ;
}
else
{
sr = bson_iterator_int ( & iter ) ;
}
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
} */
else if ( strcmp ( bson_iterator_key ( & iter ) , " activeMenu " ) = = 0 & & replace )
{
if ( bson_iterator_type ( & iter ) = = BSON_INT & & bson_iterator_int ( & iter ) > 0 & & bson_iterator_int ( & iter ) < SC_TOTAL & & msections [ bson_iterator_int ( & iter ) ] . doshow )
{
active_menu = bson_iterator_int ( & iter ) ;
}
else
{
fprintf ( stderr , " Wrong value for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
2011-12-30 13:48:11 -06:00
}
//Read wall and fan data
if ( wallData )
{
j = 0 ;
if ( blockW * blockH > wallDataLen )
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Not enough wall data \n " ) ;
2011-12-30 13:48:11 -06:00
goto fail ;
}
for ( x = 0 ; x < blockW ; x + + )
{
for ( y = 0 ; y < blockH ; y + + )
{
bmap [ blockY + y ] [ blockX + x ] = wallData [ y * blockW + x ] ;
if ( ( bmap [ blockY + y ] [ blockX + x ] = = WL_FAN | | bmap [ blockY + y ] [ blockX + x ] = = 4 ) & & fanData )
{
if ( j + 1 > = fanDataLen )
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Not enough fan data \n " ) ;
2011-12-30 13:48:11 -06:00
}
fvx [ blockY + y ] [ blockX + x ] = ( fanData [ j + + ] - 127.0f ) / 64.0f ;
fvy [ blockY + y ] [ blockX + x ] = ( fanData [ j + + ] - 127.0f ) / 64.0f ;
}
}
}
2011-12-29 20:06:31 -06:00
}
//Read particle data
2011-12-31 10:49:18 -06:00
if ( partsData & & partsPosData )
2011-12-29 20:06:31 -06:00
{
int newIndex = 0 , fieldDescriptor , tempTemp ;
2011-12-31 10:49:18 -06:00
int posCount , posTotal , partsPosDataIndex = 0 ;
int saved_x , saved_y ;
2012-01-04 07:45:36 -06:00
int freeIndicesIndex = 0 ;
2011-12-31 10:49:18 -06:00
if ( fullW * fullH * 3 > partsPosDataLen )
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Not enough particle position data \n " ) ;
2011-12-31 10:49:18 -06:00
goto fail ;
}
2011-12-29 20:06:31 -06:00
parts_lastActiveIndex = NPART - 1 ;
freeIndicesCount = 0 ;
freeIndices = calloc ( sizeof ( int ) , NPART ) ;
for ( i = 0 ; i < NPART ; i + + )
{
//Ensure ALL parts (even photons) are in the pmap so we can overwrite, keep a track of indices we can use
if ( partsptr [ i ] . type )
{
x = ( int ) ( partsptr [ i ] . x + 0.5f ) ;
y = ( int ) ( partsptr [ i ] . y + 0.5f ) ;
pmap [ y ] [ x ] = ( i < < 8 ) | 1 ;
}
else
freeIndices [ freeIndicesCount + + ] = i ;
}
i = 0 ;
2011-12-31 10:49:18 -06:00
for ( saved_y = 0 ; saved_y < fullH ; saved_y + + )
2011-12-29 20:06:31 -06:00
{
2011-12-31 10:49:18 -06:00
for ( saved_x = 0 ; saved_x < fullW ; saved_x + + )
2011-12-29 20:06:31 -06:00
{
2011-12-31 10:49:18 -06:00
//Read total number of particles at this position
posTotal = 0 ;
posTotal | = partsPosData [ partsPosDataIndex + + ] < < 16 ;
posTotal | = partsPosData [ partsPosDataIndex + + ] < < 8 ;
posTotal | = partsPosData [ partsPosDataIndex + + ] ;
//Put the next posTotal particles at this position
for ( posCount = 0 ; posCount < posTotal ; posCount + + )
2011-12-29 20:06:31 -06:00
{
2011-12-31 12:57:42 -06:00
//i+3 because we have 4 bytes of required fields (type (1), descriptor (2), temp (1))
2011-12-31 10:49:18 -06:00
if ( i + 3 > = partsDataLen )
goto fail ;
x = saved_x + fullX ;
y = saved_y + fullY ;
2011-12-31 12:57:42 -06:00
fieldDescriptor = partsData [ i + 1 ] ;
fieldDescriptor | = partsData [ i + 2 ] < < 8 ;
2011-12-31 10:49:18 -06:00
if ( x > = XRES | | x < 0 | | y > = YRES | | y < 0 )
{
fprintf ( stderr , " Out of range [%d]: %d %d, [%d, %d], [%d, %d] \n " , i , x , y , ( unsigned ) partsData [ i + 1 ] , ( unsigned ) partsData [ i + 2 ] , ( unsigned ) partsData [ i + 3 ] , ( unsigned ) partsData [ i + 4 ] ) ;
goto fail ;
}
2012-01-01 08:35:37 -06:00
if ( partsData [ i ] > = PT_NUM )
2011-12-31 10:49:18 -06:00
partsData [ i ] = PT_DMND ; //Replace all invalid powders with diamond
if ( pmap [ y ] [ x ] )
{
//Replace existing particle or allocated block
newIndex = pmap [ y ] [ x ] > > 8 ;
}
2012-01-04 07:45:36 -06:00
else if ( freeIndicesIndex < freeIndicesCount )
2011-12-31 10:49:18 -06:00
{
//Create new particle
2012-01-04 07:45:36 -06:00
newIndex = freeIndices [ freeIndicesIndex + + ] ;
2011-12-31 10:49:18 -06:00
}
else
{
//Nowhere to put new particle, tpt is sad :(
break ;
}
if ( newIndex < 0 | | newIndex > = NPART )
goto fail ;
//Clear the particle, ready for our new properties
memset ( & ( partsptr [ newIndex ] ) , 0 , sizeof ( particle ) ) ;
//Required fields
partsptr [ newIndex ] . type = partsData [ i ] ;
partsptr [ newIndex ] . x = x ;
partsptr [ newIndex ] . y = y ;
2011-12-31 12:57:42 -06:00
i + = 3 ;
2011-12-31 10:49:18 -06:00
2011-12-31 12:57:42 -06:00
//Read temp
2011-12-31 10:49:18 -06:00
if ( fieldDescriptor & 0x01 )
2011-12-31 12:57:42 -06:00
{
//Full 16bit int
tempTemp = partsData [ i + + ] ;
tempTemp | = ( ( ( unsigned ) partsData [ i + + ] ) < < 8 ) ;
partsptr [ newIndex ] . temp = tempTemp ;
}
else
{
//1 Byte room temp offset
tempTemp = ( char ) partsData [ i + + ] ;
partsptr [ newIndex ] . temp = tempTemp + 294.15f ;
}
//Read life
if ( fieldDescriptor & 0x02 )
2011-12-31 10:49:18 -06:00
{
if ( i > = partsDataLen ) goto fail ;
partsptr [ newIndex ] . life = partsData [ i + + ] ;
//Read 2nd byte
2011-12-31 12:57:42 -06:00
if ( fieldDescriptor & 0x04 )
2011-12-31 10:49:18 -06:00
{
if ( i > = partsDataLen ) goto fail ;
2012-01-02 08:04:42 -06:00
partsptr [ newIndex ] . life | = ( ( ( unsigned ) partsData [ i + + ] ) < < 8 ) ;
2011-12-31 10:49:18 -06:00
}
}
//Read tmp
2011-12-31 12:57:42 -06:00
if ( fieldDescriptor & 0x08 )
2011-12-31 10:49:18 -06:00
{
if ( i > = partsDataLen ) goto fail ;
partsptr [ newIndex ] . tmp = partsData [ i + + ] ;
//Read 2nd byte
2011-12-31 12:57:42 -06:00
if ( fieldDescriptor & 0x10 )
2011-12-31 10:49:18 -06:00
{
if ( i > = partsDataLen ) goto fail ;
2012-01-02 08:04:42 -06:00
partsptr [ newIndex ] . tmp | = ( ( ( unsigned ) partsData [ i + + ] ) < < 8 ) ;
2011-12-31 10:49:18 -06:00
}
}
//Read ctype
2011-12-31 12:57:42 -06:00
if ( fieldDescriptor & 0x20 )
2011-12-31 10:49:18 -06:00
{
if ( i > = partsDataLen ) goto fail ;
partsptr [ newIndex ] . ctype = partsData [ i + + ] ;
2012-01-04 08:29:22 -06:00
//Read additional bytes
if ( fieldDescriptor & 0x200 )
{
if ( i + 2 > = partsDataLen ) goto fail ;
partsptr [ newIndex ] . ctype | = ( ( ( unsigned ) partsData [ i + + ] ) < < 24 ) ;
partsptr [ newIndex ] . ctype | = ( ( ( unsigned ) partsData [ i + + ] ) < < 16 ) ;
partsptr [ newIndex ] . ctype | = ( ( ( unsigned ) partsData [ i + + ] ) < < 8 ) ;
}
2011-12-31 10:49:18 -06:00
}
//Read dcolour
2011-12-31 12:57:42 -06:00
if ( fieldDescriptor & 0x40 )
2011-12-31 10:49:18 -06:00
{
if ( i + 3 > = partsDataLen ) goto fail ;
2012-01-02 08:04:42 -06:00
partsptr [ newIndex ] . dcolour = ( ( ( unsigned ) partsData [ i + + ] ) < < 24 ) ;
partsptr [ newIndex ] . dcolour | = ( ( ( unsigned ) partsData [ i + + ] ) < < 16 ) ;
partsptr [ newIndex ] . dcolour | = ( ( ( unsigned ) partsData [ i + + ] ) < < 8 ) ;
partsptr [ newIndex ] . dcolour | = ( ( unsigned ) partsData [ i + + ] ) ;
2011-12-31 10:49:18 -06:00
}
//Read vx
2011-12-31 12:57:42 -06:00
if ( fieldDescriptor & 0x80 )
2011-12-31 10:49:18 -06:00
{
if ( i > = partsDataLen ) goto fail ;
partsptr [ newIndex ] . vx = ( partsData [ i + + ] - 127.0f ) / 16.0f ;
}
//Read vy
2011-12-31 12:57:42 -06:00
if ( fieldDescriptor & 0x100 )
2011-12-31 10:49:18 -06:00
{
if ( i > = partsDataLen ) goto fail ;
partsptr [ newIndex ] . vy = ( partsData [ i + + ] - 127.0f ) / 16.0f ;
}
2011-12-29 20:06:31 -06:00
}
}
}
}
goto fin ;
fail :
//Clean up everything
returnCode = 1 ;
fin :
bson_destroy ( & b ) ;
if ( freeIndices )
free ( freeIndices ) ;
return returnCode ;
}
2011-12-30 13:48:11 -06:00
//Old saving
pixel * prerender_save_PSv ( void * save , int size , int * width , int * height )
{
unsigned char * d , * c = save ;
int i , j , k , x , y , rx , ry , p = 0 ;
int bw , bh , w , h , new_format = 0 ;
pixel * fb ;
if ( size < 16 )
return NULL ;
if ( ! ( c [ 2 ] = = 0x43 & & c [ 1 ] = = 0x75 & & c [ 0 ] = = 0x66 ) & & ! ( c [ 2 ] = = 0x76 & & c [ 1 ] = = 0x53 & & c [ 0 ] = = 0x50 ) )
return NULL ;
if ( c [ 2 ] = = 0x43 & & c [ 1 ] = = 0x75 & & c [ 0 ] = = 0x66 ) {
new_format = 1 ;
}
if ( c [ 4 ] > SAVE_VERSION )
return NULL ;
bw = c [ 6 ] ;
bh = c [ 7 ] ;
w = bw * CELL ;
h = bh * CELL ;
if ( c [ 5 ] ! = CELL )
return NULL ;
i = ( unsigned ) c [ 8 ] ;
i | = ( ( unsigned ) c [ 9 ] ) < < 8 ;
i | = ( ( unsigned ) c [ 10 ] ) < < 16 ;
i | = ( ( unsigned ) c [ 11 ] ) < < 24 ;
d = malloc ( i ) ;
if ( ! d )
return NULL ;
fb = calloc ( w * h , PIXELSIZE ) ;
if ( ! fb )
{
free ( d ) ;
return NULL ;
}
if ( BZ2_bzBuffToBuffDecompress ( ( char * ) d , ( unsigned * ) & i , ( char * ) ( c + 12 ) , size - 12 , 0 , 0 ) )
goto corrupt ;
size = i ;
if ( size < bw * bh )
goto corrupt ;
k = 0 ;
for ( y = 0 ; y < bh ; y + + )
for ( x = 0 ; x < bw ; x + + )
{
rx = x * CELL ;
ry = y * CELL ;
switch ( d [ p ] )
{
case 1 :
for ( j = 0 ; j < CELL ; j + + )
for ( i = 0 ; i < CELL ; i + + )
fb [ ( ry + j ) * w + ( rx + i ) ] = PIXPACK ( 0x808080 ) ;
break ;
case 2 :
for ( j = 0 ; j < CELL ; j + = 2 )
for ( i = ( j > > 1 ) & 1 ; i < CELL ; i + = 2 )
fb [ ( ry + j ) * w + ( rx + i ) ] = PIXPACK ( 0x808080 ) ;
break ;
case 3 :
for ( j = 0 ; j < CELL ; j + + )
for ( i = 0 ; i < CELL ; i + + )
if ( ! ( j % 2 ) & & ! ( i % 2 ) )
fb [ ( ry + j ) * w + ( rx + i ) ] = PIXPACK ( 0xC0C0C0 ) ;
break ;
case 4 :
for ( j = 0 ; j < CELL ; j + = 2 )
for ( i = ( j > > 1 ) & 1 ; i < CELL ; i + = 2 )
fb [ ( ry + j ) * w + ( rx + i ) ] = PIXPACK ( 0x8080FF ) ;
k + + ;
break ;
case 6 :
for ( j = 0 ; j < CELL ; j + = 2 )
for ( i = ( j > > 1 ) & 1 ; i < CELL ; i + = 2 )
fb [ ( ry + j ) * w + ( rx + i ) ] = PIXPACK ( 0xFF8080 ) ;
break ;
case 7 :
for ( j = 0 ; j < CELL ; j + + )
for ( i = 0 ; i < CELL ; i + + )
if ( ! ( i & j & 1 ) )
fb [ ( ry + j ) * w + ( rx + i ) ] = PIXPACK ( 0x808080 ) ;
break ;
case 8 :
for ( j = 0 ; j < CELL ; j + + )
for ( i = 0 ; i < CELL ; i + + )
if ( ! ( j % 2 ) & & ! ( i % 2 ) )
fb [ ( ry + j ) * w + ( rx + i ) ] = PIXPACK ( 0xC0C0C0 ) ;
else
fb [ ( ry + j ) * w + ( rx + i ) ] = PIXPACK ( 0x808080 ) ;
break ;
case WL_WALL :
for ( j = 0 ; j < CELL ; j + + )
for ( i = 0 ; i < CELL ; i + + )
fb [ ( ry + j ) * w + ( rx + i ) ] = PIXPACK ( 0x808080 ) ;
break ;
case WL_DESTROYALL :
for ( j = 0 ; j < CELL ; j + = 2 )
for ( i = ( j > > 1 ) & 1 ; i < CELL ; i + = 2 )
fb [ ( ry + j ) * w + ( rx + i ) ] = PIXPACK ( 0x808080 ) ;
break ;
case WL_ALLOWLIQUID :
for ( j = 0 ; j < CELL ; j + + )
for ( i = 0 ; i < CELL ; i + + )
if ( ! ( j % 2 ) & & ! ( i % 2 ) )
fb [ ( ry + j ) * w + ( rx + i ) ] = PIXPACK ( 0xC0C0C0 ) ;
break ;
case WL_FAN :
for ( j = 0 ; j < CELL ; j + = 2 )
for ( i = ( j > > 1 ) & 1 ; i < CELL ; i + = 2 )
fb [ ( ry + j ) * w + ( rx + i ) ] = PIXPACK ( 0x8080FF ) ;
k + + ;
break ;
case WL_DETECT :
for ( j = 0 ; j < CELL ; j + = 2 )
for ( i = ( j > > 1 ) & 1 ; i < CELL ; i + = 2 )
fb [ ( ry + j ) * w + ( rx + i ) ] = PIXPACK ( 0xFF8080 ) ;
break ;
case WL_EWALL :
for ( j = 0 ; j < CELL ; j + + )
for ( i = 0 ; i < CELL ; i + + )
if ( ! ( i & j & 1 ) )
fb [ ( ry + j ) * w + ( rx + i ) ] = PIXPACK ( 0x808080 ) ;
break ;
case WL_WALLELEC :
for ( j = 0 ; j < CELL ; j + + )
for ( i = 0 ; i < CELL ; i + + )
if ( ! ( j % 2 ) & & ! ( i % 2 ) )
fb [ ( ry + j ) * w + ( rx + i ) ] = PIXPACK ( 0xC0C0C0 ) ;
else
fb [ ( ry + j ) * w + ( rx + i ) ] = PIXPACK ( 0x808080 ) ;
break ;
}
p + + ;
}
p + = 2 * k ;
if ( p > = size )
goto corrupt ;
for ( y = 0 ; y < h ; y + + )
for ( x = 0 ; x < w ; x + + )
{
if ( p > = size )
goto corrupt ;
j = d [ p + + ] ;
if ( j < PT_NUM & & j > 0 )
{
if ( j = = PT_STKM | | j = = PT_STKM2 | | j = = PT_FIGH )
{
pixel lc , hc = PIXRGB ( 255 , 224 , 178 ) ;
if ( j = = PT_STKM | | j = = PT_FIGH ) lc = PIXRGB ( 255 , 255 , 255 ) ;
else lc = PIXRGB ( 100 , 100 , 255 ) ;
//only need to check upper bound of y coord - lower bounds and x<w are checked in draw_line
draw_line ( fb , x - 2 , y - 2 , x + 2 , y - 2 , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , w ) ;
if ( y + 2 < h )
{
draw_line ( fb , x - 2 , y + 2 , x + 2 , y + 2 , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , w ) ;
draw_line ( fb , x - 2 , y - 2 , x - 2 , y + 2 , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , w ) ;
draw_line ( fb , x + 2 , y - 2 , x + 2 , y + 2 , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , w ) ;
}
if ( y + 6 < h )
{
draw_line ( fb , x , y + 3 , x - 1 , y + 6 , PIXR ( lc ) , PIXG ( lc ) , PIXB ( lc ) , w ) ;
draw_line ( fb , x , y + 3 , x + 1 , y + 6 , PIXR ( lc ) , PIXG ( lc ) , PIXB ( lc ) , w ) ;
}
if ( y + 12 < h )
{
draw_line ( fb , x - 1 , y + 6 , x - 3 , y + 12 , PIXR ( lc ) , PIXG ( lc ) , PIXB ( lc ) , w ) ;
draw_line ( fb , x + 1 , y + 6 , x + 3 , y + 12 , PIXR ( lc ) , PIXG ( lc ) , PIXB ( lc ) , w ) ;
}
}
else
fb [ y * w + x ] = ptypes [ j ] . pcolors ;
}
}
free ( d ) ;
* width = w ;
* height = h ;
return fb ;
corrupt :
free ( d ) ;
free ( fb ) ;
return NULL ;
}
2011-12-29 20:06:31 -06:00
void * build_save_PSv ( int * size , int orig_x0 , int orig_y0 , int orig_w , int orig_h , unsigned char bmap [ YRES / CELL ] [ XRES / CELL ] , float fvx [ YRES / CELL ] [ XRES / CELL ] , float fvy [ YRES / CELL ] [ XRES / CELL ] , sign signs [ MAXSIGNS ] , void * partsptr )
{
unsigned char * d = calloc ( 1 , 3 * ( XRES / CELL ) * ( YRES / CELL ) + ( XRES * YRES ) * 15 + MAXSIGNS * 262 ) , * c ;
int i , j , x , y , p = 0 , * m = calloc ( XRES * YRES , sizeof ( int ) ) ;
int x0 , y0 , w , h , bx0 = orig_x0 / CELL , by0 = orig_y0 / CELL , bw , bh ;
particle * parts = partsptr ;
bw = ( orig_w + orig_x0 - bx0 * CELL + CELL - 1 ) / CELL ;
bh = ( orig_h + orig_y0 - by0 * CELL + CELL - 1 ) / CELL ;
// normalize coordinates
x0 = bx0 * CELL ;
y0 = by0 * CELL ;
w = bw * CELL ;
h = bh * CELL ;
// save the required air state
for ( y = by0 ; y < by0 + bh ; y + + )
for ( x = bx0 ; x < bx0 + bw ; x + + )
d [ p + + ] = bmap [ y ] [ x ] ;
for ( y = by0 ; y < by0 + bh ; y + + )
for ( x = bx0 ; x < bx0 + bw ; x + + )
if ( bmap [ y ] [ x ] = = WL_FAN | | bmap [ y ] [ x ] = = 4 )
{
i = ( int ) ( fvx [ y ] [ x ] * 64.0f + 127.5f ) ;
if ( i < 0 ) i = 0 ;
if ( i > 255 ) i = 255 ;
d [ p + + ] = i ;
}
for ( y = by0 ; y < by0 + bh ; y + + )
for ( x = bx0 ; x < bx0 + bw ; x + + )
if ( bmap [ y ] [ x ] = = WL_FAN | | bmap [ y ] [ x ] = = 4 )
{
i = ( int ) ( fvy [ y ] [ x ] * 64.0f + 127.5f ) ;
if ( i < 0 ) i = 0 ;
if ( i > 255 ) i = 255 ;
d [ p + + ] = i ;
}
// save the particle map
for ( i = 0 ; i < NPART ; i + + )
if ( parts [ i ] . type )
{
x = ( int ) ( parts [ i ] . x + 0.5f ) ;
y = ( int ) ( parts [ i ] . y + 0.5f ) ;
if ( x > = orig_x0 & & x < orig_x0 + orig_w & & y > = orig_y0 & & y < orig_y0 + orig_h ) {
if ( ! m [ ( x - x0 ) + ( y - y0 ) * w ] | |
parts [ m [ ( x - x0 ) + ( y - y0 ) * w ] - 1 ] . type = = PT_PHOT | |
parts [ m [ ( x - x0 ) + ( y - y0 ) * w ] - 1 ] . type = = PT_NEUT )
m [ ( x - x0 ) + ( y - y0 ) * w ] = i + 1 ;
}
}
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
d [ p + + ] = parts [ i - 1 ] . type ;
else
d [ p + + ] = 0 ;
}
// save particle properties
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
{
i - - ;
x = ( int ) ( parts [ i ] . vx * 16.0f + 127.5f ) ;
y = ( int ) ( parts [ i ] . vy * 16.0f + 127.5f ) ;
if ( x < 0 ) x = 0 ;
if ( x > 255 ) x = 255 ;
if ( y < 0 ) y = 0 ;
if ( y > 255 ) y = 255 ;
d [ p + + ] = x ;
d [ p + + ] = y ;
}
}
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i ) {
//Everybody loves a 16bit int
//d[p++] = (parts[i-1].life+3)/4;
int ttlife = ( int ) parts [ i - 1 ] . life ;
d [ p + + ] = ( ( ttlife & 0xFF00 ) > > 8 ) ;
d [ p + + ] = ( ttlife & 0x00FF ) ;
}
}
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i ) {
//Now saving tmp!
//d[p++] = (parts[i-1].life+3)/4;
int tttmp = ( int ) parts [ i - 1 ] . tmp ;
d [ p + + ] = ( ( tttmp & 0xFF00 ) > > 8 ) ;
d [ p + + ] = ( tttmp & 0x00FF ) ;
}
}
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i & & ( parts [ i - 1 ] . type = = PT_PBCN ) ) {
//Save tmp2
d [ p + + ] = parts [ i - 1 ] . tmp2 ;
}
}
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i ) {
//Save colour (ALPHA)
d [ p + + ] = ( parts [ i - 1 ] . dcolour & 0xFF000000 ) > > 24 ;
}
}
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i ) {
//Save colour (RED)
d [ p + + ] = ( parts [ i - 1 ] . dcolour & 0x00FF0000 ) > > 16 ;
}
}
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i ) {
//Save colour (GREEN)
d [ p + + ] = ( parts [ i - 1 ] . dcolour & 0x0000FF00 ) > > 8 ;
}
}
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i ) {
//Save colour (BLUE)
d [ p + + ] = ( parts [ i - 1 ] . dcolour & 0x000000FF ) ;
}
}
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
{
//New Temperature saving uses a 16bit unsigned int for temperatures, giving a precision of 1 degree versus 36 for the old format
int tttemp = ( int ) parts [ i - 1 ] . temp ;
d [ p + + ] = ( ( tttemp & 0xFF00 ) > > 8 ) ;
d [ p + + ] = ( tttemp & 0x00FF ) ;
}
}
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i & & ( parts [ i - 1 ] . type = = PT_CLNE | | parts [ i - 1 ] . type = = PT_PCLN | | parts [ i - 1 ] . type = = PT_BCLN | | parts [ i - 1 ] . type = = PT_SPRK | | parts [ i - 1 ] . type = = PT_LAVA | | parts [ i - 1 ] . type = = PT_PIPE | | parts [ i - 1 ] . type = = PT_LIFE | | parts [ i - 1 ] . type = = PT_PBCN | | parts [ i - 1 ] . type = = PT_WIRE | | parts [ i - 1 ] . type = = PT_STOR | | parts [ i - 1 ] . type = = PT_CONV ) )
d [ p + + ] = parts [ i - 1 ] . ctype ;
}
j = 0 ;
for ( i = 0 ; i < MAXSIGNS ; i + + )
if ( signs [ i ] . text [ 0 ] & &
signs [ i ] . x > = x0 & & signs [ i ] . x < x0 + w & &
signs [ i ] . y > = y0 & & signs [ i ] . y < y0 + h )
j + + ;
d [ p + + ] = j ;
for ( i = 0 ; i < MAXSIGNS ; i + + )
if ( signs [ i ] . text [ 0 ] & &
signs [ i ] . x > = x0 & & signs [ i ] . x < x0 + w & &
signs [ i ] . y > = y0 & & signs [ i ] . y < y0 + h )
{
d [ p + + ] = ( signs [ i ] . x - x0 ) ;
d [ p + + ] = ( signs [ i ] . x - x0 ) > > 8 ;
d [ p + + ] = ( signs [ i ] . y - y0 ) ;
d [ p + + ] = ( signs [ i ] . y - y0 ) > > 8 ;
d [ p + + ] = signs [ i ] . ju ;
x = strlen ( signs [ i ] . text ) ;
d [ p + + ] = x ;
memcpy ( d + p , signs [ i ] . text , x ) ;
p + = x ;
}
i = ( p * 101 + 99 ) / 100 + 612 ;
c = malloc ( i ) ;
//New file header uses PSv, replacing fuC. This is to detect if the client uses a new save format for temperatures
//This creates a problem for old clients, that display and "corrupt" error instead of a "newer version" error
c [ 0 ] = 0x50 ; //0x66;
c [ 1 ] = 0x53 ; //0x75;
c [ 2 ] = 0x76 ; //0x43;
c [ 3 ] = legacy_enable | ( ( sys_pause < < 1 ) & 0x02 ) | ( ( gravityMode < < 2 ) & 0x0C ) | ( ( airMode < < 4 ) & 0x70 ) | ( ( ngrav_enable < < 7 ) & 0x80 ) ;
c [ 4 ] = SAVE_VERSION ;
c [ 5 ] = CELL ;
c [ 6 ] = bw ;
c [ 7 ] = bh ;
c [ 8 ] = p ;
c [ 9 ] = p > > 8 ;
c [ 10 ] = p > > 16 ;
c [ 11 ] = p > > 24 ;
i - = 12 ;
if ( BZ2_bzBuffToBuffCompress ( ( char * ) ( c + 12 ) , ( unsigned * ) & i , ( char * ) d , p , 9 , 0 , 0 ) ! = BZ_OK )
{
free ( d ) ;
free ( c ) ;
free ( m ) ;
return NULL ;
}
free ( d ) ;
free ( m ) ;
* size = i + 12 ;
return c ;
}
int parse_save_PSv ( void * save , int size , int replace , int x0 , int y0 , unsigned char bmap [ YRES / CELL ] [ XRES / CELL ] , float fvx [ YRES / CELL ] [ XRES / CELL ] , float fvy [ YRES / CELL ] [ XRES / CELL ] , sign signs [ MAXSIGNS ] , void * partsptr , unsigned pmap [ YRES ] [ XRES ] )
{
unsigned char * d = NULL , * c = save ;
int q , i , j , k , x , y , p = 0 , * m = NULL , ver , pty , ty , legacy_beta = 0 , tempGrav = 0 ;
int bx0 = x0 / CELL , by0 = y0 / CELL , bw , bh , w , h ;
int nf = 0 , new_format = 0 , ttv = 0 ;
particle * parts = partsptr ;
int * fp = malloc ( NPART * sizeof ( int ) ) ;
//New file header uses PSv, replacing fuC. This is to detect if the client uses a new save format for temperatures
//This creates a problem for old clients, that display and "corrupt" error instead of a "newer version" error
if ( size < 16 )
return 1 ;
if ( ! ( c [ 2 ] = = 0x43 & & c [ 1 ] = = 0x75 & & c [ 0 ] = = 0x66 ) & & ! ( c [ 2 ] = = 0x76 & & c [ 1 ] = = 0x53 & & c [ 0 ] = = 0x50 ) )
return 1 ;
if ( c [ 2 ] = = 0x76 & & c [ 1 ] = = 0x53 & & c [ 0 ] = = 0x50 ) {
new_format = 1 ;
}
if ( c [ 4 ] > SAVE_VERSION )
return 2 ;
ver = c [ 4 ] ;
if ( ver < 34 )
{
legacy_enable = 1 ;
}
else
{
if ( ver > = 44 ) {
legacy_enable = c [ 3 ] & 0x01 ;
if ( ! sys_pause ) {
sys_pause = ( c [ 3 ] > > 1 ) & 0x01 ;
}
if ( ver > = 46 & & replace ) {
gravityMode = ( ( c [ 3 ] > > 2 ) & 0x03 ) ; // | ((c[3]>>2)&0x01);
airMode = ( ( c [ 3 ] > > 4 ) & 0x07 ) ; // | ((c[3]>>4)&0x02) | ((c[3]>>4)&0x01);
}
if ( ver > = 49 & & replace ) {
tempGrav = ( ( c [ 3 ] > > 7 ) & 0x01 ) ;
}
} else {
if ( c [ 3 ] = = 1 | | c [ 3 ] = = 0 ) {
legacy_enable = c [ 3 ] ;
} else {
legacy_beta = 1 ;
}
}
}
bw = c [ 6 ] ;
bh = c [ 7 ] ;
if ( bx0 + bw > XRES / CELL )
bx0 = XRES / CELL - bw ;
if ( by0 + bh > YRES / CELL )
by0 = YRES / CELL - bh ;
if ( bx0 < 0 )
bx0 = 0 ;
if ( by0 < 0 )
by0 = 0 ;
if ( c [ 5 ] ! = CELL | | bx0 + bw > XRES / CELL | | by0 + bh > YRES / CELL )
return 3 ;
i = ( unsigned ) c [ 8 ] ;
i | = ( ( unsigned ) c [ 9 ] ) < < 8 ;
i | = ( ( unsigned ) c [ 10 ] ) < < 16 ;
i | = ( ( unsigned ) c [ 11 ] ) < < 24 ;
d = malloc ( i ) ;
if ( ! d )
return 1 ;
if ( BZ2_bzBuffToBuffDecompress ( ( char * ) d , ( unsigned * ) & i , ( char * ) ( c + 12 ) , size - 12 , 0 , 0 ) )
return 1 ;
size = i ;
if ( size < bw * bh )
return 1 ;
// normalize coordinates
x0 = bx0 * CELL ;
y0 = by0 * CELL ;
w = bw * CELL ;
h = bh * CELL ;
if ( replace )
{
if ( ver < 46 ) {
gravityMode = 0 ;
airMode = 0 ;
}
clear_sim ( ) ;
}
parts_lastActiveIndex = NPART - 1 ;
m = calloc ( XRES * YRES , sizeof ( int ) ) ;
// make a catalog of free parts
//memset(pmap, 0, sizeof(pmap)); "Using sizeof for array given as function argument returns the size of pointer."
memset ( pmap , 0 , sizeof ( unsigned ) * ( XRES * YRES ) ) ;
for ( i = 0 ; i < NPART ; i + + )
if ( parts [ i ] . type )
{
x = ( int ) ( parts [ i ] . x + 0.5f ) ;
y = ( int ) ( parts [ i ] . y + 0.5f ) ;
pmap [ y ] [ x ] = ( i < < 8 ) | 1 ;
}
else
fp [ nf + + ] = i ;
// load the required air state
for ( y = by0 ; y < by0 + bh ; y + + )
for ( x = bx0 ; x < bx0 + bw ; x + + )
{
if ( d [ p ] )
{
2012-01-04 07:45:36 -06:00
//In old saves, ignore walls created by sign tool bug
//Not ignoring other invalid walls or invalid walls in new saves, so that any other bugs causing them are easier to notice, find and fix
if ( ver < 71 & & d [ p ] = = WL_SIGN )
{
p + + ;
continue ;
}
2011-12-29 20:06:31 -06:00
bmap [ y ] [ x ] = d [ p ] ;
if ( bmap [ y ] [ x ] = = 1 )
bmap [ y ] [ x ] = WL_WALL ;
if ( bmap [ y ] [ x ] = = 2 )
bmap [ y ] [ x ] = WL_DESTROYALL ;
if ( bmap [ y ] [ x ] = = 3 )
bmap [ y ] [ x ] = WL_ALLOWLIQUID ;
if ( bmap [ y ] [ x ] = = 4 )
bmap [ y ] [ x ] = WL_FAN ;
if ( bmap [ y ] [ x ] = = 5 )
bmap [ y ] [ x ] = WL_STREAM ;
if ( bmap [ y ] [ x ] = = 6 )
bmap [ y ] [ x ] = WL_DETECT ;
if ( bmap [ y ] [ x ] = = 7 )
bmap [ y ] [ x ] = WL_EWALL ;
if ( bmap [ y ] [ x ] = = 8 )
bmap [ y ] [ x ] = WL_WALLELEC ;
if ( bmap [ y ] [ x ] = = 9 )
bmap [ y ] [ x ] = WL_ALLOWAIR ;
if ( bmap [ y ] [ x ] = = 10 )
bmap [ y ] [ x ] = WL_ALLOWSOLID ;
if ( bmap [ y ] [ x ] = = 11 )
bmap [ y ] [ x ] = WL_ALLOWALLELEC ;
if ( bmap [ y ] [ x ] = = 12 )
bmap [ y ] [ x ] = WL_EHOLE ;
if ( bmap [ y ] [ x ] = = 13 )
bmap [ y ] [ x ] = WL_ALLOWGAS ;
}
p + + ;
}
for ( y = by0 ; y < by0 + bh ; y + + )
for ( x = bx0 ; x < bx0 + bw ; x + + )
if ( d [ ( y - by0 ) * bw + ( x - bx0 ) ] = = 4 | | d [ ( y - by0 ) * bw + ( x - bx0 ) ] = = WL_FAN )
{
if ( p > = size )
goto corrupt ;
fvx [ y ] [ x ] = ( d [ p + + ] - 127.0f ) / 64.0f ;
}
for ( y = by0 ; y < by0 + bh ; y + + )
for ( x = bx0 ; x < bx0 + bw ; x + + )
if ( d [ ( y - by0 ) * bw + ( x - bx0 ) ] = = 4 | | d [ ( y - by0 ) * bw + ( x - bx0 ) ] = = WL_FAN )
{
if ( p > = size )
goto corrupt ;
fvy [ y ] [ x ] = ( d [ p + + ] - 127.0f ) / 64.0f ;
}
// load the particle map
i = 0 ;
pty = p ;
for ( y = y0 ; y < y0 + h ; y + + )
for ( x = x0 ; x < x0 + w ; x + + )
{
if ( p > = size )
goto corrupt ;
j = d [ p + + ] ;
if ( j > = PT_NUM ) {
//TODO: Possibly some server side translation
j = PT_DUST ; //goto corrupt;
}
gol [ x ] [ y ] = 0 ;
if ( j )
{
if ( pmap [ y ] [ x ] )
{
k = pmap [ y ] [ x ] > > 8 ;
}
else if ( i < nf )
{
k = fp [ i ] ;
i + + ;
}
else
{
m [ ( x - x0 ) + ( y - y0 ) * w ] = NPART + 1 ;
continue ;
}
memset ( parts + k , 0 , sizeof ( particle ) ) ;
parts [ k ] . type = j ;
if ( j = = PT_COAL )
parts [ k ] . tmp = 50 ;
if ( j = = PT_FUSE )
parts [ k ] . tmp = 50 ;
if ( j = = PT_PHOT )
parts [ k ] . ctype = 0x3fffffff ;
if ( j = = PT_SOAP )
parts [ k ] . ctype = 0 ;
if ( j = = PT_BIZR | | j = = PT_BIZRG | | j = = PT_BIZRS )
parts [ k ] . ctype = 0x47FFFF ;
parts [ k ] . x = ( float ) x ;
parts [ k ] . y = ( float ) y ;
m [ ( x - x0 ) + ( y - y0 ) * w ] = k + 1 ;
}
}
// load particle properties
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
{
i - - ;
if ( p + 1 > = size )
goto corrupt ;
if ( i < NPART )
{
parts [ i ] . vx = ( d [ p + + ] - 127.0f ) / 16.0f ;
parts [ i ] . vy = ( d [ p + + ] - 127.0f ) / 16.0f ;
}
else
p + = 2 ;
}
}
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
{
if ( ver > = 44 ) {
if ( p > = size ) {
goto corrupt ;
}
if ( i < = NPART ) {
ttv = ( d [ p + + ] ) < < 8 ;
ttv | = ( d [ p + + ] ) ;
parts [ i - 1 ] . life = ttv ;
} else {
p + = 2 ;
}
} else {
if ( p > = size )
goto corrupt ;
if ( i < = NPART )
parts [ i - 1 ] . life = d [ p + + ] * 4 ;
else
p + + ;
}
}
}
if ( ver > = 44 ) {
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
{
if ( p > = size ) {
goto corrupt ;
}
if ( i < = NPART ) {
ttv = ( d [ p + + ] ) < < 8 ;
ttv | = ( d [ p + + ] ) ;
parts [ i - 1 ] . tmp = ttv ;
if ( ver < 53 & & ! parts [ i - 1 ] . tmp )
for ( q = 1 ; q < = NGOLALT ; q + + ) {
if ( parts [ i - 1 ] . type = = goltype [ q - 1 ] & & grule [ q ] [ 9 ] = = 2 )
parts [ i - 1 ] . tmp = grule [ q ] [ 9 ] - 1 ;
}
if ( ver > = 51 & & ver < 53 & & parts [ i - 1 ] . type = = PT_PBCN )
{
parts [ i - 1 ] . tmp2 = parts [ i - 1 ] . tmp ;
parts [ i - 1 ] . tmp = 0 ;
}
} else {
p + = 2 ;
}
}
}
}
if ( ver > = 53 ) {
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
ty = d [ pty + j ] ;
if ( i & & ty = = PT_PBCN )
{
if ( p > = size )
goto corrupt ;
if ( i < = NPART )
parts [ i - 1 ] . tmp2 = d [ p + + ] ;
else
p + + ;
}
}
}
//Read ALPHA component
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
{
if ( ver > = 49 ) {
if ( p > = size ) {
goto corrupt ;
}
if ( i < = NPART ) {
parts [ i - 1 ] . dcolour = d [ p + + ] < < 24 ;
} else {
p + + ;
}
}
}
}
//Read RED component
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
{
if ( ver > = 49 ) {
if ( p > = size ) {
goto corrupt ;
}
if ( i < = NPART ) {
parts [ i - 1 ] . dcolour | = d [ p + + ] < < 16 ;
} else {
p + + ;
}
}
}
}
//Read GREEN component
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
{
if ( ver > = 49 ) {
if ( p > = size ) {
goto corrupt ;
}
if ( i < = NPART ) {
parts [ i - 1 ] . dcolour | = d [ p + + ] < < 8 ;
} else {
p + + ;
}
}
}
}
//Read BLUE component
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
{
if ( ver > = 49 ) {
if ( p > = size ) {
goto corrupt ;
}
if ( i < = NPART ) {
parts [ i - 1 ] . dcolour | = d [ p + + ] ;
} else {
p + + ;
}
}
}
}
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
ty = d [ pty + j ] ;
if ( i )
{
if ( ver > = 34 & & legacy_beta = = 0 )
{
if ( p > = size )
{
goto corrupt ;
}
if ( i < = NPART )
{
if ( ver > = 42 ) {
if ( new_format ) {
ttv = ( d [ p + + ] ) < < 8 ;
ttv | = ( d [ p + + ] ) ;
if ( parts [ i - 1 ] . type = = PT_PUMP ) {
parts [ i - 1 ] . temp = ttv + 0.15 ; //fix PUMP saved at 0, so that it loads at 0.
} else {
parts [ i - 1 ] . temp = ttv ;
}
} else {
parts [ i - 1 ] . temp = ( d [ p + + ] * ( ( MAX_TEMP + ( - MIN_TEMP ) ) / 255 ) ) + MIN_TEMP ;
}
} else {
parts [ i - 1 ] . temp = ( ( d [ p + + ] * ( ( O_MAX_TEMP + ( - O_MIN_TEMP ) ) / 255 ) ) + O_MIN_TEMP ) + 273 ;
}
}
else
{
p + + ;
if ( new_format ) {
p + + ;
}
}
}
else
{
parts [ i - 1 ] . temp = ptypes [ parts [ i - 1 ] . type ] . heat ;
}
}
}
for ( j = 0 ; j < w * h ; j + + )
{
int gnum = 0 ;
i = m [ j ] ;
ty = d [ pty + j ] ;
if ( i & & ( ty = = PT_CLNE | | ( ty = = PT_PCLN & & ver > = 43 ) | | ( ty = = PT_BCLN & & ver > = 44 ) | | ( ty = = PT_SPRK & & ver > = 21 ) | | ( ty = = PT_LAVA & & ver > = 34 ) | | ( ty = = PT_PIPE & & ver > = 43 ) | | ( ty = = PT_LIFE & & ver > = 51 ) | | ( ty = = PT_PBCN & & ver > = 52 ) | | ( ty = = PT_WIRE & & ver > = 55 ) | | ( ty = = PT_STOR & & ver > = 59 ) | | ( ty = = PT_CONV & & ver > = 60 ) ) )
{
if ( p > = size )
goto corrupt ;
if ( i < = NPART )
parts [ i - 1 ] . ctype = d [ p + + ] ;
else
p + + ;
}
// no more particle properties to load, so we can change type here without messing up loading
if ( i & & i < = NPART )
{
if ( ( player . spwn = = 1 & & ty = = PT_STKM ) | | ( player2 . spwn = = 1 & & ty = = PT_STKM2 ) )
{
parts [ i - 1 ] . type = PT_NONE ;
}
else if ( parts [ i - 1 ] . type = = PT_STKM )
{
STKM_init_legs ( & player , i - 1 ) ;
player . spwn = 1 ;
player . elem = PT_DUST ;
}
else if ( parts [ i - 1 ] . type = = PT_STKM2 )
{
STKM_init_legs ( & player2 , i - 1 ) ;
player2 . spwn = 1 ;
player2 . elem = PT_DUST ;
}
else if ( parts [ i - 1 ] . type = = PT_FIGH )
{
unsigned char fcount = 0 ;
while ( fcount < 100 & & fcount < ( fighcount + 1 ) & & fighters [ fcount ] . spwn = = 1 ) fcount + + ;
if ( fcount < 100 & & fighters [ fcount ] . spwn = = 0 )
{
parts [ i - 1 ] . tmp = fcount ;
fighters [ fcount ] . spwn = 1 ;
fighters [ fcount ] . elem = PT_DUST ;
fighcount + + ;
STKM_init_legs ( & ( fighters [ fcount ] ) , i - 1 ) ;
}
}
if ( ver < 48 & & ( ty = = OLD_PT_WIND | | ( ty = = PT_BRAY & & parts [ i - 1 ] . life = = 0 ) ) )
{
// Replace invisible particles with something sensible and add decoration to hide it
x = ( int ) ( parts [ i - 1 ] . x + 0.5f ) ;
y = ( int ) ( parts [ i - 1 ] . y + 0.5f ) ;
parts [ i - 1 ] . dcolour = 0xFF000000 ;
parts [ i - 1 ] . type = PT_DMND ;
}
if ( ver < 51 & & ( ( ty > = 78 & & ty < = 89 ) | | ( ty > = 134 & & ty < = 146 & & ty ! = 141 ) ) ) {
//Replace old GOL
parts [ i - 1 ] . type = PT_LIFE ;
for ( gnum = 0 ; gnum < NGOLALT ; gnum + + ) {
if ( ty = = goltype [ gnum ] )
parts [ i - 1 ] . ctype = gnum ;
}
ty = PT_LIFE ;
}
if ( ver < 52 & & ( ty = = PT_CLNE | | ty = = PT_PCLN | | ty = = PT_BCLN ) ) {
//Replace old GOL ctypes in clone
for ( gnum = 0 ; gnum < NGOLALT ; gnum + + ) {
if ( parts [ i - 1 ] . ctype = = goltype [ gnum ] )
{
parts [ i - 1 ] . ctype = PT_LIFE ;
parts [ i - 1 ] . tmp = gnum ;
}
}
}
if ( ty = = PT_LCRY ) {
if ( ver < 67 )
{
//New LCRY uses TMP not life
if ( parts [ i - 1 ] . life > = 10 )
{
parts [ i - 1 ] . life = 10 ;
parts [ i - 1 ] . tmp2 = 10 ;
parts [ i - 1 ] . tmp = 3 ;
}
else if ( parts [ i - 1 ] . life < = 0 )
{
parts [ i - 1 ] . life = 0 ;
parts [ i - 1 ] . tmp2 = 0 ;
parts [ i - 1 ] . tmp = 0 ;
}
else if ( parts [ i - 1 ] . life < 10 & & parts [ i - 1 ] . life > 0 )
{
parts [ i - 1 ] . tmp = 1 ;
}
}
else
{
parts [ i - 1 ] . tmp2 = parts [ i - 1 ] . life ;
}
}
if ( ! ptypes [ parts [ i - 1 ] . type ] . enabled )
parts [ i - 1 ] . type = PT_NONE ;
}
}
# ifndef RENDERER
//Change the gravity state
if ( ngrav_enable ! = tempGrav & & replace )
{
if ( tempGrav )
start_grav_async ( ) ;
else
stop_grav_async ( ) ;
}
# endif
gravity_mask ( ) ;
if ( p > = size )
goto version1 ;
j = d [ p + + ] ;
for ( i = 0 ; i < j ; i + + )
{
if ( p + 6 > size )
goto corrupt ;
for ( k = 0 ; k < MAXSIGNS ; k + + )
if ( ! signs [ k ] . text [ 0 ] )
break ;
x = d [ p + + ] ;
x | = ( ( unsigned ) d [ p + + ] ) < < 8 ;
if ( k < MAXSIGNS )
signs [ k ] . x = x + x0 ;
x = d [ p + + ] ;
x | = ( ( unsigned ) d [ p + + ] ) < < 8 ;
if ( k < MAXSIGNS )
signs [ k ] . y = x + y0 ;
x = d [ p + + ] ;
if ( k < MAXSIGNS )
signs [ k ] . ju = x ;
x = d [ p + + ] ;
if ( p + x > size )
goto corrupt ;
if ( k < MAXSIGNS )
{
memcpy ( signs [ k ] . text , d + p , x ) ;
signs [ k ] . text [ x ] = 0 ;
clean_text ( signs [ k ] . text , 158 - 14 /* Current max sign length */ ) ;
}
p + = x ;
}
version1 :
if ( m ) free ( m ) ;
if ( d ) free ( d ) ;
if ( fp ) free ( fp ) ;
return 0 ;
corrupt :
if ( m ) free ( m ) ;
if ( d ) free ( d ) ;
if ( fp ) free ( fp ) ;
if ( replace )
{
legacy_enable = 0 ;
clear_sim ( ) ;
}
return 1 ;
}
void * build_thumb ( int * size , int bzip2 )
{
unsigned char * d = calloc ( 1 , XRES * YRES ) , * c ;
int i , j , x , y ;
for ( i = 0 ; i < NPART ; i + + )
if ( parts [ i ] . type )
{
x = ( int ) ( parts [ i ] . x + 0.5f ) ;
y = ( int ) ( parts [ i ] . y + 0.5f ) ;
if ( x > = 0 & & x < XRES & & y > = 0 & & y < YRES )
d [ x + y * XRES ] = parts [ i ] . type ;
}
for ( y = 0 ; y < YRES / CELL ; y + + )
for ( x = 0 ; x < XRES / CELL ; x + + )
if ( bmap [ y ] [ x ] )
for ( j = 0 ; j < CELL ; j + + )
for ( i = 0 ; i < CELL ; i + + )
d [ x * CELL + i + ( y * CELL + j ) * XRES ] = 0xFF ;
j = XRES * YRES ;
if ( bzip2 )
{
i = ( j * 101 + 99 ) / 100 + 608 ;
c = malloc ( i ) ;
c [ 0 ] = 0x53 ;
c [ 1 ] = 0x68 ;
c [ 2 ] = 0x49 ;
c [ 3 ] = 0x74 ;
c [ 4 ] = PT_NUM ;
c [ 5 ] = CELL ;
c [ 6 ] = XRES / CELL ;
c [ 7 ] = YRES / CELL ;
i - = 8 ;
if ( BZ2_bzBuffToBuffCompress ( ( char * ) ( c + 8 ) , ( unsigned * ) & i , ( char * ) d , j , 9 , 0 , 0 ) ! = BZ_OK )
{
free ( d ) ;
free ( c ) ;
return NULL ;
}
free ( d ) ;
* size = i + 8 ;
return c ;
}
* size = j ;
return d ;
2011-12-31 10:49:18 -06:00
}