Load SGX SymbOS graphics
This commit is contained in:
parent
951f58445c
commit
713fd9ff71
@ -129,6 +129,7 @@ enum FILE_FORMATS
|
||||
FORMAT_CM5, ///< Amstrad CPC Mode 5
|
||||
FORMAT_PPH, ///< Amstrad CPC Perfect Pix
|
||||
FORMAT_GOS, ///< Amstrad Plus Graphos
|
||||
FORMAT_SGX, ///< SymbOS graphic files
|
||||
FORMAT_XPM, ///< X PixMap
|
||||
FORMAT_ICO, ///< Windows icons
|
||||
FORMAT_INFO, ///< Amiga OS icons
|
||||
|
||||
223
src/cpcformats.c
223
src/cpcformats.c
@ -33,6 +33,10 @@
|
||||
#include "gfx2mem.h"
|
||||
#include "gfx2log.h"
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) (((a)>(b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup cpcformats Amstrad CPC/CPC+ picture formats
|
||||
* @ingroup loadsaveformats
|
||||
@ -48,10 +52,229 @@
|
||||
* - SCR : OCP Art Studio / iMPdraw v2 / etc.
|
||||
* - CM5 : Mode 5 Viewer
|
||||
* - PPH : Perfect Pix
|
||||
* - SGX : SymbOS graphic files
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test for SGX file (SymbOS)
|
||||
*
|
||||
* http://www.cpcwiki.eu/index.php/Format:SGX_(SymbOS_graphic_files)
|
||||
*/
|
||||
void Test_SGX(T_IO_Context * context, FILE * file)
|
||||
{
|
||||
byte header[8];
|
||||
(void)context;
|
||||
|
||||
if (Read_bytes(file, header, 8))
|
||||
{
|
||||
unsigned long file_size = File_length_file(file);
|
||||
if (header[0] > 0 && header[0] < 64
|
||||
&& ((header[1] + 3) >> 2) == header[0]
|
||||
&& file_size >= (3 + (unsigned long)header[0] * (unsigned long)header[2]))
|
||||
{
|
||||
// Simple 4 colour graphic
|
||||
File_error = 0;
|
||||
}
|
||||
else if (header[0] == 64 && (header[1] == 0 || header[1] == 5))
|
||||
{
|
||||
// extended
|
||||
word byte_width = header[2] | ((word)header[3] << 8);
|
||||
word pixel_width = header[4] | ((word)header[5] << 8);
|
||||
word height = header[6] | ((word)header[7] << 8);
|
||||
if (height == 0 || byte_width == 0 || byte_width > 255) return;
|
||||
if (header[1] == 0 && byte_width != ((pixel_width + 3) >> 2)) return;
|
||||
if (header[1] == 5 && byte_width != ((pixel_width + 1) >> 1)) return;
|
||||
File_error = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Set_SGX_Palette(T_IO_Context * context)
|
||||
{
|
||||
static const byte sgx_palette[] = {
|
||||
0xff, 0xff, 0x80, // 0
|
||||
0x00, 0x00, 0x00,
|
||||
0xff, 0x80, 0x00,
|
||||
0x80, 0x00, 0x00,
|
||||
0x00, 0xff, 0xff, // 4
|
||||
0x00, 0x00, 0x80,
|
||||
0x80, 0x80, 0xff,
|
||||
0x80, 0x00, 0xff,
|
||||
0xff, 0xff, 0xff, // 8
|
||||
0x00, 0x80, 0x00,
|
||||
0x00, 0xff, 0x00,
|
||||
0xff, 0x00, 0xff,
|
||||
0xff, 0xff, 0x00, // 12
|
||||
0x80, 0x80, 0x80,
|
||||
0xff, 0x80, 0x80,
|
||||
0xff, 0x00, 0x00
|
||||
};
|
||||
if (Config.Clear_palette)
|
||||
memset(context->Palette,0,sizeof(T_Palette));
|
||||
memcpy(context->Palette, sgx_palette, sizeof(sgx_palette));
|
||||
}
|
||||
|
||||
/**
|
||||
* Structure for current information about loading SGX file
|
||||
*/
|
||||
struct sgx_data {
|
||||
T_IO_Context * context;
|
||||
FILE * file;
|
||||
unsigned long file_size;
|
||||
word width, height;
|
||||
byte ncolors;
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback function for Read_SGX()
|
||||
*/
|
||||
typedef int (*Read_SGX_Callback)(struct sgx_data *, word, word, word, word, word, byte);
|
||||
|
||||
/**
|
||||
* Read a SGX file structure.
|
||||
*
|
||||
* @return 0 for error
|
||||
*/
|
||||
static int Read_SGX(struct sgx_data * data, Read_SGX_Callback cb)
|
||||
{
|
||||
word posx = 0;
|
||||
word posy = 0;
|
||||
byte b;
|
||||
|
||||
data->width = 0;
|
||||
data->height = 0;
|
||||
while (Read_byte(data->file, &b))
|
||||
{
|
||||
if (b == 0)
|
||||
{
|
||||
// EOF
|
||||
GFX2_Log(GFX2_DEBUG, "SGX EOF\n");
|
||||
return 1;
|
||||
}
|
||||
else if (b == 255)
|
||||
{
|
||||
GFX2_Log(GFX2_DEBUG, "SGX LF\n");
|
||||
// skip 2 bytes
|
||||
if (!(Read_byte(data->file, &b) && Read_byte(data->file, &b)))
|
||||
return 0;
|
||||
posx = 0;
|
||||
posy = data->height;
|
||||
}
|
||||
else if (b < 64)
|
||||
{
|
||||
byte byte_width, width, height;
|
||||
byte_width = b;
|
||||
if (!(Read_byte(data->file, &width) && Read_byte(data->file, &height)))
|
||||
return 0;
|
||||
GFX2_Log(GFX2_DEBUG, "SGX Simple 4c : %dx%d\n", (int)width, (int)height);
|
||||
if (!cb(data, posx, posy, width, height, byte_width, 4))
|
||||
return 0;
|
||||
posx += width;
|
||||
data->width = MAX(data->width, posx);
|
||||
data->height = MAX(data->height, posy + height);
|
||||
if (data->ncolors == 0)
|
||||
data->ncolors = 4;
|
||||
}
|
||||
else if (b == 64)
|
||||
{
|
||||
byte type;
|
||||
word byte_width, width, height;
|
||||
if (!(Read_byte(data->file, &type) && Read_word_le(data->file, &byte_width)
|
||||
&& Read_word_le(data->file, &width) && Read_word_le(data->file, &height)))
|
||||
return 0;
|
||||
GFX2_Log(GFX2_DEBUG, "SGX Extended %dc : %dx%d\n", type == 0 ? 4 : 16, (int)width, (int)height);
|
||||
if (!cb(data, posx, posy, width, height, byte_width, type == 0 ? 4 : 16))
|
||||
return 0;
|
||||
posx += width;
|
||||
data->width = MAX(data->width, posx);
|
||||
data->height = MAX(data->height, posy + height);
|
||||
data->ncolors = MAX(data->ncolors, type == 0 ? 4 : 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
GFX2_Log(GFX2_WARNING, "SGX : unrecognized chunk. Byte 0x%02x at offset 0x%06x\n", b, ftell(data->file) - 1);
|
||||
}
|
||||
}
|
||||
return 1; // it is OK if the file does finish with a EOF mark
|
||||
}
|
||||
|
||||
/**
|
||||
* Only skip bytes
|
||||
*/
|
||||
int SGX_Get_dimensions(struct sgx_data * data, word posx, word posy, word width, word height, word byte_width, byte ncolors)
|
||||
{
|
||||
(void)posx;
|
||||
(void)posy;
|
||||
(void)width;
|
||||
(void)ncolors;
|
||||
if (fseek(data->file, (long)byte_width * height, SEEK_CUR) < 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the pixels
|
||||
* @return 0 in case of error
|
||||
*/
|
||||
int SGX_Load_Picture(struct sgx_data * data, word posx, word posy, word width, word height, word byte_width, byte ncolors)
|
||||
{
|
||||
word y;
|
||||
|
||||
for (y = posy; y < (posy + height); y++)
|
||||
{
|
||||
word i, x;
|
||||
for (i = 0, x = posx; i < byte_width; i++)
|
||||
{
|
||||
byte b;
|
||||
if (!Read_byte(data->file, &b))
|
||||
return 0;
|
||||
if (ncolors == 4)
|
||||
{
|
||||
do {
|
||||
// upper nibble is 4 lower color bits, lower nibble is 4 upper color bits
|
||||
Set_pixel(data->context, x++, y, (b & 0x80) >> 7 | (b & 0x08) >> 2);
|
||||
b <<= 1;
|
||||
}
|
||||
while (((x ^ posx) & 3) && (x < (posx + width)));
|
||||
}
|
||||
else
|
||||
{
|
||||
Set_pixel(data->context, x++, y, b >> 4);
|
||||
if (x < (posx + width))
|
||||
Set_pixel(data->context, x++, y, b & 0x0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Load_SGX(T_IO_Context * context)
|
||||
{
|
||||
struct sgx_data data = { context, NULL, 0, 0, 0, 0 };
|
||||
|
||||
File_error = 1;
|
||||
data.file = Open_file_read(context);
|
||||
if (data.file == NULL) return;
|
||||
data.file_size = File_length_file(data.file);
|
||||
if (Read_SGX(&data, SGX_Get_dimensions))
|
||||
{
|
||||
GFX2_Log(GFX2_DEBUG, "SGX total dimensions : %ux%u, %d colors\n",
|
||||
(unsigned)data.width, (unsigned)data.height, (int)data.ncolors);
|
||||
File_error = 0;
|
||||
Pre_load(context, data.width, data.height, data.file_size, FORMAT_SGX, PIXEL_SIMPLE, data.ncolors == 16 ? 4 : 2);
|
||||
if (File_error == 0)
|
||||
{
|
||||
if (fseek(data.file, 0, SEEK_SET) < 0 || !Read_SGX(&data, SGX_Load_Picture))
|
||||
File_error = 1;
|
||||
else
|
||||
Set_SGX_Palette(context);
|
||||
}
|
||||
}
|
||||
fclose(data.file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for SCR file (Amstrad CPC)
|
||||
*
|
||||
|
||||
@ -148,6 +148,10 @@ void Test_GOS(T_IO_Context *, FILE *);
|
||||
void Load_GOS(T_IO_Context *);
|
||||
void Save_GOS(T_IO_Context *);
|
||||
|
||||
// -- SGX (SymbOS)
|
||||
void Test_SGX(T_IO_Context *, FILE *);
|
||||
void Load_SGX(T_IO_Context *);
|
||||
|
||||
// -- XPM (X PixMap)
|
||||
// Loading is done through SDL_Image
|
||||
void Save_XPM(T_IO_Context*);
|
||||
|
||||
@ -541,6 +541,7 @@ static const T_Help_table helptable_credits[] =
|
||||
HELP_TEXT (" PPH : Rhino / Batman Group")
|
||||
HELP_TEXT (" SCx : Colorix (?)")
|
||||
HELP_TEXT (" SCR : Advanced OCP Art Studio + iMPdraw")
|
||||
HELP_TEXT (" SGX : SymbOS")
|
||||
HELP_TEXT (" TIFF : Aldus (now Adobe)")
|
||||
HELP_TEXT (" TNY : David Mumper")
|
||||
HELP_TEXT (" XPM : C.Nahaboo and D.Dardailler / Bull")
|
||||
|
||||
@ -112,7 +112,7 @@ const T_Format File_formats[] = {
|
||||
"pi1;pc1;pi2;pc2;pi3;pc3;neo;tny;tn1;tn2;tn3;tn4;ca1;ca2;ca3;"
|
||||
"c64;p64;a64;pi;rp;aas;art;dd;iph;ipt;hpc;ocp;koa;koala;fli;bml;cdu;prg;pmg;rpm;"
|
||||
"gpx;"
|
||||
"cpc;scr;win;pph;cm5;go1;"
|
||||
"cpc;scr;win;pph;cm5;go1;sgx;"
|
||||
"hgr;dhgr;"
|
||||
"grb;grob;"
|
||||
"sc2;"
|
||||
@ -148,6 +148,7 @@ const T_Format File_formats[] = {
|
||||
{FORMAT_CM5, " cm5", Test_CM5, Load_CM5, Save_CM5, 0, 0, 1, "cm5", "cm5"},
|
||||
{FORMAT_PPH, " pph", Test_PPH, Load_PPH, Save_PPH, 0, 0, 1, "pph", "pph"},
|
||||
{FORMAT_GOS, " go1", Test_GOS, Load_GOS, Save_GOS, 0, 0, 0, "go1", "go1"},
|
||||
{FORMAT_SGX, " sgx", Test_SGX, Load_SGX, NULL, 0, 0, 1, "sgx", "sgx"},
|
||||
{FORMAT_XPM, " xpm", NULL, NULL, Save_XPM, 0, 0, 0, "xpm", "xpm"},
|
||||
{FORMAT_ICO, " ico", Test_ICO, Load_ICO, Save_ICO, 0, 0, 0, "ico", "ico;ic2;cur"},
|
||||
{FORMAT_INFO," info",Test_INFO,Load_INFO,NULL, 0, 0, 0, "info", "info"},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user