[layers] Implemented SwapUp and SwapDown (Alt-PgUp, Alt-PgDown) to change layers order; Implemented layer merge (Alt-End); improved GIF loader to read images with optimized layers (smaller) and the ones with a transparent color different than zero.

git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1077 416bcca6-2ee7-4201-b75f-2eb2f807beb1
This commit is contained in:
Yves Rizoud 2009-10-18 19:06:07 +00:00
parent abb6204757
commit 89f2173d70
6 changed files with 185 additions and 48 deletions

View File

@ -1059,6 +1059,90 @@ void Main_handler(void)
} }
action++; action++;
break; 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 } // End of special keys

View File

@ -2883,24 +2883,38 @@ void Save_BMP(void)
#pragma pack(1) #pragma pack(1)
typedef struct typedef struct
{ {
word Width; // width de l'écran virtuel word Width; // Width of the complete image area
word Height; // height de l'écran virtuel word Height; // Height of the complete image area
byte Resol; // Informations sur la résolution (et autres) byte Resol; // Informations about the resolution (and other)
byte Backcol; // color de fond byte Backcol; // Proposed background color
byte Aspect; // Informations sur l'aspect ratio (et autres) byte Aspect; // Informations about aspect ratio (and other)
} T_GIF_LSDB; // Logical Screen Descriptor Block } T_GIF_LSDB; // Logical Screen Descriptor Block
typedef struct typedef struct
{ {
word Pos_X; // Abscisse où devrait être affichée l'image word Pos_X; // X offset where the image should be pasted
word Pos_Y; // Ordonnée où devrait être affichée l'image word Pos_Y; // Y offset where the image should be pasted
word Image_width; // width de l'image word Image_width; // Width of image
word Image_height; // height de l'image word Image_height; // Height of image
byte Indicator; // Informations diverses sur l'image byte Indicator; // Misc image information
byte Nb_bits_pixel; // Nb de bits par pixel byte Nb_bits_pixel; // Nb de bits par pixel
} T_GIF_IDB; // Image Descriptor Block } T_GIF_IDB; // Image Descriptor Block
#pragma pack() #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 -------------------------------- // -- Tester si un fichier est au format GIF --------------------------------
void Test_GIF(void) void Test_GIF(void)
@ -2983,13 +2997,14 @@ void Test_GIF(void)
// -- Affiche un nouveau pixel -- // -- 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++; GIF_pos_X++;
if (GIF_pos_X>=Main_image_width) if (GIF_pos_X>=idb->Image_width)
{ {
GIF_pos_X=0; GIF_pos_X=0;
@ -3008,7 +3023,7 @@ void Test_GIF(void)
default: GIF_pos_Y+=2; default: GIF_pos_Y+=2;
} }
if (GIF_pos_Y>=Main_image_height) if (GIF_pos_Y>=idb->Image_height)
{ {
switch(++GIF_pass) switch(++GIF_pass)
{ {
@ -3040,11 +3055,12 @@ void Load_GIF(void)
T_GIF_LSDB LSDB; T_GIF_LSDB LSDB;
T_GIF_IDB IDB; T_GIF_IDB IDB;
T_GIF_GCE GCE;
word nb_colors; // Nombre de couleurs dans l'image word nb_colors; // Nombre de couleurs dans l'image
word color_index; // index de traitement d'une couleur word color_index; // index de traitement d'une couleur
byte size_to_read; // Nombre de données à lire (divers) 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 initial_nb_bits; // Nb de bits au début du traitement LZW
word special_case=0; // Mémoire pour le cas spécial word special_case=0; // Mémoire pour le cas spécial
word old_code=0; // Code précédent word old_code=0; // Code précédent
@ -3086,6 +3102,10 @@ void Load_GIF(void)
Original_screen_X=LSDB.Width; Original_screen_X=LSDB.Width;
Original_screen_Y=LSDB.Height; 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) // Palette globale dispo = (LSDB.Resol and $80)
// Profondeur de couleur =((LSDB.Resol and $70) shr 4)+1 // Profondeur de couleur =((LSDB.Resol and $70) shr 4)+1
// Nombre de bits/pixel = (LSDB.Resol and $07)+1 // Nombre de bits/pixel = (LSDB.Resol and $07)+1
@ -3124,10 +3144,10 @@ void Load_GIF(void)
} }
// On lit un indicateur de block // On lit un indicateur de block
Read_byte(GIF_file,&block_indentifier); Read_byte(GIF_file,&block_identifier);
while (block_indentifier!=0x3B && !File_error) while (block_identifier!=0x3B && !File_error)
{ {
switch (block_indentifier) switch (block_identifier)
{ {
case 0x21: // Bloc d'extension case 0x21: // Bloc d'extension
{ {
@ -3157,7 +3177,20 @@ void Load_GIF(void)
break; break;
case 0xF9: // Graphics Control Extension case 0xF9: // Graphics Control Extension
// Prévu pour la transparence // 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: default:
// On saute le bloc: // On saute le bloc:
fseek(GIF_file,size_to_read,SEEK_CUR); fseek(GIF_file,size_to_read,SEEK_CUR);
@ -3171,10 +3204,11 @@ void Load_GIF(void)
case 0x2C: // Local Image Descriptor case 0x2C: // Local Image Descriptor
{ {
// Si on a deja lu une image, c'est une GIF animée ou bizarroide, on sort. // 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++; // This a second layer/frame, or more.
Add_layer(Main_backups, Main_current_layer); // Attempt to add a layer to current image
Add_layer(Main_backups, Main_current_layer+1);
} }
number_LID++; number_LID++;
@ -3187,11 +3221,6 @@ void Load_GIF(void)
&& Read_byte(GIF_file,&(IDB.Nb_bits_pixel)) && Read_byte(GIF_file,&(IDB.Nb_bits_pixel))
&& IDB.Image_width && IDB.Image_height) && 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) // Palette locale dispo = (IDB.Indicator and $80)
// Image entrelacée = (IDB.Indicator and $40) // 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; special_case=alphabet_stack[alphabet_stack_pos++]=GIF_current_code;
do do
GIF_new_pixel(alphabet_stack[--alphabet_stack_pos]); GIF_new_pixel(&IDB, alphabet_stack[--alphabet_stack_pos]);
while (alphabet_stack_pos!=0); while (alphabet_stack_pos!=0);
alphabet_prefix[alphabet_free ]=old_code; alphabet_prefix[alphabet_free ]=old_code;
@ -3291,7 +3320,7 @@ void Load_GIF(void)
alphabet_free =nb_colors+2; alphabet_free =nb_colors+2;
special_case =GIF_get_next_code(); special_case =GIF_get_next_code();
old_code =GIF_current_code; old_code =GIF_current_code;
GIF_new_pixel(GIF_current_code); GIF_new_pixel(&IDB, GIF_current_code);
} }
} }
else else
@ -3302,7 +3331,7 @@ void Load_GIF(void)
if (File_error>=0) if (File_error>=0)
if ( /* (GIF_pos_X!=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) ) ( (GIF_interlaced) && (!GIF_finished_interlaced_image) )
) ) ) )
File_error=2; File_error=2;
@ -3314,7 +3343,7 @@ void Load_GIF(void)
break; break;
} }
// Lecture du code de fonction suivant: // Lecture du code de fonction suivant:
Read_byte(GIF_file,&block_indentifier); Read_byte(GIF_file,&block_identifier);
} }
} // Le fichier contenait un LSDB } // Le fichier contenait un LSDB
else else
@ -3395,16 +3424,16 @@ void Load_GIF(void)
// -- Lire le pixel suivant -- // -- Lire le pixel suivant --
byte GIF_next_pixel(void) byte GIF_next_pixel(T_GIF_IDB *idb)
{ {
byte temp; byte temp;
temp=Read_pixel_function(GIF_pos_X,GIF_pos_Y); 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; GIF_pos_X=0;
if (++GIF_pos_Y>=Main_image_height) if (++GIF_pos_Y>=idb->Image_height)
GIF_stop=1; GIF_stop=1;
} }
@ -3430,7 +3459,7 @@ void Save_GIF(void)
T_GIF_IDB IDB; 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 word current_string; // Code de la chaîne en cours de traitement
byte current_char; // Caractère à coder byte current_char; // Caractère à coder
word index; // index de recherche de chaîne 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 // 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_X=0;
IDB.Pos_Y=0; IDB.Pos_Y=0;
IDB.Image_width=Main_image_width; 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.Indicator=0x07; // Image non entrelacée, pas de palette locale.
IDB.Nb_bits_pixel=8; // Image 256 couleurs; 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_X) &&
Write_word_le(GIF_file,IDB.Pos_Y) && Write_word_le(GIF_file,IDB.Pos_Y) &&
Write_word_le(GIF_file,IDB.Image_width) && Write_word_le(GIF_file,IDB.Image_width) &&
@ -3567,12 +3596,12 @@ void Save_GIF(void)
////////////////////////////////////////////// COMPRESSION LZW // ////////////////////////////////////////////// COMPRESSION LZW //
start=current_string=GIF_next_pixel(); start=current_string=GIF_next_pixel(&IDB);
descend=1; descend=1;
do do
{ {
current_char=GIF_next_pixel(); current_char=GIF_next_pixel(&IDB);
// On regarde si dans la table on aurait pas une chaîne // On regarde si dans la table on aurait pas une chaîne
// équivalente à current_string+Caractere // équivalente à current_string+Caractere

4
misc.c
View File

@ -222,7 +222,7 @@ byte Read_pixel_from_current_screen (word x,word y)
byte depth; byte depth;
byte color; byte color;
color = *(Main_screen+y*Main_image_width+x); color = *(Main_screen+y*Main_image_width+x);
if (color != 0) // transparent if (color != Main_backups->Pages->Transparent_color) // transparent color
return color; return color;
depth = *(Visible_image_depth_buffer.Image+x+y*Main_image_width); 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; *(Main_backups->Pages->Image[Main_current_layer] + x+y*Main_image_width)=color;
if ( depth <= Main_current_layer) 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 // fetch pixel color from the topmost visible layer
color=*(Main_backups->Pages->Image[depth] + x+y*Main_image_width); color=*(Main_backups->Pages->Image[depth] + x+y*Main_image_width);

29
pages.c
View File

@ -193,7 +193,7 @@ void Redraw_layered_image(void)
for (i=0; i<Main_image_width*Main_image_height; i++) for (i=0; i<Main_image_width*Main_image_height; i++)
{ {
byte color = *(Main_backups->Pages->Image[layer]+i); byte color = *(Main_backups->Pages->Image[layer]+i);
if (color != 0) /* transp color */ if (color != Main_backups->Pages->Transparent_color) // transparent color
{ {
*(Visible_image[0].Image+i) = color; *(Visible_image[0].Image+i) = color;
if (layer != Main_current_layer) if (layer != Main_current_layer)
@ -240,7 +240,7 @@ void Update_depth_buffer(void)
for (i=0; i<Main_image_width*Main_image_height; i++) for (i=0; i<Main_image_width*Main_image_height; i++)
{ {
byte color = *(Main_backups->Pages->Image[layer]+i); byte color = *(Main_backups->Pages->Image[layer]+i);
if (color != 0) /* transp color */ if (color != Main_backups->Pages->Transparent_color) // transparent color
{ {
*(Visible_image_depth_buffer.Image+i) = layer; *(Visible_image_depth_buffer.Image+i) = layer;
} }
@ -259,7 +259,7 @@ void Redraw_current_layer(void)
if (depth<=Main_current_layer) if (depth<=Main_current_layer)
{ {
byte color = *(Main_backups->Pages->Image[Main_current_layer]+i); 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; *(Visible_image[0].Image+i) = color;
} }
@ -833,6 +833,10 @@ void Undo(void)
// palette que la page courante. Mais en temps normal, le backup // 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 // n'est pas utilisé à la suite d'un Undo. Donc ça ne devrait pas
// poser de problèmes. // 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(); Redraw_layered_image();
} }
@ -860,6 +864,10 @@ void Redo(void)
// palette que la page courante. Mais en temps normal, le backup // 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 // n'est pas utilisé à la suite d'un Redo. Donc ça ne devrait pas
// poser de problèmes. // 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(); Redraw_layered_image();
} }
@ -983,7 +991,7 @@ byte Add_layer(T_List_of_pages *list, byte layer)
} }
new_page->Image[layer]=new_image; new_page->Image[layer]=new_image;
// Fill with transparency, initially // 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 // Done. Note that the visible buffer is already ok since we
// only inserted a transparent "slide" somewhere. // only inserted a transparent "slide" somewhere.
@ -1084,3 +1092,16 @@ byte Delete_layer(T_List_of_pages *list, byte layer)
// All ok // All ok
return 0; return 0;
} }
/// Merges the current layer onto the one below it.
byte Merge_layer()
{
int i;
for (i=0; i<Main_image_width*Main_image_height; i++)
{
byte color = *(Main_backups->Pages->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);
}

View File

@ -41,6 +41,8 @@ void Upload_infos_page_main(T_Page * page);
byte Add_layer(T_List_of_pages *list, byte layer); byte Add_layer(T_List_of_pages *list, byte layer);
/// Delete a layer from the latest page of a list. Returns 0 on success. /// Delete a layer from the latest page of a list. Returns 0 on success.
byte Delete_layer(T_List_of_pages *list, byte layer); byte Delete_layer(T_List_of_pages *list, byte layer);
/// Merges the current layer onto the one below it.
byte Merge_layer();
// private // private
T_Page * New_page(byte nb_layers); T_Page * New_page(byte nb_layers);

View File

@ -340,8 +340,10 @@ typedef struct T_Page
byte File_format; ///< File format, in enum ::FILE_FORMATS byte File_format; ///< File format, in enum ::FILE_FORMATS
struct T_Page *Next; ///< Pointer to the next backup struct T_Page *Next; ///< Pointer to the next backup
struct T_Page *Prev; ///< Pointer to the previous 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 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; } T_Page;
/// Collection of undo/redo steps. /// Collection of undo/redo steps.
@ -356,7 +358,6 @@ typedef struct
{ {
int Width; ///< Image width in pixels. int Width; ///< Image width in pixels.
int Height; ///< Image height in pixels. int Height; ///< Image height in pixels.
//int Users; ///< Number of references.
byte * Image; ///< Pixel data for the image. byte * Image; ///< Pixel data for the image.
} T_Image; } T_Image;