diff --git a/engine.c b/engine.c index ae230458..67b4f404 100644 --- a/engine.c +++ b/engine.c @@ -1059,6 +1059,90 @@ void Main_handler(void) } action++; break; + case SPECIAL_LAYER_MERGE: + if (Main_current_layer>0) + { + // Backup layer below the current + Backup_layers(1<<(Main_current_layer-1)); + + Merge_layer(); + + Redraw_layered_image(); + Hide_cursor(); + Display_all_screen(); + Display_cursor(); + End_of_modification(); + } + action++; + break; + case SPECIAL_LAYER_SWAP_UP: + if (Main_current_layer < (Main_backups->Pages->Nb_layers-1)) + { + byte * tmp; + dword layer_flags; + + // Backup with unchanged layers + Backup_layers(0); + + // swap + tmp = Main_backups->Pages->Image[Main_current_layer]; + Main_backups->Pages->Image[Main_current_layer] = Main_backups->Pages->Image[Main_current_layer+1]; + Main_backups->Pages->Image[Main_current_layer+1] = tmp; + + // Swap visibility indicators + layer_flags = (Main_layers_visible >> Main_current_layer) & 3; + // Only needed if they are different. + if (layer_flags == 1 || layer_flags == 2) + { + // One is on, the other is off. Negating them will + // perform the swap. + Main_layers_visible ^= (3 << Main_current_layer); + } + Main_current_layer++; + + Redraw_layered_image(); + Hide_cursor(); + Display_all_screen(); + Display_cursor(); + End_of_modification(); + } + action++; + break; + + case SPECIAL_LAYER_SWAP_DOWN: + if (Main_current_layer > 0) + { + byte * tmp; + dword layer_flags; + + // Backup with unchanged layers + Backup_layers(0); + + // swap + tmp = Main_backups->Pages->Image[Main_current_layer]; + Main_backups->Pages->Image[Main_current_layer] = Main_backups->Pages->Image[Main_current_layer-1]; + Main_backups->Pages->Image[Main_current_layer-1] = tmp; + + // Swap visibility indicators + layer_flags = (Main_layers_visible >> (Main_current_layer-1)) & 3; + // Only needed if they are different. + if (layer_flags == 1 || layer_flags == 2) + { + // Only needed if they are different. + // One is on, the other is off. Negating them will + // perform the swap. + Main_layers_visible ^= (3 << (Main_current_layer-1)); + } + Main_current_layer--; + + Redraw_layered_image(); + Hide_cursor(); + Display_all_screen(); + Display_cursor(); + End_of_modification(); + } + action++; + break; } } } // End of special keys diff --git a/loadsave.c b/loadsave.c index 9ba10821..e46c3a2d 100644 --- a/loadsave.c +++ b/loadsave.c @@ -2883,24 +2883,38 @@ void Save_BMP(void) #pragma pack(1) typedef struct { - word Width; // width de l'écran virtuel - word Height; // height de l'écran virtuel - byte Resol; // Informations sur la résolution (et autres) - byte Backcol; // color de fond - byte Aspect; // Informations sur l'aspect ratio (et autres) -} T_GIF_LSDB; // Logical Screen Descriptor Block + word Width; // Width of the complete image area + word Height; // Height of the complete image area + byte Resol; // Informations about the resolution (and other) + byte Backcol; // Proposed background color + byte Aspect; // Informations about aspect ratio (and other) +} T_GIF_LSDB; // Logical Screen Descriptor Block typedef struct { - word Pos_X; // Abscisse où devrait être affichée l'image - word Pos_Y; // Ordonnée où devrait être affichée l'image - word Image_width; // width de l'image - word Image_height; // height de l'image - byte Indicator; // Informations diverses sur l'image + word Pos_X; // X offset where the image should be pasted + word Pos_Y; // Y offset where the image should be pasted + word Image_width; // Width of image + word Image_height; // Height of image + byte Indicator; // Misc image information byte Nb_bits_pixel; // Nb de bits par pixel -} T_GIF_IDB; // Image Descriptor Block +} T_GIF_IDB; // Image Descriptor Block #pragma pack() +typedef struct +{ + // byte Block_identifier : 0x21 + // byte Function : 0xF9 + // byte Block_size // 4 + byte Packed_fields; // 11100000 : Reserved + // 00011100 : Disposal method + // 00000010 : User input flag + // 00000001 : Transparent flag + word Delay_time; // Time for this frame to stay displayed + byte Transparent_color; // Which color index acts as transparent + //word Bloc_terminator; // 0x00 +} T_GIF_GCE; // Graphic Control Extension + // -- Tester si un fichier est au format GIF -------------------------------- void Test_GIF(void) @@ -2983,13 +2997,14 @@ void Test_GIF(void) // -- Affiche un nouveau pixel -- - void GIF_new_pixel(byte color) + void GIF_new_pixel(T_GIF_IDB *idb, byte color) { - Pixel_load_function(GIF_pos_X,GIF_pos_Y,color); + if (color != Main_backups->Pages->Transparent_color) // transparent color + Pixel_load_function(idb->Pos_X+GIF_pos_X, idb->Pos_Y+GIF_pos_Y,color); GIF_pos_X++; - if (GIF_pos_X>=Main_image_width) + if (GIF_pos_X>=idb->Image_width) { GIF_pos_X=0; @@ -3008,7 +3023,7 @@ void Test_GIF(void) default: GIF_pos_Y+=2; } - if (GIF_pos_Y>=Main_image_height) + if (GIF_pos_Y>=idb->Image_height) { switch(++GIF_pass) { @@ -3040,11 +3055,12 @@ void Load_GIF(void) T_GIF_LSDB LSDB; T_GIF_IDB IDB; + T_GIF_GCE GCE; word nb_colors; // Nombre de couleurs dans l'image word color_index; // index de traitement d'une couleur byte size_to_read; // Nombre de données à lire (divers) - byte block_indentifier; // Code indicateur du type de bloc en cours + byte block_identifier; // Code indicateur du type de bloc en cours word initial_nb_bits; // Nb de bits au début du traitement LZW word special_case=0; // Mémoire pour le cas spécial word old_code=0; // Code précédent @@ -3086,6 +3102,10 @@ void Load_GIF(void) Original_screen_X=LSDB.Width; Original_screen_Y=LSDB.Height; + Init_preview(LSDB.Width,LSDB.Height,file_size,FORMAT_GIF,PIXEL_SIMPLE); + Main_image_width=LSDB.Width; + Main_image_height=LSDB.Height; + // Palette globale dispo = (LSDB.Resol and $80) // Profondeur de couleur =((LSDB.Resol and $70) shr 4)+1 // Nombre de bits/pixel = (LSDB.Resol and $07)+1 @@ -3124,10 +3144,10 @@ void Load_GIF(void) } // On lit un indicateur de block - Read_byte(GIF_file,&block_indentifier); - while (block_indentifier!=0x3B && !File_error) + Read_byte(GIF_file,&block_identifier); + while (block_identifier!=0x3B && !File_error) { - switch (block_indentifier) + switch (block_identifier) { case 0x21: // Bloc d'extension { @@ -3157,7 +3177,20 @@ void Load_GIF(void) break; case 0xF9: // Graphics Control Extension // Prévu pour la transparence + if ( Read_byte(GIF_file,&(GCE.Packed_fields)) + && Read_word_le(GIF_file,&(GCE.Delay_time)) + && Read_byte(GIF_file,&(GCE.Transparent_color))) + { + if (GCE.Packed_fields & 1) + Main_backups->Pages->Transparent_color= GCE.Transparent_color; + else + Main_backups->Pages->Transparent_color = -1; + } + else + File_error=2; + break; + default: // On saute le bloc: fseek(GIF_file,size_to_read,SEEK_CUR); @@ -3171,10 +3204,11 @@ void Load_GIF(void) case 0x2C: // Local Image Descriptor { // Si on a deja lu une image, c'est une GIF animée ou bizarroide, on sort. - if (number_LID!=0) + if (number_LID!=0 && Pixel_load_function==Pixel_load_in_current_screen) { - Main_current_layer++; - Add_layer(Main_backups, Main_current_layer); + // This a second layer/frame, or more. + // Attempt to add a layer to current image + Add_layer(Main_backups, Main_current_layer+1); } number_LID++; @@ -3187,11 +3221,6 @@ void Load_GIF(void) && Read_byte(GIF_file,&(IDB.Nb_bits_pixel)) && IDB.Image_width && IDB.Image_height) { - Main_image_width=IDB.Image_width; - Main_image_height=IDB.Image_height; - - if (number_LID==1) - Init_preview(IDB.Image_width,IDB.Image_height,file_size,FORMAT_GIF,PIXEL_SIMPLE); // Palette locale dispo = (IDB.Indicator and $80) // Image entrelacée = (IDB.Indicator and $40) @@ -3271,7 +3300,7 @@ void Load_GIF(void) special_case=alphabet_stack[alphabet_stack_pos++]=GIF_current_code; do - GIF_new_pixel(alphabet_stack[--alphabet_stack_pos]); + GIF_new_pixel(&IDB, alphabet_stack[--alphabet_stack_pos]); while (alphabet_stack_pos!=0); alphabet_prefix[alphabet_free ]=old_code; @@ -3291,7 +3320,7 @@ void Load_GIF(void) alphabet_free =nb_colors+2; special_case =GIF_get_next_code(); old_code =GIF_current_code; - GIF_new_pixel(GIF_current_code); + GIF_new_pixel(&IDB, GIF_current_code); } } else @@ -3302,7 +3331,7 @@ void Load_GIF(void) if (File_error>=0) if ( /* (GIF_pos_X!=0) || */ - ( ( (!GIF_interlaced) && (GIF_pos_Y!=Main_image_height) ) || + ( ( (!GIF_interlaced) && (GIF_pos_Y!=IDB.Image_height) ) || ( (GIF_interlaced) && (!GIF_finished_interlaced_image) ) ) ) File_error=2; @@ -3314,7 +3343,7 @@ void Load_GIF(void) break; } // Lecture du code de fonction suivant: - Read_byte(GIF_file,&block_indentifier); + Read_byte(GIF_file,&block_identifier); } } // Le fichier contenait un LSDB else @@ -3395,16 +3424,16 @@ void Load_GIF(void) // -- Lire le pixel suivant -- - byte GIF_next_pixel(void) + byte GIF_next_pixel(T_GIF_IDB *idb) { byte temp; temp=Read_pixel_function(GIF_pos_X,GIF_pos_Y); - if (++GIF_pos_X>=Main_image_width) + if (++GIF_pos_X>=idb->Image_width) { GIF_pos_X=0; - if (++GIF_pos_Y>=Main_image_height) + if (++GIF_pos_Y>=idb->Image_height) GIF_stop=1; } @@ -3430,7 +3459,7 @@ void Save_GIF(void) T_GIF_IDB IDB; - byte block_indentifier; // Code indicateur du type de bloc en cours + byte block_identifier; // Code indicateur du type de bloc en cours word current_string; // Code de la chaîne en cours de traitement byte current_char; // Caractère à coder word index; // index de recherche de chaîne @@ -3524,7 +3553,7 @@ void Save_GIF(void) { // On va écrire un block indicateur d'IDB et l'IDB du fichier - block_indentifier=0x2C; + block_identifier=0x2C; IDB.Pos_X=0; IDB.Pos_Y=0; IDB.Image_width=Main_image_width; @@ -3532,7 +3561,7 @@ void Save_GIF(void) IDB.Indicator=0x07; // Image non entrelacée, pas de palette locale. IDB.Nb_bits_pixel=8; // Image 256 couleurs; - if ( Write_byte(GIF_file,block_indentifier) && + if ( Write_byte(GIF_file,block_identifier) && Write_word_le(GIF_file,IDB.Pos_X) && Write_word_le(GIF_file,IDB.Pos_Y) && Write_word_le(GIF_file,IDB.Image_width) && @@ -3567,12 +3596,12 @@ void Save_GIF(void) ////////////////////////////////////////////// COMPRESSION LZW // - start=current_string=GIF_next_pixel(); + start=current_string=GIF_next_pixel(&IDB); descend=1; do { - current_char=GIF_next_pixel(); + current_char=GIF_next_pixel(&IDB); // On regarde si dans la table on aurait pas une chaîne // équivalente à current_string+Caractere diff --git a/misc.c b/misc.c index c0fb6e65..955b5221 100644 --- a/misc.c +++ b/misc.c @@ -222,7 +222,7 @@ byte Read_pixel_from_current_screen (word x,word y) byte depth; byte color; color = *(Main_screen+y*Main_image_width+x); - if (color != 0) // transparent + if (color != Main_backups->Pages->Transparent_color) // transparent color return color; depth = *(Visible_image_depth_buffer.Image+x+y*Main_image_width); @@ -236,7 +236,7 @@ void Pixel_in_current_screen (word x,word y,byte color,int with_preview) *(Main_backups->Pages->Image[Main_current_layer] + x+y*Main_image_width)=color; if ( depth <= Main_current_layer) { - if (color == 0) // transparent + if (color == Main_backups->Pages->Transparent_color) // transparent color // fetch pixel color from the topmost visible layer color=*(Main_backups->Pages->Image[depth] + x+y*Main_image_width); diff --git a/pages.c b/pages.c index e591b5c0..80c139b9 100644 --- a/pages.c +++ b/pages.c @@ -193,7 +193,7 @@ void Redraw_layered_image(void) for (i=0; iPages->Image[layer]+i); - if (color != 0) /* transp color */ + if (color != Main_backups->Pages->Transparent_color) // transparent color { *(Visible_image[0].Image+i) = color; if (layer != Main_current_layer) @@ -240,7 +240,7 @@ void Update_depth_buffer(void) for (i=0; iPages->Image[layer]+i); - if (color != 0) /* transp color */ + if (color != Main_backups->Pages->Transparent_color) // transparent color { *(Visible_image_depth_buffer.Image+i) = layer; } @@ -259,7 +259,7 @@ void Redraw_current_layer(void) if (depth<=Main_current_layer) { byte color = *(Main_backups->Pages->Image[Main_current_layer]+i); - if (color != 0) /* transp color */ + if (color != Main_backups->Pages->Transparent_color) // transparent color { *(Visible_image[0].Image+i) = color; } @@ -833,6 +833,10 @@ void Undo(void) // palette que la page courante. Mais en temps normal, le backup // n'est pas utilisé à la suite d'un Undo. Donc ça ne devrait pas // poser de problèmes. + + if (Main_current_layer > Main_backups->Pages->Nb_layers-1) + Main_current_layer = Main_backups->Pages->Nb_layers-1; + Redraw_layered_image(); } @@ -860,6 +864,10 @@ void Redo(void) // palette que la page courante. Mais en temps normal, le backup // n'est pas utilisé à la suite d'un Redo. Donc ça ne devrait pas // poser de problèmes. + + if (Main_current_layer > Main_backups->Pages->Nb_layers-1) + Main_current_layer = Main_backups->Pages->Nb_layers-1; + Redraw_layered_image(); } @@ -983,7 +991,7 @@ byte Add_layer(T_List_of_pages *list, byte layer) } new_page->Image[layer]=new_image; // Fill with transparency, initially - memset(new_image, 0, list->Pages->Height*list->Pages->Width); // transparent color + memset(new_image, Main_backups->Pages->Transparent_color, list->Pages->Height*list->Pages->Width); // transparent color // Done. Note that the visible buffer is already ok since we // only inserted a transparent "slide" somewhere. @@ -1084,3 +1092,16 @@ byte Delete_layer(T_List_of_pages *list, byte layer) // All ok return 0; } + +/// Merges the current layer onto the one below it. +byte Merge_layer() +{ + int i; + for (i=0; iPages->Image[Main_current_layer]+i); + if (color != Main_backups->Pages->Transparent_color) // transparent color + *(Main_backups->Pages->Image[Main_current_layer-1]+i) = color; + } + return Delete_layer(Main_backups,Main_current_layer); +} diff --git a/pages.h b/pages.h index 691ff668..c36d98dc 100644 --- a/pages.h +++ b/pages.h @@ -41,6 +41,8 @@ void Upload_infos_page_main(T_Page * page); byte Add_layer(T_List_of_pages *list, byte layer); /// Delete a layer from the latest page of a list. Returns 0 on success. byte Delete_layer(T_List_of_pages *list, byte layer); +/// Merges the current layer onto the one below it. +byte Merge_layer(); // private T_Page * New_page(byte nb_layers); diff --git a/struct.h b/struct.h index 51a209bf..68954295 100644 --- a/struct.h +++ b/struct.h @@ -340,8 +340,10 @@ typedef struct T_Page byte File_format; ///< File format, in enum ::FILE_FORMATS struct T_Page *Next; ///< Pointer to the next backup struct T_Page *Prev; ///< Pointer to the previous backup + word Transparent_color; ///< Index of transparent color. -1 or 0 to 255. byte Nb_layers; ///< Number of layers - byte * Image[0]; ///< Pixel data for the image. + byte * Image[0]; ///< Pixel data for the (first layer of) image. + // No field after Image[] ! Dynamic layer allocation for Image[1], [2] etc. } T_Page; /// Collection of undo/redo steps. @@ -356,7 +358,6 @@ typedef struct { int Width; ///< Image width in pixels. int Height; ///< Image height in pixels. - //int Users; ///< Number of references. byte * Image; ///< Pixel data for the image. } T_Image;