From 2fc6b9375c39567b330e3e835ea128511a012f51 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Tue, 22 Nov 2016 20:42:15 +0000 Subject: [PATCH] Fix loading some Atari ST IFF files IFF is a versatile format, and can store data in Atari ST display RAM format. This allows to load several of our IFF test files, but the result for most seems corrupt (either that, or the files in our testsuite are ugly). Thanks to miniupnp for the patch! Fixes #38. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@2168 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- src/fileformats.c | 225 ++++++++++++++++++++++++++++++---------------- 1 file changed, 149 insertions(+), 76 deletions(-) diff --git a/src/fileformats.c b/src/fileformats.c index 1ea154ac..6b104e64 100644 --- a/src/fileformats.c +++ b/src/fileformats.c @@ -231,10 +231,10 @@ typedef struct word X_org; // Inutile word Y_org; // Inutile byte BitPlanes; - byte Mask; - byte Compression; - byte Pad1; // Inutile - word Transp_col; + byte Mask; // 0=none, 1=mask, 2=transp color, 3=Lasso + byte Compression; // 0=none, 1=packbits, 2=vertical RLE + byte Pad1; // Inutile + word Transp_col; // transparent color for masking mode 2 byte X_aspect; // Inutile byte Y_aspect; // Inutile word X_screen; @@ -438,7 +438,7 @@ int IFF_Skip_section(void) } // ------------------------- Attendre une section ------------------------- -byte IFF_Wait_for(byte * expected_section) +byte IFF_Wait_for(const char * expected_section) { // Valeur retournée: 1=Section trouvée, 0=Section non trouvée (erreur) byte section_read[4]; @@ -584,12 +584,14 @@ void Load_IFF(T_IO_Context * context) short y_pos; short counter; short line_size; // Taille d'une ligne en octets + short plane_line_size; // Size of line in bytes for 1 plane short real_line_size; // Taille d'une ligne en pixels byte color; long file_size; dword dummy; byte is_anim=0; int iff_format; + int plane; Get_full_filename(filename, context->File_name, context->File_directory); @@ -617,7 +619,7 @@ void Load_IFF(T_IO_Context * context) else iff_format = FORMAT_PBM; - if (!IFF_Wait_for((byte *)"BMHD")) + if (!IFF_Wait_for("BMHD")) File_error=1; Read_dword_be(IFF_file,&dummy); @@ -637,7 +639,7 @@ void Load_IFF(T_IO_Context * context) && (Read_word_be(IFF_file,&header.Y_screen)) && header.Width && header.Height) { - if ( (header.BitPlanes) && (IFF_Wait_for((byte *)"CMAP")) ) + if ( (header.BitPlanes) && (IFF_Wait_for("CMAP")) ) { Read_dword_be(IFF_file,&nb_colors); nb_colors/=3; @@ -662,6 +664,8 @@ void Load_IFF(T_IO_Context * context) if ( (!File_error) && (nb_colors>=2) && (nb_colors<=256) ) { + byte real_bit_planes = header.BitPlanes; + if (header.Mask==1) header.BitPlanes++; @@ -769,73 +773,148 @@ void Load_IFF(T_IO_Context * context) if (!memcmp(format,"ILBM",4)) // "ILBM": InterLeaved BitMap { // Calcul de la taille d'une ligne ILBM (pour les images ayant des dimensions exotiques) - if (context->Width & 15) + real_line_size = (context->Width+15) & ~15; + plane_line_size = real_line_size >> 3; // 8bits per byte + line_size = plane_line_size * header.BitPlanes; + + switch(header.Compression) { - real_line_size=( (context->Width+16) >> 4 ) << 4; - line_size=( (context->Width+16) >> 4 )*(header.BitPlanes<<1); - } - else - { - real_line_size=context->Width; - line_size=(context->Width>>3)*header.BitPlanes; - } - - if (!header.Compression) - { // non compressé - IFF_buffer=(byte *)malloc(line_size); - for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) - { - if (Read_bytes(IFF_file,IFF_buffer,line_size)) - Draw_IFF_line(context, y_pos,real_line_size, header.BitPlanes); - else - File_error=21; - } - free(IFF_buffer); - IFF_buffer = NULL; - } - else - { // compressé - /*Init_lecture();*/ - - IFF_buffer=(byte *)malloc(line_size); - - for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) - { - for (x_pos=0; ((x_posHeight) && (!File_error)); y_pos++) { - if(Read_byte(IFF_file, &temp_byte)!=1) + if (Read_bytes(IFF_file,IFF_buffer,line_size)) + Draw_IFF_line(context, y_pos,real_line_size, header.BitPlanes); + else + File_error=21; + } + free(IFF_buffer); + IFF_buffer = NULL; + break; + case 1: // compressé packbits (Amiga) + /*Init_lecture();*/ + + IFF_buffer=(byte *)malloc(line_size); + + for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) + { + for (x_pos=0; ((x_pos 127 alors il faut répéter 256-'temp_byte' fois la couleur de l'octet suivant - // Si temp_byte <= 127 alors il faut afficher directement les 'temp_byte' octets suivants - if (temp_byte>127) - { - if(Read_byte(IFF_file, &color)!=1) + if(Read_byte(IFF_file, &temp_byte)!=1) { - File_error=23; + File_error=22; break; } - b256=(short)(256-temp_byte); - for (counter=0; counter<=b256; counter++) - if (x_pos 127 alors il faut répéter 256-'temp_byte' fois la couleur de l'octet suivant + // Si temp_byte <= 127 alors il faut afficher directement les 'temp_byte' octets suivants + if (temp_byte>127) + { + if(Read_byte(IFF_file, &color)!=1) + { + File_error=23; + break; + } + b256=(short)(256-temp_byte); + for (counter=0; counter<=b256; counter++) + if (x_pos=line_size || Read_byte(IFF_file, &(IFF_buffer[x_pos++]))!=1) + File_error=25; } - else - for (counter=0; counter<=(short)(temp_byte); counter++) - if (x_pos>=line_size || Read_byte(IFF_file, &(IFF_buffer[x_pos++]))!=1) - File_error=25; + if (!File_error) + Draw_IFF_line(context, y_pos,real_line_size,header.BitPlanes); + } + + free(IFF_buffer); + IFF_buffer = NULL; + /*Close_lecture();*/ + break; + case 2: // compressé vertical RLE (Atari ST) + IFF_buffer=(byte *)malloc(line_size*context->Height); + plane_line_size = real_line_size >> 3; + for (plane = 0; plane < header.BitPlanes && !File_error; plane++) + { + word cmd_count; + word cmd; + signed char * commands; + word count; + + y_pos = 0; x_pos = 0; + if (!IFF_Wait_for("VDAT")) + { + File_error = 30; + break; + } + Read_dword_be(IFF_file,§ion_size); + Read_word_be(IFF_file,&cmd_count); + cmd_count -= 2; + commands = (signed char *)malloc(cmd_count); + if (!Read_bytes(IFF_file,commands,cmd_count)) + { + File_error = 31; + break; + } + for (cmd = 0; cmd < cmd_count && x_pos < plane_line_size; cmd++) + { + if (commands[cmd] <= 0) + { // cmd=0 : load count from data, COPY + // cmd < 0 : count = -cmd, COPY + if (commands[cmd] == 0) + Read_word_be(IFF_file,&count); + else + count = -commands[cmd]; + while (count-- > 0 && x_pos < plane_line_size) + { + Read_bytes(IFF_file,IFF_buffer+x_pos+y_pos*line_size+plane*plane_line_size,2); + if(++y_pos >= context->Height) + { + y_pos = 0; + x_pos += 2; + } + } + } + else if (commands[cmd] >= 1) + { // cmd=1 : load count from data, RLE + // cmd >1 : count = cmd, RLE + byte data[2]; + if (commands[cmd] == 1) + Read_word_be(IFF_file,&count); + else + count = (word)commands[cmd]; + Read_bytes(IFF_file,data,2); + while (count-- > 0 && x_pos < plane_line_size) + { + memcpy(IFF_buffer+x_pos+y_pos*line_size+plane*plane_line_size,data,2); + if (++y_pos >= context->Height) + { + y_pos = 0; + x_pos += 2; + } + } + } + } + free(commands); } if (!File_error) - Draw_IFF_line(context, y_pos,real_line_size,header.BitPlanes); - } - - free(IFF_buffer); - IFF_buffer = NULL; - /*Close_lecture();*/ + { + byte * save_IFF_buffer = IFF_buffer; + for (y_pos = 0; y_pos < context->Height; y_pos++) + { + Draw_IFF_line(context,y_pos,real_line_size,real_bit_planes); + IFF_buffer += line_size; + } + IFF_buffer = save_IFF_buffer; + } + free(IFF_buffer); + IFF_buffer = NULL; + break; + default: // compression non reconnue + File_error = 32; } } else // "PBM ": Planar(?) BitMap @@ -909,7 +988,7 @@ void Load_IFF(T_IO_Context * context) // ILBM, hopefully Read_bytes(IFF_file,format,4); - if (!IFF_Wait_for((byte *)"DLTA")) + if (!IFF_Wait_for("DLTA")) { File_error=1; break; @@ -1142,19 +1221,13 @@ void Save_IFF(T_IO_Context * context) if (context->Format == FORMAT_LBM) { short line_size; // Size of line in bytes + short plane_line_size; // Size of line in bytes for 1 plane short real_line_size; // Size of line in pixels // Calcul de la taille d'une ligne ILBM (pour les images ayant des dimensions exotiques) - if (context->Width & 15) - { - real_line_size=( (context->Width+16) >> 4 ) << 4; - line_size=( (context->Width+16) >> 4 )*(header.BitPlanes<<1); - } - else - { - real_line_size=context->Width; - line_size=(context->Width>>3)*header.BitPlanes; - } + real_line_size = (context->Width+15) & ~15; + plane_line_size = real_line_size >> 3; // 8bits per byte + line_size = plane_line_size * header.BitPlanes; IFF_buffer=(byte *)malloc(line_size); // Start encoding