From e5f948076b4932e9b936a32f5573f60af8f3a69d Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sat, 2 May 2009 16:44:06 +0000 Subject: [PATCH] New: Picture effects screen, resizes / mirrors / rotates image (Issue 73) New: Distort brush (Issue 34) New: Pixel scaler "Triple" for 3x3 zoom (Issue 147) New: Pixel scaler "Quadruple" for 4x4 zoom (Issue 151) New: Pixel scaler "Wide2" for 4x2 zoom (Issue 148) New: Pixel scaler "Tall2" for 2x4 zoom (Issue 149) Fix of very old bug: Resizing the image didn't mark the image 'modified since last save' git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@763 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- Makefile | 2 +- Makefile.dep | 43 +++-- brush.c | 285 +++++++++++++++++++++------ brush.h | 12 ++ buttons.c | 37 ++-- const.h | 4 + engine.c | 23 ++- filesel.c | 2 +- gfx2.cfg | Bin 10062 -> 10062 bytes graph.c | 117 ++++++++++- graph.h | 26 +-- helpfile.h | 35 +++- init.c | 21 +- input.c | 30 ++- main.c | 34 +++- misc.c | 143 +++++++++----- misc.h | 50 ++++- operatio.c | 381 +++++++++++++++++++++++++++--------- operatio.h | 10 + pxdouble.c | 108 +++++------ pxquad.c | 534 +++++++++++++++++++++++++++++++++++++++++++++++++++ pxquad.h | 50 +++++ pxsimple.c | 40 ++-- pxtall.c | 77 ++++---- pxtall2.c | 526 ++++++++++++++++++++++++++++++++++++++++++++++++++ pxtall2.h | 50 +++++ pxtriple.c | 522 +++++++++++++++++++++++++++++++++++++++++++++++++ pxtriple.h | 50 +++++ pxwide.c | 103 +++++----- pxwide2.c | 516 +++++++++++++++++++++++++++++++++++++++++++++++++ pxwide2.h | 50 +++++ sdlscreen.c | 77 ++++++-- sdlscreen.h | 31 ++- transform.c | 411 +++++++++++++++++++++++++++++++++++++++ transform.h | 29 +++ windows.c | 2 + windows.h | 2 + 37 files changed, 3952 insertions(+), 481 deletions(-) create mode 100644 pxquad.c create mode 100644 pxquad.h create mode 100644 pxtall2.c create mode 100644 pxtall2.h create mode 100644 pxtriple.c create mode 100644 pxtriple.h create mode 100644 pxwide2.c create mode 100644 pxwide2.h create mode 100644 transform.c create mode 100644 transform.h 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 9c4e6a83d0742434008f261d44ac7eaa97779847..8dde4a90ed502357e54fee5dccf48c0dcb50818e 100644 GIT binary patch delta 14 VcmX@-cg}Bvk17)*<6=KmCIBkg1a<%b delta 14 VcmX@-cg}Bvk1EqchQ)rWOaL$x1yuk5 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