2020-07-06 22:14:50 +00:00
# if defined(REC98_PROJECT)
# include "platform.h" /* see also [https://github.com/nmlgc/ReC98/issues/8] */
2020-07-09 07:37:00 +00:00
# elif defined(_MSC_VER) /*Microsoft C++*/ || defined(__BORLANDC__) || defined(__TURBOC__)
2020-07-06 22:14:50 +00:00
typedef unsigned char uint8_t ;
typedef unsigned short uint16_t ;
typedef unsigned long uint32_t ;
# else
# include <stdint.h>
# endif
2020-07-09 07:37:00 +00:00
# if defined(_MSC_VER) /*Microsoft C++*/ || defined(__BORLANDC__) || defined(__TURBOC__)
2020-07-06 22:14:50 +00:00
# include <io.h>
# else
# include <sys / types.h>
# include <sys / stat.h>
# include <unistd.h>
# endif
# include <stdlib.h>
# include <string.h>
# include <malloc.h>
# include <stdio.h>
# include <fcntl.h>
# if defined(__GNUC__)
# include <endian.h>
# else
# define le16toh(x) (x)
# define le32toh(x) (x)
# define htole16(x) (x)
# define htole32(x) (x)
# endif
# include "bmp2arrl.h"
/* O_BINARY is needed for MS-DOS, Windows, etc.
* Linux , Mac OS X , etc . do not have O_BINARY */
# ifndef O_BINARY
# define O_BINARY (0)
# endif
static unsigned char bmp_tmp [ 128 ] ; /* more than enough */
/*
typedef struct tagBITMAPFILEHEADER {
WORD bfType ; + 0
DWORD bfSize ; + 2
WORD bfReserved1 ; + 6
WORD bfReserved2 ; + 8
DWORD bfOffBits ; + 10
} BITMAPFILEHEADER , * LPBITMAPFILEHEADER , * PBITMAPFILEHEADER ; = 14
typedef struct tagBITMAPINFOHEADER {
DWORD biSize ; + 0
LONG biWidth ; + 4
LONG biHeight ; + 8
WORD biPlanes ; + 12
WORD biBitCount ; + 14
DWORD biCompression ; + 16
DWORD biSizeImage ; + 20
LONG biXPelsPerMeter ; + 24
LONG biYPelsPerMeter ; + 28
DWORD biClrUsed ; + 32
DWORD biClrImportant ; + 36
} BITMAPINFOHEADER , * PBITMAPINFOHEADER ; = 40
*/
static void memcpyxor ( unsigned char * dst , unsigned char * src , unsigned int bytes , unsigned char xorval ) {
while ( bytes - - ! = 0 )
* dst + + = * src + + ^ xorval ;
}
static void memcpy24to1 ( unsigned char * dst , unsigned char * src , unsigned int w ) {
unsigned char r , g , b , tmp ;
unsigned int x ;
while ( w > = 8 ) {
tmp = 0 ;
for ( x = 0 ; x < 8 ; x + + ) {
b = * src + + ;
g = * src + + ;
r = * src + + ;
if ( ( r | g | b ) & 0x80 )
tmp | = 0x80 > > x ;
}
* dst + + = tmp ;
w - = 8 ;
}
if ( w > 0 ) {
tmp = 0 ;
for ( x = 0 ; x < w ; x + + ) {
b = * src + + ;
g = * src + + ;
r = * src + + ;
if ( ( r | g | b ) & 0x80 )
tmp | = 0x80 > > x ;
}
* dst + + = tmp ;
}
}
static void memcpy32to1 ( unsigned char * dst , unsigned char * src , unsigned int w ) {
unsigned char r , g , b , tmp ;
unsigned int x ;
while ( w > = 8 ) {
tmp = 0 ;
for ( x = 0 ; x < 8 ; x + + ) {
b = * src + + ;
g = * src + + ;
r = * src + + ;
src + + ; /* A */
if ( ( r | g | b ) & 0x80 )
tmp | = 0x80 > > x ;
}
* dst + + = tmp ;
w - = 8 ;
}
if ( w > 0 ) {
tmp = 0 ;
for ( x = 0 ; x < w ; x + + ) {
b = * src + + ;
g = * src + + ;
r = * src + + ;
src + + ; /* A */
if ( ( r | g | b ) & 0x80 )
tmp | = 0x80 > > x ;
}
* dst + + = tmp ;
}
}
static int saveout_write_prologue ( struct rec98_bmp2arr_task * t , struct saveout_ctx * sctx ) {
if ( t - > output_type = = REC98_OUT_C ) {
fprintf ( sctx - > fp , " /* Generated by bmp2arr from %s, do not modify directly. */ \n " , t - > input_bmp ) ;
fprintf ( sctx - > fp , " /* Sprite sheet: %d sprites (%d x %d) of %d x %d sprites. */ \n " , sctx - > sscols * sctx - > ssrows , sctx - > sscols , sctx - > ssrows , t - > sprite_width , t - > sprite_height ) ;
fprintf ( sctx - > fp , " \n " ) ;
fprintf ( sctx - > fp , " const unsigned char %s " , t - > output_symname ! = NULL ? t - > output_symname : " untitled " ) ;
if ( t - > preshift & & t - > preshift_inner = = 0 )
fprintf ( sctx - > fp , " [8/*PRESHIFT*/] " ) ;
fprintf ( sctx - > fp , " [%d] " , sctx - > ssrows * sctx - > sscols ) ;
if ( t - > preshift & & t - > preshift_inner = = 1 )
fprintf ( sctx - > fp , " [8/*PRESHIFT*/] " ) ;
fprintf ( sctx - > fp , " [%d/*%d bytes x %d rows*/] = { \n " ,
sctx - > bytesperrow * t - > sprite_height , sctx - > bytesperrow , t - > sprite_height ) ;
}
else if ( t - > output_type = = REC98_OUT_ASM ) {
fprintf ( sctx - > fp , " ; Generated by bmp2arr from %s, do not modify directly. \n " , t - > input_bmp ) ;
fprintf ( sctx - > fp , " ; Sprite sheet: %d sprites (%d x %d) of %d x %d sprites. \n " , sctx - > sscols * sctx - > ssrows , sctx - > sscols , sctx - > ssrows , t - > sprite_width , t - > sprite_height ) ;
fprintf ( sctx - > fp , " \n " ) ;
fprintf ( sctx - > fp , " ; const unsigned char %s " , t - > output_symname ! = NULL ? t - > output_symname : " untitled " ) ;
if ( t - > preshift & & t - > preshift_inner = = 0 )
fprintf ( sctx - > fp , " [8/*PRESHIFT*/] " ) ;
fprintf ( sctx - > fp , " [%d] " , sctx - > ssrows * sctx - > sscols ) ;
if ( t - > preshift & & t - > preshift_inner = = 1 )
fprintf ( sctx - > fp , " [8/*PRESHIFT*/] " ) ;
fprintf ( sctx - > fp , " [%d/*%d bytes x %d rows*/]; \n " ,
sctx - > bytesperrow * t - > sprite_height , sctx - > bytesperrow , t - > sprite_height ) ;
fprintf ( sctx - > fp , " public %s \n " , t - > output_symname ! = NULL ? t - > output_symname : " untitled " ) ;
fprintf ( sctx - > fp , " label %s byte \n " , t - > output_symname ! = NULL ? t - > output_symname : " untitled " ) ;
}
else if ( t - > output_type = = REC98_OUT_BIN ) {
/* none needed */
}
else if ( t - > output_type = = REC98_OUT_BMP ) {
const unsigned int balign = ( sctx - > bytesperrow + 3u ) & ( ~ 3u ) ;
/* BITMAPFILEHEADER */
memcpy ( bmp_tmp + 0 , " BM " , 2 ) ;
* ( ( uint32_t * ) ( bmp_tmp + 2 ) ) = htole32 ( 14 + 40 + 4 * 2 + ( balign * t - > sprite_height * sctx - > ssrows * sctx - > sscols * ( t - > preshift ? 8u : 1u ) ) ) ; /* bfSize */
* ( ( uint16_t * ) ( bmp_tmp + 6 ) ) = htole16 ( 0 ) ;
* ( ( uint16_t * ) ( bmp_tmp + 8 ) ) = htole16 ( 0 ) ;
* ( ( uint32_t * ) ( bmp_tmp + 10 ) ) = htole32 ( 14 + 40 + 4 * 2 ) ; /* bfOffBits */
fwrite ( bmp_tmp , 14 , 1 , sctx - > fp ) ;
/* BITMAPINFOHEADER */
* ( ( uint32_t * ) ( bmp_tmp + 0 ) ) = htole32 ( 40 ) ;
* ( ( uint32_t * ) ( bmp_tmp + 4 ) ) = htole32 ( sctx - > bytesperrow * 8u ) ;
* ( ( uint32_t * ) ( bmp_tmp + 8 ) ) = htole32 ( t - > sprite_height * sctx - > ssrows * sctx - > sscols * ( t - > preshift ? 8u : 1u ) ) ;
* ( ( uint16_t * ) ( bmp_tmp + 12 ) ) = htole16 ( 1 ) ;
* ( ( uint16_t * ) ( bmp_tmp + 14 ) ) = htole16 ( 1 ) ;
* ( ( uint32_t * ) ( bmp_tmp + 16 ) ) = htole32 ( 0 ) ;
* ( ( uint32_t * ) ( bmp_tmp + 20 ) ) = htole32 ( balign * t - > sprite_height * sctx - > ssrows * sctx - > sscols * ( t - > preshift ? 8u : 1u ) ) ;
* ( ( uint32_t * ) ( bmp_tmp + 24 ) ) = htole32 ( 0 ) ;
* ( ( uint32_t * ) ( bmp_tmp + 28 ) ) = htole32 ( 0 ) ;
* ( ( uint32_t * ) ( bmp_tmp + 32 ) ) = htole32 ( 2 ) ;
* ( ( uint32_t * ) ( bmp_tmp + 36 ) ) = htole32 ( 2 ) ;
fwrite ( bmp_tmp , 40 , 1 , sctx - > fp ) ;
/* color palette */
bmp_tmp [ 0 + 0 ] = 0x00 ;
bmp_tmp [ 0 + 1 ] = 0x00 ;
bmp_tmp [ 0 + 2 ] = 0x00 ;
bmp_tmp [ 0 + 3 ] = 0x00 ;
bmp_tmp [ 4 + 0 ] = 0xFF ;
bmp_tmp [ 4 + 1 ] = 0xFF ;
bmp_tmp [ 4 + 2 ] = 0xFF ;
bmp_tmp [ 4 + 3 ] = 0x00 ;
fwrite ( bmp_tmp , 4 , 2 , sctx - > fp ) ;
}
return 0 ;
}
static int saveout_write_epilogue ( struct rec98_bmp2arr_task * t , struct saveout_ctx * sctx ) {
if ( t - > output_type = = REC98_OUT_C ) {
fprintf ( sctx - > fp , " };/*end spritesheet*/ \n " ) ;
}
else if ( t - > output_type = = REC98_OUT_ASM ) {
/* none needed */
}
else if ( t - > output_type = = REC98_OUT_BIN ) {
/* none needed */
}
else if ( t - > output_type = = REC98_OUT_BMP ) {
/* none needed */
}
return 0 ;
}
/* C-string utils */
void cstr_free ( char * * s ) {
if ( s ! = NULL ) {
if ( * s ! = NULL ) {
2020-07-09 07:39:06 +00:00
free ( ( void * ) ( * s ) ) ;
2020-07-06 22:14:50 +00:00
* s = NULL ;
}
}
}
void cstr_set ( char * * s , const char * n ) {
if ( s ! = NULL ) {
cstr_free ( s ) ;
if ( n ! = NULL ) * s = strdup ( n ) ;
}
}
void rec98_bmp2arr_task_free_bmp ( struct rec98_bmp2arr_task * t ) {
if ( t ! = NULL ) {
if ( t - > bmp ! = NULL ) {
2020-07-09 07:39:06 +00:00
free ( ( void * ) ( t - > bmp ) ) ;
2020-07-06 22:14:50 +00:00
t - > bmp = NULL ;
}
}
}
/* assume *t is uninitialized data */
int rec98_bmp2arr_task_init ( struct rec98_bmp2arr_task * t ) {
if ( t = = NULL ) return - 1 ; /* failure */
memset ( t , 0 , sizeof ( * t ) ) ;
return 0 ; /* success */
}
/* assume *t is initialized data */
int rec98_bmp2arr_task_free ( struct rec98_bmp2arr_task * t ) {
if ( t = = NULL ) return - 1 ; /* failure */
rec98_bmp2arr_task_free_bmp ( t ) ;
cstr_free ( & t - > output_symname ) ;
cstr_free ( & t - > output_file ) ;
cstr_free ( & t - > input_bmp ) ;
memset ( t , 0 , sizeof ( * t ) ) ;
return 0 ; /* success */
}
int rec98_bmp2arr_save_debug_bmp_out ( struct rec98_bmp2arr_task * t ) {
unsigned int y ;
int fd ;
if ( t = = NULL | | t - > output_file = = NULL ) return - 1 ;
if ( t - > bmp = = NULL ) return - 1 ;
fd = open ( t - > output_file , O_WRONLY | O_CREAT | O_TRUNC | O_BINARY , 0644 ) ;
if ( fd < 0 ) return - 1 ;
/* BITMAPFILEHEADER */
memcpy ( bmp_tmp + 0 , " BM " , 2 ) ;
* ( ( uint32_t * ) ( bmp_tmp + 2 ) ) = htole32 ( 14 + 40 + 4 * 2 + ( t - > bmp_height * t - > bmp_stride ) ) ; /* bfSize */
* ( ( uint16_t * ) ( bmp_tmp + 6 ) ) = htole16 ( 0 ) ;
* ( ( uint16_t * ) ( bmp_tmp + 8 ) ) = htole16 ( 0 ) ;
* ( ( uint32_t * ) ( bmp_tmp + 10 ) ) = htole32 ( 14 + 40 + 4 * 2 ) ; /* bfOffBits */
write ( fd , bmp_tmp , 14 ) ;
/* BITMAPINFOHEADER */
* ( ( uint32_t * ) ( bmp_tmp + 0 ) ) = htole32 ( 40 ) ;
* ( ( uint32_t * ) ( bmp_tmp + 4 ) ) = htole32 ( t - > bmp_width ) ;
* ( ( uint32_t * ) ( bmp_tmp + 8 ) ) = htole32 ( t - > bmp_height ) ;
* ( ( uint16_t * ) ( bmp_tmp + 12 ) ) = htole16 ( 1 ) ;
* ( ( uint16_t * ) ( bmp_tmp + 14 ) ) = htole16 ( 1 ) ;
* ( ( uint32_t * ) ( bmp_tmp + 16 ) ) = htole32 ( 0 ) ;
* ( ( uint32_t * ) ( bmp_tmp + 20 ) ) = htole32 ( t - > bmp_height * t - > bmp_stride ) ;
* ( ( uint32_t * ) ( bmp_tmp + 24 ) ) = htole32 ( 0 ) ;
* ( ( uint32_t * ) ( bmp_tmp + 28 ) ) = htole32 ( 0 ) ;
* ( ( uint32_t * ) ( bmp_tmp + 32 ) ) = htole32 ( 2 ) ;
* ( ( uint32_t * ) ( bmp_tmp + 36 ) ) = htole32 ( 2 ) ;
write ( fd , bmp_tmp , 40 ) ;
/* color palette */
bmp_tmp [ 0 + 0 ] = 0x00 ;
bmp_tmp [ 0 + 1 ] = 0x00 ;
bmp_tmp [ 0 + 2 ] = 0x00 ;
bmp_tmp [ 0 + 3 ] = 0x00 ;
bmp_tmp [ 4 + 0 ] = 0xFF ;
bmp_tmp [ 4 + 1 ] = 0xFF ;
bmp_tmp [ 4 + 2 ] = 0xFF ;
bmp_tmp [ 4 + 3 ] = 0x00 ;
write ( fd , bmp_tmp , 4 * 2 ) ;
/* the bits */
y = t - > bmp_height - 1 ;
do {
write ( fd , t - > bmp + ( y * t - > bmp_stride ) , t - > bmp_stride ) ;
} while ( y - - ! = 0 ) ;
close ( fd ) ;
return 0 ;
}
2020-07-06 22:16:05 +00:00
static int saveout_write_sprite ( struct rec98_bmp2arr_task * t , struct saveout_ctx * sctx , const unsigned char * bmp /*length bytesperrow * height*/ ) {
2020-07-06 22:14:50 +00:00
unsigned int r , c , b ;
if ( t - > output_type = = REC98_OUT_C ) {
if ( t - > preshift & & t - > preshift_inner ) {
fprintf ( sctx - > fp , " %c " , sctx - > sspreshift ! = 0 ? ' , ' : ' ' ) ;
}
else {
fprintf ( sctx - > fp , " %c " , sctx - > spritenum ! = 0 ? ' , ' : ' ' ) ;
}
if ( t - > preshift ) {
fprintf ( sctx - > fp , " {/*sprite %u preshift %u*/ \n " , sctx - > spritenum , sctx - > sspreshift ) ;
}
else {
fprintf ( sctx - > fp , " {/*sprite %u*/ \n " , sctx - > spritenum ) ;
}
for ( r = 0 ; r < t - > sprite_height ; r + + ) {
fprintf ( sctx - > fp , " \t " ) ;
for ( c = 0 ; c < sctx - > bytesperrow ; c + + ) {
fprintf ( sctx - > fp , " %c " , ( c ! = 0 | | r ! = 0 ) ? ' , ' : ' ' ) ;
fprintf ( sctx - > fp , " 0x%02x " , * bmp + + ) ;
}
fprintf ( sctx - > fp , " /* row %u */ " , t - > upsidedown ? ( t - > sprite_height - 1u - r ) : r ) ;
fprintf ( sctx - > fp , " \n " ) ;
}
if ( t - > preshift ) {
fprintf ( sctx - > fp , " }/*end sprite %u preshift %u*/ \n " , sctx - > spritenum , sctx - > sspreshift ) ;
}
else {
fprintf ( sctx - > fp , " }/*end sprite %u*/ \n " , sctx - > spritenum ) ;
}
}
else if ( t - > output_type = = REC98_OUT_ASM ) {
if ( t - > preshift ) {
fprintf ( sctx - > fp , " ; sprite %u preshift %u \n " , sctx - > spritenum , sctx - > sspreshift ) ;
}
else {
fprintf ( sctx - > fp , " ; sprite %u \n " , sctx - > spritenum ) ;
}
for ( r = 0 ; r < t - > sprite_height ; r + + ) {
fprintf ( sctx - > fp , " \t db " ) ;
for ( c = 0 ; c < sctx - > bytesperrow ; c + + ) {
if ( c ! = 0 ) fprintf ( sctx - > fp , " , " ) ;
for ( b = 0 ; b < 8 ; b + + )
fprintf ( sctx - > fp , " %u " , ( * bmp > > ( 7u - b ) ) & 1u ) ;
fprintf ( sctx - > fp , " b " ) ;
bmp + + ;
}
fprintf ( sctx - > fp , " ; row %u " , t - > upsidedown ? ( t - > sprite_height - 1u - r ) : r ) ;
fprintf ( sctx - > fp , " \n " ) ;
}
}
else if ( t - > output_type = = REC98_OUT_BIN ) {
fwrite ( bmp , sctx - > bytesperrow * t - > sprite_height , 1 , sctx - > fp ) ;
}
else if ( t - > output_type = = REC98_OUT_BMP ) {
const unsigned int balign = ( sctx - > bytesperrow + 3u ) & ( ~ 3u ) ;
for ( r = 0 ; r < t - > sprite_height ; r + + ) {
memcpy ( bmp_tmp , bmp , sctx - > bytesperrow ) ;
fwrite ( bmp_tmp , balign , 1 , sctx - > fp ) ;
bmp + = sctx - > bytesperrow ;
}
}
return 0 ;
}
int rec98_bmp2arr_save_output ( struct rec98_bmp2arr_task * t ) {
struct saveout_ctx sctx ;
if ( t = = NULL | | t - > output_file = = NULL ) return - 1 ;
if ( t - > bmp = = NULL ) return - 1 ;
if ( t - > sprite_width < 8 ) return - 1 ;
if ( t - > sprite_height = = 0 ) return - 1 ;
sctx . sscols = t - > bmp_width / t - > sprite_width ;
sctx . ssrows = t - > bmp_height / t - > sprite_height ;
if ( sctx . sscols = = 0 | | sctx . ssrows = = 0 ) return - 1 ;
/* PRESHIFT only supported for 8-pixel wide sprites */
if ( t - > preshift & & t - > sprite_width ! = 8 )
return - 1 ;
sctx . bytesperrow = ( t - > sprite_width + 7u ) / 8u ;
if ( t - > preshift ) sctx . bytesperrow + = 1u ; /* in the examples, an 8-pixel wide sprite is shifted across 16 pixels */
if ( ( sctx . bytesperrow * t - > sprite_height ) > sizeof ( bmp_tmp ) )
return - 1 ;
sctx . fp = fopen ( t - > output_file , " wb " ) ;
if ( sctx . fp = = NULL ) return - 1 ;
fprintf ( stderr , " Sprite sheet: %d sprites total (%d x %d). \n " ,
sctx . sscols * sctx . ssrows , sctx . sscols , sctx . ssrows ) ;
fprintf ( stderr , " Each sprite is %d x %d \n " ,
t - > sprite_width , t - > sprite_height ) ;
if ( saveout_write_prologue ( t , & sctx ) )
goto fioerr ;
if ( t - > preshift & & t - > preshift_inner = = 1 ) {
for ( sctx . ssrow = 0 ; sctx . ssrow < sctx . ssrows ; sctx . ssrow + + ) {
sctx . spritenum = sctx . ssrow * sctx . sscols ;
for ( sctx . sscol = 0 ; sctx . sscol < sctx . sscols ; sctx . sscol + + , sctx . spritenum + + ) {
if ( t - > output_type = = REC98_OUT_C ) {
fprintf ( sctx . fp , " %c " , sctx . spritenum ! = 0 ? ' , ' : ' ' ) ;
fprintf ( sctx . fp , " {/*preshift*/ \n " ) ;
}
for ( sctx . sspreshift = 0 ; sctx . sspreshift < 8 ; sctx . sspreshift + + ) {
unsigned char * dbits = bmp_tmp ; /* use bmp_tmp[], this is why the size check */
unsigned int y , b ;
for ( y = 0 ; y < t - > sprite_height ; y + + ) {
unsigned int shif = 0 ;
unsigned int sr =
t - > upsidedown ? ( t - > sprite_height - 1 - y ) : y ;
const unsigned char * sbits =
( const unsigned char * ) t - > bmp +
( sctx . sscol * ( ( t - > sprite_width + 7u ) / 8u ) ) +
( ( ( sctx . ssrow * t - > sprite_height ) + sr ) * t - > bmp_stride ) ;
b = sctx . bytesperrow ;
while ( b > = 2 ) {
b - - ;
shif = ( shif < < 8u ) + ( ( ( unsigned int ) ( * sbits + + ) ) < < ( 8u - sctx . sspreshift ) ) ;
* dbits + + = shif > > 8u ;
}
while ( b > = 1 ) {
b - - ;
shif = ( shif < < 8u ) ;
* dbits + + = shif > > 8u ;
}
}
if ( saveout_write_sprite ( t , & sctx , bmp_tmp ) )
goto fioerr ;
}
if ( t - > output_type = = REC98_OUT_C ) {
fprintf ( sctx . fp , " }/*end preshift*/ \n " ) ;
}
}
}
}
else if ( t - > preshift & & t - > preshift_inner = = 0 ) {
for ( sctx . sspreshift = 0 ; sctx . sspreshift < 8 ; sctx . sspreshift + + ) {
if ( t - > output_type = = REC98_OUT_C ) {
fprintf ( sctx . fp , " %c " , sctx . sspreshift ! = 0 ? ' , ' : ' ' ) ;
fprintf ( sctx . fp , " {/*preshift %u*/ \n " , sctx . sspreshift ) ;
}
for ( sctx . ssrow = 0 ; sctx . ssrow < sctx . ssrows ; sctx . ssrow + + ) {
sctx . spritenum = sctx . ssrow * sctx . sscols ;
for ( sctx . sscol = 0 ; sctx . sscol < sctx . sscols ; sctx . sscol + + , sctx . spritenum + + ) {
unsigned char * dbits = bmp_tmp ; /* use bmp_tmp[], this is why the size check */
unsigned int y , b ;
for ( y = 0 ; y < t - > sprite_height ; y + + ) {
unsigned int shif = 0 ;
unsigned int sr =
t - > upsidedown ? ( t - > sprite_height - 1 - y ) : y ;
const unsigned char * sbits =
( const unsigned char * ) t - > bmp +
( sctx . sscol * ( ( t - > sprite_width + 7u ) / 8u ) ) +
( ( ( sctx . ssrow * t - > sprite_height ) + sr ) * t - > bmp_stride ) ;
b = sctx . bytesperrow ;
while ( b > = 2 ) {
b - - ;
shif = ( shif < < 8u ) + ( ( ( unsigned int ) ( * sbits + + ) ) < < ( 8u - sctx . sspreshift ) ) ;
* dbits + + = shif > > 8u ;
}
while ( b > = 1 ) {
b - - ;
shif = ( shif < < 8u ) ;
* dbits + + = shif > > 8u ;
}
}
if ( saveout_write_sprite ( t , & sctx , bmp_tmp ) )
goto fioerr ;
}
}
if ( t - > output_type = = REC98_OUT_C ) {
fprintf ( sctx . fp , " }/*end preshift %u*/ \n " , sctx . sspreshift ) ;
}
}
}
else {
sctx . sspreshift = 0 ;
for ( sctx . ssrow = 0 ; sctx . ssrow < sctx . ssrows ; sctx . ssrow + + ) {
sctx . spritenum = sctx . ssrow * sctx . sscols ;
for ( sctx . sscol = 0 ; sctx . sscol < sctx . sscols ; sctx . sscol + + , sctx . spritenum + + ) {
unsigned char * dbits = bmp_tmp ; /* use bmp_tmp[], this is why the size check */
unsigned int y , b ;
for ( y = 0 ; y < t - > sprite_height ; y + + ) {
unsigned int sr =
t - > upsidedown ? ( t - > sprite_height - 1 - y ) : y ;
const unsigned char * sbits =
( const unsigned char * ) t - > bmp +
( sctx . sscol * ( ( t - > sprite_width + 7u ) / 8u ) ) +
( ( ( sctx . ssrow * t - > sprite_height ) + sr ) * t - > bmp_stride ) ;
for ( b = 0 ; b < sctx . bytesperrow ; b + + )
* dbits + + = * sbits + + ;
}
if ( saveout_write_sprite ( t , & sctx , bmp_tmp ) )
goto fioerr ;
}
}
}
if ( saveout_write_epilogue ( t , & sctx ) )
goto fioerr ;
fclose ( sctx . fp ) ;
return 0 ;
fioerr :
fclose ( sctx . fp ) ;
return - 1 ;
}
int rec98_bmp2arr_load_bitmap ( struct rec98_bmp2arr_task * t ) {
unsigned char * tmprow = NULL ;
uint8_t xorval = 0 ;
uint32_t srcstride ;
uint32_t offbits ;
uint32_t bisize ;
uint16_t bpp ;
uint32_t row ;
int fd ;
if ( t = = NULL | | t - > input_bmp = = NULL ) return - 1 ;
if ( t - > bmp ! = NULL ) return - 1 ;
fd = open ( t - > input_bmp , O_RDONLY | O_BINARY ) ;
if ( fd < 0 ) return - 1 ;
if ( lseek ( fd , 0 , SEEK_SET ) ! = 0 ) goto fioerr ;
/* BITMAPFILEHEADER */
if ( read ( fd , bmp_tmp , 14 ) ! = 14 ) goto fioerr ;
if ( memcmp ( bmp_tmp , " BM " , 2 ) ) goto fioerr ;
offbits = le32toh ( * ( ( uint32_t * ) ( bmp_tmp + 10 ) ) ) ; /* endian.h little endian to host */
/* BITMAPINFOHEADER */
if ( read ( fd , bmp_tmp , 40 ) ! = 40 ) goto fioerr ;
bisize = le32toh ( * ( ( uint32_t * ) ( bmp_tmp + 0 ) ) ) ;
if ( bisize < 40 ) goto fioerr ; /* *sigh* GIMP has decided to export the larger header with NO option to emit the traditional 40-byte format */
t - > bmp_width = le32toh ( * ( ( uint32_t * ) ( bmp_tmp + 4 ) ) ) ;
t - > bmp_height = le32toh ( * ( ( uint32_t * ) ( bmp_tmp + 8 ) ) ) ;
if ( t - > bmp_width < 1 | | t - > bmp_height < 1 | | t - > bmp_width > 1024 | | t - > bmp_height > 1024 ) goto fioerr ;
if ( le16toh ( * ( ( uint16_t * ) ( bmp_tmp + 12 ) ) ) ! = 1 /* biPlanes*/ )
goto fioerr ;
/* biCompression can be 0 (no compression) or 3 (BI_RGB) */
if ( ! ( le32toh ( * ( ( uint32_t * ) ( bmp_tmp + 16 ) ) ) = = 0 /* biCompression */ | |
le32toh ( * ( ( uint32_t * ) ( bmp_tmp + 16 ) ) ) = = 3 /* biCompression */ ) )
goto fioerr ;
bpp = le16toh ( * ( ( uint16_t * ) ( bmp_tmp + 14 ) ) ) ;
if ( ! ( bpp = = 1 | | bpp = = 24 | | bpp = = 32 ) ) goto fioerr ;
t - > bmp_stride = srcstride = ( ( ( t - > bmp_width * bpp ) + 31u ) & ( ~ 31u ) ) / 8u ; /* 4-byte align */
# if TARGET_MSDOS == 16
if ( ( 32768u / t - > bmp_stride ) < t - > bmp_height ) /* cannot fit into 32KB */
goto fioerr ;
# endif
/* skip anything beyond the 40 byte header we expect */
if ( bisize > 40 )
lseek ( fd , bisize - 40 , SEEK_CUR ) ;
/* palette */
if ( bpp = = 1 ) {
if ( read ( fd , bmp_tmp , 4 * 2 ) ! = ( 4 * 2 ) ) goto fioerr ;
/* in case of stupid editing programs that put the white color first */
if ( ( bmp_tmp [ 0 ] | bmp_tmp [ 1 ] | bmp_tmp [ 2 ] ) & 0x80 ) xorval = 0xFF ;
}
2020-07-09 07:39:06 +00:00
t - > bmp = ( unsigned char * ) malloc ( t - > bmp_height * t - > bmp_stride ) ;
2020-07-06 22:14:50 +00:00
if ( t - > bmp = = NULL ) goto fioerr ;
/* read bitmap bits. BMPs are upside-down */
if ( lseek ( fd , offbits , SEEK_SET ) ! = offbits ) goto fioerr ;
/* may need to convert to 1bpp from source */
# if TARGET_MSDOS == 16
if ( srcstride > = 0xFFFFul ) goto fioerr ;
# endif
2020-07-09 07:39:06 +00:00
tmprow = ( unsigned char * ) malloc ( ( unsigned int ) srcstride ) ;
2020-07-06 22:14:50 +00:00
if ( tmprow = = NULL ) goto fioerr ;
/* count: height-1 to 0 inclusive */
row = t - > bmp_height - 1u ;
do {
if ( ( uint32_t ) read ( fd , tmprow , ( unsigned int ) srcstride ) ! = srcstride ) goto fioerr ;
if ( bpp = = 1 )
memcpyxor ( t - > bmp + ( row * t - > bmp_stride ) , tmprow , ( unsigned int ) srcstride , xorval ) ;
else if ( bpp = = 24 )
memcpy24to1 ( t - > bmp + ( row * t - > bmp_stride ) , tmprow , t - > bmp_width ) ;
else if ( bpp = = 32 )
memcpy32to1 ( t - > bmp + ( row * t - > bmp_stride ) , tmprow , t - > bmp_width ) ;
} while ( row - - ! = 0u ) ; /* compare against post decrement to break out if it is zero */
2020-07-09 07:39:06 +00:00
if ( tmprow ) free ( ( void * ) tmprow ) ;
2020-07-06 22:14:50 +00:00
close ( fd ) ;
return 0 ;
fioerr :
2020-07-09 07:39:06 +00:00
if ( tmprow ) free ( ( void * ) tmprow ) ;
2020-07-06 22:14:50 +00:00
close ( fd ) ;
return - 1 ;
}