[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++;
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

View File

@ -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,6 +3177,19 @@ 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:
@ -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

4
misc.c
View File

@ -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);

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++)
{
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;
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++)
{
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;
}
@ -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; 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);
/// 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);

View File

@ -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;