improve Atari ST file formats NEOchrome and Degas

This commit is contained in:
Thomas Bernard 2018-12-14 09:25:19 +01:00
parent 003fbcfc1b
commit da092228f3
No known key found for this signature in database
GPG Key ID: 0FF11B67A5C0863C
2 changed files with 448 additions and 223 deletions

View File

@ -88,7 +88,8 @@ void Load_Recoil_Image(T_IO_Context *);
// ENUM Name TestFunc LoadFunc SaveFunc PalOnly Comment Layers Ext Exts // ENUM Name TestFunc LoadFunc SaveFunc PalOnly Comment Layers Ext Exts
const T_Format File_formats[] = { const T_Format File_formats[] = {
{FORMAT_ALL_IMAGES, "(all)", NULL, NULL, NULL, 0, 0, 0, "", {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;pi1;pc1;cel;neo;" "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;"
"c64;p64;a64;pi;rp;aas;art;dd;iph;ipt;hpc;ocp;koa;koala;fli;bml;cdu;prg;pmg;rpm;" "c64;p64;a64;pi;rp;aas;art;dd;iph;ipt;hpc;ocp;koa;koala;fli;bml;cdu;prg;pmg;rpm;"
"cpc;scr;win;" "cpc;scr;win;"
"hgr;dhgr;" "hgr;dhgr;"
@ -107,8 +108,8 @@ const T_Format File_formats[] = {
{FORMAT_ACBM," acbm",Test_ACBM,Load_IFF, NULL, 0, 1, 0, "iff", "iff;pic;acbm"}, {FORMAT_ACBM," acbm",Test_ACBM,Load_IFF, NULL, 0, 1, 0, "iff", "iff;pic;acbm"},
{FORMAT_IMG, " img", Test_IMG, Load_IMG, Save_IMG, 0, 0, 0, "img", "img"}, {FORMAT_IMG, " img", Test_IMG, Load_IMG, Save_IMG, 0, 0, 0, "img", "img"},
{FORMAT_SCx, " sc?", Test_SCx, Load_SCx, Save_SCx, 0, 0, 0, "sc?", "sci;scq;scf;scn;sco"}, {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"}, {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"}, {FORMAT_PC1, " pc1", Test_PC1, Load_PC1, Save_PC1, 0, 0, 0, "pc1", "pc1;pc2;pc3"},
{FORMAT_CEL, " cel", Test_CEL, Load_CEL, Save_CEL, 0, 0, 0, "cel", "cel"}, {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"}, {FORMAT_NEO, " neo", Test_NEO, Load_NEO, Save_NEO, 0, 0, 0, "neo", "neo"},
{FORMAT_KCF, " kcf", Test_KCF, Load_KCF, Save_KCF, 1, 0, 0, "kcf", "kcf"}, {FORMAT_KCF, " kcf", Test_KCF, Load_KCF, Save_KCF, 1, 0, 0, "kcf", "kcf"},

View File

@ -1414,11 +1414,28 @@ void Save_KCF(T_IO_Context * context)
} }
/**
* @defgroup atarist Atari ST picture formats
* @ingroup loadsaveformats
*
* Support for Atari ST picture formats. The Atari ST has
* 3 video modes :
* - low res : 320x200 16 colors
* - med res : 640x200 4 colors
* - high res : 640x400 monochrome
*
* Supported formats :
* - PI1 : Degas
* - PC1 : Degas elite compressed
* - NEO : Neochrome
*
* @{
*/
//////////////////////////////////// PI1 //////////////////////////////////// //////////////////////////////////// PI1 ////////////////////////////////////
//// DECODAGE d'une partie d'IMAGE //// //// DECODAGE d'une partie d'IMAGE ////
void PI1_8b_to_16p(byte * src,byte * dest) void PI1_8b_to_16p(const byte * src,byte * dest)
{ {
int i; // index du pixel à calculer int i; // index du pixel à calculer
word byte_mask; // Masque de decodage word byte_mask; // Masque de decodage
@ -1442,6 +1459,22 @@ void PI1_8b_to_16p(byte * src,byte * dest)
} }
} }
void PI2_8b_to_16p(const byte * src,byte * dest)
{
int i; // index du pixel à calculer
word mask; // Masque de decodage
word w0,w1;
w0=(((word)src[0])<<8) | src[1];
w1=(((word)src[2])<<8) | src[3];
mask=0x8000;
for (i = 0; i < 16; i++)
{
dest[i] = ((w0 & mask) ? 0x01 : 0) | ((w1 & mask) ? 0x02 : 0);
mask >>= 1;
}
}
//// CODAGE d'une partie d'IMAGE //// //// CODAGE d'une partie d'IMAGE ////
void PI1_16p_to_8b(byte * src,byte * dest) void PI1_16p_to_8b(byte * src,byte * dest)
@ -1521,8 +1554,8 @@ void PI1_code_palette(const T_Components * palette, byte * dest)
} }
} }
/// Load color ranges from a PI1 or PC1 image (Degas Elite format) /// Load color cycling data from a PI1 or PC1 image (Degas Elite format)
void PI1_load_ranges(T_IO_Context * context, const byte * buffer, int size) static void PI1_load_ranges(T_IO_Context * context, const byte * buffer, int size)
{ {
int range; int range;
@ -1540,6 +1573,8 @@ void PI1_load_ranges(T_IO_Context * context, const byte * buffer, int size)
if (max_col < min_col) if (max_col < min_col)
SWAP_WORDS(min_col,max_col) SWAP_WORDS(min_col,max_col)
GFX2_Log(GFX2_DEBUG, "Degas Color cycling : [#%d:#%d] direction=%d delay=%d\n", min_col, max_col, direction, delay);
// Sanity checks // Sanity checks
if (min_col < 256 && max_col < 256 && direction < 3 && (direction == 1 || delay < 128)) if (min_col < 256 && max_col < 256 && direction < 3 && (direction == 1 || delay < 128))
{ {
@ -1591,83 +1626,122 @@ void PI1_save_ranges(T_IO_Context * context, byte * buffer, int size)
} }
} }
} }
// -- Tester si un fichier est au format PI1 --------------------------------
/// Test for Degas file format
void Test_PI1(T_IO_Context * context, FILE * file) void Test_PI1(T_IO_Context * context, FILE * file)
{ {
int size; // Taille du fichier unsigned long size; // Taille du fichier
word resolution; // Résolution de l'image word resolution; // Résolution de l'image
(void)context; (void)context;
File_error=1; File_error=1;
// Vérification de la taille if (!Read_word_be(file,&resolution))
size=File_length_file(file); return;
if ((size==32034) || (size==32066))
{ size = File_length_file(file);
// Lecture et vérification de la résolution if ((size==32034) || (size==32066)) // size check
if (Read_word_le(file,&resolution)) {
{ if (resolution < 3)
if (resolution==0x0000) File_error=0;
File_error=0; }
}
}
} }
// -- Lire un fichier au format PI1 ----------------------------------------- /// Load Degas file format
void Load_PI1(T_IO_Context * context) void Load_PI1(T_IO_Context * context)
{ {
enum PIXEL_RATIO ratio = PIXEL_SIMPLE;
word resolution;
word width, height;
FILE *file; FILE *file;
word x_pos,y_pos; word x_pos,y_pos;
byte * buffer; byte buffer[160];
byte * ptr; byte * ptr;
byte pixels[320]; byte pixels[320];
byte bpp;
File_error=0; File_error = 1;
if ((file=Open_file_read(context))) file = Open_file_read(context);
if (file == NULL)
return;
if (!Read_word_be(file, &resolution))
return;
GFX2_Log(GFX2_DEBUG, "Degas UnCompressed. Resolution = %04x\n", resolution);
// Read palette
if (!Read_bytes(file, buffer, 32))
{ {
// allocation d'un buffer mémoire
buffer=(byte *)malloc(32034);
if (buffer!=NULL)
{
// Lecture du fichier dans le buffer
if (Read_bytes(file,buffer,32034))
{
// Initialisation de la preview
Pre_load(context, 320,200,File_length_file(file),FORMAT_PI1,PIXEL_SIMPLE,4);
if (File_error==0)
{
// Initialisation de la palette
if (Config.Clear_palette)
memset(context->Palette,0,sizeof(T_Palette));
PI1_decode_palette(buffer+2, context->Palette);
// Chargement/décompression de l'image
ptr=buffer+34;
for (y_pos=0;y_pos<200;y_pos++)
{
for (x_pos=0;x_pos<(320>>4);x_pos++)
{
PI1_8b_to_16p(ptr,pixels+(x_pos<<4));
ptr+=8;
}
for (x_pos=0;x_pos<320;x_pos++)
Set_pixel(context, x_pos,y_pos,pixels[x_pos]);
}
PI1_load_ranges(context, buffer, 32034);
}
}
else
File_error=1;
free(buffer);
buffer = NULL;
}
else
File_error=1;
fclose(file); fclose(file);
return;
} }
else if (Config.Clear_palette)
File_error=1; memset(context->Palette,0,sizeof(T_Palette));
PI1_decode_palette(buffer, context->Palette);
switch (resolution)
{
case 0: // Low Res
width = 320;
height = 200;
bpp = 4;
break;
case 1: // Med Res
width = 640;
height = 200;
bpp = 2;
ratio = PIXEL_TALL;
break;
case 2: // High Res
width = 640;
height = 400;
bpp = 1;
break;
default:
fclose(file);
return;
}
Pre_load(context, width, height, File_length_file(file),FORMAT_PI1,ratio, bpp);
for (y_pos=0;y_pos<height;y_pos++)
{
if (!Read_bytes(file, buffer, (resolution == 2) ? 80 : 160))
{
fclose(file);
return;
}
ptr = buffer;
for (x_pos=0; x_pos < width;)
{
int i;
switch (resolution)
{
case 0:
PI1_8b_to_16p(ptr, pixels);
ptr += 8;
break;
case 1:
PI2_8b_to_16p(ptr, pixels);
ptr += 4;
break;
case 2:
for (i = 0; i < 8; i++)
pixels[i] = (ptr[0] & (0x80 >> i)) ? 1 : 0;
for (; i < 16; i++)
pixels[i] = (ptr[1] & (0x80 >> (i - 8))) ? 1 : 0;
ptr += 2;
}
for (i = 0; i < 16; i++)
Set_pixel(context, x_pos++, y_pos, pixels[i]);
}
}
// load color cycling information
if (Read_bytes(file, buffer, 32))
{
PI1_load_ranges(context, buffer, 32);
}
fclose(file);
File_error = 0;
} }
@ -1743,42 +1817,50 @@ void Save_PI1(T_IO_Context * context)
//////////////////////////////////// PC1 //////////////////////////////////// //////////////////////////////////// PC1 ////////////////////////////////////
//// DECOMPRESSION d'un buffer selon la méthode PACKBITS //// /// uncompress degas elite compressed stream (PACKBITS)
/// @return 1 for success
void PC1_uncompress_packbits(byte * src,byte * dest) /// @return 0 for failure
static int PC1_uncompress_packbits_file(FILE *f, byte * dest)
{ {
int is,id; // Les indices de parcour des buffers int id = 0;
int n; // Octet de contrôle unsigned count;
byte code, value;
for (is=id=0;id<32000;) while (id < 32000)
{ {
n=src[is++]; if (!Read_byte(f, &code))
return 0;
if (n & 0x80) if (code & 0x80)
{ {
// Recopier src[is] -n+1 fois /// Code is negative :
n=257-n; /// Repeat (1-code) times next byte
for (;(n>0) && (id<32000);n--) count = 257 - code;
dest[id++]=src[is]; if (id + count > 32000)
is++; return 0;
if (!Read_byte(f, &value))
return 0;
while (count-- > 0)
dest[id++] = value;
} }
else else
{ {
// Recopier n+1 octets littéralement /// Code is positive :
n=n+1; /// Copy (code+1) bytes
for (;(n>0) && (id<32000);n--) count = code + 1;
dest[id++]=src[is++]; if (id + count > 32000)
return 0;
if (!Read_bytes(f, dest + id, count))
return 0;
id += count;
} }
// Contrôle des erreurs
if (n>0)
File_error=1;
} }
return 1;
} }
//// COMPRESSION d'un buffer selon la méthode PACKBITS //// //// COMPRESSION d'un buffer selon la méthode PACKBITS ////
void PC1_compress_packbits(byte * src,byte * dest,int source_size,int * dest_size) static void PC1_compress_packbits(byte * src,byte * dest,int source_size,int * dest_size)
{ {
*dest_size = 0; *dest_size = 0;
@ -1842,7 +1924,7 @@ void PC1_compress_packbits(byte * src,byte * dest,int source_size,int * dest_siz
// Transformation de 4 plans de bits en 1 ligne de pixels // Transformation de 4 plans de bits en 1 ligne de pixels
void PC1_4bp_to_1line(byte * src0,byte * src1,byte * src2,byte * src3,byte * dest) static void PC1_4bp_to_1line(byte * src0,byte * src1,byte * src2,byte * src3,byte * dest)
{ {
int i,j; // Compteurs int i,j; // Compteurs
int ip; // index du pixel à calculer int ip; // index du pixel à calculer
@ -1874,7 +1956,7 @@ void PC1_4bp_to_1line(byte * src0,byte * src1,byte * src2,byte * src3,byte * des
// Transformation d'1 ligne de pixels en 4 plans de bits // Transformation d'1 ligne de pixels en 4 plans de bits
void PC1_1line_to_4bp(byte * src,byte * dst0,byte * dst1,byte * dst2,byte * dst3) static void PC1_1line_to_4bp(byte * src,byte * dst0,byte * dst1,byte * dst2,byte * dst3)
{ {
int i,j; // Compteurs int i,j; // Compteurs
int ip; // index du pixel à calculer int ip; // index du pixel à calculer
@ -1905,98 +1987,148 @@ void PC1_1line_to_4bp(byte * src,byte * dst0,byte * dst1,byte * dst2,byte * dst3
} }
// -- Tester si un fichier est au format PC1 -------------------------------- /// Test for Degas Elite Compressed format
void Test_PC1(T_IO_Context * context, FILE * file) void Test_PC1(T_IO_Context * context, FILE * file)
{ {
int size; // Taille du fichier int size; // Taille du fichier
word resolution; // Résolution de l'image word resolution; // Résolution de l'image
(void)context; (void)context;
File_error=1; File_error=1;
// Vérification de la taille size = File_length_file(file);
size=File_length_file(file); if (!Read_word_be(file,&resolution))
if ((size<=32066)) return;
{
// Lecture et vérification de la résolution if ((size <= 32066) && (resolution & 0x8000))
if (Read_word_le(file,&resolution)) {
{ if ((resolution & 0x7fff) < 3)
if (resolution==0x0080) File_error=0;
File_error=0; }
}
}
} }
// -- Lire un fichier au format PC1 ----------------------------------------- /// Load Degas Elite compressed files
void Load_PC1(T_IO_Context * context) void Load_PC1(T_IO_Context * context)
{ {
enum PIXEL_RATIO ratio = PIXEL_SIMPLE;
unsigned long size;
word width, height;
byte bpp;
FILE *file; FILE *file;
int size;
word x_pos,y_pos; word x_pos,y_pos;
byte * buffercomp; byte buffer[32];
byte * bufferdecomp; byte * bufferdecomp;
byte * ptr; byte * ptr;
byte pixels[320]; byte pixels[640];
word resolution;
File_error=0; File_error = 1;
if ((file=Open_file_read(context))) file = Open_file_read(context);
if (file == NULL)
return;
size = File_length_file(file);
if (!Read_word_be(file, &resolution))
return;
GFX2_Log(GFX2_DEBUG, "Degas Elite Compressed. Resolution = %04x\n", resolution);
// Read palette
if (!Read_bytes(file, buffer, 32))
{ {
size=File_length_file(file);
// allocation des buffers mémoire
buffercomp=(byte *)malloc(size);
bufferdecomp=(byte *)malloc(32000);
if ( (buffercomp!=NULL) && (bufferdecomp!=NULL) )
{
// Lecture du fichier dans le buffer
if (Read_bytes(file,buffercomp,size))
{
// Initialisation de la preview
Pre_load(context, 320,200,File_length_file(file),FORMAT_PC1,PIXEL_SIMPLE,4);
if (File_error==0)
{
// Initialisation de la palette
if (Config.Clear_palette)
memset(context->Palette,0,sizeof(T_Palette));
PI1_decode_palette(buffercomp+2, context->Palette);
// Décompression du buffer
PC1_uncompress_packbits(buffercomp+34,bufferdecomp);
// Décodage de l'image
ptr=bufferdecomp;
for (y_pos=0;y_pos<200;y_pos++)
{
// Décodage de la scanline
PC1_4bp_to_1line(ptr,ptr+40,ptr+80,ptr+120,pixels);
ptr+=160;
// Chargement de la ligne
for (x_pos=0;x_pos<320;x_pos++)
Set_pixel(context, x_pos,y_pos,pixels[x_pos]);
}
if (!File_error)
{
PI1_load_ranges(context, buffercomp, size);
}
}
}
else
File_error=1;
free(bufferdecomp);
free(buffercomp);
buffercomp = bufferdecomp = NULL;
}
else
{
File_error=1;
free(bufferdecomp);
free(buffercomp);
buffercomp = bufferdecomp = NULL;
}
fclose(file); fclose(file);
return;
} }
else if (Config.Clear_palette)
File_error=1; memset(context->Palette,0,sizeof(T_Palette));
PI1_decode_palette(buffer, context->Palette);
switch (resolution)
{
case 0x8000: // Low Res
width = 320;
height = 200;
bpp = 4;
break;
case 0x8001: // Med Res
width = 640;
height = 200;
bpp = 2;
ratio = PIXEL_TALL;
break;
case 0x8002: // High Res
width = 640;
height = 400;
bpp = 1;
break;
default:
fclose(file);
return;
}
bufferdecomp=(byte *)malloc(32000);
if (bufferdecomp == NULL)
{
fclose(file);
return;
}
// Initialisation de la preview
Pre_load(context, width, height, size, FORMAT_PC1, ratio, bpp);
//PC1_uncompress_packbits(buffercomp, bufferdecomp);
if (!PC1_uncompress_packbits_file(file, bufferdecomp))
{
GFX2_Log(GFX2_INFO, "PC1_uncompress_packbits_file() failed\n");
free(bufferdecomp);
fclose(file);
return;
}
// Décodage de l'image
ptr=bufferdecomp;
for (y_pos = 0; y_pos < height; y_pos++)
{
// Décodage de la scanline
switch (resolution)
{
case 0x8000: // Low Res
PC1_4bp_to_1line(ptr,ptr+40,ptr+80,ptr+120,pixels);
ptr+=160;
break;
case 0x8001: // Med Res
x_pos = 0;
while (x_pos < width)
{
int i;
for (i = 7; i >= 0; i--, x_pos++)
pixels[x_pos] = ((ptr[0] >> i) & 1)
| (((ptr[80] >> i) << 1) & 2);
ptr++;
}
ptr += 80;
break;
case 0x8002: // High Res
x_pos = 0;
while (x_pos < width)
{
int i;
for (i = 7; i >= 0; i--)
pixels[x_pos++] = (*ptr >> i) & 1;
ptr++;
}
}
for (x_pos=0;x_pos<width;x_pos++)
Set_pixel(context, x_pos, y_pos, pixels[x_pos]);
}
// Try to load color cycling information
GFX2_Log(GFX2_DEBUG, "remaining bytes = %ld\n", size - ftell(file));
if (Read_bytes(file, buffer, 32))
{
PI1_load_ranges(context, buffer, 32);
}
free(bufferdecomp);
fclose(file);
File_error = 0;
} }
@ -2073,90 +2205,180 @@ void Save_PC1(T_IO_Context * context)
//////////////////////////////////// NEO //////////////////////////////////// //////////////////////////////////// NEO ////////////////////////////////////
/**
NeoChrome Format :
<pre>
1 word flag word [always 0]
1 word resolution [0 = low res, 1 = medium res, 2 = high res]
16 words palette
12 bytes filename [usually " . "]
1 word color animation limits. High bit (bit 15) set if color
animation data is valid. Low byte contains color animation
limits (4 most significant bits are left/lower limit,
4 least significant bits are right/upper limit).
1 word color animation speed and direction. High bit (bit 15) set
if animation is on. Low order byte is # vblanks per step.
If negative, scroll is left (decreasing). Number of vblanks
between cycles is |x| - 1
1 word # of color steps (as defined in previous word) to display
picture before going to the next. (For use in slide shows)
1 word image X offset [unused, always 0]
1 word image Y offset [unused, always 0]
1 word image width [unused, always 320]
1 word image height [unused, always 200]
33 words reserved for future expansion
32000 bytes pixel data
</pre>
Dali *.SD0 (ST low resolution)
*.SD1 (ST medium resolution)
*.SD2 (ST high resolution)
Files do not seem to have any resolution or bit plane info stored in them. The file
extension seems to be the only way to determine the contents.
1 long file id? [always 0]
16 words palette
92 bytes reserved? [usually 0]
*/
void Test_NEO(T_IO_Context * context, FILE * file) void Test_NEO(T_IO_Context * context, FILE * file)
{ {
int size; // Taille du fichier word flag;
word resolution; // Résolution de l'image word resolution; // Atari ST resolution
(void)context; (void)context;
File_error=1; File_error=1;
// Vérification de la taille if (File_length_file(file) != 32128)
size=File_length_file(file); return;
if (size==32128)
{
// Flag word : toujours 0
if (Read_word_le(file,&resolution))
{
if (resolution == 0)
File_error = 0;
}
// Lecture et vérification de la résolution if (!Read_word_be(file,&flag))
if (Read_word_le(file,&resolution)) return;
{ // Flag word : always 0
if (resolution==0 || resolution==1 || resolution==2) if (flag != 0)
File_error |= 0; return;
}
} if (!Read_word_be(file,&resolution))
return;
// 0 = STlow, 1 = STmed, 2 = SThigh
if (resolution==0 || resolution==1 || resolution==2)
File_error = 0;
} }
/// Load Neochrome file format
void Load_NEO(T_IO_Context * context) void Load_NEO(T_IO_Context * context)
{ {
enum PIXEL_RATIO ratio = PIXEL_SIMPLE;
word flag;
word resolution; // Atari ST resolution
word width, height;
byte bpp;
FILE *file; FILE *file;
word x_pos,y_pos; word x_pos,y_pos;
byte * buffer;
byte * ptr; byte * ptr;
byte pixels[320]; byte buffer[160];
byte pixels[16];
File_error=0; File_error = 1;
if ((file=Open_file_read(context))) file = Open_file_read(context);
if (file == NULL)
return;
if (!Read_word_be(file,&flag))
goto error;
// Flag word : always 0
if (flag != 0)
goto error;
if (!Read_word_be(file,&resolution))
goto error;
switch (resolution)
{ {
// allocation d'un buffer mémoire case 0:
buffer=(byte *)malloc(32128); width = 320;
if (buffer!=NULL) height = 200;
{ bpp = 4;
// Lecture du fichier dans le buffer break;
if (Read_bytes(file,buffer,32128)) case 1:
{ width = 640;
// Initialisation de la preview height = 200;
Pre_load(context, 320,200,File_length_file(file),FORMAT_NEO,PIXEL_SIMPLE,4); bpp = 2;
if (File_error==0) ratio = PIXEL_TALL;
{ break;
// Initialisation de la palette case 2:
if (Config.Clear_palette) width = 640;
memset(context->Palette,0,sizeof(T_Palette)); height = 400;
// on saute la résolution et le flag, chacun 2 bits bpp = 1;
PI1_decode_palette(buffer+4, context->Palette); break;
default:
// Chargement/décompression de l'image goto error;
ptr=buffer+128;
for (y_pos=0;y_pos<200;y_pos++)
{
for (x_pos=0;x_pos<(320>>4);x_pos++)
{
PI1_8b_to_16p(ptr,pixels+(x_pos<<4));
ptr+=8;
}
for (x_pos=0;x_pos<320;x_pos++)
Set_pixel(context, x_pos,y_pos,pixels[x_pos]);
}
}
}
else
File_error=1;
free(buffer);
buffer = NULL;
}
else
File_error=1;
fclose(file);
} }
else
File_error=1; Pre_load(context, width, height, File_length_file(file), FORMAT_NEO, ratio, bpp);
if (!Read_bytes(file,buffer,32))
goto error;
// Initialisation de la palette
if (Config.Clear_palette)
memset(context->Palette, 0, sizeof(T_Palette));
PI1_decode_palette(buffer, context->Palette);
if (!Read_bytes(file, buffer, 12))
goto error;
buffer[12] = '\0';
GFX2_Log(GFX2_DEBUG, "NEO resolution %u name=\"%s\"\n", resolution, (char *)buffer);
if (!Read_bytes(file, buffer, 6))
goto error;
GFX2_Log(GFX2_DEBUG, " Color cycling : %02x %02x - %02x %02x. Time to show %02x%02x\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
if (!Read_bytes(file, buffer, 128-4-32-12-6))
goto error;
GFX2_LogHexDump(GFX2_DEBUG, "NEO ", buffer, 0, 128-4-32-12-6);
// Chargement/décompression de l'image
for (y_pos=0;y_pos<height;y_pos++)
{
if (!Read_bytes(file, buffer, (resolution==2) ? 80 : 160))
goto error;
ptr = buffer;
for (x_pos = 0; x_pos < width; )
{
int i;
switch (resolution)
{
case 0:
PI1_8b_to_16p(ptr, pixels);
ptr += 8;
break;
case 1:
PI2_8b_to_16p(ptr, pixels);
ptr += 4;
break;
case 2:
for (i = 0; i < 8; i++)
pixels[i] = (ptr[0] & (0x80 >> i)) ? 1 : 0;
for (; i < 16; i++)
pixels[i] = (ptr[1] & (0x80 >> (i - 8))) ? 1 : 0;
ptr += 2;
break;
default:
goto error;
}
for (i = 0; i < 16; i++)
Set_pixel(context, x_pos++, y_pos, pixels[i]);
}
}
File_error = 0; // everything was ok
error:
fclose(file);
} }
/// Save in NeoChrome format
void Save_NEO(T_IO_Context * context) void Save_NEO(T_IO_Context * context)
{ {
FILE *file; FILE *file;
@ -2221,6 +2443,8 @@ void Save_NEO(T_IO_Context * context)
} }
} }
/* @} */
//////////////////////////////////// C64 //////////////////////////////////// //////////////////////////////////// C64 ////////////////////////////////////
/** C64 file formats /** C64 file formats