From faea65e62b49139fd7790452b742a0e86c7bf8cf Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Mon, 21 Sep 2009 13:59:30 +0000 Subject: [PATCH 01/25] Initializing branch 'layers' from trunk at revision 1034 git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1038 416bcca6-2ee7-4201-b75f-2eb2f807beb1 From cedb706326da30e6849e8c297a2ae6f29ca2a466 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Mon, 21 Sep 2009 14:16:41 +0000 Subject: [PATCH 02/25] First svn commit of the experiment with layers. Preemptive backup (to shorten delay before drawing) is currently disabled. Basic Undo/Redo works, but not image resizing, the adjust tool, and saving (not even flattened) git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1039 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- brush.c | 7 +- buttons.c | 93 +++++-- buttons.h | 2 + const.h | 2 +- engine.c | 24 +- global.h | 18 +- graph.c | 16 +- loadsave.c | 4 +- main.c | 18 +- misc.c | 38 ++- misc.h | 3 +- operatio.c | 3 +- pages.c | 789 ++++++++++++++++++++--------------------------------- pages.h | 24 +- struct.h | 20 +- 15 files changed, 489 insertions(+), 572 deletions(-) diff --git a/brush.c b/brush.c index c6fe95ca..c3032587 100644 --- a/brush.c +++ b/brush.c @@ -728,8 +728,7 @@ void Capture_brush(short start_x,short start_y,short end_x,short end_y,short cle for (y_pos=start_y;y_posNb_pages_allocated==1) + if ( (Main_backups->List_size==1) || (!Confirmation_box("Delete the current page?")) ) { - if (Main_backups->Nb_pages_allocated==1) + if (Main_backups->List_size==1) Warning_message("You can't delete the last page."); Hide_cursor(); Unselect_button(BUTTON_KILL); @@ -2540,33 +2542,33 @@ void Button_Paintbrush_menu(void) Hide_cursor(); Display_stored_brush_in_window(x_pos+2, y_pos+2, index); Display_cursor(); - } + } else { // Restore and exit - + if (Restore_brush(index)) { - Close_window(); + Close_window(); break; } } - + } else if (clicked_button>1 && Window_attribute1==LEFT_SIDE) // Standard paintbrushes - { + { Close_window(); - index=clicked_button-2; - Paintbrush_shape=Gfx->Paintbrush_type[index]; - Paintbrush_width=Gfx->Preset_paintbrush_width[index]; - Paintbrush_height=Gfx->Preset_paintbrush_height[index]; - Paintbrush_offset_X=Gfx->Preset_paintbrush_offset_X[index]; - Paintbrush_offset_Y=Gfx->Preset_paintbrush_offset_Y[index]; - for (y_pos=0; y_posPaintbrush_sprite[index][y_pos][x_pos]; - Change_paintbrush_shape(Gfx->Paintbrush_type[index]); + index=clicked_button-2; + Paintbrush_shape=Gfx->Paintbrush_type[index]; + Paintbrush_width=Gfx->Preset_paintbrush_width[index]; + Paintbrush_height=Gfx->Preset_paintbrush_height[index]; + Paintbrush_offset_X=Gfx->Preset_paintbrush_offset_X[index]; + Paintbrush_offset_Y=Gfx->Preset_paintbrush_offset_Y[index]; + for (y_pos=0; y_posPaintbrush_sprite[index][y_pos][x_pos]; + Change_paintbrush_shape(Gfx->Paintbrush_type[index]); break; } @@ -4254,6 +4256,45 @@ void Transparency_set(byte amount) Compute_colorize_table(); } +void Layer_activate(short layer, short side) +{ + if (side == RIGHT_SIDE) + { + // Right-click on current layer + if (Main_current_layer == layer) + { + if (Main_layers_visible == (1<Pages); + //Download_infos_backup(Main_backups); + Display_all_screen(); + Display_cursor(); +} + //---------------------------- Courbes de Bézier ---------------------------- void Button_Curves(void) @@ -5442,9 +5483,11 @@ void Button_Effects(void) break; case 13 : // Feedback (pour Colorize et Shade) if ((Config.FX_Feedback=!Config.FX_Feedback)) //!!! - FX_feedback_screen=Main_screen; + FX_feedback_screen=Main_backups->Pages->Image[Main_current_layer]; + // Main_screen else - FX_feedback_screen=Screen_backup; + FX_feedback_screen=Main_backups->Pages->Next->Image[Main_current_layer]; + // Screen_backup Hide_cursor(); Display_feedback_state(); Display_cursor(); @@ -5752,10 +5795,10 @@ void Display_stored_brush_in_window(word x_pos,word y_pos,int index) offset_y = (BRUSH_CONTAINER_PREVIEW_HEIGHT-Brush_container[index].Height)/2; // Determine corner pixel of paintbrush to draw (if bigger than preview area) // - + // Clear Window_rectangle(x_pos,y_pos,BRUSH_CONTAINER_PREVIEW_WIDTH,BRUSH_CONTAINER_PREVIEW_HEIGHT,MC_Light); - + // Draw up to 16x16 for (y=0; y=0) && (y_pos>=0)) //Toujours vrai ? if ((x_posPages->Image[depth] + x+y*Main_image_width); + // return *(Main_screen+y*Main_image_width+x); } -void Pixel_in_current_screen (word x,word y,byte color) +void Pixel_in_current_screen (word x,word y,byte color,int with_preview) { - byte* dest=(x+y*Main_image_width+Main_screen); - *dest=color; + byte depth = *(Visible_image_depth_buffer.Image+x+y*Main_image_width); + *(Main_backups->Pages->Image[Main_current_layer] + x+y*Main_image_width)=color; + if ( depth <= Main_current_layer) + { + if (color == 0) // transparent + // fetch pixel color from the topmost visible layer + color=*(Main_backups->Pages->Image[depth] + x+y*Main_image_width); + + *(x+y*Main_image_width+Main_screen)=color; + + if (with_preview) + Pixel_preview(x,y,color); + } +} + +byte Read_pixel_from_current_layer(word x,word y) +{ + return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer]); } void Replace_a_color(byte old_color, byte New_color) @@ -346,9 +370,9 @@ void Remap_general_lowlevel(byte * conversion_table,byte * buffer,short width,sh void Copy_image_to_brush(short start_x,short start_y,short Brush_width,short Brush_height,word image_width) { - byte* src=start_y*image_width+start_x+Main_screen; //Adr départ image (ESI) - byte* dest=Brush; //Adr dest brosse (EDI) - int dx; + byte* src=start_y*image_width+start_x+Main_backups->Pages->Image[Main_current_layer]; //Adr départ image (ESI) + byte* dest=Brush; //Adr dest brosse (EDI) + int dx; for (dx=Brush_height;dx!=0;dx--) //Pour chaque ligne diff --git a/misc.h b/misc.h index a4396e02..e0a63fba 100644 --- a/misc.h +++ b/misc.h @@ -36,13 +36,14 @@ dword Round_div(dword numerator,dword divisor); word Count_used_colors(dword * usage); word Count_used_colors_area(dword* usage, word start_x, word start_y, word width, word height); word Count_used_colors_screen_area(dword* usage, word start_x, word start_y, word width, word height); -void Pixel_in_current_screen (word x,word y,byte color); +void Pixel_in_current_screen (word x,word y,byte color,int with_preview); void Pixel_in_brush (word x,word y,byte color); byte Read_pixel_from_current_screen (word x,word y); byte Read_pixel_from_spare_screen(word x,word y); byte Read_pixel_from_backup_screen (word x,word y); byte Read_pixel_from_feedback_screen (word x,word y); byte Read_pixel_from_brush (word x,word y); +byte Read_pixel_from_current_layer(word x,word y); void Ellipse_compute_limites(short horizontal_radius,short vertical_radius); // Calcule les valeurs suivantes en fonction des deux paramètres: diff --git a/operatio.c b/operatio.c index c30a1f1b..ee6a8f54 100644 --- a/operatio.c +++ b/operatio.c @@ -3004,7 +3004,8 @@ void Brush_0_5(void) Brush_offset_X=(Brush_offset_X/Snap_width)*Snap_width; Brush_offset_Y=(Brush_offset_Y/Snap_height)*Snap_height; } - + + End_of_modification(); End_of_modification(); Return_to_draw_mode(); } diff --git a/pages.c b/pages.c index a52c9c22..e1598f94 100644 --- a/pages.c +++ b/pages.c @@ -35,13 +35,20 @@ /// GESTION DES PAGES /// -void Init_page(T_Page * page) -{ - // Important: appeler cette fonction sur toute nouvelle structure T_Page! +/// Bitfield which records which layers are backed up in Page 0. +static word Last_backed_up_layers=0; +/// Allocate and initialize a new page. +T_Page * New_page(void) +{ + T_Page * page; + + page = (T_Page *)malloc(sizeof(T_Page)); if (page!=NULL) { - page->Image=NULL; + int i; + for (i=0; iImage[i]=NULL; page->Width=0; page->Height=0; memset(page->Palette,0,sizeof(T_Palette)); @@ -50,6 +57,7 @@ void Init_page(T_Page * page) page->Filename[0]='\0'; page->File_format=DEFAULT_FILEFORMAT; } + return page; } void Download_infos_page_main(T_Page * page) @@ -57,13 +65,13 @@ void Download_infos_page_main(T_Page * page) { //int factor_index; int size_is_modified; - + if (page!=NULL) { size_is_modified=(Main_image_width!=page->Width) || (Main_image_height!=page->Height); - Main_screen=page->Image; + Main_screen=Visible_image[0].Image; Main_image_width=page->Width; Main_image_height=page->Height; memcpy(Main_palette,page->Palette,sizeof(T_Palette)); @@ -81,7 +89,57 @@ void Download_infos_page_main(T_Page * page) Compute_limits(); Compute_paintbrush_coordinates(); } + } + //Update_visible_page_buffer(Visible_image_index, page->Width, page->Height); + //memcpy(Main_screen, page->Image[Main_current_layer], page->Width*page->Height); + +} + +void Redraw_layered_image(void) +{ + // Re-construct the image with the visible layers + int layer; + // First layer + for (layer=0; layerPages->Image[layer], + Main_image_width*Main_image_height); + + // Initialize the depth buffer + memset(Visible_image_depth_buffer.Image, + layer, + Main_image_width*Main_image_height); + + // skip all other layers + layer++; + break; + } + } + // subsequent layer(s) + for (; layerPages->Image[layer]+i); + if (color != 0) /* transp color */ + { + *(Visible_image[0].Image+i) = color; + if (layer != Main_current_layer) + *(Visible_image_depth_buffer.Image+i) = layer; + } + } + } + } + Main_screen=Visible_image[0].Image; + Download_infos_backup(Main_backups); } void Upload_infos_page_main(T_Page * page) @@ -89,7 +147,7 @@ void Upload_infos_page_main(T_Page * page) { if (page!=NULL) { - page->Image=Main_screen; + //page->Image[Main_current_layer]=Main_screen; page->Width=Main_image_width; page->Height=Main_image_height; memcpy(page->Palette,Main_palette,sizeof(T_Palette)); @@ -104,7 +162,7 @@ void Download_infos_page_spare(T_Page * page) { if (page!=NULL) { - Spare_screen=page->Image; + Spare_screen=page->Image[Spare_current_layer]; Spare_image_width=page->Width; Spare_image_height=page->Height; memcpy(Spare_palette,page->Palette,sizeof(T_Palette)); @@ -119,7 +177,7 @@ void Upload_infos_page_spare(T_Page * page) { if (page!=NULL) { - page->Image=Spare_screen; + page->Image[Spare_current_layer]=Spare_screen; page->Width=Spare_image_width; page->Height=Spare_image_height; memcpy(page->Palette,Spare_palette,sizeof(T_Palette)); @@ -132,21 +190,26 @@ void Upload_infos_page_spare(T_Page * page) void Download_infos_backup(T_List_of_pages * list) { - Screen_backup=list->Pages[1].Image; + Screen_backup=Visible_image[1].Image; + //list->Pages->Next->Image[Main_current_layer]; if (Config.FX_Feedback) - FX_feedback_screen=list->Pages[0].Image; + FX_feedback_screen=list->Pages->Image[Main_current_layer]; + // Visible_image[0].Image; else - FX_feedback_screen=list->Pages[1].Image; + FX_feedback_screen=list->Pages->Next->Image[Main_current_layer]; + // Visible_image[1].Image; } -void Free_a_page(T_Page * page) +void Clear_page(T_Page * page) { // On peut appeler cette fonction sur une page non allouée. - - if (page->Image!=NULL) - free(page->Image); - page->Image=NULL; + int i; + for (i=0; iImage[i]); + page->Image[i]=NULL; + } page->Width=0; page->Height=0; // On ne se préoccupe pas de ce que deviens le reste des infos de l'image. @@ -157,15 +220,6 @@ void Copy_S_page(T_Page * dest,T_Page * source) *dest=*source; } -int Size_of_a_page(T_Page * page) -{ - return sizeof(T_Page)+(page->Width*page->Height)+8; - // 8 = 4 + 4 - // (Toute zone allouée en mémoire est précédée d'un mot double indiquant sa - // taille, or la taille d'un mot double est de 4 octets, et on utilise deux - // allocations de mémoires: une pour la T_Page et une pour l'image) -} - /// /// GESTION DES LISTES DE PAGES @@ -177,62 +231,30 @@ void Init_list_of_pages(T_List_of_pages * list) // T_List_of_pages! list->List_size=0; - list->Nb_pages_allocated=0; list->Pages=NULL; } -int Allocate_list_of_pages(T_List_of_pages * list,int size) +int Allocate_list_of_pages(T_List_of_pages * list) { // Important: la T_List_of_pages ne doit pas déjà désigner une liste de // pages allouée auquel cas celle-ci serait perdue. - int index; + T_Page * page; - /* Debug : if (list->Pages!=NULL) exit(666); */ + // On initialise chacune des nouvelles pages + page=New_page(); + if (!page) + return 0; + + // Set as first page of the list + page->Next = page; + page->Prev = page; + list->Pages = page; - // On alloue la mémoire pour la liste - list->Pages=(T_Page *)malloc(size*sizeof(T_Page)); + list->List_size=1; - // On vérifie que l'allocation se soit bien passée - if (list->Pages==NULL) - return 0; // Echec - else - { - // On initialise chacune des nouvelles pages - for (index=0;indexPages+index); - list->List_size=size; - list->Nb_pages_allocated=0; - - return 1; // Succès - } + return 1; // Succès } -void Free_a_list_of_pages(T_List_of_pages * list) -{ - // On peut appeler cette fonction sur une liste de pages non allouée. - - // Important: cette fonction ne libère pas les pages de la liste. Il faut - // donc le faire préalablement si nécessaire. - - if (list->Pages!=NULL) - free(list->Pages); - list->Pages=NULL; - list->List_size=0; - list->Nb_pages_allocated=0; -} - -int Size_of_a_list_of_pages(T_List_of_pages * list) -{ - int result=0; - int index; - - for (index=0;indexNb_pages_allocated;index++) - result+=Size_of_a_page(list->Pages+index); - - return result+sizeof(T_List_of_pages)+4; - - // C.F. la remarque à propos de Size_of_a_page pour la valeur 4. -} void Backward_in_list_of_pages(T_List_of_pages * list) { @@ -252,29 +274,26 @@ void Backward_in_list_of_pages(T_List_of_pages * list) // sortie, ainsi que celles relatives à la plus récente page d'undo (1ère // page de la liste). - int index; - T_Page * temp_page; - - if (list->Nb_pages_allocated>1) + if (Last_backed_up_layers) { - // On crée la page tempo - temp_page=(T_Page *)malloc(sizeof(T_Page)); - Init_page(temp_page); + // First page contains a ready-made backup of its ->Next. + // We have swap the first two pages, so the original page 0 + // will end up in position 0 again, and then overwrite it with a backup + // of the 'new' page1. + T_Page * page0; + T_Page * page1; - // On copie la 1ère page (page 0) dans la page temporaire - Copy_S_page(temp_page,list->Pages); - - // On copie toutes les pages 1-A à leur gauche - for (index=1;indexNb_pages_allocated;index++) - Copy_S_page(list->Pages+index-1,list->Pages+index); - - // On copie la page 0 (dont la sauvegarde a été effectuée dans la page - // temporaire) en dernière position - Copy_S_page(list->Pages+list->Nb_pages_allocated-1,temp_page); - - // On détruit la page tempo - free(temp_page); + page0 = list->Pages; + page1 = list->Pages->Next; + + page0->Next = page1->Next; + page1->Prev = page0->Prev; + page0->Prev = page1; + page1->Next = page0; + list->Pages = page0; + return; } + list->Pages = list->Pages->Next; } void Advance_in_list_of_pages(T_List_of_pages * list) @@ -294,242 +313,96 @@ void Advance_in_list_of_pages(T_List_of_pages * list) // de page courante à jour avant l'appel, puis en réextraire les infos en // sortie, ainsi que celles relatives à la plus récente page d'undo (1ère // page de la liste). - - int index; - T_Page * temp_page; - - if (list->Nb_pages_allocated>1) + if (Last_backed_up_layers) { - // On crée la page tempo - temp_page=(T_Page *)malloc(sizeof(T_Page)); - Init_page(temp_page); + // First page contains a ready-made backup of its ->Next. + // We have swap the first two pages, so the original page 0 + // will end up in position -1 again, and then overwrite it with a backup + // of the 'new' page1. + T_Page * page0; + T_Page * page1; - // On copie la dernière page dans la page temporaire - Copy_S_page(temp_page,list->Pages+list->Nb_pages_allocated-1); - - // On copie toutes les pages 0-9 à leur droite - for (index=list->Nb_pages_allocated-1;index>0;index--) - Copy_S_page(list->Pages+index,list->Pages+index-1); - - // On copie la page plus ancienne page (la "A", dont la sauvegarde a été - // effectuée dans la page temporaire) en 1ère position - Copy_S_page(list->Pages,temp_page); - - // On détruit la page tempo - free(temp_page); + page0 = list->Pages; + page1 = list->Pages->Prev; + + page0->Prev = page1->Prev; + page1->Next = page0->Next; + page0->Next = page1; + page1->Prev = page0; + list->Pages = page1; + return; } -} - -int New_page_is_possible( - T_Page * new_page, - T_List_of_pages * current_list, - T_List_of_pages * secondary_list -) -{ - long long mem_available_now; - unsigned long current_list_size; - unsigned long spare_list_size; - unsigned long current_page_size; - unsigned long spare_page_size; - unsigned long new_page_size; - - mem_available_now = Memory_free() - - MINIMAL_MEMORY_TO_RESERVE; - current_list_size =Size_of_a_list_of_pages(current_list); - spare_list_size=Size_of_a_list_of_pages(secondary_list); - current_page_size =Size_of_a_page(current_list->Pages); - spare_page_size =Size_of_a_page(secondary_list->Pages); - new_page_size =Size_of_a_page(new_page); - - // Il faut pouvoir loger la nouvelle page et son backup dans la page - // courante, en conservant au pire la 1ère page de brouillon. - if ( (mem_available_now + current_list_size + - spare_list_size - spare_page_size) - < (2*new_page_size) ) - return 0; - - // Il faut pouvoir loger le brouillon et son backup dans la page de - // brouillon, en conservant au pire un exemplaire de la nouvelle page dans - // la page courante. (pour permettre à l'utilisateur de travailler sur son - // brouillon) - if ((mem_available_now+current_list_size+ - spare_list_size-new_page_size)<(2*spare_page_size)) - return 0; - - return 1; + list->Pages = list->Pages->Prev; } void Free_last_page_of_list(T_List_of_pages * list) { if (list!=NULL) { - if (list->Nb_pages_allocated>0) + if (list->List_size>0) { - list->Nb_pages_allocated--; - Free_a_page(list->Pages+list->Nb_pages_allocated); + T_Page * page; + // The last page is the one before first + page = list->Pages->Prev; + + page->Next->Prev = page->Prev; + page->Prev->Next = page->Next; + Clear_page(page); + free(page); + list->List_size--; } } } -void Create_new_page(T_Page * new_page,T_List_of_pages * current_list,T_List_of_pages * secondary_list) +int Create_new_page(T_Page * new_page,T_List_of_pages * list) { // Cette fonction crée une nouvelle page dont les attributs correspondent à // ceux de new_page (width,height,...) (le champ Image est invalide // à l'appel, c'est la fonction qui le met à jour), et l'enfile dans -// current_list. -// Il est impératif que la création de cette page soit possible, -// éventuellement au détriment des backups de la page de brouillon -// (secondary_list). Afin de s'en assurer, il faut vérifier cette -// possibilité à l'aide de -// New_page_is_possible(new_page,current_list,secondary_list) avant -// l'appel à cette fonction. -// De plus, il faut qu'il y ait au moins une page dans chacune des listes. +// list. - int need_to_free; - T_List_of_pages * list_to_reduce=NULL; - T_Page * page_to_delete; - int index; - // On regarde s'il faut libérer des pages: - need_to_free= - // C'est le cas si la current_list est pleine - ( (current_list->List_size==current_list->Nb_pages_allocated) - // ou qu'il ne reste plus assez de place pour allouer la new_page - || ( (Memory_free()-MINIMAL_MEMORY_TO_RESERVE)< - (unsigned long)(new_page->Height*new_page->Width) ) ); - - if (!need_to_free) + if (list->List_size >= (Config.Max_undo_pages+1)) { - // On a assez de place pour allouer une page, et de plus la current_list - // n'est pas pleine. On n'a donc aucune page à supprimer. On peut en - // allouer une directement. - new_page->Image=(byte *)malloc(new_page->Height*new_page->Width); + // On manque de mémoire ou la list est pleine. Dans tous les + // cas, il faut libérer une page. + + // Détruire la dernière page allouée dans la Liste_à_raboter + Free_last_page_of_list(list); } - else { - // On manque de mémoire ou la current_list est pleine. Dans tous les - // cas, il faut libérer une page... qui peut-être pourra re-servir. - - // Tant qu'il faut libérer - while (need_to_free) - { - // On cherche sur quelle liste on va virer une page - - // S'il reste des pages à libérer dans la current_list - if (current_list->Nb_pages_allocated>1) - // Alors on va détruire la dernière page allouée de la current_list - list_to_reduce=current_list; - else - { - if (secondary_list->Nb_pages_allocated>1) - { - // Sinon on va détruire la dernière page allouée de la - // secondary_list - list_to_reduce=secondary_list; - } - else - { - // Bon, alors là, on vient de vider toutes les pages et on a toujours pas asez de mémoire... C'est donc qu'un vilain programmeur a oublié de vérifier avec Noiuvelle_page_possible avant de venir ici. - // On sort méchament du programme sans sauvegarde ni rien. De toutes façons, ça ne devrait jamais se produire... - Error(ERROR_SORRY_SORRY_SORRY); - } - } - - // Puis on détermine la page que l'on va supprimer (c'est la dernière de - // la liste) - page_to_delete=list_to_reduce->Pages+(list_to_reduce->Nb_pages_allocated)-1; - - // On regarde si on peut recycler directement la page (cas où elle - // aurait la même surface que la new_page) - if ((page_to_delete->Height*page_to_delete->Width)== - (new_page->Height*new_page->Width)) - { - // Alors - // On récupère le bitmap de la page à supprimer (évite de faire des - // allocations/désallocations fastidieuses et inutiles) - new_page->Image=page_to_delete->Image; - - // On fait semblant que la dernière page allouée ne l'est pas - list_to_reduce->Nb_pages_allocated--; - - // On n'a plus besoin de libérer de la mémoire puisqu'on a refilé à - // new_page un bitmap valide - need_to_free=0; - } - else - { - // Sinon - - // Détruire la dernière page allouée dans la Liste_à_raboter - Free_last_page_of_list(list_to_reduce); - - // On regarde s'il faut continuer à libérer de la place - need_to_free=(Memory_free()-MINIMAL_MEMORY_TO_RESERVE) - <(unsigned long)(new_page->Height*new_page->Width); - - // S'il ne faut pas, c'est qu'on peut allouer un bitmap - // pour la new_page - if (!need_to_free) - new_page->Image=(byte *)malloc(new_page->Height*new_page->Width); - } - } + int i; + for (i=0; iImage[i]=(byte *)malloc(new_page->Height*new_page->Width); } - // D'après l'hypothèse de départ, la boucle ci-dessus doit s'arrêter car - // on a assez de mémoire pour allouer la nouvelle page. - // Désormais new_page contient un pointeur sur une zone bitmap valide. - - // Décaler la current_list d'un cran vers le passé. - for (index=current_list->List_size-1;index>0;index--) - Copy_S_page(current_list->Pages+index,current_list->Pages+index-1); - - // Recopier la new_page en 1ère position de la current_list - Copy_S_page(current_list->Pages,new_page); - current_list->Nb_pages_allocated++; + + // Insert as first + new_page->Next = list->Pages; + new_page->Prev = list->Pages->Prev; + list->Pages->Prev->Next = new_page; + list->Pages->Prev = new_page; + list->Pages = new_page; + list->List_size++; + + return 1; } void Change_page_number_of_list(T_List_of_pages * list,int number) { - int index; - T_Page * new_pages; - - // Si la liste a déjà la taille demandée - if (list->List_size==number) - // Alors il n'y a rien à faire - return; - - // Si la liste contient plus de pages que souhaité - if (list->List_size>number) - // Alors pour chaque page en excés - for (index=number;indexList_size;index++) - // On libère la page - Free_a_page(list->Pages+index); - - // On fait une nouvelle liste de pages: - new_pages=(T_Page *)malloc(number*sizeof(T_Page)); - for (index=0;indexList_size);index++) - Copy_S_page(new_pages+index,list->Pages+index); - - // On libère l'ancienne liste - free(list->Pages); - - // On met à jour les champs de la nouvelle liste - list->Pages=new_pages; - list->List_size=number; - if (list->Nb_pages_allocated>number) - list->Nb_pages_allocated=number; + // Truncate the list if larger than requested + while(list->List_size > number) + { + Free_last_page_of_list(list); + } } void Free_page_of_a_list(T_List_of_pages * list) { // On ne peut pas détruire la page courante de la liste si après // destruction il ne reste pas encore au moins une page. - if (list->Nb_pages_allocated>1) + if (list->List_size>1) { // On fait faire un undo à la liste, comme ça, la nouvelle page courante // est la page précédente @@ -540,82 +413,96 @@ void Free_page_of_a_list(T_List_of_pages * list) } } +int Update_visible_page_buffer(int index, int width, int height) +{ + if (Visible_image[index].Width != width || Visible_image[index].Height != height) + { + Visible_image[index].Width = width; + Visible_image[index].Height = height; + free(Visible_image[index].Image); + Visible_image[index].Image = (byte *)malloc(width * height); + if (Visible_image[index].Image == NULL) + return 0; + } + return 1; +} + +void Advance_visible_page_buffer() +{ + +} /// /// GESTION DES BACKUPS /// -int Init_all_backup_lists(int size,int width,int height) +int Init_all_backup_lists(int width,int height) { - // size correspond au nombre de pages que l'on souhaite dans chaque liste - // (1 pour la page courante, puis 1 pour chaque backup, soit 2 au minimum). // width et height correspondent à la dimension des images de départ. + int i; - T_Page * page; - int return_code=0; - - if (Allocate_list_of_pages(Main_backups,size) && - Allocate_list_of_pages(Spare_backups,size)) + if (Allocate_list_of_pages(Main_backups) && + Allocate_list_of_pages(Spare_backups)) { // On a réussi à allouer deux listes de pages dont la taille correspond à // celle demandée par l'utilisateur. // On crée un descripteur de page correspondant à la page principale - page=(T_Page *)malloc(sizeof(T_Page)); - Init_page(page); - Upload_infos_page_main(page); + Upload_infos_page_main(Main_backups->Pages); // On y met les infos sur la dimension de démarrage - page->Width=width; - page->Height=height; - - // On regarde si on peut ajouter cette page - if (New_page_is_possible(page,Main_backups,Spare_backups)) + Main_backups->Pages->Width=width; + Main_backups->Pages->Height=height; + for (i=0; iPages->Image[i]=(byte *)malloc(width*height); + } - // Maintenant, on regarde si on a le droit de créer la même page dans - // la page de brouillon. - if (New_page_is_possible(page,Spare_backups,Main_backups)) + if (!Update_visible_page_buffer(0, width, height)) + return 0; + if (!Update_visible_page_buffer(1, width, height)) + return 0; + + Main_screen=Visible_image[0].Image; + + Download_infos_page_main(Main_backups->Pages); + Download_infos_backup(Main_backups); + + // Maintenant, on regarde si on a le droit de créer la même page dans + // la page de brouillon. + Download_infos_page_spare(Spare_backups->Pages); + + // Et on efface les 2 images en les remplacant de "0" + memset(Main_screen,0,Main_image_width*Main_image_height); + memset(Spare_screen,0,Spare_image_width*Spare_image_height); + + Visible_image[0].Width = width; + Visible_image[0].Height = height; + Visible_image[0].Image = NULL; + + Visible_image[1].Width = width; + Visible_image[1].Height = height; + Visible_image[1].Image = NULL; + + Visible_image_depth_buffer.Width = width; + Visible_image_depth_buffer.Height = height; + Visible_image_depth_buffer.Image = NULL; + + Visible_image[0].Image = (byte *)malloc(Visible_image[0].Width * Visible_image[0].Height); + if (Visible_image[0].Image) + { + Visible_image[1].Image = (byte *)malloc(Visible_image[1].Width * Visible_image[1].Height); + if (Visible_image[1].Image) { - // On peut donc on le fait - Create_new_page(page,Spare_backups,Main_backups); - Download_infos_page_spare(page); - - // Et on efface les 2 images en les remplacant de "0" - memset(Main_screen,0,Main_image_width*Main_image_height); - memset(Spare_screen,0,Spare_image_width*Spare_image_height); - - return_code=1; - } - else - { - // Il n'est pas possible de démarrer le programme avec la page - // principale et la page de brouillon aux dimensions demandée par - // l'utilisateur. ==> On l'envoie ballader - return_code=0; + Visible_image_depth_buffer.Image = (byte *)malloc(Visible_image_depth_buffer.Width * Visible_image_depth_buffer.Height); + if (Visible_image_depth_buffer.Image) + { + End_of_modification(); + return 1; + } } } - else - { - // On ne peut pas démarrer le programme avec ne serait-ce qu'une - // page de la dimension souhaitée, donc on laisse tout tomber et on - // le renvoie chier. - free(page); - return_code=0; - } } - else - { - // On n'a même pas réussi à créer les listes. Donc c'est même pas la - // peine de continuer : l'utilisateur ne pourra jamais rien faire, - // autant avorter le chargement du programme. - return_code=0; - } - - return return_code; + return 0; } void Set_number_of_backups(int nb_backups) @@ -642,15 +529,18 @@ int Backup_with_new_dimensions(int upload,int width,int height) Upload_infos_page_main(Main_backups->Pages); // On crée un descripteur pour la nouvelle page courante - new_page=(T_Page *)malloc(sizeof(T_Page)); - Init_page(new_page); + new_page=New_page(); + if (!new_page) + { + Error(0); + return 0; + } Upload_infos_page_main(new_page); new_page->Width=width; new_page->Height=height; - if (New_page_is_possible(new_page,Main_backups,Spare_backups)) + if (Create_new_page(new_page,Main_backups)) { - Create_new_page(new_page,Main_backups,Spare_backups); Download_infos_page_main(new_page); Download_infos_backup(Main_backups); // On nettoie la nouvelle image: @@ -677,15 +567,18 @@ int Backup_and_resize_the_spare(int width,int height) Upload_infos_page_spare(Spare_backups->Pages); // On crée un descripteur pour la nouvelle page de brouillon - new_page=(T_Page *)malloc(sizeof(T_Page)); - Init_page(new_page); - + new_page=New_page(); + if (!new_page) + { + Error(0); + return 0; + } + Upload_infos_page_spare(new_page); new_page->Width=width; new_page->Height=height; - if (New_page_is_possible(new_page,Spare_backups,Main_backups)) + if (Create_new_page(new_page,Spare_backups)) { - Create_new_page(new_page,Spare_backups,Main_backups); Download_infos_page_spare(new_page); return_code=1; } @@ -700,50 +593,56 @@ void Backup(void) // Sauve la page courante comme première page de backup et crée une nouvelle page // pur continuer à dessiner. Utilisé par exemple pour le fill { - #if defined(__macosx__) || defined(__FreeBSD__) - T_Page new_page; - #else - T_Page *new_page; - #endif + int i; + + T_Page *new_page; + + /* + if (Last_backed_up_layers == (1<Pages); // On crée un descripteur pour la nouvelle page courante -#if defined(__macosx__) || defined(__FreeBSD__) - Init_page(&new_page); - - // Enrichissement de l'historique - Copy_S_page(&new_page,Main_backups->Pages); - Create_new_page(&new_page,Main_backups,Spare_backups); - Download_infos_page_main(&new_page); -#else - new_page=(T_Page *)malloc(sizeof(T_Page)); - Init_page(new_page); - + new_page=New_page(); + if (!new_page) + { + Error(0); + return; + } + // Enrichissement de l'historique Copy_S_page(new_page,Main_backups->Pages); - Create_new_page(new_page,Main_backups,Spare_backups); + Create_new_page(new_page,Main_backups); Download_infos_page_main(new_page); -#endif Download_infos_backup(Main_backups); // On copie l'image du backup vers la page courante: - memcpy(Main_screen,Screen_backup,Main_image_width*Main_image_height); - - // On détruit le descripteur de la page courante -#if !(defined(__macosx__) || defined(__FreeBSD__)) - free(new_page); -#endif + for (i=0; iPages->Image[i], + Main_backups->Pages->Next->Image[i], + Main_image_width*Main_image_height); // On allume l'indicateur de modification de l'image Main_image_is_modified=1; + + /* + Last_backed_up_layers = 1<Pages); @@ -758,10 +657,17 @@ 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. + Redraw_layered_image(); + } void Redo(void) { + if (Last_backed_up_layers) + { + Free_page_of_a_list(Main_backups); + Last_backed_up_layers=0; + } // On remet à jour l'état des infos de la page courante (pour pouvoir les // retrouver plus tard) Upload_infos_page_main(Main_backups->Pages); @@ -776,6 +682,8 @@ 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. + Redraw_layered_image(); + } void Free_current_page(void) @@ -822,115 +730,22 @@ void Exchange_main_and_spare(void) Download_infos_page_main(Main_backups->Pages); Download_infos_page_spare(Spare_backups->Pages); Download_infos_backup(Main_backups); -} - - -int Can_borrow_memory_from_page(int size) -{ - int mem_available_now; - int current_list_size; - int spare_list_size; - int current_page_size; - int spare_page_size; - - mem_available_now=Memory_free()-MINIMAL_MEMORY_TO_RESERVE; - current_list_size =Size_of_a_list_of_pages(Main_backups); - spare_list_size=Size_of_a_list_of_pages(Spare_backups); - current_page_size =Size_of_a_page(Main_backups->Pages); - spare_page_size =Size_of_a_page(Spare_backups->Pages); - - // Il faut pouvoir loger la zone mémoire ainsi qu'un exemplaire de la page - // courante, en conservant au pire la 1ère page de brouillon. - if ((mem_available_now - +current_list_size - +spare_list_size - -current_page_size - -spare_page_size)Nb_pages_allocated>1) - // Alors on va détruire la dernière page allouée de la liste des - // brouillons - list_to_reduce=Spare_backups; - else - { - if (Main_backups->Nb_pages_allocated>1) - { - // Sinon on va détruire la dernière page allouée de la - // liste principale - list_to_reduce=Main_backups; - } - else - { - // Dans cette branche, il était prévu qu'on obtienne la mémoire - // nécessaire mais on n'arrive pas à la trouver. On indique donc - // qu'elle n'est pas disponible, et on aura perdu des backups - // pour rien - return 0; - } - } - - // Puis on détermine la page que l'on va supprimer (c'est la dernière - // de la liste) - page_to_delete=list_to_reduce->Pages+(list_to_reduce->Nb_pages_allocated)-1; - - // Détruire la dernière page allouée dans la Liste_à_raboter - Free_last_page_of_list(list_to_reduce); - - // On regarde s'il faut continuer à libérer de la place - need_to_free= - (Memory_free()-MINIMAL_MEMORY_TO_RESERVE)<(unsigned long)size; - - // S'il ne faut pas, c'est qu'on peut allouer un bitmap - // pour la new_page - if (!need_to_free) - return malloc(size); - } - } - } - else - { - // Il n'y a pas assez de place pour allouer la mémoire temporaire dans - // la mémoire réservée aux pages. - return 0; - } - - // Pour que le compilateur ne dise pas qu'il manque une valeur de sortie: - return 0; + Redraw_layered_image(); } void End_of_modification(void) { +/* + Update_visible_page_buffer(1, Main_image_width, Main_image_height); + memcpy(Visible_image[1].Image, + Visible_image[0].Image, + Main_image_width*Main_image_height); + + Main_screen=Visible_image[0].Image; + + Download_infos_backup(Main_backups); + + Last_backed_up_layers = 0; + Backup(); + */ } diff --git a/pages.h b/pages.h index 8a6c8ca4..e715d2e9 100644 --- a/pages.h +++ b/pages.h @@ -39,13 +39,12 @@ void Download_infos_page_main(T_Page * page); void Upload_infos_page_main(T_Page * page); // private -void Init_page(T_Page * page); +T_Page * New_page(void); void Download_infos_page_spare(T_Page * page); void Upload_infos_page_spare(T_Page * page); void Download_infos_backup(T_List_of_pages * list); -void Free_a_page(T_Page * page); +void Clear_page(T_Page * page); void Copy_S_page(T_Page * dest,T_Page * source); -int Size_of_a_page(T_Page * page); @@ -55,14 +54,11 @@ int Size_of_a_page(T_Page * page); void Init_list_of_pages(T_List_of_pages * list); // private -int Allocate_list_of_pages(T_List_of_pages * list,int size); -void Free_a_list_of_pages(T_List_of_pages * list); -int Size_of_a_list_of_pages(T_List_of_pages * list); +int Allocate_list_of_pages(T_List_of_pages * list); void Backward_in_list_of_pages(T_List_of_pages * list); void Advance_in_list_of_pages(T_List_of_pages * list); -int New_page_is_possible(T_Page * new_page,T_List_of_pages * current_list,T_List_of_pages * secondary_list); void Free_last_page_of_list(T_List_of_pages * list); -void Create_new_page(T_Page * new_page,T_List_of_pages * current_list,T_List_of_pages * secondary_list); +int Create_new_page(T_Page * new_page,T_List_of_pages * current_list); void Change_page_number_of_list(T_List_of_pages * list,int number); void Free_page_of_a_list(T_List_of_pages * list); @@ -72,7 +68,7 @@ void Free_page_of_a_list(T_List_of_pages * list); /// BACKUP HIGH-LEVEL FUNCTIONS /// -int Init_all_backup_lists(int size,int width,int height); +int Init_all_backup_lists(int width,int height); void Set_number_of_backups(int nb_backups); int Backup_with_new_dimensions(int upload,int width,int height); int Backup_and_resize_the_spare(int width,int height); @@ -83,14 +79,4 @@ void Free_current_page(void); // 'Kill' button void Exchange_main_and_spare(void); void End_of_modification(void); - -/// -/// BORROWING MEMORY FROM PAGE -/// - -void * Borrow_memory_from_page(int size); -// private -int Can_borrow_memory_from_page(int size); - - #endif diff --git a/struct.h b/struct.h index 7ffed0b4..4b62483f 100644 --- a/struct.h +++ b/struct.h @@ -319,9 +319,8 @@ typedef struct // backup dans "graph.c". /// This is the data for one step of Undo/Redo, for one image. -typedef struct +typedef struct T_Page { - byte * Image; ///< Pixel data for the image. int Width; ///< Image width in pixels. int Height; ///< Image height in pixels. T_Palette Palette; ///< Image palette. @@ -331,17 +330,27 @@ typedef struct char File_directory[MAX_PATH_CHARACTERS];///< Directory that contains the file. char Filename[MAX_PATH_CHARACTERS]; ///< Filename without directory. byte File_format; ///< File format, in enum ::FILE_FORMATS - + struct T_Page *Next; + struct T_Page *Prev; + byte * Image[NB_LAYERS];///< Pixel data for the image. } T_Page; /// Collection of undo/redo steps. typedef struct { int List_size; ///< Number of ::T_Page in the vector "Pages". - int Nb_pages_allocated;///< Number of ::T_Page used so far in the vector "Pages". - T_Page * Pages; ///< Vector of Pages, each one being a undo/redo step. + T_Page * Pages; ///< Head of a linked list of pages, each one being a undo/redo step. } T_List_of_pages; +/// A single image bitmap +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; + /// A single memorized brush from the Brush Container typedef struct { @@ -355,7 +364,6 @@ typedef struct byte Transp_color; } T_Brush_template; - /// GUI skin data typedef struct { From 78e59e6127c191c568c28794fbeffa122c2040d2 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Tue, 22 Sep 2009 22:55:02 +0000 Subject: [PATCH 03/25] (layers branch) Adjust tool implemented. Left click and drag to move a single layer, Right-click and drag to move everything. git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1041 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- gfx2.cfg | Bin 10217 -> 10217 bytes init.c | 12 +++++----- misc.c | 32 ++++++++++++------------- misc.h | 2 +- operatio.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++----- operatio.h | 4 ++-- pages.c | 4 ++-- 7 files changed, 88 insertions(+), 33 deletions(-) diff --git a/gfx2.cfg b/gfx2.cfg index eacf653bdb5c66e77dd7093073d60b5dd73ddf00..f250eb60b2892a7c49503e69173057dcdbed9dcd 100644 GIT binary patch delta 33 lcmaFq|I&YhAG3&|00To0gAtJIWiSSkeGDc7o0FK^RREin2l@a2 delta 33 lcmaFq|I&YhAG3%l0|P@3gBg(QWiSVleGC>1o0FK^RREaP2g(2d diff --git a/init.c b/init.c index 2cc6761a..f0540359 100644 --- a/init.c +++ b/init.c @@ -1585,12 +1585,12 @@ void Init_operations(void) Scroll_12_0,HIDE_CURSOR,FAST_MOUSE); Init_operation(OPERATION_SCROLL,2,0, Scroll_12_0,HIDE_CURSOR,FAST_MOUSE); - Init_operation(OPERATION_SCROLL,1,4, - Scroll_12_4,0,FAST_MOUSE); - Init_operation(OPERATION_SCROLL,2,4, - Scroll_12_4,0,FAST_MOUSE); - Init_operation(OPERATION_SCROLL,0,4, - Scroll_0_4,HIDE_CURSOR,FAST_MOUSE); + Init_operation(OPERATION_SCROLL,1,5, + Scroll_12_5,0,FAST_MOUSE); + Init_operation(OPERATION_SCROLL,2,5, + Scroll_12_5,0,FAST_MOUSE); + Init_operation(OPERATION_SCROLL,0,5, + Scroll_0_5,HIDE_CURSOR,FAST_MOUSE); Init_operation(OPERATION_GRAD_CIRCLE,1,0,Grad_circle_12_0,HIDE_CURSOR,FAST_MOUSE); Init_operation(OPERATION_GRAD_CIRCLE,2,0,Grad_circle_12_0,HIDE_CURSOR,FAST_MOUSE); diff --git a/misc.c b/misc.c index 75bdec10..b6434bac 100644 --- a/misc.c +++ b/misc.c @@ -685,33 +685,33 @@ void Slider_timer(byte speed) } while (Mouse_K == original_mouse_k && SDL_GetTicks()0;dx--) + byte* src = main_src; //source de la copie + byte* dest = main_dest + y_offset * Main_image_width + x_offset; + const word length = Main_image_width - x_offset; // Nombre de pixels à copier à droite + word y; + for(y = Main_image_height - y_offset;y>0;y--) { // Pour chaque ligne - memcpy(edi,esi,ax); - memcpy(edi - x_offset,esi+ax,x_offset); + memcpy(dest,src,length); + memcpy(dest - x_offset,src+length,x_offset); // On passe à la ligne suivante - edi += Main_image_width; - esi += Main_image_width; + dest += Main_image_width; + src += Main_image_width; } // On vient de faire le traitement pour otutes les lignes au-dessous de y_offset // Maintenant on traite celles au dessus - edi = x_offset + Main_screen; - for(dx = y_offset;dx>0;dx--) + dest = x_offset + main_dest; + for(y = y_offset;y>0;y--) { - memcpy(edi,esi,ax); - memcpy(edi - x_offset,esi+ax,x_offset); + memcpy(dest,src,length); + memcpy(dest - x_offset,src+length,x_offset); - edi += Main_image_width; - esi += Main_image_width; + dest += Main_image_width; + src += Main_image_width; } Update_rect(0,0,0,0); diff --git a/misc.h b/misc.h index e0a63fba..7c669ee6 100644 --- a/misc.h +++ b/misc.h @@ -23,7 +23,7 @@ void Copy_image_to_brush(short start_x,short start_y,short Brush_width,short Brush_height,word image_width); void Remap_general_lowlevel(byte * conversion_table,byte * buffer,short width,short height,short buffer_width); -void Scroll_picture(short x_offset,short y_offset); +void Scroll_picture(byte * main_src, byte * main_dest, short x_offset,short y_offset); void Wait_end_of_click(void); void Set_color(byte color, byte red, byte green, byte blue); void Set_palette(T_Palette palette); diff --git a/operatio.c b/operatio.c index ee6a8f54..35308969 100644 --- a/operatio.c +++ b/operatio.c @@ -3914,6 +3914,8 @@ void Scroll_12_0(void) Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); + Operation_push(Mouse_K); // LEFT_SIDE or RIGHT_SIDE + Cursor_hidden_before_scroll=Cursor_hidden; Cursor_hidden=1; if ((Config.Coords_rel) && (Menu_is_visible)) @@ -3921,11 +3923,11 @@ void Scroll_12_0(void) } -void Scroll_12_4(void) +void Scroll_12_5(void) // // Opération : OPERATION_SCROLL // Click Souris: 1 ou 2 -// Taille_Pile : 4 +// Taille_Pile : 5 // // Souris effacée: Non // @@ -3936,8 +3938,10 @@ void Scroll_12_4(void) short y_pos; short x_offset; short y_offset; + short side; //char str[5]; + Operation_pop(&side); Operation_pop(&y_pos); Operation_pop(&x_pos); Operation_pop(¢er_y); @@ -3959,7 +3963,17 @@ void Scroll_12_4(void) Display_coords_rel_or_abs(center_x,center_y); - Scroll_picture(x_offset,y_offset); + if (side == RIGHT_SIDE) + { + // All layers at once + Scroll_picture(Screen_backup, Main_screen, x_offset,y_offset); + } + else + { + // One layer at once + Scroll_picture(Main_backups->Pages->Next->Image[Main_current_layer], Main_backups->Pages->Image[Main_current_layer], x_offset, y_offset); + Redraw_layered_image(); + } Display_all_screen(); } @@ -3968,19 +3982,60 @@ void Scroll_12_4(void) Operation_push(center_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); + Operation_push(side); } -void Scroll_0_4(void) +void Scroll_0_5(void) // // Opération : OPERATION_SCROLL // Click Souris: 0 -// Taille_Pile : 4 +// Taille_Pile : 5 // // Souris effacée: Oui // { - Operation_stack_size-=4; + // All layers at once + short center_x; + short center_y; + short x_pos; + short y_pos; + short x_offset; + short y_offset; + short side; + int i; + + + Operation_pop(&side); + Operation_pop(&y_pos); + Operation_pop(&x_pos); + Operation_pop(¢er_y); + Operation_pop(¢er_x); + + if (side == RIGHT_SIDE) + { + // All layers at once + if (x_pos>=center_x) + x_offset=(x_pos-center_x)%Main_image_width; + else + x_offset=Main_image_width-((center_x-x_pos)%Main_image_width); + + if (y_pos>=center_y) + y_offset=(y_pos-center_y)%Main_image_height; + else + y_offset=Main_image_height-((center_y-y_pos)%Main_image_height); + + + // Do the actual scroll operation on all layers. + for (i=0; iPages->Next->Image[i], Main_backups->Pages->Image[i], x_offset, y_offset); + } + else + { + // One layer : everything was done while dragging the mouse + } + Cursor_hidden=Cursor_hidden_before_scroll; + End_of_modification(); if ((Config.Coords_rel) && (Menu_is_visible)) { diff --git a/operatio.h b/operatio.h index 41f6f133..9bef2eba 100644 --- a/operatio.h +++ b/operatio.h @@ -181,8 +181,8 @@ void Filled_contour_0_8(void); //////////////////////////////////////////////////////////// OPERATION_SCROLL void Scroll_12_0(void); -void Scroll_12_4(void); -void Scroll_0_4(void); +void Scroll_12_5(void); +void Scroll_0_5(void); //////////////////////////////////////////////////// OPERATION_GRAD_CIRCLE diff --git a/pages.c b/pages.c index e1598f94..d7c91892 100644 --- a/pages.c +++ b/pages.c @@ -735,7 +735,7 @@ void Exchange_main_and_spare(void) void End_of_modification(void) { -/* + Update_visible_page_buffer(1, Main_image_width, Main_image_height); memcpy(Visible_image[1].Image, Visible_image[0].Image, @@ -744,7 +744,7 @@ void End_of_modification(void) Main_screen=Visible_image[0].Image; Download_infos_backup(Main_backups); - +/* Last_backed_up_layers = 0; Backup(); */ From b18266e0174d2ae6466acf1a943ed69883447192 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sat, 26 Sep 2009 17:51:08 +0000 Subject: [PATCH 04/25] [layers] Resizing canvas now works git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1042 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- graph.c | 17 +++++++++++++---- pages.c | 59 ++++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 55 insertions(+), 21 deletions(-) diff --git a/graph.c b/graph.c index debe0fbd..76c38b93 100644 --- a/graph.c +++ b/graph.c @@ -582,6 +582,7 @@ void Resize_image(word chosen_width,word chosen_height) { word old_width=Main_image_width; word old_height=Main_image_height; + int i; // +-+-+ // |C| | A+B+C = Ancienne image @@ -597,10 +598,18 @@ void Resize_image(word chosen_width,word chosen_height) Main_image_is_modified=1; // On copie donc maintenant la partie C dans la nouvelle image. - Copy_part_of_image_to_another( - Screen_backup,0,0,Min(old_width,Main_image_width), - Min(old_height,Main_image_height),old_width, - Main_screen,0,0,Main_image_width); + //Copy_part_of_image_to_another( + // Screen_backup,0,0,Min(old_width,Main_image_width), + // Min(old_height,Main_image_height),old_width, + // Main_screen,0,0,Main_image_width); + for (i=0; iPages->Next->Image[i],0,0,Min(old_width,Main_image_width), + Min(old_height,Main_image_height),old_width, + Main_backups->Pages->Image[i],0,0,Main_image_width); + } + Redraw_layered_image(); } else { diff --git a/pages.c b/pages.c index d7c91892..780b5f3f 100644 --- a/pages.c +++ b/pages.c @@ -56,6 +56,8 @@ T_Page * New_page(void) page->File_directory[0]='\0'; page->Filename[0]='\0'; page->File_format=DEFAULT_FILEFORMAT; + + page->Next = page->Prev = NULL; } return page; } @@ -71,7 +73,6 @@ void Download_infos_page_main(T_Page * page) size_is_modified=(Main_image_width!=page->Width) || (Main_image_height!=page->Height); - Main_screen=Visible_image[0].Image; Main_image_width=page->Width; Main_image_height=page->Height; memcpy(Main_palette,page->Palette,sizeof(T_Palette)); @@ -138,7 +139,6 @@ void Redraw_layered_image(void) } } } - Main_screen=Visible_image[0].Image; Download_infos_backup(Main_backups); } @@ -190,7 +190,6 @@ void Upload_infos_page_spare(T_Page * page) void Download_infos_backup(T_List_of_pages * list) { - Screen_backup=Visible_image[1].Image; //list->Pages->Next->Image[Main_current_layer]; if (Config.FX_Feedback) @@ -369,7 +368,7 @@ int Create_new_page(T_Page * new_page,T_List_of_pages * list) // cas, il faut libérer une page. // Détruire la dernière page allouée dans la Liste_à_raboter - Free_last_page_of_list(list); + Free_last_page_of_list(list); } { int i; @@ -427,9 +426,18 @@ int Update_visible_page_buffer(int index, int width, int height) return 1; } -void Advance_visible_page_buffer() +int Update_depth_buffer(int width, int height) { - + if (Visible_image_depth_buffer.Width != width || Visible_image_depth_buffer.Height != height) + { + Visible_image_depth_buffer.Width = width; + Visible_image_depth_buffer.Height = height; + free(Visible_image_depth_buffer.Image); + Visible_image_depth_buffer.Image = (byte *)malloc(width * height); + if (Visible_image_depth_buffer.Image == NULL) + return 0; + } + return 1; } /// @@ -459,11 +467,12 @@ int Init_all_backup_lists(int width,int height) if (!Update_visible_page_buffer(0, width, height)) return 0; - if (!Update_visible_page_buffer(1, width, height)) - return 0; - Main_screen=Visible_image[0].Image; + if (!Update_visible_page_buffer(1, width, height)) + return 0; + Screen_backup=Visible_image[1].Image; + Download_infos_page_main(Main_backups->Pages); Download_infos_backup(Main_backups); @@ -522,6 +531,7 @@ int Backup_with_new_dimensions(int upload,int width,int height) T_Page * new_page; int return_code=0; + int i; if (upload) // On remet à jour l'état des infos de la page courante (pour pouvoir les @@ -535,21 +545,36 @@ int Backup_with_new_dimensions(int upload,int width,int height) Error(0); return 0; } - + //Copy_S_page(new_page,Main_backups->Pages); Upload_infos_page_main(new_page); new_page->Width=width; new_page->Height=height; if (Create_new_page(new_page,Main_backups)) { - Download_infos_page_main(new_page); + for (i=0; iPages->Image[i]=(byte *)malloc(width*height); + memset(Main_backups->Pages->Image[i], 0, width*height); + } + Update_depth_buffer(width, height); + + Update_visible_page_buffer(0, width, height); + Main_screen=Visible_image[0].Image; + + Update_visible_page_buffer(1, width, height); + Screen_backup=Visible_image[1].Image; + + + Download_infos_page_main(Main_backups->Pages); Download_infos_backup(Main_backups); // On nettoie la nouvelle image: - memset(Main_screen,0,Main_image_width*Main_image_height); + //memset(Main_screen,0,width*height); + return_code=1; } // On détruit le descripteur de la page courante - free(new_page); + //free(new_page); return return_code; } @@ -728,21 +753,21 @@ void Exchange_main_and_spare(void) Main_image_height=Main_backups->Pages->Height; Download_infos_page_main(Main_backups->Pages); - Download_infos_page_spare(Spare_backups->Pages); Download_infos_backup(Main_backups); + Download_infos_page_spare(Spare_backups->Pages); Redraw_layered_image(); } void End_of_modification(void) { - Update_visible_page_buffer(1, Main_image_width, Main_image_height); + //Update_visible_page_buffer(1, Main_image_width, Main_image_height); + + memcpy(Visible_image[1].Image, Visible_image[0].Image, Main_image_width*Main_image_height); - Main_screen=Visible_image[0].Image; - Download_infos_backup(Main_backups); /* Last_backed_up_layers = 0; From b534cfd7d40550ad460139aa3a0c2858dfa56c7b Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sat, 26 Sep 2009 18:01:25 +0000 Subject: [PATCH 05/25] [layers] Picture effects now work git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1043 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- graph.c | 4 ---- transform.c | 52 +++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/graph.c b/graph.c index 76c38b93..abe2fbb8 100644 --- a/graph.c +++ b/graph.c @@ -598,10 +598,6 @@ void Resize_image(word chosen_width,word chosen_height) Main_image_is_modified=1; // On copie donc maintenant la partie C dans la nouvelle image. - //Copy_part_of_image_to_another( - // Screen_backup,0,0,Min(old_width,Main_image_width), - // Min(old_height,Main_image_height),old_width, - // Main_screen,0,0,Main_image_width); for (i=0; iPages->Image[i],Main_backups->Pages->Next->Image[i],Main_image_width*Main_image_height); + Flip_X_lowlevel(Main_backups->Pages->Image[i], Main_image_width, Main_image_height); + } break; case 3 : // Flip Y - memcpy(Main_screen,Screen_backup,Main_image_width*Main_image_height); - Flip_Y_lowlevel(Main_screen, Main_image_width, Main_image_height); + for (i=0; iPages->Image[i],Main_backups->Pages->Next->Image[i],Main_image_width*Main_image_height); + Flip_Y_lowlevel(Main_backups->Pages->Image[i], Main_image_width, Main_image_height); + } break; case 4 : // -90° Rotation - Rotate_270_deg_lowlevel(Screen_backup, Main_screen, old_width, old_height); + for (i=0; iPages->Next->Image[i], Main_backups->Pages->Image[i], old_width, old_height); + } break; case 5 : // +90° Rotation - Rotate_90_deg_lowlevel(Screen_backup, Main_screen, old_width, old_height); + for (i=0; iPages->Next->Image[i], Main_backups->Pages->Image[i], old_width, old_height); + } break; case 6 : // 180° Rotation - memcpy(Main_screen,Screen_backup,Main_image_width*Main_image_height); - Rotate_180_deg_lowlevel(Main_screen, Main_image_width, Main_image_height); + for (i=0; iPages->Image[i],Main_backups->Pages->Next->Image[i],Main_image_width*Main_image_height); + Rotate_180_deg_lowlevel(Main_backups->Pages->Image[i], Main_image_width, Main_image_height); + } break; case 7 : // Resize - Rescale(Screen_backup, old_width, old_height, Main_screen, Main_image_width, Main_image_height, 0, 0); - break; + for (i=0; iPages->Next->Image[i], old_width, old_height, Main_backups->Pages->Image[i], Main_image_width, Main_image_height, 0, 0); + } + break; } - Display_all_screen(); + /* + for (i=0; iPages->Next->Image[i],0,0,Min(old_width,Main_image_width), + Min(old_height,Main_image_height),old_width, + Main_backups->Pages->Image[i],0,0,Main_image_width); + } + */ + Redraw_layered_image(); + Display_all_screen(); } else { From 057d5e76e472d58971ec50600e99fc5fafa482bf Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Mon, 28 Sep 2009 18:48:05 +0000 Subject: [PATCH 06/25] [layers] working swap between main/spare, and loading files in command-line. Start of work on variable layers number and layer sharing. git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1044 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- gfx2.cfg | Bin 10217 -> 10217 bytes graph.c | 2 +- main.c | 12 --- operatio.c | 2 +- pages.c | 212 +++++++++++++++++++++++++++++++--------------------- pages.h | 2 +- struct.h | 7 +- transform.c | 12 +-- 8 files changed, 139 insertions(+), 110 deletions(-) diff --git a/gfx2.cfg b/gfx2.cfg index f250eb60b2892a7c49503e69173057dcdbed9dcd..0b52ae553dd4b152cdcd8a46b80d3f2eb9b378f6 100644 GIT binary patch delta 14 VcmaFq|I&X07ZYQ`W^Sf?ssJuS1yKM1 delta 14 VcmaFq|I&X07Zc;A&D>1)Q~@wA1)~4} diff --git a/graph.c b/graph.c index abe2fbb8..bbb347af 100644 --- a/graph.c +++ b/graph.c @@ -598,7 +598,7 @@ void Resize_image(word chosen_width,word chosen_height) Main_image_is_modified=1; // On copie donc maintenant la partie C dans la nouvelle image. - for (i=0; iPages->Nb_layers; i++) { Copy_part_of_image_to_another( Main_backups->Pages->Next->Image[i],0,0,Min(old_width,Main_image_width), diff --git a/main.c b/main.c index 8e8bebfb..9866aa98 100644 --- a/main.c +++ b/main.c @@ -635,18 +635,6 @@ int Init_program(int argc,char * argv[]) // Allocation de mémoire pour les différents écrans virtuels (et brosse) if (Init_all_backup_lists(Screen_width,Screen_height)==0) Error(ERROR_MEMORY); - // On remet le nom par défaut pour la page de brouillon car il été modifié - // par le passage d'un fichier en paramètre lors du traitement précédent. - // Note: le fait que l'on ne modifie que les variables globales - // Brouillon_* et pas les infos contenues dans la page de brouillon - // elle-même ne m'inspire pas confiance mais ça a l'air de marcher sans - // poser de problèmes, alors... - if (File_in_command_line) - { - strcpy(Spare_file_directory,Spare_current_directory); - strcpy(Spare_filename,"NO_NAME.GIF"); - Spare_fileformat=DEFAULT_FILEFORMAT; - } // Nettoyage de l'écran virtuel (les autres recevront celui-ci par copie) memset(Main_screen,0,Main_image_width*Main_image_height); diff --git a/operatio.c b/operatio.c index 35308969..e21d0ae6 100644 --- a/operatio.c +++ b/operatio.c @@ -4026,7 +4026,7 @@ void Scroll_0_5(void) // Do the actual scroll operation on all layers. - for (i=0; iPages->Nb_layers; i++) Scroll_picture(Main_backups->Pages->Next->Image[i], Main_backups->Pages->Image[i], x_offset, y_offset); } else diff --git a/pages.c b/pages.c index 780b5f3f..0792371d 100644 --- a/pages.c +++ b/pages.c @@ -39,15 +39,15 @@ static word Last_backed_up_layers=0; /// Allocate and initialize a new page. -T_Page * New_page(void) +T_Page * New_page(byte nb_layers) { T_Page * page; - page = (T_Page *)malloc(sizeof(T_Page)); + page = (T_Page *)malloc(sizeof(T_Page)+NB_LAYERS*sizeof(byte *)); if (page!=NULL) { int i; - for (i=0; iImage[i]=NULL; page->Width=0; page->Height=0; @@ -56,12 +56,26 @@ T_Page * New_page(void) page->File_directory[0]='\0'; page->Filename[0]='\0'; page->File_format=DEFAULT_FILEFORMAT; - + page->Nb_layers=nb_layers; page->Next = page->Prev = NULL; } return page; } +byte * New_layer(long pixel_size) +{ + return (byte *)(malloc(pixel_size)); +} +void Free_layer(byte * layer) +{ + free(layer); +} + +byte * Dup_layer(byte * layer) +{ + return layer; +} + void Download_infos_page_main(T_Page * page) // Affiche la page à l'écran { @@ -102,7 +116,7 @@ void Redraw_layered_image(void) // Re-construct the image with the visible layers int layer; // First layer - for (layer=0; layerPages->Nb_layers; layer++) { if ((1<Pages->Nb_layers; layer++) { if ((1<Image[Spare_current_layer]; + //Spare_screen=page->Image[Spare_current_layer]; Spare_image_width=page->Width; Spare_image_height=page->Height; memcpy(Spare_palette,page->Palette,sizeof(T_Palette)); @@ -177,7 +191,7 @@ void Upload_infos_page_spare(T_Page * page) { if (page!=NULL) { - page->Image[Spare_current_layer]=Spare_screen; + //page->Image[Spare_current_layer]=Spare_screen; page->Width=Spare_image_width; page->Height=Spare_image_height; memcpy(page->Palette,Spare_palette,sizeof(T_Palette)); @@ -204,9 +218,9 @@ void Clear_page(T_Page * page) { // On peut appeler cette fonction sur une page non allouée. int i; - for (i=0; iNb_layers; i++) { - free(page->Image[i]); + Free_layer(page->Image[i]); page->Image[i]=NULL; } page->Width=0; @@ -240,7 +254,7 @@ int Allocate_list_of_pages(T_List_of_pages * list) T_Page * page; // On initialise chacune des nouvelles pages - page=New_page(); + page=New_page(NB_LAYERS); if (!page) return 0; @@ -372,8 +386,8 @@ int Create_new_page(T_Page * new_page,T_List_of_pages * list) } { int i; - for (i=0; iImage[i]=(byte *)malloc(new_page->Height*new_page->Width); + for (i=0; iNb_layers; i++) + new_page->Image[i]=New_layer(new_page->Height*new_page->Width); } @@ -449,69 +463,84 @@ int Init_all_backup_lists(int width,int height) // width et height correspondent à la dimension des images de départ. int i; - if (Allocate_list_of_pages(Main_backups) && - Allocate_list_of_pages(Spare_backups)) + if (! Allocate_list_of_pages(Main_backups) || + ! Allocate_list_of_pages(Spare_backups)) + return 0; + // On a réussi à allouer deux listes de pages dont la taille correspond à + // celle demandée par l'utilisateur. + + // On crée un descripteur de page correspondant à la page principale + Upload_infos_page_main(Main_backups->Pages); + // On y met les infos sur la dimension de démarrage + Main_backups->Pages->Width=width; + Main_backups->Pages->Height=height; + for (i=0; iPages->Nb_layers; i++) { - // On a réussi à allouer deux listes de pages dont la taille correspond à - // celle demandée par l'utilisateur. - - // On crée un descripteur de page correspondant à la page principale - Upload_infos_page_main(Main_backups->Pages); - // On y met les infos sur la dimension de démarrage - Main_backups->Pages->Width=width; - Main_backups->Pages->Height=height; - for (i=0; iPages->Image[i]=(byte *)malloc(width*height); - } - - if (!Update_visible_page_buffer(0, width, height)) + Main_backups->Pages->Image[i]=New_layer(width*height); + if (! Main_backups->Pages->Image[i]) return 0; - Main_screen=Visible_image[0].Image; - - if (!Update_visible_page_buffer(1, width, height)) - return 0; - Screen_backup=Visible_image[1].Image; - - Download_infos_page_main(Main_backups->Pages); - Download_infos_backup(Main_backups); - - // Maintenant, on regarde si on a le droit de créer la même page dans - // la page de brouillon. - Download_infos_page_spare(Spare_backups->Pages); - - // Et on efface les 2 images en les remplacant de "0" - memset(Main_screen,0,Main_image_width*Main_image_height); - memset(Spare_screen,0,Spare_image_width*Spare_image_height); - - Visible_image[0].Width = width; - Visible_image[0].Height = height; - Visible_image[0].Image = NULL; - - Visible_image[1].Width = width; - Visible_image[1].Height = height; - Visible_image[1].Image = NULL; - - Visible_image_depth_buffer.Width = width; - Visible_image_depth_buffer.Height = height; - Visible_image_depth_buffer.Image = NULL; - - Visible_image[0].Image = (byte *)malloc(Visible_image[0].Width * Visible_image[0].Height); - if (Visible_image[0].Image) - { - Visible_image[1].Image = (byte *)malloc(Visible_image[1].Width * Visible_image[1].Height); - if (Visible_image[1].Image) - { - Visible_image_depth_buffer.Image = (byte *)malloc(Visible_image_depth_buffer.Width * Visible_image_depth_buffer.Height); - if (Visible_image_depth_buffer.Image) - { - End_of_modification(); - return 1; - } - } - } } - return 0; + + if (!Update_visible_page_buffer(0, width, height)) + return 0; + Main_screen=Visible_image[0].Image; + + if (!Update_visible_page_buffer(1, width, height)) + return 0; + Screen_backup=Visible_image[1].Image; + + Download_infos_page_main(Main_backups->Pages); + Download_infos_backup(Main_backups); + + // Default values for spare page + Spare_backups->Pages->Width = width; + Spare_backups->Pages->Height = height; + memcpy(Spare_backups->Pages->Palette,Main_palette,sizeof(T_Palette)); + strcpy(Spare_backups->Pages->Comment,""); + strcpy(Spare_backups->Pages->File_directory,Spare_current_directory); + strcpy(Spare_backups->Pages->Filename,"NO_NAME.GIF"); + Spare_backups->Pages->File_format=DEFAULT_FILEFORMAT; + // Copy this informations in the global Spare_ variables + Download_infos_page_spare(Spare_backups->Pages); + + // Clear the initial Visible buffer + //memset(Main_screen,0,Main_image_width*Main_image_height); + + // Spare + for (i=0; iPages->Image[i]=New_layer(width*height); + if (! Spare_backups->Pages->Image[i]) + return 0; + } + //memset(Spare_screen,0,Spare_image_width*Spare_image_height); + + Visible_image[0].Width = width; + Visible_image[0].Height = height; + Visible_image[0].Image = NULL; + + Visible_image[1].Width = width; + Visible_image[1].Height = height; + Visible_image[1].Image = NULL; + + Visible_image_depth_buffer.Width = width; + Visible_image_depth_buffer.Height = height; + Visible_image_depth_buffer.Image = NULL; + + Visible_image[0].Image = (byte *)malloc(Visible_image[0].Width * Visible_image[0].Height); + if (! Visible_image[0].Image) + return 0; + + Visible_image[1].Image = (byte *)malloc(Visible_image[1].Width * Visible_image[1].Height); + if (! Visible_image[1].Image) + return 0; + + Visible_image_depth_buffer.Image = (byte *)malloc(Visible_image_depth_buffer.Width * Visible_image_depth_buffer.Height); + if (! Visible_image_depth_buffer.Image) + return 0; + + End_of_modification(); + return 1; } void Set_number_of_backups(int nb_backups) @@ -530,6 +559,7 @@ int Backup_with_new_dimensions(int upload,int width,int height) // 0 sinon. T_Page * new_page; + byte nb_layers; int return_code=0; int i; @@ -538,8 +568,9 @@ int Backup_with_new_dimensions(int upload,int width,int height) // retrouver plus tard) Upload_infos_page_main(Main_backups->Pages); + nb_layers=Main_backups->Pages->Nb_layers; // On crée un descripteur pour la nouvelle page courante - new_page=New_page(); + new_page=New_page(nb_layers); if (!new_page) { Error(0); @@ -551,7 +582,7 @@ int Backup_with_new_dimensions(int upload,int width,int height) new_page->Height=height; if (Create_new_page(new_page,Main_backups)) { - for (i=0; iPages->Image[i]=(byte *)malloc(width*height); memset(Main_backups->Pages->Image[i], 0, width*height); @@ -592,7 +623,7 @@ int Backup_and_resize_the_spare(int width,int height) Upload_infos_page_spare(Spare_backups->Pages); // On crée un descripteur pour la nouvelle page de brouillon - new_page=New_page(); + new_page=New_page(Spare_backups->Pages->Nb_layers); if (!new_page) { Error(0); @@ -632,7 +663,7 @@ void Backup(void) Upload_infos_page_main(Main_backups->Pages); // On crée un descripteur pour la nouvelle page courante - new_page=New_page(); + new_page=New_page(Main_backups->Pages->Nb_layers); if (!new_page) { Error(0); @@ -647,7 +678,7 @@ void Backup(void) Download_infos_backup(Main_backups); // On copie l'image du backup vers la page courante: - for (i=0; iPages->Nb_layers;i++) memcpy(Main_backups->Pages->Image[i], Main_backups->Pages->Next->Image[i], Main_image_width*Main_image_height); @@ -743,14 +774,23 @@ void Exchange_main_and_spare(void) // On extrait ensuite les infos sur les nouvelles pages courante, brouillon // et backup. - /* SECTION GROS CACA PROUT PROUT */ - // Auparavant on ruse en mettant déjà à jour les dimensions de la - // nouvelle page courante. Si on ne le fait pas, le "Download" va détecter - // un changement de dimensions et va bêtement sortir du mode loupe, alors - // que lors d'un changement de page, on veut bien conserver l'état du mode - // loupe du brouillon. - Main_image_width=Main_backups->Pages->Width; - Main_image_height=Main_backups->Pages->Height; + Update_depth_buffer(Main_backups->Pages->Width, Main_backups->Pages->Height); + + Update_visible_page_buffer(0, Main_backups->Pages->Width, Main_backups->Pages->Height); + Main_screen=Visible_image[0].Image; + + Update_visible_page_buffer(1, Main_backups->Pages->Width, Main_backups->Pages->Height); + Screen_backup=Visible_image[1].Image; + + + /* SECTION GROS CACA PROUT PROUT */ + // Auparavant on ruse en mettant déjà à jour les dimensions de la + // nouvelle page courante. Si on ne le fait pas, le "Download" va détecter + // un changement de dimensions et va bêtement sortir du mode loupe, alors + // que lors d'un changement de page, on veut bien conserver l'état du mode + // loupe du brouillon. + Main_image_width=Main_backups->Pages->Width; + Main_image_height=Main_backups->Pages->Height; Download_infos_page_main(Main_backups->Pages); Download_infos_backup(Main_backups); diff --git a/pages.h b/pages.h index e715d2e9..18fdaba0 100644 --- a/pages.h +++ b/pages.h @@ -39,7 +39,7 @@ void Download_infos_page_main(T_Page * page); void Upload_infos_page_main(T_Page * page); // private -T_Page * New_page(void); +T_Page * New_page(byte nb_layers); void Download_infos_page_spare(T_Page * page); void Upload_infos_page_spare(T_Page * page); void Download_infos_backup(T_List_of_pages * list); diff --git a/struct.h b/struct.h index 4b62483f..2b245943 100644 --- a/struct.h +++ b/struct.h @@ -330,9 +330,10 @@ typedef struct T_Page char File_directory[MAX_PATH_CHARACTERS];///< Directory that contains the file. char Filename[MAX_PATH_CHARACTERS]; ///< Filename without directory. byte File_format; ///< File format, in enum ::FILE_FORMATS - struct T_Page *Next; - struct T_Page *Prev; - byte * Image[NB_LAYERS];///< Pixel data for the image. + struct T_Page *Next; ///< Pointer to the next backup + struct T_Page *Prev; ///< Pointer to the previous backup + byte Nb_layers; ///< Number of layers + byte * Image[0]; ///< Pixel data for the image. } T_Page; /// Collection of undo/redo steps. diff --git a/transform.c b/transform.c index ccf2ffe3..dd714391 100644 --- a/transform.c +++ b/transform.c @@ -380,40 +380,40 @@ void Button_Transform_menu(void) int i; case 2 : // Flip X - for (i=0; iPages->Nb_layers; i++) { memcpy(Main_backups->Pages->Image[i],Main_backups->Pages->Next->Image[i],Main_image_width*Main_image_height); Flip_X_lowlevel(Main_backups->Pages->Image[i], Main_image_width, Main_image_height); } break; case 3 : // Flip Y - for (i=0; iPages->Nb_layers; i++) { memcpy(Main_backups->Pages->Image[i],Main_backups->Pages->Next->Image[i],Main_image_width*Main_image_height); Flip_Y_lowlevel(Main_backups->Pages->Image[i], Main_image_width, Main_image_height); } break; case 4 : // -90° Rotation - for (i=0; iPages->Nb_layers; i++) { Rotate_270_deg_lowlevel(Main_backups->Pages->Next->Image[i], Main_backups->Pages->Image[i], old_width, old_height); } break; case 5 : // +90° Rotation - for (i=0; iPages->Nb_layers; i++) { Rotate_90_deg_lowlevel(Main_backups->Pages->Next->Image[i], Main_backups->Pages->Image[i], old_width, old_height); } break; case 6 : // 180° Rotation - for (i=0; iPages->Nb_layers; i++) { memcpy(Main_backups->Pages->Image[i],Main_backups->Pages->Next->Image[i],Main_image_width*Main_image_height); Rotate_180_deg_lowlevel(Main_backups->Pages->Image[i], Main_image_width, Main_image_height); } break; case 7 : // Resize - for (i=0; iPages->Nb_layers; i++) { Rescale(Main_backups->Pages->Next->Image[i], old_width, old_height, Main_backups->Pages->Image[i], Main_image_width, Main_image_height, 0, 0); } From 2fd88b81bb1bf74ac7407915830e35343019ddde Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Mon, 28 Sep 2009 21:01:29 +0000 Subject: [PATCH 07/25] [layers] work on layer sharing (still stable) git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1045 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 2 ++ graph.c | 3 ++- misc.c | 10 +++++----- operatio.c | 5 ++++- pages.c | 7 ++++++- pages.h | 3 +++ palette.c | 14 +++++++------- pversion.c | 2 +- 8 files changed, 30 insertions(+), 16 deletions(-) diff --git a/buttons.c b/buttons.c index 1c513a99..41c757ec 100644 --- a/buttons.c +++ b/buttons.c @@ -507,6 +507,7 @@ void Button_Clear(void) Hide_current_image_with_stencil(0,Stencil); else Hide_current_image(0); + Redraw_layered_image(); Display_all_screen(); End_of_modification(); Unselect_button(BUTTON_CLEAR); @@ -521,6 +522,7 @@ void Button_Clear_with_backcolor(void) Hide_current_image_with_stencil(Back_color,Stencil); else Hide_current_image(Back_color); + Redraw_layered_image(); Display_all_screen(); End_of_modification(); Unselect_button(BUTTON_CLEAR); diff --git a/graph.c b/graph.c index bbb347af..d056b178 100644 --- a/graph.c +++ b/graph.c @@ -662,7 +662,8 @@ void Get_colors_from_brush(void) if (Confirmation_box("Modify current palette ?")) { - Backup(); + // Backup with unchanged layers, only palette is modified + Backup_layers(0); // On commence par initialiser le tableau de booléen à faux for (color=0;color<=255;color++) diff --git a/misc.c b/misc.c index b6434bac..473fe562 100644 --- a/misc.c +++ b/misc.c @@ -175,16 +175,16 @@ void Hide_current_image_with_stencil(byte color, byte * stencil) int nb_pixels=0; //ECX //al=color //edi=Screen_pixels - byte* Pixel_Courant=Screen_pixels; //dl + byte* pixel=Main_backups->Pages->Image[Main_current_layer]; int i; nb_pixels=Main_image_height*Main_image_width; for(i=0;iPages->Image[Main_current_layer], color , Main_image_width * Main_image_height ); diff --git a/operatio.c b/operatio.c index e21d0ae6..83ed306a 100644 --- a/operatio.c +++ b/operatio.c @@ -3909,12 +3909,15 @@ void Scroll_12_0(void) // { Init_start_operation(); - Backup(); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Mouse_K); // LEFT_SIDE or RIGHT_SIDE + if (Mouse_K == LEFT_SIDE) + Backup(); + else + Backup_layers(Main_layers_visible); Cursor_hidden_before_scroll=Cursor_hidden; Cursor_hidden=1; diff --git a/pages.c b/pages.c index 0792371d..633c84f9 100644 --- a/pages.c +++ b/pages.c @@ -649,7 +649,12 @@ void Backup(void) // Sauve la page courante comme première page de backup et crée une nouvelle page // pur continuer à dessiner. Utilisé par exemple pour le fill { - int i; + Backup_layers(1< Date: Mon, 28 Sep 2009 22:00:04 +0000 Subject: [PATCH 08/25] [layers] Implemented shared layers. Speeds up Backup() by 800. Little unrelated bug: On program start, use 'tab' at least once, or the undo buffers won't be updated on screen. git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1046 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- pages.c | 71 +++++++++++++++++++++++++++++++++++++++++++++------------ pages.h | 2 +- 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/pages.c b/pages.c index 633c84f9..9f2bbf1d 100644 --- a/pages.c +++ b/pages.c @@ -62,20 +62,55 @@ T_Page * New_page(byte nb_layers) return page; } +// ============================================================== +// Layers allocation functions. +// +// Layers are made of a "number of users" (short), followed by +// the actual pixel data (a large number of bytes). +// Every time a layer is 'duplicated' as a reference, the number +// of users is incremented. +// Every time a layer is freed, the number of users is decreased, +// and only when it reaches zero the pixel data is freed. +// ============================================================== + +/// Allocate a new layer byte * New_layer(long pixel_size) { - return (byte *)(malloc(pixel_size)); -} -void Free_layer(byte * layer) -{ - free(layer); + short * ptr = malloc(sizeof(short)+pixel_size); + if (ptr==NULL) + return NULL; + + *ptr = 1; + return (byte *)(ptr+1); } +/// Free a layer +void Free_layer(byte * layer) +{ + short * ptr = (short *)(layer); + if (layer==NULL) + return; + + if (-- (*(ptr-1))) // Users-- + return; + else + free(ptr-1); +} + +/// Duplicate a layer (new reference) byte * Dup_layer(byte * layer) { + short * ptr = (short *)(layer); + + if (layer==NULL) + return NULL; + + (*(ptr-1)) ++; // Users ++ return layer; } +// ============================================================== + void Download_infos_page_main(T_Page * page) // Affiche la page à l'écran { @@ -367,7 +402,8 @@ void Free_last_page_of_list(T_List_of_pages * list) } } -int Create_new_page(T_Page * new_page,T_List_of_pages * list) +// layer_mask tells which layers have to be fresh copies instead of references +int Create_new_page(T_Page * new_page,T_List_of_pages * list, byte layer_mask) { // Cette fonction crée une nouvelle page dont les attributs correspondent à @@ -387,7 +423,12 @@ int Create_new_page(T_Page * new_page,T_List_of_pages * list) { int i; for (i=0; iNb_layers; i++) - new_page->Image[i]=New_layer(new_page->Height*new_page->Width); + { + if ((1<Image[i]=New_layer(new_page->Height*new_page->Width); + else + new_page->Image[i]=Dup_layer(list->Pages->Image[i]); + } } @@ -580,7 +621,7 @@ int Backup_with_new_dimensions(int upload,int width,int height) Upload_infos_page_main(new_page); new_page->Width=width; new_page->Height=height; - if (Create_new_page(new_page,Main_backups)) + if (Create_new_page(new_page,Main_backups,0)) { for (i=0; iWidth=width; new_page->Height=height; - if (Create_new_page(new_page,Spare_backups)) + if (Create_new_page(new_page,Spare_backups,0)) { Download_infos_page_spare(new_page); return_code=1; @@ -677,17 +718,19 @@ void Backup_layers(byte layer_mask) // Enrichissement de l'historique Copy_S_page(new_page,Main_backups->Pages); - Create_new_page(new_page,Main_backups); + Create_new_page(new_page,Main_backups,layer_mask); Download_infos_page_main(new_page); Download_infos_backup(Main_backups); // On copie l'image du backup vers la page courante: for (i=0; iPages->Nb_layers;i++) - memcpy(Main_backups->Pages->Image[i], - Main_backups->Pages->Next->Image[i], - Main_image_width*Main_image_height); - + { + if ((1<Pages->Image[i], + Main_backups->Pages->Next->Image[i], + Main_image_width*Main_image_height); + } // On allume l'indicateur de modification de l'image Main_image_is_modified=1; diff --git a/pages.h b/pages.h index ae16e47e..461c124e 100644 --- a/pages.h +++ b/pages.h @@ -58,7 +58,7 @@ int Allocate_list_of_pages(T_List_of_pages * list); void Backward_in_list_of_pages(T_List_of_pages * list); void Advance_in_list_of_pages(T_List_of_pages * list); void Free_last_page_of_list(T_List_of_pages * list); -int Create_new_page(T_Page * new_page,T_List_of_pages * current_list); +int Create_new_page(T_Page * new_page,T_List_of_pages * current_list, byte layer_mask); void Change_page_number_of_list(T_List_of_pages * list,int number); void Free_page_of_a_list(T_List_of_pages * list); From 61f0a4ec717f33e0121f1212703fed11d1e440f9 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Tue, 29 Sep 2009 17:57:43 +0000 Subject: [PATCH 09/25] [layers] Sped up the scrolling/adjusting of single layers. Speed is no longer relative to the number of visible layers. Pulkomandy, your idea of depth buffer was genius. git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1047 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- operatio.c | 3 ++- pages.c | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/operatio.c b/operatio.c index 83ed306a..332672c7 100644 --- a/operatio.c +++ b/operatio.c @@ -3975,7 +3975,8 @@ void Scroll_12_5(void) { // One layer at once Scroll_picture(Main_backups->Pages->Next->Image[Main_current_layer], Main_backups->Pages->Image[Main_current_layer], x_offset, y_offset); - Redraw_layered_image(); + //Redraw_layered_image(); + Redraw_current_layer(); } Display_all_screen(); diff --git a/pages.c b/pages.c index 9f2bbf1d..75107cc5 100644 --- a/pages.c +++ b/pages.c @@ -191,6 +191,27 @@ void Redraw_layered_image(void) Download_infos_backup(Main_backups); } +void Redraw_current_layer(void) +{ + int i; + for (i=0; iPages->Image[Main_current_layer]+i); + if (color != 0) /* transp color */ + { + *(Visible_image[0].Image+i) = color; + } + else + { + *(Visible_image[0].Image+i) = *(Main_backups->Pages->Image[depth]+i); + } + } + } +} + void Upload_infos_page_main(T_Page * page) // Sauve l'écran courant dans la page { From 20b1aef7f5f2a640b37444db3b51ed1b92e52d88 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Tue, 29 Sep 2009 18:49:00 +0000 Subject: [PATCH 10/25] [layers] cleanup git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1048 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- pages.c | 97 +++++++++++++++++++++++---------------------------------- 1 file changed, 39 insertions(+), 58 deletions(-) diff --git a/pages.c b/pages.c index 75107cc5..4a0e0b76 100644 --- a/pages.c +++ b/pages.c @@ -141,7 +141,7 @@ void Download_infos_page_main(T_Page * page) } } - //Update_visible_page_buffer(Visible_image_index, page->Width, page->Height); + //Update_buffers( page->Width, page->Height); //memcpy(Main_screen, page->Image[Main_current_layer], page->Width*page->Height); } @@ -488,31 +488,40 @@ void Free_page_of_a_list(T_List_of_pages * list) } } -int Update_visible_page_buffer(int index, int width, int height) +/// Resize one of the special bitmap buffers, if necessary. +int Update_buffer(T_Image * image, int width, int height) { - if (Visible_image[index].Width != width || Visible_image[index].Height != height) + // At least one dimension is different + if (image->Width != width || image->Height != height) { - Visible_image[index].Width = width; - Visible_image[index].Height = height; - free(Visible_image[index].Image); - Visible_image[index].Image = (byte *)malloc(width * height); - if (Visible_image[index].Image == NULL) - return 0; + // Actual size difference + if (image->Width * image->Height != width * height) + { + free(image->Image); + image->Image = (byte *)malloc(width * height); + if (image->Image == NULL) + return 0; + } + image->Width = width; + image->Height = height; } return 1; } -int Update_depth_buffer(int width, int height) +/// Update all the special image buffers, if necessary. +int Update_buffers(int width, int height) { - if (Visible_image_depth_buffer.Width != width || Visible_image_depth_buffer.Height != height) - { - Visible_image_depth_buffer.Width = width; - Visible_image_depth_buffer.Height = height; - free(Visible_image_depth_buffer.Image); - Visible_image_depth_buffer.Image = (byte *)malloc(width * height); - if (Visible_image_depth_buffer.Image == NULL) - return 0; - } + if (! Update_buffer(&Visible_image_depth_buffer, width, height)) + return 0; + + if (! Update_buffer(&Visible_image[0], width, height)) + return 0; + Main_screen=Visible_image[0].Image; + + if (! Update_buffer(&Visible_image[1], width, height)) + return 0; + Screen_backup=Visible_image[1].Image; + return 1; } @@ -543,13 +552,8 @@ int Init_all_backup_lists(int width,int height) return 0; } - if (!Update_visible_page_buffer(0, width, height)) + if (!Update_buffers(width, height)) return 0; - Main_screen=Visible_image[0].Image; - - if (!Update_visible_page_buffer(1, width, height)) - return 0; - Screen_backup=Visible_image[1].Image; Download_infos_page_main(Main_backups->Pages); Download_infos_backup(Main_backups); @@ -577,29 +581,19 @@ int Init_all_backup_lists(int width,int height) } //memset(Spare_screen,0,Spare_image_width*Spare_image_height); - Visible_image[0].Width = width; - Visible_image[0].Height = height; + Visible_image[0].Width = 0; + Visible_image[0].Height = 0; Visible_image[0].Image = NULL; - Visible_image[1].Width = width; - Visible_image[1].Height = height; + Visible_image[1].Width = 0; + Visible_image[1].Height = 0; Visible_image[1].Image = NULL; - Visible_image_depth_buffer.Width = width; - Visible_image_depth_buffer.Height = height; + Visible_image_depth_buffer.Width = 0; + Visible_image_depth_buffer.Height = 0; Visible_image_depth_buffer.Image = NULL; - Visible_image[0].Image = (byte *)malloc(Visible_image[0].Width * Visible_image[0].Height); - if (! Visible_image[0].Image) - return 0; - - Visible_image[1].Image = (byte *)malloc(Visible_image[1].Width * Visible_image[1].Height); - if (! Visible_image[1].Image) - return 0; - - Visible_image_depth_buffer.Image = (byte *)malloc(Visible_image_depth_buffer.Width * Visible_image_depth_buffer.Height); - if (! Visible_image_depth_buffer.Image) - return 0; + Update_buffers(width, height); End_of_modification(); return 1; @@ -649,14 +643,8 @@ int Backup_with_new_dimensions(int upload,int width,int height) //Main_backups->Pages->Image[i]=(byte *)malloc(width*height); memset(Main_backups->Pages->Image[i], 0, width*height); } - Update_depth_buffer(width, height); - - Update_visible_page_buffer(0, width, height); - Main_screen=Visible_image[0].Image; - Update_visible_page_buffer(1, width, height); - Screen_backup=Visible_image[1].Image; - + Update_buffers(width, height); Download_infos_page_main(Main_backups->Pages); Download_infos_backup(Main_backups); @@ -843,14 +831,7 @@ void Exchange_main_and_spare(void) // On extrait ensuite les infos sur les nouvelles pages courante, brouillon // et backup. - Update_depth_buffer(Main_backups->Pages->Width, Main_backups->Pages->Height); - - Update_visible_page_buffer(0, Main_backups->Pages->Width, Main_backups->Pages->Height); - Main_screen=Visible_image[0].Image; - - Update_visible_page_buffer(1, Main_backups->Pages->Width, Main_backups->Pages->Height); - Screen_backup=Visible_image[1].Image; - + Update_buffers(Main_backups->Pages->Width, Main_backups->Pages->Height); /* SECTION GROS CACA PROUT PROUT */ // Auparavant on ruse en mettant déjà à jour les dimensions de la @@ -870,7 +851,7 @@ void Exchange_main_and_spare(void) void End_of_modification(void) { - //Update_visible_page_buffer(1, Main_image_width, Main_image_height); + //Update_buffers(Main_image_width, Main_image_height); memcpy(Visible_image[1].Image, From 9be9ed9c17333a6b8b03375189249e6342ebd36d Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Wed, 30 Sep 2009 21:37:16 +0000 Subject: [PATCH 11/25] [layers] Sped up the switching from one active layer to another, when the new layer was already displayed (thanks to the depth buffer, again) git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1049 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 12 ++++++++++-- pages.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ pages.h | 4 ++++ 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/buttons.c b/buttons.c index 41c757ec..74edc017 100644 --- a/buttons.c +++ b/buttons.c @@ -2879,6 +2879,7 @@ void Load_picture(byte image) } Compute_optimal_menu_colors(Main_palette); + Redraw_layered_image(); Display_all_screen(); if (image) @@ -2980,7 +2981,7 @@ void Button_Reload(void) Compute_limits(); Compute_paintbrush_coordinates(); } - + Redraw_layered_image(); Display_all_screen(); Main_image_is_modified=0; @@ -4260,6 +4261,10 @@ void Transparency_set(byte amount) void Layer_activate(short layer, short side) { + byte old_layers; + + // Keep a copy of which layers were visible + old_layers = Main_layers_visible; if (side == RIGHT_SIDE) { // Right-click on current layer @@ -4290,7 +4295,10 @@ void Layer_activate(short layer, short side) } Hide_cursor(); - Redraw_layered_image(); + if (Main_layers_visible != old_layers) + Redraw_layered_image(); + else + Update_depth_buffer(); // Only need the depth buffer //Download_infos_page_main(Main_backups->Pages); //Download_infos_backup(Main_backups); Display_all_screen(); diff --git a/pages.c b/pages.c index 4a0e0b76..9a113213 100644 --- a/pages.c +++ b/pages.c @@ -191,6 +191,51 @@ void Redraw_layered_image(void) Download_infos_backup(Main_backups); } +void Update_depth_buffer(void) +{ + // Re-construct the depth buffer with the visible layers. + // This function doesn't touch the visible buffer, it assumes + // that it was already up-to-date. (Ex. user only changed active layer) + + int layer; + // First layer + for (layer=0; layerPages->Nb_layers; layer++) + { + if ((1<Pages->Nb_layers; layer++) + { + // skip the current layer, whenever we reach it + if (layer == Main_current_layer) + continue; + + if ((1<Pages->Image[layer]+i); + if (color != 0) /* transp color */ + { + *(Visible_image_depth_buffer.Image+i) = layer; + } + } + } + } + Download_infos_backup(Main_backups); +} + void Redraw_current_layer(void) { int i; diff --git a/pages.h b/pages.h index 461c124e..ad22e7c6 100644 --- a/pages.h +++ b/pages.h @@ -82,4 +82,8 @@ void Free_current_page(void); // 'Kill' button void Exchange_main_and_spare(void); void End_of_modification(void); +void Update_depth_buffer(void); +void Redraw_layered_image(void); +void Redraw_current_layer(void); + #endif From 56e62c4b4758daff24634dd444aedc8e97a95f30 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Thu, 1 Oct 2009 22:11:26 +0000 Subject: [PATCH 12/25] [layers] Fixed many embarrassing memory overruns and uninitialized memory reads. Woops. git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1050 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- init.c | 4 ++-- pages.c | 44 ++++++++++++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/init.c b/init.c index f0540359..474ec4a0 100644 --- a/init.c +++ b/init.c @@ -1257,7 +1257,7 @@ void Init_operations(void) for (number=0;numberPages->Image[i]=New_layer(width*height); if (! Main_backups->Pages->Image[i]) return 0; + memset(Main_backups->Pages->Image[i], 0, width*height); } + Visible_image[0].Width = 0; + Visible_image[0].Height = 0; + Visible_image[0].Image = NULL; + + Visible_image[1].Width = 0; + Visible_image[1].Height = 0; + Visible_image[1].Image = NULL; + + Visible_image_depth_buffer.Width = 0; + Visible_image_depth_buffer.Height = 0; + Visible_image_depth_buffer.Image = NULL; + if (!Update_buffers(width, height)) return 0; + // For speed, instead of Redraw_layered_image() we'll directly set the buffers. + memset(Visible_image[0].Image, 0, width*height); + memset(Visible_image[1].Image, 0, width*height); + memset(Visible_image_depth_buffer.Image, 0, width*height); Download_infos_page_main(Main_backups->Pages); Download_infos_backup(Main_backups); @@ -623,23 +640,11 @@ int Init_all_backup_lists(int width,int height) Spare_backups->Pages->Image[i]=New_layer(width*height); if (! Spare_backups->Pages->Image[i]) return 0; + memset(Spare_backups->Pages->Image[i], 0, width*height); + } //memset(Spare_screen,0,Spare_image_width*Spare_image_height); - Visible_image[0].Width = 0; - Visible_image[0].Height = 0; - Visible_image[0].Image = NULL; - - Visible_image[1].Width = 0; - Visible_image[1].Height = 0; - Visible_image[1].Image = NULL; - - Visible_image_depth_buffer.Width = 0; - Visible_image_depth_buffer.Height = 0; - Visible_image_depth_buffer.Image = NULL; - - Update_buffers(width, height); - End_of_modification(); return 1; } @@ -681,7 +686,7 @@ int Backup_with_new_dimensions(int upload,int width,int height) Upload_infos_page_main(new_page); new_page->Width=width; new_page->Height=height; - if (Create_new_page(new_page,Main_backups,0)) + if (Create_new_page(new_page,Main_backups,255)) { for (i=0; iWidth=width; new_page->Height=height; - if (Create_new_page(new_page,Spare_backups,0)) + if (Create_new_page(new_page,Spare_backups,255)) { Download_infos_page_spare(new_page); return_code=1; @@ -807,6 +812,8 @@ void Undo(void) // On fait faire un undo à la liste des backups de la page principale Backward_in_list_of_pages(Main_backups); + Update_buffers(Main_backups->Pages->Width, Main_backups->Pages->Height); + // On extrait ensuite les infos sur la nouvelle page courante Download_infos_page_main(Main_backups->Pages); // Et celles du backup @@ -832,6 +839,8 @@ void Redo(void) // On fait faire un redo à la liste des backups de la page principale Advance_in_list_of_pages(Main_backups); + Update_buffers(Main_backups->Pages->Width, Main_backups->Pages->Height); + // On extrait ensuite les infos sur la nouvelle page courante Download_infos_page_main(Main_backups->Pages); // Et celles du backup @@ -848,6 +857,9 @@ void Free_current_page(void) { // On détruit la page courante de la liste principale Free_page_of_a_list(Main_backups); + + Update_buffers(Main_backups->Pages->Width, Main_backups->Pages->Height); + // On extrait ensuite les infos sur la nouvelle page courante Download_infos_page_main(Main_backups->Pages); // Et celles du backup From 416ad0cd783cdbf1e0a4aecec3487b53e7fadeb2 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Thu, 1 Oct 2009 22:23:54 +0000 Subject: [PATCH 13/25] [layers] Added missing screen refresh on 'Kill page' git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1051 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- pages.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pages.c b/pages.c index db82bb40..8e8a3fc1 100644 --- a/pages.c +++ b/pages.c @@ -859,6 +859,7 @@ void Free_current_page(void) Free_page_of_a_list(Main_backups); Update_buffers(Main_backups->Pages->Width, Main_backups->Pages->Height); + Redraw_layered_image(); // On extrait ensuite les infos sur la nouvelle page courante Download_infos_page_main(Main_backups->Pages); @@ -867,7 +868,7 @@ void Free_current_page(void) // Note: le backup n'a pas obligatoirement les mêmes dimensions ni la même // palette que la page courante. Mais en temps normal, le backup // n'est pas utilisé à la suite d'une destruction de page. Donc ça ne - // devrait pas poser de problèmes. + // devrait pas poser de problèmes. } void Exchange_main_and_spare(void) From 874ccd44301daeccbb848d38b7a93f9da44fd957 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sun, 4 Oct 2009 01:25:38 +0000 Subject: [PATCH 14/25] [layers] Fix a bug with scroll. Implemented basic save/load of layers in GIF as non-looping animation. git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1058 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- loadsave.c | 408 +++++++++++++++++++++++++++++------------------------ operatio.c | 4 + 2 files changed, 225 insertions(+), 187 deletions(-) diff --git a/loadsave.c b/loadsave.c index a87643d4..19922f41 100644 --- a/loadsave.c +++ b/loadsave.c @@ -465,6 +465,9 @@ void Init_preview(short width,short height,long size,int format, enum PIXEL_RATI // La nouvelle page a pu être allouée, elle est pour l'instant pleine // de 0s. Elle fait Main_image_width de large. // Normalement tout va bien, tout est sous contrôle... + + // Load into layer 0, by default. + Main_current_layer=0; } else { @@ -3024,11 +3027,6 @@ void Load_GIF(void) /////////////////////////////////////////////////// FIN DES DECLARATIONS // - GIF_pos_X=0; - GIF_pos_Y=0; - GIF_last_byte=0; - GIF_remainder_bits=0; - GIF_remainder_byte=0; number_LID=0; Get_full_filename(filename,0); @@ -3063,11 +3061,6 @@ void Load_GIF(void) // Nombre de bits/pixel = (LSDB.Resol and $07)+1 // Ordre de Classement = (LSDB.Aspect and $80) - alphabet_stack_pos=0; - GIF_last_byte =0; - GIF_remainder_bits =0; - GIF_remainder_byte =0; - nb_colors=(1 << ((LSDB.Resol & 0x07)+1)); initial_nb_bits=(LSDB.Resol & 0x07)+2; @@ -3150,8 +3143,7 @@ void Load_GIF(void) // Si on a deja lu une image, c'est une GIF animée ou bizarroide, on sort. if (number_LID!=0) { - File_error=2; - break; + Main_current_layer++; } number_LID++; @@ -3167,7 +3159,8 @@ void Load_GIF(void) Main_image_width=IDB.Image_width; Main_image_height=IDB.Image_height; - Init_preview(IDB.Image_width,IDB.Image_height,file_size,FORMAT_GIF,PIXEL_SIMPLE); + 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) @@ -3219,6 +3212,13 @@ void Load_GIF(void) //////////////////////////////////////////// DECOMPRESSION LZW // + GIF_pos_X=0; + GIF_pos_Y=0; + alphabet_stack_pos=0; + GIF_last_byte =0; + GIF_remainder_bits =0; + GIF_remainder_byte =0; + while ( (GIF_get_next_code()!=value_eof) && (!File_error) ) { if (GIF_current_code<=alphabet_free) @@ -3404,16 +3404,15 @@ void Save_GIF(void) byte current_char; // Caractère à coder word index; // index de recherche de chaîne + byte old_current_layer=Main_current_layer; /////////////////////////////////////////////////// FIN DES DECLARATIONS // - - GIF_pos_X=0; - GIF_pos_Y=0; - GIF_last_byte=0; - GIF_remainder_bits=0; - GIF_remainder_byte=0; - + if (Read_pixel_function==Read_pixel_from_current_screen) + Read_pixel_function=Read_pixel_from_current_layer; + + File_error=0; + Get_full_filename(filename,0); if ((GIF_file=fopen(filename,"wb"))) @@ -3446,12 +3445,11 @@ void Save_GIF(void) // On sauve le LSDB dans le fichier -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - LSDB.Width = SDL_Swap16(LSDB.Width); - LSDB.Height = SDL_Swap16(LSDB.Height); -#endif - - if (Write_bytes(GIF_file,&LSDB,sizeof(T_GIF_LSDB))) + if (Write_word_le(GIF_file,LSDB.Width) && + Write_word_le(GIF_file,LSDB.Height) && + Write_byte(GIF_file,LSDB.Resol) && + Write_byte(GIF_file,LSDB.Backcol) && + Write_byte(GIF_file,LSDB.Aspect) ) { // Le LSDB a été correctement écrit. @@ -3466,6 +3464,11 @@ void Save_GIF(void) // Ecriture de la transparence //Write_bytes(GIF_file,"\x21\xF9\x04\x01\x00\x00\xNN\x00",8); + // "Netscape" animation extension + // Write_bytes(GIF_file,"\x21\xFF\x0BNETSCAPE2.0\x03\xLL\xSS\xSS\x00",19); + // LL : 01 to loop + // SSSS : number of loops + // Ecriture du commentaire if (Main_comment[0]) { @@ -3473,180 +3476,208 @@ void Save_GIF(void) Write_byte(GIF_file,strlen(Main_comment)); Write_bytes(GIF_file,Main_comment,strlen(Main_comment)+1); } - - - // On va écrire un block indicateur d'IDB et l'IDB du fichier - - block_indentifier=0x2C; - IDB.Pos_X=0; - IDB.Pos_Y=0; - IDB.Image_width=Main_image_width; - IDB.Image_height=Main_image_height; - IDB.Indicator=0x07; // Image non entrelacée, pas de palette locale. - IDB.Nb_bits_pixel=8; // Image 256 couleurs; - -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - IDB.Image_width = SDL_Swap16(IDB.Image_width); - IDB.Image_height = SDL_Swap16(IDB.Image_height); -#endif - - if ( Write_bytes(GIF_file,&block_indentifier,1) && - Write_bytes(GIF_file,&IDB,sizeof(T_GIF_IDB)) ) + // Loop on all layers + for (Main_current_layer=0; + Main_current_layer < Main_backups->Pages->Nb_layers && !File_error; + Main_current_layer++) { - // Le block indicateur d'IDB et l'IDB ont étés correctements - // écrits. - - Init_write_buffer(); - - index=4096; - File_error=0; - GIF_stop=0; - - // Réintialisation de la table: - alphabet_free=258; - GIF_nb_bits =9; - alphabet_max =511; - GIF_set_code(256); - for (start=0;start<4096;start++) + // Write a Graphic Control Extension + char * GCE_block = "\x21\xF9\x04\x05\x05\x00\x00\x00"; + //if (Main_current_layer > 0) + // GCE_block[3] = '\x05'; + if (Main_current_layer == Main_backups->Pages->Nb_layers -1) { - alphabet_daughter[start]=4096; - alphabet_sister[start]=4096; + // "Infinite" delay for last frame + GCE_block[4] = 255; + GCE_block[5] = 255; } - - ////////////////////////////////////////////// COMPRESSION LZW // - - start=current_string=GIF_next_pixel(); - descend=1; - - do + if (Write_bytes(GIF_file,GCE_block,8)) { - current_char=GIF_next_pixel(); - - // On regarde si dans la table on aurait pas une chaîne - // équivalente à current_string+Caractere - - while ( (index0xFFF) + // Le block indicateur d'IDB et l'IDB ont étés correctements + // écrits. + + Init_write_buffer(); + GIF_pos_X=0; + GIF_pos_Y=0; + GIF_last_byte=0; + GIF_remainder_bits=0; + GIF_remainder_byte=0; + + index=4096; + File_error=0; + GIF_stop=0; + + // Réintialisation de la table: + alphabet_free=258; + GIF_nb_bits =9; + alphabet_max =511; + GIF_set_code(256); + for (start=0;start<4096;start++) { - // Réintialisation de la table: - GIF_set_code(256); - alphabet_free=258; - GIF_nb_bits =9; - alphabet_max =511; - for (start=0;start<4096;start++) + alphabet_daughter[start]=4096; + alphabet_sister[start]=4096; + } + + ////////////////////////////////////////////// COMPRESSION LZW // + + start=current_string=GIF_next_pixel(); + descend=1; + + do + { + current_char=GIF_next_pixel(); + + // On regarde si dans la table on aurait pas une chaîne + // équivalente à current_string+Caractere + + while ( (index0xFFF) + { + // Réintialisation de la table: + GIF_set_code(256); + alphabet_free=258; + GIF_nb_bits =9; + alphabet_max =511; + for (start=0;start<4096;start++) + { + alphabet_daughter[start]=4096; + alphabet_sister[start]=4096; + } + } + else if (alphabet_free>alphabet_max+1) + { + // On augmente le nb de bits + + GIF_nb_bits++; + alphabet_max=(1<alphabet_max+1) + while ((!GIF_stop) && (!File_error)); + + if (!File_error) { - // On augmente le nb de bits - - GIF_nb_bits++; - alphabet_max=(1<Pages->Nb_layers; i++) Scroll_picture(Main_backups->Pages->Next->Image[i], Main_backups->Pages->Image[i], x_offset, y_offset); + // Update the depth buffer too ... + // It would be faster to scroll it, but we don't have method + // for in-place scrolling. + Update_depth_buffer(); } else { From 2f1888e50d4908d39bd7ece5fa0a58c7c14887cb Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Tue, 6 Oct 2009 23:28:37 +0000 Subject: [PATCH 15/25] [layers] Implemented 'Copy to spare - pixels'. It replaces the current layer in the spare, resizing the whole spare (all layers) as needed. git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1064 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 24 ++++++++++++++++++++++-- pages.c | 30 +++++++++++++++--------------- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/buttons.c b/buttons.c index 74edc017..b14340cf 100644 --- a/buttons.c +++ b/buttons.c @@ -1382,18 +1382,38 @@ void Button_Page(void) void Copy_image_only(void) { + word old_width=Spare_image_width; + word old_height=Spare_image_height; + if (Backup_and_resize_the_spare(Main_image_width,Main_image_height)) { - // copie de l'image - memcpy(Spare_screen,Main_screen,Main_image_width*Main_image_height); + byte i; + for (i=0; iPages->Nb_layers; i++) + { + if (i == Spare_current_layer) + { + // Copy the current layer + memcpy(Spare_backups->Pages->Image[i],Main_backups->Pages->Image[Main_current_layer],Main_image_width*Main_image_height); + } + else + { + // Resize the original layer + Copy_part_of_image_to_another( + Spare_backups->Pages->Next->Image[i],0,0,Min(old_width,Spare_image_width), + Min(old_height,Spare_image_height),old_width, + Spare_backups->Pages->Image[i],0,0,Spare_image_width); + } + } // Copie des dimensions de l'image /* C'est inutile, le "Backuper et redimensionner brouillon" a déjà modifié ces valeurs pour qu'elles soient correctes. */ + /* Spare_image_width=Main_image_width; Spare_image_height=Main_image_height; + */ // Copie des décalages de la fenêtre principale (non zoomée) de l'image Spare_offset_X=Main_offset_X; diff --git a/pages.c b/pages.c index 8e8a3fc1..cfa6c84d 100644 --- a/pages.c +++ b/pages.c @@ -682,7 +682,6 @@ int Backup_with_new_dimensions(int upload,int width,int height) Error(0); return 0; } - //Copy_S_page(new_page,Main_backups->Pages); Upload_infos_page_main(new_page); new_page->Width=width; new_page->Height=height; @@ -690,7 +689,6 @@ int Backup_with_new_dimensions(int upload,int width,int height) { for (i=0; iPages->Image[i]=(byte *)malloc(width*height); memset(Main_backups->Pages->Image[i], 0, width*height); } @@ -698,15 +696,9 @@ int Backup_with_new_dimensions(int upload,int width,int height) Download_infos_page_main(Main_backups->Pages); Download_infos_backup(Main_backups); - // On nettoie la nouvelle image: - //memset(Main_screen,0,width*height); return_code=1; } - - // On détruit le descripteur de la page courante - //free(new_page); - return return_code; } @@ -717,31 +709,39 @@ int Backup_and_resize_the_spare(int width,int height) T_Page * new_page; int return_code=0; + byte nb_layers; + // On remet à jour l'état des infos de la page de brouillon (pour pouvoir // les retrouver plus tard) Upload_infos_page_spare(Spare_backups->Pages); + nb_layers=Spare_backups->Pages->Nb_layers; // On crée un descripteur pour la nouvelle page de brouillon - new_page=New_page(Spare_backups->Pages->Nb_layers); + new_page=New_page(nb_layers); if (!new_page) { Error(0); return 0; } - Upload_infos_page_spare(new_page); new_page->Width=width; new_page->Height=height; if (Create_new_page(new_page,Spare_backups,255)) { - Download_infos_page_spare(new_page); + byte i; + + for (i=0; iPages->Image[i], 0, width*height); + } + + // Update_buffers(width, height); // Not for spare + + Download_infos_page_spare(Spare_backups->Pages); + return_code=1; } - - // On détruit le descripteur de la page courante - free(new_page); - return return_code; } From eb1878e413a30a9a13cae3c1fc22ac3af9782cb6 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Thu, 8 Oct 2009 00:58:45 +0000 Subject: [PATCH 16/25] [layers] Fix a merge error from last commit which disabled layer selection. Implemented Fill. Color replacer in progress (ie: it crashes). git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1067 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- engine.c | 1104 +++++++++++++++++++++++++++++------------------------- graph.c | 56 +-- misc.c | 37 +- misc.h | 1 + 4 files changed, 639 insertions(+), 559 deletions(-) diff --git a/engine.c b/engine.c index 3a80d289..44be2eba 100644 --- a/engine.c +++ b/engine.c @@ -476,11 +476,12 @@ void Main_handler(void) int button_index; // Numéro de bouton de menu en cours int prev_button_number=0; // Numéro de bouton de menu sur lequel on était précédemment byte blink; // L'opération demande un effacement du curseur - int shortcut_button; // Button à enclencher d'après la touche de raccourci enfoncée - byte clicked_button = 0; // Côté du bouton à enclencher d'après la touche de raccourci enfoncée int key_index; // index du tableau de touches spéciales correspondant à la touche enfoncée char str[25]; byte temp; + byte effect_modified; + byte action; + dword key_pressed; do { @@ -498,534 +499,599 @@ void Main_handler(void) if(Get_input()) { - - // Evenement de fermeture - if (Quit_is_required) - { - Quit_is_required=0; - Button_Quit(); - } - - // Gestion des touches - if (Key) - { - for (key_index=0;(key_indexSPECIAL_CLICK_RIGHT) - switch(key_index) + // Inhibit all keys if a drawing operation is in progress. + // We make an exception for the freehand operations, but these will + // only accept a very limited number of shortcuts. + if (Operation_stack_size!=0 && !Allow_color_change_during_operation) + Key=0; + + // Evenement de fermeture + if (Quit_is_required) { - case SPECIAL_SCROLL_UP : // Scroll up - if (Main_magnifier_mode) - Scroll_magnifier(0,-(Main_magnifier_height>>2)); - else - Scroll_screen(0,-(Screen_height>>3)); - Key=0; - break; - case SPECIAL_SCROLL_DOWN : // Scroll down - if (Main_magnifier_mode) - Scroll_magnifier(0,(Main_magnifier_height>>2)); - else - Scroll_screen(0,(Screen_height>>3)); - Key=0; - break; - case SPECIAL_SCROLL_LEFT : // Scroll left - if (Main_magnifier_mode) - Scroll_magnifier(-(Main_magnifier_width>>2),0); - else - Scroll_screen(-(Screen_width>>3),0); - Key=0; - break; - case SPECIAL_SCROLL_RIGHT : // Scroll right - if (Main_magnifier_mode) - Scroll_magnifier((Main_magnifier_width>>2),0); - else - Scroll_screen((Screen_width>>3),0); - Key=0; - break; - case SPECIAL_SCROLL_UP_FAST : // Scroll up faster - if (Main_magnifier_mode) - Scroll_magnifier(0,-(Main_magnifier_height>>1)); - else - Scroll_screen(0,-(Screen_height>>2)); - Key=0; - break; - case SPECIAL_SCROLL_DOWN_FAST : // Scroll down faster - if (Main_magnifier_mode) - Scroll_magnifier(0,(Main_magnifier_height>>1)); - else - Scroll_screen(0,(Screen_height>>2)); - Key=0; - break; - case SPECIAL_SCROLL_LEFT_FAST : // Scroll left faster - if (Main_magnifier_mode) - Scroll_magnifier(-(Main_magnifier_width>>1),0); - else - Scroll_screen(-(Screen_width>>2),0); - Key=0; - break; - case SPECIAL_SCROLL_RIGHT_FAST : // Scroll right faster - if (Main_magnifier_mode) - Scroll_magnifier((Main_magnifier_width>>1),0); - else - Scroll_screen((Screen_width>>2),0); - Key=0; - break; - case SPECIAL_SCROLL_UP_SLOW : // Scroll up slower - if (Main_magnifier_mode) - Scroll_magnifier(0,-1); - else - Scroll_screen(0,-1); - Key=0; - break; - case SPECIAL_SCROLL_DOWN_SLOW : // Scroll down slower - if (Main_magnifier_mode) - Scroll_magnifier(0,1); - else - Scroll_screen(0,1); - Key=0; - break; - case SPECIAL_SCROLL_LEFT_SLOW : // Scroll left slower - if (Main_magnifier_mode) - Scroll_magnifier(-1,0); - else - Scroll_screen(-1,0); - Key=0; - break; - case SPECIAL_SCROLL_RIGHT_SLOW : // Scroll right slower - if (Main_magnifier_mode) - Scroll_magnifier(1,0); - else - Scroll_screen(1,0); - Key=0; - break; - case SPECIAL_NEXT_FORECOLOR : // Next foreground color - Special_next_forecolor(); - Key=0; - break; - case SPECIAL_PREVIOUS_FORECOLOR : // Previous foreground color - Special_previous_forecolor(); - Key=0; - break; - case SPECIAL_NEXT_BACKCOLOR : // Next background color - Special_next_backcolor(); - Key=0; - break; - case SPECIAL_PREVIOUS_BACKCOLOR : // Previous background color - Special_previous_backcolor(); - Key=0; - break; - case SPECIAL_SMALLER_PAINTBRUSH: // Rétrécir le pinceau - Smaller_paintbrush(); - Key=0; - break; - case SPECIAL_BIGGER_PAINTBRUSH: // Grossir le pinceau - Bigger_paintbrush(); - Key=0; - break; - case SPECIAL_NEXT_USER_FORECOLOR : // Next user-defined foreground color - Special_next_user_forecolor(); - Key=0; - break; - case SPECIAL_PREVIOUS_USER_FORECOLOR : // Previous user-defined foreground color - Special_previous_user_forecolor(); - Key=0; - break; - case SPECIAL_NEXT_USER_BACKCOLOR : // Next user-defined background color - Special_next_user_backcolor(); - Key=0; - break; - case SPECIAL_PREVIOUS_USER_BACKCOLOR : // Previous user-defined background color - Special_previous_user_backcolor(); - Key=0; - break; - case SPECIAL_SHOW_HIDE_CURSOR : // Show / Hide cursor - Hide_cursor(); - Cursor_hidden=!Cursor_hidden; - Display_cursor(); - Key=0; - break; - case SPECIAL_DOT_PAINTBRUSH : // Paintbrush = "." - Hide_cursor(); - Paintbrush_shape=PAINTBRUSH_SHAPE_ROUND; - Set_paintbrush_size(1,1); - Change_paintbrush_shape(PAINTBRUSH_SHAPE_ROUND); - Display_cursor(); - Key=0; - break; - case SPECIAL_CONTINUOUS_DRAW : // Continuous freehand drawing - Select_button(BUTTON_DRAW,LEFT_SIDE); - // ATTENTION CE TRUC EST MOCHE ET VA MERDER SI ON SE MET A UTILISER DES BOUTONS POPUPS - while (Current_operation!=OPERATION_CONTINUOUS_DRAW) - Select_button(BUTTON_DRAW,RIGHT_SIDE); - Key=0; - break; - case SPECIAL_FLIP_X : // Flip X - Hide_cursor(); - Flip_X_lowlevel(Brush, Brush_width, Brush_height); - Display_cursor(); - Key=0; - break; - case SPECIAL_FLIP_Y : // Flip Y - Hide_cursor(); - Flip_Y_lowlevel(Brush, Brush_width, Brush_height); - Display_cursor(); - Key=0; - break; - case SPECIAL_ROTATE_90 : // 90° brush rotation - Hide_cursor(); - Rotate_90_deg(); - Display_cursor(); - Key=0; - break; - case SPECIAL_ROTATE_180 : // 180° brush rotation - Hide_cursor(); - Rotate_180_deg_lowlevel(Brush, Brush_width, Brush_height); - Brush_offset_X=(Brush_width>>1); - Brush_offset_Y=(Brush_height>>1); - Display_cursor(); - Key=0; - break; - case SPECIAL_STRETCH : // Stretch brush - Hide_cursor(); - Start_operation_stack(OPERATION_STRETCH_BRUSH); - Display_cursor(); - Key=0; - break; - case SPECIAL_DISTORT : // Distort brush - Hide_cursor(); - Start_operation_stack(OPERATION_DISTORT_BRUSH); - Display_cursor(); - Key=0; - break; - case SPECIAL_ROTATE_ANY_ANGLE : // Rotate brush by any angle - Hide_cursor(); - Start_operation_stack(OPERATION_ROTATE_BRUSH); - Display_cursor(); - Key=0; - break; - case SPECIAL_OUTLINE : // Outline brush - Hide_cursor(); - Outline_brush(); - Display_cursor(); - Key=0; - break; - case SPECIAL_NIBBLE : // Nibble brush - Hide_cursor(); - Nibble_brush(); - Display_cursor(); - Key=0; - break; - case SPECIAL_GET_BRUSH_COLORS : // Get colors from brush - Get_colors_from_brush(); - Key=0; - break; - case SPECIAL_RECOLORIZE_BRUSH : // Recolorize brush - Hide_cursor(); - Remap_brush(); - Display_cursor(); - Key=0; - break; - case SPECIAL_LOAD_BRUSH : - Load_picture(0); - Key=0; - break; - case SPECIAL_SAVE_BRUSH : - Save_picture(0); - Key=0; - break; - case SPECIAL_ZOOM_IN : // Zoom in - Zoom(+1); - Key=0; - break; - case SPECIAL_ZOOM_OUT : // Zoom out - Zoom(-1); - Key=0; - break; - case SPECIAL_CENTER_ATTACHMENT : // Center brush attachment - Hide_cursor(); - Brush_offset_X=(Brush_width>>1); - Brush_offset_Y=(Brush_height>>1); - Display_cursor(); - Key=0; - break; - case SPECIAL_TOP_LEFT_ATTACHMENT : // Top-left brush attachment - Hide_cursor(); - Brush_offset_X=0; - Brush_offset_Y=0; - Display_cursor(); - Key=0; - break; - case SPECIAL_TOP_RIGHT_ATTACHMENT : // Top-right brush attachment - Hide_cursor(); - Brush_offset_X=(Brush_width-1); - Brush_offset_Y=0; - Display_cursor(); - Key=0; - break; - case SPECIAL_BOTTOM_LEFT_ATTACHMENT : // Bottom-left brush attachment - Hide_cursor(); - Brush_offset_X=0; - Brush_offset_Y=(Brush_height-1); - Display_cursor(); - Key=0; - break; - case SPECIAL_BOTTOM_RIGHT_ATTACHMENT : // Bottom right brush attachment - Hide_cursor(); - Brush_offset_X=(Brush_width-1); - Brush_offset_Y=(Brush_height-1); - Display_cursor(); - Key=0; - break; - case SPECIAL_EXCLUDE_COLORS_MENU : // Exclude colors menu - Menu_tag_colors("Tag colors to exclude",Exclude_color,&temp,1, NULL, SPECIAL_EXCLUDE_COLORS_MENU); - Key=0; - break; - case SPECIAL_INVERT_SIEVE : - Invert_trame(); - Key=0; - break; - case SPECIAL_SHADE_MODE : - Button_Shade_mode(); - Key=0; - break; - case SPECIAL_SHADE_MENU : - Button_Shade_menu(); - Key=0; - break; - case SPECIAL_QUICK_SHADE_MODE : - Button_Quick_shade_mode(); - Key=0; - break; - case SPECIAL_QUICK_SHADE_MENU : - Button_Quick_shade_menu(); - Key=0; - break; - case SPECIAL_STENCIL_MODE : - Button_Stencil_mode(); - Key=0; - break; - case SPECIAL_STENCIL_MENU : - Button_Stencil_menu(); - Key=0; - break; - case SPECIAL_MASK_MODE : - Button_Mask_mode(); - Key=0; - break; - case SPECIAL_MASK_MENU : - Button_Mask_menu(); - Key=0; - break; - case SPECIAL_GRID_MODE : - Button_Snap_mode(); - Key=0; - break; - case SPECIAL_GRID_MENU : - Button_Grid_menu(); - Key=0; - break; - case SPECIAL_SHOW_GRID : - Button_Show_grid(); - Key=0; - break; - case SPECIAL_SIEVE_MODE : - Button_Sieve_mode(); - Key=0; - break; - case SPECIAL_SIEVE_MENU : - Button_Sieve_menu(); - Key=0; - break; - case SPECIAL_COLORIZE_MODE : - Button_Colorize_mode(); - Key=0; - break; - case SPECIAL_COLORIZE_MENU : - Button_Colorize_menu(); - Key=0; - break; - case SPECIAL_SMOOTH_MODE : - Button_Smooth_mode(); - Key=0; - break; - case SPECIAL_SMOOTH_MENU : - Button_Smooth_menu(); - Key=0; - break; - case SPECIAL_SMEAR_MODE : - Button_Smear_mode(); - Key=0; - break; - case SPECIAL_TILING_MODE : - Button_Tiling_mode(); - Key=0; - break; - case SPECIAL_TILING_MENU : - Button_Tiling_menu(); - Key=0; - break; - case SPECIAL_EFFECTS_OFF : - Effects_off(); - Key=0; - break; - case SPECIAL_TRANSPARENCY_1 : - Layer_activate(0, LEFT_SIDE); - //Transparency_set(1); - Key=0; - break; - case SPECIAL_TRANSPARENCY_2 : - Layer_activate(1, LEFT_SIDE); - //Transparency_set(2); - Key=0; - break; - case SPECIAL_TRANSPARENCY_3 : - Layer_activate(2, LEFT_SIDE); - //Transparency_set(3); - Key=0; - break; - case SPECIAL_TRANSPARENCY_4 : - Layer_activate(3, LEFT_SIDE); - //Transparency_set(4); - Key=0; - break; - case SPECIAL_TRANSPARENCY_5 : - Layer_activate(0, RIGHT_SIDE); - //Transparency_set(5); - Key=0; - break; - case SPECIAL_TRANSPARENCY_6 : - Layer_activate(1, RIGHT_SIDE); - //Transparency_set(6); - Key=0; - break; - case SPECIAL_TRANSPARENCY_7 : - Layer_activate(2, RIGHT_SIDE); - //Transparency_set(7); - Key=0; - break; - case SPECIAL_TRANSPARENCY_8 : - Layer_activate(3, RIGHT_SIDE); - //Transparency_set(8); - Key=0; - break; - case SPECIAL_TRANSPARENCY_9 : - Transparency_set(9); - Key=0; - break; - case SPECIAL_TRANSPARENCY_0 : - Transparency_set(0); - Key=0; - break; - case SPECIAL_ZOOM_1 : - Zoom_set(-1); - Key=0; - break; - case SPECIAL_ZOOM_2 : - Zoom_set(0); - Key=0; - break; - case SPECIAL_ZOOM_3 : - Zoom_set(1); - Key=0; - break; - case SPECIAL_ZOOM_4 : - Zoom_set(2); - Key=0; - break; - case SPECIAL_ZOOM_5 : - Zoom_set(3); - Key=0; - break; - case SPECIAL_ZOOM_6 : - Zoom_set(4); - Key=0; - break; - case SPECIAL_ZOOM_8 : - Zoom_set(5); - Key=0; - break; - case SPECIAL_ZOOM_10 : - Zoom_set(6); - Key=0; - break; - case SPECIAL_ZOOM_12 : - Zoom_set(7); - Key=0; - break; - case SPECIAL_ZOOM_14 : - Zoom_set(8); - Key=0; - break; - case SPECIAL_ZOOM_16 : - Zoom_set(9); - Key=0; - break; - case SPECIAL_ZOOM_18 : - Zoom_set(10); - Key=0; - break; - case SPECIAL_ZOOM_20 : - Zoom_set(11); - Key=0; - break; - default : // Gestion des touches de raccourci de bouton: - // Pour chaque bouton - shortcut_button=-1; + Quit_is_required=0; + Button_Quit(); + } + + if (Key) + { + effect_modified = 0; + + for (key_index=SPECIAL_CLICK_RIGHT+1;key_index>2)); + else + Scroll_screen(0,-(Screen_height>>3)); + action++; + break; + case SPECIAL_SCROLL_DOWN : // Scroll down + if (Main_magnifier_mode) + Scroll_magnifier(0,(Main_magnifier_height>>2)); + else + Scroll_screen(0,(Screen_height>>3)); + action++; + break; + case SPECIAL_SCROLL_LEFT : // Scroll left + if (Main_magnifier_mode) + Scroll_magnifier(-(Main_magnifier_width>>2),0); + else + Scroll_screen(-(Screen_width>>3),0); + action++; + break; + case SPECIAL_SCROLL_RIGHT : // Scroll right + if (Main_magnifier_mode) + Scroll_magnifier((Main_magnifier_width>>2),0); + else + Scroll_screen((Screen_width>>3),0); + action++; + break; + case SPECIAL_SCROLL_UP_FAST : // Scroll up faster + if (Main_magnifier_mode) + Scroll_magnifier(0,-(Main_magnifier_height>>1)); + else + Scroll_screen(0,-(Screen_height>>2)); + action++; + break; + case SPECIAL_SCROLL_DOWN_FAST : // Scroll down faster + if (Main_magnifier_mode) + Scroll_magnifier(0,(Main_magnifier_height>>1)); + else + Scroll_screen(0,(Screen_height>>2)); + action++; + break; + case SPECIAL_SCROLL_LEFT_FAST : // Scroll left faster + if (Main_magnifier_mode) + Scroll_magnifier(-(Main_magnifier_width>>1),0); + else + Scroll_screen(-(Screen_width>>2),0); + action++; + break; + case SPECIAL_SCROLL_RIGHT_FAST : // Scroll right faster + if (Main_magnifier_mode) + Scroll_magnifier((Main_magnifier_width>>1),0); + else + Scroll_screen((Screen_width>>2),0); + action++; + break; + case SPECIAL_SCROLL_UP_SLOW : // Scroll up slower + if (Main_magnifier_mode) + Scroll_magnifier(0,-1); + else + Scroll_screen(0,-1); + action++; + break; + case SPECIAL_SCROLL_DOWN_SLOW : // Scroll down slower + if (Main_magnifier_mode) + Scroll_magnifier(0,1); + else + Scroll_screen(0,1); + action++; + break; + case SPECIAL_SCROLL_LEFT_SLOW : // Scroll left slower + if (Main_magnifier_mode) + Scroll_magnifier(-1,0); + else + Scroll_screen(-1,0); + action++; + break; + case SPECIAL_SCROLL_RIGHT_SLOW : // Scroll right slower + if (Main_magnifier_mode) + Scroll_magnifier(1,0); + else + Scroll_screen(1,0); + action++; + break; + case SPECIAL_SHOW_HIDE_CURSOR : // Show / Hide cursor + Hide_cursor(); + Cursor_hidden=!Cursor_hidden; + Display_cursor(); + action++; + break; + case SPECIAL_DOT_PAINTBRUSH : // Paintbrush = "." + Hide_cursor(); + Paintbrush_shape=PAINTBRUSH_SHAPE_ROUND; + Set_paintbrush_size(1,1); + Change_paintbrush_shape(PAINTBRUSH_SHAPE_ROUND); + Display_cursor(); + action++; + break; + case SPECIAL_CONTINUOUS_DRAW : // Continuous freehand drawing + Select_button(BUTTON_DRAW,LEFT_SIDE); + // ATTENTION CE TRUC EST MOCHE ET VA MERDER SI ON SE MET A UTILISER DES BOUTONS POPUPS + while (Current_operation!=OPERATION_CONTINUOUS_DRAW) + Select_button(BUTTON_DRAW,RIGHT_SIDE); + action++; + break; + case SPECIAL_FLIP_X : // Flip X + Hide_cursor(); + Flip_X_lowlevel(Brush, Brush_width, Brush_height); + Display_cursor(); + action++; + break; + case SPECIAL_FLIP_Y : // Flip Y + Hide_cursor(); + Flip_Y_lowlevel(Brush, Brush_width, Brush_height); + Display_cursor(); + action++; + break; + case SPECIAL_ROTATE_90 : // 90° brush rotation + Hide_cursor(); + Rotate_90_deg(); + Display_cursor(); + action++; + break; + case SPECIAL_ROTATE_180 : // 180° brush rotation + Hide_cursor(); + Rotate_180_deg_lowlevel(Brush, Brush_width, Brush_height); + Brush_offset_X=(Brush_width>>1); + Brush_offset_Y=(Brush_height>>1); + Display_cursor(); + action++; + break; + case SPECIAL_STRETCH : // Stretch brush + Hide_cursor(); + Start_operation_stack(OPERATION_STRETCH_BRUSH); + Display_cursor(); + action++; + break; + case SPECIAL_DISTORT : // Distort brush + Hide_cursor(); + Start_operation_stack(OPERATION_DISTORT_BRUSH); + Display_cursor(); + action++; + break; + case SPECIAL_ROTATE_ANY_ANGLE : // Rotate brush by any angle + Hide_cursor(); + Start_operation_stack(OPERATION_ROTATE_BRUSH); + Display_cursor(); + action++; + break; + case SPECIAL_OUTLINE : // Outline brush + Hide_cursor(); + Outline_brush(); + Display_cursor(); + action++; + break; + case SPECIAL_NIBBLE : // Nibble brush + Hide_cursor(); + Nibble_brush(); + Display_cursor(); + action++; + break; + case SPECIAL_GET_BRUSH_COLORS : // Get colors from brush + Get_colors_from_brush(); + action++; + break; + case SPECIAL_RECOLORIZE_BRUSH : // Recolorize brush + Hide_cursor(); + Remap_brush(); + Display_cursor(); + action++; + break; + case SPECIAL_LOAD_BRUSH : + Load_picture(0); + action++; + break; + case SPECIAL_SAVE_BRUSH : + Save_picture(0); + action++; + break; + case SPECIAL_ZOOM_IN : // Zoom in + Zoom(+1); + action++; + break; + case SPECIAL_ZOOM_OUT : // Zoom out + Zoom(-1); + action++; + break; + case SPECIAL_CENTER_ATTACHMENT : // Center brush attachment + Hide_cursor(); + Brush_offset_X=(Brush_width>>1); + Brush_offset_Y=(Brush_height>>1); + Display_cursor(); + action++; + break; + case SPECIAL_TOP_LEFT_ATTACHMENT : // Top-left brush attachment + Hide_cursor(); + Brush_offset_X=0; + Brush_offset_Y=0; + Display_cursor(); + action++; + break; + case SPECIAL_TOP_RIGHT_ATTACHMENT : // Top-right brush attachment + Hide_cursor(); + Brush_offset_X=(Brush_width-1); + Brush_offset_Y=0; + Display_cursor(); + action++; + break; + case SPECIAL_BOTTOM_LEFT_ATTACHMENT : // Bottom-left brush attachment + Hide_cursor(); + Brush_offset_X=0; + Brush_offset_Y=(Brush_height-1); + Display_cursor(); + action++; + break; + case SPECIAL_BOTTOM_RIGHT_ATTACHMENT : // Bottom right brush attachment + Hide_cursor(); + Brush_offset_X=(Brush_width-1); + Brush_offset_Y=(Brush_height-1); + Display_cursor(); + action++; + break; + case SPECIAL_EXCLUDE_COLORS_MENU : // Exclude colors menu + Menu_tag_colors("Tag colors to exclude",Exclude_color,&temp,1, NULL, SPECIAL_EXCLUDE_COLORS_MENU); + action++; + break; + case SPECIAL_INVERT_SIEVE : + Invert_trame(); + action++; + break; + case SPECIAL_SHADE_MODE : + Button_Shade_mode(); + effect_modified = 1; + action++; + break; + case SPECIAL_SHADE_MENU : + Button_Shade_menu(); + effect_modified = 1; + action++; + break; + case SPECIAL_QUICK_SHADE_MODE : + Button_Quick_shade_mode(); + effect_modified = 1; + action++; + break; + case SPECIAL_QUICK_SHADE_MENU : + Button_Quick_shade_menu(); + effect_modified = 1; + action++; + break; + case SPECIAL_STENCIL_MODE : + Button_Stencil_mode(); + effect_modified = 1; + action++; + break; + case SPECIAL_STENCIL_MENU : + Button_Stencil_menu(); + effect_modified = 1; + action++; + break; + case SPECIAL_MASK_MODE : + Button_Mask_mode(); + effect_modified = 1; + action++; + break; + case SPECIAL_MASK_MENU : + Button_Mask_menu(); + effect_modified = 1; + action++; + break; + case SPECIAL_GRID_MODE : + Button_Snap_mode(); + effect_modified = 1; + action++; + break; + case SPECIAL_GRID_MENU : + Button_Grid_menu(); + effect_modified = 1; + action++; + break; + case SPECIAL_SHOW_GRID : + Button_Show_grid(); + effect_modified = 1; + action++; + break; + case SPECIAL_SIEVE_MODE : + Button_Sieve_mode(); + effect_modified = 1; + action++; + break; + case SPECIAL_SIEVE_MENU : + Button_Sieve_menu(); + effect_modified = 1; + action++; + break; + case SPECIAL_COLORIZE_MODE : + Button_Colorize_mode(); + effect_modified = 1; + action++; + break; + case SPECIAL_COLORIZE_MENU : + Button_Colorize_menu(); + effect_modified = 1; + action++; + break; + case SPECIAL_SMOOTH_MODE : + Button_Smooth_mode(); + effect_modified = 1; + action++; + break; + case SPECIAL_SMOOTH_MENU : + Button_Smooth_menu(); + effect_modified = 1; + action++; + break; + case SPECIAL_SMEAR_MODE : + Button_Smear_mode(); + effect_modified = 1; + action++; + break; + case SPECIAL_TILING_MODE : + Button_Tiling_mode(); + effect_modified = 1; + action++; + break; + case SPECIAL_TILING_MENU : + effect_modified = 1; + Button_Tiling_menu(); + action++; + break; + case SPECIAL_EFFECTS_OFF : + Effects_off(); + effect_modified = 1; + action++; + break; + case SPECIAL_TRANSPARENCY_1 : + Transparency_set(1); + effect_modified = 1; + action++; + break; + case SPECIAL_TRANSPARENCY_2 : + Transparency_set(2); + effect_modified = 1; + action++; + break; + case SPECIAL_TRANSPARENCY_3 : + Transparency_set(3); + effect_modified = 1; + action++; + break; + case SPECIAL_TRANSPARENCY_4 : + Transparency_set(4); + effect_modified = 1; + action++; + break; + case SPECIAL_TRANSPARENCY_5 : + Transparency_set(5); + effect_modified = 1; + action++; + break; + case SPECIAL_TRANSPARENCY_6 : + Transparency_set(6); + effect_modified = 1; + action++; + break; + case SPECIAL_TRANSPARENCY_7 : + Transparency_set(7); + effect_modified = 1; + action++; + break; + case SPECIAL_TRANSPARENCY_8 : + Transparency_set(8); + effect_modified = 1; + action++; + break; + case SPECIAL_TRANSPARENCY_9 : + Transparency_set(9); + effect_modified = 1; + action++; + break; + case SPECIAL_TRANSPARENCY_0 : + Transparency_set(0); + effect_modified = 1; + action++; + break; + case SPECIAL_ZOOM_1 : + Zoom_set(-1); + action++; + break; + case SPECIAL_ZOOM_2 : + Zoom_set(0); + action++; + break; + case SPECIAL_ZOOM_3 : + Zoom_set(1); + action++; + break; + case SPECIAL_ZOOM_4 : + Zoom_set(2); + action++; + break; + case SPECIAL_ZOOM_5 : + Zoom_set(3); + action++; + break; + case SPECIAL_ZOOM_6 : + Zoom_set(4); + action++; + break; + case SPECIAL_ZOOM_8 : + Zoom_set(5); + action++; + break; + case SPECIAL_ZOOM_10 : + Zoom_set(6); + action++; + break; + case SPECIAL_ZOOM_12 : + Zoom_set(7); + action++; + break; + case SPECIAL_ZOOM_14 : + Zoom_set(8); + action++; + break; + case SPECIAL_ZOOM_16 : + Zoom_set(9); + action++; + break; + case SPECIAL_ZOOM_18 : + Zoom_set(10); + action++; + break; + case SPECIAL_ZOOM_20 : + Zoom_set(11); + action++; + break; + case SPECIAL_LAYER1_SELECT: + case SPECIAL_LAYER2_SELECT: + case SPECIAL_LAYER3_SELECT: + case SPECIAL_LAYER4_SELECT: + case SPECIAL_LAYER5_SELECT: + case SPECIAL_LAYER6_SELECT: + case SPECIAL_LAYER7_SELECT: + case SPECIAL_LAYER8_SELECT: + Layer_activate((key_index-SPECIAL_LAYER1_SELECT)/2, LEFT_SIDE); + action++; + break; + case SPECIAL_LAYER1_TOGGLE: + case SPECIAL_LAYER2_TOGGLE: + case SPECIAL_LAYER3_TOGGLE: + case SPECIAL_LAYER4_TOGGLE: + case SPECIAL_LAYER5_TOGGLE: + case SPECIAL_LAYER6_TOGGLE: + case SPECIAL_LAYER7_TOGGLE: + case SPECIAL_LAYER8_TOGGLE: + Layer_activate((key_index-SPECIAL_LAYER1_TOGGLE)/2, RIGHT_SIDE); + action++; + break; + } + } + } // End of special keys + + + // Shortcut for clicks of Menu buttons. + // Disable all of them when an operation is in progress + if (Operation_stack_size==0) + { + // Some functions open windows that clear the Key variable, + // so we need to use a temporary replacement. + key_pressed = Key; for (button_index=0;button_index=SPECIAL_SHADE_MODE) - && (key_index<=SPECIAL_TILING_MENU)) - { - Hide_cursor(); - Draw_menu_button_frame(BUTTON_EFFECTS, - (Shade_mode||Quick_shade_mode||Colorize_mode||Smooth_mode||Tiling_mode||Smear_mode||Stencil_mode||Mask_mode||Sieve_mode||Snap_mode)); - Display_cursor(); - } - } + if (action) + Key=0; } else - { - // No event : we go asleep for a while, but we try to get waked up at constant intervals of time - // no matter the machine speed or system load. The time is fixed to 10ms (that should be about a cpu slice on most systems) - // This allows nice smooth mouse movement. - const int delay = 10; - - Uint32 debut; - debut = SDL_GetTicks(); - // Première attente : le complément de "delay" millisecondes - SDL_Delay(delay - (debut % delay)); - // Si ça ne suffit pas, on complète par des attentes successives de "1ms". - // (Remarque, Windows arrondit généralement aux 10ms supérieures) - while ( SDL_GetTicks()/delay <= debut/delay) - { - SDL_Delay(1); - } - } + { + // No event : we go asleep for a while, but we try to get waked up at constant intervals of time + // no matter the machine speed or system load. The time is fixed to 10ms (that should be about a cpu slice on most systems) + // This allows nice smooth mouse movement. + const int delay = 10; + + Uint32 debut; + debut = SDL_GetTicks(); + // Première attente : le complément de "delay" millisecondes + SDL_Delay(delay - (debut % delay)); + // Si ça ne suffit pas, on complète par des attentes successives de "1ms". + // (Remarque, Windows arrondit généralement aux 10ms supérieures) + while ( SDL_GetTicks()/delay <= debut/delay) + { + SDL_Delay(1); + } + } // Gestion de la souris diff --git a/graph.c b/graph.c index f91b263f..fc1c2f35 100644 --- a/graph.c +++ b/graph.c @@ -736,7 +736,7 @@ void Fill(short * top_reached , short * bottom_reached, current_limit_bottom =Min(Paintbrush_Y+1,Limit_bottom); *left_reached=Paintbrush_X; *right_reached=Paintbrush_X+1; - Pixel_in_current_screen(Paintbrush_X,Paintbrush_Y,2,0); + Pixel_in_current_layer(Paintbrush_X,Paintbrush_Y,2); while (changes_made) { @@ -755,7 +755,7 @@ void Fill(short * top_reached , short * bottom_reached, { // On cherche son début while((start_x<=Limit_right) && - (Read_pixel_from_current_screen(start_x,line)!=1)) + (Read_pixel_from_current_layer(start_x,line)!=1)) start_x++; if (start_x<=Limit_right) @@ -763,7 +763,7 @@ void Fill(short * top_reached , short * bottom_reached, // Un segment de couleur 1 existe et commence à la position start_x. // On va donc en chercher la fin. for (end_x=start_x+1;(end_x<=Limit_right) && - (Read_pixel_from_current_screen(end_x,line)==1);end_x++); + (Read_pixel_from_current_layer(end_x,line)==1);end_x++); // On sait qu'il existe un segment de couleur 1 qui commence en // start_x et qui se termine en end_x-1. @@ -774,16 +774,16 @@ void Fill(short * top_reached , short * bottom_reached, can_propagate=( // Test de la présence d'un point à gauche du segment ((start_x>Limit_left) && - (Read_pixel_from_current_screen(start_x-1,line)==2)) || + (Read_pixel_from_current_layer(start_x-1,line)==2)) || // Test de la présence d'un point à droite du segment ((end_x-1Limit_top)) for (x_pos=start_x;x_posLimit_left) && - (Read_pixel_from_current_screen(start_x-1,line)==2)) || + (Read_pixel_from_current_layer(start_x-1,line)==2)) || // Test de la présence d'un point à droite du segment ((end_x-1Pages->Next->Image[Main_current_layer]); +} void Fill_general(byte fill_color) // @@ -940,7 +944,7 @@ void Fill_general(byte fill_color) // On va maintenant "épurer" la zone visible de l'image: memset(replace_table,0,256); - replace_table[Read_pixel_from_current_screen(Paintbrush_X,Paintbrush_Y)]=1; + replace_table[Read_pixel_from_backup_layer(Paintbrush_X,Paintbrush_Y)]=1; Replace_colors_within_limits(replace_table); // On fait maintenant un remplissage classique de la couleur 1 avec la 2 @@ -955,39 +959,39 @@ void Fill_general(byte fill_color) // Il va maintenant falloir qu'on "turn" ce gros caca "into" un truc qui // ressemble un peu plus à ce à quoi l'utilisateur peut s'attendre. if (top_reached>Limit_top) - Copy_part_of_image_to_another(Screen_backup, // source + Copy_part_of_image_to_another(Main_backups->Pages->Next->Image[Main_current_layer], // source Limit_left,Limit_top, // Pos X et Y dans source (Limit_right-Limit_left)+1, // width copie top_reached-Limit_top,// height copie Main_image_width, // width de la source - Main_screen, // Destination + Main_backups->Pages->Image[Main_current_layer], // Destination Limit_left,Limit_top, // Pos X et Y destination Main_image_width); // width destination if (bottom_reachedPages->Next->Image[Main_current_layer], Limit_left,bottom_reached+1, (Limit_right-Limit_left)+1, Limit_bottom-bottom_reached, - Main_image_width,Main_screen, + Main_image_width,Main_backups->Pages->Image[Main_current_layer], Limit_left,bottom_reached+1,Main_image_width); if (left_reached>Limit_left) - Copy_part_of_image_to_another(Screen_backup, + Copy_part_of_image_to_another(Main_backups->Pages->Next->Image[Main_current_layer], Limit_left,top_reached, left_reached-Limit_left, (bottom_reached-top_reached)+1, - Main_image_width,Main_screen, + Main_image_width,Main_backups->Pages->Image[Main_current_layer], Limit_left,top_reached,Main_image_width); if (right_reachedPages->Next->Image[Main_current_layer], right_reached+1,top_reached, Limit_right-right_reached, (bottom_reached-top_reached)+1, - Main_image_width,Main_screen, + Main_image_width,Main_backups->Pages->Image[Main_current_layer], right_reached+1,top_reached,Main_image_width); for (y_pos=top_reached;y_pos<=bottom_reached;y_pos++) for (x_pos=left_reached;x_pos<=right_reached;x_pos++) - if (Read_pixel_from_current_screen(x_pos,y_pos)==2) + if (Read_pixel_from_current_layer(x_pos,y_pos)==2) { // Si le pixel en cours de traitement a été touché par le Fill() // on se doit d'afficher le pixel modifié par la couleur de @@ -996,14 +1000,14 @@ void Fill_general(byte fill_color) // Ceci se fait en commençant par restaurer la couleur qu'il y avait // précédemment (c'est important pour que les effets ne s'emmèlent // pas le pinceaux) - Pixel_in_current_screen(x_pos,y_pos,Read_pixel_from_backup_screen(x_pos,y_pos),0); + Pixel_in_current_screen(x_pos,y_pos,Read_pixel_from_backup_layer(x_pos,y_pos),0); // Enfin, on peut afficher le pixel, en le soumettant aux effets en // cours: Display_pixel(x_pos,y_pos,fill_color); } else - Pixel_in_current_screen(x_pos,y_pos,Read_pixel_from_backup_screen(x_pos,y_pos),0); + Pixel_in_current_screen(x_pos,y_pos,Read_pixel_from_backup_layer(x_pos,y_pos),0); FX_feedback_screen=old_fx_feedback_screen; @@ -2555,7 +2559,7 @@ void Replace(byte New_color) if ((Paintbrush_XPages->Image[Main_current_layer])=color; +} + byte Read_pixel_from_current_layer(word x,word y) { return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer]); @@ -254,12 +259,19 @@ byte Read_pixel_from_current_layer(word x,word y) void Replace_a_color(byte old_color, byte New_color) { - byte* edi; + byte* pixel_on_layer; + byte* pixel_visible; // pour chaque pixel : - for(edi = Main_screen;edi < Main_screen + Main_image_height * Main_image_width;edi++) - if (*edi == old_color) - *edi = New_color; + pixel_visible=Main_screen; + for(pixel_on_layer = Main_backups->Pages->Image[Main_current_layer];pixel_on_layer < Main_screen + Main_image_height * Main_image_width;pixel_on_layer++,pixel_visible++) + { + if (*pixel_on_layer == old_color) + { + *pixel_on_layer = New_color; + *pixel_visible = New_color; + } + } Update_rect(0,0,0,0); // On peut TOUT a jour // C'est pas un problème car il n'y a pas de preview } @@ -405,21 +417,18 @@ byte Effect_sieve(word x,word y) void Replace_colors_within_limits(byte * replace_table) { - int line; - int counter; - byte* Adresse; - - byte old; + int y; + int x; + byte* pixel; // Pour chaque ligne : - for(line = Limit_top;line <= Limit_bottom; line++) + for(y = Limit_top;y <= Limit_bottom; y++) { // Pour chaque pixel sur la ligne : - for (counter = Limit_left;counter <= Limit_right;counter ++) + for (x = Limit_left;x <= Limit_right;x ++) { - Adresse = Main_screen+line*Main_image_width+counter; - old=*Adresse; - *Adresse = replace_table[old]; + pixel = Main_backups->Pages->Image[Main_current_layer]+y*Main_image_width+x; + *pixel = replace_table[*pixel]; } } } diff --git a/misc.h b/misc.h index 7c669ee6..8dd97925 100644 --- a/misc.h +++ b/misc.h @@ -44,6 +44,7 @@ byte Read_pixel_from_backup_screen (word x,word y); byte Read_pixel_from_feedback_screen (word x,word y); byte Read_pixel_from_brush (word x,word y); byte Read_pixel_from_current_layer(word x,word y); +void Pixel_in_current_layer(word x,word y, byte color); void Ellipse_compute_limites(short horizontal_radius,short vertical_radius); // Calcule les valeurs suivantes en fonction des deux paramètres: From 2049f96c59d95d84362fdea17f028f156f71d665 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Thu, 8 Oct 2009 23:54:02 +0000 Subject: [PATCH 17/25] [layers] Implemented layer insertion. No keys or menu yet, but it's already used when loading images, to make an image with right number of layers. Undoing/redoing such change works. Implemented single-layer deletion (untested) git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1069 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 6 +- gfx2.cfg | Bin 10308 -> 10308 bytes global.h | 4 +- graph.c | 2 +- loadsave.c | 3 +- main.c | 4 +- pages.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++---- pages.h | 10 +++- transform.c | 2 +- 9 files changed, 174 insertions(+), 25 deletions(-) diff --git a/buttons.c b/buttons.c index 4cb44869..142a53eb 100644 --- a/buttons.c +++ b/buttons.c @@ -1365,7 +1365,7 @@ void Button_Page(void) SWAP_WORDS (Main_fileselector_position,Spare_fileselector_position) SWAP_WORDS (Main_fileselector_offset,Spare_fileselector_offset) SWAP_SHORTS(Main_current_layer,Spare_current_layer) - SWAP_BYTES (Main_layers_visible,Spare_layers_visible) + SWAP_WORDS (Main_layers_visible,Spare_layers_visible) // A la fin, on affiche l'écran for (factor_index=0; ZOOM_FACTOR[factor_index]!=Main_magnifier_factor; factor_index++); @@ -4285,7 +4285,7 @@ void Transparency_set(byte amount) void Layer_activate(short layer, short side) { - byte old_layers; + word old_layers; if (layer >= Main_backups->Pages->Nb_layers) return; @@ -4300,7 +4300,7 @@ void Layer_activate(short layer, short side) if (Main_layers_visible == (1<Sa3o*@7ZYQ`W^N`+H2^741Z4mK delta 14 VcmX>Sa3o*@7Zc;A&D>0uY5*%d1h)VH diff --git a/global.h b/global.h index 6e6b780a..9f98c0c3 100644 --- a/global.h +++ b/global.h @@ -348,7 +348,7 @@ GFX2_GLOBAL short Main_magnifier_offset_Y; /// Index of layer currently being edited GFX2_GLOBAL int Main_current_layer; /// Bitfield that records which layers are visible. 2^0 for 0, 2^1 for 1, 2^2 for 2, etc. -GFX2_GLOBAL byte Main_layers_visible; +GFX2_GLOBAL word Main_layers_visible; // -- Spare page data @@ -412,7 +412,7 @@ GFX2_GLOBAL short Spare_magnifier_offset_Y; /// Index of layer currently being edited GFX2_GLOBAL short Spare_current_layer; /// Bitfield that records which layers are visible. 2^0 for 0, 2^1 for 1, 2^2 for 2, etc. -GFX2_GLOBAL byte Spare_layers_visible; +GFX2_GLOBAL word Spare_layers_visible; // -- Image backups /// Backup of the current screen, used during drawing when FX feedback is OFF. diff --git a/graph.c b/graph.c index 5674d025..e5411ae9 100644 --- a/graph.c +++ b/graph.c @@ -595,7 +595,7 @@ void Resize_image(word chosen_width,word chosen_height) // |B| | C = Nouvelle image // +-+-+ - if (Backup_with_new_dimensions(1,chosen_width,chosen_height)) + if (Backup_with_new_dimensions(1,Main_backups->Pages->Nb_layers,chosen_width,chosen_height)) { // La nouvelle page a pu être allouée, elle est pour l'instant pleine de // 0s. Elle fait Main_image_width de large. diff --git a/loadsave.c b/loadsave.c index 82388cf1..9ba10821 100644 --- a/loadsave.c +++ b/loadsave.c @@ -460,7 +460,7 @@ void Init_preview(short width,short height,long size,int format, enum PIXEL_RATI { if (Pixel_load_function==Pixel_load_in_current_screen) { - if (Backup_with_new_dimensions(0,width,height)) + if (Backup_with_new_dimensions(0,1,width,height)) { // La nouvelle page a pu être allouée, elle est pour l'instant pleine // de 0s. Elle fait Main_image_width de large. @@ -3174,6 +3174,7 @@ void Load_GIF(void) if (number_LID!=0) { Main_current_layer++; + Add_layer(Main_backups, Main_current_layer); } number_LID++; diff --git a/main.c b/main.c index 73c4cf8b..650563a6 100644 --- a/main.c +++ b/main.c @@ -370,9 +370,9 @@ int Init_program(int argc,char * argv[]) Main_fileselector_offset=0; // Au début, le fileselect est en haut de la liste des fichiers Main_format=0; Main_current_layer=0; - Main_layers_visible=0xFF; + Main_layers_visible=0xFFFF; Spare_current_layer=0; - Spare_layers_visible=0xFF; + Spare_layers_visible=0xFFFF; Spare_fileselector_position=0; Spare_fileselector_offset=0; diff --git a/pages.c b/pages.c index cfa6c84d..7e6d96c3 100644 --- a/pages.c +++ b/pages.c @@ -43,7 +43,7 @@ T_Page * New_page(byte nb_layers) { T_Page * page; - page = (T_Page *)malloc(sizeof(T_Page)+NB_LAYERS*sizeof(byte *)); + page = (T_Page *)malloc(sizeof(T_Page)+nb_layers*sizeof(byte *)); if (page!=NULL) { int i; @@ -469,7 +469,7 @@ void Free_last_page_of_list(T_List_of_pages * list) } // layer_mask tells which layers have to be fresh copies instead of references -int Create_new_page(T_Page * new_page,T_List_of_pages * list, byte layer_mask) +int Create_new_page(T_Page * new_page, T_List_of_pages * list, word layer_mask) { // Cette fonction crée une nouvelle page dont les attributs correspondent à @@ -659,13 +659,12 @@ void Set_number_of_backups(int nb_backups) // (nb_backups = Nombre de backups, sans compter les pages courantes) } -int Backup_with_new_dimensions(int upload,int width,int height) +int Backup_with_new_dimensions(int upload,byte layers,int width,int height) { // Retourne 1 si une nouvelle page est disponible (alors pleine de 0) et // 0 sinon. T_Page * new_page; - byte nb_layers; int return_code=0; int i; @@ -674,9 +673,8 @@ int Backup_with_new_dimensions(int upload,int width,int height) // retrouver plus tard) Upload_infos_page_main(Main_backups->Pages); - nb_layers=Main_backups->Pages->Nb_layers; // On crée un descripteur pour la nouvelle page courante - new_page=New_page(nb_layers); + new_page=New_page(layers); if (!new_page) { Error(0); @@ -685,9 +683,9 @@ int Backup_with_new_dimensions(int upload,int width,int height) Upload_infos_page_main(new_page); new_page->Width=width; new_page->Height=height; - if (Create_new_page(new_page,Main_backups,255)) + if (Create_new_page(new_page,Main_backups,0xFFFF)) { - for (i=0; iPages->Image[i], 0, width*height); } @@ -727,7 +725,7 @@ int Backup_and_resize_the_spare(int width,int height) Upload_infos_page_spare(new_page); new_page->Width=width; new_page->Height=height; - if (Create_new_page(new_page,Spare_backups,255)) + if (Create_new_page(new_page,Spare_backups,0xFFFF)) { byte i; @@ -752,10 +750,9 @@ void Backup(void) Backup_layers(1<Pages; + + // Keep the position reasonable + if (layer > list->Pages->Nb_layers) + layer = list->Pages->Nb_layers; + + // Allocate the pixel data + new_image = New_layer(list->Pages->Height*list->Pages->Width); + if (! new_image) + { + Error(0); + return 1; + } + // Re-allocate the page itself, with room for one more pointer + new_page = realloc(source_page, sizeof(T_Page)+(list->Pages->Nb_layers+1)*sizeof(byte *)); + if (!new_page) + { + Error(0); + return 1; + } + if (new_page != source_page) + { + // Need some housekeeping because the page moved in memory. + // Update all pointers that pointed to it: + new_page->Prev->Next = new_page; + new_page->Next->Prev = new_page; + list->Pages = new_page; + } + list->Pages->Nb_layers++; + // Move around the pointers. This part is going to be tricky when we + // have 'animations x layers' in this vector. + for (i=list->Pages->Nb_layers-1; i>layer ; i--) + { + new_page->Image[i]=new_page->Image[i-1]; + } + new_page->Image[layer]=new_image; + // Fill with transparency, initially + memset(new_image, 0, 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. + // The depth buffer is all wrong though. + + // Update the flags of visible layers. + { + word layers_before; + word layers_after; + word *visible_layers_flag; + + // Determine if we're modifying the spare or the main page. + if (list == Main_backups) + { + visible_layers_flag = &Main_layers_visible; + Main_current_layer = layer; + } + else + { + visible_layers_flag = &Spare_layers_visible; + Spare_current_layer = layer; + } + + // Fun with binary! + layers_before = ((1<Pages; + + // Keep the position reasonable + if (layer >= list->Pages->Nb_layers) + layer = list->Pages->Nb_layers - 1; + if (list->Pages->Nb_layers == 1) + return 1; + + // For simplicity, we won't actually shrink the page in terms of allocation. + // It would only save the size of a pointer, and anyway, as the user draws, + // this page is going to fall off the end of the Undo-list + // and so it will be cleared anyway. + + // Smart freeing of the pixel data + Free_layer(list->Pages->Image[layer]); + + list->Pages->Nb_layers--; + // Move around the pointers. This part is going to be tricky when we + // have 'animations x layers' in this vector. + for (i=layer; i < list->Pages->Nb_layers; i++) + { + list->Pages->Image[i]=list->Pages->Image[i+1]; + } + + // Done. At this point the visible buffer and the depth buffer are + // all wrong. + + // Update the flags of visible layers. + { + word layers_before; + word layers_after; + word *visible_layers_flag; + byte new_current_layer; + + // Determine if we're modifying the spare or the main page. + if (list == Main_backups) + { + visible_layers_flag = &Main_layers_visible; + if (Main_current_layer>=layer && Main_current_layer>0) + Main_current_layer--; + new_current_layer = Main_current_layer; + } + else + { + visible_layers_flag = &Spare_layers_visible; + if (Spare_current_layer>=layer && Spare_current_layer>0) + Spare_current_layer--; + new_current_layer = Spare_current_layer; + } + + // Fun with binary! + layers_before = ((1<>1; + *visible_layers_flag = layers_before | layers_after; + // Ensure the current layer is part what is shown. + *visible_layers_flag |= 1<Pages->Nb_layers,new_width,new_height)) { // The new image is allocated, the new dimensions are already updated. From 7690cd9e507fb970d8969ce1b40100196b5c585f Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Tue, 13 Oct 2009 01:03:32 +0000 Subject: [PATCH 18/25] [layers] Added functions to add and delete layers (Keyboard shortcuts alt-ins and alt-del) Now defaults back to 1 layer per image on startup. git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1073 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 99 ---------------------------------------------- buttons.h | 7 ---- const.h | 2 +- engine.c | 25 ++++++++++++ pages.c | 4 +- special.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ special.h | 12 ++++++ 7 files changed, 155 insertions(+), 109 deletions(-) diff --git a/buttons.c b/buttons.c index 142a53eb..81926943 100644 --- a/buttons.c +++ b/buttons.c @@ -4233,105 +4233,6 @@ void Effects_off(void) Snap_mode=0; } -void Transparency_set(byte amount) -{ - const int doubleclick_delay = Config.Double_key_speed; - static long time_click = 0; - long time_previous; - - if (!Colorize_mode) - { - // Activate mode - switch(Colorize_current_mode) - { - case 0 : - Effect_function=Effect_interpolated_colorize; - break; - case 1 : - Effect_function=Effect_additive_colorize; - break; - case 2 : - Effect_function=Effect_substractive_colorize; - } - Shade_mode=0; - Quick_shade_mode=0; - Smooth_mode=0; - Tiling_mode=0; - - Colorize_mode=1; - } - - time_previous = time_click; - time_click = SDL_GetTicks(); - - // Check if it's a quick re-press - if (time_click - time_previous < doubleclick_delay) - { - // Use the typed amount as units, keep the tens. - Colorize_opacity = ((Colorize_opacity%100) /10 *10) + amount; - if (Colorize_opacity == 0) - Colorize_opacity = 100; - } - else - { - // Use 10% units: "1"=10%, ... "0"=100% - if (amount == 0) - Colorize_opacity = 100; - else - Colorize_opacity = amount*10; - } - Compute_colorize_table(); -} - -void Layer_activate(short layer, short side) -{ - word old_layers; - - if (layer >= Main_backups->Pages->Nb_layers) - return; - - // Keep a copy of which layers were visible - old_layers = Main_layers_visible; - if (side == RIGHT_SIDE) - { - // Right-click on current layer - if (Main_current_layer == layer) - { - if (Main_layers_visible == (1<Pages); - //Download_infos_backup(Main_backups); - Display_all_screen(); - Display_cursor(); -} - //---------------------------- Courbes de Bézier ---------------------------- void Button_Curves(void) diff --git a/buttons.h b/buttons.h index 1b25ac64..7c38d05e 100644 --- a/buttons.h +++ b/buttons.h @@ -436,13 +436,6 @@ void Button_Tiling_menu(void); */ void Effects_off(void); -/*! - Command that sets the transparency level. -*/ -void Transparency_set(byte amount); - -void Layer_activate(short layer, short side); - // Menu des effets /*! diff --git a/const.h b/const.h index 60608858..d58c8d0b 100644 --- a/const.h +++ b/const.h @@ -64,7 +64,7 @@ #define LEFT_TRIANGLE_CHARACTER 17 /// Character to display in menus for an ellipsis. #define ELLIPSIS_CHARACTER '…' -#define NB_LAYERS 8 +#define NB_LAYERS 1 ///< Initial number of layers for a new image #define BRUSH_CONTAINER_PREVIEW_WIDTH 16 ///< Size for preview of a brush in Brush container #define BRUSH_CONTAINER_PREVIEW_HEIGHT 16 ///< Size for preview of a brush in Brush container #define BRUSH_CONTAINER_COLUMNS 4 ///< Number of columns in the Brush container diff --git a/engine.c b/engine.c index 44be2eba..2c2f9df1 100644 --- a/engine.c +++ b/engine.c @@ -36,6 +36,7 @@ #include "brush.h" #include "input.h" #include "engine.h" +#include "pages.h" // we need this as global @@ -1032,6 +1033,30 @@ void Main_handler(void) Layer_activate((key_index-SPECIAL_LAYER1_TOGGLE)/2, RIGHT_SIDE); action++; break; + case SPECIAL_LAYER_ADD: + // Backup with unchanged layers + Backup_layers(0); + if (!Add_layer(Main_backups,Main_current_layer+1)) + { + Update_depth_buffer(); + Hide_cursor(); + Display_all_screen(); + Display_cursor(); + } + action++; + break; + case SPECIAL_LAYER_DELETE: + // Backup with unchanged layers + Backup_layers(0); + if (!Delete_layer(Main_backups,Main_current_layer)) + { + Redraw_layered_image(); + Hide_cursor(); + Display_all_screen(); + Display_cursor(); + } + action++; + break; } } } // End of special keys diff --git a/pages.c b/pages.c index 7e6d96c3..03199945 100644 --- a/pages.c +++ b/pages.c @@ -991,7 +991,7 @@ byte Add_layer(T_List_of_pages *list, byte layer) // Fun with binary! layers_before = ((1<>1; + layers_after = (*visible_layers_flag & (~layers_before))>>1; *visible_layers_flag = layers_before | layers_after; // Ensure the current layer is part what is shown. *visible_layers_flag |= 1<= Main_backups->Pages->Nb_layers) + return; + + // Keep a copy of which layers were visible + old_layers = Main_layers_visible; + if (side == RIGHT_SIDE) + { + // Right-click on current layer + if (Main_current_layer == layer) + { + if (Main_layers_visible == (1<Pages); + //Download_infos_backup(Main_backups); + Display_all_screen(); + Display_cursor(); +} + +void Special_add_layer() +{ + + +} +void Special_delete_layer() +{ + + +} diff --git a/special.h b/special.h index d6d64b37..8dfa57c0 100644 --- a/special.h +++ b/special.h @@ -48,3 +48,15 @@ void Zoom_set(int index); void Display_stored_brush_in_window(word x,word y,int number); void Store_brush(int index); byte Restore_brush(int index); + +/*! + Command that sets the transparency level. +*/ +void Transparency_set(byte amount); + +void Layer_activate(short layer, short side); + +void Special_add_layer(void); + +void Special_delete_layer(void); + From 2dcc1cf8bdb285134ebdfb592d30a2885409c203 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Tue, 13 Oct 2009 19:07:58 +0000 Subject: [PATCH 19/25] [layers] Stats on memory usage in the Stats screen. Tracks the number and total memory size of the pages (bitmaps) used by layers and their backups. Doesn't count housekeeping costs. git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1074 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- help.c | 11 +++++++++++ pages.c | 24 +++++++++++++++++++----- pages.h | 9 +++++++++ 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/help.c b/help.c index f5e75e5b..f476b5a3 100644 --- a/help.c +++ b/help.c @@ -45,6 +45,7 @@ #include "input.h" #include "hotkeys.h" #include "errors.h" +#include "pages.h" // Recherche un raccourci clavier: word * Shortcut(word shortcut_number) @@ -637,6 +638,16 @@ void Button_Stats(void) sprintf(buffer,"%u bytes",(unsigned int)freeRam); Print_in_window(114,51,buffer,STATS_DATA_COLOR,MC_Black); + // Used memory + Print_in_window(10,59,"Used memory pages: ",STATS_TITLE_COLOR,MC_Black); + if(Stats_pages_memory > (100LL*1024*1024*1024)) + sprintf(buffer,"%u (%u Gb)",Stats_pages_number, (unsigned int)(Stats_pages_memory/(1024*1024*1024))); + else if(Stats_pages_memory > (100*1024*1024)) + sprintf(buffer,"%u (%u Mb)",Stats_pages_number, (unsigned int)(Stats_pages_memory/(1024*1024))); + else + sprintf(buffer,"%u (%u Kb)",Stats_pages_number, (unsigned int)(Stats_pages_memory/1024)); + Print_in_window(162,59,buffer,STATS_DATA_COLOR,MC_Black); + // Affichage de l'espace disque libre sprintf(buffer,"Free space on %c:",Main_current_directory[0]); Print_in_window(10,67,buffer,STATS_TITLE_COLOR,MC_Black); diff --git a/pages.c b/pages.c index 03199945..c449815f 100644 --- a/pages.c +++ b/pages.c @@ -38,6 +38,11 @@ /// Bitfield which records which layers are backed up in Page 0. static word Last_backed_up_layers=0; +/// Total number of unique bitmaps (layers, animation frames, backups) +long Stats_pages_number=0; +/// Total memory used by bitmaps (layers, animation frames, backups) +long long Stats_pages_memory=0; + /// Allocate and initialize a new page. T_Page * New_page(byte nb_layers) { @@ -79,22 +84,31 @@ byte * New_layer(long pixel_size) short * ptr = malloc(sizeof(short)+pixel_size); if (ptr==NULL) return NULL; + + // Stats + Stats_pages_number++; + Stats_pages_memory+=pixel_size; *ptr = 1; return (byte *)(ptr+1); } /// Free a layer -void Free_layer(byte * layer) +void Free_layer(T_Page * page, byte layer) { - short * ptr = (short *)(layer); - if (layer==NULL) + short * ptr; + if (page->Image[layer]==NULL) return; + ptr = (short *)(page->Image[layer]); if (-- (*(ptr-1))) // Users-- return; else free(ptr-1); + + // Stats + Stats_pages_number--; + Stats_pages_memory-=page->Width * page->Height; } /// Duplicate a layer (new reference) @@ -321,7 +335,7 @@ void Clear_page(T_Page * page) int i; for (i=0; iNb_layers; i++) { - Free_layer(page->Image[i]); + Free_layer(page, i); page->Image[i]=NULL; } page->Width=0; @@ -1019,7 +1033,7 @@ byte Delete_layer(T_List_of_pages *list, byte layer) // and so it will be cleared anyway. // Smart freeing of the pixel data - Free_layer(list->Pages->Image[layer]); + Free_layer(list->Pages, layer); list->Pages->Nb_layers--; // Move around the pointers. This part is going to be tricky when we diff --git a/pages.h b/pages.h index bc451cb5..51c3c7b2 100644 --- a/pages.h +++ b/pages.h @@ -90,4 +90,13 @@ void Update_depth_buffer(void); void Redraw_layered_image(void); void Redraw_current_layer(void); +/// +/// STATISTICS +/// + +/// Total number of unique bitmaps (layers, animation frames, backups) +extern long Stats_pages_number; +/// Total memory used by bitmaps (layers, animation frames, backups) +extern long long Stats_pages_memory; + #endif From abb6204757fe0dcc94aefa41528ab54cc0160ea4 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Wed, 14 Oct 2009 00:13:49 +0000 Subject: [PATCH 20/25] [layers] Limited to 32 layers. (previously there was no limit and the 16-bit depth buffer wrapped). Fixed a display bug after picture transforms or layers add/del. git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1075 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- engine.c | 2 ++ global.h | 4 ++-- main.c | 4 ++-- pages.c | 26 +++++++++++++++----------- pages.h | 4 ++-- special.c | 4 ++-- transform.c | 1 + 7 files changed, 26 insertions(+), 19 deletions(-) diff --git a/engine.c b/engine.c index 2c2f9df1..ae230458 100644 --- a/engine.c +++ b/engine.c @@ -1042,6 +1042,7 @@ void Main_handler(void) Hide_cursor(); Display_all_screen(); Display_cursor(); + End_of_modification(); } action++; break; @@ -1054,6 +1055,7 @@ void Main_handler(void) Hide_cursor(); Display_all_screen(); Display_cursor(); + End_of_modification(); } action++; break; diff --git a/global.h b/global.h index 9f98c0c3..e7104a12 100644 --- a/global.h +++ b/global.h @@ -348,7 +348,7 @@ GFX2_GLOBAL short Main_magnifier_offset_Y; /// Index of layer currently being edited GFX2_GLOBAL int Main_current_layer; /// Bitfield that records which layers are visible. 2^0 for 0, 2^1 for 1, 2^2 for 2, etc. -GFX2_GLOBAL word Main_layers_visible; +GFX2_GLOBAL dword Main_layers_visible; // -- Spare page data @@ -412,7 +412,7 @@ GFX2_GLOBAL short Spare_magnifier_offset_Y; /// Index of layer currently being edited GFX2_GLOBAL short Spare_current_layer; /// Bitfield that records which layers are visible. 2^0 for 0, 2^1 for 1, 2^2 for 2, etc. -GFX2_GLOBAL word Spare_layers_visible; +GFX2_GLOBAL dword Spare_layers_visible; // -- Image backups /// Backup of the current screen, used during drawing when FX feedback is OFF. diff --git a/main.c b/main.c index 650563a6..2daddfbb 100644 --- a/main.c +++ b/main.c @@ -370,9 +370,9 @@ int Init_program(int argc,char * argv[]) Main_fileselector_offset=0; // Au début, le fileselect est en haut de la liste des fichiers Main_format=0; Main_current_layer=0; - Main_layers_visible=0xFFFF; + Main_layers_visible=0xFFFFFFFF; Spare_current_layer=0; - Spare_layers_visible=0xFFFF; + Spare_layers_visible=0xFFFFFFFF; Spare_fileselector_position=0; Spare_fileselector_offset=0; diff --git a/pages.c b/pages.c index c449815f..e591b5c0 100644 --- a/pages.c +++ b/pages.c @@ -36,7 +36,7 @@ /// /// Bitfield which records which layers are backed up in Page 0. -static word Last_backed_up_layers=0; +static dword Last_backed_up_layers=0; /// Total number of unique bitmaps (layers, animation frames, backups) long Stats_pages_number=0; @@ -483,7 +483,7 @@ void Free_last_page_of_list(T_List_of_pages * list) } // layer_mask tells which layers have to be fresh copies instead of references -int Create_new_page(T_Page * new_page, T_List_of_pages * list, word layer_mask) +int Create_new_page(T_Page * new_page, T_List_of_pages * list, dword layer_mask) { // Cette fonction crée une nouvelle page dont les attributs correspondent à @@ -697,7 +697,7 @@ int Backup_with_new_dimensions(int upload,byte layers,int width,int height) Upload_infos_page_main(new_page); new_page->Width=width; new_page->Height=height; - if (Create_new_page(new_page,Main_backups,0xFFFF)) + if (Create_new_page(new_page,Main_backups,0xFFFFFFFF)) { for (i=0; iWidth=width; new_page->Height=height; - if (Create_new_page(new_page,Spare_backups,0xFFFF)) + if (Create_new_page(new_page,Spare_backups,0xFFFFFFFF)) { byte i; @@ -764,7 +764,7 @@ void Backup(void) Backup_layers(1<Pages; + + // Hard limit of 32 at the moment, because layer bitmasks are 32bit. + if (list->Pages->Nb_layers == 32) + return 1; // Keep the position reasonable if (layer > list->Pages->Nb_layers) @@ -987,9 +991,9 @@ byte Add_layer(T_List_of_pages *list, byte layer) // Update the flags of visible layers. { - word layers_before; - word layers_after; - word *visible_layers_flag; + dword layers_before; + dword layers_after; + dword *visible_layers_flag; // Determine if we're modifying the spare or the main page. if (list == Main_backups) @@ -1048,9 +1052,9 @@ byte Delete_layer(T_List_of_pages *list, byte layer) // Update the flags of visible layers. { - word layers_before; - word layers_after; - word *visible_layers_flag; + dword layers_before; + dword layers_after; + dword *visible_layers_flag; byte new_current_layer; // Determine if we're modifying the spare or the main page. diff --git a/pages.h b/pages.h index 51c3c7b2..691ff668 100644 --- a/pages.h +++ b/pages.h @@ -62,7 +62,7 @@ int Allocate_list_of_pages(T_List_of_pages * list); void Backward_in_list_of_pages(T_List_of_pages * list); void Advance_in_list_of_pages(T_List_of_pages * list); void Free_last_page_of_list(T_List_of_pages * list); -int Create_new_page(T_Page * new_page,T_List_of_pages * current_list, word layer_mask); +int Create_new_page(T_Page * new_page,T_List_of_pages * current_list, dword layer_mask); void Change_page_number_of_list(T_List_of_pages * list,int number); void Free_page_of_a_list(T_List_of_pages * list); @@ -79,7 +79,7 @@ int Backup_and_resize_the_spare(int width,int height); /// Backup with a new copy for the working layer, and references for all others. void Backup(void); /// Backup with a new copy of some layers (the others are references). -void Backup_layers(word layer_mask); +void Backup_layers(dword layer_mask); void Undo(void); void Redo(void); void Free_current_page(void); // 'Kill' button diff --git a/special.c b/special.c index 06f17e7e..5b29f155 100644 --- a/special.c +++ b/special.c @@ -481,10 +481,10 @@ void Layer_activate(short layer, short side) // Right-click on current layer if (Main_current_layer == layer) { - if (Main_layers_visible == (1< Date: Sun, 18 Oct 2009 19:06:07 +0000 Subject: [PATCH 21/25] [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 --- engine.c | 84 +++++++++++++++++++++++++++++++++++++++++ loadsave.c | 109 +++++++++++++++++++++++++++++++++-------------------- misc.c | 4 +- pages.c | 29 ++++++++++++-- pages.h | 2 + struct.h | 5 ++- 6 files changed, 185 insertions(+), 48 deletions(-) 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; From 3037d1a84e377e2b89b020071e0a03bd26924a52 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sun, 18 Oct 2009 19:14:34 +0000 Subject: [PATCH 22/25] [layers] Fixed crash on png saving (thanks Roberto) git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1078 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- loadsave.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loadsave.c b/loadsave.c index e46c3a2d..68f6b33c 100644 --- a/loadsave.c +++ b/loadsave.c @@ -6881,7 +6881,7 @@ void Save_PNG(void) /* ecriture des pixels de l'image */ Row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * Main_image_height); - pixel_ptr = (Read_pixel_function==Read_pixel_from_current_screen)?Main_screen:Brush; + pixel_ptr = (Read_pixel_function==Read_pixel_from_brush)?Brush:Main_screen; for (y=0; y Date: Sun, 1 Nov 2009 14:31:36 +0000 Subject: [PATCH 23/25] [layers] Adapted lua bindings to draw/read in current layer (untested) git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1134 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- factory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/factory.c b/factory.c index e0ebd24d..5034e97f 100644 --- a/factory.c +++ b/factory.c @@ -84,14 +84,14 @@ int L_GetPictureSize(lua_State* L) int L_PutPicturePixel(lua_State* L) { - Pixel_in_current_screen(lua_tonumber(L, 1), lua_tonumber(L, 2), + Pixel_in_current_layer(lua_tonumber(L, 1), lua_tonumber(L, 2), lua_tonumber(L, 3),1); return 0; // no values returned for lua } int L_GetPicturePixel(lua_State* L) { - uint8_t c = Read_pixel_from_current_screen(lua_tonumber(L, 1), + uint8_t c = Read_pixel_from_current_layer(lua_tonumber(L, 1), lua_tonumber(L, 2)); lua_pushinteger(L, c); return 1; From 3ede1f3a5670b801254cf458cb3106d8397c25a9 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sun, 1 Nov 2009 23:22:43 +0000 Subject: [PATCH 24/25] [layers] NOLAYERS option at compile time. Unfinished. git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1140 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- Makefile | 10 +++++++++- buttons.c | 3 ++- engine.c | 9 ++++++--- factory.c | 2 +- global.h | 8 -------- graph.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++ graph.h | 5 +++++ loadsave.c | 1 + main.c | 2 ++ misc.c | 42 +--------------------------------------- misc.h | 4 ---- pages.c | 56 +++++++++++++++++++++++++++++++++++++++--------------- pages.h | 4 ++++ special.c | 13 +++++++++++++ 14 files changed, 134 insertions(+), 74 deletions(-) diff --git a/Makefile b/Makefile index cf0e13f3..8beba9db 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ ifdef COMSPEC RMDIR = rmdir CP = cp BIN = grafx2.exe - COPT = -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -g -ggdb `sdl-config --cflags` $(TTFCOPT) $(JOYCOPT) $(LUACOPT) + COPT = -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -g -ggdb `sdl-config --cflags` $(TTFCOPT) $(JOYCOPT) $(LUACOPT) $(LAYERCOPT) LOPT = `sdl-config --libs` -lSDL_image $(TTFLOPT) -lpng $(LUALOPT) CC = gcc OBJDIR = obj/win32 @@ -274,6 +274,14 @@ else JOYCOPT = endif +#To speed up rendering, can disable the layered editing +# with NOLAYERS=1 +ifeq ($(NOLAYERS),1) + LAYERCOPT = -DNOLAYERS +else + LAYERCOPT = +endif + ### And now for the real build rules ### .PHONY : all debug release clean depend zip version force install uninstall diff --git a/buttons.c b/buttons.c index 3b3cde15..85c3ec2c 100644 --- a/buttons.c +++ b/buttons.c @@ -1013,6 +1013,7 @@ void Draw_one_skin_name(word x, word y, word index, byte highlighted) #define SWAP_BYTES(a,b) { byte c=a; a=b; b=c;} #define SWAP_WORDS(a,b) { word c=a; a=b; b=c;} +#define SWAP_DWORDS(a,b) { dword c=a; a=b; b=c;} #define SWAP_SHORTS(a,b) { short c=a; a=b; b=c;} #define SWAP_FLOATS(a,b) { float c=a; a=b; b=c;} @@ -1286,7 +1287,7 @@ void Button_Page(void) SWAP_WORDS (Main_fileselector_position,Spare_fileselector_position) SWAP_WORDS (Main_fileselector_offset,Spare_fileselector_offset) SWAP_SHORTS(Main_current_layer,Spare_current_layer) - SWAP_WORDS (Main_layers_visible,Spare_layers_visible) + SWAP_DWORDS (Main_layers_visible,Spare_layers_visible) // A la fin, on affiche l'écran for (factor_index=0; ZOOM_FACTOR[factor_index]!=Main_magnifier_factor; factor_index++); diff --git a/engine.c b/engine.c index 6b040a9b..b83e91a0 100644 --- a/engine.c +++ b/engine.c @@ -1055,6 +1055,7 @@ void Main_handler(void) Backup_layers(0); if (!Delete_layer(Main_backups,Main_current_layer)) { + Update_screen_targets(); Redraw_layered_image(); Hide_cursor(); Display_all_screen(); @@ -1070,7 +1071,8 @@ void Main_handler(void) Backup_layers(1<<(Main_current_layer-1)); Merge_layer(); - + + Update_screen_targets(); Redraw_layered_image(); Hide_cursor(); Display_all_screen(); @@ -1103,7 +1105,8 @@ void Main_handler(void) Main_layers_visible ^= (3 << Main_current_layer); } Main_current_layer++; - + + Update_screen_targets(); Redraw_layered_image(); Hide_cursor(); Display_all_screen(); @@ -1138,7 +1141,7 @@ void Main_handler(void) Main_layers_visible ^= (3 << (Main_current_layer-1)); } Main_current_layer--; - + Update_screen_targets(); Redraw_layered_image(); Hide_cursor(); Display_all_screen(); diff --git a/factory.c b/factory.c index 5034e97f..e14fd12a 100644 --- a/factory.c +++ b/factory.c @@ -85,7 +85,7 @@ int L_GetPictureSize(lua_State* L) int L_PutPicturePixel(lua_State* L) { Pixel_in_current_layer(lua_tonumber(L, 1), lua_tonumber(L, 2), - lua_tonumber(L, 3),1); + lua_tonumber(L, 3)); return 0; // no values returned for lua } diff --git a/global.h b/global.h index d45ad4db..32765b6b 100644 --- a/global.h +++ b/global.h @@ -415,14 +415,6 @@ GFX2_GLOBAL T_List_of_pages * Main_backups; GFX2_GLOBAL T_List_of_pages * Spare_backups; -// -- Layers data - -/// Array of two images, that contains the "flattened" version of the visible layers. -GFX2_GLOBAL T_Image Visible_image[2]; -GFX2_GLOBAL T_Image Visible_image_depth_buffer; -/// Index that is 0 or 1, it ways which of the two ::Visible_image[] contains the current image (the other contains the data from last backup) -GFX2_GLOBAL int Visible_image_index; - // -- Brush data /// Pixel data of the current brush. diff --git a/graph.c b/graph.c index e5411ae9..a7a6870a 100644 --- a/graph.c +++ b/graph.c @@ -2867,3 +2867,52 @@ void Redraw_grid(short x, short y, unsigned short w, unsigned short h) col+= Snap_width*Main_magnifier_factor; } } + +byte Read_pixel_from_current_screen (word x,word y) +{ + #ifndef NOLAYERS + byte depth; + byte color; + color = *(Main_screen+y*Main_image_width+x); + if (color != Main_backups->Pages->Transparent_color) // transparent color + return color; + + depth = *(Visible_image_depth_buffer.Image+x+y*Main_image_width); + return *(Main_backups->Pages->Image[depth] + x+y*Main_image_width); + #else + return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer]); + #endif +} + +void Pixel_in_current_screen (word x,word y,byte color,int with_preview) +{ + #ifndef NOLAYERS + byte depth = *(Visible_image_depth_buffer.Image+x+y*Main_image_width); + *(Main_backups->Pages->Image[Main_current_layer] + x+y*Main_image_width)=color; + if ( depth <= Main_current_layer) + { + 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); + + *(x+y*Main_image_width+Main_screen)=color; + + if (with_preview) + Pixel_preview(x,y,color); + } + #else + *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer])=color; + if (with_preview) + Pixel_preview(x,y,color); + #endif +} + +void Pixel_in_current_layer(word x,word y, byte color) +{ + *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer])=color; +} + +byte Read_pixel_from_current_layer(word x,word y) +{ + return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer]); +} diff --git a/graph.h b/graph.h index 08154832..96f12f99 100644 --- a/graph.h +++ b/graph.h @@ -111,3 +111,8 @@ extern Func_pixel Pixel_figure; void Update_part_of_screen(short x, short y, short width, short height); void Redraw_grid(short x, short y, unsigned short w, unsigned short h); + +void Pixel_in_current_screen (word x,word y,byte color,int with_preview); +void Pixel_in_current_layer(word x,word y, byte color); +byte Read_pixel_from_current_screen (word x,word y); +byte Read_pixel_from_current_layer(word x,word y); diff --git a/loadsave.c b/loadsave.c index 5395efcd..517f6a6b 100644 --- a/loadsave.c +++ b/loadsave.c @@ -37,6 +37,7 @@ #include "io.h" #include "loadsave.h" #include "misc.h" +#include "graph.h" #include "op_c.h" #include "pages.h" #include "palette.h" diff --git a/main.c b/main.c index 6ec7e6b4..9b6bad14 100644 --- a/main.c +++ b/main.c @@ -639,6 +639,7 @@ int Init_program(int argc,char * argv[]) Spare_image_width=Screen_width/Pixel_width; Spare_image_height=Screen_height/Pixel_height; + #ifndef NOLAYERS Visible_image[0].Width = 0; Visible_image[0].Height = 0; Visible_image[0].Image = NULL; @@ -648,6 +649,7 @@ int Init_program(int argc,char * argv[]) Visible_image_depth_buffer.Width = 0; Visible_image_depth_buffer.Height = 0; Visible_image_depth_buffer.Image = NULL; + #endif // Allocation de mémoire pour les différents écrans virtuels (et brosse) if (Init_all_backup_lists(Screen_width,Screen_height)==0) diff --git a/misc.c b/misc.c index 162d35b8..a5937a58 100644 --- a/misc.c +++ b/misc.c @@ -34,6 +34,7 @@ #include "windows.h" #include "palette.h" #include "input.h" +#include "graph.h" ///Count used palette indexes in the whole picture ///Return the total number of different colors @@ -216,47 +217,6 @@ byte Read_pixel_from_brush (word x, word y) return *(Brush + y * Brush_width + x); } - -byte Read_pixel_from_current_screen (word x,word y) -{ - byte depth; - byte color; - color = *(Main_screen+y*Main_image_width+x); - if (color != Main_backups->Pages->Transparent_color) // transparent color - return color; - - depth = *(Visible_image_depth_buffer.Image+x+y*Main_image_width); - return *(Main_backups->Pages->Image[depth] + x+y*Main_image_width); - // return *(Main_screen+y*Main_image_width+x); -} - -void Pixel_in_current_screen (word x,word y,byte color,int with_preview) -{ - byte depth = *(Visible_image_depth_buffer.Image+x+y*Main_image_width); - *(Main_backups->Pages->Image[Main_current_layer] + x+y*Main_image_width)=color; - if ( depth <= Main_current_layer) - { - 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); - - *(x+y*Main_image_width+Main_screen)=color; - - if (with_preview) - Pixel_preview(x,y,color); - } -} - -void Pixel_in_current_layer(word x,word y, byte color) -{ - *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer])=color; -} - -byte Read_pixel_from_current_layer(word x,word y) -{ - return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer]); -} - void Replace_a_color(byte old_color, byte new_color) { word x; diff --git a/misc.h b/misc.h index 8dd97925..d91f0f74 100644 --- a/misc.h +++ b/misc.h @@ -36,15 +36,11 @@ dword Round_div(dword numerator,dword divisor); word Count_used_colors(dword * usage); word Count_used_colors_area(dword* usage, word start_x, word start_y, word width, word height); word Count_used_colors_screen_area(dword* usage, word start_x, word start_y, word width, word height); -void Pixel_in_current_screen (word x,word y,byte color,int with_preview); void Pixel_in_brush (word x,word y,byte color); -byte Read_pixel_from_current_screen (word x,word y); byte Read_pixel_from_spare_screen(word x,word y); byte Read_pixel_from_backup_screen (word x,word y); byte Read_pixel_from_feedback_screen (word x,word y); byte Read_pixel_from_brush (word x,word y); -byte Read_pixel_from_current_layer(word x,word y); -void Pixel_in_current_layer(word x,word y, byte color); void Ellipse_compute_limites(short horizontal_radius,short vertical_radius); // Calcule les valeurs suivantes en fonction des deux paramètres: diff --git a/pages.c b/pages.c index 80c139b9..cbfa0d36 100644 --- a/pages.c +++ b/pages.c @@ -31,6 +31,15 @@ #include "misc.h" #include "windows.h" +// -- Layers data + +/// Array of two images, that contains the "flattened" version of the visible layers. +#ifndef NOLAYERS +T_Image Visible_image[2]; +T_Image Visible_image_depth_buffer; +#endif + + /// /// GESTION DES PAGES /// @@ -162,6 +171,7 @@ void Download_infos_page_main(T_Page * page) void Redraw_layered_image(void) { + #ifndef NOLAYERS // Re-construct the image with the visible layers int layer; // First layer @@ -202,11 +212,15 @@ void Redraw_layered_image(void) } } } + #else + Update_screen_targets(); + #endif Download_infos_backup(Main_backups); } void Update_depth_buffer(void) { + #ifndef NOLAYERS // Re-construct the depth buffer with the visible layers. // This function doesn't touch the visible buffer, it assumes // that it was already up-to-date. (Ex. user only changed active layer) @@ -247,11 +261,13 @@ void Update_depth_buffer(void) } } } + #endif Download_infos_backup(Main_backups); } void Redraw_current_layer(void) { +#ifndef NOLAYERS int i; for (i=0; iPages->Image[Main_current_layer]; - // Visible_image[0].Image; else FX_feedback_screen=list->Pages->Next->Image[Main_current_layer]; - // Visible_image[1].Image; } void Clear_page(T_Page * page) @@ -567,26 +582,35 @@ int Update_buffer(T_Image * image, int width, int height) return 1; } +void Update_screen_targets(void) +{ + #ifndef NOLAYERS + Main_screen=Visible_image[0].Image; + Screen_backup=Visible_image[1].Image; + #else + Main_screen=Main_backups->Pages->Image[Main_current_layer]; + Screen_backup=Main_backups->Pages->Next->Image[Main_current_layer]; + #endif +} + /// Update all the special image buffers, if necessary. int Update_buffers(int width, int height) { +#ifndef NOLAYERS if (! Update_buffer(&Visible_image_depth_buffer, width, height)) return 0; - if (! Update_buffer(&Visible_image[0], width, height)) return 0; - Main_screen=Visible_image[0].Image; - if (! Update_buffer(&Visible_image[1], width, height)) - return 0; - Screen_backup=Visible_image[1].Image; - + return 0; +#endif + Update_screen_targets(); return 1; } - /// - /// GESTION DES BACKUPS - /// +/// +/// GESTION DES BACKUPS +/// int Init_all_backup_lists(int width,int height) { @@ -611,7 +635,7 @@ int Init_all_backup_lists(int width,int height) return 0; memset(Main_backups->Pages->Image[i], 0, width*height); } - +#ifndef NOLAYERS Visible_image[0].Width = 0; Visible_image[0].Height = 0; Visible_image[0].Image = NULL; @@ -623,14 +647,15 @@ int Init_all_backup_lists(int width,int height) Visible_image_depth_buffer.Width = 0; Visible_image_depth_buffer.Height = 0; Visible_image_depth_buffer.Image = NULL; - +#endif if (!Update_buffers(width, height)) return 0; +#ifndef NOLAYERS // For speed, instead of Redraw_layered_image() we'll directly set the buffers. memset(Visible_image[0].Image, 0, width*height); memset(Visible_image[1].Image, 0, width*height); memset(Visible_image_depth_buffer.Image, 0, width*height); - +#endif Download_infos_page_main(Main_backups->Pages); Download_infos_backup(Main_backups); @@ -930,10 +955,11 @@ void End_of_modification(void) //Update_buffers(Main_image_width, Main_image_height); - +#ifndef NOLAYERS memcpy(Visible_image[1].Image, Visible_image[0].Image, Main_image_width*Main_image_height); +#endif Download_infos_backup(Main_backups); /* diff --git a/pages.h b/pages.h index c36d98dc..2e434c50 100644 --- a/pages.h +++ b/pages.h @@ -30,6 +30,8 @@ /////////////////////////// BACKUP /////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// +extern T_Image Visible_image[2]; +extern T_Image Visible_image_depth_buffer; /// /// INDIVIDUAL PAGES @@ -92,6 +94,8 @@ void Update_depth_buffer(void); void Redraw_layered_image(void); void Redraw_current_layer(void); +void Update_screen_targets(void); + /// /// STATISTICS /// diff --git a/special.c b/special.c index 5b29f155..0b0c1ce1 100644 --- a/special.c +++ b/special.c @@ -476,6 +476,9 @@ void Layer_activate(short layer, short side) // Keep a copy of which layers were visible old_layers = Main_layers_visible; + + #ifndef NOLAYERS + if (side == RIGHT_SIDE) { // Right-click on current layer @@ -504,6 +507,16 @@ void Layer_activate(short layer, short side) Main_current_layer = layer; Main_layers_visible |= 1< Date: Mon, 2 Nov 2009 00:10:59 +0000 Subject: [PATCH 25/25] [layers] continuted work on no-layer option. No more crash. git-svn-id: svn://pulkomandy.tk/GrafX2/branches/layers@1141 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 3 +++ pages.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/buttons.c b/buttons.c index 85c3ec2c..07ae8c05 100644 --- a/buttons.c +++ b/buttons.c @@ -1286,9 +1286,12 @@ void Button_Page(void) SWAP_BYTES (Main_format,Spare_format) SWAP_WORDS (Main_fileselector_position,Spare_fileselector_position) SWAP_WORDS (Main_fileselector_offset,Spare_fileselector_offset) + SWAP_SHORTS(Main_current_layer,Spare_current_layer) SWAP_DWORDS (Main_layers_visible,Spare_layers_visible) + Update_screen_targets(); + // A la fin, on affiche l'écran for (factor_index=0; ZOOM_FACTOR[factor_index]!=Main_magnifier_factor; factor_index++); Change_magnifier_factor(factor_index); diff --git a/pages.c b/pages.c index cbfa0d36..da98467e 100644 --- a/pages.c +++ b/pages.c @@ -959,6 +959,8 @@ void End_of_modification(void) memcpy(Visible_image[1].Image, Visible_image[0].Image, Main_image_width*Main_image_height); +#else + Update_screen_targets(); #endif Download_infos_backup(Main_backups);