support Atari ST CA1 format (Crack Art)
This commit is contained in:
parent
893f4531c9
commit
1f601d06ae
@ -138,6 +138,7 @@ enum FILE_FORMATS
|
||||
FORMAT_SCx, ///< ColoRIX
|
||||
FORMAT_PI1, ///< Atari ST Degas
|
||||
FORMAT_PC1, ///< Atari ST Degas Elite
|
||||
FORMAT_CA1, ///< Atari ST CrackArt
|
||||
FORMAT_CEL, ///< Atari ST Cyber Paint Cell
|
||||
FORMAT_NEO, ///< Atari ST NeoChrome
|
||||
FORMAT_TNY, ///< Atari ST Tiny Stuff
|
||||
|
||||
@ -101,6 +101,11 @@ void Test_PC1(T_IO_Context *, FILE *);
|
||||
void Load_PC1(T_IO_Context *);
|
||||
void Save_PC1(T_IO_Context *);
|
||||
|
||||
// -- CA1 -------------------------------------------------------------------
|
||||
void Test_CA1(T_IO_Context *, FILE *);
|
||||
void Load_CA1(T_IO_Context *);
|
||||
void Save_CA1(T_IO_Context *);
|
||||
|
||||
// -- Tiny Stuff ------------------------------------------------------------
|
||||
void Test_TNY(T_IO_Context *, FILE *);
|
||||
void Load_TNY(T_IO_Context *);
|
||||
|
||||
@ -520,6 +520,7 @@ static const T_Help_table helptable_credits[] =
|
||||
HELP_TITLE(" FILE FORMATS CREDITS")
|
||||
HELP_TEXT ("")
|
||||
HELP_TEXT (" BMP,ICO : Microsoft")
|
||||
HELP_TEXT (" CA1 : Crack Art (Jaybee and Roy)")
|
||||
HELP_TEXT (" CEL,KCF : K.O.S. (KISekae Set system)")
|
||||
HELP_TEXT (" CM5 : SyX")
|
||||
HELP_TEXT (" EGX : Targhan & Supersly / Cargosoft")
|
||||
|
||||
@ -115,7 +115,7 @@ static void Save_ClipBoard_Image(T_IO_Context *);
|
||||
const T_Format File_formats[] = {
|
||||
{FORMAT_ALL_IMAGES, "(all)", NULL, NULL, NULL, 0, 0, 0, "",
|
||||
"gif;png;bmp;2bp;pcx;pkm;iff;lbm;ilbm;sham;ham;ham6;ham8;acbm;pic;anim;img;sci;scq;scf;scn;sco;cel;"
|
||||
"pi1;pc1;pi2;pc2;pi3;pc3;neo;tny;tn1;tn2;tn3;tn4;"
|
||||
"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;"
|
||||
@ -139,6 +139,7 @@ const T_Format File_formats[] = {
|
||||
{FORMAT_SCx, " sc?", Test_SCx, Load_SCx, Save_SCx, 0, 0, 0, "sc?", "sci;scq;scf;scn;sco"},
|
||||
{FORMAT_PI1, " pi1", Test_PI1, Load_PI1, Save_PI1, 0, 0, 0, "pi1", "pi1;pi2;pi3"},
|
||||
{FORMAT_PC1, " pc1", Test_PC1, Load_PC1, Save_PC1, 0, 0, 0, "pc1", "pc1;pc2;pc3"},
|
||||
{FORMAT_CA1, " ca1", Test_CA1, Load_CA1, Save_CA1, 0, 0, 0, "ca1", "ca1;ca2;ca3"},
|
||||
{FORMAT_TNY, " tny", Test_TNY, Load_TNY, Save_TNY, 0, 0, 0, "tny", "tny;tn1;tn2;tn3;tn4"},
|
||||
{FORMAT_CEL, " cel", Test_CEL, Load_CEL, Save_CEL, 0, 0, 0, "cel", "cel"},
|
||||
{FORMAT_NEO, " neo", Test_NEO, Load_NEO, Save_NEO, 0, 0, 0, "neo", "neo"},
|
||||
|
||||
419
src/stformats.c
419
src/stformats.c
@ -100,7 +100,7 @@ void PI2_8b_to_16p(const byte * src,byte * dest)
|
||||
|
||||
//// CODAGE d'une partie d'IMAGE ////
|
||||
|
||||
void PI1_16p_to_8b(byte * src,byte * dest)
|
||||
void PI1_16p_to_8b(const byte * src, byte * dest)
|
||||
{
|
||||
int i; // index du pixel à calculer
|
||||
word byte_mask; // Masque de codage
|
||||
@ -1513,4 +1513,421 @@ error:
|
||||
Remove_file(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* test for CrackArt format.
|
||||
*
|
||||
* Test that the files starts with the "CA" signature,
|
||||
* then 1 byte for the compressed flag (0 or 1),
|
||||
* then 1 byte for the resolution (0=low, 1=med, 2=high)
|
||||
*/
|
||||
void Test_CA1(T_IO_Context * context, FILE * file)
|
||||
{
|
||||
byte header[4];
|
||||
|
||||
(void)context;
|
||||
File_error = 1;
|
||||
if (!Read_bytes(file, header, 4))
|
||||
return;
|
||||
if (header[0] == 'C' && header[1] == 'A')
|
||||
{
|
||||
if ((header[2] & 0xfe) == 0 && (header[3] < 3))
|
||||
File_error = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Load_CA1(T_IO_Context * context)
|
||||
{
|
||||
FILE * file;
|
||||
byte sig[2];
|
||||
byte compressed;
|
||||
byte res;
|
||||
byte * buffer;
|
||||
|
||||
File_error = 1;
|
||||
buffer = GFX2_malloc(32000);
|
||||
if (buffer == NULL)
|
||||
return;
|
||||
file = Open_file_read(context);
|
||||
if (file == NULL)
|
||||
{
|
||||
free(buffer);
|
||||
return;
|
||||
}
|
||||
if (Read_bytes(file, sig, 2) && Read_byte(file, &compressed)
|
||||
&& Read_byte(file, &res))
|
||||
{
|
||||
unsigned long file_size;
|
||||
short width = 640, height = 200;
|
||||
enum PIXEL_RATIO ratio = PIXEL_SIMPLE;
|
||||
byte bpp = 4;
|
||||
|
||||
file_size = File_length_file(file);
|
||||
GFX2_Log(GFX2_DEBUG, "Signature : '%c%c' %s res=%d\n",
|
||||
sig[0], sig[1], compressed ? "compressed" : "", res);
|
||||
switch (res)
|
||||
{
|
||||
case 0:
|
||||
width = 320;
|
||||
break;
|
||||
case 1:
|
||||
ratio = PIXEL_TALL;
|
||||
bpp = 2;
|
||||
break;
|
||||
case 2:
|
||||
height = 400;
|
||||
bpp = 1;
|
||||
}
|
||||
File_error = 0;
|
||||
|
||||
Pre_load(context, width, height, file_size, FORMAT_CA1, ratio, bpp);
|
||||
if (File_error == 0)
|
||||
{
|
||||
if (Config.Clear_palette)
|
||||
memset(context->Palette,0,sizeof(T_Palette));
|
||||
memset(buffer, 0, 32);
|
||||
if (res == 2)
|
||||
{
|
||||
// black & white
|
||||
buffer[0] = 0xff;
|
||||
buffer[1] = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Read_bytes(file, buffer, 1 << (bpp + 1)))
|
||||
File_error = 1;
|
||||
}
|
||||
PI1_decode_palette(buffer, context->Palette);
|
||||
if (compressed)
|
||||
{
|
||||
byte escape, delta;
|
||||
word offset;
|
||||
|
||||
if (!(Read_byte(file, &escape) && Read_byte(file, &delta) && Read_word_be(file, &offset)))
|
||||
File_error = 1;
|
||||
else if(offset != 0)
|
||||
{
|
||||
int i = 0, c = 0;
|
||||
|
||||
GFX2_Log(GFX2_DEBUG, " escape=%02X delta=%02X offset=%hu\n", escape, delta, offset);
|
||||
memset(buffer, delta, 32000);
|
||||
while (c < 32000 && File_error == 0)
|
||||
{
|
||||
byte cmd, data;
|
||||
word repeat;
|
||||
|
||||
repeat = 0;
|
||||
data = delta;
|
||||
if (!Read_byte(file, &cmd))
|
||||
File_error = 1;
|
||||
if (cmd == escape)
|
||||
{
|
||||
if (!Read_byte(file, &cmd))
|
||||
File_error = 1;
|
||||
if (cmd == 0)
|
||||
{
|
||||
// byte count repeat
|
||||
if (!Read_byte(file, &cmd) || !Read_byte(file, &data))
|
||||
File_error = 1;
|
||||
repeat = cmd;
|
||||
GFX2_Log(GFX2_DEBUG, "byte count repeat : 0x%02x,0x%02x,%hu,0x%02x\n", escape, 0, repeat, data);
|
||||
}
|
||||
else if (cmd == 1)
|
||||
{
|
||||
// word count repeat
|
||||
if (!Read_word_be(file, &repeat) || !Read_byte(file, &data))
|
||||
File_error = 1;
|
||||
GFX2_Log(GFX2_DEBUG, "word count repeat : 0x%02x,0x%02x,%hu,0x%02x\n", escape, cmd, repeat, data);
|
||||
}
|
||||
else if (cmd == 2)
|
||||
{
|
||||
if (!Read_byte(file, &cmd))
|
||||
File_error = 1;
|
||||
else if (cmd == 0)
|
||||
{
|
||||
// ESC,02,00 => STOP code
|
||||
GFX2_Log(GFX2_DEBUG, "STOP : 0x%02x,0x02,%02x\n", escape, cmd);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ESC,02,a,b => repeat (a << 8 + b + 1) x byte "delta"
|
||||
repeat = cmd << 8;
|
||||
if (!Read_byte(file, &cmd))
|
||||
File_error = 1;
|
||||
repeat += cmd;
|
||||
GFX2_Log(GFX2_DEBUG, "delta repeat : 0x%02x,%hu\n", escape, repeat);
|
||||
}
|
||||
}
|
||||
else if (cmd == escape)
|
||||
{
|
||||
// ESC,ESC => 1 x byte "ESC"
|
||||
data = cmd;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ESC,a,b => repeat (a + 1) x byte b
|
||||
repeat = cmd;
|
||||
if (!Read_byte(file, &data))
|
||||
File_error = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data = cmd;
|
||||
}
|
||||
// output bytes
|
||||
do
|
||||
{
|
||||
buffer[i] = data;
|
||||
i += offset;
|
||||
c++;
|
||||
if (i >= 32000)
|
||||
i -= (32000 - 1);
|
||||
}
|
||||
while (repeat-- > 0);
|
||||
}
|
||||
GFX2_Log(GFX2_DEBUG, "finished : i=%d c=%d\n", i, c);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// not compressed
|
||||
if (!Read_bytes(file, buffer, 32000))
|
||||
File_error = 1;
|
||||
}
|
||||
if (File_error == 0)
|
||||
{
|
||||
int line;
|
||||
const byte * ptr = buffer;
|
||||
int ncols;
|
||||
|
||||
ncols = (res == 0) ? 20 : 40;
|
||||
|
||||
for (line = 0; line < height; line++)
|
||||
{
|
||||
byte pixels[16];
|
||||
int col, x;
|
||||
|
||||
for (col = 0; col < ncols; col++)
|
||||
{
|
||||
switch (res)
|
||||
{
|
||||
case 0:
|
||||
PI1_8b_to_16p(ptr, pixels);
|
||||
ptr += 8;
|
||||
for (x = 0; x < 16; x++)
|
||||
Set_pixel(context, col * 16 + x, line, pixels[x]);
|
||||
break;
|
||||
case 1:
|
||||
PI2_8b_to_16p(ptr, pixels);
|
||||
ptr += 4;
|
||||
for (x = 0; x < 16; x++)
|
||||
Set_pixel(context, col * 16 + x, line, pixels[x]);
|
||||
break;
|
||||
case 2:
|
||||
for (x = 0 ; x < 16; x++)
|
||||
Set_pixel(context, col * 16 + x, line, (ptr[(x >> 3)] >> (7 - (x & 7))) & 1);
|
||||
ptr += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a 320x200 16c picture in CrackArt format
|
||||
*
|
||||
* @todo support medium and high resolution
|
||||
*/
|
||||
void Save_CA1(T_IO_Context * context)
|
||||
{
|
||||
FILE * file;
|
||||
byte * buffer;
|
||||
byte res = 0; // 0 = low, 1 = med, 2 = high
|
||||
byte compressed = 1; // 0 or 1
|
||||
int height = 200;
|
||||
|
||||
File_error = 1;
|
||||
buffer = GFX2_malloc(32000);
|
||||
if (buffer == NULL)
|
||||
return;
|
||||
file = Open_file_write(context);
|
||||
if (file == NULL)
|
||||
{
|
||||
free(buffer);
|
||||
return;
|
||||
}
|
||||
if (Write_bytes(file, "CA", 2) && Write_byte(file, compressed) && Write_byte(file, res))
|
||||
{
|
||||
PI1_code_palette(context->Palette, buffer);
|
||||
if (Write_bytes(file, buffer, 32))
|
||||
{
|
||||
int line;
|
||||
byte * ptr = buffer;
|
||||
|
||||
for (line = 0; line < height; line++)
|
||||
{
|
||||
byte pixels[16];
|
||||
int col, x;
|
||||
|
||||
for (col = 0; col < 20; col++)
|
||||
{
|
||||
for (x = 0; x < 16; x++)
|
||||
pixels[x] = Get_pixel(context, col * 16 + x, line);
|
||||
PI1_16p_to_8b(pixels, ptr);
|
||||
ptr += 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (compressed)
|
||||
{
|
||||
word freq[256];
|
||||
word max, min;
|
||||
byte max_index, min_index;
|
||||
byte escape;
|
||||
word offset;
|
||||
int i;
|
||||
|
||||
memset(freq, 0, sizeof(freq));
|
||||
for (i = 0; i < 32000; i++)
|
||||
freq[buffer[i]]++;
|
||||
min = 65535;
|
||||
min_index = 0;
|
||||
max = 0;
|
||||
max_index = 0;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
if (freq[i] <= min && i > 2)
|
||||
{
|
||||
min = freq[i];
|
||||
min_index = (byte)i;
|
||||
}
|
||||
if (freq[i] > max)
|
||||
{
|
||||
max = freq[i];
|
||||
max_index = (byte)i;
|
||||
}
|
||||
}
|
||||
GFX2_Log(GFX2_DEBUG, " 0x%02X (%hu times) 0x%02X (%hu times)\n", min_index, min, max_index, max);
|
||||
escape = min_index;
|
||||
offset = 160; // 80 in high res
|
||||
if (Write_byte(file, escape) && Write_byte(file, max_index) && Write_word_be(file, offset))
|
||||
{
|
||||
int c = 1;
|
||||
byte current;
|
||||
word count = 0;
|
||||
File_error = 0;
|
||||
i = offset;
|
||||
current = buffer[0];
|
||||
while (c < 32000 && File_error == 0)
|
||||
{
|
||||
if (buffer[i] == current)
|
||||
count++;
|
||||
else
|
||||
{
|
||||
if (count < 3)
|
||||
{
|
||||
// Litteral
|
||||
do
|
||||
{
|
||||
if (!Write_byte(file, current))
|
||||
File_error = 1;
|
||||
if (current == escape)
|
||||
Write_byte(file, current);
|
||||
}
|
||||
while (count-- && File_error == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
GFX2_Log(GFX2_DEBUG, "byte %02X x %hu\n", current, count);
|
||||
if (count < 256)
|
||||
{
|
||||
// ESC,a,b => repeat (a + 1) x byte b
|
||||
// with a > 2
|
||||
if (!(Write_byte(file, escape)
|
||||
&& Write_byte(file, count)
|
||||
&& Write_byte(file, current)))
|
||||
File_error = 1;
|
||||
}
|
||||
else if (current == max_index)
|
||||
{
|
||||
// ESC,02,word count => repeat (count + 1) x byte "delta"
|
||||
if (!(Write_byte(file, escape)
|
||||
&& Write_byte(file, 2)
|
||||
&& Write_word_be(file, count)))
|
||||
File_error = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ESC,01,word count,data
|
||||
if (!(Write_byte(file, escape)
|
||||
&& Write_byte(file, 1)
|
||||
&& Write_word_be(file, count)
|
||||
&& Write_byte(file, current)))
|
||||
File_error = 1;
|
||||
}
|
||||
}
|
||||
current = buffer[i];
|
||||
count = 0;
|
||||
}
|
||||
i += offset;
|
||||
c++;
|
||||
if (i >= 32000)
|
||||
i -= (32000 - 1);
|
||||
}
|
||||
GFX2_Log(GFX2_DEBUG, "end: byte %02X x %hu\n", current, count);
|
||||
if (count < 3)
|
||||
{
|
||||
do
|
||||
{
|
||||
Write_byte(file, current);
|
||||
if (current == escape)
|
||||
Write_byte(file, current);
|
||||
}
|
||||
while (count--);
|
||||
}
|
||||
else if (current == max_index)
|
||||
{
|
||||
// STOP code
|
||||
if (!(Write_byte(file, escape)
|
||||
&& Write_byte(file, 2)
|
||||
&& Write_byte(file, 0)))
|
||||
File_error = 1;
|
||||
}
|
||||
else if (count < 256)
|
||||
{
|
||||
// ESC,a,b => repeat (a + 1) x byte b
|
||||
// with a > 2
|
||||
if (!(Write_byte(file, escape)
|
||||
&& Write_byte(file, count)
|
||||
&& Write_byte(file, current)))
|
||||
File_error = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ESC,01,word count,data
|
||||
if (!(Write_byte(file, escape)
|
||||
&& Write_byte(file, 1)
|
||||
&& Write_word_be(file, count)
|
||||
&& Write_byte(file, current)))
|
||||
File_error = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// uncompressed
|
||||
if (Write_bytes(file, buffer, 32000))
|
||||
File_error = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
/* @} */
|
||||
|
||||
@ -70,6 +70,7 @@ static const struct {
|
||||
TESTFMTF(NEO, "atari_st/ATARIART.NEO", FLAG_16C)
|
||||
TESTFMTF(PC1, "atari_st/eunmiisa.pc1", FLAG_16C)
|
||||
TESTFMTF(PI1, "atari_st/evolutn.pi1", FLAG_16C)
|
||||
TESTFMTF(CA1, "atari_st/GIANTS.CA1", FLAG_16C)
|
||||
TESTFMTF(TNY, "atari_st/rose.tny", FLAG_16C)
|
||||
TESTFMTL(FLI, "autodesk_FLI_FLC/2noppaa.fli")
|
||||
TESTFMT(BMP, "bmp/test8.bmp")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user