diff --git a/Makefile b/Makefile index 3f6bce18..7732ea29 100644 --- a/Makefile +++ b/Makefile @@ -236,7 +236,7 @@ endif .PHONY : all debug release clean depend zip version force install uninstall # This is the list of the objects we want to build. Dependancies are built by "make depend" automatically. -OBJ = $(OBJDIR)/main.o $(OBJDIR)/init.o $(OBJDIR)/graph.o $(OBJDIR)/sdlscreen.o $(OBJDIR)/misc.o $(OBJDIR)/special.o $(OBJDIR)/buttons.o $(OBJDIR)/palette.o $(OBJDIR)/help.o $(OBJDIR)/operatio.o $(OBJDIR)/pages.o $(OBJDIR)/loadsave.o $(OBJDIR)/readline.o $(OBJDIR)/engine.o $(OBJDIR)/filesel.o $(OBJDIR)/op_c.o $(OBJDIR)/readini.o $(OBJDIR)/saveini.o $(OBJDIR)/shade.o $(OBJDIR)/keyboard.o $(OBJDIR)/io.o $(OBJDIR)/version.o $(OBJDIR)/text.o $(OBJDIR)/SFont.o $(OBJDIR)/setup.o $(OBJDIR)/pxsimple.o $(OBJDIR)/pxtall.o $(OBJDIR)/pxwide.o $(OBJDIR)/pxdouble.o $(OBJDIR)/windows.o $(OBJDIR)/brush.o $(OBJDIR)/realpath.o $(OBJDIR)/mountlist.o $(OBJDIR)/input.o $(OBJDIR)/hotkeys.o +OBJ = $(OBJDIR)/main.o $(OBJDIR)/init.o $(OBJDIR)/graph.o $(OBJDIR)/sdlscreen.o $(OBJDIR)/misc.o $(OBJDIR)/special.o $(OBJDIR)/buttons.o $(OBJDIR)/palette.o $(OBJDIR)/help.o $(OBJDIR)/operatio.o $(OBJDIR)/pages.o $(OBJDIR)/loadsave.o $(OBJDIR)/readline.o $(OBJDIR)/engine.o $(OBJDIR)/filesel.o $(OBJDIR)/op_c.o $(OBJDIR)/readini.o $(OBJDIR)/saveini.o $(OBJDIR)/shade.o $(OBJDIR)/keyboard.o $(OBJDIR)/io.o $(OBJDIR)/version.o $(OBJDIR)/text.o $(OBJDIR)/SFont.o $(OBJDIR)/setup.o $(OBJDIR)/pxsimple.o $(OBJDIR)/pxtall.o $(OBJDIR)/pxwide.o $(OBJDIR)/pxdouble.o $(OBJDIR)/pxtriple.o $(OBJDIR)/pxtall2.o $(OBJDIR)/pxwide2.o $(OBJDIR)/pxquad.o $(OBJDIR)/windows.o $(OBJDIR)/brush.o $(OBJDIR)/realpath.o $(OBJDIR)/mountlist.o $(OBJDIR)/input.o $(OBJDIR)/hotkeys.o $(OBJDIR)/transform.o all : $(BIN) diff --git a/Makefile.dep b/Makefile.dep index 82106eee..992c6c4e 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -1,6 +1,6 @@ $(OBJDIR)/SFont.o: SFont.c SFont.h $(OBJDIR)/brush.o: brush.c global.h struct.h const.h graph.h misc.h errors.h \ - windows.h sdlscreen.h + windows.h sdlscreen.h brush.h $(OBJDIR)/buttons.o: buttons.c const.h struct.h global.h misc.h graph.h engine.h \ readline.h filesel.h loadsave.h init.h buttons.h operatio.h pages.h \ errors.h readini.h saveini.h shade.h io.h help.h text.h sdlscreen.h \ @@ -10,21 +10,21 @@ $(OBJDIR)/engine.o: engine.c const.h struct.h global.h graph.h misc.h special.h input.h engine.h $(OBJDIR)/filesel.o: filesel.c const.h struct.h global.h misc.h errors.h io.h \ windows.h sdlscreen.h loadsave.h mountlist.h engine.h readline.h \ - input.h help.h + input.h help.h filesel.h $(OBJDIR)/graph.o: graph.c global.h struct.h const.h engine.h buttons.h pages.h \ errors.h sdlscreen.h graph.h misc.h pxsimple.h pxtall.h pxwide.h \ - pxdouble.h windows.h + pxdouble.h pxtriple.h pxwide2.h pxtall2.h pxquad.h windows.h $(OBJDIR)/help.o: help.c const.h struct.h global.h misc.h engine.h helpfile.h \ help.h sdlscreen.h text.h keyboard.h windows.h input.h hotkeys.h \ errors.h $(OBJDIR)/hotkeys.o: hotkeys.c struct.h const.h global.h hotkeys.h $(OBJDIR)/init.o: init.c const.h struct.h global.h graph.h buttons.h palette.h \ help.h operatio.h misc.h errors.h keyboard.h io.h hotkeys.h setup.h \ - windows.h sdlscreen.h mountlist.h loadsave.h + windows.h sdlscreen.h mountlist.h loadsave.h init.h transform.h $(OBJDIR)/input.o: input.c global.h struct.h const.h keyboard.h sdlscreen.h \ windows.h errors.h misc.h input.h $(OBJDIR)/io.o: io.c struct.h const.h io.h realpath.h -$(OBJDIR)/keyboard.o: keyboard.c global.h struct.h const.h +$(OBJDIR)/keyboard.o: keyboard.c global.h struct.h const.h keyboard.h $(OBJDIR)/loadsave.o: loadsave.c buttons.h struct.h const.h errors.h global.h io.h \ loadsave.h misc.h op_c.h pages.h palette.h sdlscreen.h windows.h $(OBJDIR)/main.o: main.c const.h struct.h global.h graph.h misc.h init.h buttons.h \ @@ -39,27 +39,40 @@ $(OBJDIR)/operatio.o: operatio.c const.h struct.h global.h misc.h engine.h graph $(OBJDIR)/pages.o: pages.c global.h struct.h const.h pages.h errors.h misc.h \ windows.h $(OBJDIR)/palette.o: palette.c const.h struct.h global.h misc.h engine.h readline.h \ - buttons.h pages.h help.h sdlscreen.h errors.h op_c.h windows.h input.h + buttons.h pages.h help.h sdlscreen.h errors.h op_c.h windows.h input.h \ + palette.h $(OBJDIR)/pxdouble.o: pxdouble.c global.h struct.h const.h sdlscreen.h misc.h \ - pxwide.h -$(OBJDIR)/pxsimple.o: pxsimple.c global.h struct.h const.h sdlscreen.h misc.h -$(OBJDIR)/pxtall.o: pxtall.c global.h struct.h const.h sdlscreen.h misc.h \ + pxdouble.h pxwide.h +$(OBJDIR)/pxquad.o: pxquad.c global.h struct.h const.h sdlscreen.h misc.h pxquad.h +$(OBJDIR)/pxsimple.o: pxsimple.c global.h struct.h const.h sdlscreen.h misc.h \ pxsimple.h -$(OBJDIR)/pxwide.o: pxwide.c global.h struct.h const.h sdlscreen.h misc.h -$(OBJDIR)/readini.o: readini.c const.h global.h struct.h misc.h +$(OBJDIR)/pxtall.o: pxtall.c global.h struct.h const.h sdlscreen.h misc.h pxtall.h \ + pxsimple.h +$(OBJDIR)/pxtall2.o: pxtall2.c global.h struct.h const.h sdlscreen.h misc.h \ + pxtall2.h +$(OBJDIR)/pxtriple.o: pxtriple.c global.h struct.h const.h sdlscreen.h misc.h \ + pxtriple.h +$(OBJDIR)/pxwide.o: pxwide.c global.h struct.h const.h sdlscreen.h misc.h pxwide.h +$(OBJDIR)/pxwide2.o: pxwide2.c global.h struct.h const.h sdlscreen.h misc.h \ + pxwide2.h +$(OBJDIR)/readini.o: readini.c const.h global.h struct.h misc.h readini.h $(OBJDIR)/readline.o: readline.c const.h struct.h global.h misc.h errors.h \ sdlscreen.h readline.h windows.h input.h $(OBJDIR)/realpath.o: realpath.c $(OBJDIR)/saveini.o: saveini.c const.h global.h struct.h readini.h io.h errors.h \ - misc.h + misc.h saveini.h $(OBJDIR)/sdlscreen.o: sdlscreen.c global.h struct.h const.h sdlscreen.h errors.h \ misc.h -$(OBJDIR)/setup.o: setup.c struct.h const.h io.h +$(OBJDIR)/setup.o: setup.c struct.h const.h io.h setup.h $(OBJDIR)/shade.o: shade.c global.h struct.h const.h graph.h engine.h misc.h \ - readline.h help.h sdlscreen.h windows.h input.h -$(OBJDIR)/special.o: special.c const.h struct.h global.h graph.h engine.h windows.h + readline.h help.h sdlscreen.h windows.h input.h shade.h +$(OBJDIR)/special.o: special.c const.h struct.h global.h graph.h engine.h windows.h \ + special.h $(OBJDIR)/text.o: text.c SFont.h struct.h const.h global.h sdlscreen.h io.h \ errors.h +$(OBJDIR)/transform.o: transform.c global.h struct.h const.h transform.h engine.h \ + sdlscreen.h windows.h input.h help.h misc.h readline.h buttons.h \ + pages.h $(OBJDIR)/version.o: version.c $(OBJDIR)/windows.o: windows.c windows.h struct.h const.h global.h graph.h engine.h \ misc.h sdlscreen.h errors.h diff --git a/brush.c b/brush.c index c3f33ccc..209aa7ea 100644 --- a/brush.c +++ b/brush.c @@ -718,7 +718,7 @@ void Rotate_90_deg() new_brush=(byte *)malloc(((long)Brush_height)*Brush_width); if (new_brush) { - Rotate_90_deg_lowlevel(Brush,new_brush); + Rotate_90_deg_lowlevel(Brush,new_brush,Brush_width,Brush_height); free(Brush); Brush=new_brush; @@ -1149,75 +1149,32 @@ void Capture_brush_with_lasso(int vertices, short * points,short clear) void Stretch_brush(short x1, short y1, short x2, short y2) { - int offset,line,column; byte * new_brush; - int new_brush_width; // Width de la nouvelle brosse int new_brush_height; // Height de la nouvelle brosse - - int x_pos_in_brush; // Position courante dans l'ancienne brosse - int y_pos_in_brush; - int delta_x_in_brush; // "Vecteur incrémental" du point précédent - int delta_y_in_brush; - int initial_x_pos; // Position X de début de parcours de ligne - int dx,dy; - - dx=(x1=0) - initial_x_pos = 0; // Pas d'inversion en X de la brosse - else - initial_x_pos = (Brush_width<<16)-1; // Inversion en X de la brosse - - free(Smear_brush); // On libère un peu de mémoire + // Free some memory + free(Smear_brush); if ((new_brush=((byte *)malloc(new_brush_width*new_brush_height)))) { - offset=0; - - // Calcul de la valeur initiale de y_pos: - if (dy>=0) - y_pos_in_brush=0; // Pas d'inversion en Y de la brosse - else - y_pos_in_brush=(Brush_height<<16)-1; // Inversion en Y de la brosse - - // Pour chaque ligne - for (line=0;line>16,y_pos_in_brush>>16); - // On passe à la colonne de brosse suivante: - x_pos_in_brush+=delta_x_in_brush; - // On passe au pixel suivant de la nouvelle brosse: - offset++; - } - - // On passe à la ligne de brosse suivante: - y_pos_in_brush+=delta_y_in_brush; - } + Rescale(Brush, Brush_width, Brush_height, new_brush, new_brush_width, new_brush_height, x2b) + if (c>d) + return a>c?a:c; + else + return a>d?a:d; + else + if (c>d) + return b>c?b:c; + else + return b>d?b:d; +} + +// Recursive function for linear distortion. +void Draw_brush_linear_distort(long int tex_min_x, + long int tex_min_y, + long int tex_max_x, + long int tex_max_y, + long int x1, + long int y1, + long int x2, + long int y2, + long int x3, + long int y3, + long int x4, + long int y4) +{ + static byte color; + // bounding rectangle + static long int min_x, max_x, min_y, max_y; + + min_x=Min4(x1,x2,x3,x4); + max_x=Max4(x1,x2,x3,x4); + min_y=Min4(y1,y2,y3,y4); + max_y=Max4(y1,y2,y3,y4); + + if ((max_x>>16) - (min_x>>16) <= 1 && (max_y>>16) - (min_y>>16) <= 1) + //if (max_x - min_x <= 1<<16 && max_y - min_y <= 1<<16) + { + if ((min_x<(max_x&0x7FFF0000)) && (min_y<(max_y&0x7FFF0000))) + { + color=Read_pixel_from_brush((tex_min_x)>>16,(tex_min_y)>>16); + if (color!=Back_color) + Pixel_for_distort(min_x>>16,min_y>>16,color); + } + return; + } + // Cut in 4 quarters and repeat + // "top left" + Draw_brush_linear_distort(tex_min_x, + tex_min_y, + (tex_min_x+tex_max_x)>>1, + (tex_min_y+tex_max_y)>>1, + x1, + y1, + (x1+x2)>>1, + (y1+y2)>>1, + (x1+x2+x3+x4)>>2, + (y1+y2+y3+y4)>>2, + (x1+x4)>>1, + (y1+y4)>>1); + + // "top right" + Draw_brush_linear_distort((tex_min_x+tex_max_x)>>1, + tex_min_y, + tex_max_x, + (tex_min_y+tex_max_y)>>1, + (x1+x2)>>1, + (y1+y2)>>1, + x2, + y2, + (x2+x3)>>1, + (y2+y3)>>1, + (x1+x2+x3+x4)>>2, + (y1+y2+y3+y4)>>2); + + // "bottom right" + Draw_brush_linear_distort((tex_min_x+tex_max_x)>>1, + (tex_min_y+tex_max_y)>>1, + tex_max_x, + tex_max_y, + (x1+x2+x3+x4)>>2, + (y1+y2+y3+y4)>>2, + (x2+x3)>>1, + (y2+y3)>>1, + x3, + y3, + (x3+x4)>>1, + (y3+y4)>>1); + + // "bottom left" + Draw_brush_linear_distort(tex_min_x, + (tex_min_y+tex_max_y)>>1, + (tex_min_x+tex_max_x)>>1, + tex_max_y, + (x1+x4)>>1, + (y1+y4)>>1, + (x1+x2+x3+x4)>>2, + (y1+y2+y3+y4)>>2, + (x3+x4)>>1, + (y3+y4)>>1, + x4, + y4); + + return; +} + +/// Draws a distorted version of the brush, mapped over the given quad (picture coordinates). +void Distort_brush_preview(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4) +{ + Pixel_for_distort=Pixel_figure_preview; + Draw_brush_linear_distort(0, 0, (Brush_width<<16), (Brush_height<<16), (x1<<16), (y1<<16), (x2<<16), (y2<<16), (x3<<16), (y3<<16), (x4<<16), (y4<<16)); +} + +/// Modifies the current brush, mapping it over the given quad. +void Distort_brush(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4) +{ + short min_x, max_x, min_y, max_y; + short width, height; + byte * new_brush; + byte * new_smear_brush; + short new_smear_brush_width; + short new_smear_brush_height; + + // Move all coordinates to start on (0,0) + min_x=Min4(x1,x2,x3,x4); + max_x=Max4(x1,x2,x3,x4); + min_y=Min4(y1,y2,y3,y4); + max_y=Max4(y1,y2,y3,y4); + + x1-=min_x; + x2-=min_x; + x3-=min_x; + x4-=min_x; + + y1-=min_y; + y2-=min_y; + y3-=min_y; + y4-=min_y; + + width=Max(max_x-min_x, 1); + height=Max(max_y-min_y, 1); + + new_smear_brush_width=(width>MAX_PAINTBRUSH_SIZE)?width:MAX_PAINTBRUSH_SIZE; + new_smear_brush_height=(height>MAX_PAINTBRUSH_SIZE)?height:MAX_PAINTBRUSH_SIZE; + + new_smear_brush=(byte *)malloc(((long)new_smear_brush_height)*new_smear_brush_width); + if (! new_smear_brush) + { + // Out of memory while allocating new smear brush + Error(0); + return; + } + + new_brush=((byte *)malloc((long)width*height)); + if (!new_brush) + { + // Out of memory while allocating new brush + Error(0); + free(new_smear_brush); + return; + } + + // Fill the new brush with backcolor, originally. + memset(new_brush,Back_color,((long)width)*height); + + // Call distort routine + Pixel_for_distort=Pixel_in_distort_buffer; + Distort_buffer=new_brush; + Distort_buffer_width=width; + Draw_brush_linear_distort(0, 0, (Brush_width<<16), (Brush_height<<16), (x1<<16), (y1<<16), (x2<<16), (y2<<16), (x3<<16), (y3<<16), (x4<<16), (y4<<16)); + + // Free old brushes + free(Smear_brush); + free(Brush); + + // Point to the new ones + Brush=new_brush; + Brush_width=width; + Brush_height=height; + + Smear_brush=new_smear_brush; + Smear_brush_width=new_smear_brush_width; + Smear_brush_height=new_smear_brush_height; +} //------------------------- Rotation de la brosse --------------------------- diff --git a/brush.h b/brush.h index 8ffba112..e2e09a02 100644 --- a/brush.h +++ b/brush.h @@ -68,6 +68,18 @@ void Rotate_brush_preview(float angle); Remap the brush palette to the nearest color in the picture one. Used when switching to the spare page. */ + +/*! + Distort the brush on the screen. +*/ +void Distort_brush_preview(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4); + +/*! + Replace the brush by a distorted version of itself. +*/ +void Distort_brush(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4); + + void Remap_brush(void); /*! diff --git a/buttons.c b/buttons.c index 5a3b40b7..01972c32 100644 --- a/buttons.c +++ b/buttons.c @@ -1367,11 +1367,15 @@ void Button_Resolution(void) char str[5]; T_Special_button * input_width_button, * input_button_height; T_Dropdown_button * pixel_button; - static const char *pixel_ratio_labels[] ={ - "Normal (1x1)", - "Wide (2x1)", - "Tall (1x2)", - "Double (2x2)"}; + static const char *pixel_ratio_labels[PIXEL_MAX] ={ + "Normal (1x1)", + "Wide (2x1)", + "Tall (1x2)", + "Double (2x2)", + "Triple (3x3)", + "Wide2 (4x2)", + "Tall2 (2x4)", + "Quadruple (4x4)"}; Open_window(299,190,"Picture & screen sizes"); @@ -1423,11 +1427,9 @@ void Button_Resolution(void) chosen_pixel=Pixel_ratio; Print_in_window( 12, 57,"Pixel size:" ,MC_Dark,MC_Light); - pixel_button=Window_set_dropdown_button(108,55,14*8,11,14*8,pixel_ratio_labels[Pixel_ratio],1,0,1,LEFT_SIDE|RIGHT_SIDE); // 7 - Window_dropdown_add_item(pixel_button,PIXEL_SIMPLE,pixel_ratio_labels[PIXEL_SIMPLE]); - Window_dropdown_add_item(pixel_button,PIXEL_WIDE,pixel_ratio_labels[PIXEL_WIDE]); - Window_dropdown_add_item(pixel_button,PIXEL_TALL,pixel_ratio_labels[PIXEL_TALL]); - Window_dropdown_add_item(pixel_button,PIXEL_DOUBLE,pixel_ratio_labels[PIXEL_DOUBLE]); + pixel_button=Window_set_dropdown_button(108,55,17*8,11,17*8,pixel_ratio_labels[Pixel_ratio],1,0,1,LEFT_SIDE|RIGHT_SIDE); // 7 + for (temp=0;temp>1); Brush_offset_Y=(Brush_height>>1); break; @@ -3394,9 +3391,7 @@ void Button_Brush_FX(void) Start_operation_stack(OPERATION_STRETCH_BRUSH); break; case 8 : // Distort - Display_cursor(); - Message_not_implemented(); // !!! TEMPORAIRE !!! - Hide_cursor(); + Start_operation_stack(OPERATION_DISTORT_BRUSH); break; case 9 : // Recolorize Remap_brush(); diff --git a/const.h b/const.h index 80af6583..3769b89c 100644 --- a/const.h +++ b/const.h @@ -153,6 +153,10 @@ enum PIXEL_RATIO PIXEL_WIDE, PIXEL_TALL, PIXEL_DOUBLE, + PIXEL_TRIPLE, + PIXEL_WIDE2, + PIXEL_TALL2, + PIXEL_QUAD, PIXEL_MAX ///< Number of elements in enum }; diff --git a/engine.c b/engine.c index b7c82950..a6cd583c 100644 --- a/engine.c +++ b/engine.c @@ -106,7 +106,7 @@ void Restore_effects(void) char * Menu_tooltip[NB_BUTTONS]= { "Paintbrush choice ", - "Adjust picture / Effects", + "Adjust / Transform menu ", "Freehand draw. / Toggle ", "Splines / Toggle ", "Lines / Toggle ", @@ -407,6 +407,10 @@ void Unselect_button(int btn_number,byte click) && (!(Main_magnifier_mode && (b==BUTTON_MAGNIFIER))) ) // Alors on désenclenche le bouton Unselect_bouton(b); + // Right-clicking on Adjust opens a menu, so in this case we skip + // the unselection of all "Tool" buttons. + if (btn_number==BUTTON_ADJUST && click==RIGHT_SIDE) + break; // Pour chaque bouton: for (b=0; b>1); Brush_offset_Y=(Brush_height>>1); Display_cursor(); @@ -736,7 +733,9 @@ void Main_handler(void) Key=0; break; case SPECIAL_DISTORT : // Distort brush - Message_not_implemented(); // !!! TEMPORAIRE !!! + Hide_cursor(); + Start_operation_stack(OPERATION_DISTORT_BRUSH); + Display_cursor(); Key=0; break; case SPECIAL_ROTATE_ANY_ANGLE : // Rotate brush by any angle diff --git a/filesel.c b/filesel.c index 55b74bea..199e60ed 100644 --- a/filesel.c +++ b/filesel.c @@ -1040,7 +1040,7 @@ byte Button_Load_or_Save(byte load, byte image) { bookmark_dropdown[temp]= Window_set_dropdown_button(127+(88+1)*(temp%2),18+(temp/2)*12,88,11,56,"",0,0,1,RIGHT_SIDE); // 10-13 - Window_display_icon_sprite(bookmark_dropdown[temp]->Pos_X+3,bookmark_dropdown[temp]->Pos_Y+2,5); + Window_display_icon_sprite(bookmark_dropdown[temp]->Pos_X+3,bookmark_dropdown[temp]->Pos_Y+2,ICON_STAR); Display_bookmark(bookmark_dropdown[temp],temp); } // On prend bien soin de passer dans le répertoire courant (le bon qui faut! Oui madame!) diff --git a/gfx2.cfg b/gfx2.cfg index 9c4e6a83..8dde4a90 100644 Binary files a/gfx2.cfg and b/gfx2.cfg differ diff --git a/graph.c b/graph.c index 56a77d19..5ff924bb 100644 --- a/graph.c +++ b/graph.c @@ -42,8 +42,15 @@ #include "pxtall.h" #include "pxwide.h" #include "pxdouble.h" +#include "pxtriple.h" +#include "pxwide2.h" +#include "pxtall2.h" +#include "pxquad.h" #include "windows.h" +// Generic pixel-drawing function. +Func_pixel Pixel_figure; + // Fonction qui met à jour la zone de l'image donnée en paramètre sur l'écran. // Tient compte du décalage X et Y et du zoom, et fait tous les controles nécessaires void Update_part_of_screen(short x, short y, short width, short height) @@ -177,7 +184,6 @@ void Transform_point(short x, short y, float cos_a, float sin_a, } - //--------------------- Initialisation d'un mode vidéo ----------------------- int Init_mode_video(int width, int height, int fullscreen, int pix_ratio) @@ -213,6 +219,22 @@ int Init_mode_video(int width, int height, int fullscreen, int pix_ratio) pix_width=2; pix_height=2; break; + case PIXEL_TRIPLE: + pix_width=3; + pix_height=3; + break; + case PIXEL_WIDE2: + pix_width=4; + pix_height=2; + break; + case PIXEL_TALL2: + pix_width=2; + pix_height=4; + break; + case PIXEL_QUAD: + pix_width=4; + pix_height=4; + break; } screen_changed = (Screen_width*Pixel_width!=width || @@ -246,7 +268,7 @@ int Init_mode_video(int width, int height, int fullscreen, int pix_ratio) // On AmigaOS the systems adds some more constraints on that ... width = (width + 15) & 0xFFFFFFF0; #else - width = (width + 3 ) & 0xFFFFFFFC; + //width = (width + 3 ) & 0xFFFFFFFC; #endif pixels_changed = (Pixel_ratio!=pix_ratio); @@ -257,6 +279,7 @@ int Init_mode_video(int width, int height, int fullscreen, int pix_ratio) { Set_mode_SDL(&width, &height,fullscreen); } + Clear_border(MC_Black); if (screen_changed || pixels_changed) { Pixel_ratio=pix_ratio; @@ -353,6 +376,94 @@ int Init_mode_video(int width, int height, int fullscreen, int pix_ratio) Clear_brush_scaled = Clear_brush_scaled_double ; Display_brush = Display_brush_double ; break; + case PIXEL_TRIPLE: + Pixel = Pixel_triple ; + Read_pixel= Read_pixel_triple ; + Display_screen = Display_part_of_screen_triple ; + Block = Block_triple ; + Pixel_preview_normal = Pixel_preview_normal_triple ; + Pixel_preview_magnifier = Pixel_preview_magnifier_triple ; + Horizontal_XOR_line = Horizontal_XOR_line_triple ; + Vertical_XOR_line = Vertical_XOR_line_triple ; + Display_brush_color = Display_brush_color_triple ; + Display_brush_mono = Display_brush_mono_triple ; + Clear_brush = Clear_brush_triple ; + Remap_screen = Remap_screen_triple ; + Display_line = Display_line_on_screen_triple ; + Display_line_fast = Display_line_on_screen_fast_triple ; + Read_line = Read_line_screen_triple ; + Display_zoomed_screen = Display_part_of_screen_scaled_triple ; + Display_brush_color_zoom = Display_brush_color_zoom_triple ; + Display_brush_mono_zoom = Display_brush_mono_zoom_triple ; + Clear_brush_scaled = Clear_brush_scaled_triple ; + Display_brush = Display_brush_triple ; + break; + case PIXEL_WIDE2: + Pixel = Pixel_wide2 ; + Read_pixel= Read_pixel_wide2 ; + Display_screen = Display_part_of_screen_wide2 ; + Block = Block_wide2 ; + Pixel_preview_normal = Pixel_preview_normal_wide2 ; + Pixel_preview_magnifier = Pixel_preview_magnifier_wide2 ; + Horizontal_XOR_line = Horizontal_XOR_line_wide2 ; + Vertical_XOR_line = Vertical_XOR_line_wide2 ; + Display_brush_color = Display_brush_color_wide2 ; + Display_brush_mono = Display_brush_mono_wide2 ; + Clear_brush = Clear_brush_wide2 ; + Remap_screen = Remap_screen_wide2 ; + Display_line = Display_line_on_screen_wide2 ; + Display_line_fast = Display_line_on_screen_fast_wide2 ; + Read_line = Read_line_screen_wide2 ; + Display_zoomed_screen = Display_part_of_screen_scaled_wide2 ; + Display_brush_color_zoom = Display_brush_color_zoom_wide2 ; + Display_brush_mono_zoom = Display_brush_mono_zoom_wide2 ; + Clear_brush_scaled = Clear_brush_scaled_wide2 ; + Display_brush = Display_brush_wide2 ; + break; + case PIXEL_TALL2: + Pixel = Pixel_tall2 ; + Read_pixel= Read_pixel_tall2 ; + Display_screen = Display_part_of_screen_tall2 ; + Block = Block_tall2 ; + Pixel_preview_normal = Pixel_preview_normal_tall2 ; + Pixel_preview_magnifier = Pixel_preview_magnifier_tall2 ; + Horizontal_XOR_line = Horizontal_XOR_line_tall2 ; + Vertical_XOR_line = Vertical_XOR_line_tall2 ; + Display_brush_color = Display_brush_color_tall2 ; + Display_brush_mono = Display_brush_mono_tall2 ; + Clear_brush = Clear_brush_tall2 ; + Remap_screen = Remap_screen_tall2 ; + Display_line = Display_line_on_screen_tall2 ; + Display_line_fast = Display_line_on_screen_fast_tall2 ; + Read_line = Read_line_screen_tall2 ; + Display_zoomed_screen = Display_part_of_screen_scaled_tall2 ; + Display_brush_color_zoom = Display_brush_color_zoom_tall2 ; + Display_brush_mono_zoom = Display_brush_mono_zoom_tall2 ; + Clear_brush_scaled = Clear_brush_scaled_tall2 ; + Display_brush = Display_brush_tall2 ; + break; + case PIXEL_QUAD: + Pixel = Pixel_quad ; + Read_pixel= Read_pixel_quad ; + Display_screen = Display_part_of_screen_quad ; + Block = Block_quad ; + Pixel_preview_normal = Pixel_preview_normal_quad ; + Pixel_preview_magnifier = Pixel_preview_magnifier_quad ; + Horizontal_XOR_line = Horizontal_XOR_line_quad ; + Vertical_XOR_line = Vertical_XOR_line_quad ; + Display_brush_color = Display_brush_color_quad ; + Display_brush_mono = Display_brush_mono_quad ; + Clear_brush = Clear_brush_quad ; + Remap_screen = Remap_screen_quad ; + Display_line = Display_line_on_screen_quad ; + Display_line_fast = Display_line_on_screen_fast_quad ; + Read_line = Read_line_screen_quad ; + Display_zoomed_screen = Display_part_of_screen_scaled_quad ; + Display_brush_color_zoom = Display_brush_color_zoom_quad ; + Display_brush_mono_zoom = Display_brush_mono_zoom_quad ; + Clear_brush_scaled = Clear_brush_scaled_quad ; + Display_brush = Display_brush_quad ; + break; } } Screen_width = width/Pixel_width; @@ -480,6 +591,8 @@ void Resize_image(word chosen_width,word 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. + 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), diff --git a/graph.h b/graph.h index a5c6525d..7c5de01a 100644 --- a/graph.h +++ b/graph.h @@ -97,22 +97,16 @@ void Draw_grad_rectangle(short rax,short ray,short rbx,short rby,short vax,short void Polyfill_general(int vertices, short * points, int color); void Polyfill(int vertices, short * points, int color); -// Gestion des backups: -void Download_infos_page_main(T_Page * page); -void Download_infos_page_spare(T_Page * page); -void Download_infos_backup(T_List_of_pages * list); -void Free_all_backup_lists(void); -int Backup_with_new_dimensions(int upload,int width,int height); -int Backup_and_resize_the_spare(int width,int height); -void Undo(void); -void Redo(void); -void Free_current_page(void); -void Exchange_main_and_spare(void); - -void Change_magnifier_factor(byte factor_index); - void Remap_picture(void); -// Définition d'une fonction générique de traçage de figures: -Func_pixel Pixel_figure; +/// +/// All the figure-drawing functions work by calling this function for each +/// pixel to draw. Before calling these functions, you should assign +/// ::Pixel_figure depending on what you where you want to draw: +/// - ::Pixel_figure_preview : On screen. +/// - ::Pixel_figure_preview_xor : On screen, XORing the color. +/// - ::Pixel_figure_permanent : On screen and in the image. +/// - ::Pixel_figure_clear_preview : On screen, reverting to the image's pixels. +extern Func_pixel Pixel_figure; + void Update_part_of_screen(short x, short y, short width, short height); diff --git a/helpfile.h b/helpfile.h index 26b186ce..b92e7142 100644 --- a/helpfile.h +++ b/helpfile.h @@ -54,7 +54,7 @@ static const T_Help_table helptable_about[] = HELP_TITLE("======================") */ { - HELP_TEXT ("") // Laisse de la place pour le logo + HELP_TEXT ("") // Leave enough room for a hard-coded logo, eventually. HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("") @@ -539,7 +539,8 @@ static const T_Help_table helptable_paintbrush[] = }; static const T_Help_table helptable_adjust[] = { - HELP_TITLE("ADJUST PICTURE") + HELP_TITLE("ADJUST OR TRANSFORM") + HELP_TITLE(" PICTURE") HELP_TEXT ("") HELP_BOLD (" LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_ADJUST) @@ -558,8 +559,24 @@ static const T_Help_table helptable_adjust[] = HELP_BOLD (" RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_ADJUST) HELP_TEXT ("") - HELP_TEXT (" *** Not implemented yet ***") - + HELP_TEXT ("Opens the Picture Transform menu.") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE("PICTURE TRANSFORM") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("") }; static const T_Help_table helptable_draw[] = { @@ -1079,7 +1096,15 @@ static const T_Help_table helptable_brush_fx[] = HELP_TEXT ("because it's the only way for cancelling)") HELP_TEXT ("") HELP_LINK ("- Distort: (Key:%s)",SPECIAL_DISTORT) - HELP_TEXT ("*** Not implemented yet ***") + HELP_TEXT ("Triggers an interactive operation") + HELP_TEXT ("that allows you to distort your brush.") + HELP_TEXT ("Start by placing the brush somewhere on the") + HELP_TEXT ("screen and left-click. The brush will") + HELP_TEXT ("appear, with a little peg at each corner.") + HELP_TEXT ("Use the left mouse button to displace the") + HELP_TEXT ("corners, which will deform the brush.") + HELP_TEXT ("When you're done, click the right mouse") + HELP_TEXT ("button.") HELP_TEXT ("") HELP_LINK ("- Outline: (Key:%s)",SPECIAL_OUTLINE) HELP_TEXT ("This option permits to draw the") diff --git a/init.c b/init.c index 9728093a..d630498e 100644 --- a/init.c +++ b/init.c @@ -66,6 +66,8 @@ #include "mountlist.h" // read_file_system_list #include "loadsave.h" // Image_emergency_backup #include "init.h" +#include "transform.h" + // Rechercher la liste et le type des lecteurs de la machine @@ -822,12 +824,11 @@ void Init_buttons(void) Do_nothing, FAMILY_INSTANT); -// !!! TEMPORAIRE !!! Init_button(BUTTON_ADJUST, 0,18, 16,16, BUTTON_SHAPE_RECTANGLE, - Button_Adjust,Message_not_implemented, + Button_Adjust,Button_Transform_menu, Do_nothing, FAMILY_TOOL); @@ -1322,6 +1323,22 @@ void Init_operations(void) Init_operation(OPERATION_ROTATE_BRUSH,2,5, Rotate_brush_2_5,1); + Init_operation(OPERATION_DISTORT_BRUSH,0,0, + Distort_brush_0_0,0); + Init_operation(OPERATION_DISTORT_BRUSH,1,0, + Distort_brush_1_0,0); + Init_operation(OPERATION_DISTORT_BRUSH,1,8, + Distort_brush_1_8,0); + Init_operation(OPERATION_DISTORT_BRUSH,2,8, + Distort_brush_2_8,1); + Init_operation(OPERATION_DISTORT_BRUSH,2,0, + Distort_brush_2_0,1); + Init_operation(OPERATION_DISTORT_BRUSH,1,9, + Distort_brush_1_9,0); + Init_operation(OPERATION_DISTORT_BRUSH,0,9, + Distort_brush_0_9,0); + + Init_operation(OPERATION_POLYBRUSH,1,0, Filled_polyform_12_0,1); Init_operation(OPERATION_POLYBRUSH,2,0, diff --git a/input.c b/input.c index 94889dd1..e0b66f99 100644 --- a/input.c +++ b/input.c @@ -88,12 +88,25 @@ int Is_shortcut(word Key, word function) int Move_cursor_with_constraints() { int feedback=0; + byte bl=0;//BL va indiquer si on doit corriger la position du curseur + // Clip mouse to the editing area. There can be a border when using big + // pixels, if the SDL screen dimensions are not factors of the pixel size. + if (Input_new_mouse_Y>=Screen_height) + { + Input_new_mouse_Y=Screen_height-1; + bl=1; + } + if (Input_new_mouse_X>=Screen_width) + { + Input_new_mouse_X=Screen_width-1; + bl=1; + } //Gestion "avancée" du curseur: interdire la descente du curseur dans le //menu lorsqu'on est en train de travailler dans l'image if (Operation_stack_size != 0) { - byte bl=0;//BL va indiquer si on doit corriger la position du curseur + //Si le curseur ne se trouve plus dans l'image if(Menu_Y<=Input_new_mouse_Y) @@ -122,14 +135,13 @@ int Move_cursor_with_constraints() } } } - - if (bl) - { - SDL_WarpMouse( - Input_new_mouse_X*Pixel_width, - Input_new_mouse_Y*Pixel_height - ); - } + } + if (bl) + { + SDL_WarpMouse( + Input_new_mouse_X*Pixel_width, + Input_new_mouse_Y*Pixel_height + ); } if ((Input_new_mouse_X != Mouse_X) || (Input_new_mouse_Y != Mouse_Y) || diff --git a/main.c b/main.c index deb2d0ec..67f1eead 100644 --- a/main.c +++ b/main.c @@ -79,14 +79,18 @@ static char Gui_skin_file[MAX_PATH_CHARACTERS]= "skins" PATH_SEPARATOR "base.gif void Display_syntax(void) { int mode_index; - printf("Syntax: GFX2 [] []\n\n"); + printf("Syntax: grafx2 [] []\n\n"); printf(" can be:]\n"); - printf("\t/? /h /help for this help screen\n"); - printf("\t/wide to emulate a video mode with wide pixels (2x1)\n"); - printf("\t/tall to emulate a video mode with tall pixels (1x2)\n"); - printf("\t/double to emulate a video mode with double pixels (2x2)\n"); - printf("\t/skin use an alternate file with the menu graphics\n"); - printf("\t/mode to set a video mode\n\n"); + printf("\t/? /h /help for this help screen\n"); + printf("\t/wide to emulate a video mode with wide pixels (2x1)\n"); + printf("\t/tall to emulate a video mode with tall pixels (1x2)\n"); + printf("\t/double to emulate a video mode with double pixels (2x2)\n"); + printf("\t/wide2 to emulate a video mode with double wide pixels (4x2)\n"); + printf("\t/tall2 to emulate a video mode with double tall pixels (2x4)\n"); + printf("\t/triple to emulate a video mode with triple pixels (3x3)\n"); + printf("\t/quadruple to emulate a video mode with quadruple pixels (4x4)\n"); + printf("\t/skin use an alternate file with the menu graphics\n"); + printf("\t/mode to set a video mode\n\n"); printf("Available video modes:\n\n"); for (mode_index=0; mode_index0;dx--) + for(y=0;y0;cx--) + for(x=0;xTimer_start) Timer_state=1; } -// Effectue une inversion de la brosse selon une droite horizontale -void Flip_Y_lowlevel(void) +void Flip_Y_lowlevel(byte *src, short width, short height) { // ESI pointe sur la partie haute de la brosse // EDI sur la partie basse - byte* ESI = Brush ; - byte* EDI = Brush + (Brush_height - 1) *Brush_width; + byte* ESI = src ; + byte* EDI = src + (height - 1) *width; byte tmp; word cx; @@ -501,7 +499,7 @@ void Flip_Y_lowlevel(void) // Il faut inverser les lignes pointées par ESI et // EDI ("Brush_width" octets en tout) - for(cx = Brush_width;cx>0;cx--) + for(cx = width;cx>0;cx--) { tmp = *ESI; *ESI = *EDI; @@ -514,57 +512,65 @@ void Flip_Y_lowlevel(void) // ESI pointe déjà sur le début de la ligne suivante // EDI pointe sur la fin de la ligne en cours, il // doit pointer sur le début de la précédente... - EDI -= 2 * Brush_width; // On recule de 2 lignes + EDI -= 2 * width; // On recule de 2 lignes } } -// Effectue une inversion de la brosse selon une droite verticale -void Flip_X_lowlevel(void) +void Flip_X_lowlevel(byte *src, short width, short height) { // ESI pointe sur la partie gauche et EDI sur la partie // droite - byte* ESI = Brush; - byte* EDI = Brush + Brush_width - 1; + byte* ESI = src; + byte* EDI = src + width - 1; - byte* Debut_Ligne; - byte* Fin_Ligne; + byte* line_start; + byte* line_end; byte tmp; word cx; while(ESI0;cx--) + for(cx=height;cx>0;cx--) { tmp=*ESI; *ESI=*EDI; *EDI=tmp; - EDI+=Brush_width; - ESI+=Brush_width; + EDI+=width; + ESI+=width; } // On change de colonne // ESI > colonne suivante // EDI > colonne précédente - ESI = Debut_Ligne + 1; - EDI = Fin_Ligne - 1; + ESI = line_start + 1; + EDI = line_end - 1; } } -// Faire une rotation de 180º de la brosse -void Rotate_180_deg_lowlevel(void) +// Rotate a pixel buffer 180º on itself. +void Rotate_180_deg_lowlevel(byte *src, short width, short height) { // ESI pointe sur la partie supérieure de la brosse // EDI pointe sur la partie basse - byte* ESI = Brush; - byte* EDI = Brush + Brush_height*Brush_width - 1; + byte* ESI = src; + byte* EDI = src + height*width - 1; // EDI pointe sur le dernier pixel de la derniere ligne byte tmp; word cx; + // In case of odd height, the algorithm in this function would + // miss the middle line, so we do it this way: + if (height & 1) + { + Flip_X_lowlevel(src, width, height); + Flip_Y_lowlevel(src, width, height); + return; + } + while(ESI < EDI) { // On échange les deux lignes pointées par EDI et @@ -572,7 +578,7 @@ void Rotate_180_deg_lowlevel(void) // En même temps, on échange les pixels, donc EDI // pointe sur la FIN de sa ligne - for(cx=Brush_width;cx>0;cx--) + for(cx=width;cx>0;cx--) { tmp = *ESI; *ESI = *EDI; @@ -584,6 +590,55 @@ void Rotate_180_deg_lowlevel(void) } } +void Rescale(byte *src_buffer, short src_width, short src_height, byte *dst_buffer, short dst_width, short dst_height, short x_flipped, short y_flipped) +{ + int offset,line,column; + + int x_pos_in_brush; // Position courante dans l'ancienne brosse + int y_pos_in_brush; + int delta_x_in_brush; // "Vecteur incrémental" du point précédent + int delta_y_in_brush; + int initial_x_pos; // Position X de début de parcours de ligne + + // Calcul du "vecteur incrémental": + delta_x_in_brush=(src_width<<16) * (x_flipped?-1:1) / (dst_width); + delta_y_in_brush=(src_height<<16) * (y_flipped?-1:1) / (dst_height); + + offset=0; + + // Calcul de la valeur initiale de y_pos: + if (y_flipped) + y_pos_in_brush=(src_height<<16)-1; // Inversion en Y de la brosse + else + y_pos_in_brush=0; // Pas d'inversion en Y de la brosse + + // Calcul de la valeur initiale de x_pos pour chaque ligne: + if (x_flipped) + initial_x_pos = (src_width<<16)-1; // Inversion en X de la brosse + else + initial_x_pos = 0; // Pas d'inversion en X de la brosse + + // Pour chaque ligne + for (line=0;line>16) + (y_pos_in_brush>>16)*src_width); + // On passe à la colonne de brosse suivante: + x_pos_in_brush+=delta_x_in_brush; + // On passe au pixel suivant de la nouvelle brosse: + offset++; + } + // On passe à la ligne de brosse suivante: + y_pos_in_brush+=delta_y_in_brush; + } +} + void Slider_timer(byte speed) //Boucle d'attente pour faire bouger les scrollbars à une vitesse correcte { diff --git a/misc.h b/misc.h index 319f1c52..68d93751 100644 --- a/misc.h +++ b/misc.h @@ -84,10 +84,52 @@ byte Effect_additive_colorize (word x,word y,byte color); byte Effect_substractive_colorize(word x,word y,byte color); byte Effect_sieve(word x,word y); -void Flip_Y_lowlevel(void); -void Flip_X_lowlevel(void); -void Rotate_90_deg_lowlevel(byte * source,byte * dest); -void Rotate_180_deg_lowlevel(void); +/// +/// Inverts a pixel buffer, according to a horizontal axis. +/// @param src Pointer to the pixel buffer to process. +/// @param width Width of the buffer. +/// @param height Height of the buffer. +void Flip_Y_lowlevel(byte *src, short width, short height); + +/// +/// Inverts a pixel buffer, according to a vertical axis. +/// @param src Pointer to the pixel buffer to process. +/// @param width Width of the buffer. +/// @param height Height of the buffer. +void Flip_X_lowlevel(byte *src, short width, short height); +/// +/// Rotate a pixel buffer by 90 degrees, clockwise. +/// @param source Source pixel buffer. +/// @param dest Destination pixel buffer. +/// @param width Width of the original buffer (height of the destination one). +/// @param height Height of the original buffer (width of the destination one). +void Rotate_90_deg_lowlevel(byte * source, byte * dest, short width, short height); +/// +/// Rotate a pixel buffer by 90 degrees, counter-clockwise. +/// @param source Source pixel buffer. +/// @param dest Destination pixel buffer. +/// @param width Width of the original buffer (height of the destination one). +/// @param height Height of the original buffer (width of the destination one). +void Rotate_270_deg_lowlevel(byte * source, byte * dest, short width, short height); +/// +/// Rotate a pixel buffer by 180 degrees. +/// @param src The pixel buffer (source and destination). +/// @param width Width of the buffer. +/// @param height Height of the buffer. +void Rotate_180_deg_lowlevel(byte *src, short width, short height); + +/// +/// Copies an image to another, rescaling it and optionally flipping it. +/// @param src_buffer Original image (address of first byte) +/// @param src_width Original image's width in pixels +/// @param src_height Original image's height in pixels +/// @param dst_buffer Destination image (address of first byte) +/// @param dst_width Destination image's width in pixels +/// @param dst_height Destination image's height in pixels +/// @param x_flipped Boolean, true to flip the image horizontally +/// @param y_flipped Boolean, true to flip the image vertically +void Rescale(byte *src_buffer, short src_width, short src_height, byte *dst_buffer, short dst_width, short dst_height, short x_flipped, short y_flipped); + void Zoom_a_line(byte * original_line,byte * zoomed_line,word factor,word width); void Copy_part_of_image_to_another(byte * source,word source_x,word source_y,word width,word height,word source_width,byte * dest,word dest_x,word dest_y,word destination_width); diff --git a/operatio.c b/operatio.c index c2bcf090..050fe4b0 100644 --- a/operatio.c +++ b/operatio.c @@ -157,6 +157,35 @@ void Display_coords_rel_or_abs(short start_x, short start_y) Print_coordinates(); } +/// Simulates clicking the "Draw" button. +void Return_to_draw_mode(void) +{ + + // Comme l'enclenchement du bouton efface le curseur, il faut l'afficher au + // préalable: + Display_cursor(); + if (Mouse_K) + Wait_end_of_click(); + // !!! Efface la croix puis affiche le viseur !!! + Unselect_button(BUTTON_DRAW,LEFT_SIDE); // Désenclenche au passage le bouton brosse + if (Config.Auto_discontinuous) + { + // On se place en mode Dessin discontinu à la main + while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW) + Unselect_button(BUTTON_DRAW,RIGHT_SIDE); + } + // Maintenant, il faut réeffacer le curseur parce qu'il sera raffiché en fin + // d'appel à cette action: + Hide_cursor(); + + // On passe en brosse couleur: + Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); + + if ((Config.Coords_rel) && (Menu_is_visible)) + Print_in_menu("X: Y:",0); + Print_coordinates(); +} + //////////////////////////////////////////////////// OPERATION_CONTINUOUS_DRAW void Freehand_mode1_1_0(void) @@ -2955,29 +2984,7 @@ void Brush_0_5(void) Brush_offset_Y=(Brush_offset_Y/Snap_height)*Snap_height; } - // Simuler l'appui du bouton "Dessin" - - // Comme l'enclenchement du bouton efface le curseur, il faut l'afficher au - // préalable: - Display_cursor(); - // !!! Efface la croix puis affiche le viseur !!! - Unselect_button(BUTTON_DRAW,LEFT_SIDE); // Désenclenche au passage le bouton brosse - if (Config.Auto_discontinuous) - { - // On se place en mode Dessin discontinu à la main - while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW) - Unselect_button(BUTTON_DRAW,RIGHT_SIDE); - } - // Maintenant, il faut réeffacer le curseur parce qu'il sera raffiché en fin - // d'appel à cette action: - Hide_cursor(); - - // On passe en brosse couleur: - Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X: Y:",0); - Print_coordinates(); + Return_to_draw_mode(); } @@ -3099,28 +3106,8 @@ void Polybrush_12_8(void) Brush_offset_X=(Brush_offset_X/Snap_width)*Snap_width; Brush_offset_Y=(Brush_offset_Y/Snap_height)*Snap_height; } - - // Simuler l'appui du bouton "Dessin" - - // Comme l'enclenchement du bouton efface le curseur, il faut l'afficher au - // préalable: - Display_cursor(); - Wait_end_of_click(); - // !!! Efface la croix puis affiche le viseur !!! - Unselect_button(BUTTON_DRAW,LEFT_SIDE); // Désenclenche au passage le bouton brosse - if (Config.Auto_discontinuous) - { - // On se place en mode Dessin discontinu à la main - while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW) - Unselect_button(BUTTON_DRAW,RIGHT_SIDE); - } - // Maintenant, il faut réeffacer le curseur parce qu'il sera raffiché en fin - // d'appel à cette action: - Hide_cursor(); - - // On passe en brosse couleur: - Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); - + + Return_to_draw_mode(); Display_cursor(); } } @@ -3398,31 +3385,7 @@ void Stretch_brush_2_7(void) // Et enfin on stocke pour de bon la nouvelle brosse étirée Stretch_brush(start_x,start_y,computed_x,computed_y); - // Simuler l'appui du bouton "Dessin" - - // Comme l'enclenchement du bouton efface le curseur, il faut l'afficher au - // préalable: - Display_cursor(); - // !!! Efface la croix puis affiche le viseur !!! - Unselect_button(BUTTON_DRAW,LEFT_SIDE); // Désenclenche au passage le bouton brosse - if (Config.Auto_discontinuous) - { - // On se place en mode Dessin discontinu à la main - while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW) - Unselect_button(BUTTON_DRAW,RIGHT_SIDE); - } - // Maintenant, il faut réeffacer le curseur parce qu'il sera raffiché en fin - // d'appel à cette action: - Hide_cursor(); - - // On passe en brosse couleur: - Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X: Y:",0); - Print_coordinates(); - - // Inutile de de faire un Wait_end_of_click car c'est fait dans Unselect_button + Return_to_draw_mode(); } @@ -3650,33 +3613,261 @@ void Rotate_brush_2_5(void) // Et enfin on stocke pour de bon la nouvelle brosse étirée Rotate_brush(angle); - // Simuler l'appui du bouton "Dessin" - - // Comme l'enclenchement du bouton efface le curseur, il faut l'afficher au - // préalable: - Display_cursor(); - // !!! Efface le curseur de l'opération puis affiche le viseur !!! - Unselect_button(BUTTON_DRAW,LEFT_SIDE); // Désenclenche au passage le bouton brosse - if (Config.Auto_discontinuous) - { - // On se place en mode Dessin discontinu à la main - while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW) - Unselect_button(BUTTON_DRAW,RIGHT_SIDE); - } - // Maintenant, il faut réeffacer le curseur parce qu'il sera raffiché en fin - // d'appel à cette action: - Hide_cursor(); - - // On passe en brosse couleur: - Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X: Y:",0); - Print_coordinates(); - - // Inutile de de faire un Wait_end_of_click car c'est fait dans Unselect_button + Return_to_draw_mode(); } +///////////////////////////////////////////////////// OPERATION_DISTORT_BRUSH + +/// Draws a 2x2 XOR square at the specified picture coordinates, on the screen. +void Draw_stretch_spot(short x_pos, short y_pos) +{ + short x,y; + + for (y=y_pos-1;y=Limit_top && y<=Limit_visible_bottom) + for (x=x_pos-1;x=Limit_left && x<=Limit_visible_right) + Pixel_preview(x,y,~Read_pixel(x-Main_offset_X,y-Main_offset_Y)); + Update_part_of_screen(x_pos-1, y_pos-1, 2, 2); +} + +void Distort_brush_0_0(void) +// +// Opération : OPERATION_DISTORT_BRUSH +// Click Souris: 0 +// Taille_Pile : 0 +// +// Souris effacée: Non +// +{ + if ( Menu_is_visible ) + { + Print_in_menu("POSITION BRUSH TO START ",0); + } +} + +void Distort_brush_1_0(void) +// +// Opération : OPERATION_DISTORT_BRUSH +// Click Souris: 1 +// Taille_Pile : 0 +// +// Souris effacée: Non +// +{ + short x_pos, y_pos; + + Init_start_operation(); + Paintbrush_hidden=1; + Hide_cursor(); + + // Top left angle + x_pos=Paintbrush_X-Brush_offset_X; + y_pos=Paintbrush_Y-Brush_offset_Y; + Draw_stretch_spot(x_pos,y_pos); + Operation_push(x_pos); + Operation_push(y_pos); + + // Top right angle + x_pos+=Brush_width; + Draw_stretch_spot(x_pos,y_pos); + Operation_push(x_pos); + Operation_push(y_pos); + + // Bottom right angle + y_pos+=Brush_height; + Draw_stretch_spot(x_pos,y_pos); + Operation_push(x_pos); + Operation_push(y_pos); + + // Bottom left angle + x_pos-=Brush_width; + Draw_stretch_spot(x_pos,y_pos); + Operation_push(x_pos); + Operation_push(y_pos); + + Distort_brush_preview( + Operation_stack[1], + Operation_stack[2], + Operation_stack[3], + Operation_stack[4], + Operation_stack[5], + Operation_stack[6], + Operation_stack[7], + Operation_stack[8]); + Display_cursor(); + Update_part_of_screen(Paintbrush_X-Brush_offset_X, Paintbrush_Y-Brush_offset_Y, Brush_width, Brush_height); + Wait_end_of_click(); + // Erase the message in status bar + if ( (Config.Coords_rel) && (Menu_is_visible) ) + { + Print_in_menu("X: Y: ",0); + } +} + +void Distort_brush_1_8(void) +// +// Opération : OPERATION_DISTORT_BRUSH +// Click Souris: 1 +// Taille_Pile : 8 +// +// Souris effacée: No +// +{ + // How far (in pixels) you can catch a handle + #define REACH_DISTANCE 100 + short i; + short x[4]; + short y[4]; + long best_distance=REACH_DISTANCE; + short best_spot=-1; + + for (i=3;i>=0;i--) + { + long distance; + Operation_pop(&y[i]); + Operation_pop(&x[i]); + distance=Distance(Paintbrush_X,Paintbrush_Y,x[i],y[i]); + if (distance-1) + { + Operation_push(best_spot); + } + if ( (Config.Coords_rel) && (Menu_is_visible) ) + { + Print_in_menu("X: Y: ",0); + Print_coordinates(); + } +} + +void Distort_brush_1_9(void) +// +// Opération : OPERATION_DISTORT_BRUSH +// Click Souris: 1 +// Taille_Pile : 9 +// +// Souris effacée: No +// +{ + short i; + short x[4]; + short y[4]; + short selected_corner; + + // Pop all arguments + Operation_pop(&selected_corner); + for (i=3;i>=0;i--) + { + Operation_pop(&y[i]); + Operation_pop(&x[i]); + } + + if (Paintbrush_X!=x[selected_corner] || Paintbrush_Y!=y[selected_corner]) + { + Hide_cursor(); + + // Easiest refresh mode: make no assumptions on how the brush was + // displayed before. + Display_all_screen(); + + x[selected_corner]=Paintbrush_X; + y[selected_corner]=Paintbrush_Y; + + for (i=0;i<4;i++) + Draw_stretch_spot(x[i],y[i]); + + Distort_brush_preview(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3]); + + Display_cursor(); + + if ( (Config.Coords_rel) && (Menu_is_visible) ) + { + Print_in_menu("X: Y: ",0); + Print_coordinates(); + } + Update_rect(0,0,Screen_width,Menu_Y); + } + + // Push back all arguments + for (i=0;i<4;i++) + { + Operation_push(x[i]); + Operation_push(y[i]); + } + Operation_push(selected_corner); + +} +void Distort_brush_0_9(void) +// +// Opération : OPERATION_DISTORT_BRUSH +// Click Souris: 0 +// Taille_Pile : 9 +// +// Souris effacée: No +// +{ + short selected_corner; + Operation_pop(&selected_corner); + +} + +void Distort_brush_2_0(void) +// +// Opération : OPERATION_DISTORT_BRUSH +// Click Souris: 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui +// +{ + Paintbrush_hidden=0; + Display_all_screen(); + // Erase the message in status bar + if ( (Config.Coords_rel) && (Menu_is_visible) ) + { + Print_in_menu("X: Y: ",0); + } + Return_to_draw_mode(); +} + +void Distort_brush_2_8(void) +// +// Opération : OPERATION_DISTORT_BRUSH +// Click Souris: 2 +// Taille_Pile : 8 +// +// Souris effacée: Oui +// +{ + short i; + short x[4]; + short y[4]; + + // Pop all arguments + for (i=3;i>=0;i--) + { + Operation_pop(&y[i]); + Operation_pop(&x[i]); + } + Distort_brush(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3]); + + Paintbrush_hidden=0; + Display_all_screen(); + + Return_to_draw_mode(); +} //////////////////////////////////////////////////////////// OPERATION_SCROLL diff --git a/operatio.h b/operatio.h index a8dc3058..350f2e37 100644 --- a/operatio.h +++ b/operatio.h @@ -100,6 +100,16 @@ void Rotate_brush_1_5(void); void Rotate_brush_0_5(void); void Rotate_brush_2_5(void); +///////////////////////////////////////////////////// OPERATION_DISTORT_BRUSH + +void Distort_brush_0_0(void); +void Distort_brush_1_0(void); +void Distort_brush_2_0(void); +void Distort_brush_1_8(void); +void Distort_brush_2_8(void); +void Distort_brush_1_9(void); +void Distort_brush_0_9(void); + //////////////////////////////////////////////////////// OPERATION_POLYBRUSH void Polybrush_12_8(void); diff --git a/pxdouble.c b/pxdouble.c index 7246cfd1..3aae22c9 100644 --- a/pxdouble.c +++ b/pxdouble.c @@ -36,26 +36,26 @@ void Pixel_double (word x,word y,byte color) /* Affiche un pixel de la color aux coords x;y à l'écran */ { - *(Screen_pixels + x * 2 + y * 4 * Screen_width)=color; - *(Screen_pixels + x * 2 + y * 4 * Screen_width + 1)=color; - *(Screen_pixels + x * 2 + (y * 4 + 2 )* Screen_width)=color; - *(Screen_pixels + x * 2 + (y * 4 + 2 )* Screen_width + 1)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1)* VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1)* VIDEO_LINE_WIDTH + 1)=color; } byte Read_pixel_double (word x,word y) /* On retourne la couleur du pixel aux coords données */ { - return *( Screen_pixels + y * 4 * Screen_width + x * 2); + return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); } void Block_double (word start_x,word start_y,word width,word height,byte color) /* On affiche un rectangle de la couleur donnée */ { SDL_Rect rectangle; - rectangle.x=start_x*2; - rectangle.y=start_y*2; - rectangle.w=width*2; - rectangle.h=height*2; + rectangle.x=start_x*ZOOMX; + rectangle.y=start_y*ZOOMY; + rectangle.w=width*ZOOMX; + rectangle.h=height*ZOOMY; SDL_FillRect(Screen_SDL,&rectangle,color); } @@ -75,14 +75,14 @@ void Display_part_of_screen_double (word width,word height,word image_width) { *(dest+1)=*dest=*src; src++; - dest+=2; + dest+=ZOOMX; } // On double la ligne qu'on vient de copier - memcpy(dest-width*ZOOMX+Screen_width*ZOOMX,dest-width*ZOOMX,width*ZOOMX); + memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); // On passe à la ligne suivante src+=image_width-width; - dest+=Screen_width*4 - width*2; + dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; } //Update_rect(0,0,width,height); } @@ -127,29 +127,29 @@ void Pixel_preview_magnifier_double (word x,word y,byte color) void Horizontal_XOR_line_double(word x_pos,word y_pos,word width) { //On calcule la valeur initiale de dest: - byte* dest=y_pos*4*Screen_width+x_pos*2+Screen_pixels; + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; int x; - for (x=0;x0;i--) { - *dest=*(dest+1)=*(dest+Screen_width*2)=*(dest+Screen_width*2+1)=~*dest; - dest+=Screen_width*4; + *dest=*(dest+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=~*dest; + dest+=VIDEO_LINE_WIDTH*ZOOMY; } } void Display_brush_color_double(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * 4 * Screen_width + x_pos * 2; + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; // src = Position dans la brosse byte* src = Brush + y_offset * brush_width + x_offset; @@ -164,16 +164,16 @@ void Display_brush_color_double(word x_pos,word y_pos,word x_offset,word y_offse // On vérifie que ce n'est pas la transparence if(*src != transp_color) { - *(dest+Screen_width*2+1) = *(dest+Screen_width*2) = *(dest+1) = *dest = *src; + *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+1) = *dest = *src; } // Pixel suivant src++; - dest+=2; + dest+=ZOOMX; } // On passe à la ligne suivante - dest = dest + Screen_width*4 - width*2; + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; src = src + brush_width - width; } Update_rect(x_pos,y_pos,width,height); @@ -184,7 +184,7 @@ void Display_brush_mono_double(word x_pos, word y_pos, byte transp_color, byte color, word brush_width) /* On affiche la brosse en monochrome */ { - byte* dest=y_pos*4*Screen_width+x_pos*2+Screen_pixels; // dest = adr destination à + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à // l'écran byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds // la brosse @@ -197,23 +197,23 @@ void Display_brush_mono_double(word x_pos, word y_pos, //Pour chaque pixel { if (*src!=transp_color) - *(dest+Screen_width*2+1)=*(dest+Screen_width*2)=*(dest+1)=*dest=color; + *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=color; // On passe au pixel suivant src++; - dest+=2; + dest+=ZOOMX; } // On passe à la ligne suivante src+=brush_width-width; - dest+=Screen_width*4-width*2; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } void Clear_brush_double(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) { - byte* dest=Screen_pixels+x_pos*2+y_pos*4*Screen_width; //On va se mettre en 0,0 dans l'écran (dest) + byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) int y; int x; @@ -224,16 +224,16 @@ void Clear_brush_double(word x_pos,word y_pos,__attribute__((unused)) word x_off for(x=width;x!=0;x--) //Pour chaque pixel { - *(dest+Screen_width*2+1)=*(dest+Screen_width*2)=*(dest+1)=*dest=*src; + *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=*src; // On passe au pixel suivant src++; - dest+=2; + dest+=ZOOMX; } // On passe à la ligne suivante src+=image_width-width; - dest+=Screen_width*4-width*2; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } @@ -242,7 +242,7 @@ void Clear_brush_double(word x_pos,word y_pos,__attribute__((unused)) word x_off void Display_brush_double(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * 4 * Screen_width + x_pos * 2; + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; // src = Position dans la brosse byte* src = brush + y_offset * brush_width + x_offset; @@ -257,15 +257,15 @@ void Display_brush_double(byte * brush, word x_pos,word y_pos,word x_offset,word // On vérifie que ce n'est pas la transparence if(*src != transp_color) { - *(dest+Screen_width*2+1)=*(dest+Screen_width*2)=*(dest+1)=*dest=*src; + *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=*src; } // Pixel suivant - src++; dest+=2; + src++; dest+=ZOOMX; } // On passe à la ligne suivante - dest = dest + Screen_width*4 - width*2; + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; src = src + brush_width - width; } } @@ -273,7 +273,7 @@ void Display_brush_double(byte * brush, word x_pos,word y_pos,word x_offset,word void Remap_screen_double(word x_pos,word y_pos,word width,word height,byte * conversion_table) { // dest = coords a l'écran - byte* dest = Screen_pixels + y_pos * 4 * Screen_width + x_pos * 2; + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; int x,y; // Pour chaque ligne @@ -282,12 +282,12 @@ void Remap_screen_double(word x_pos,word y_pos,word width,word height,byte * con // Pour chaque pixel for(x=width;x>0;x--) { - *(dest+Screen_width*2+1)=*(dest+Screen_width*2)=*(dest+1)=*dest= + *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest= conversion_table[*dest]; - dest +=2; + dest +=ZOOMX; } - dest = dest + Screen_width*4 - width*2; + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); @@ -297,8 +297,8 @@ void Display_line_on_screen_fast_double(word x_pos,word y_pos,word width,byte * /* On affiche toute une ligne de pixels telle quelle. */ /* Utilisée si le buffer contient déja des pixel doublés. */ { - memcpy(Screen_pixels+x_pos*2+y_pos*4*Screen_width,line,width*2); - memcpy(Screen_pixels+x_pos*2+(y_pos*4+2)*Screen_width,line,width*2); + memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); } void Display_line_on_screen_double(word x_pos,word y_pos,word width,byte * line) @@ -306,11 +306,11 @@ void Display_line_on_screen_double(word x_pos,word y_pos,word width,byte * line) { int x; byte *dest; - dest=Screen_pixels+x_pos*2+y_pos*4*Screen_width; + dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; for(x=width;x>0;x--) { - *(dest+Screen_width*2+1)=*(dest+Screen_width*2)=*(dest+1)=*dest=*line; - dest+=2; + *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=*line; + dest+=ZOOMX; line++; } } @@ -320,7 +320,7 @@ void Display_transparent_mono_line_on_screen_double( // Affiche une ligne à l'écran avec une couleur + transparence. // Utilisé par les brosses en mode zoom { - byte* dest = Screen_pixels+ y_pos*ZOOMX*Screen_width + x_pos*ZOOMX; + byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; int x; // Pour chaque pixel for(x=0;x0;bx--) { - Display_transparent_line_on_screen_wide(x_pos,y*ZOOMX,width*Main_magnifier_factor,buffer,transp_color); - // TODO: pas clair ici - memcpy(Screen_pixels + (y*ZOOMY+1)*ZOOMX*Screen_width + x_pos*ZOOMX, Screen_pixels + y*ZOOMX*ZOOMY*Screen_width + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + Display_transparent_line_on_screen_wide(x_pos,y*ZOOMY,width*Main_magnifier_factor,buffer,transp_color); + memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); y++; if(y==end_y_pos) { @@ -435,7 +434,7 @@ void Display_brush_mono_zoom_double(word x_pos, word y_pos, // On affiche la ligne Facteur fois à l'écran (sur des // lignes consécutives) - bx = Main_magnifier_factor*ZOOMX; + bx = Main_magnifier_factor*ZOOMY; // Pour chaque ligne écran do @@ -448,7 +447,7 @@ void Display_brush_mono_zoom_double(word x_pos, word y_pos, // On passe à la ligne suivante y++; // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos*ZOOMX) + if(y == end_y_pos*ZOOMY) { Update_rect( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); @@ -473,13 +472,12 @@ void Clear_brush_scaled_double(word x_pos,word y_pos,word x_offset,word y_offset // Pour chaque ligne à zoomer while(1){ - Zoom_a_line(src,buffer,Main_magnifier_factor*2,width); + Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); bx=Main_magnifier_factor; // Pour chaque ligne do{ - // TODO a verifier Display_line_on_screen_fast_double(x_pos,y, width * Main_magnifier_factor,buffer); diff --git a/pxquad.c b/pxquad.c new file mode 100644 index 00000000..33320905 --- /dev/null +++ b/pxquad.c @@ -0,0 +1,534 @@ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + Copyright 2008 Franck Charlet + Copyright 2007 Adrien Destugues + Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) + + Grafx2 is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 + of the License. + + Grafx2 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grafx2; if not, see or + write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include +#include +#include +#include "global.h" +#include "sdlscreen.h" +#include "misc.h" +#include "pxquad.h" + +#define ZOOMX 4 +#define ZOOMY 4 + +void Pixel_quad (word x,word y,byte color) +/* Affiche un pixel de la color aux coords x;y à l'écran */ +{ + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 2)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 3)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 2)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 3)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 2)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 3)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 2)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 3)=color; +} + +byte Read_pixel_quad (word x,word y) +/* On retourne la couleur du pixel aux coords données */ +{ + return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); +} + +void Block_quad (word start_x,word start_y,word width,word height,byte color) +/* On affiche un rectangle de la couleur donnée */ +{ + SDL_Rect rectangle; + rectangle.x=start_x*ZOOMX; + rectangle.y=start_y*ZOOMY; + rectangle.w=width*ZOOMX; + rectangle.h=height*ZOOMY; + SDL_FillRect(Screen_SDL,&rectangle,color); +} + +void Display_part_of_screen_quad (word width,word height,word image_width) +/* Afficher une partie de l'image telle quelle sur l'écran */ +{ + byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) + byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) + int y; + int dy; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + // On fait une copie de la ligne + for (dy=width;dy>0;dy--) + { + *(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; + src++; + dest+=ZOOMX; + } + // On double la ligne qu'on vient de copier + memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + // On la triple + memcpy(dest-width*ZOOMX+2*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + // On la quadruple + memcpy(dest-width*ZOOMX+3*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + //Update_rect(0,0,width,height); +} + +void Pixel_preview_normal_quad (word x,word y,byte color) +/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image + * dans l'écran, en mode normal (pas en mode loupe) + * Note: si on modifie cette procédure, il faudra penser à faire également + * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ +{ +// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) + Pixel_quad(x-Main_offset_X,y-Main_offset_Y,color); +} + +void Pixel_preview_magnifier_quad (word x,word y,byte color) +{ + // Affiche le pixel dans la partie non zoomée + Pixel_quad(x-Main_offset_X,y-Main_offset_Y,color); + + // Regarde si on doit aussi l'afficher dans la partie zoomée + if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom + && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) + { + // On est dedans + int height; + int y_zoom = Zoom_factor_table[y-Main_magnifier_offset_Y]; + + if (Menu_Y - y_zoom < Main_magnifier_factor) + // On ne doit dessiner qu'un morceau du pixel + // sinon on dépasse sur le menu + height = Menu_Y - y_zoom; + else + height = Main_magnifier_factor; + + Block_quad( + Zoom_factor_table[x-Main_magnifier_offset_X]+Main_X_zoom, + y_zoom, Main_magnifier_factor, height, color + ); + } +} + +void Horizontal_XOR_line_quad(word x_pos,word y_pos,word width) +{ + //On calcule la valeur initiale de dest: + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; + + int x; + + for (x=0;x0;i--) + { + *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*(dest)=~*(dest); + dest+=VIDEO_LINE_WIDTH*ZOOMY; + } +} + +void Display_brush_color_quad(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = Brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+3*VIDEO_LINE_WIDTH+3) = *(dest+3*VIDEO_LINE_WIDTH+2) = *(dest+3*VIDEO_LINE_WIDTH+1) = *(dest+3*VIDEO_LINE_WIDTH) = *(dest+2*VIDEO_LINE_WIDTH+3) = *(dest+2*VIDEO_LINE_WIDTH+2) = *(dest+2*VIDEO_LINE_WIDTH+1) = *(dest+2*VIDEO_LINE_WIDTH) = *(dest+VIDEO_LINE_WIDTH+3) = *(dest+VIDEO_LINE_WIDTH+2) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+3) = *(dest+2) = *(dest+1) = *dest = *src; + } + + // Pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Display_brush_mono_quad(word x_pos, word y_pos, + word x_offset, word y_offset, word width, word height, + byte transp_color, byte color, word brush_width) +/* On affiche la brosse en monochrome */ +{ + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à + // l'écran + byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds + // la brosse + int x,y; + + for(y=height;y!=0;y--) + //Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + if (*src!=transp_color) + *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=color; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=brush_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Clear_brush_quad(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) +{ + byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) + byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) + int y; + int x; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +// Affiche une brosse (arbitraire) à l'écran +void Display_brush_quad(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; + } + + // Pixel suivant + src++; dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } +} + +void Remap_screen_quad(word x_pos,word y_pos,word width,word height,byte * conversion_table) +{ + // dest = coords a l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + int x,y; + + // Pour chaque ligne + for(y=height;y>0;y--) + { + // Pour chaque pixel + for(x=width;x>0;x--) + { + *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest= + conversion_table[*dest]; + dest +=ZOOMX; + } + + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + + Update_rect(x_pos,y_pos,width,height); +} + +void Display_line_on_screen_fast_quad(word x_pos,word y_pos,word width,byte * line) +/* On affiche toute une ligne de pixels telle quelle. */ +/* Utilisée si le buffer contient déja des pixel doublés. */ +{ + memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+2)*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+3)*VIDEO_LINE_WIDTH,line,width*ZOOMX); +} + +void Display_line_on_screen_quad(word x_pos,word y_pos,word width,byte * line) +/* On affiche une ligne de pixels en les doublant. */ +{ + int x; + byte *dest; + dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; + for(x=width;x>0;x--) + { + *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*line; + dest+=ZOOMX; + line++; + } +} +void Display_transparent_mono_line_on_screen_quad( + word x_pos, word y_pos, word width, byte* line, + byte transp_color, byte color) +// Affiche une ligne à l'écran avec une couleur + transparence. +// Utilisé par les brosses en mode zoom +{ + byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; + int x; + // Pour chaque pixel + for(x=0;x 0); + src += image_width; + } +// ATTENTION on n'arrive jamais ici ! +} + +// Affiche une partie de la brosse couleur zoomée +void Display_brush_color_zoom_quad(word x_pos,word y_pos, + word x_offset,word y_offset, + word width, // width non zoomée + word end_y_pos,byte transp_color, + word brush_width, // width réelle de la brosse + byte * buffer) +{ + byte* src = Brush+y_offset*brush_width + x_offset; + word y = y_pos; + byte bx; + + // Pour chaque ligne + while(1) + { + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + // On affiche facteur fois la ligne zoomée + for(bx=Main_magnifier_factor;bx>0;bx--) + { + byte* line_src = buffer; + byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + word x; + // Pour chaque pixel de la ligne + for(x = width*Main_magnifier_factor;x > 0;x--) + { + if(*line_src!=transp_color) + { + *(dest+3)=*(dest+2)=*(dest+1)=*dest = *line_src; + } + line_src++; + dest+=ZOOMX; + } + // Double the line + memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + // Triple the line + memcpy(Screen_pixels + (y*ZOOMY+2)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + // Quadruple it + memcpy(Screen_pixels + (y*ZOOMY+3)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + y++; + if(y==end_y_pos) + { + return; + } + } + src += brush_width; + } + // ATTENTION zone jamais atteinte +} + +void Display_brush_mono_zoom_quad(word x_pos, word y_pos, + word x_offset, word y_offset, + word width, // width non zoomée + word end_y_pos, + byte transp_color, byte color, + word brush_width, // width réelle de la brosse + byte * buffer +) + +{ + byte* src = Brush + y_offset * brush_width + x_offset; + int y=y_pos*ZOOMY; + + //Pour chaque ligne à zoomer : + while(1) + { + int bx; + // src = Ligne originale + // On éclate la ligne + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + + // On affiche la ligne Facteur fois à l'écran (sur des + // lignes consécutives) + bx = Main_magnifier_factor*ZOOMY; + + // Pour chaque ligne écran + do + { + // On affiche la ligne zoomée + Display_transparent_mono_line_on_screen_quad( + x_pos, y, width * Main_magnifier_factor, + buffer, transp_color, color + ); + // On passe à la ligne suivante + y++; + // On vérifie qu'on est pas à la ligne finale + if(y == end_y_pos*ZOOMY) + { + Update_rect( x_pos, y_pos, + width * Main_magnifier_factor, end_y_pos - y_pos ); + return; + } + bx --; + } + while (bx > 0); + + // Passage à la ligne suivante dans la brosse aussi + src+=brush_width; + } +} + +void Clear_brush_scaled_quad(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) +{ + + // En fait on va recopier l'image non zoomée dans la partie zoomée ! + byte* src = Main_screen + y_offset * image_width + x_offset; + int y = y_pos; + int bx; + + // Pour chaque ligne à zoomer + while(1){ + Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); + + bx=Main_magnifier_factor; + + // Pour chaque ligne + do{ + // TODO a verifier + Display_line_on_screen_fast_quad(x_pos,y, + width * Main_magnifier_factor,buffer); + + // Ligne suivante + y++; + if(y==end_y_pos) + { + Update_rect(x_pos,y_pos, + width*Main_magnifier_factor,end_y_pos-y_pos); + return; + } + bx--; + }while(bx!=0); + + src+= image_width; + } +} + + diff --git a/pxquad.h b/pxquad.h new file mode 100644 index 00000000..94de70ad --- /dev/null +++ b/pxquad.h @@ -0,0 +1,50 @@ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + Copyright 2007 Adrien Destugues + Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) + + Grafx2 is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 + of the License. + + Grafx2 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grafx2; if not, see or + write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file pxquad.h +/// Renderer for quadruple pixels (4x4). +////////////////////////////////////////////////////////////////////////////// + +#include "struct.h" + + void Pixel_quad (word x,word y,byte color); + byte Read_pixel_quad (word x,word y); + void Block_quad (word start_x,word start_y,word width,word height,byte color); + void Pixel_preview_normal_quad (word x,word y,byte color); + void Pixel_preview_magnifier_quad (word x,word y,byte color); + void Horizontal_XOR_line_quad (word x_pos,word y_pos,word width); + void Vertical_XOR_line_quad (word x_pos,word y_pos,word height); + void Display_brush_color_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + void Display_brush_mono_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); + void Clear_brush_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); + void Remap_screen_quad (word x_pos,word y_pos,word width,word height,byte * conversion_table); + void Display_part_of_screen_quad (word width,word height,word image_width); + void Display_line_on_screen_quad (word x_pos,word y_pos,word width,byte * line); + void Read_line_screen_quad (word x_pos,word y_pos,word width,byte * line); + void Display_part_of_screen_scaled_quad(word width,word height,word image_width,byte * buffer); + void Display_brush_color_zoom_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); + void Display_brush_mono_zoom_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); + void Clear_brush_scaled_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); + void Display_brush_quad (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + + void Display_line_on_screen_fast_quad (word x_pos,word y_pos,word width,byte * line); diff --git a/pxsimple.c b/pxsimple.c index 49cc00ae..fb745bce 100644 --- a/pxsimple.c +++ b/pxsimple.c @@ -32,13 +32,13 @@ void Pixel_simple (word x,word y,byte color) /* Affiche un pixel de la color aux coords x;y à l'écran */ { - *(Screen_pixels + x + y * Screen_width)=color; + *(Screen_pixels + x + y * VIDEO_LINE_WIDTH)=color; } byte Read_pixel_simple (word x,word y) /* On retourne la couleur du pixel aux coords données */ { - return *( Screen_pixels + y * Screen_width + x ); + return *( Screen_pixels + y * VIDEO_LINE_WIDTH + x ); } void Block_simple (word start_x,word start_y,word width,word height,byte color) @@ -67,7 +67,7 @@ void Display_part_of_screen_simple (word width,word height,word image_width) // On passe à la ligne suivante src+=image_width; - dest+=Screen_width; + dest+=VIDEO_LINE_WIDTH; } //Update_rect(0,0,width,height); } @@ -112,7 +112,7 @@ void Pixel_preview_magnifier_simple (word x,word y,byte color) void Horizontal_XOR_line_simple(word x_pos,word y_pos,word width) { //On calcule la valeur initiale de dest: - byte* dest=y_pos*Screen_width+x_pos+Screen_pixels; + byte* dest=y_pos*VIDEO_LINE_WIDTH+x_pos+Screen_pixels; int x; @@ -126,15 +126,15 @@ void Vertical_XOR_line_simple(word x_pos,word y_pos,word height) byte color; for (i=y_pos;i0;y--) + for(y=height*ZOOMY;y>0;y--) { // Pour chaque pixel for(x=width;x>0;x--) @@ -277,7 +280,7 @@ void Remap_screen_tall(word x_pos,word y_pos,word width,word height,byte * conve dest ++; } - dest = dest + Screen_width - width; + dest = dest + VIDEO_LINE_WIDTH - width; } Update_rect(x_pos,y_pos,width,height); @@ -286,13 +289,13 @@ void Remap_screen_tall(word x_pos,word y_pos,word width,word height,byte * conve void Display_line_on_screen_tall(word x_pos,word y_pos,word width,byte * line) /* On affiche toute une ligne de pixels. Utilisé pour les textes. */ { - memcpy(Screen_pixels+x_pos+y_pos*2*Screen_width,line,width); - memcpy(Screen_pixels+x_pos+(y_pos*2+1)*Screen_width,line,width); + memcpy(Screen_pixels+x_pos+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width); + memcpy(Screen_pixels+x_pos+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width); } void Read_line_screen_tall(word x_pos,word y_pos,word width,byte * line) { - memcpy(line,Screen_width * 2 * y_pos + x_pos + Screen_pixels,width); + memcpy(line,VIDEO_LINE_WIDTH*ZOOMY*y_pos + x_pos + Screen_pixels,width); } void Display_part_of_screen_scaled_tall( @@ -312,7 +315,7 @@ void Display_part_of_screen_scaled_tall( // On éclate la ligne Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On l'affiche Facteur fois, sur des lignes consécutives - x = Main_magnifier_factor*2; + x = Main_magnifier_factor*ZOOMY; // Pour chaque ligne do{ // On affiche la ligne zoomée @@ -322,7 +325,7 @@ void Display_part_of_screen_scaled_tall( ); // On passe à la suivante y++; - if(y==height*2) + if(y==height*ZOOMY) { Update_rect(Main_X_zoom,0, width*Main_magnifier_factor,height); @@ -354,8 +357,8 @@ void Display_brush_color_zoom_tall(word x_pos,word y_pos, // On affiche facteur fois la ligne zoomée for(bx=Main_magnifier_factor;bx>0;bx--) { - Display_transparent_line_on_screen_simple(x_pos,y*2,width*Main_magnifier_factor,buffer,transp_color); - memcpy(Screen_pixels + (y*2 +1) * Screen_width + x_pos, Screen_pixels + y*2* Screen_width + x_pos, width*Main_magnifier_factor); + Display_transparent_line_on_screen_simple(x_pos,y*ZOOMY,width*Main_magnifier_factor,buffer,transp_color); + memcpy(Screen_pixels + (y*ZOOMY +1) * VIDEO_LINE_WIDTH + x_pos, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos, width*Main_magnifier_factor); y++; if(y==end_y_pos) { @@ -378,7 +381,7 @@ void Display_brush_mono_zoom_tall(word x_pos, word y_pos, { byte* src = Brush + y_offset * brush_width + x_offset; - int y=y_pos*2; + int y=y_pos*ZOOMY; //Pour chaque ligne à zoomer : while(1) @@ -390,7 +393,7 @@ void Display_brush_mono_zoom_tall(word x_pos, word y_pos, // On affiche la ligne Facteur fois à l'écran (sur des // lignes consécutives) - bx = Main_magnifier_factor*2; + bx = Main_magnifier_factor*ZOOMY; // Pour chaque ligne écran do @@ -403,7 +406,7 @@ void Display_brush_mono_zoom_tall(word x_pos, word y_pos, // On passe à la ligne suivante y++; // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos*2) + if(y == end_y_pos*ZOOMY) { Update_rect( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); diff --git a/pxtall2.c b/pxtall2.c new file mode 100644 index 00000000..71488126 --- /dev/null +++ b/pxtall2.c @@ -0,0 +1,526 @@ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + Copyright 2008 Franck Charlet + Copyright 2007 Adrien Destugues + Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) + + Grafx2 is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 + of the License. + + Grafx2 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grafx2; if not, see or + write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include +#include +#include +#include "global.h" +#include "sdlscreen.h" +#include "misc.h" +#include "pxtall2.h" + +#define ZOOMX 2 +#define ZOOMY 4 + +void Pixel_tall2 (word x,word y,byte color) +/* Affiche un pixel de la color aux coords x;y à l'écran */ +{ + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 1)=color; +} + +byte Read_pixel_tall2 (word x,word y) +/* On retourne la couleur du pixel aux coords données */ +{ + return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); +} + +void Block_tall2 (word start_x,word start_y,word width,word height,byte color) +/* On affiche un rectangle de la couleur donnée */ +{ + SDL_Rect rectangle; + rectangle.x=start_x*ZOOMX; + rectangle.y=start_y*ZOOMY; + rectangle.w=width*ZOOMX; + rectangle.h=height*ZOOMY; + SDL_FillRect(Screen_SDL,&rectangle,color); +} + +void Display_part_of_screen_tall2 (word width,word height,word image_width) +/* Afficher une partie de l'image telle quelle sur l'écran */ +{ + byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) + byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) + int y; + int dy; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + // On fait une copie de la ligne + for (dy=width;dy>0;dy--) + { + *(dest+1)=*dest=*src; + src++; + dest+=ZOOMX; + } + // On double la ligne qu'on vient de copier + memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + // On la triple + memcpy(dest-width*ZOOMX+2*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + // On la quadruple + memcpy(dest-width*ZOOMX+3*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + //Update_rect(0,0,width,height); +} + +void Pixel_preview_normal_tall2 (word x,word y,byte color) +/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image + * dans l'écran, en mode normal (pas en mode loupe) + * Note: si on modifie cette procédure, il faudra penser à faire également + * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ +{ +// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) + Pixel_tall2(x-Main_offset_X,y-Main_offset_Y,color); +} + +void Pixel_preview_magnifier_tall2 (word x,word y,byte color) +{ + // Affiche le pixel dans la partie non zoomée + Pixel_tall2(x-Main_offset_X,y-Main_offset_Y,color); + + // Regarde si on doit aussi l'afficher dans la partie zoomée + if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom + && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) + { + // On est dedans + int height; + int y_zoom = Zoom_factor_table[y-Main_magnifier_offset_Y]; + + if (Menu_Y - y_zoom < Main_magnifier_factor) + // On ne doit dessiner qu'un morceau du pixel + // sinon on dépasse sur le menu + height = Menu_Y - y_zoom; + else + height = Main_magnifier_factor; + + Block_tall2( + Zoom_factor_table[x-Main_magnifier_offset_X]+Main_X_zoom, + y_zoom, Main_magnifier_factor, height, color + ); + } +} + +void Horizontal_XOR_line_tall2(word x_pos,word y_pos,word width) +{ + //On calcule la valeur initiale de dest: + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; + + int x; + + for (x=0;x0;i--) + { + *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=~*(dest); + dest+=VIDEO_LINE_WIDTH*ZOOMY; + } +} + +void Display_brush_color_tall2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = Brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+3*VIDEO_LINE_WIDTH+1) = *(dest+3*VIDEO_LINE_WIDTH) = *(dest+2*VIDEO_LINE_WIDTH+1) = *(dest+2*VIDEO_LINE_WIDTH) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+1) = *dest = *src; + } + + // Pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Display_brush_mono_tall2(word x_pos, word y_pos, + word x_offset, word y_offset, word width, word height, + byte transp_color, byte color, word brush_width) +/* On affiche la brosse en monochrome */ +{ + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à + // l'écran + byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds + // la brosse + int x,y; + + for(y=height;y!=0;y--) + //Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + if (*src!=transp_color) + *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=color; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=brush_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Clear_brush_tall2(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) +{ + byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) + byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) + int y; + int x; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=*src; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +// Affiche une brosse (arbitraire) à l'écran +void Display_brush_tall2(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=*src; + } + + // Pixel suivant + src++; dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } +} + +void Remap_screen_tall2(word x_pos,word y_pos,word width,word height,byte * conversion_table) +{ + // dest = coords a l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + int x,y; + + // Pour chaque ligne + for(y=height;y>0;y--) + { + // Pour chaque pixel + for(x=width;x>0;x--) + { + *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)= + conversion_table[*dest]; + dest +=ZOOMX; + } + + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + + Update_rect(x_pos,y_pos,width,height); +} + +void Display_line_on_screen_fast_tall2(word x_pos,word y_pos,word width,byte * line) +/* On affiche toute une ligne de pixels telle quelle. */ +/* Utilisée si le buffer contient déja des pixel doublés. */ +{ + memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+2)*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+3)*VIDEO_LINE_WIDTH,line,width*ZOOMX); +} + +void Display_line_on_screen_tall2(word x_pos,word y_pos,word width,byte * line) +/* On affiche une ligne de pixels en les doublant. */ +{ + int x; + byte *dest; + dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; + for(x=width;x>0;x--) + { + *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=*line; + dest+=ZOOMX; + line++; + } +} +void Display_transparent_mono_line_on_screen_tall2( + word x_pos, word y_pos, word width, byte* line, + byte transp_color, byte color) +// Affiche une ligne à l'écran avec une couleur + transparence. +// Utilisé par les brosses en mode zoom +{ + byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; + int x; + // Pour chaque pixel + for(x=0;x 0); + src += image_width; + } +// ATTENTION on n'arrive jamais ici ! +} + +// Affiche une partie de la brosse couleur zoomée +void Display_brush_color_zoom_tall2(word x_pos,word y_pos, + word x_offset,word y_offset, + word width, // width non zoomée + word end_y_pos,byte transp_color, + word brush_width, // width réelle de la brosse + byte * buffer) +{ + byte* src = Brush+y_offset*brush_width + x_offset; + word y = y_pos; + byte bx; + + // Pour chaque ligne + while(1) + { + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + // On affiche facteur fois la ligne zoomée + for(bx=Main_magnifier_factor;bx>0;bx--) + { + byte* line_src = buffer; + byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + word x; + // Pour chaque pixel de la ligne + for(x = width*Main_magnifier_factor;x > 0;x--) + { + if(*line_src!=transp_color) + { + *(dest+1)=*dest = *line_src; + } + line_src++; + dest+=ZOOMX; + } + // Double the line + memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + // Triple the line + memcpy(Screen_pixels + (y*ZOOMY+2)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + // Quadruple it + memcpy(Screen_pixels + (y*ZOOMY+3)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + y++; + if(y==end_y_pos) + { + return; + } + } + src += brush_width; + } + // ATTENTION zone jamais atteinte +} + +void Display_brush_mono_zoom_tall2(word x_pos, word y_pos, + word x_offset, word y_offset, + word width, // width non zoomée + word end_y_pos, + byte transp_color, byte color, + word brush_width, // width réelle de la brosse + byte * buffer +) + +{ + byte* src = Brush + y_offset * brush_width + x_offset; + int y=y_pos*ZOOMY; + + //Pour chaque ligne à zoomer : + while(1) + { + int bx; + // src = Ligne originale + // On éclate la ligne + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + + // On affiche la ligne Facteur fois à l'écran (sur des + // lignes consécutives) + bx = Main_magnifier_factor*ZOOMY; + + // Pour chaque ligne écran + do + { + // On affiche la ligne zoomée + Display_transparent_mono_line_on_screen_tall2( + x_pos, y, width * Main_magnifier_factor, + buffer, transp_color, color + ); + // On passe à la ligne suivante + y++; + // On vérifie qu'on est pas à la ligne finale + if(y == end_y_pos*ZOOMY) + { + Update_rect( x_pos, y_pos, + width * Main_magnifier_factor, end_y_pos - y_pos ); + return; + } + bx --; + } + while (bx > 0); + + // Passage à la ligne suivante dans la brosse aussi + src+=brush_width; + } +} + +void Clear_brush_scaled_tall2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) +{ + + // En fait on va recopier l'image non zoomée dans la partie zoomée ! + byte* src = Main_screen + y_offset * image_width + x_offset; + int y = y_pos; + int bx; + + // Pour chaque ligne à zoomer + while(1){ + Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); + + bx=Main_magnifier_factor; + + // Pour chaque ligne + do{ + // TODO a verifier + Display_line_on_screen_fast_tall2(x_pos,y, + width * Main_magnifier_factor,buffer); + + // Ligne suivante + y++; + if(y==end_y_pos) + { + Update_rect(x_pos,y_pos, + width*Main_magnifier_factor,end_y_pos-y_pos); + return; + } + bx--; + }while(bx!=0); + + src+= image_width; + } +} + + diff --git a/pxtall2.h b/pxtall2.h new file mode 100644 index 00000000..d0e27e33 --- /dev/null +++ b/pxtall2.h @@ -0,0 +1,50 @@ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + Copyright 2007 Adrien Destugues + Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) + + Grafx2 is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 + of the License. + + Grafx2 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grafx2; if not, see or + write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file pxtall2.h +/// Renderer for double-tall pixels (2x4). +////////////////////////////////////////////////////////////////////////////// + +#include "struct.h" + + void Pixel_tall2 (word x,word y,byte color); + byte Read_pixel_tall2 (word x,word y); + void Block_tall2 (word start_x,word start_y,word width,word height,byte color); + void Pixel_preview_normal_tall2 (word x,word y,byte color); + void Pixel_preview_magnifier_tall2 (word x,word y,byte color); + void Horizontal_XOR_line_tall2 (word x_pos,word y_pos,word width); + void Vertical_XOR_line_tall2 (word x_pos,word y_pos,word height); + void Display_brush_color_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + void Display_brush_mono_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); + void Clear_brush_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); + void Remap_screen_tall2 (word x_pos,word y_pos,word width,word height,byte * conversion_table); + void Display_part_of_screen_tall2 (word width,word height,word image_width); + void Display_line_on_screen_tall2 (word x_pos,word y_pos,word width,byte * line); + void Read_line_screen_tall2 (word x_pos,word y_pos,word width,byte * line); + void Display_part_of_screen_scaled_tall2(word width,word height,word image_width,byte * buffer); + void Display_brush_color_zoom_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); + void Display_brush_mono_zoom_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); + void Clear_brush_scaled_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); + void Display_brush_tall2 (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + + void Display_line_on_screen_fast_tall2 (word x_pos,word y_pos,word width,byte * line); diff --git a/pxtriple.c b/pxtriple.c new file mode 100644 index 00000000..662e81ef --- /dev/null +++ b/pxtriple.c @@ -0,0 +1,522 @@ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + Copyright 2008 Franck Charlet + Copyright 2007 Adrien Destugues + Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) + + Grafx2 is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 + of the License. + + Grafx2 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grafx2; if not, see or + write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include +#include +#include +#include "global.h" +#include "sdlscreen.h" +#include "misc.h" +#include "pxtriple.h" + +#define ZOOMX 3 +#define ZOOMY 3 + +void Pixel_triple (word x,word y,byte color) +/* Affiche un pixel de la color aux coords x;y à l'écran */ +{ + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 2)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 2)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 2)=color; +} + +byte Read_pixel_triple (word x,word y) +/* On retourne la couleur du pixel aux coords données */ +{ + return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); +} + +void Block_triple (word start_x,word start_y,word width,word height,byte color) +/* On affiche un rectangle de la couleur donnée */ +{ + SDL_Rect rectangle; + rectangle.x=start_x*ZOOMX; + rectangle.y=start_y*ZOOMY; + rectangle.w=width*ZOOMX; + rectangle.h=height*ZOOMY; + SDL_FillRect(Screen_SDL,&rectangle,color); +} + +void Display_part_of_screen_triple (word width,word height,word image_width) +/* Afficher une partie de l'image telle quelle sur l'écran */ +{ + byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) + byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) + int y; + int dy; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + // On fait une copie de la ligne + for (dy=width;dy>0;dy--) + { + *(dest+2)=*(dest+1)=*dest=*src; + src++; + dest+=ZOOMX; + } + // On double la ligne qu'on vient de copier + memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + // On la triple + memcpy(dest-width*ZOOMX+2*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + //Update_rect(0,0,width,height); +} + +void Pixel_preview_normal_triple (word x,word y,byte color) +/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image + * dans l'écran, en mode normal (pas en mode loupe) + * Note: si on modifie cette procédure, il faudra penser à faire également + * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ +{ +// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) + Pixel_triple(x-Main_offset_X,y-Main_offset_Y,color); +} + +void Pixel_preview_magnifier_triple (word x,word y,byte color) +{ + // Affiche le pixel dans la partie non zoomée + Pixel_triple(x-Main_offset_X,y-Main_offset_Y,color); + + // Regarde si on doit aussi l'afficher dans la partie zoomée + if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom + && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) + { + // On est dedans + int height; + int y_zoom = Zoom_factor_table[y-Main_magnifier_offset_Y]; + + if (Menu_Y - y_zoom < Main_magnifier_factor) + // On ne doit dessiner qu'un morceau du pixel + // sinon on dépasse sur le menu + height = Menu_Y - y_zoom; + else + height = Main_magnifier_factor; + + Block_triple( + Zoom_factor_table[x-Main_magnifier_offset_X]+Main_X_zoom, + y_zoom, Main_magnifier_factor, height, color + ); + } +} + +void Horizontal_XOR_line_triple(word x_pos,word y_pos,word width) +{ + //On calcule la valeur initiale de dest: + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; + + int x; + + for (x=0;x0;i--) + { + *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=~*dest; + dest+=VIDEO_LINE_WIDTH*ZOOMY; + } +} + +void Display_brush_color_triple(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = Brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+2*VIDEO_LINE_WIDTH+2) = *(dest+2*VIDEO_LINE_WIDTH+1) = *(dest+2*VIDEO_LINE_WIDTH) = *(dest+VIDEO_LINE_WIDTH+2) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+2) = *(dest+1) = *dest = *src; + } + + // Pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Display_brush_mono_triple(word x_pos, word y_pos, + word x_offset, word y_offset, word width, word height, + byte transp_color, byte color, word brush_width) +/* On affiche la brosse en monochrome */ +{ + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à + // l'écran + byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds + // la brosse + int x,y; + + for(y=height;y!=0;y--) + //Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + if (*src!=transp_color) + *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=color; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=brush_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Clear_brush_triple(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) +{ + byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) + byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) + int y; + int x; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=*src; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +// Affiche une brosse (arbitraire) à l'écran +void Display_brush_triple(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=*src; + } + + // Pixel suivant + src++; dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } +} + +void Remap_screen_triple(word x_pos,word y_pos,word width,word height,byte * conversion_table) +{ + // dest = coords a l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + int x,y; + + // Pour chaque ligne + for(y=height;y>0;y--) + { + // Pour chaque pixel + for(x=width;x>0;x--) + { + *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest= + conversion_table[*dest]; + dest +=ZOOMX; + } + + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + + Update_rect(x_pos,y_pos,width,height); +} + +void Display_line_on_screen_fast_triple(word x_pos,word y_pos,word width,byte * line) +/* On affiche toute une ligne de pixels telle quelle. */ +/* Utilisée si le buffer contient déja des pixel doublés. */ +{ + memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+2)*VIDEO_LINE_WIDTH,line,width*ZOOMX); +} + +void Display_line_on_screen_triple(word x_pos,word y_pos,word width,byte * line) +/* On affiche une ligne de pixels en les doublant. */ +{ + int x; + byte *dest; + dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; + for(x=width;x>0;x--) + { + *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=*line; + dest+=ZOOMX; + line++; + } +} +void Display_transparent_mono_line_on_screen_triple( + word x_pos, word y_pos, word width, byte* line, + byte transp_color, byte color) +// Affiche une ligne à l'écran avec une couleur + transparence. +// Utilisé par les brosses en mode zoom +{ + byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; + int x; + // Pour chaque pixel + for(x=0;x 0); + src += image_width; + } +// ATTENTION on n'arrive jamais ici ! +} + +// Affiche une partie de la brosse couleur zoomée +void Display_brush_color_zoom_triple(word x_pos,word y_pos, + word x_offset,word y_offset, + word width, // width non zoomée + word end_y_pos,byte transp_color, + word brush_width, // width réelle de la brosse + byte * buffer) +{ + byte* src = Brush+y_offset*brush_width + x_offset; + word y = y_pos; + byte bx; + + // Pour chaque ligne + while(1) + { + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + // On affiche facteur fois la ligne zoomée + for(bx=Main_magnifier_factor;bx>0;bx--) + { + byte* line_src = buffer; + byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + word x; + // Pour chaque pixel de la ligne + for(x = width*Main_magnifier_factor;x > 0;x--) + { + if(*line_src!=transp_color) + { + *(dest+2)=*(dest+1)=*dest = *line_src; + } + line_src++; + dest+=ZOOMX; + } + // Double the line + memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + // Triple the line + memcpy(Screen_pixels + (y*ZOOMY+2)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + y++; + if(y==end_y_pos) + { + return; + } + } + src += brush_width; + } + // ATTENTION zone jamais atteinte +} + +void Display_brush_mono_zoom_triple(word x_pos, word y_pos, + word x_offset, word y_offset, + word width, // width non zoomée + word end_y_pos, + byte transp_color, byte color, + word brush_width, // width réelle de la brosse + byte * buffer +) + +{ + byte* src = Brush + y_offset * brush_width + x_offset; + int y=y_pos*ZOOMY; + + //Pour chaque ligne à zoomer : + while(1) + { + int bx; + // src = Ligne originale + // On éclate la ligne + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + + // On affiche la ligne Facteur fois à l'écran (sur des + // lignes consécutives) + bx = Main_magnifier_factor*ZOOMY; + + // Pour chaque ligne écran + do + { + // On affiche la ligne zoomée + Display_transparent_mono_line_on_screen_triple( + x_pos, y, width * Main_magnifier_factor, + buffer, transp_color, color + ); + // On passe à la ligne suivante + y++; + // On vérifie qu'on est pas à la ligne finale + if(y == end_y_pos*ZOOMY) + { + Update_rect( x_pos, y_pos, + width * Main_magnifier_factor, end_y_pos - y_pos ); + return; + } + bx --; + } + while (bx > 0); + + // Passage à la ligne suivante dans la brosse aussi + src+=brush_width; + } +} + +void Clear_brush_scaled_triple(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) +{ + + // En fait on va recopier l'image non zoomée dans la partie zoomée ! + byte* src = Main_screen + y_offset * image_width + x_offset; + int y = y_pos; + int bx; + + // Pour chaque ligne à zoomer + while(1){ + Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); + + bx=Main_magnifier_factor; + + // Pour chaque ligne + do{ + // TODO a verifier + Display_line_on_screen_fast_triple(x_pos,y, + width * Main_magnifier_factor,buffer); + + // Ligne suivante + y++; + if(y==end_y_pos) + { + Update_rect(x_pos,y_pos, + width*Main_magnifier_factor,end_y_pos-y_pos); + return; + } + bx--; + }while(bx!=0); + + src+= image_width; + } +} + + diff --git a/pxtriple.h b/pxtriple.h new file mode 100644 index 00000000..416fed42 --- /dev/null +++ b/pxtriple.h @@ -0,0 +1,50 @@ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + Copyright 2007 Adrien Destugues + Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) + + Grafx2 is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 + of the License. + + Grafx2 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grafx2; if not, see or + write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file pxtriple.h +/// Renderer for triple pixels (3x3). +////////////////////////////////////////////////////////////////////////////// + +#include "struct.h" + + void Pixel_triple (word x,word y,byte color); + byte Read_pixel_triple (word x,word y); + void Block_triple (word start_x,word start_y,word width,word height,byte color); + void Pixel_preview_normal_triple (word x,word y,byte color); + void Pixel_preview_magnifier_triple (word x,word y,byte color); + void Horizontal_XOR_line_triple (word x_pos,word y_pos,word width); + void Vertical_XOR_line_triple (word x_pos,word y_pos,word height); + void Display_brush_color_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + void Display_brush_mono_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); + void Clear_brush_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); + void Remap_screen_triple (word x_pos,word y_pos,word width,word height,byte * conversion_table); + void Display_part_of_screen_triple (word width,word height,word image_width); + void Display_line_on_screen_triple (word x_pos,word y_pos,word width,byte * line); + void Read_line_screen_triple (word x_pos,word y_pos,word width,byte * line); + void Display_part_of_screen_scaled_triple(word width,word height,word image_width,byte * buffer); + void Display_brush_color_zoom_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); + void Display_brush_mono_zoom_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); + void Clear_brush_scaled_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); + void Display_brush_triple (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + + void Display_line_on_screen_fast_triple (word x_pos,word y_pos,word width,byte * line); diff --git a/pxwide.c b/pxwide.c index 04477173..1d38ae90 100644 --- a/pxwide.c +++ b/pxwide.c @@ -29,27 +29,30 @@ #include "misc.h" #include "pxwide.h" +#define ZOOMX 2 +#define ZOOMY 1 + void Pixel_wide (word x,word y,byte color) /* Affiche un pixel de la color aux coords x;y à l'écran */ { - *(Screen_pixels + x * 2 + y * 2 * Screen_width)=color; - *(Screen_pixels + x * 2 + y * 2 * Screen_width + 1)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; } byte Read_pixel_wide (word x,word y) /* On retourne la couleur du pixel aux coords données */ { - return *( Screen_pixels + y * 2 * Screen_width + x * 2); + return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); } void Block_wide (word start_x,word start_y,word width,word height,byte color) /* On affiche un rectangle de la couleur donnée */ { SDL_Rect rectangle; - rectangle.x=start_x*2; - rectangle.y=start_y; - rectangle.w=width*2; - rectangle.h=height; + rectangle.x=start_x*ZOOMX; + rectangle.y=start_y*ZOOMY; + rectangle.w=width*ZOOMX; + rectangle.h=height*ZOOMY; SDL_FillRect(Screen_SDL,&rectangle,color); } @@ -69,12 +72,12 @@ void Display_part_of_screen_wide (word width,word height,word image_width) { *(dest+1)=*dest=*src; src++; - dest+=2; + dest+=ZOOMX; } // On passe à la ligne suivante src+=image_width-width; - dest+=(Screen_width - width)*2; + dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; } //Update_rect(0,0,width,height); } @@ -119,32 +122,29 @@ void Pixel_preview_magnifier_wide (word x,word y,byte color) void Horizontal_XOR_line_wide(word x_pos,word y_pos,word width) { //On calcule la valeur initiale de dest: - byte* dest=y_pos*2*Screen_width+x_pos*2+Screen_pixels; + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; int x; - for (x=0;x0;i--) { - color=~*dest; - *dest=color; - *(dest+1)=color; - dest+=Screen_width*2; + *dest=*(dest+1)=~*dest; + dest+=VIDEO_LINE_WIDTH*ZOOMY; } } void Display_brush_color_wide(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * 2 * Screen_width + x_pos * 2; + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; // src = Position dans la brosse byte* src = Brush + y_offset * brush_width + x_offset; @@ -164,11 +164,11 @@ void Display_brush_color_wide(word x_pos,word y_pos,word x_offset,word y_offset, // Pixel suivant src++; - dest+=2; + dest+=ZOOMX; } // On passe à la ligne suivante - dest = dest + (Screen_width - width)*2; + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; src = src + brush_width - width; } Update_rect(x_pos,y_pos,width,height); @@ -179,7 +179,7 @@ void Display_brush_mono_wide(word x_pos, word y_pos, byte transp_color, byte color, word brush_width) /* On affiche la brosse en monochrome */ { - byte* dest=y_pos*2*Screen_width+x_pos*2+Screen_pixels; // dest = adr Destination à + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à // l'écran byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds // la brosse @@ -196,19 +196,19 @@ void Display_brush_mono_wide(word x_pos, word y_pos, // On passe au pixel suivant src++; - dest+=2; + dest+=ZOOMX; } // On passe à la ligne suivante src+=brush_width-width; - dest+=(Screen_width-width)*2; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } void Clear_brush_wide(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) { - byte* dest=Screen_pixels+x_pos*2+y_pos*2*Screen_width; //On va se mettre en 0,0 dans l'écran (dest) + byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) int y; int x; @@ -223,12 +223,12 @@ void Clear_brush_wide(word x_pos,word y_pos,__attribute__((unused)) word x_offse // On passe au pixel suivant src++; - dest+=2; + dest+=ZOOMX; } // On passe à la ligne suivante src+=image_width-width; - dest+=(Screen_width-width)*2; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } @@ -237,7 +237,7 @@ void Clear_brush_wide(word x_pos,word y_pos,__attribute__((unused)) word x_offse void Display_brush_wide(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * 2 * Screen_width + x_pos * 2; + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; // src = Position dans la brosse byte* src = brush + y_offset * brush_width + x_offset; @@ -256,11 +256,11 @@ void Display_brush_wide(byte * brush, word x_pos,word y_pos,word x_offset,word y } // Pixel suivant - src++; dest+=2; + src++; dest+=ZOOMX; } // On passe à la ligne suivante - dest = dest + (Screen_width - width)*2; + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; src = src + brush_width - width; } } @@ -268,7 +268,7 @@ void Display_brush_wide(byte * brush, word x_pos,word y_pos,word x_offset,word y void Remap_screen_wide(word x_pos,word y_pos,word width,word height,byte * conversion_table) { // dest = coords a l'écran - byte* dest = Screen_pixels + y_pos * 2 * Screen_width + x_pos * 2; + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; int x,y; // Pour chaque ligne @@ -278,10 +278,10 @@ void Remap_screen_wide(word x_pos,word y_pos,word width,word height,byte * conve for(x=width;x>0;x--) { *(dest+1) = *dest = conversion_table[*dest]; - dest +=2; + dest +=ZOOMX; } - dest = dest + (Screen_width - width)*2; + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); @@ -291,7 +291,7 @@ void Display_line_on_screen_fast_wide(word x_pos,word y_pos,word width,byte * li /* On affiche toute une ligne de pixels telle quelle. */ /* Utilisée si le buffer contient déja des pixel doublés. */ { - memcpy(Screen_pixels+x_pos*2+y_pos*2*Screen_width,line,width*2); + memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); } void Display_line_on_screen_wide(word x_pos,word y_pos,word width,byte * line) @@ -299,13 +299,11 @@ void Display_line_on_screen_wide(word x_pos,word y_pos,word width,byte * line) { int x; byte *dest; - dest=Screen_pixels+x_pos*2+y_pos*2*Screen_width; + dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; for(x=width;x>0;x--) { - *dest=*line; - dest++; - *dest=*line; - dest++; + *(dest+1)=*dest=*line; + dest+=ZOOMX; line++; } } @@ -315,24 +313,23 @@ void Display_transparent_mono_line_on_screen_wide( // Affiche une ligne à l'écran avec une couleur + transparence. // Utilisé par les brosses en mode zoom { - byte* dest = Screen_pixels+ y_pos*2 * Screen_width + x_pos*2; + byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; int x; // Pour chaque pixel for(x=0;x0;bx--) { - Display_transparent_line_on_screen_wide(x_pos,y,width*Main_magnifier_factor,buffer,transp_color); + Display_transparent_line_on_screen_wide(x_pos,y*ZOOMY,width*Main_magnifier_factor,buffer,transp_color); y++; if(y==end_y_pos) { @@ -437,7 +432,7 @@ void Display_brush_mono_zoom_wide(word x_pos, word y_pos, { byte* src = Brush + y_offset * brush_width + x_offset; - int y=y_pos; + int y=y_pos*ZOOMY; //Pour chaque ligne à zoomer : while(1) @@ -449,7 +444,7 @@ void Display_brush_mono_zoom_wide(word x_pos, word y_pos, // On affiche la ligne Facteur fois à l'écran (sur des // lignes consécutives) - bx = Main_magnifier_factor; + bx = Main_magnifier_factor*ZOOMY; // Pour chaque ligne écran do @@ -462,7 +457,7 @@ void Display_brush_mono_zoom_wide(word x_pos, word y_pos, // On passe à la ligne suivante y++; // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos) + if(y == end_y_pos*ZOOMY) { Update_rect( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); @@ -486,7 +481,7 @@ void Clear_brush_scaled_wide(word x_pos,word y_pos,word x_offset,word y_offset,w // Pour chaque ligne à zoomer while(1){ - Zoom_a_line(src,buffer,Main_magnifier_factor*2,width); + Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); bx=Main_magnifier_factor; diff --git a/pxwide2.c b/pxwide2.c new file mode 100644 index 00000000..43c5c185 --- /dev/null +++ b/pxwide2.c @@ -0,0 +1,516 @@ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + Copyright 2008 Franck Charlet + Copyright 2007 Adrien Destugues + Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) + + Grafx2 is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 + of the License. + + Grafx2 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grafx2; if not, see or + write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include +#include +#include +#include "global.h" +#include "sdlscreen.h" +#include "misc.h" +#include "pxwide2.h" + +#define ZOOMX 4 +#define ZOOMY 2 + +void Pixel_wide2 (word x,word y,byte color) +/* Affiche un pixel de la color aux coords x;y à l'écran */ +{ + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 2)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 3)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 2)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 3)=color; +} + +byte Read_pixel_wide2 (word x,word y) +/* On retourne la couleur du pixel aux coords données */ +{ + return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); +} + +void Block_wide2 (word start_x,word start_y,word width,word height,byte color) +/* On affiche un rectangle de la couleur donnée */ +{ + SDL_Rect rectangle; + rectangle.x=start_x*ZOOMX; + rectangle.y=start_y*ZOOMY; + rectangle.w=width*ZOOMX; + rectangle.h=height*ZOOMY; + SDL_FillRect(Screen_SDL,&rectangle,color); +} + +void Display_part_of_screen_wide2 (word width,word height,word image_width) +/* Afficher une partie de l'image telle quelle sur l'écran */ +{ + byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) + byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) + int y; + int dy; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + // On fait une copie de la ligne + for (dy=width;dy>0;dy--) + { + *(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; + src++; + dest+=ZOOMX; + } + // On double la ligne qu'on vient de copier + memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + //Update_rect(0,0,width,height); +} + +void Pixel_preview_normal_wide2 (word x,word y,byte color) +/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image + * dans l'écran, en mode normal (pas en mode loupe) + * Note: si on modifie cette procédure, il faudra penser à faire également + * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ +{ +// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) + Pixel_wide2(x-Main_offset_X,y-Main_offset_Y,color); +} + +void Pixel_preview_magnifier_wide2 (word x,word y,byte color) +{ + // Affiche le pixel dans la partie non zoomée + Pixel_wide2(x-Main_offset_X,y-Main_offset_Y,color); + + // Regarde si on doit aussi l'afficher dans la partie zoomée + if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom + && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) + { + // On est dedans + int height; + int y_zoom = Zoom_factor_table[y-Main_magnifier_offset_Y]; + + if (Menu_Y - y_zoom < Main_magnifier_factor) + // On ne doit dessiner qu'un morceau du pixel + // sinon on dépasse sur le menu + height = Menu_Y - y_zoom; + else + height = Main_magnifier_factor; + + Block_wide2( + Zoom_factor_table[x-Main_magnifier_offset_X]+Main_X_zoom, + y_zoom, Main_magnifier_factor, height, color + ); + } +} + +void Horizontal_XOR_line_wide2(word x_pos,word y_pos,word width) +{ + //On calcule la valeur initiale de dest: + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; + + int x; + + for (x=0;x0;i--) + { + *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*(dest)=~*(dest); + dest+=VIDEO_LINE_WIDTH*ZOOMY; + } +} + +void Display_brush_color_wide2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = Brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+VIDEO_LINE_WIDTH+3) = *(dest+VIDEO_LINE_WIDTH+2) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+3) = *(dest+2) = *(dest+1) = *dest = *src; + } + + // Pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Display_brush_mono_wide2(word x_pos, word y_pos, + word x_offset, word y_offset, word width, word height, + byte transp_color, byte color, word brush_width) +/* On affiche la brosse en monochrome */ +{ + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à + // l'écran + byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds + // la brosse + int x,y; + + for(y=height;y!=0;y--) + //Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + if (*src!=transp_color) + *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=color; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=brush_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Clear_brush_wide2(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) +{ + byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) + byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) + int y; + int x; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +// Affiche une brosse (arbitraire) à l'écran +void Display_brush_wide2(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; + } + + // Pixel suivant + src++; dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } +} + +void Remap_screen_wide2(word x_pos,word y_pos,word width,word height,byte * conversion_table) +{ + // dest = coords a l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + int x,y; + + // Pour chaque ligne + for(y=height;y>0;y--) + { + // Pour chaque pixel + for(x=width;x>0;x--) + { + *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest= + conversion_table[*dest]; + dest +=ZOOMX; + } + + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + + Update_rect(x_pos,y_pos,width,height); +} + +void Display_line_on_screen_fast_wide2(word x_pos,word y_pos,word width,byte * line) +/* On affiche toute une ligne de pixels telle quelle. */ +/* Utilisée si le buffer contient déja des pixel doublés. */ +{ + memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); +} + +void Display_line_on_screen_wide2(word x_pos,word y_pos,word width,byte * line) +/* On affiche une ligne de pixels en les doublant. */ +{ + int x; + byte *dest; + dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; + for(x=width;x>0;x--) + { + *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*line; + dest+=ZOOMX; + line++; + } +} +void Display_transparent_mono_line_on_screen_wide2( + word x_pos, word y_pos, word width, byte* line, + byte transp_color, byte color) +// Affiche une ligne à l'écran avec une couleur + transparence. +// Utilisé par les brosses en mode zoom +{ + byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; + int x; + // Pour chaque pixel + for(x=0;x 0); + src += image_width; + } +// ATTENTION on n'arrive jamais ici ! +} + +// Affiche une partie de la brosse couleur zoomée +void Display_brush_color_zoom_wide2(word x_pos,word y_pos, + word x_offset,word y_offset, + word width, // width non zoomée + word end_y_pos,byte transp_color, + word brush_width, // width réelle de la brosse + byte * buffer) +{ + byte* src = Brush+y_offset*brush_width + x_offset; + word y = y_pos; + byte bx; + + // Pour chaque ligne + while(1) + { + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + // On affiche facteur fois la ligne zoomée + for(bx=Main_magnifier_factor;bx>0;bx--) + { + byte* line_src = buffer; + byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + word x; + // Pour chaque pixel de la ligne + for(x = width*Main_magnifier_factor;x > 0;x--) + { + if(*line_src!=transp_color) + { + *(dest+3)=*(dest+2)=*(dest+1)=*dest = *line_src; + } + line_src++; + dest+=ZOOMX; + } + // Double the line + memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + y++; + if(y==end_y_pos) + { + return; + } + } + src += brush_width; + } + // ATTENTION zone jamais atteinte +} + +void Display_brush_mono_zoom_wide2(word x_pos, word y_pos, + word x_offset, word y_offset, + word width, // width non zoomée + word end_y_pos, + byte transp_color, byte color, + word brush_width, // width réelle de la brosse + byte * buffer +) + +{ + byte* src = Brush + y_offset * brush_width + x_offset; + int y=y_pos*ZOOMY; + + //Pour chaque ligne à zoomer : + while(1) + { + int bx; + // src = Ligne originale + // On éclate la ligne + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + + // On affiche la ligne Facteur fois à l'écran (sur des + // lignes consécutives) + bx = Main_magnifier_factor*ZOOMY; + + // Pour chaque ligne écran + do + { + // On affiche la ligne zoomée + Display_transparent_mono_line_on_screen_wide2( + x_pos, y, width * Main_magnifier_factor, + buffer, transp_color, color + ); + // On passe à la ligne suivante + y++; + // On vérifie qu'on est pas à la ligne finale + if(y == end_y_pos*ZOOMY) + { + Update_rect( x_pos, y_pos, + width * Main_magnifier_factor, end_y_pos - y_pos ); + return; + } + bx --; + } + while (bx > 0); + + // Passage à la ligne suivante dans la brosse aussi + src+=brush_width; + } +} + +void Clear_brush_scaled_wide2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) +{ + + // En fait on va recopier l'image non zoomée dans la partie zoomée ! + byte* src = Main_screen + y_offset * image_width + x_offset; + int y = y_pos; + int bx; + + // Pour chaque ligne à zoomer + while(1){ + Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); + + bx=Main_magnifier_factor; + + // Pour chaque ligne + do{ + // TODO a verifier + Display_line_on_screen_fast_wide2(x_pos,y, + width * Main_magnifier_factor,buffer); + + // Ligne suivante + y++; + if(y==end_y_pos) + { + Update_rect(x_pos,y_pos, + width*Main_magnifier_factor,end_y_pos-y_pos); + return; + } + bx--; + }while(bx!=0); + + src+= image_width; + } +} + + diff --git a/pxwide2.h b/pxwide2.h new file mode 100644 index 00000000..2ffcf66a --- /dev/null +++ b/pxwide2.h @@ -0,0 +1,50 @@ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + Copyright 2007 Adrien Destugues + Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) + + Grafx2 is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 + of the License. + + Grafx2 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grafx2; if not, see or + write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file pxwide2.h +/// Renderer for double-wide pixels (4x2). +////////////////////////////////////////////////////////////////////////////// + +#include "struct.h" + + void Pixel_wide2 (word x,word y,byte color); + byte Read_pixel_wide2 (word x,word y); + void Block_wide2 (word start_x,word start_y,word width,word height,byte color); + void Pixel_preview_normal_wide2 (word x,word y,byte color); + void Pixel_preview_magnifier_wide2 (word x,word y,byte color); + void Horizontal_XOR_line_wide2 (word x_pos,word y_pos,word width); + void Vertical_XOR_line_wide2 (word x_pos,word y_pos,word height); + void Display_brush_color_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + void Display_brush_mono_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); + void Clear_brush_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); + void Remap_screen_wide2 (word x_pos,word y_pos,word width,word height,byte * conversion_table); + void Display_part_of_screen_wide2 (word width,word height,word image_width); + void Display_line_on_screen_wide2 (word x_pos,word y_pos,word width,byte * line); + void Read_line_screen_wide2 (word x_pos,word y_pos,word width,byte * line); + void Display_part_of_screen_scaled_wide2(word width,word height,word image_width,byte * buffer); + void Display_brush_color_zoom_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); + void Display_brush_mono_zoom_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); + void Clear_brush_scaled_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); + void Display_brush_wide2 (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + + void Display_line_on_screen_fast_wide2 (word x_pos,word y_pos,word width,byte * line); diff --git a/sdlscreen.c b/sdlscreen.c index 6aa55ac9..5c11f5d9 100644 --- a/sdlscreen.c +++ b/sdlscreen.c @@ -28,14 +28,17 @@ #include "errors.h" #include "misc.h" -// Mise à jour minimaliste en nombre de pixels +// Update method that does a large number of small rectangles, aiming +// for a minimum number of total pixels updated. #define UPDATE_METHOD_MULTI_RECTANGLE 1 -// Mise à jour intermédiaire, par rectangle inclusif. +// Intermediate update method, does only one update with the smallest +// rectangle that includes all modified pixels. #define UPDATE_METHOD_CUMULATED 2 -// Mise à jour totale, pour les plate-formes qui imposent un Vsync à chaque mise à jour écran. -#define UPDATE_METHOD_FULL_PAGE 3 +// Total screen update, for platforms that impose a Vsync on each SDL update. +#define UPDATE_METHOD_FULL_PAGE 3 -// UPDATE_METHOD peut être fixé depuis le makefile, sinon c'est ici: +// UPDATE_METHOD can be set from makefile, otherwise it's selected here +// depending on the platform : #ifndef UPDATE_METHOD #if defined(__macosx__) || defined(__FreeBSD__) #define UPDATE_METHOD UPDATE_METHOD_FULL_PAGE @@ -44,13 +47,13 @@ #endif #endif +/// Sets the new screen/window dimensions. void Set_mode_SDL(int *width, int *height, int fullscreen) -/* On règle la résolution de l'écran */ { Screen_SDL=SDL_SetVideoMode(*width,*height,8,(fullscreen?SDL_FULLSCREEN:0)|SDL_RESIZABLE); if(Screen_SDL != NULL) { - // Vérification du mode obtenu (ce n'est pas toujours celui demandé) + // Check the mode we got, in case it was different from the one we requested. if (Screen_SDL->w != *width || Screen_SDL->h != *height) { DEBUG("Error: Got a different video mode than the requested one!",0); @@ -62,7 +65,7 @@ void Set_mode_SDL(int *width, int *height, int fullscreen) else DEBUG("Error: Unable to change video mode!",0); - SDL_ShowCursor(0); // Cache le curseur SDL, on le gère en soft + SDL_ShowCursor(0); // Hide the SDL mouse cursor, we use our own } #if (UPDATE_METHOD == UPDATE_METHOD_CUMULATED) @@ -79,7 +82,7 @@ short Max_Y=10000; void Flush_update(void) { #if (UPDATE_METHOD == UPDATE_METHOD_FULL_PAGE) - // Mise à jour de la totalité de l'écran + // Do a full screen update if (update_is_required) { SDL_UpdateRect(Screen_SDL, 0, 0, 0, 0); @@ -89,7 +92,7 @@ void Flush_update(void) #if (UPDATE_METHOD == UPDATE_METHOD_CUMULATED) if (Min_X>=Max_X || Min_Y>=Max_Y) { - ; // Rien a faire + ; // Nothing to do } else { @@ -137,9 +140,10 @@ void Update_rect(short x, short y, unsigned short width, unsigned short height) } -// Convertit une SDL_Surface (couleurs indexées ou RGB) en tableau de bytes (couleurs indexées) -// Si on passe NULL comme destination, elle est allouée par malloc(). Sinon, -// attention aux dimensions! +// Converts a SDL_Surface (indexed colors or RGB) into an array of bytes +// (indexed colors). +// If dest is NULL, it's allocated by malloc(). Otherwise, be sure to +// pass a buffer of the right dimensions. byte * Surface_to_bytefield(SDL_Surface *source, byte * dest) { byte *src; @@ -171,7 +175,7 @@ byte * Surface_to_bytefield(SDL_Surface *source, byte * dest) } -// Convertit un index de palette en couleur RGB 24 bits +/// Gets the RGB 24-bit color currently associated with a palette index. SDL_Color Color_to_SDL_color(byte index) { SDL_Color color; @@ -182,9 +186,50 @@ SDL_Color Color_to_SDL_color(byte index) return color; } -// Lecture d'un pixel pour une surface SDL. -// Attention, ne fonctionne que pour les surfaces 8-bit +// Reads a pixel in a SDL surface. +// Warning, this is only suitable for 8-bit surfaces. byte Get_SDL_pixel_8(SDL_Surface *bmp, int x, int y) { return ((byte *)(bmp->pixels))[(y*bmp->pitch+x)]; } + +void Clear_screen(byte color) +{ + memset(Screen_SDL->pixels,color,Screen_SDL->pitch*Screen_SDL->h); + Update_rect(0,0,0,0); +} + +void Clear_border(byte color) +{ + int width; + int height; + + // This function can be called before the graphics mode is set. + // Nothing to do then. + if (!Screen_SDL) + return; + + width = Screen_SDL->w - Screen_width*Pixel_width; + height = Screen_SDL->h - Screen_height*Pixel_height; + if (width) + { + SDL_Rect r; + r.x=Screen_SDL->w - width; + r.y=0; + r.h=Screen_SDL->h; + r.w=width; + SDL_FillRect(Screen_SDL,&r,color); + SDL_UpdateRect(Screen_SDL, r.x, r.y, r.w, r.h); + } + if (height) + { + SDL_Rect r; + r.x=0; + r.y=Screen_SDL->h - height; + r.h=height; + r.w=Screen_SDL->w - height; + SDL_FillRect(Screen_SDL,&r,color); + SDL_UpdateRect(Screen_SDL, r.x, r.y, r.w, r.h); + } +} + diff --git a/sdlscreen.h b/sdlscreen.h index 496f3956..3412d75a 100644 --- a/sdlscreen.h +++ b/sdlscreen.h @@ -31,15 +31,30 @@ #include #include "struct.h" - void Set_mode_SDL(int *,int *,int); +/// +/// This is the number of bytes in a video line for the current mode. +/// On many platforms it will be the video mode's width (in pixels), rounded up +/// to be a multiple of 4. +#define VIDEO_LINE_WIDTH (Screen_SDL->pitch) - SDL_Rect ** List_SDL_video_modes; - byte* Screen_pixels; +void Set_mode_SDL(int *,int *,int); - void Update_rect(short x, short y, unsigned short width, unsigned short height); - void Flush_update(void); - byte * Surface_to_bytefield(SDL_Surface *source, byte * dest); - SDL_Color Color_to_SDL_color(byte); - byte Get_SDL_pixel_8(SDL_Surface *bmp, int x, int y); +SDL_Rect ** List_SDL_video_modes; +byte* Screen_pixels; + +void Update_rect(short x, short y, unsigned short width, unsigned short height); +void Flush_update(void); +byte * Surface_to_bytefield(SDL_Surface *source, byte * dest); +SDL_Color Color_to_SDL_color(byte); +byte Get_SDL_pixel_8(SDL_Surface *bmp, int x, int y); + +/// Fills the SDL screen with a given color +void Clear_screen(byte color); + +/// +/// Clears the parts of screen that are outside of the editing area. +/// There is such area only if the screen mode is not a multiple of the pixel +/// size, eg: 3x3 pixels in 1024x768 leaves 1 column on the right, 0 rows on bottom. +void Clear_border(byte color); #endif // SDLSCREEN_H_INCLUDED diff --git a/transform.c b/transform.c new file mode 100644 index 00000000..ecabeeb2 --- /dev/null +++ b/transform.c @@ -0,0 +1,411 @@ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2009 Yves Rizoud + Copyright 2009 Adrien Destugues + Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) + + Grafx2 is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 + of the License. + + Grafx2 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grafx2; if not, see or + write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include +#include + +#include "global.h" +#include "struct.h" +#include "transform.h" +#include "engine.h" +#include "sdlscreen.h" +#include "windows.h" +#include "input.h" +#include "help.h" +#include "misc.h" // Num2str +#include "readline.h" +#include "buttons.h" // Message_out_of_memory() +#include "pages.h" // Backup_with_new_dimensions() + +/// Reduces a fraction A/B to its smallest representation. ie (40,60) becomes (2/3) +void Factorize(short *a, short *b) +{ + // Method: brute-force. + short factor; + + factor=2; + while (factor<=*a && factor<=*b) + { + if (((*a % factor) == 0) && ((*b % factor) == 0)) + { + // common factor is found + *a/=factor; + *b/=factor; + // restart + factor=2; + } + else + factor++; + } +} + +/// Multiplies original_size by new_ratio/old_ratio, but keeps result in 1-9999 range. +short Compute_dimension(short original_size, short new_ratio, short old_ratio) +{ + long amount; + amount = (long)original_size*new_ratio/old_ratio; + if (amount>9999) + return 9999; + else if (amount<1) + return 1; + else + return amount; +} + +void Button_Transform_menu(void) +{ + enum RESIZE_UNIT { + UNIT_PIXELS = 1, + UNIT_PERCENT = 2, + UNIT_RATIO = 3 + }; + + char buffer[5]; + short clicked_button; + const char * unit_label[] = { + "", + "Pixels ", + "Percent", + "Ratio "}; + short last_unit_index = -1; + short old_ratio_width; + short old_ratio_height; + short new_ratio_width; + short new_ratio_height; + short new_width=Main_image_width; + short new_height=Main_image_height; + byte need_display_size = 0; + + // Persistent data + static short unit_index = 1; // 1= Pixels, 2= Percent, 3=Ratio + static short ratio_is_locked = 1; // True if X and Y resize should go together + + T_Dropdown_button * unit_button; + T_Special_button * input_button[4]; + short *input_value[4]; + + // Set initial ratio + if (unit_index == UNIT_PERCENT) + new_ratio_width=old_ratio_width=new_ratio_height=old_ratio_height=100; + else + new_ratio_width=old_ratio_width=new_ratio_height=old_ratio_height=1; + + Open_window(215,165,"Picture transform"); + + Window_display_frame( 5, 15,205,91); + Window_display_frame( 5,110, 55,49); + Window_display_frame(64,110, 85,49); + + Window_set_normal_button(154,140, 54,14,"Cancel",0,1,KEY_ESC); // 1 + + Print_in_window( 9,114,"Mirror",MC_Dark,MC_Light); + Window_set_normal_button( 17,125, 27,14,"X\035" ,1,1,SDLK_x); // 2 + Window_set_normal_button( 17,140, 27,14,"Y\022" ,1,1,SDLK_y); // 3 + + Print_in_window( 84,114,"Rotate",MC_Dark,MC_Light); + Window_set_normal_button( 69,125, 37,14,"-90°" ,0,1,SDLK_LAST); // 4 + Window_set_normal_button(107,125, 37,14,"+90°" ,0,1,SDLK_LAST); // 5 + Window_set_normal_button( 69,140, 75,14,"180°" ,0,1,SDLK_LAST); // 6 + + Print_in_window( 87, 19,"Resize",MC_Dark,MC_Light); + Window_set_normal_button( 80, 86, 60,14,"RESIZE",1,1,SDLK_r); // 7 + Print_in_window( 51, 34,"New",MC_Dark,MC_Light); + Print_in_window( 96, 34,"Old",MC_Dark,MC_Light); + Print_in_window( 30, 44,"X:",MC_Dark,MC_Light); + Print_in_window( 30, 59,"Y:",MC_Dark,MC_Light); + Print_in_window( 80, 44,":",MC_Dark,MC_Light); + Print_in_window( 80, 59,":",MC_Dark,MC_Light); + Print_in_window( 44, 75,"Lock proportions",MC_Dark,MC_Light); + + Window_set_normal_button( 28, 72, 13,13,ratio_is_locked?"X":" ",0,1,SDLK_l);// 8 + unit_button = Window_set_dropdown_button(128,50,69,11,69,unit_label[unit_index],1,0,1,LEFT_SIDE|RIGHT_SIDE);// 9 + Window_dropdown_add_item(unit_button,UNIT_PIXELS,unit_label[UNIT_PIXELS]); + Window_dropdown_add_item(unit_button,UNIT_PERCENT,unit_label[UNIT_PERCENT]); + Window_dropdown_add_item(unit_button,UNIT_RATIO,unit_label[UNIT_RATIO]); + + input_button[0] = Window_set_input_button(45,43,4); // 10 + input_button[1] = Window_set_input_button(89,43,4); // 11 + input_button[2] = Window_set_input_button(45,58,4); // 12 + input_button[3] = Window_set_input_button(89,58,4); // 13 + + Update_window_area(0,0,Window_width, Window_height); + + Display_cursor(); + + do + { + // Display the coordinates with the right unit + if (last_unit_index != unit_index) + { + switch(unit_index) + { + case UNIT_PIXELS: + default: + input_value[0]=&new_width; + input_value[1]=&Main_image_width; // Don't worry, it's read-only + input_value[2]=&new_height; + input_value[3]=&Main_image_height; // Don't worry, it's read-only + break; + case UNIT_PERCENT: + case UNIT_RATIO: + input_value[0]=&new_ratio_width; + input_value[1]=&old_ratio_width; + input_value[2]=&new_ratio_height; + input_value[3]=&old_ratio_height; + break; + } + need_display_size=1; + last_unit_index=unit_index; + } + if (need_display_size) + { + short i; + Hide_cursor(); + for (i=0;i<4;i++) + { + // "Old" values are not editable, unless the unit is "ratio" + byte color = ((unit_index!=UNIT_RATIO) && (i==1 || i==3)) ? MC_Dark : MC_Black; + Num2str(*(input_value[i]),buffer,4); + Print_in_window_limited(input_button[i]->Pos_X+2,input_button[i]->Pos_Y+2,buffer,input_button[i]->Width/8,color,MC_Light); + } + Display_cursor(); + need_display_size=0; + } + + clicked_button=Window_clicked_button(); + + // Contextual help + if (Is_shortcut(Key,0x100+BUTTON_HELP)) + { + Key=0; + Window_help(BUTTON_ADJUST, "PICTURE TRANSFORM"); + } + else switch(clicked_button) + { + case 9: // Unit + switch(Window_attribute2) + { + case UNIT_PIXELS: + // Do nothing, pixel size was already computed. + break; + case UNIT_PERCENT: + if (unit_index == UNIT_RATIO) + { + // Approximate from current ratio + new_ratio_width = Compute_dimension(new_ratio_width,100,old_ratio_width); + new_ratio_height = Compute_dimension(new_ratio_height,100,old_ratio_height); + old_ratio_width = 100; + old_ratio_height = 100; + // Update pixel dimensions, to match percentage exactly + new_width=Compute_dimension(Main_image_width, new_ratio_width, old_ratio_width); + new_height=Compute_dimension(Main_image_height, new_ratio_height, old_ratio_height); + } + else // unit_index == UNIT_PIXELS + { + // Approximate from current pixel size + new_ratio_width = new_width*100/Main_image_width; + new_ratio_height = new_height*100/Main_image_height; + old_ratio_width = 100; + old_ratio_height = 100; + } + break; + case UNIT_RATIO: + if (unit_index == UNIT_PERCENT) + { + // Compute simplest ratio from current % + Factorize(&new_ratio_width, &old_ratio_width); + Factorize(&new_ratio_height, &old_ratio_height); + } + else // unit_index == UNIT_PIXELS + { + // Compute simplest ratio from current pixel size + new_ratio_width = new_width; + new_ratio_height = new_height; + old_ratio_width = Main_image_width; + old_ratio_height = Main_image_height; + Factorize(&new_ratio_width, &old_ratio_width); + Factorize(&new_ratio_height, &old_ratio_height); + } + break; + } + + unit_index = Window_attribute2; + break; + + case 8: // Lock proportions + ratio_is_locked = ! ratio_is_locked; + Hide_cursor(); + Print_in_window(31,75,(ratio_is_locked)?"X":" ",MC_Black,MC_Light); + Display_cursor(); + break; + + case 11: // input old width + case 13: // input old height + // "Old" values are not editable, unless the unit is "ratio" + if (unit_index!=UNIT_RATIO) + break; + case 10: // input new width + case 12: // input new height + Num2str(*( input_value[clicked_button-10]),buffer,4); + Hide_cursor(); + if (Readline(input_button[clicked_button-10]->Pos_X+2, + input_button[clicked_button-10]->Pos_Y+2, + buffer, + 4, + 1)) + { + // Accept entered value + *(input_value[clicked_button-10])=atoi(buffer); + // 0 is not acceptable size + if (*(input_value[clicked_button-10])==0) + { + *(input_value[clicked_button-10])=1; + } + // Adapt the other coordinate if X and Y are locked + if (ratio_is_locked) + { + if (clicked_button == 10 || clicked_button == 11 ) + { + // Get Y value because X changed + if (unit_index == UNIT_PIXELS) + { + new_height=Compute_dimension(Main_image_height, new_width, Main_image_width); + } + else + { + // Copy the whole ratio + new_ratio_height=new_ratio_width; + old_ratio_height=old_ratio_width; + } + } + else // (clicked_button == 12 || clicked_button == 13) + { + // Get X value because Y changed + if (unit_index == UNIT_PIXELS) + { + new_width=Compute_dimension(Main_image_width, new_height, Main_image_height); + } + else + { + // Copy the whole ratio + new_ratio_width=new_ratio_height; + old_ratio_width=old_ratio_height; + } + } + } + + // Re-compute ratio from size in pixels + if (unit_index == UNIT_PIXELS) + { + //new_width=(long)Main_image_width*new_ratio_width/old_ratio_width; + //new_height=(long)Main_image_height*new_ratio_height/old_ratio_height; + } + else // Re-compute size in pixels from ratio + { + new_width=Compute_dimension(Main_image_width,new_ratio_width,old_ratio_width); + new_height=Compute_dimension(Main_image_height,new_ratio_height,old_ratio_height); + } + need_display_size=1; + } + Display_cursor(); + break; + } + } + while (clicked_button<=0 || clicked_button>=8); + + Close_window(); + + // The Scroll operation uses the same button as transformation menu. + if (Current_operation != OPERATION_SCROLL) + Unselect_bouton(BUTTON_ADJUST); + + if (clicked_button != 1) // 1 is Cancel + { + short old_width; + short old_height; + + // Determine new image dimensions + switch (clicked_button) + { + case 7 : // Resize + // Keep new_width and new_height as entered. + break; + case 2 : // Flip X + case 3 : // Flip Y + case 6 : // 180° Rotation + new_width=Main_image_width; + new_height=Main_image_height; + break; + + case 4 : // -90° Rotation + case 5 : // +90° Rotation + + new_width=Main_image_height; + new_height=Main_image_width; + break; + } + // Memorize the current dimensions + old_width=Main_image_width; + old_height=Main_image_height; + + // Allocate a new page + if (Backup_with_new_dimensions(1,new_width,new_height)) + { + // The new image is allocated, the new dimensions are already updated. + + Main_image_is_modified=1; + + // Process the transformation: + switch(clicked_button) + { + case 2 : // Flip X + memcpy(Main_screen,Screen_backup,Main_image_width*Main_image_height); + Flip_X_lowlevel(Main_screen, 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); + break; + case 4 : // -90° Rotation + Rotate_270_deg_lowlevel(Screen_backup, Main_screen, old_width, old_height); + break; + case 5 : // +90° Rotation + Rotate_90_deg_lowlevel(Screen_backup, Main_screen, 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); + break; + case 7 : // Resize + Rescale(Screen_backup, old_width, old_height, Main_screen, Main_image_width, Main_image_height, 0, 0); + break; + } + Display_all_screen(); + } + else + { + Display_cursor(); + Message_out_of_memory(); + Hide_cursor(); + } + } + Display_cursor(); +} diff --git a/transform.h b/transform.h new file mode 100644 index 00000000..574a66bc --- /dev/null +++ b/transform.h @@ -0,0 +1,29 @@ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2009 Yves Rizoud + Copyright 2009 Adrien Destugues + Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) + + Grafx2 is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 + of the License. + + Grafx2 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grafx2; if not, see or + write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file transform.h +/// Screen and functions for picture transform. +////////////////////////////////////////////////////////////////////////////// + +/// Opens and handles the Picture transform screen. +void Button_Transform_menu(void); diff --git a/windows.c b/windows.c index f865223f..32a1a78f 100644 --- a/windows.c +++ b/windows.c @@ -2394,6 +2394,7 @@ void Remap_screen_after_menu_colors_change(void) // On passe la table juste pour ne rafficher que les couleurs modifiées Display_menu_palette_avoiding_window(conversion_table); } + Clear_border(MC_Black); } } @@ -2529,4 +2530,5 @@ void Compute_optimal_menu_colors(T_Components * palette) for (i=0; i