grafx2/src/SFont.c0000644000076400010400000001423711532235570014430 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* SFont: a simple font-library that uses special .pngs as fonts Copyright (C) 2003 Karl Bartel License: GPL or LGPL (at your choice) WWW: http://www.linux-games.com/sfont/ This program 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; either version 2 of the License, or (at your option) any later version. This program 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 this program; if not, see . Karl Bartel Cecilienstr. 14 12307 Berlin GERMANY karlb@gmx.net */ #include #include #include #include #include "SFont.h" static Uint32 GetPixel(SDL_Surface *Surface, Sint32 X, Sint32 Y) { Uint8 *bits; Uint32 Bpp; assert(X>=0); assert(Xw); Bpp = Surface->format->BytesPerPixel; bits = ((Uint8 *)Surface->pixels)+Y*Surface->pitch+X*Bpp; // Get the pixel switch(Bpp) { case 1: return *((Uint8 *)Surface->pixels + Y * Surface->pitch + X); break; case 2: return *((Uint16 *)Surface->pixels + Y * Surface->pitch/2 + X); break; case 3: { // Format/endian independent Uint8 r, g, b; r = *((bits)+Surface->format->Rshift/8); g = *((bits)+Surface->format->Gshift/8); b = *((bits)+Surface->format->Bshift/8); return SDL_MapRGB(Surface->format, r, g, b); } break; case 4: return *((Uint32 *)Surface->pixels + Y * Surface->pitch/4 + X); break; } return -1; } SFont_Font* SFont_InitFont(SDL_Surface* Surface) { int x = 0, i = 33; Uint32 pixel; SFont_Font* Font; Uint32 pink; if (Surface == NULL) return NULL; Font = (SFont_Font *) malloc(sizeof(SFont_Font)); memset(Font, 0, sizeof(SFont_Font)); Font->Surface = Surface; SDL_LockSurface(Surface); pink = GetPixel(Surface, 0, 0); while (x < Surface->w) { if (GetPixel(Surface, x, 0) != pink) { Font->CharBegin[i]=x; while((x < Surface->w) && (GetPixel(Surface, x, 0)!= pink)) x++; Font->CharWidth[i]=x-Font->CharBegin[i]; i++; } x++; } // Create lowercase characters, if not present for (i=0; i <26; i++) { if (Font->CharWidth['a'+i]==0) { Font->CharBegin['a'+i]=Font->CharBegin['A'+i]; Font->CharWidth['a'+i]=Font->CharWidth['A'+i]; } } // Determine space width. // This strange format doesn't allow font designer to write explicit // space as a character. // Rule: A space should be as large as the character " if available, // or 'a' if it's not. Font->Space = Font->CharWidth[(int)'"']; if (Font->Space<2) Font->Space = Font->CharWidth[(int)'a']; pixel = GetPixel(Surface, 0, Surface->h-1); SDL_UnlockSurface(Surface); // No longer use SDL color keying //SDL_SetColorKey(Surface, SDL_SRCCOLORKEY, pixel); Font->Transparent=pixel; return Font; } void SFont_FreeFont(SFont_Font* FontInfo) { SDL_FreeSurface(FontInfo->Surface); free(FontInfo); } void SFont_Write(SDL_Surface *Surface, const SFont_Font *Font, int x, int y, const char *text) { const char* c; SDL_Rect srcrect, dstrect; if(text == NULL) return; // these values won't change in the loop srcrect.y = 1; dstrect.y = y; srcrect.h = dstrect.h = Font->Surface->h - 1; for(c = text; *c != '\0' && x <= Surface->w ; c++) { if (*c == '\n') { dstrect.y += Font->Surface->h-1; x=0; continue; } // skip spaces and nonprintable characters else if (*c == ' ' || Font->CharWidth[(int)*c]==0) { x += Font->Space; continue; } srcrect.w = Font->CharWidth[(int)*c]; dstrect.w = srcrect.w; srcrect.x = Font->CharBegin[(int)*c]; dstrect.x = x; SDL_BlitSurface(Font->Surface, &srcrect, Surface, &dstrect); x += Font->CharWidth[(int)*c]; } } int SFont_TextWidth(const SFont_Font *Font, const char *text) { const char* c; int width = 0; int previous_width = 0; if(text == NULL) return 0; for(c = text; *c != '\0'; c++) { if (*c == '\n') { if (previous_widthCharWidth[(int)*c]==0) { width += Font->Space; continue; } width += Font->CharWidth[(int)*c]; } return previous_widthSurface->h - 1) * (nb_cr+1); } /* // Do not use: Doesn't implement carriage returns void SFont_WriteCenter(SDL_Surface *Surface, const SFont_Font *Font, int y, const char *text) { SFont_Write(Surface, Font, Surface->w/2 - SFont_TextWidth(Font, text)/2, y, text); } */ grafx2/src/brush.c0000644000076400010400000016712011525510216014515 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Franck Charlet Copyright 2007-2008 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 ******************************************************************************** Brush manipulation functions */ #include #include #include // memset() #include "global.h" #include "graph.h" #include "misc.h" #include "errors.h" #include "windows.h" #include "sdlscreen.h" #include "brush.h" // Calcul de redimensionnement du pinceau pour viter les dbordements de // l'cran et de l'image void Compute_clipped_dimensions(short * x,short * y,short * width,short * height) { if ((*x)(Limit_right+1)) { (*width)=(Limit_right-(*x))+1; } if ((*y)(Limit_bottom+1)) { (*height)=(Limit_bottom-(*y))+1; } } // -- Calcul de redimensionnement du pinceau pour viter les dbordements // de l'cran zoom et de l'image -- void Compute_clipped_dimensions_zoom(short * x,short * y,short * width,short * height) { if ((*x)(Limit_right_zoom+1)) { (*width)=(Limit_right_zoom-(*x))+1; } if ((*y)(Limit_bottom_zoom+1)) { (*height)=(Limit_bottom_zoom-(*y))+1; } } // -- Afficher le pinceau (de faon dfinitive ou non) -- void Display_paintbrush(short x,short y,byte color,byte is_preview) // x,y: position du centre du pinceau // color: couleur appliquer au pinceau // is_preview: "Il ne faut l'afficher qu' l'cran" { short start_x; // Position X (dans l'image) partir de laquelle on // affiche la brosse/pinceau short start_y; // Position Y (dans l'image) partir de laquelle on // affiche la brosse/pinceau short width; // width dans l'cran selon laquelle on affiche la // brosse/pinceau short height; // height dans l'cran selon laquelle on affiche la // brosse/pinceau short start_x_counter; // Position X (dans la brosse/pinceau) partir // de laquelle on affiche la brosse/pinceau short start_y_counter; // Position Y (dans la brosse/pinceau) partir // de laquelle on affiche la brosse/pinceau short x_pos; // Position X (dans l'image) en cours d'affichage short y_pos; // Position Y (dans l'image) en cours d'affichage short counter_x; // Position X (dans la brosse/pinceau) en cours // d'affichage short counter_y; // Position Y (dans la brosse/pinceau) en cours // d'affichage short end_counter_x; // Position X ou s'arrte l'affichade de la // brosse/pinceau short end_counter_y; // Position Y ou s'arrte l'affichade de la // brosse/pinceau byte temp_color; // color de la brosse en cours d'affichage int position; byte * temp; if (is_preview==0 || Mouse_K==0) // pas de curseur si on est en preview et // en train de cliquer switch (Paintbrush_shape) { case PAINTBRUSH_SHAPE_NONE : // No paintbrush. for colorpicker for example break; case PAINTBRUSH_SHAPE_POINT : // !!! TOUJOURS EN PREVIEW !!! if ( (Paintbrush_X>=Limit_left) && (Paintbrush_X<=Limit_right) && (Paintbrush_Y>=Limit_top) && (Paintbrush_Y<=Limit_bottom) ) { Pixel_preview(Paintbrush_X,Paintbrush_Y,color); Update_part_of_screen(x,y,1,1); } break; case PAINTBRUSH_SHAPE_COLOR_BRUSH : // Brush en couleur start_x=x-Brush_offset_X; start_y=y-Brush_offset_Y; width=Brush_width; height=Brush_height; Compute_clipped_dimensions(&start_x,&start_y,&width,&height); if (width<=0 || height<=0) break; start_x_counter=start_x-(x-Brush_offset_X); start_y_counter=start_y-(y-Brush_offset_Y); end_counter_x=start_x_counter+width; end_counter_y=start_y_counter+height; if (is_preview != 0) { if ( (width>0) && (height>0) ) Display_brush_color( start_x-Main_offset_X, start_y-Main_offset_Y, start_x_counter, start_y_counter, width, height, Back_color, Brush_width ); if (Main_magnifier_mode != 0) { Compute_clipped_dimensions_zoom(&start_x,&start_y,&width, &height ); start_x_counter=start_x-(x-Brush_offset_X); start_y_counter=start_y-(y-Brush_offset_Y); if ( (width>0) && (height>0) ) { // Corrections dues au Zoom: start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor; start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor; height=start_y+(height*Main_magnifier_factor); if (height>Menu_Y) height=Menu_Y; Display_brush_color_zoom(Main_X_zoom+start_x,start_y, start_x_counter,start_y_counter, width,height,Back_color, Brush_width, Horizontal_line_buffer); } } Update_part_of_screen(x-Brush_offset_X,y-Brush_offset_Y,Brush_width,Brush_height); } else { if ((Smear_mode != 0) && (Shade_table==Shade_table_left)) { if (Smear_start != 0) { if ((width>0) && (height>0)) { Copy_part_of_image_to_another( Main_screen, start_x, start_y, width, height, Main_image_width, Smear_brush, start_x_counter, start_y_counter, Smear_brush_width ); Update_part_of_screen(start_x,start_y,width,height); } Smear_start=0; } else { for (y_pos = start_y, counter_y = start_y_counter; counter_y < end_counter_y; y_pos++, counter_y++ ) for (x_pos = start_x, counter_x = start_x_counter; counter_x < end_counter_x; x_pos++, counter_x++ ) { temp_color = Read_pixel_from_current_screen( x_pos,y_pos ); position = (counter_y * Smear_brush_width)+ counter_x; if ( (Read_pixel_from_brush(counter_x,counter_y) != Back_color) && (counter_y=Smear_min_Y) && (counter_x>=Smear_min_X) ) Display_pixel(x_pos,y_pos,Smear_brush[position]); Smear_brush[position]=temp_color; } Update_part_of_screen(start_x,start_y,width,height); } Smear_min_X=start_x_counter; Smear_min_Y=start_y_counter; Smear_max_X=end_counter_x; Smear_max_Y=end_counter_y; } else { if (Shade_table==Shade_table_left) for (y_pos=start_y,counter_y=start_y_counter;counter_y0) && (height>0) ) Display_brush_mono(start_x-Main_offset_X, start_y-Main_offset_Y, start_x_counter,start_y_counter, width,height, Back_color,Fore_color, Brush_width); if (Main_magnifier_mode != 0) { Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height); start_x_counter=start_x-(x-Brush_offset_X); start_y_counter=start_y-(y-Brush_offset_Y); if ( (width>0) && (height>0) ) { // Corrections dues au Zoom: start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor; start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor; height=start_y+(height*Main_magnifier_factor); if (height>Menu_Y) height=Menu_Y; Display_brush_mono_zoom(Main_X_zoom+start_x,start_y, start_x_counter,start_y_counter, width,height, Back_color,Fore_color, Brush_width, Horizontal_line_buffer); } } Update_part_of_screen(x-Brush_offset_X,y-Brush_offset_Y,Brush_width,Brush_height); } else { if ((Smear_mode != 0) && (Shade_table==Shade_table_left)) { if (Smear_start != 0) { if ((width>0) && (height>0)) { Copy_part_of_image_to_another(Main_screen, start_x,start_y, width,height, Main_image_width, Smear_brush, start_x_counter, start_y_counter, Smear_brush_width); Update_part_of_screen(start_x,start_y,width,height); } Smear_start=0; } else { for (y_pos=start_y,counter_y=start_y_counter;counter_y=Smear_min_Y) && (counter_x>=Smear_min_X) ) Display_pixel(x_pos,y_pos,Smear_brush[position]); Smear_brush[position]=temp_color; } Update_part_of_screen(start_x,start_y,width,height); } Smear_min_X=start_x_counter; Smear_min_Y=start_y_counter; Smear_max_X=end_counter_x; Smear_max_Y=end_counter_y; } else { for (y_pos=start_y,counter_y=start_y_counter;counter_y0) && (height>0) ) Display_brush_mono(start_x-Main_offset_X, start_y-Main_offset_Y, start_x_counter,start_y_counter, width,height, 0,Fore_color, MAX_PAINTBRUSH_SIZE); if (Main_magnifier_mode != 0) { Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height); start_x_counter=start_x-(x-Paintbrush_offset_X); start_y_counter=start_y-(y-Paintbrush_offset_Y); if ( (width>0) && (height>0) ) { // Corrections dues au Zoom: start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor; start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor; height=start_y+(height*Main_magnifier_factor); if (height>Menu_Y) height=Menu_Y; Display_brush_mono_zoom(Main_X_zoom+start_x,start_y, start_x_counter,start_y_counter, width,height, 0,Fore_color, MAX_PAINTBRUSH_SIZE, Horizontal_line_buffer); } } Brush=temp; } else { if ((Smear_mode != 0) && (Shade_table==Shade_table_left)) { if (Smear_start != 0) { if ((width>0) && (height>0)) { Copy_part_of_image_to_another(Main_screen, start_x,start_y, width,height, Main_image_width, Smear_brush, start_x_counter, start_y_counter, Smear_brush_width); Update_part_of_screen(start_x,start_y,width,height); } Smear_start=0; } else { for (y_pos=start_y,counter_y=start_y_counter;counter_y=Smear_min_Y) && (counter_x>=Smear_min_X) // On clippe l'effet smear entre Smear_Min et Smear_Max ) Display_pixel(x_pos,y_pos,Smear_brush[position]); Smear_brush[position]=temp_color; } Update_part_of_screen(start_x, start_y, width, height); } Smear_min_X=start_x_counter; Smear_min_Y=start_y_counter; Smear_max_X=end_counter_x; Smear_max_Y=end_counter_y; } else { for (y_pos=start_y,counter_y=start_y_counter;counter_yMAX_PAINTBRUSH_SIZE)?new_brush_width:MAX_PAINTBRUSH_SIZE; new_smear_brush_height=(new_brush_height>MAX_PAINTBRUSH_SIZE)?new_brush_height:MAX_PAINTBRUSH_SIZE; new_smear_brush=NULL; if ( (((long)Smear_brush_height)*Smear_brush_width) != (((long)new_smear_brush_width)*new_smear_brush_height) ) { new_smear_brush=(byte *)malloc(((long)new_smear_brush_height)*new_smear_brush_width); if (new_smear_brush == NULL) { Error(0); if (old_brush) *old_brush=NULL; if (!new_brush_is_provided) free(new_brush); return 2; } } new_brush_remapped=NULL; if ( (((long)Brush_height)*Brush_width) != (((long)new_brush_height)*new_brush_width) ) { new_brush_remapped=(byte *)malloc(((long)new_brush_height)*new_brush_width); if (new_brush_remapped == NULL) { Error(0); free(new_smear_brush); if (old_brush) *old_brush=NULL; if (!new_brush_is_provided) free(new_brush); return 3; } } // All allocations successful: can replace globals Brush_width=new_brush_width; Brush_height=new_brush_height; Brush_original_back_color=Back_color; if (new_smear_brush) { free(Smear_brush); Smear_brush=new_smear_brush; } Smear_brush_width=new_smear_brush_width; Smear_brush_height=new_smear_brush_height; // Save or free the old brush pixels if (old_brush) *old_brush=Brush_original_pixels; else free(old_brush); Brush_original_pixels=new_brush; // Assign new brush if (new_brush_remapped) { free(Brush); Brush=new_brush_remapped; } return 0; } // -- Effacer le pinceau -- // // void Hide_paintbrush(short x,short y) // x,y: position du centre du pinceau { short start_x; // Position X (dans l'image) partir de laquelle on // affiche la brosse/pinceau short start_y; // Position Y (dans l'image) partir de laquelle on // affiche la brosse/pinceau short width; // width dans l'cran selon laquelle on affiche la // brosse/pinceau short height; // height dans l'cran selon laquelle on affiche la // brosse/pinceau short start_x_counter; // Position X (dans la brosse/pinceau) partir // de laquelle on affiche la brosse/pinceau short start_y_counter; // Position Y (dans la brosse/pinceau) partir // de laquelle on affiche la brosse/pinceau //short x_pos; // Position X (dans l'image) en cours d'affichage //short y_pos; // Position Y (dans l'image) en cours d'affichage //short counter_x; // Position X (dans la brosse/pinceau) en cours //d'affichage //short counter_y; // Position Y (dans la brosse/pinceau) en cours d'affichage short end_counter_x; // Position X ou s'arrte l'affichage de la brosse/pinceau short end_counter_y; // Position Y ou s'arrte l'affichage de la brosse/pinceau byte * temp; if (Mouse_K == 0) switch (Paintbrush_shape) { case PAINTBRUSH_SHAPE_POINT : if ( (Paintbrush_X>=Limit_left) && (Paintbrush_X<=Limit_right) && (Paintbrush_Y>=Limit_top) && (Paintbrush_Y<=Limit_bottom) ) { Pixel_preview(Paintbrush_X,Paintbrush_Y,Read_pixel_from_current_screen(Paintbrush_X,Paintbrush_Y)); Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); } break; case PAINTBRUSH_SHAPE_COLOR_BRUSH : // Brush en couleur case PAINTBRUSH_SHAPE_MONO_BRUSH : // Brush monochrome start_x=x-Brush_offset_X; start_y=y-Brush_offset_Y; width=Brush_width; height=Brush_height; Compute_clipped_dimensions(&start_x,&start_y,&width,&height); start_x_counter=start_x-(x-Brush_offset_X); start_y_counter=start_y-(y-Brush_offset_Y); end_counter_x=start_x_counter+width; end_counter_y=start_y_counter+height; if ( (width>0) && (height>0) ) Clear_brush(start_x-Main_offset_X, start_y-Main_offset_Y, start_x_counter,start_y_counter, width,height,Back_color, Main_image_width); if (Main_magnifier_mode != 0) { Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height); start_x_counter=start_x; start_y_counter=start_y; if ( (width>0) && (height>0) ) { // Corrections dues au Zoom: start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor; start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor; height=start_y+(height*Main_magnifier_factor); if (height>Menu_Y) height=Menu_Y; Clear_brush_scaled(Main_X_zoom+start_x,start_y, start_x_counter,start_y_counter, width,height,Back_color, Main_image_width, Horizontal_line_buffer); } } break; default: // Pinceau start_x=x-Paintbrush_offset_X; start_y=y-Paintbrush_offset_Y; width=Paintbrush_width; height=Paintbrush_height; Compute_clipped_dimensions(&start_x,&start_y,&width,&height); start_x_counter=start_x-(x-Paintbrush_offset_X); start_y_counter=start_y-(y-Paintbrush_offset_Y); end_counter_x=start_x_counter+width; end_counter_y=start_y_counter+height; temp=Brush; Brush=Paintbrush_sprite; if ( (width>0) && (height>0) ) { Clear_brush(start_x-Main_offset_X, start_y-Main_offset_Y, start_x_counter,start_y_counter, width,height,0, Main_image_width); } if (Main_magnifier_mode != 0) { Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height); start_x_counter=start_x; start_y_counter=start_y; if ( (width>0) && (height>0) ) { // Corrections dues au Zoom: start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor; start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor; height=start_y+(height*Main_magnifier_factor); if (height>Menu_Y) height=Menu_Y; Clear_brush_scaled(Main_X_zoom+start_x,start_y, start_x_counter,start_y_counter, width,height,0, Main_image_width, Horizontal_line_buffer); } } Brush=temp; break; } } void Capture_brush(short start_x,short start_y,short end_x,short end_y,short clear) { short temp; short x_pos; short y_pos; word new_brush_width; word new_brush_height; // On commence par "redresser" les bornes: if (start_x>end_x) { temp=start_x; start_x =end_x; end_x =temp; } if (start_y>end_y) { temp=start_y; start_y =end_y; end_y =temp; } // On ne capture la nouvelle brosse que si elle est au moins partiellement // dans l'image: if ((start_xMain_image_width) new_brush_width=Main_image_width-start_x; if (start_y+new_brush_height>Main_image_height) new_brush_height=Main_image_height-start_y; if (Realloc_brush(new_brush_width, new_brush_height, NULL, NULL)) return; // Unable to allocate the new brush, keep the old one. Copy_image_to_brush(start_x,start_y,Brush_width,Brush_height,Main_image_width); // On regarde s'il faut effacer quelque chose: if (clear != 0) { for (y_pos=start_y;y_pos>1); Brush_offset_Y=(Brush_height>>1); } } void Rotate_90_deg(void) { byte * old_brush; if (Realloc_brush(Brush_height, Brush_width, NULL, &old_brush)) { Error(0); return; } Rotate_90_deg_lowlevel(old_brush,Brush_original_pixels,Brush_height,Brush_width); free(old_brush); // Remap according to the last used remap table Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); // On centre la prise sur la brosse Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); } void Remap_brush(void) { short x_pos; // Variable de balayage de la brosse short y_pos; // Variable de balayage de la brosse int color; // On commence par initialiser le tableau de boolens faux for (color=0;color<=255;color++) Brush_colormap[color]=0; // On calcule la table d'utilisation des couleurs for (y_pos=0;y_pos>1); Brush_offset_Y=(Brush_height>>1); free(old_brush); // Libration de l'ancienne brosse } void Nibble_brush(void) { long x_pos,y_pos; byte state; byte * old_brush; word old_width; word old_height; int i; if ( (Brush_width>2) && (Brush_height>2) ) { old_width=Brush_width; old_height=Brush_height; SWAP_PBYTES(Brush, Brush_original_pixels); if (Realloc_brush(Brush_width-2, Brush_height-2, NULL, &old_brush)) { Error(0); SWAP_PBYTES(Brush, Brush_original_pixels); return; } // On copie l'ancienne brosse dans la nouvelle Copy_part_of_image_to_another(old_brush, // source 1, 1, old_width-2, old_height-2, old_width, Brush, // Destination 0, 0, Brush_width); // 1er balayage (horizontal) for (y_pos=0; y_pos0) Pixel_in_brush(x_pos-1,y_pos,Back_color); state=0; } } else { if (state == 0) { Pixel_in_brush(x_pos,y_pos,Back_color); state=1; } } } // Cas du dernier pixel droite de la ligne if (old_brush[((y_pos+1)*old_width)+x_pos+1]==Back_color) Pixel_in_brush(x_pos-1,y_pos,Back_color); } // 2me balayage (vertical) for (x_pos=0; x_pos0) Pixel_in_brush(x_pos,y_pos-1,Back_color); state=0; } } else { if (state == 0) { Pixel_in_brush(x_pos,y_pos,Back_color); state=1; } } } // Cas du dernier pixel en bas de la colonne if (old_brush[((y_pos+1)*old_width)+x_pos+1]==Back_color) Pixel_in_brush(x_pos,y_pos-1,Back_color); } free(old_brush); // Adopt the current palette. memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette)); memcpy(Brush_original_pixels, Brush, (long)Brush_width*Brush_height); for (i=0; i<256; i++) Brush_colormap[i]=i; //-- // On recentre la prise sur la brosse Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); } } void Capture_brush_with_lasso(int vertices, short * points,short clear) { short start_x=Limit_right+1; short start_y=Limit_bottom+1; short end_x=Limit_left-1; short end_y=Limit_top-1; unsigned short temp; short x_pos; short y_pos; word new_brush_width; word new_brush_height; // On recherche les bornes de la brosse: for (temp=0; temp<2*vertices; temp+=2) { x_pos=points[temp]; y_pos=points[temp+1]; if (x_posend_x) end_x=x_pos; if (y_posend_y) end_y=y_pos; } // On clippe ces bornes l'cran: if (start_xLimit_right) end_x=Limit_right; if (start_yLimit_bottom) end_y=Limit_bottom; // On ne capture la nouvelle brosse que si elle est au moins partiellement // dans l'image: if ((start_x>1); Brush_offset_Y=(Brush_height>>1); } } //------------------------- Etirement de la brosse --------------------------- void Stretch_brush(short x1, short y1, short x2, short y2) { byte * new_brush; int new_brush_width; // Width de la nouvelle brosse int new_brush_height; // Height de la nouvelle brosse int x_flipped, y_flipped; // Compute new brush dimensions if ((new_brush_width=x1-x2)<0) { x_flipped=1; new_brush_width=-new_brush_width; } new_brush_width++; if ((new_brush_height=y1-y2)<0) { y_flipped=1; new_brush_height=-new_brush_height; } new_brush_height++; new_brush=((byte *)malloc(new_brush_width*new_brush_height)); if (!new_brush) { Error(0); return; } Rescale(Brush_original_pixels, Brush_width, Brush_height, new_brush, new_brush_width, new_brush_height, x2>1); Brush_offset_Y=(Brush_height>>1); } void Stretch_brush_preview(short x1, short y1, short x2, short y2) { int src_x_pos,src_y_pos; int initial_src_x_pos,initial_src_y_pos; int delta_x,delta_y; int dest_x_pos,dest_y_pos; int initial_dest_x_pos,initial_dest_y_pos; int final_dest_x_pos,final_dest_y_pos; int dest_width,dest_height; byte color; // 1er calcul des positions destination extremes: initial_dest_x_pos=Min(x1,x2); initial_dest_y_pos=Min(y1,y2); final_dest_x_pos =Max(x1,x2); final_dest_y_pos =Max(y1,y2); // Calcul des dimensions de la destination: dest_width=final_dest_x_pos-initial_dest_x_pos+1; dest_height=final_dest_y_pos-initial_dest_y_pos+1; // Calcul des vecteurs d'incrmentation : delta_x=(Brush_width<<16)/dest_width; delta_y=(Brush_height<<16)/dest_height; // 1er calcul de la position X initiale dans la source: initial_src_x_pos=(Brush_width<<16)* (Max(initial_dest_x_pos,Limit_left)- initial_dest_x_pos)/dest_width; // Calcul du clip de la destination: initial_dest_x_pos=Max(initial_dest_x_pos,Limit_left); final_dest_x_pos =Min(final_dest_x_pos ,Limit_visible_right); // On discute selon l'inversion en X if (x1>x2) { // Inversion -> Inversion du signe de delta_x delta_x=-delta_x; initial_src_x_pos=(Brush_width<<16)-1-initial_src_x_pos; } // 1er calcul de la position Y initiale dans la source: initial_src_y_pos=(Brush_height<<16)* (Max(initial_dest_y_pos,Limit_top)- initial_dest_y_pos)/dest_height; // Calcul du clip de la destination: initial_dest_y_pos=Max(initial_dest_y_pos,Limit_top); final_dest_y_pos =Min(final_dest_y_pos ,Limit_visible_bottom); // On discute selon l'inversion en Y if (y1>y2) { // Inversion -> Inversion du signe de delta_y delta_y=-delta_y; initial_src_y_pos=(Brush_height<<16)-1-initial_src_y_pos; } // Pour chaque ligne : src_y_pos=initial_src_y_pos; for (dest_y_pos=initial_dest_y_pos;dest_y_pos<=final_dest_y_pos;dest_y_pos++) { // Pour chaque colonne: src_x_pos=initial_src_x_pos; for (dest_x_pos=initial_dest_x_pos;dest_x_pos<=final_dest_x_pos;dest_x_pos++) { color=Read_pixel_from_brush(src_x_pos>>16,src_y_pos>>16); if (color!=Back_color) Pixel_preview(dest_x_pos,dest_y_pos,color); src_x_pos+=delta_x; } src_y_pos+=delta_y; } Update_part_of_screen(initial_dest_x_pos,initial_dest_y_pos,dest_width,dest_height); } /// Returns the minimum of 4 integers. int Min4(long int a, long int b, long int c, long int d) { if (ab) 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(unsigned long int tex_min_x, unsigned long int tex_min_y, unsigned long int tex_max_x, unsigned 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; // 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_brush=((byte *)malloc((long)width*height)); if (!new_brush) { // Out of memory while allocating new brush Error(0); 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)); if (Realloc_brush(width, height, new_brush, NULL)) { free(new_brush); Error(0); return; } // Remap according to the last used remap table Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); // Re-center brush handle Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); } //------------------------- Rotation de la brosse --------------------------- #ifndef NAN #define NAN (-1.0e20F) #define isnan(x) ((x)==NAN) #endif float * ScanY_Xt[2]; float * ScanY_Yt[2]; float * ScanY_X[2]; void Interpolate_texture(int start_x,int start_y,int xt1,int yt1, int end_x ,int end_y ,int xt2,int yt2,int height) { int x_pos,y_pos; int incr_x,incr_y; int i,cumul; int delta_x,delta_y; int delta_xt=xt2-xt1; int delta_yt=yt2-yt1; int delta_x2=end_x-start_x; int delta_y2=end_y-start_y; float xt,yt; x_pos=start_x; y_pos=start_y; if (start_xdelta_y) { cumul=delta_x>>1; for (i=0; i<=delta_x; i++) { if (cumul>=delta_x) { cumul-=delta_x; y_pos+=incr_y; } if ((y_pos>=0) && (y_pos=ScanY_X[0][y_pos]) { if (isnan(ScanY_X[1][y_pos]) // Droit non dfini || (x_pos>ScanY_X[1][y_pos])) { ScanY_X[1][y_pos]=(float)x_pos; ScanY_Xt[1][y_pos]=xt; ScanY_Yt[1][y_pos]=yt; } } else { if (isnan(ScanY_X[1][y_pos])) // Droit non dfini { ScanY_X[1][y_pos]=ScanY_X[0][y_pos]; ScanY_Xt[1][y_pos]=ScanY_Xt[0][y_pos]; ScanY_Yt[1][y_pos]=ScanY_Yt[0][y_pos]; ScanY_X[0][y_pos]=(float)x_pos; ScanY_Xt[0][y_pos]=xt; ScanY_Yt[0][y_pos]=yt; } else { ScanY_X[0][y_pos]=(float)x_pos; ScanY_Xt[0][y_pos]=xt; ScanY_Yt[0][y_pos]=yt; } } } } x_pos+=incr_x; cumul+=delta_y; } } else { cumul=delta_y>>1; for (i=0; i<=delta_y; i++) { if (cumul>=delta_y) { cumul-=delta_y; x_pos+=incr_x; } if ((y_pos>=0) && (y_pos=ScanY_X[0][y_pos]) { if (isnan(ScanY_X[1][y_pos]) // Droit non dfini || (x_pos>ScanY_X[1][y_pos])) { ScanY_X[1][y_pos]=(float)x_pos; ScanY_Xt[1][y_pos]=xt; ScanY_Yt[1][y_pos]=yt; } } else { if (isnan(ScanY_X[1][y_pos])) // Droit non dfini { ScanY_X[1][y_pos]=ScanY_X[0][y_pos]; ScanY_Xt[1][y_pos]=ScanY_Xt[0][y_pos]; ScanY_Yt[1][y_pos]=ScanY_Yt[0][y_pos]; ScanY_X[0][y_pos]=(float)x_pos; ScanY_Xt[0][y_pos]=xt; ScanY_Yt[0][y_pos]=yt; } else { ScanY_X[0][y_pos]=(float)x_pos; ScanY_Xt[0][y_pos]=xt; ScanY_Yt[0][y_pos]=yt; } } } } y_pos+=incr_y; cumul+=delta_x; } } } void Compute_quad_texture(int x1,int y1,int xt1,int yt1, int x2,int y2,int xt2,int yt2, int x3,int y3,int xt3,int yt3, int x4,int y4,int xt4,int yt4, byte * buffer, int width, int height) { int x_min,/*x_max,*/y_min/*,y_max*/; int x,y,xt,yt; int start_x,end_x,line_width; float temp; //byte color; x_min=Min(Min(x1,x2),Min(x3,x4)); y_min=Min(Min(y1,y2),Min(y3,y4)); ScanY_Xt[0]=(float *)malloc(height*sizeof(float)); ScanY_Xt[1]=(float *)malloc(height*sizeof(float)); ScanY_Yt[0]=(float *)malloc(height*sizeof(float)); ScanY_Yt[1]=(float *)malloc(height*sizeof(float)); ScanY_X[0] =(float *)malloc(height*sizeof(float)); ScanY_X[1] =(float *)malloc(height*sizeof(float)); // Fill_general avec des valeurs gales NAN. for (y=0; y=0 && yt>=0) buffer[x+(y*width)]=*(Brush_original_pixels + yt * Brush_width + xt); } for (; x>1); start_y=1-(Brush_height>>1); end_x=start_x+Brush_width-1; end_y=start_y+Brush_height-1; Transform_point(start_x,start_y, cos_a,sin_a, &x1,&y1); Transform_point(end_x ,start_y, cos_a,sin_a, &x2,&y2); Transform_point(start_x,end_y , cos_a,sin_a, &x3,&y3); Transform_point(end_x ,end_y , cos_a,sin_a, &x4,&y4); // Calcul des nouvelles dimensions de la brosse: x_min=Min(Min((int)x1,(int)x2),Min((int)x3,(int)x4)); x_max=Max(Max((int)x1,(int)x2),Max((int)x3,(int)x4)); y_min=Min(Min((int)y1,(int)y2),Min((int)y3,(int)y4)); y_max=Max(Max((int)y1,(int)y2),Max((int)y3,(int)y4)); new_brush_width=x_max+1-x_min; new_brush_height=y_max+1-y_min; new_brush=(byte *)malloc(new_brush_width*new_brush_height); if (!new_brush) { Error(0); return; } // Et maintenant on calcule la nouvelle brosse tourne. Compute_quad_texture(x1,y1, 0, 0, x2,y2,Brush_width-1, 0, x3,y3, 0,Brush_height-1, x4,y4,Brush_width-1,Brush_height-1, new_brush,new_brush_width,new_brush_height); if (Realloc_brush(new_brush_width, new_brush_height, new_brush, NULL)) { free(new_brush); return; } // Remap according to the last used remap table Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); // Center offsets Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); } void Draw_quad_texture_preview(int x1,int y1,int xt1,int yt1, int x2,int y2,int xt2,int yt2, int x3,int y3,int xt3,int yt3, int x4,int y4,int xt4,int yt4) { int x_min,x_max,y_min,y_max; int x,y,xt,yt; int y_,y_min_; int start_x,end_x,width,height; float temp; byte color; x_min=Min(Min(x1,x2),Min(x3,x4)); x_max=Max(Max(x1,x2),Max(x3,x4)); y_min=Min(Min(y1,y2),Min(y3,y4)); y_max=Max(Max(y1,y2),Max(y3,y4)); height=1+y_max-y_min; ScanY_Xt[0]=(float *)malloc(height*sizeof(float)); ScanY_Xt[1]=(float *)malloc(height*sizeof(float)); ScanY_Yt[0]=(float *)malloc(height*sizeof(float)); ScanY_Yt[1]=(float *)malloc(height*sizeof(float)); ScanY_X[0] =(float *)malloc(height*sizeof(float)); ScanY_X[1] =(float *)malloc(height*sizeof(float)); // Fill_general avec des valeurs gales NAN. for (y=0; yLimit_bottom) y_max=Limit_bottom; for (y_=y_min; y_<=y_max; y_++) { y=y_-y_min_; start_x=Round(ScanY_X[0][y]); end_x =Round(ScanY_X[1][y]); width=1+end_x-start_x; if (start_xLimit_right) end_x=Limit_right; for (x=start_x; x<=end_x; x++) { temp=(float)(0.5+(float)x-ScanY_X[0][y])/(float)width; xt=Round((float)(ScanY_Xt[0][y])+(temp*(ScanY_Xt[1][y]-ScanY_Xt[0][y]))); yt=Round((float)(ScanY_Yt[0][y])+(temp*(ScanY_Yt[1][y]-ScanY_Yt[0][y]))); if (xt>=0 && yt>=0) { color=Read_pixel_from_brush(xt,yt); if (color!=Back_color) Pixel_preview(x,y_,color); } } } free(ScanY_Xt[0]); free(ScanY_Xt[1]); free(ScanY_Yt[0]); free(ScanY_Yt[1]); free(ScanY_X[0]); free(ScanY_X[1]); ScanY_Xt[0] = ScanY_Xt[1] = ScanY_Yt[0] = ScanY_Yt[1] = ScanY_X[0] = ScanY_X[1] = NULL; } void Rotate_brush_preview(float angle) { short x1,y1,x2,y2,x3,y3,x4,y4; int start_x,end_x,start_y,end_y; float cos_a=cos(angle); float sin_a=sin(angle); // Calcul des coordonnes des 4 coins: // 1 2 // 3 4 start_x=1-(Brush_width>>1); start_y=1-(Brush_height>>1); end_x=start_x+Brush_width-1; end_y=start_y+Brush_height-1; Transform_point(start_x,start_y, cos_a,sin_a, &x1,&y1); Transform_point(end_x ,start_y, cos_a,sin_a, &x2,&y2); Transform_point(start_x,end_y , cos_a,sin_a, &x3,&y3); Transform_point(end_x ,end_y , cos_a,sin_a, &x4,&y4); x1+=Brush_rotation_center_X; y1+=Brush_rotation_center_Y; x2+=Brush_rotation_center_X; y2+=Brush_rotation_center_Y; x3+=Brush_rotation_center_X; y3+=Brush_rotation_center_Y; x4+=Brush_rotation_center_X; y4+=Brush_rotation_center_Y; // Et maintenant on dessine la brosse tourne. Draw_quad_texture_preview(x1,y1, 0, 0, x2,y2,Brush_width-1, 0, x3,y3, 0,Brush_height-1, x4,y4,Brush_width-1,Brush_height-1); start_x=Min(Min(x1,x2),Min(x3,x4)); end_x=Max(Max(x1,x2),Max(x3,x4)); start_y=Min(Min(y1,y2),Min(y3,y4)); end_y=Max(Max(y1,y2),Max(y3,y4)); Update_part_of_screen(start_x,start_y,end_x-start_x+1,end_y-start_y+1); } /* /// Sets brush's original palette and color mapping. void Brush_set_palette(T_Palette *palette) { int i; byte need_remap; need_remap=0; memcpy(Brush_original_palette,palette,sizeof(T_Palette)); for (i=0;i<256;i++) { if (Brush_original_palette[i].R!=Main_palette[i].R || Brush_original_palette[i].G!=Main_palette[i].G || Brush_original_palette[i].B!=Main_palette[i].B) { need_remap=1; } } } */grafx2/src/brush_ops.c0000644000076400010400000007712311517642570015413 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 2009 Franck Charlet 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file brush_ops.c /// Code for operations about the brush (grabbing, rotating, ...) and magnifier ////////////////////////////////////////////////////////////////////////////// #include #include #include "brush.h" #include "buttons.h" #include "engine.h" #include "global.h" #include "graph.h" #include "misc.h" #include "operatio.h" #include "pages.h" #include "sdlscreen.h" #include "windows.h" #if defined(__VBCC__) || defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) #define M_PI 3.141592653589793238462643 #endif /// Simulates clicking the "Draw" button. void Return_to_draw_mode(void) { // Comme l'enclenchement du bouton efface le curseur, il faut l'afficher au // pralable: Display_cursor(); if (Mouse_K) Wait_end_of_click(); // !!! Efface la croix puis affiche le viseur !!! Select_button(BUTTON_DRAW,LEFT_SIDE); // Dsenclenche au passage le bouton brosse if (Config.Auto_discontinuous) { // On se place en mode Dessin discontinu la main while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW) Select_button(BUTTON_DRAW,RIGHT_SIDE); } // Maintenant, il faut reffacer 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_MAGNIFY void Magnifier_12_0(void) // Opration : 4 (item d'une Loupe) // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui { // On passe en mode loupe Main_magnifier_mode=1; // La fonction d'affichage dans la partie image est dsormais un affichage // spcial loupe. Pixel_preview=Pixel_preview_magnifier; // On calcule l'origine de la loupe Main_magnifier_offset_X=Mouse_X-(Main_magnifier_width>>1); Main_magnifier_offset_Y=Mouse_Y-(Main_magnifier_height>>1); // Calcul des coordonnes absolues de ce coin DANS L'IMAGE Main_magnifier_offset_X+=Main_offset_X; Main_magnifier_offset_Y+=Main_offset_Y; Clip_magnifier_offsets(&Main_magnifier_offset_X, &Main_magnifier_offset_Y); // On calcule les bornes visibles dans l'cran Position_screen_according_to_zoom(); Compute_limits(); Display_all_screen(); // Repositionner le curseur en fonction des coordonnes visibles Compute_paintbrush_coordinates(); // On fait de notre mieux pour restaurer l'ancienne opration: Start_operation_stack(Operation_before_interrupt); Display_cursor(); Wait_end_of_click(); } /////////////////////////////////////////////////////////// OPERATION_COLORPICK void Colorpicker_12_0(void) // // Opration : OPERATION_COLORPICK // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui // { Init_start_operation(); if (Mouse_K==LEFT_SIDE) { Set_fore_color(Colorpicker_color); } else { Set_back_color(Colorpicker_color); } Operation_push(Mouse_K); } void Colorpicker_1_1(void) // // Opration : OPERATION_COLORPICK // Click Souris: 1 // Taille_Pile : 1 // // Souris efface: Non // { char str[4]; if ( (Paintbrush_X>=0) && (Paintbrush_Y>=0) && (Paintbrush_X=0) && (Paintbrush_Y>=0) && (Paintbrush_X=0) && (Paintbrush_Y>=0) && (Paintbrush_X=Main_X_zoom) ) ) Print_in_menu("X: Y: ",0); Print_coordinates(); Display_cursor(); } ////////////////////////////////////////////////////// OPERATION_GRAB_BRUSH void Brush_12_0(void) // // Opration : OPERATION_GRAB_BRUSH // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui // { Init_start_operation(); if (Mouse_K==RIGHT_SIDE) // Besoin d'effacer la brosse aprs ? { Operation_push(1); // Puisque la zone o on prend la brosse sera efface, on fait un backup Backup(); } else Operation_push(0); // On laisse une trace du curseur pour que l'utilisateur puisse visualiser // o demarre sa brosse: Display_cursor(); Operation_push(Paintbrush_X); // Dbut X Operation_push(Paintbrush_Y); // Dbut Y Operation_push(Paintbrush_X); // Dernire position X Operation_push(Paintbrush_Y); // Dernire position Y if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("\035: 1 \022: 1",0); } void Brush_12_5(void) // // Opration : OPERATION_GRAB_BRUSH // Click Souris: 1 ou 2 // Taille_Pile : 5 // // Souris efface: Non // { char str[5]; short start_x; short start_y; short old_x; short old_y; short width; short height; Operation_pop(&old_y); Operation_pop(&old_x); if ( (Menu_is_visible) && ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) ) { if (Config.Coords_rel) { Operation_pop(&start_y); Operation_pop(&start_x); Operation_push(start_x); Operation_push(start_y); width=((start_x1) width--; if (height>1) height--; } Num2str(width,str,4); Print_in_menu(str,2); Num2str(height,str,4); Print_in_menu(str,11); } else Print_coordinates(); } Display_all_screen(); x=Paintbrush_X; y=Paintbrush_Y; if (Snap_mode && Config.Adjust_brush_pick) { dx=Paintbrush_X-start_x; dy=Paintbrush_Y-start_y; if (dx<0) x++; else {if (dx>0) x--;} if (dy<0) y++; else {if (dy>0) y--;} Stretch_brush_preview(start_x,start_y,x,y); } else Stretch_brush_preview(start_x,start_y,Paintbrush_X,Paintbrush_Y); old_x=Paintbrush_X; old_y=Paintbrush_Y; Paintbrush_X=start_x; Paintbrush_Y=start_y; Display_cursor(); Paintbrush_X=old_x; Paintbrush_Y=old_y; Display_cursor(); Operation_stack_size-=2; Operation_push(x); Operation_push(y); Operation_push(start_x); Operation_push(start_y); } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(2); } void Stretch_brush_0_7(void) // // Opration : OPERATION_STRETCH_BRUSH // Click Souris: 0 // Taille_Pile : 7 // // Souris efface: Non // { char str[5]; short start_x; short start_y; short old_x; short old_y; short width=0; short height=0; byte size_change; short prev_state; Operation_pop(&prev_state); Operation_pop(&old_y); Operation_pop(&old_x); Operation_pop(&start_y); Operation_pop(&start_x); if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) || (prev_state!=3)) { if (Menu_is_visible) { if (Config.Coords_rel) { width=((start_x1)?start_x+(Brush_width>>1)-1:1; height=(Brush_height>1)?start_y+(Brush_height>>1)-1:1; break; case 'X': // Moiti X width=(Brush_width>1)?start_x+(Brush_width>>1)-1:1; height=start_y+Brush_height-1; break; case 'Y': // Moiti Y width=start_x+Brush_width-1; height=(Brush_height>1)?start_y+(Brush_height>>1)-1:1; break; case 'n': // Normal width=start_x+Brush_width-1; height=start_y+Brush_height-1; break; default : size_change=0; } Key_ANSI=0; } else size_change=0; if (size_change) { // On efface la preview de la brosse (et la croix) Display_all_screen(); old_x=Paintbrush_X; old_y=Paintbrush_Y; Paintbrush_X=start_x; Paintbrush_Y=start_y; Display_cursor(); Paintbrush_X=old_x; Paintbrush_Y=old_y; Stretch_brush_preview(start_x,start_y,width,height); Display_cursor(); Operation_stack_size-=2; Operation_push(width); Operation_push(height); } Operation_push(start_x); Operation_push(start_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(3); } void Stretch_brush_2_7(void) // // Opration : OPERATION_STRETCH_BRUSH // Click Souris: 2 // Taille_Pile : 7 // // Souris efface: Oui // { short computed_x; short computed_y; short start_x; short start_y; Operation_stack_size-=3; Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&computed_y); Operation_pop(&computed_x); // On efface la preview de la brosse (et la croix) Display_all_screen(); // Et enfin on stocke pour de bon la nouvelle brosse tire Stretch_brush(start_x,start_y,computed_x,computed_y); Return_to_draw_mode(); } //////////////////////////////////////////////////// OPERATION_ROTATE_BRUSH void Rotate_brush_12_0(void) // // Opration : OPERATION_ROTATE_BRUSH // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui // { Init_start_operation(); if (Mouse_K==LEFT_SIDE) { Brush_rotation_center_X=Paintbrush_X+(Brush_width>>1)-Brush_width; Brush_rotation_center_Y=Paintbrush_Y; Brush_rotation_center_is_defined=1; Operation_push(Paintbrush_X); // Dernire position calcule X Operation_push(Paintbrush_Y); // Dernire position calcule Y Operation_push(Paintbrush_X); // Dernire position X Operation_push(Paintbrush_Y); // Dernire position Y Operation_push(1); // State prcdent if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("Angle: 0 ",0); } else { Start_operation_stack(Operation_before_interrupt); Wait_end_of_click(); // FIXME: celui-la il donne un rsultat pas trs chouette en visuel } } void Rotate_brush_1_5(void) // // Opration : OPERATION_ROTATE_BRUSH // Click Souris: 1 // Taille_Pile : 5 // // Souris efface: Non // { char str[4]; short old_x; short old_y; short prev_state; float angle; int dx,dy; Operation_pop(&prev_state); Operation_pop(&old_y); Operation_pop(&old_x); // On corrige les coordonnes de la ligne si la touche shift est appuye... if(SDL_GetModState() & KMOD_SHIFT) Clamp_coordinates_regular_angle(Brush_rotation_center_X,Brush_rotation_center_Y,&Paintbrush_X,&Paintbrush_Y); if ( (Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) || (prev_state!=2) ) { if ( (Brush_rotation_center_X==Paintbrush_X) && (Brush_rotation_center_Y==Paintbrush_Y) ) angle=0.0; else { dx=Paintbrush_X-Brush_rotation_center_X; dy=Paintbrush_Y-Brush_rotation_center_Y; angle=acos(((float)dx)/sqrt((dx*dx)+(dy*dy))); if (dy>0) angle=M_2PI-angle; } if (Menu_is_visible) { if (Config.Coords_rel) { Num2str((int)(angle*180.0/M_PI),str,3); Print_in_menu(str,7); } else Print_coordinates(); } Display_all_screen(); Rotate_brush_preview(angle); Display_cursor(); Operation_stack_size-=2; Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(2); } void Rotate_brush_0_5(void) // // Opration : OPERATION_ROTATE_BRUSH // Click Souris: 0 // Taille_Pile : 5 // // Souris efface: Non // { char str[4]; short old_x; short old_y; short computed_x=0; short computed_y=0; byte angle_change; short prev_state; float angle=0.0; int dx,dy; Operation_pop(&prev_state); Operation_pop(&old_y); Operation_pop(&old_x); // On corrige les coordonnes de la ligne si la touche shift est appuye... if(SDL_GetModState() & KMOD_SHIFT) Clamp_coordinates_regular_angle(Brush_rotation_center_X,Brush_rotation_center_Y,&Paintbrush_X,&Paintbrush_Y); if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) || (prev_state!=3)) { if ( (Brush_rotation_center_X==Paintbrush_X) && (Brush_rotation_center_Y==Paintbrush_Y) ) angle=0.0; else { dx=Paintbrush_X-Brush_rotation_center_X; dy=Paintbrush_Y-Brush_rotation_center_Y; angle=acos(((float)dx)/sqrt((dx*dx)+(dy*dy))); if (dy>0) angle=M_2PI-angle; } if (Menu_is_visible) { if (Config.Coords_rel) { Num2str(Round(angle*180.0/M_PI),str,3); Print_in_menu(str,7); } else Print_coordinates(); } } // Utilise Key_ANSI au lieu de Key, car Get_input() met ce dernier // zero si une operation est en cours (Operation_stack_size!=0) if (Key_ANSI) { angle_change=1; computed_x=Brush_rotation_center_X; computed_y=Brush_rotation_center_Y; switch (Key_ANSI) { case '6': angle= 0.0 ; computed_x++; break; case '9': angle=M_PI*0.25; computed_x++; computed_y--; break; case '8': angle=M_PI*0.5 ; computed_y--; break; case '7': angle=M_PI*0.75; computed_x--; computed_y--; break; case '4': angle=M_PI ; computed_x--; break; case '1': angle=M_PI*1.25; computed_x--; computed_y++; break; case '2': angle=M_PI*1.5 ; computed_y++; break; case '3': angle=M_PI*1.75; computed_x++; computed_y++; break; default : angle_change=0; } Key_ANSI=0; } else angle_change=0; if (angle_change) { // On efface la preview de la brosse Display_all_screen(); Rotate_brush_preview(angle); Display_cursor(); Operation_stack_size-=2; Operation_push(computed_x); Operation_push(computed_y); } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(3); } void Rotate_brush_2_5(void) // // Opration : OPERATION_ROTATE_BRUSH // Click Souris: 2 // Taille_Pile : 5 // // Souris efface: Oui // { short computed_x; short computed_y; int dx,dy; float angle; // On efface la preview de la brosse Display_all_screen(); Operation_stack_size-=3; Operation_pop(&computed_y); Operation_pop(&computed_x); // Calcul de l'angle par rapport la dernire position calcule if ( (Brush_rotation_center_X==computed_x) && (Brush_rotation_center_Y==computed_y) ) angle=0.0; else { dx=computed_x-Brush_rotation_center_X; dy=computed_y-Brush_rotation_center_Y; angle=acos(((float)dx)/sqrt((dx*dx)+(dy*dy))); if (dy>0) angle=M_2PI-angle; } // Et enfin on stocke pour de bon la nouvelle brosse tire Rotate_brush(angle); 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) // // Opration : OPERATION_DISTORT_BRUSH // Click Souris: 0 // Taille_Pile : 0 // // Souris efface: Non // { if ( Menu_is_visible ) { Print_in_menu("POSITION BRUSH TO START ",0); } } void Distort_brush_1_0(void) // // Opration : OPERATION_DISTORT_BRUSH // Click Souris: 1 // Taille_Pile : 0 // // Souris efface: 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) // // Opration : OPERATION_DISTORT_BRUSH // Click Souris: 1 // Taille_Pile : 8 // // Souris efface: 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) // // Opration : OPERATION_DISTORT_BRUSH // Click Souris: 1 // Taille_Pile : 9 // // Souris efface: 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) // // Opration : OPERATION_DISTORT_BRUSH // Click Souris: 0 // Taille_Pile : 9 // // Souris efface: No // { short selected_corner; Operation_pop(&selected_corner); } void Distort_brush_2_0(void) // // Opration : OPERATION_DISTORT_BRUSH // Click Souris: 2 // Taille_Pile : 0 // // Souris efface: 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) // // Opration : OPERATION_DISTORT_BRUSH // Click Souris: 2 // Taille_Pile : 8 // // Souris efface: 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(); } grafx2/src/buttons.c0000644000076400010400000047356011553130706015103 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2008 Yves Rizoud Copyright 2007-2010 Adrien Destugues (PulkoMandy) 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 */ #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) #include #include #include #elif defined(__WIN32__) #include #include #else #include #endif #define _XOPEN_SOURCE 500 #include #include #include #include #include #include #include #include #include #include "const.h" #include "struct.h" #include "global.h" #include "misc.h" #include "graph.h" #include "engine.h" #include "readline.h" #include "filesel.h" #include "loadsave.h" #include "init.h" #include "buttons.h" #include "operatio.h" #include "pages.h" #include "palette.h" #include "errors.h" #include "readini.h" #include "saveini.h" #include "shade.h" #include "io.h" #include "help.h" #include "text.h" #include "sdlscreen.h" #include "windows.h" #include "brush.h" #include "input.h" #include "special.h" #include "setup.h" #ifdef __VBCC__ #define __attribute__(x) #endif #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) #include #include #elif defined(__MINT__) #include #include #elif defined(__WIN32__) #include #include #else #include #endif extern char Program_version[]; // generated in pversion.c extern short Old_MX; extern short Old_MY; //-- MODELE DE BOUTON DE MENU ------------------------------------------------ /* void Bouton_***(void) { short clicked_button; Open_window(310,190,"***"); Window_set_normal_button(103,137,80,14,"OK",0,1,SDLK_RETURN); // 1 Window_set_scroller_button(18,44,88,16,4,0); // 2 Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); } while (clicked_button!=1); Close_window(); Unselect_button(BOUTON_***); Display_cursor(); } */ void Message_out_of_memory(void) { short clicked_button; Open_window(216,76,"Not enough memory!"); Print_in_window(8,20,"Please consult the manual",MC_Black,MC_Light); Print_in_window(24,28,"to know how to obtain",MC_Black,MC_Light); Print_in_window(36,36,"more memory space.",MC_Black,MC_Light); Window_set_normal_button(60,53,40,14,"OK",1,1,SDLK_RETURN); // 1 Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do clicked_button=Window_clicked_button(); while ((clicked_button<=0) && (Key!=KEY_ESC) && (Key!=SDLK_o)); if(clicked_button<=0) Key=0; Close_window(); Display_cursor(); } void Button_Message_initial(void) { char str[30]; int x_pos,offs_y,x,y; strcpy(str,"GrafX2 version "); strcat(str,Program_version); Open_window(260,172,str); Window_display_frame_in(10,20,239,62); Block(Window_pos_X+(Menu_factor_X*11), Window_pos_Y+(Menu_factor_Y*21), Menu_factor_X*237,Menu_factor_Y*60,MC_Black); for (y=23,offs_y=0; y<79; offs_y+=231,y++) for (x=14,x_pos=0; x_pos<231; x_pos++,x++) Pixel_in_window(x,y,Gfx->Logo_grafx2[offs_y+x_pos]); Print_in_window(130-4*26,88,"Copyright (c) 2007-2011 by",MC_Dark,MC_Light); Print_in_window(130-4*23,96,"the Grafx2 project team",MC_Black,MC_Light); Print_in_window(130-4*26,112,"Copyright (c) 1996-2001 by",MC_Dark,MC_Light); Print_in_window(130-4*13,120,"Sunset Design",MC_Black,MC_Light); //Print_in_window( 120-4*13,128,"(placeholder)",MC_Dark,MC_Light); Print_in_window(130-4*28,136,"http://grafx2.googlecode.com",MC_Dark,MC_Light); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); while(!Mouse_K && !Key) Get_input(20); if (Mouse_K) Wait_end_of_click(); Close_window(); Display_cursor(); } void Change_paintbrush_shape(byte shape) { Paintbrush_shape=shape; Display_paintbrush_in_menu(); switch (Current_operation) { case OPERATION_FILL : Paintbrush_shape_before_fill=shape; Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; break; case OPERATION_COLORPICK : Paintbrush_shape_before_colorpicker=shape; Paintbrush_shape=PAINTBRUSH_SHAPE_NONE; break; // Note: Il existe un Paintbrush_shape_before_lasso, mais comme le lasso aura // t automatiquement dsactiv avant d'arriver ici, y'a pas de problme. } } //-------------------------------- UNDO/REDO --------------------------------- void Button_Undo(void) { Hide_cursor(); Undo(); Set_palette(Main_palette); Compute_optimal_menu_colors(Main_palette); Display_all_screen(); Unselect_button(BUTTON_UNDO); Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); Display_menu(); Display_cursor(); } void Button_Redo(void) { Hide_cursor(); Redo(); Set_palette(Main_palette); Compute_optimal_menu_colors(Main_palette); Display_all_screen(); Unselect_button(BUTTON_UNDO); Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); Display_menu(); Display_cursor(); } //---------------------------- SCROLL PALETTE LEFT --------------------------- void Button_Pal_left(void) { short cells; cells = (Config.Palette_vertical)?Palette_cells_X():Palette_cells_Y(); Hide_cursor(); if (First_color_in_palette) { if (First_color_in_palette>=cells) First_color_in_palette-=cells; else First_color_in_palette=0; Display_menu_palette(); } Unselect_button(BUTTON_PAL_LEFT); Display_cursor(); } void Button_Pal_left_fast(void) { short cells_x = Palette_cells_X(); short cells_y = Palette_cells_Y(); Hide_cursor(); if (First_color_in_palette) { if (First_color_in_palette>=cells_y*cells_x) First_color_in_palette-=cells_y*cells_x; else First_color_in_palette=0; Display_menu_palette(); } Unselect_button(BUTTON_PAL_LEFT); Display_cursor(); } //--------------------------- SCROLL PALETTE RIGHT --------------------------- void Button_Pal_right(void) { short cells; cells = (Config.Palette_vertical)?Palette_cells_X():Palette_cells_Y(); Hide_cursor(); if ((int)First_color_in_palette+Palette_cells_X()*Palette_cells_Y()<256) { First_color_in_palette+=cells; Display_menu_palette(); } Unselect_button(BUTTON_PAL_RIGHT); Display_cursor(); } void Button_Pal_right_fast(void) { short cells_x = Palette_cells_X(); short cells_y = Palette_cells_Y(); Hide_cursor(); if ((int)First_color_in_palette+cells_y*cells_x<256) { if ((int)First_color_in_palette+(cells_y)*cells_x*2<256) First_color_in_palette+=cells_x*cells_y; else First_color_in_palette=255/cells_y*cells_y-(cells_x-1)*cells_y; Display_menu_palette(); } Unselect_button(BUTTON_PAL_RIGHT); Display_cursor(); } //-------------------- item de la forecolor dans le menu -------------------- void Button_Select_forecolor(void) { static long time_click = 0; long time_previous; int color; time_previous = time_click; time_click = SDL_GetTicks(); color=Pick_color_in_palette(); if (color == Fore_color) { // Check if it's a double-click if (time_click - time_previous < Config.Double_click_speed) { // Open palette window Button_Palette(); return; } } do { if (color != Fore_color && color!=-1) { Hide_cursor(); Set_fore_color(color); Display_cursor(); } // Wait loop after initial click while(Mouse_K) { Get_input(20); if (Button_under_mouse()==BUTTON_CHOOSE_COL) { color=Pick_color_in_palette(); if (color != Fore_color && color!=-1) { Hide_cursor(); Status_print_palette_color(color); Set_fore_color(color); Display_cursor(); } } } } while(Mouse_K); } //-------------------- item de la backcolor dans le menu -------------------- void Button_Select_backcolor(void) { int color; do { color=Pick_color_in_palette(); if (color!=-1 && color != Back_color) { Hide_cursor(); Status_print_palette_color(color); Set_back_color(color); Display_cursor(); } // Wait loop after initial click do { Get_input(20); if (Button_under_mouse()==BUTTON_CHOOSE_COL) break; // This will repeat this button's action } while(Mouse_K); } while(Mouse_K); } void Button_Hide_menu(void) { Hide_cursor(); if (Menu_is_visible) { Menu_is_visible=0; Menu_Y=Screen_height; if (Main_magnifier_mode) { Compute_magnifier_data(); } // On repositionne le dcalage de l'image pour qu'il n'y ait pas d'in- // -cohrences lorsqu'on sortira du mode Loupe. if (Main_offset_Y+Screen_height>Main_image_height) { if (Screen_height>Main_image_height) Main_offset_Y=0; else Main_offset_Y=Main_image_height-Screen_height; } // On fait pareil pour le brouillon if (Spare_offset_Y+Screen_height>Spare_image_height) { if (Screen_height>Spare_image_height) Spare_offset_Y=0; else Spare_offset_Y=Spare_image_height-Screen_height; } Compute_magnifier_data(); if (Main_magnifier_mode) Position_screen_according_to_zoom(); Compute_limits(); Compute_paintbrush_coordinates(); Display_all_screen(); } else { byte current_menu; Menu_is_visible=1; Menu_Y=Screen_height; for (current_menu = 0; current_menu < MENUBAR_COUNT; current_menu++) if (Menu_bars[current_menu].Visible) Menu_Y -= Menu_bars[current_menu].Height * Menu_factor_Y; Compute_magnifier_data(); if (Main_magnifier_mode) Position_screen_according_to_zoom(); Compute_limits(); Compute_paintbrush_coordinates(); Display_menu(); if (Main_magnifier_mode) Display_all_screen(); } Unselect_button(BUTTON_HIDE); Display_cursor(); } void Set_bar_visibility(word bar, byte visible) { if (!visible && Menu_bars[bar].Visible) { // Hide it Menu_bars[bar].Visible=0; Compute_menu_offsets(); if (Main_magnifier_mode) { Compute_magnifier_data(); } // On repositionne le dcalage de l'image pour qu'il n'y ait pas d'in- // -cohrences lorsqu'on sortira du mode Loupe. if (Main_offset_Y+Screen_height>Main_image_height) { if (Screen_height>Main_image_height) Main_offset_Y=0; else Main_offset_Y=Main_image_height-Screen_height; } // On fait pareil pour le brouillon if (Spare_offset_Y+Screen_height>Spare_image_height) { if (Screen_height>Spare_image_height) Spare_offset_Y=0; else Spare_offset_Y=Spare_image_height-Screen_height; } Compute_magnifier_data(); if (Main_magnifier_mode) Position_screen_according_to_zoom(); Compute_limits(); Compute_paintbrush_coordinates(); Display_menu(); Display_all_screen(); } else if (visible && !Menu_bars[bar].Visible) { // Show it Menu_bars[bar].Visible = 1; Compute_menu_offsets(); Compute_magnifier_data(); if (Main_magnifier_mode) Position_screen_according_to_zoom(); Compute_limits(); Compute_paintbrush_coordinates(); Display_menu(); if (Main_magnifier_mode) Display_all_screen(); } } void Button_Toggle_toolbar(void) { T_Dropdown_button dropdown; T_Dropdown_choice *item; static char menu_name[2][9]= { " Tools", " Layers" }; menu_name[0][0] = Menu_bars[MENUBAR_TOOLS ].Visible ? 22 : ' '; menu_name[1][0] = Menu_bars[MENUBAR_LAYERS].Visible ? 22 : ' '; Hide_cursor(); dropdown.Pos_X =Buttons_Pool[BUTTON_HIDE].X_offset; dropdown.Pos_Y =Buttons_Pool[BUTTON_HIDE].Y_offset; dropdown.Height =Buttons_Pool[BUTTON_HIDE].Height; dropdown.Dropdown_width=70; dropdown.First_item =NULL; dropdown.Bottom_up =1; Window_dropdown_add_item(&dropdown, 0, menu_name[0]); Window_dropdown_add_item(&dropdown, 1, menu_name[1]); item=Dropdown_activate(&dropdown,0,Menu_Y+Menu_bars[MENUBAR_STATUS].Top*Menu_factor_Y); if (item) { switch (item->Number) { case 0: Set_bar_visibility(MENUBAR_TOOLS, !Menu_bars[MENUBAR_TOOLS].Visible); break; case 1: Set_bar_visibility(MENUBAR_LAYERS, !Menu_bars[MENUBAR_LAYERS].Visible); break; } } // Closing Window_dropdown_clear_items(&dropdown); Unselect_button(BUTTON_HIDE); Display_cursor(); } void Button_Toggle_all_toolbars(void) { // This is used to memorize the bars' visibility when temporarily hidden static word Last_visibility = 0xFFFF; int i; word current_visibility; Hide_cursor(); // Check which bars are visible current_visibility=0; for (i=MENUBAR_STATUS+1;iPages->Filename, Main_backups->Pages->File_directory); if ( (!File_exists(filename)) || Confirmation_box("Erase old file ?") ) { T_IO_Context save_context; Hide_cursor(); old_cursor_shape=Cursor_shape; Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); Init_context_layered_image(&save_context, Main_backups->Pages->Filename, Main_backups->Pages->File_directory); Save_image(&save_context); Destroy_context(&save_context); Hide_cursor(); Cursor_shape=old_cursor_shape; Display_cursor(); if (!File_error) // L'ayant sauve avec succs, return 1; // On peut quitter else // Il y a eu une erreur lors de la sauvegarde, return 0; // On ne peut donc pas quitter } else // L'utilisateur ne veut pas craser l'ancien fichier, return 0; // On doit donc rester case 3 : return 1; // Quitter } return 0; } void Button_Quit(void) { //short clicked_button; if (Button_Quit_local_function()) { if (Spare_image_is_modified) { Button_Page(); // On passe sur le brouillon // Si l'utilisateur prsente les derniers symptomes de l'abandon if (Button_Quit_local_function()) Quitting=1; } else Quitting=1; } if ( (Menu_is_visible) && (Mouse_Y+8>Menu_Y) ) Hide_cursor(); Unselect_button(BUTTON_QUIT); if ( (Menu_is_visible) && (Mouse_Y+8>Menu_Y) ) Display_cursor(); } //---------------------------- Effacer l'cran ------------------------------- void Button_Clear(void) { Hide_cursor(); Backup(); if (Stencil_mode && Config.Clear_with_stencil) Clear_current_image_with_stencil(Main_backups->Pages->Transparent_color,Stencil); else Clear_current_image(Main_backups->Pages->Transparent_color); Redraw_layered_image(); End_of_modification(); Display_all_screen(); Unselect_button(BUTTON_CLEAR); Display_cursor(); } void Button_Clear_with_backcolor(void) { Hide_cursor(); Backup(); if (Stencil_mode && Config.Clear_with_stencil) Clear_current_image_with_stencil(Back_color,Stencil); else Clear_current_image(Back_color); Redraw_layered_image(); End_of_modification(); Display_all_screen(); Unselect_button(BUTTON_CLEAR); Display_cursor(); } //------------------------------- Paramtres --------------------------------- #define SETTING_PER_PAGE 11 #define SETTING_PAGES 5 #define SETTING_HEIGHT 12 typedef struct { const char* Label; // Use NULL label to stop an array int Code; } T_Lookup; const T_Lookup Lookup_YesNo[] = { {"NO",0}, {"YES",1}, {NULL,-1}, }; const T_Lookup Lookup_FFF[] = { {"All",0}, {"Files",1}, {"Dirs.",2}, {NULL,-1}, }; const T_Lookup Lookup_AutoRes[] = { {"Internal",1}, {"Real",2}, {NULL,-1}, }; const T_Lookup Lookup_Coords[] = { {"Relative",1}, {"Absolute",2}, {NULL,-1}, }; const T_Lookup Lookup_MenuRatio[] = { {"None",0}, {"x2",254}, // -2 {"x3",253}, // -3 {"x4",252}, // -4 {"Moderate",2}, {"Maximum",1}, {NULL,-1}, }; const T_Lookup Lookup_MouseSpeed[] = { {"Normal",1}, {"/2",2}, {"/3",3}, {"/4",4}, {NULL,-1}, }; const T_Lookup Lookup_SwapButtons[] = { {"None",0}, {"Control",MOD_CTRL}, {"Alt",MOD_ALT}, {NULL,-1}, }; typedef struct { const char* Label; byte Type; // 0: label, 1+: setting (size in bytes) void * Value; int Min_value; int Max_value; int Digits; // Could be computed from Max_value...but don't bother. const T_Lookup * Lookup; } T_Setting; long int Get_setting_value(T_Setting *item) { switch(item->Type) { case 1: return *((byte *)(item->Value)); break; case 2: return *((word *)(item->Value)); break; case 4: default: return *((long int *)(item->Value)); break; } } void Set_setting_value(T_Setting *item, long int value) { switch(item->Type) { case 1: *((byte *)(item->Value)) = value; break; case 2: *((word *)(item->Value)) = value; break; case 4: default: *((long int *)(item->Value)) = value; break; } } // Fetch a label in a lookup table. Unknown values get label 0. const char *Lookup_code(int code, const T_Lookup *lookup) { int i; for(i=0; lookup[i].Label!=NULL; i++) { if (lookup[i].Code == code) return lookup[i].Label; } return lookup[0].Label; } /// Increase an enum to next-higher value (wrapping). int Lookup_next(int code, const T_Lookup *lookup) { int i; for(i=0; lookup[i].Label!=NULL; i++) { if (lookup[i].Code == code) { if (lookup[i+1].Label==NULL) return lookup[0].Code; return lookup[i+1].Code; } } return 0; } /// Decrease an enum to previous value (wrapping). int Lookup_previous(int code, const T_Lookup *lookup) { int count; int current=-1; for(count=0; lookup[count].Label!=NULL; count++) { if (lookup[count].Code == code) current=count; } return lookup[(current + count - 1) % count].Code; } void Settings_display_config(T_Setting *setting, T_Config * conf, T_Special_button *panel) { int i; // A single button Print_in_window(155,166,(conf->Auto_save)?"YES":" NO",MC_Black,MC_Light); // Clear all Window_rectangle(panel->Pos_X, panel->Pos_Y, panel->Width, panel->Height+1, MC_Light); for (i=0; iPos_X+3, panel->Pos_Y+i*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2, setting[i].Label, i==0?MC_White:MC_Dark, MC_Light); if(setting[i].Value) { int value = Get_setting_value(&setting[i]); if (setting[i].Lookup) { // Use a lookup table to print a label const char *str; str = Lookup_code(value,setting[i].Lookup); Print_in_window(panel->Pos_X+3+176, panel->Pos_Y+i*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2, str, MC_Black, MC_Light); } else { // Print a number char str[10]; Num2str(value,str,setting[i].Digits); Print_in_window(panel->Pos_X+3+176, panel->Pos_Y+i*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2, str, MC_Black, MC_Light); } } } Update_window_area(panel->Pos_X, panel->Pos_Y, panel->Width, panel->Height+1); } void Settings_save_config(T_Config * conf) { if (Save_CFG()) Error(0); else if (Save_INI(conf)) Error(0); } void Settings_load_config(T_Config * conf) { if (Load_CFG(0)) Error(0); else if (Load_INI(conf)) Error(0); } void Button_Settings(void) { short clicked_button; T_Config selected_config; byte config_is_reloaded=0; T_Special_button *panel; byte need_redraw=1; static byte current_page=0; // Definition of settings pages // Label,Type (0 = label, 1+ = setting size in bytes), // Value, min, max, digits, Lookup) T_Setting setting[SETTING_PER_PAGE*SETTING_PAGES] = { {" --- GUI ---",0,NULL,0,0,0,NULL}, {"Opening message:",1,&(selected_config.Opening_message),0,1,0,Lookup_YesNo}, {"Menu ratio adapt:",1,&(selected_config.Ratio),0,1,0,Lookup_MenuRatio}, {"Draw limits:",1,&(selected_config.Display_image_limits),0,1,0,Lookup_YesNo}, {"Coordinates:",1,&(selected_config.Coords_rel),0,1,0,Lookup_Coords}, {"Separate colors:",1,&(selected_config.Separate_colors),0,1,0,Lookup_YesNo}, {"Safety colors:",1,&(selected_config.Safety_colors),0,1,0,Lookup_YesNo}, {"Grid XOR color:",1,&(selected_config.Grid_XOR_color),0,255,3,NULL}, {"Sync views:",1,&(selected_config.Sync_views),0,1,0,Lookup_YesNo}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {" --- Input ---",0,NULL,0,0,0,NULL}, {"Scrollbar speed",0,NULL,0,0,0,NULL}, {" on left click:",1,&(selected_config.Delay_left_click_on_slider),1,255,4,NULL}, {" on right click:",1,&(selected_config.Delay_right_click_on_slider),1,255,4,NULL}, {"Merge movement:",1,&(selected_config.Mouse_merge_movement),0,100,4,NULL}, {"Double click speed:",2,&(selected_config.Double_click_speed),1,1999,4,NULL}, {"Double key speed:",2,&(selected_config.Double_key_speed),1,1999,4,NULL}, //{"Mouse speed (fullscreen)",0,NULL,0,0,0,NULL}, //{" horizontally:",1,&(selected_config.Mouse_sensitivity_index_x),1,4,0,Lookup_MouseSpeed}, //{" vertically:",1,&(selected_config.Mouse_sensitivity_index_y),1,4,0,Lookup_MouseSpeed}, {"Key to swap buttons:",2,&(selected_config.Swap_buttons),0,0,0,Lookup_SwapButtons}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {" --- Editing ---",0,NULL,0,0,0,NULL}, {"Adjust brush pick:",1,&(selected_config.Adjust_brush_pick),0,1,0,Lookup_YesNo}, {"Undo pages:",1,&(selected_config.Max_undo_pages),1,99,5,NULL}, {"Vertices per polygon:",4,&(selected_config.Nb_max_vertices_per_polygon),2,16384,5,NULL}, {"Fast zoom:",1,&(selected_config.Fast_zoom),0,1,0,Lookup_YesNo}, {"Clear with stencil:",1,&(selected_config.Clear_with_stencil),0,1,0,Lookup_YesNo}, {"Auto discontinuous:",1,&(selected_config.Auto_discontinuous),0,1,0,Lookup_YesNo}, {"Auto count colors:",1,&(selected_config.Auto_nb_used),0,1,0,Lookup_YesNo}, {"Right click colorpick:",1,&(selected_config.Right_click_colorpick),0,1,0,Lookup_YesNo}, {"Multi shortcuts:",1,&(selected_config.Allow_multi_shortcuts),0,1,0,Lookup_YesNo}, {"",0,NULL,0,0,0,NULL}, {" --- File selector ---",0,NULL,0,0,0,NULL}, {"Show in fileselector",0,NULL,0,0,0,NULL}, {" Hidden files:",4,&(selected_config.Show_hidden_files),0,1,0,Lookup_YesNo}, {" Hidden dirs:",4,&(selected_config.Show_hidden_directories),0,1,0,Lookup_YesNo}, {"Preview delay:",4,&(selected_config.Timer_delay), 1,256,3,NULL}, {"Maximize preview:",1,&(selected_config.Maximize_preview), 0,1,0,Lookup_YesNo}, {"Find file fast:",1,&(selected_config.Find_file_fast), 0,2,0,Lookup_FFF}, {"Auto set resolution:",1,&(selected_config.Auto_set_res), 0,1,0,Lookup_YesNo}, {" According to:",1,&(selected_config.Set_resolution_according_to), 1,2,0,Lookup_AutoRes}, {"Backup:",1,&(selected_config.Backup), 0,1,0,Lookup_YesNo}, {"",0,NULL,0,0,0,NULL}, {" --- Format options ---",0,NULL,0,0,0,NULL}, {"Screen size in GIF:",1,&(selected_config.Screen_size_in_GIF),0,1,0,Lookup_YesNo}, {"Clear palette:",1,&(selected_config.Clear_palette),0,1,0,Lookup_YesNo}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, }; const char * help_section[SETTING_PAGES] = { "GUI", "INPUT", "EDITING", "FILE SELECTOR", "FILE FORMAT OPTIONS", }; selected_config=Config; Open_window(307,182,"Settings"); // Button Reload Window_set_normal_button( 6,163, 51,14,"Reload" ,0,1,SDLK_LAST); // 1 // Button Auto-save Window_set_normal_button( 73,163,107,14,"Auto-save: ",0,1,SDLK_LAST); // 2 // Button Save Window_set_normal_button(183,163, 51,14,"Save" ,0,1,SDLK_LAST); // 3 // Button Close Window_set_normal_button(250,163, 51,14,"Close" ,0,1,KEY_ESC); // 4 panel=Window_set_special_button(10, 21, 272,SETTING_PER_PAGE*SETTING_HEIGHT); // 5 Window_set_scroller_button(285,21,SETTING_PER_PAGE*SETTING_HEIGHT,SETTING_PAGES,1,current_page); // 6 Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { if (need_redraw) { Hide_cursor(); Settings_display_config(setting+current_page*SETTING_PER_PAGE, &selected_config, panel); if (need_redraw & 2) { // Including slider position Window_scroller_button_list->Position=current_page; Window_draw_slider(Window_scroller_button_list); } Display_cursor(); need_redraw=0; } clicked_button=Window_clicked_button(); switch(clicked_button) { case 1 : // Reload Settings_load_config(&selected_config); config_is_reloaded=1; need_redraw=1; break; case 2 : // Auto-save selected_config.Auto_save=!selected_config.Auto_save; need_redraw=1; break; case 3 : // Save Settings_save_config(&selected_config); break; // case 4: // Close case 5: // Panel area { T_Setting item; int num=(((short)Mouse_Y-Window_pos_Y)/Menu_factor_Y - panel->Pos_Y)/SETTING_HEIGHT; if (num >= 0 && num < SETTING_PER_PAGE) { item=setting[current_page*SETTING_PER_PAGE+num]; if (item.Type!=0) { // Remember which button is clicked byte old_mouse_k = Mouse_K; if (Window_normal_button_onclick(panel->Pos_X, panel->Pos_Y+num*SETTING_HEIGHT, panel->Width, SETTING_HEIGHT+1, 5)) { int value = Get_setting_value(&item); if (item.Lookup) { // Enum: toggle it if (old_mouse_k & LEFT_SIDE) value = Lookup_next(value, item.Lookup); else value = Lookup_previous(value, item.Lookup); Set_setting_value(&item, value); } else { // Numeric: edit it char str[10]; str[0]='\0'; if (! (old_mouse_k & RIGHT_SIDE)) Num2str(value,str,item.Digits+1); if (Readline(panel->Pos_X+3+176, panel->Pos_Y+num*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2,str,item.Digits+1,INPUT_TYPE_INTEGER)) { value=atoi(str); if (valueitem.Max_value) value = item.Max_value; Set_setting_value(&item, value); } Key=0; // Need to discard keys used during editing } } } } } need_redraw=1; break; case 6: // Scroller current_page = Window_attribute2; need_redraw=1; break; } if (Key == KEY_MOUSEWHEELDOWN) { if (current_page < (SETTING_PAGES-1)) { current_page++; need_redraw=2; } } else if (Key == KEY_MOUSEWHEELUP) { if (current_page > 0) { current_page--; need_redraw=2; } } else if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(NB_BUTTONS+0, help_section[current_page]); else if (Is_shortcut(Key,0x100+BUTTON_SETTINGS)) clicked_button=4; } while ( (clicked_button!=4) && (Key!=SDLK_RETURN) ); // Checks on change if (Config.Show_hidden_directories!=selected_config.Show_hidden_directories ||Config.Show_hidden_files!=selected_config.Show_hidden_files) { // Reset fileselector offsets // since different files are shown now Main_fileselector_position=0; Main_fileselector_offset=0; Spare_fileselector_position=0; Spare_fileselector_offset=0; } if(Config.Allow_multi_shortcuts && !selected_config.Allow_multi_shortcuts) { // User just disabled multi shortcuts: make them unique now. Remove_duplicate_shortcuts(); } // Copy all Config=selected_config; if (config_is_reloaded) Compute_optimal_menu_colors(Main_palette); Close_window(); Unselect_button(BUTTON_SETTINGS); // Raffichage du menu pour que les inscriptions qui y figurent soient // retraces avec la nouvelle fonte Display_menu(); Display_cursor(); // On vrifie qu'on peut bien allouer le nombre de pages Undo. Set_number_of_backups(Config.Max_undo_pages); } // Data for skin selector T_Fileselector Skin_files_list; // Data for font selector T_Fileselector Font_files_list; // char * Format_font_filename(const char * fname) { static char result[12]; int c; int length; fname+=strlen(FONT_PREFIX); // Omit file prefix length=strlen(fname) - 4; // assume .png extension for (c=0;c<11 && c11) result[10] = ELLIPSIS_CHARACTER; return result; } // Add a skin to the list void Add_font_or_skin(const char *name) { const char * fname; int namelength; // Cut the long name to keep only filename (no directory) fname = Find_last_slash(name); if (fname) fname++; else fname = name; namelength = strlen(fname); if (namelength>=10 && fname[0]!='_' && !strncasecmp(fname, SKIN_PREFIX, strlen(SKIN_PREFIX)) && (!strcasecmp(fname + namelength - 4,".png") || !strcasecmp(fname + namelength - 4,".gif"))) { Add_element_to_list(&Skin_files_list, fname, Format_filename(fname, 19, 0), 0, ICON_NONE); if (fname[0]=='\0') return; } else if (namelength>=10 && !strncasecmp(fname, FONT_PREFIX, strlen(FONT_PREFIX)) && (!strcasecmp(fname + namelength - 4, ".png"))) { Add_element_to_list(&Font_files_list, fname, Format_font_filename(fname), 0, ICON_NONE); if (fname[0]=='\0') return; } } // Callback to display a skin name in the list void Draw_one_skin_name(word x, word y, word index, byte highlighted) { T_Fileselector_item * current_item; if (Skin_files_list.Nb_elements) { current_item = Get_item_by_index(&Skin_files_list, index); Print_in_window(x, y, current_item->Short_name, MC_Black, (highlighted)?MC_Dark:MC_Light); } } /// Skin selector window void Button_Skins(void) { short clicked_button; short temp; char skinsdir[MAX_PATH_CHARACTERS]; T_Dropdown_button * font_dropdown; T_Dropdown_button * cursor_dropdown; T_List_button * skin_list; T_Scroller_button * file_scroller; int selected_font = 0; int selected_cursor = Config.Cursor; byte separatecolors = Config.Separate_colors; byte showlimits = Config.Display_image_limits; byte need_load=1; int button; word x, y, x_pos, offs_y; char * cursors[] = { "Solid", "Transparent", "Thin" }; T_Gui_skin * gfx = NULL; #define FILESEL_Y 34 // --- Read the contents of skins/ directory ------------------ // Here we use the same data container as the fileselectors. // Reinitialize the list Free_fileselector_list(&Skin_files_list); Free_fileselector_list(&Font_files_list); // Browse the "skins" directory strcpy(skinsdir, Data_directory); strcat(skinsdir, SKINS_SUBDIRECTORY); // Add each found file to the list For_each_file(skinsdir, Add_font_or_skin); // Sort it Sort_list_of_files(&Skin_files_list); Sort_list_of_files(&Font_files_list); selected_font = Find_file_in_fileselector(&Font_files_list, Config.Font_file); // -------------------------------------------------------------- Open_window(290, 140, "Skins"); // Frames Window_display_frame_in(6, FILESEL_Y - 2, 148, 84); // File selector // Texts Print_in_window( 172, 33,"Font:" ,MC_Black,MC_Light); Print_in_window( 172, 59,"Cursor:" ,MC_Black,MC_Light); // Ok button Window_set_normal_button(6, 120, 51, 14, "OK", 0, 1, SDLK_RETURN); // 1 // List of skins skin_list = Window_set_list_button( // Fileselector Window_set_special_button(8, FILESEL_Y + 1, 144, 80), // 2 // Scroller for the fileselector (file_scroller = Window_set_scroller_button(155, FILESEL_Y - 1, 82, Skin_files_list.Nb_elements, 10, 0)), // 3 Draw_one_skin_name, 2); // 4 skin_list->Cursor_position = Find_file_in_fileselector(&Skin_files_list, Config.Skin_file); // Buttons to choose a font font_dropdown = Window_set_dropdown_button(172, 43, 104, 11, 0, Get_item_by_index(&Font_files_list,selected_font)->Short_name,1,0,1,RIGHT_SIDE|LEFT_SIDE,0); // 5 for (temp=0; tempShort_name); // Cancel Window_set_normal_button(61, 120, 51,14,"Cancel",0,1,SDLK_ESCAPE); // 6 // Dropdown list to choose cursor type cursor_dropdown = Window_set_dropdown_button(172, 69, 104, 11, 0, cursors[selected_cursor], 1, 0, 1, RIGHT_SIDE|LEFT_SIDE,0); // 7 for (temp = 0; temp<3; temp++) Window_dropdown_add_item(cursor_dropdown, temp, cursors[temp]); Window_set_normal_button(172, 87, 14, 14, (Config.Display_image_limits)?"X":" ", -1, 1, SDLK_LAST); // 8 Print_in_window( 190, 85,"Draw picture", MC_Dark, MC_Light); Print_in_window( 190, 94,"limits", MC_Dark, MC_Light); Window_set_normal_button(172, 111, 14, 14, (Config.Separate_colors)?"X":" ", -1, 1, SDLK_LAST); // 9 Print_in_window( 190, 109,"Separate", MC_Dark, MC_Light); Print_in_window( 190, 118,"colors", MC_Dark, MC_Light); Window_redraw_list(skin_list); for (y = 14, offs_y = 0; offs_y < 16; offs_y++, y++) for (x = 6, x_pos = 0; x_pos<173; x_pos++, x++) Pixel_in_window(x, y, Gfx->Preview[offs_y][x_pos]); Update_window_area(0, 0, Window_width, Window_height); Display_cursor(); do { if (need_load) { need_load=0; Hide_cursor(); // (Re-)load GUI graphics from selected skins strcpy(skinsdir, Get_item_by_index(&Skin_files_list, skin_list->List_start + skin_list->Cursor_position)->Full_name); gfx = Load_graphics(skinsdir, NULL); if (gfx == NULL) // Error { Display_cursor(); Verbose_message("Error!", Gui_loading_error_message); Hide_cursor(); // Update preview Window_rectangle(6, 14, 173, 16, MC_Light); } else { // Update preview // Display the bitmap according to its own color indices for (y = 14, offs_y = 0; offs_y < 16; offs_y++, y++) for (x = 6, x_pos = 0; x_pos<173; x_pos++, x++) { if (gfx->Preview[offs_y][x_pos] == gfx->Color[0]) Pixel_in_window(x, y, MC_Black); else if (gfx->Preview[offs_y][x_pos] == gfx->Color[1]) Pixel_in_window(x, y, MC_Dark); else if (gfx->Preview[offs_y][x_pos] == gfx->Color[3]) Pixel_in_window(x, y, MC_White); else if (gfx->Preview[offs_y][x_pos] == gfx->Color[2]) Pixel_in_window(x, y, MC_Light); } // Actualize current screen according to preferred GUI colors // Note this only updates onscreen colors Set_color( MC_Black, gfx->Default_palette[gfx->Color[0]].R, gfx->Default_palette[gfx->Color[0]].G, gfx->Default_palette[gfx->Color[0]].B); Set_color( MC_Dark, gfx->Default_palette[gfx->Color[1]].R, gfx->Default_palette[gfx->Color[1]].G, gfx->Default_palette[gfx->Color[1]].B); Set_color( MC_Light, gfx->Default_palette[gfx->Color[2]].R, gfx->Default_palette[gfx->Color[2]].G, gfx->Default_palette[gfx->Color[2]].B); Set_color( MC_White, gfx->Default_palette[gfx->Color[3]].R, gfx->Default_palette[gfx->Color[3]].G, gfx->Default_palette[gfx->Color[3]].B); } Update_window_area(6, 14, 173, 16); Display_cursor(); } clicked_button=Window_clicked_button(); if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_SETTINGS, "SKINS"); switch(clicked_button) { case 1 : // OK break; case 2 : // double-click file: do nothing break; case 3 : // doesn't happen break; case 4 : // a file is selected need_load=1; break; case 5 : // Font dropdown selected_font = Window_attribute2; // Get the index of the chosen font. break; // 6: Cancel case 7 : // Cursor selected_cursor = Window_attribute2; break; case 8: // Display limits showlimits = !showlimits; Hide_cursor(); Print_in_window(175, 90, (showlimits)?"X":" ", MC_Black, MC_Light); Display_cursor(); break; case 9: // Separate colors separatecolors = !separatecolors; Hide_cursor(); Print_in_window(175, 114, (separatecolors)?"X":" ", MC_Black, MC_Light); Display_cursor(); break; } } while ( (clicked_button!=1) && (clicked_button !=6) && (Key != SDLK_ESCAPE)); if(clicked_button == 1) { byte * new_font; if (gfx != NULL) { Set_current_skin(skinsdir, gfx); } // (Re-)load the selected font new_font = Load_font(Get_item_by_index(&Font_files_list,selected_font)->Full_name); if (new_font) { const char * fname; free(Menu_font); Menu_font = new_font; fname = Get_item_by_index(&Font_files_list,selected_font)->Full_name; free(Config.Font_file); Config.Font_file = (char *)strdup(fname); } // Confirm the change of cursor shape Config.Cursor = selected_cursor; Config.Display_image_limits = showlimits; Config.Separate_colors = separatecolors; // Now find the best colors for the new skin in the current palette // and remap the skin Compute_optimal_menu_colors(Main_palette); } // We don't want to keep the skin's palette, as this would corrupt the current picture's one. Set_palette(Main_palette); Close_window(); Unselect_button(BUTTON_SETTINGS); // Raffichage du menu pour que les inscriptions qui y figurent soient retraces avec la nouvelle fonte Display_menu(); // Redraw all buttons, to ensure all specific sprites are in place. // This is necessary for multi-state buttons, for example Freehand. for (button=0; buttonPages->Nb_layers; i++) { if (i == Spare_current_layer) { // Copy the current layer memcpy(Spare_backups->Pages->Image[i],Main_backups->Pages->Image[Main_current_layer],Main_image_width*Main_image_height); } else { // Resize the original layer Copy_part_of_image_to_another( Spare_backups->Pages->Next->Image[i],0,0,Min(old_width,Spare_image_width), Min(old_height,Spare_image_height),old_width, Spare_backups->Pages->Image[i],0,0,Spare_image_width); } } // Copie des dimensions de l'image /* C'est inutile, le "Backuper et redimensionner brouillon" a dj modifi ces valeurs pour qu'elles soient correctes. */ /* Spare_image_width=Main_image_width; Spare_image_height=Main_image_height; */ Copy_view_to_spare(); // Update the visible buffer of the spare. // It's a bit complex because at the moment, to save memory, // the spare doesn't have a full visible_buffer + depth_buffer, // so I can't use exactly the same technique as for Main page. // (It's the same reason that the "Page" function gets complex, // it needs to rebuild a depth buffer only, trusting the // depth buffer that was already available in Spare_.) Update_spare_buffers(Spare_image_width,Spare_image_height); Redraw_spare_image(); } else Message_out_of_memory(); } void Copy_some_colors(void) { short index; byte confirmation=0; static byte mask_color_to_copy[256]; // static to use less stack memset(mask_color_to_copy,1,256); Menu_tag_colors("Tag colors to copy",mask_color_to_copy,&confirmation,0, NULL, 0xFFFF); if (confirmation) { // Make a backup with the same pixel data as previous history steps Backup_the_spare(0); for (index=0; index<256; index++) { if (mask_color_to_copy[index]) memcpy(Spare_palette+index,Main_palette+index, sizeof(T_Components)); } } } void Button_Copy_page(void) { short clicked_button; Open_window(168,137,"Copy to spare page"); Window_set_normal_button(10, 20,148,14,"Pixels + palette" , 0,1,SDLK_RETURN); // 1 Window_set_normal_button(10, 37,148,14,"Pixels only" , 3,1,SDLK_x); // 2 Window_set_normal_button(10, 54,148,14,"Palette only" , 1,1,SDLK_p); // 3 Window_set_normal_button(10, 71,148,14,"Some colors only" , 6,1,SDLK_c); // 4 Window_set_normal_button(10, 88,148,14,"Palette and remap",13,1,SDLK_r); // 5 Window_set_normal_button(44,114, 80,14,"Cancel" , 0,1,KEY_ESC); // 6 Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_PAGE, NULL); else if (Is_shortcut(Key,0x200+BUTTON_PAGE)) clicked_button=6; } while (clicked_button<=0); Close_window(); Display_cursor(); switch (clicked_button) { case 1: // Pixels+palette Backup_the_spare(-1); Copy_image_only(); // copie de la palette memcpy(Spare_palette,Main_palette,sizeof(T_Palette)); // Equivalent of 'end_of_modifications' for spare. Update_spare_buffers(Spare_image_width,Spare_image_height); Redraw_spare_image(); Spare_image_is_modified=1; break; case 2: // Pixels only Backup_the_spare(-1); Copy_image_only(); // Equivalent of 'end_of_modifications' for spare. Update_spare_buffers(Spare_image_width,Spare_image_height); Redraw_spare_image(); Spare_image_is_modified=1; break; case 3: // Palette only Backup_the_spare(0); // Copy palette memcpy(Spare_palette,Main_palette,sizeof(T_Palette)); // Equivalent of 'end_of_modifications' for spare. Update_spare_buffers(Spare_image_width,Spare_image_height); Redraw_spare_image(); Spare_image_is_modified=1; break; case 4: // Some colors // Will backup if needed Copy_some_colors(); break; case 5: // Palette and remap Backup_the_spare(-1); Remap_spare(); // Copy palette memcpy(Spare_palette,Main_palette,sizeof(T_Palette)); // Equivalent of 'end_of_modifications' for spare. Update_spare_buffers(Spare_image_width,Spare_image_height); Redraw_spare_image(); Spare_image_is_modified=1; break; } Hide_cursor(); Unselect_button(BUTTON_PAGE); Display_cursor(); } // -- Suppression d'une page ------------------------------------------------- void Button_Kill(void) { if ( (Main_backups->List_size==1) || (!Confirmation_box("Delete the current page?")) ) { if (Main_backups->List_size==1) Warning_message("You can't delete the last page."); Hide_cursor(); Unselect_button(BUTTON_KILL); Display_cursor(); } else { Hide_cursor(); Free_current_page(); Set_palette(Main_palette); Compute_optimal_menu_colors(Main_palette); Display_all_screen(); Unselect_button(BUTTON_KILL); Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); Display_menu(); Display_cursor(); } } //------------------------- Dimensions Image/Screen --------------------------- void Check_mode_button(short x_pos, short y_pos, byte state) { byte color; switch (state & 0x7F) { case 0 : color=MC_White; break; case 1 : color=MC_Light; break; case 2 : color=MC_Dark; break; default: color=MC_Black; } Block(Window_pos_X+Menu_factor_X*x_pos,Window_pos_Y+Menu_factor_Y*y_pos, Menu_factor_X*9,Menu_factor_Y*3,color); Update_rect(Window_pos_X+Menu_factor_X*x_pos,Window_pos_Y+Menu_factor_Y*y_pos, Menu_factor_X*9,Menu_factor_Y*3); } /// Number of video modes to display in the resolution menu #define MODELIST_LINES 10 void Display_modes_list(short list_start, short cursor_position) { short index,current_mode; short y_pos; byte text_color,background_color; char str[29]; char *ratio; for (current_mode=list_start,index=0; indexPosition!=list_start) { Window_scroller_button_list->Position=list_start; Window_draw_slider(Window_scroller_button_list); } Display_modes_list(list_start,cursor_position); Display_cursor(); } void Button_Resolution(void) { short clicked_button; int selected_mode; word chosen_width; word chosen_height; byte chosen_pixel; short list_start; short cursor_position; short temp; char str[5]; T_Special_button * input_width_button, * input_button_height; T_Dropdown_button * pixel_button; 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"); Print_in_window( 12, 21,"Picture size:" ,MC_Dark,MC_Light); Window_display_frame ( 8,17,195, 33); Window_set_normal_button(223, 18,67,14,"OK" ,0,1,SDLK_RETURN); // 1 Window_set_normal_button(223, 35,67,14,"Cancel" ,0,1,KEY_ESC); // 2 Print_in_window( 12, 37,"Width:" ,MC_Dark,MC_Light); input_width_button=Window_set_input_button( 60, 35,4); // 3 Print_in_window(108, 37,"Height:" ,MC_Dark,MC_Light); input_button_height=Window_set_input_button(164, 35,4); // 4 Window_display_frame ( 8,72,283,110); Window_display_frame_in (37,84,228,84); Window_rectangle (38,85,226,82,MC_Black); Print_in_window( 16, 76,"OK" ,MC_Dark,MC_Light); Print_in_window( 55, 76,"X Y" ,MC_Dark,MC_Light); Print_in_window(120, 76,"Win / Full" ,MC_Dark,MC_Light); Print_in_window(219, 76,"Ratio" ,MC_Dark,MC_Light); Print_in_window( 30,170,"\03" ,MC_Dark,MC_Light); Print_in_window( 62,170,"OK" ,MC_Dark,MC_Light); Print_in_window(102,170,"Imperfect" ,MC_Dark,MC_Light); Print_in_window(196,170,"Unsupported" ,MC_Dark,MC_Light); Window_set_special_button(38,86,225,80); // 5 selected_mode=Current_resolution; if (selected_mode>=MODELIST_LINES/2 && Nb_video_modes > MODELIST_LINES) { if (selected_mode>3; if (temp0) cursor_position--; else if (list_start>0) list_start--; Scroll_list_of_modes(list_start,cursor_position,&selected_mode); Key=0; break; case SDLK_DOWN : // Bas if (cursor_position<(MODELIST_LINES-1) && cursor_position<(Nb_video_modes-1)) cursor_position++; else if (list_start0) cursor_position=0; else { if (list_start>(MODELIST_LINES-1)) list_start-=(MODELIST_LINES-1); else list_start=0; } Scroll_list_of_modes(list_start,cursor_position,&selected_mode); Key=0; break; case SDLK_PAGEDOWN : // PageDown if (Nb_video_modesOPERATION_FILLED_CONTOUR) Selected_freehand_mode=OPERATION_CONTINUOUS_DRAW; Hide_cursor(); switch(Selected_freehand_mode) { default: case OPERATION_CONTINUOUS_DRAW: icon=-1; break; case OPERATION_DISCONTINUOUS_DRAW: icon=MENU_SPRITE_DISCONTINUOUS_DRAW; break; case OPERATION_POINT_DRAW: icon=MENU_SPRITE_POINT_DRAW; break; case OPERATION_FILLED_CONTOUR: icon=MENU_SPRITE_CONTOUR_DRAW; break; } Display_sprite_in_menu(BUTTON_DRAW,icon); Draw_menu_button(BUTTON_DRAW,BUTTON_PRESSED); Start_operation_stack(Selected_freehand_mode); Display_cursor(); /* NOUVEAU CODE AVEC POPUP (EN COURS DE TEST) *** short clicked_button; Open_popup(16,Menu_Y/Menu_factor_X-32,18,50); Window_set_normal_button(1,1,16,16,"A",0,1,KEY_ESC); // 1 Display_cursor(); Update_rect(16*Menu_factor_X,Menu_Y-32*Menu_factor_X,18*Menu_factor_X,50*Menu_factor_X); do { while(!Get_input())Wait_VBL(); clicked_button = Window_get_clicked_button(); switch(clicked_button) { case 1: Selected_freehand_mode++; if (Selected_freehand_mode>OPERATION_FILLED_CONTOUR) Selected_freehand_mode=OPERATION_CONTINUOUS_DRAW; break; } } while (Mouse_K); Close_popup(); //Display_sprite_in_menu(BUTTON_DRAW,Selected_freehand_mode+2); Start_operation_stack(Selected_freehand_mode); Display_cursor(); */ } // -- Gestion des boutons de rectangle vide et plein ------------------------ void Button_Empty_rectangle(void) { Hide_cursor(); Start_operation_stack(OPERATION_EMPTY_RECTANGLE); Display_cursor(); } void Button_Filled_rectangle(void) { Hide_cursor(); Start_operation_stack(OPERATION_FILLED_RECTANGLE); Display_cursor(); } // -- Gestion des boutons de cercle (ellipse) vide et plein(e) -------------- void Button_Empty_circle(void) { Hide_cursor(); Start_operation_stack(OPERATION_EMPTY_CIRCLE); Display_cursor(); } void Button_Empty_ellipse(void) { Hide_cursor(); Start_operation_stack(OPERATION_EMPTY_ELLIPSE); Display_cursor(); } void Button_Filled_circle(void) { Hide_cursor(); Start_operation_stack(OPERATION_FILLED_CIRCLE); Display_cursor(); } void Button_Filled_ellipse(void) { Hide_cursor(); Start_operation_stack(OPERATION_FILLED_ELLIPSE); Display_cursor(); } // -- Gestion du menu des dgrads ------------------------------------------ void Draw_button_gradient_style(short x_pos,short y_pos,int technique) { short line; // On commence par afficher les 2 cts qui constituent le dgrad de base: // Ct gauche (noir) Block(Window_pos_X+((x_pos+2)*Menu_factor_X), Window_pos_Y+((y_pos+2)*Menu_factor_Y), Menu_factor_X*6, Menu_factor_Y*10,MC_Black); // Ct droit (blanc) Block(Window_pos_X+((x_pos+8)*Menu_factor_X), Window_pos_Y+((y_pos+2)*Menu_factor_Y), Menu_factor_X*5, Menu_factor_Y*10,MC_White); switch(technique) { case 1 : // Dgrad de trames simples // Au centre, on place 10 lignes trames simplement for (line=2;line<2+10;line++) if (line&1) { // Lignes impaires Pixel_in_window(x_pos+ 5,y_pos+line,MC_White); Pixel_in_window(x_pos+ 7,y_pos+line,MC_White); Pixel_in_window(x_pos+ 8,y_pos+line,MC_Black); } else { // Lignes paires Pixel_in_window(x_pos+ 6,y_pos+line,MC_White); Pixel_in_window(x_pos+ 9,y_pos+line,MC_Black); } break; case 2 : // Dgrad de trames tendues // Au centre, on place 10 lignes trames de faon complique for (line=2;line<2+10;line++) if (line&1) { // Lignes impaires Pixel_in_window(x_pos+ 7,y_pos+line,MC_White); Pixel_in_window(x_pos+ 8,y_pos+line,MC_Black); Pixel_in_window(x_pos+10,y_pos+line,MC_Black); } else { // Lignes paires Pixel_in_window(x_pos+ 4,y_pos+line,MC_White); Pixel_in_window(x_pos+ 6,y_pos+line,MC_White); } } Update_rect(Window_pos_X+((x_pos+2)*Menu_factor_X),Window_pos_Y+((y_pos+2)*Menu_factor_Y), Menu_factor_X*10,Menu_factor_Y*10); } void Load_gradient_data(int index) { if (Main_backups->Pages->Gradients->Range[index].Start>Main_backups->Pages->Gradients->Range[index].End) Error(0); Gradient_lower_bound =Main_backups->Pages->Gradients->Range[index].Start; Gradient_upper_bound =Main_backups->Pages->Gradients->Range[index].End; Gradient_is_inverted =Main_backups->Pages->Gradients->Range[index].Inverse; Gradient_random_factor=Main_backups->Pages->Gradients->Range[index].Mix+1; Gradient_bounds_range=(Gradient_lower_boundPages->Gradients->Range[index].Technique) { case 0 : // Degrad de base Gradient_function=Gradient_basic; break; case 1 : // Dgrad de trames simples Gradient_function=Gradient_dithered; break; case 2 : // Dgrad de trames tendues Gradient_function=Gradient_extra_dithered; } } void Draw_gradient_preview(short start_x,short start_y,short width,short height,int index) { short x_pos; // Variables de balayage du block en bas de l'cran. short y_pos; short end_x; short end_y; Load_gradient_data(index); start_x=Window_pos_X+(start_x*Menu_factor_X); start_y=Window_pos_Y+(start_y*Menu_factor_Y); Gradient_total_range=width*Menu_factor_X; end_x=start_x+Gradient_total_range; end_y=start_y+(height*Menu_factor_Y); for (y_pos=start_y;y_posPages->Gradients,sizeof(T_Gradient_array)); Open_window(235,146,"Gradation menu"); Window_set_palette_button(48,19); // 1 // Slider for gradient selection gradient_scroller=Window_set_scroller_button(218,20,75,16,1,Current_gradient); // 2 // Slider for mix mix_scroller = Window_set_scroller_button(31,20,84,256,1, Main_backups->Pages->Gradients->Range[Current_gradient].Mix); // 3 // Direction Window_set_normal_button(8,20,15,14, (Main_backups->Pages->Gradients->Range[Current_gradient].Inverse)?"\033":"\032",0,1,SDLK_TAB); // 4 // Technique Window_set_normal_button(8,90,15,14,"",0,1,SDLK_TAB|MOD_SHIFT); // 5 Draw_button_gradient_style(8,90,Main_backups->Pages->Gradients->Range[Current_gradient].Technique); Window_set_normal_button(178,128,51,14,"OK",0,1,SDLK_RETURN); // 6 Window_set_normal_button(123,128,51,14,"Cancel",0,1,KEY_ESC); // 7 // Scrolling speed speed_scroller = Window_set_horizontal_scroller_button(99,111,130,106,1,Main_backups->Pages->Gradients->Range[Current_gradient].Speed); // 8 Num2str(Main_backups->Pages->Gradients->Range[Current_gradient].Speed,str,3); Print_in_window(73,113,str,MC_Black,MC_Light); Print_in_window(5,58,"MIX",MC_Dark,MC_Light); // Cycling mode on/off Window_set_normal_button(8,109,62,14,"",0,1,KEY_NONE); // 9 Print_in_window(11,112,"Cycling",cycling_mode?MC_Black:MC_Dark,MC_Light); // On tagge les couleurs qui vont avec Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); Num2str(Current_gradient+1,str,2); Print_in_window(215,100,str,MC_Black,MC_Light); // On affiche le cadre autour de la prview Window_display_frame_in(7,127,110,16); // On affiche la preview Draw_gradient_preview(8,128,108,14,Current_gradient); first_color=last_color=(Main_backups->Pages->Gradients->Range[Current_gradient].Inverse)?Main_backups->Pages->Gradients->Range[Current_gradient].End:Main_backups->Pages->Gradients->Range[Current_gradient].Start; Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { old_mouse_x=Mouse_X; old_mouse_y=Mouse_Y; old_mouse_k=Mouse_K; if (changed_gradient_index) { // User has changed which gradient (0-15) he's watching changed_gradient_index=0; Hide_cursor(); // On affiche la valeur sous la jauge Num2str(Current_gradient+1,str,2); Print_in_window(215,100,str,MC_Black,MC_Light); // On tagge les couleurs qui vont avec Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); // On affiche le sens qui va avec Print_in_window(12,23,(Main_backups->Pages->Gradients->Range[Current_gradient].Inverse)?"\033":"\032",MC_Black,MC_Light); // On raffiche le mlange (jauge) qui va avec mix_scroller->Position=Main_backups->Pages->Gradients->Range[Current_gradient].Mix; Window_draw_slider(mix_scroller); // Update speed speed_scroller->Position=Main_backups->Pages->Gradients->Range[Current_gradient].Speed; Window_draw_slider(speed_scroller); Num2str(Main_backups->Pages->Gradients->Range[Current_gradient].Speed,str,3); Print_in_window(73,113,str,MC_Black,MC_Light); // Gradient # gradient_scroller->Position=Current_gradient; Window_draw_slider(gradient_scroller); // Technique (flat, dithered, very dithered) Draw_button_gradient_style(8,90,Main_backups->Pages->Gradients->Range[Current_gradient].Technique); // Rectangular gradient preview Draw_gradient_preview(8,128,108,14,Current_gradient); Display_cursor(); } clicked_button=Window_clicked_button(); if (Input_sticky_control!=8 || !Mouse_K) { Allow_colorcycling=0; // Restore palette Set_palette(Main_palette); } switch(clicked_button) { case -1 : case 1 : // Palette if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) ) { Hide_cursor(); temp_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); if (!old_mouse_k) { // On vient de clicker // On met jour l'intervalle du dgrad first_color=last_color=Main_backups->Pages->Gradients->Range[Current_gradient].Start=Main_backups->Pages->Gradients->Range[Current_gradient].End=temp_color; // On tagge le bloc Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); // Trac de la preview: Draw_gradient_preview(8,128,108,14,Current_gradient); } else { // On maintient le click, on va donc tester si le curseur bouge if (temp_color!=last_color) { // On commence par ordonner la 1re et dernire couleur du bloc if (first_colorPages->Gradients->Range[Current_gradient].Start=first_color; Main_backups->Pages->Gradients->Range[Current_gradient].End =temp_color; } else if (first_color>temp_color) { Main_backups->Pages->Gradients->Range[Current_gradient].Start=temp_color; Main_backups->Pages->Gradients->Range[Current_gradient].End =first_color; } else Main_backups->Pages->Gradients->Range[Current_gradient].Start=Main_backups->Pages->Gradients->Range[Current_gradient].End=first_color; // On tagge le bloc Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); // Trac de la preview: Draw_gradient_preview(8,128,108,14,Current_gradient); last_color=temp_color; } } Display_cursor(); } break; case 2 : // Nouvel indice de dgrad // Nouvel indice dans Window_attribute2 Current_gradient=Window_attribute2; changed_gradient_index=1; break; case 3 : // Nouveau mlange de dgrad Hide_cursor(); // Nouvel mlange dans Window_attribute2 Main_backups->Pages->Gradients->Range[Current_gradient].Mix=Window_attribute2; // On affiche la nouvelle preview Draw_gradient_preview(8,128,108,14,Current_gradient); Display_cursor(); break; case 4 : // Changement de sens Hide_cursor(); // On inverse le sens (par un XOR de 1) Main_backups->Pages->Gradients->Range[Current_gradient].Inverse^=1; Print_in_window(12,23,(Main_backups->Pages->Gradients->Range[Current_gradient].Inverse)?"\033":"\032",MC_Black,MC_Light); // On affiche la nouvelle preview Draw_gradient_preview(8,128,108,14,Current_gradient); Display_cursor(); break; case 5 : // Changement de technique Hide_cursor(); // On change la technique par (+1)%3 Main_backups->Pages->Gradients->Range[Current_gradient].Technique=(Main_backups->Pages->Gradients->Range[Current_gradient].Technique+1)%3; Draw_button_gradient_style(8,90,Main_backups->Pages->Gradients->Range[Current_gradient].Technique); // On affiche la nouvelle preview Draw_gradient_preview(8,128,108,14,Current_gradient); Display_cursor(); case 8 : // Speed Main_backups->Pages->Gradients->Range[Current_gradient].Speed=Window_attribute2; Num2str(Main_backups->Pages->Gradients->Range[Current_gradient].Speed,str,3); Hide_cursor(); Print_in_window(73,113,str,MC_Black,MC_Light); Display_cursor(); Allow_colorcycling=1; break; case 9: // Cycling on/off cycling_mode = !cycling_mode; Hide_cursor(); Print_in_window(11,112,"Cycling",cycling_mode?MC_Black:MC_Dark,MC_Light); Display_cursor(); break; } if (!Mouse_K) switch (Key) { case SDLK_BACKQUOTE : // Rcupration d'une couleur derrire le menu case SDLK_COMMA : Get_color_behind_window(&color,&click); if (click) { Hide_cursor(); temp_color=color; // On met jour l'intervalle du dgrad first_color=last_color=Main_backups->Pages->Gradients->Range[Current_gradient].Start=Main_backups->Pages->Gradients->Range[Current_gradient].End=temp_color; // On tagge le bloc Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); // Trac de la preview: Draw_gradient_preview(8,128,108,14,Current_gradient); Display_cursor(); Wait_end_of_click(); } Key=0; break; case KEY_MOUSEWHEELUP: if (Current_gradient>0) { Current_gradient--; changed_gradient_index=1; } break; case KEY_MOUSEWHEELDOWN: if (Current_gradient<15) { Current_gradient++; changed_gradient_index=1; } break; default: if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Window_help(BUTTON_GRADRECT, NULL); Key=0; break; } else if (Is_shortcut(Key,0x200+BUTTON_GRADRECT)) clicked_button=6; else if (Is_shortcut(Key,SPECIAL_CYCLE_MODE)) { // Cycling on/off cycling_mode = !cycling_mode; Hide_cursor(); Print_in_window(11,112,"Cycling",cycling_mode?MC_Black:MC_Dark,MC_Light); Display_cursor(); } } } while (clicked_button!=6 && clicked_button!=7); Close_window(); // The Grad rect operation uses the same button as Grad menu. if (Current_operation != OPERATION_GRAD_RECTANGLE) Unselect_button(BUTTON_GRADRECT); Display_cursor(); Gradient_pixel=Display_pixel; Cycling_mode=cycling_mode; if (clicked_button==7) // Cancel { Current_gradient=old_current_gradient; memcpy(Main_backups->Pages->Gradients,&backup_gradients,sizeof(T_Gradient_array)); } } // -- Gestion des boutons de cercle / ellipse / rectangle dgrads -------------------- void Button_Grad_circle(void) { Hide_cursor(); Start_operation_stack(OPERATION_GRAD_CIRCLE); Display_cursor(); } void Button_Grad_ellipse(void) { Hide_cursor(); Start_operation_stack(OPERATION_GRAD_ELLIPSE); Display_cursor(); } void Button_Grad_rectangle(void) { Hide_cursor(); Start_operation_stack(OPERATION_GRAD_RECTANGLE); Display_cursor(); } // -- Gestion du bouton de remplissage --------------------------------------- void Button_Fill(void) { if (Current_operation!=OPERATION_FILL) { Hide_cursor(); if (Current_operation!=OPERATION_REPLACE) { Paintbrush_shape_before_fill=Paintbrush_shape; Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; } else if ( (Mouse_Y=Main_X_zoom) ) ) Print_in_menu("X: Y: ",0); Start_operation_stack(OPERATION_FILL); Display_cursor(); } } void Button_Replace(void) { if (Current_operation!=OPERATION_REPLACE) { Hide_cursor(); if (Current_operation!=OPERATION_FILL) { Paintbrush_shape_before_fill=Paintbrush_shape; Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; } if ( (Mouse_Y=Main_X_zoom) ) ) Print_in_menu("X: Y: ( )",0); Start_operation_stack(OPERATION_REPLACE); Display_cursor(); } } void Button_Unselect_fill(void) { Paintbrush_shape=Paintbrush_shape_before_fill; if (Current_operation==OPERATION_REPLACE) if ( (Mouse_Y=Main_X_zoom) ) ) Print_in_menu("X: Y: ",0); } //---------------------------- Menu des pinceaux ----------------------------- /// Checks if the current brush is identical to a preset one. byte Same_paintbrush(byte index) { if (Paintbrush_shape!=Paintbrush[index].Shape || Paintbrush_width!=Paintbrush[index].Width || Paintbrush_height!=Paintbrush[index].Height) return 0; if (Paintbrush_shape==PAINTBRUSH_SHAPE_MISC) { // Check all pixels int x,y; for(y=0;y=(NB_PAINTBRUSH_SPRITES+3)) { index = clicked_button-NB_PAINTBRUSH_SPRITES-3; if (Window_attribute2==1) // Set { // Store x_pos=13+((index+NB_PAINTBRUSH_SPRITES)%12)*24; y_pos=27+((index+NB_PAINTBRUSH_SPRITES)/12)*25; Store_brush(index); Hide_cursor(); Display_stored_brush_in_window(x_pos+2, y_pos+2, index); Display_cursor(); } else { // Restore and exit if (Restore_brush(index)) { Close_window(); break; } } } else if (clicked_button>=3) // Standard paintbrushes { if (Window_attribute2!=1) { // Select paintbrush Close_window(); Select_paintbrush(clicked_button-3); break; } else if (Window_attribute2==1) { // Store current index=clicked_button-3; if (!Store_paintbrush(index)) { // Redraw Hide_cursor(); x_pos=13+(index%12)*24; y_pos=27+(index/12)*25; Window_rectangle(x_pos,y_pos,20,20,MC_White); Display_paintbrush_in_window(x_pos+2,y_pos+2,index); Display_cursor(); } } } else if (clicked_button==1 || Is_shortcut(Key,0x100+BUTTON_PAINTBRUSHES)) { Close_window(); break; } else if (clicked_button==2) { int size; // Pick a standard shape Paintbrush_shape=Window_attribute2; // Assign a reasonable size size=Max(Paintbrush_width,Paintbrush_height); if (size==1) size=3; switch (Paintbrush_shape) { case PAINTBRUSH_SHAPE_HORIZONTAL_BAR: Set_paintbrush_size(size, 1); break; case PAINTBRUSH_SHAPE_VERTICAL_BAR: Set_paintbrush_size(1, size); break; case PAINTBRUSH_SHAPE_CROSS: case PAINTBRUSH_SHAPE_PLUS: case PAINTBRUSH_SHAPE_DIAMOND: Set_paintbrush_size(size|1,size|1); break; default: Set_paintbrush_size(size,size); break; } Close_window(); Change_paintbrush_shape(Paintbrush_shape); break; } } while (1); Unselect_button(BUTTON_PAINTBRUSHES); Display_cursor(); } void Button_Brush_monochrome(void) { Hide_cursor(); // On passe en brosse monochrome: Change_paintbrush_shape(PAINTBRUSH_SHAPE_MONO_BRUSH); Unselect_button(BUTTON_PAINTBRUSHES); Display_cursor(); } // -- Fonction renvoyant le mode vido le plus adapt l'image charge ----- #define TOLERANCE_X 8 #define TOLERANCE_Y 4 int Best_video_mode(void) { short best_width,best_height; int best_mode; short temp_x,temp_y; int mode; // Si mode fentre, on reste dans ce mode. if (Current_resolution == 0) return 0; // On commence par borner les dimensions, ou du moins les rendre cohrentes if ((Original_screen_X<=0) || (Config.Set_resolution_according_to==2)) Original_screen_X=Main_image_width; else if (Original_screen_X<320) Original_screen_X=320; if ((Original_screen_Y<=0) || (Config.Set_resolution_according_to==2)) Original_screen_Y=Main_image_height; else if (Original_screen_Y<200) Original_screen_Y=200; if ((Original_screen_X>1024) || (Original_screen_Y>768)) { Original_screen_X=1024; Original_screen_Y=768; } // Maintenant on peut chercher le mode qui correspond le mieux best_mode=Current_resolution; best_width=0; best_height=0; for (mode=1; mode On charge/sauve une image // Image=0 => On charge/sauve une brosse { byte confirm; byte old_cursor_shape; int new_mode; T_IO_Context context; static char filename [MAX_PATH_CHARACTERS]; static char directory[MAX_PATH_CHARACTERS]; if (image) { strcpy(filename, Main_backups->Pages->Filename); strcpy(directory, Main_backups->Pages->File_directory); Init_context_layered_image(&context, filename, directory); } else { strcpy(filename, Brush_filename); strcpy(directory, Main_current_directory); Init_context_brush(&context, Brush_filename, Main_current_directory); } confirm=Button_Load_or_Save(1, &context); if (confirm) { if (image) { if (Main_image_is_modified) confirm=Confirmation_box("Discard unsaved changes?"); } } // confirm is modified inside the first if, that's why we check it // again here if (confirm) { old_cursor_shape=Cursor_shape; Hide_cursor(); Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); if (image) { Original_screen_X=0; Original_screen_Y=0; } Load_image(&context); if (!image) { if (File_error==3) // Memory allocation error when loading brush { // Nothing to do here. // Previous versions of Grafx2 would have damaged the Brush, // and need reset it here, but now the loading is done in separate // memory buffers. } Tiling_offset_X=0; Tiling_offset_Y=0; Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); Select_button(BUTTON_DRAW,LEFT_SIDE); if (Config.Auto_discontinuous) { // On se place en mode Dessin discontinu la main while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW) Select_button(BUTTON_DRAW,RIGHT_SIDE); } Hide_cursor(); // On passe en brosse couleur: Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); } else { Hide_cursor(); Cursor_shape=old_cursor_shape; } if ( (File_error==1) || (Get_fileformat(Main_fileformat)->Palette_only) ) { if (File_error!=1) Compute_optimal_menu_colors(Main_palette); } else { if (image) { if (Main_magnifier_mode) { Pixel_preview=Pixel_preview_normal; Main_magnifier_mode=0; Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); } new_mode=Best_video_mode(); if ((Config.Auto_set_res) && (new_mode!=Current_resolution)) { Init_mode_video( Video_mode[new_mode].Width, Video_mode[new_mode].Height, Video_mode[new_mode].Fullscreen, Pixel_ratio); Display_menu(); } // In window mode, activate wide or tall pixels if the image says so. else if (!Video_mode[Current_resolution].Fullscreen && ((context.Ratio == PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) || (context.Ratio == PIXEL_TALL && Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2))) { Init_mode_video( Video_mode[Current_resolution].Width, Video_mode[Current_resolution].Height, Video_mode[Current_resolution].Fullscreen, context.Ratio); Display_menu(); } else { Main_offset_X=0; Main_offset_Y=0; Compute_limits(); Compute_paintbrush_coordinates(); } } Compute_optimal_menu_colors(Main_palette); Redraw_layered_image(); End_of_modification(); Display_all_screen(); if (image) Main_image_is_modified=0; } Destroy_context(&context); Display_menu(); Display_cursor(); } //if (!image) // Swap_data_of_image_and_brush(); Hide_cursor(); Print_filename(); Display_cursor(); Set_palette(Main_palette); } void Button_Load(void) { // On sauve l'tat actuel des paramtres de l'image pour pouvoir les // restituer en cas d'erreur n'affectant pas l'image Upload_infos_page_main(Main_backups->Pages); Load_picture(1); } void Button_Reload(void) { byte old_cursor_shape; int new_mode; // On sauve l'tat actuel des paramtres de l'image pour pouvoir les // restituer en cas d'erreur n'affectant pas l'image Upload_infos_page_main(Main_backups->Pages); if ( (!Main_image_is_modified) || Confirmation_box("Discard unsaved changes ?") ) { T_IO_Context context; Hide_cursor(); old_cursor_shape=Cursor_shape; Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); Original_screen_X=0; Original_screen_Y=0; Init_context_layered_image(&context, Main_backups->Pages->Filename, Main_backups->Pages->File_directory); Load_image(&context); Hide_cursor(); Cursor_shape=old_cursor_shape; if (File_error!=1) { if (Main_magnifier_mode) { Pixel_preview=Pixel_preview_normal; Main_magnifier_mode=0; Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); } new_mode=Best_video_mode(); if ( ((Config.Auto_set_res) && (new_mode!=Current_resolution)) && (!Resolution_in_command_line) ) { Init_mode_video( Video_mode[new_mode].Width, Video_mode[new_mode].Height, Video_mode[new_mode].Fullscreen, Pixel_ratio); Display_menu(); } // In window mode, activate wide or tall pixels if the image says so. else if (!Video_mode[Current_resolution].Fullscreen && ((context.Ratio == PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) || (context.Ratio == PIXEL_TALL && Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2))) { Init_mode_video( Video_mode[Current_resolution].Width, Video_mode[Current_resolution].Height, Video_mode[Current_resolution].Fullscreen, context.Ratio); Display_menu(); } else { Main_offset_X=0; Main_offset_Y=0; Compute_limits(); Compute_paintbrush_coordinates(); } Redraw_layered_image(); End_of_modification(); Display_all_screen(); Main_image_is_modified=0; } Destroy_context(&context); } else Hide_cursor(); Compute_optimal_menu_colors(Main_palette); Display_menu(); if (Config.Display_image_limits) Display_image_limits(); Unselect_button(BUTTON_LOAD); Display_cursor(); } void Backup_filename(char * fname, char * backup_name) { short i; strcpy(backup_name,fname); for (i=strlen(fname)-strlen(Main_backups->Pages->Filename); backup_name[i]!='.'; i++); backup_name[i+1]='\0'; strcat(backup_name,"BAK"); } void Backup_existing_file(void) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier char new_filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier backup Get_full_filename(filename, Main_backups->Pages->Filename, Main_backups->Pages->File_directory); // Calcul du nom complet du fichier backup Backup_filename(filename,new_filename); File_error=0; // On fait un backup si le nom du fichier n'est pas celui qu'on a choisi // pour nommer les backups (c'est vident!). if (strcmp(new_filename,filename)) { // S'il y avait dj un fichier Backup, on l'efface if ((File_exists(new_filename)) && (remove(new_filename)!=0)) File_error=1; if ((!File_error) && (rename(filename,new_filename)!=0)) File_error=1; } } void Save_picture(byte image) // image=1 => On charge/sauve une image // image=0 => On charge/sauve une brosse { byte confirm; byte old_cursor_shape; T_IO_Context save_context; static char filename [MAX_PATH_CHARACTERS]; static char directory[MAX_PATH_CHARACTERS]; if (image) { strcpy(filename, Main_backups->Pages->Filename); strcpy(directory, Main_backups->Pages->File_directory); Init_context_layered_image(&save_context, filename, directory); save_context.Format = Main_fileformat; } else { strcpy(filename, Brush_filename); strcpy(directory, Brush_file_directory); Init_context_brush(&save_context, filename, directory); save_context.Format = Main_fileformat; } //if (!image) // Swap_data_of_image_and_brush(); confirm=Button_Load_or_Save(0, &save_context); if (confirm && File_exists(save_context.File_name)) { confirm=Confirmation_box("Erase old file ?"); if (confirm && (Config.Backup)) { Backup_existing_file(); if (File_error) { confirm=0; Error(0); } } } if (confirm) { old_cursor_shape=Cursor_shape; Hide_cursor(); Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); Save_image(&save_context); if (!File_error && image && !Get_fileformat(save_context.Format)->Palette_only) { Main_image_is_modified=0; strcpy(Main_backups->Pages->Filename, save_context.File_name); strcpy(Main_backups->Pages->File_directory, save_context.File_directory); } Hide_cursor(); Cursor_shape=old_cursor_shape; Display_cursor(); } Destroy_context(&save_context); Print_filename(); Set_palette(Main_palette); } void Button_Save(void) { Save_picture(1); } void Button_Autosave(void) { byte old_cursor_shape; static char filename[MAX_PATH_CHARACTERS]; byte file_already_exists; Get_full_filename(filename, Main_backups->Pages->Filename, Main_backups->Pages->File_directory); file_already_exists=File_exists(filename); if ( (!file_already_exists) || Confirmation_box("Erase old file ?") ) { if ((file_already_exists) && (Config.Backup)) Backup_existing_file(); else File_error=0; Hide_cursor(); if (!File_error) { T_IO_Context save_context; old_cursor_shape=Cursor_shape; Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); Init_context_layered_image(&save_context, Main_backups->Pages->Filename, Main_backups->Pages->File_directory); Save_image(&save_context); if (!File_error) { Main_image_is_modified=0; } Destroy_context(&save_context); Hide_cursor(); Cursor_shape=old_cursor_shape; } else Error(0); } else Hide_cursor(); Unselect_button(BUTTON_SAVE); Display_cursor(); } // -- Gestion des boutons de ligne ------------------------------------------ void Button_Lines(void) { Hide_cursor(); Start_operation_stack(Selected_line_mode); Display_cursor(); } void Button_Lines_switch_mode(void) { char icon; if (Selected_line_mode==OPERATION_LINE) Selected_line_mode=OPERATION_K_LINE; else { if (Selected_line_mode==OPERATION_K_LINE) Selected_line_mode=OPERATION_CENTERED_LINES; else Selected_line_mode=OPERATION_LINE; } switch(Selected_line_mode) { default: case OPERATION_LINE: icon=-1; break; case OPERATION_K_LINE: icon=MENU_SPRITE_K_LINE; break; case OPERATION_CENTERED_LINES: icon=MENU_SPRITE_CENTERED_LINES; break; } Hide_cursor(); Display_sprite_in_menu(BUTTON_LINES,icon); Draw_menu_button(BUTTON_LINES,BUTTON_PRESSED); Start_operation_stack(Selected_line_mode); Display_cursor(); } // -- Button de brosse ------------------------------------------------------ void Button_Brush(void) { Hide_cursor(); if (Current_operation!=OPERATION_GRAB_BRUSH) Start_operation_stack(OPERATION_GRAB_BRUSH); else Unselect_button(BUTTON_BRUSH); Display_cursor(); } void Button_Unselect_brush(void) { // On fait de notre mieux pour restaurer l'ancienne opration: Start_operation_stack(Operation_before_interrupt); } void Button_Restore_brush(void) { Hide_cursor(); // On passe en brosse couleur: Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); Unselect_button(BUTTON_BRUSH); Unselect_button(BUTTON_POLYBRUSH); Display_cursor(); } // -- Button de prise de brosse au lasso ------------------------------------ void Button_Lasso(void) { Hide_cursor(); if (Current_operation!=OPERATION_POLYBRUSH) { Paintbrush_shape_before_lasso=Paintbrush_shape; Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; Start_operation_stack(OPERATION_POLYBRUSH); } else Unselect_button(BUTTON_POLYBRUSH); Display_cursor(); } void Button_Unselect_lasso(void) { // On fait de notre mieux pour restaurer l'ancienne opration: Start_operation_stack(Operation_before_interrupt); Paintbrush_shape=Paintbrush_shape_before_lasso; } // -- Button de pipette ----------------------------------------------------- void Button_Colorpicker(void) { Hide_cursor(); if (Current_operation!=OPERATION_COLORPICK) { Colorpicker_color=-1; Start_operation_stack(OPERATION_COLORPICK); Paintbrush_shape_before_colorpicker=Paintbrush_shape; Paintbrush_shape=PAINTBRUSH_SHAPE_NONE; if (Operation_before_interrupt!=OPERATION_REPLACE) if ( (Mouse_Y=Main_X_zoom) ) ) Print_in_menu("X: Y: ( )",0); } else Unselect_button(BUTTON_COLORPICKER); Display_cursor(); } void Button_Unselect_colorpicker(void) { // Erase the color block which shows the picked color if (Operation_before_interrupt!=OPERATION_REPLACE) if ( (Mouse_Y=Main_X_zoom) ) ) Print_in_menu("X: Y: ",0); // On fait de notre mieux pour restaurer l'ancienne opration: if (Current_operation==OPERATION_COLORPICK) { Start_operation_stack(Operation_before_interrupt); Paintbrush_shape=Paintbrush_shape_before_colorpicker; } } // -- Inversion de la couleur Fore et de la couleur Back -- void Button_Invert_foreback(void) { byte temp_color; temp_color=Fore_color; Fore_color =Back_color; Back_color =temp_color; Hide_cursor(); Frame_menu_color(Back_color); Frame_menu_color(Fore_color); Reposition_palette(); Display_foreback(); Unselect_button(BUTTON_COLORPICKER); Display_cursor(); } // -- Gestion du bouton Loupe ----------------------------------------------- byte Coming_from_zoom_factor_menu=0; void Button_Magnify(void) { Hide_cursor(); if ( (Current_operation==OPERATION_MAGNIFY) || (Main_magnifier_mode) ) { Unselect_button(BUTTON_MAGNIFIER); } else { Compute_magnifier_data(); if ((!Config.Fast_zoom) || (Mouse_Y>=Menu_Y) || Coming_from_zoom_factor_menu) { Coming_from_zoom_factor_menu=0; Start_operation_stack(OPERATION_MAGNIFY); } else { /* Ceci est de la duplication de code de presque toute l'opration de */ /* la loupe... Il serait peut-tre plus propre de faire une procdure */ /* qui s'en charge... */ // On passe en mode loupe Main_magnifier_mode=1; // La fonction d'affichage dans la partie image est dsormais un affichage // spcial loupe. Pixel_preview=Pixel_preview_magnifier; // On calcule l'origine de la loupe Main_magnifier_offset_X=Mouse_X-(Main_magnifier_width>>1); Main_magnifier_offset_Y=Mouse_Y-(Main_magnifier_height>>1); // Calcul des coordonnes absolues de ce coin DANS L'IMAGE Main_magnifier_offset_X+=Main_offset_X; Main_magnifier_offset_Y+=Main_offset_Y; Clip_magnifier_offsets(&Main_magnifier_offset_X, &Main_magnifier_offset_Y); // On calcule les bornes visibles dans l'cran Position_screen_according_to_zoom(); Compute_limits(); Display_all_screen(); // Repositionner le curseur en fonction des coordonnes visibles Compute_paintbrush_coordinates(); } } Display_cursor(); Update_rect(0,0,0,0); } void Button_Magnify_menu(void) { T_Dropdown_button dropdown; T_Dropdown_choice *item; int i; const char text[NB_ZOOM_FACTORS][4] = {"x2", "x3", "x4", "x5", "x6", "x8", "x10", "x12", "x14", "x16", "x18", "x20", "x24", "x28", "x32"}; Hide_cursor(); dropdown.Pos_X =Buttons_Pool[BUTTON_MAGNIFIER].X_offset; dropdown.Pos_Y =Buttons_Pool[BUTTON_MAGNIFIER].Y_offset; dropdown.Height =Buttons_Pool[BUTTON_MAGNIFIER].Height; dropdown.Dropdown_width=28; dropdown.First_item =NULL; dropdown.Bottom_up =1; for(i = 0; i < NB_ZOOM_FACTORS; i++) { Window_dropdown_add_item(&dropdown, i, text[i]); } item=Dropdown_activate(&dropdown,0,Menu_Y); if (item) { Change_magnifier_factor(item->Number,0); } if ( (!item) && (!Main_magnifier_mode) && (Current_operation!=OPERATION_MAGNIFY) ) // Cancel Unselect_button(BUTTON_MAGNIFIER); Display_all_screen(); Display_cursor(); Update_rect(Main_separator_position,0,Screen_width-Main_separator_position,Menu_Y); if ( (item) && (!Main_magnifier_mode) && (Current_operation!=OPERATION_MAGNIFY) ) // Passage en mode zoom { Coming_from_zoom_factor_menu=1; Select_button(BUTTON_MAGNIFIER,LEFT_SIDE); } Window_dropdown_clear_items(&dropdown); } void Button_Unselect_magnifier(void) { if (Main_magnifier_mode) { // On sort du mode loupe Main_magnifier_mode=0; // --> Recalculer le dcalage de l'cran lorsqu'on sort de la loupe <-- // Centrage "brut" de lcran par rapport la loupe Main_offset_X=Main_magnifier_offset_X-((Screen_width-Main_magnifier_width)>>1); Main_offset_Y=Main_magnifier_offset_Y-((Menu_Y-Main_magnifier_height)>>1); // Correction en cas de dbordement de l'image if (Main_offset_X+Screen_width>Main_image_width) Main_offset_X=Main_image_width-Screen_width; if (Main_offset_X<0) Main_offset_X=0; if (Main_offset_Y+Menu_Y>Main_image_height) Main_offset_Y=Main_image_height-Menu_Y; if (Main_offset_Y<0) Main_offset_Y=0; // La fonction d'affichage dans l'image est dsormais un affichage normal. Pixel_preview=Pixel_preview_normal; // Calculer les bornes visibles dans l'cran Compute_limits(); Display_all_screen(); // <=> Display_screen(); // Repositionner le curseur en fonction des coordonnes visibles Compute_paintbrush_coordinates(); Old_MX = -1; Old_MY = -1; } else // On fait de notre mieux pour restaurer l'ancienne opration: Start_operation_stack(Operation_before_interrupt); } // ----------------------- Modifications de brosse --------------------------- void Button_Brush_FX(void) { short clicked_button; short index; Open_window(310,162,"Brush effects"); Window_display_frame( 6,19,298,61); Window_display_frame( 6,83,122,53); Window_display_frame(137,83,167,53); Window_set_normal_button(236,141, 67,14,"Cancel" ,0,1,KEY_ESC); // 1 Window_set_normal_button( 19, 46, 27,14,"X\035" ,0,1,Config_Key[SPECIAL_FLIP_X][0]); // 2 Window_set_normal_button( 19, 61, 27,14,"Y\022" ,0,1,Config_Key[SPECIAL_FLIP_Y][0]); // 3 Window_set_normal_button( 58, 46, 37,14,"90" ,0,1,Config_Key[SPECIAL_ROTATE_90][0]); // 4 Window_set_normal_button( 96, 46, 37,14,"180" ,0,1,Config_Key[SPECIAL_ROTATE_180][0]); // 5 Window_set_normal_button( 58, 61, 75,14,"any angle" ,0,1,Config_Key[SPECIAL_ROTATE_ANY_ANGLE][0]); // 6 Window_set_normal_button(145, 46, 67,14,"Stretch" ,0,1,Config_Key[SPECIAL_STRETCH][0]); // 7 Window_set_normal_button(145, 61, 67,14,"Distort" ,0,1,Config_Key[SPECIAL_DISTORT][0]); // 8 Window_set_normal_button(155, 99,131,14,"Recolorize" ,0,1,Config_Key[SPECIAL_RECOLORIZE_BRUSH][0]); // 9 Window_set_normal_button(155,117,131,14,"Get brush colors",0,1,Config_Key[SPECIAL_GET_BRUSH_COLORS][0]); // 10 // Boutons reprsentant les coins du brush handle: (HG,HD,C,BG,BD) Window_set_normal_button( 75, 90,11,11,"",0,1,Config_Key[SPECIAL_TOP_LEFT_ATTACHMENT][0]); // 11 Window_set_normal_button(103, 90,11,11,"",0,1,Config_Key[SPECIAL_TOP_RIGHT_ATTACHMENT][0]); // 12 Window_set_normal_button( 89,104,11,11,"",0,1,Config_Key[SPECIAL_CENTER_ATTACHMENT][0]); // 13 Window_set_normal_button( 75,118,11,11,"",0,1,Config_Key[SPECIAL_BOTTOM_LEFT_ATTACHMENT][0]); // 14 Window_set_normal_button(103,118,11,11,"",0,1,Config_Key[SPECIAL_BOTTOM_RIGHT_ATTACHMENT][0]); // 15 Window_set_normal_button(224,46,67,14,"Outline",0,1,Config_Key[SPECIAL_OUTLINE][0]); // 16 Window_set_normal_button(224,61,67,14,"Nibble" ,0,1,Config_Key[SPECIAL_NIBBLE][0]); // 17 Window_set_normal_button( 7,141, 60,14,"Load",0,1,Config_Key[SPECIAL_LOAD_BRUSH][0]); // 18 Window_set_normal_button( 70,141, 60,14,"Save",0,1,Config_Key[SPECIAL_SAVE_BRUSH][0]); // 19 Print_in_window( 80, 24,"Shape modifications",MC_Dark,MC_Light); Print_in_window( 10, 36,"Mirror",MC_Dark,MC_Light); Print_in_window( 72, 36,"Rotate",MC_Dark,MC_Light); Print_in_window(155, 36,"Deform",MC_Dark,MC_Light); Print_in_window(230, 36,"Borders",MC_Dark,MC_Light); Print_in_window(141, 88,"Colors modifications",MC_Dark,MC_Light); Print_in_window( 20,102,"Brush",MC_Dark,MC_Light); Print_in_window( 16,110,"handle",MC_Dark,MC_Light); // Dessin des pointills pour le "brush handle" for (index=0; index<13; index+=2) { Pixel_in_window( 88+index, 92,MC_Dark); Pixel_in_window( 88+index,126,MC_Dark); Pixel_in_window( 77,103+index,MC_Dark); Pixel_in_window(111,103+index,MC_Dark); } // Dessin des coins et du centre pour les boutons du "brush handle" // Coin HG Block(Window_pos_X+(Menu_factor_X* 77),Window_pos_Y+(Menu_factor_Y* 92),Menu_factor_X*7,Menu_factor_Y,MC_Black); Block(Window_pos_X+(Menu_factor_X* 77),Window_pos_Y+(Menu_factor_Y* 92),Menu_factor_X,Menu_factor_Y*7,MC_Black); // Coin HD Block(Window_pos_X+(Menu_factor_X*105),Window_pos_Y+(Menu_factor_Y* 92),Menu_factor_X*7,Menu_factor_Y,MC_Black); Block(Window_pos_X+(Menu_factor_X*111),Window_pos_Y+(Menu_factor_Y* 92),Menu_factor_X,Menu_factor_Y*7,MC_Black); // Centre Block(Window_pos_X+(Menu_factor_X* 91),Window_pos_Y+(Menu_factor_Y*109),Menu_factor_X*7,Menu_factor_Y,MC_Black); Block(Window_pos_X+(Menu_factor_X* 94),Window_pos_Y+(Menu_factor_Y*106),Menu_factor_X,Menu_factor_Y*7,MC_Black); // Coin BG Block(Window_pos_X+(Menu_factor_X* 77),Window_pos_Y+(Menu_factor_Y*126),Menu_factor_X*7,Menu_factor_Y,MC_Black); Block(Window_pos_X+(Menu_factor_X* 77),Window_pos_Y+(Menu_factor_Y*120),Menu_factor_X,Menu_factor_Y*7,MC_Black); // Coin BD Block(Window_pos_X+(Menu_factor_X*105),Window_pos_Y+(Menu_factor_Y*126),Menu_factor_X*7,Menu_factor_Y,MC_Black); Block(Window_pos_X+(Menu_factor_X*111),Window_pos_Y+(Menu_factor_Y*120),Menu_factor_X,Menu_factor_Y*7,MC_Black); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Key=0; Window_help(BUTTON_BRUSH_EFFECTS, NULL); } else if (Is_shortcut(Key,0x100+BUTTON_BRUSH_EFFECTS)) { clicked_button=1; } } while (clicked_button<=0); Close_window(); Unselect_button(BUTTON_BRUSH_EFFECTS); // Gestion du bouton click switch (clicked_button) { case 2 : // Flip X Flip_X_lowlevel(Brush_original_pixels, Brush_width, Brush_height); // Remap according to the last used remap table Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); break; case 3 : // Flip Y Flip_Y_lowlevel(Brush_original_pixels, Brush_width, Brush_height); // Remap according to the last used remap table Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); break; case 4 : // 90 Rotation Rotate_90_deg(); break; case 5 : // 180 Rotation Rotate_180_deg_lowlevel(Brush, Brush_width, Brush_height); Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); break; case 6 : // Any angle rotation Start_operation_stack(OPERATION_ROTATE_BRUSH); break; case 7 : // Stretch Start_operation_stack(OPERATION_STRETCH_BRUSH); break; case 8 : // Distort Start_operation_stack(OPERATION_DISTORT_BRUSH); break; case 9 : // Recolorize Remap_brush(); break; case 10 : // Get brush colors Display_cursor(); Get_colors_from_brush(); Hide_cursor(); break; case 11 : // Brush Attachment: Top-Left Brush_offset_X=0; Brush_offset_Y=0; break; case 12 : // Brush Attachment: Top-Right Brush_offset_X=(Brush_width-1); Brush_offset_Y=0; break; case 13 : // Brush Attachment: Center Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); break; case 14 : // Brush Attachment: Bottom-Left Brush_offset_X=0; Brush_offset_Y=(Brush_height-1); break; case 15 : // Brush Attachment: Bottom-Right Brush_offset_X=(Brush_width-1); Brush_offset_Y=(Brush_height-1); break; case 16 : // Outline Outline_brush(); break; case 17 : // Nibble Nibble_brush(); break; case 18 : // Load Display_cursor(); Load_picture(0); Hide_cursor(); break; case 19 : // Save Display_cursor(); Save_picture(0); Hide_cursor(); break; } Display_cursor(); } //---------------------------- Courbes de Bzier ---------------------------- void Button_Curves(void) { Hide_cursor(); Start_operation_stack(Selected_curve_mode); Display_cursor(); } void Button_Curves_switch_mode(void) { if (Selected_curve_mode==OPERATION_4_POINTS_CURVE) Selected_curve_mode=OPERATION_3_POINTS_CURVE; else Selected_curve_mode=OPERATION_4_POINTS_CURVE; Hide_cursor(); Display_sprite_in_menu(BUTTON_CURVES,Selected_curve_mode==OPERATION_4_POINTS_CURVE?MENU_SPRITE_4_POINTS_CURVE:-1); Draw_menu_button(BUTTON_CURVES,BUTTON_PRESSED); Start_operation_stack(Selected_curve_mode); Display_cursor(); } //--------------------------------- Spray ----------------------------------- void Button_Airbrush(void) { Hide_cursor(); Start_operation_stack(OPERATION_AIRBRUSH); Display_cursor(); } void Refresh_airbrush_settings(byte selected_color, byte update_slider) { char str[3]; if (update_slider) { Window_scroller_button_list->Position=49-Airbrush_multi_flow[selected_color]; Window_draw_slider(Window_scroller_button_list); } Num2str(Airbrush_multi_flow[selected_color],str,2); Print_in_window(196,130,str,MC_Black,MC_Light); Update_rect(Window_pos_X+(Menu_factor_X*(Window_palette_button_list->Pos_X+4+(selected_color >> 4)*10)), Window_pos_Y+(Menu_factor_Y*(Window_palette_button_list->Pos_Y+3+(selected_color & 15)* 5)), Menu_factor_X<<1,Menu_factor_Y*5); } void Button_Airbrush_menu(void) { static byte spray_init=1; short clicked_button; char str[4]; word index; byte selected_color=Fore_color; byte old_airbrush_mode =Airbrush_mode; short old_airbrush_size =Airbrush_size; byte old_airbrush_delay =Airbrush_delay; byte old_airbrush_mono_flow=Airbrush_mono_flow; byte old_airbrush_multi_flow[256]; T_Special_button * input_size_button; T_Special_button * input_delay_button; T_Special_button * input_flow_button; T_Special_button * input_init_button; word old_mouse_x; word old_mouse_y; byte old_mouse_k; byte color; byte click; memcpy(old_airbrush_multi_flow,Airbrush_multi_flow,256); Open_window(226,170,"Spray"); Window_set_normal_button(110,148,51,14,"Cancel" ,0,1,KEY_ESC); // 1 Window_set_normal_button(166,148,51,14,"OK" ,0,1,SDLK_RETURN); // 2 Window_set_scroller_button(178,62,74,50,1,49-Airbrush_multi_flow[selected_color]); // 3 Window_set_palette_button(7,56); // 4 Window_set_normal_button( 8,148,83,14,"Mode: ",0,1,SDLK_TAB); // 5 if (Airbrush_mode) Print_in_window(50,151," Mono",MC_Black,MC_Light); else Print_in_window(50,151,"Multi",MC_Black,MC_Light); Window_set_normal_button(194, 62,19,14,"+1" ,0,1,SDLK_KP_PLUS); // 6 Window_set_normal_button(194, 79,19,14,"-1" ,0,1,SDLK_KP_MINUS); // 7 Window_set_normal_button(194, 96,19,14,"x2" ,0,1,SDLK_KP_MULTIPLY); // 8 Window_set_normal_button(194,113,19,14,"2" ,0,1,SDLK_KP_ENTER); // 9 Window_set_normal_button( 8, 37,43,14,"Clear" ,1,1,SDLK_c); // 10 Print_in_window(142,25,"Size:" ,MC_Dark,MC_Light); input_size_button = Window_set_input_button(186,23,3); // 11 Num2str(Airbrush_size,str,3); Window_input_content(input_size_button,str); Print_in_window(142,39,"Delay:" ,MC_Dark,MC_Light); input_delay_button = Window_set_input_button(194,37,2); // 12 Num2str(Airbrush_delay,str,2); Window_input_content(input_delay_button,str); Print_in_window( 27,24,"Mono-Flow:",MC_Dark,MC_Light); input_flow_button = Window_set_input_button(111,22,2); // 13 Num2str(Airbrush_mono_flow,str,2); Window_input_content(input_flow_button,str); Print_in_window( 67,40,"Init:",MC_Dark,MC_Light); input_init_button = Window_set_input_button(111,38,2); // 14 Num2str(spray_init,str,2); Window_input_content(input_init_button,str); Window_display_frame(173,56,45,86); Window_display_frame(137,19,81,33); // On tagge toutes les couleurs utilises for (index=0; index<256; index++) if (Airbrush_multi_flow[index]) Stencil_tag_color(index,MC_Black); // Et enfin, on tagge la couleur slectionne Stencil_tag_color(selected_color,MC_White); Refresh_airbrush_settings(selected_color,0); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); Stencil_update_color(selected_color); do { old_mouse_x=Mouse_X; old_mouse_y=Mouse_Y; old_mouse_k=Mouse_K; clicked_button=Window_clicked_button(); switch (clicked_button) { case 0 : case 2 : // OK break; case 1 : // Cancel Airbrush_mode =old_airbrush_mode; Airbrush_size =old_airbrush_size; Airbrush_delay =old_airbrush_delay; Airbrush_mono_flow=old_airbrush_mono_flow; memcpy(Airbrush_multi_flow,old_airbrush_multi_flow,256); break; case 3 : // Scroller Hide_cursor(); Airbrush_multi_flow[selected_color]=49-Window_attribute2; Refresh_airbrush_settings(selected_color,0); Display_cursor(); break; case -1 : case 4 : // Palette if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) ) { Hide_cursor(); Stencil_tag_color(selected_color,(Airbrush_multi_flow[selected_color])?MC_Black:MC_Light); Stencil_update_color(selected_color); // Mettre la couleur slectionne jour suivant le click selected_color=(clicked_button==4) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); if (Mouse_K==2) Airbrush_multi_flow[selected_color]=0; else if (Airbrush_multi_flow[selected_color]==0) Airbrush_multi_flow[selected_color]=spray_init; // Tagger la couleur slectionne en blanc Stencil_tag_color(selected_color,MC_White); Refresh_airbrush_settings(selected_color,1); Display_cursor(); Stencil_update_color(selected_color); } break; case 5 : // Toggle Mode Airbrush_mode=(Airbrush_mode+1)&1; Hide_cursor(); if (Airbrush_mode) Print_in_window(50,151," Mono",MC_Black,MC_Light); else Print_in_window(50,151,"Multi",MC_Black,MC_Light); Update_rect(Window_pos_X+50*Menu_factor_X,Window_pos_Y+151*Menu_factor_Y,5*8*Menu_factor_X,8*Menu_factor_Y); Display_cursor(); break; case 6 : // +1 for (index=0; index<256; index++) { if ( (Airbrush_multi_flow[index]) && (Airbrush_multi_flow[index]<49) ) Airbrush_multi_flow[index]++; } Hide_cursor(); Refresh_airbrush_settings(selected_color,1); Display_cursor(); break; case 7 : // -1 for (index=0; index<256; index++) { if (Airbrush_multi_flow[index]>1) Airbrush_multi_flow[index]--; } Hide_cursor(); Refresh_airbrush_settings(selected_color,1); Display_cursor(); break; case 8 : // x2 for (index=0; index<256; index++) { if (Airbrush_multi_flow[index]) { Airbrush_multi_flow[index]<<=1; if (Airbrush_multi_flow[index]>49) Airbrush_multi_flow[index]=49; } } Hide_cursor(); Refresh_airbrush_settings(selected_color,1); Display_cursor(); break; case 9 : // 2 for (index=0; index<256; index++) { if (Airbrush_multi_flow[index]>1) Airbrush_multi_flow[index]>>=1; } Hide_cursor(); Refresh_airbrush_settings(selected_color,1); Display_cursor(); break; case 10 : // Clear memset(Airbrush_multi_flow,0,256); // On raffiche les infos de la couleur slectionne Refresh_airbrush_settings(selected_color,1); // On efface les anciens TAGs Window_clear_tags(); // Tagger la couleur slectionne en blanc Stencil_tag_color(selected_color,MC_White); Stencil_update_color(selected_color); break; case 11 : // Size Num2str(Airbrush_size,str,3); Readline(188,25,str,3,INPUT_TYPE_INTEGER); Airbrush_size=atoi(str); // On corrige les dimensions if (Airbrush_size>256) { Airbrush_size=256; Num2str(Airbrush_size,str,3); Window_input_content(input_size_button,str); } else if (!Airbrush_size) { Airbrush_size=1; Num2str(Airbrush_size,str,3); Window_input_content(input_size_button,str); } Display_cursor(); break; case 12 : // Delay Num2str(Airbrush_delay,str,2); Readline(196,39,str,2,INPUT_TYPE_INTEGER); Airbrush_delay=atoi(str); // On corrige le delai if (Airbrush_delay>99) { Airbrush_delay=99; Num2str(Airbrush_delay,str,2); Window_input_content(input_delay_button,str); } Display_cursor(); break; case 13 : // Mono-Flow Num2str(Airbrush_mono_flow,str,2); Readline(113,24,str,2,INPUT_TYPE_INTEGER); Airbrush_mono_flow=atoi(str); // On corrige le flux if (!Airbrush_mono_flow) { Airbrush_mono_flow=1; Num2str(Airbrush_mono_flow,str,2); Window_input_content(input_flow_button,str); } Display_cursor(); break; case 14 : // Init Num2str(spray_init,str,2); Readline(113,40,str,2,INPUT_TYPE_INTEGER); spray_init=atoi(str); // On corrige la valeur if (spray_init>=50) { spray_init=49; Num2str(spray_init,str,2); Window_input_content(input_init_button,str); } else if (spray_init<1) { spray_init=1; Num2str(spray_init,str,2); Window_input_content(input_init_button,str); } Display_cursor(); break; } if (!Mouse_K) switch (Key) { case SDLK_BACKQUOTE : // Rcupration d'une couleur derrire le menu case SDLK_COMMA : Get_color_behind_window(&color,&click); if (click) { Hide_cursor(); Stencil_tag_color(selected_color,(Airbrush_multi_flow[selected_color])?MC_Black:MC_Light); Stencil_update_color(selected_color); // Mettre la couleur slectionne jour suivant le click selected_color=color; if (click==2) Airbrush_multi_flow[selected_color]=0; else if (Airbrush_multi_flow[selected_color]==0) Airbrush_multi_flow[selected_color]=spray_init; // Tagger la couleur slectionne en blanc Stencil_tag_color(selected_color,MC_White); Refresh_airbrush_settings(selected_color,1); Display_cursor(); Stencil_update_color(selected_color); Wait_end_of_click(); } Key=0; break; default: if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Window_help(BUTTON_AIRBRUSH, NULL); Key=0; break; } if (Is_shortcut(Key,0x200+BUTTON_AIRBRUSH)) { clicked_button=2; break; } } } while ( (clicked_button!=1) && (clicked_button!=2) ); Close_window(); /* // Tant que l'on aura pas rsolu le problme du dsenclenchement du mode // de dessin prcedent, il faudra laisser a en remarque et donc passer en // spray mme si on a click sur Cancel (idem pour OK (un peu plus bas)). if (clicked_button==1) // Cancel { if (Current_operation!=OPERATION_AIRBRUSH) Unselect_button(BUTTON_AIRBRUSH); } */ Display_cursor(); /* if (clicked_button==2) // OK */ if (Current_operation!=OPERATION_AIRBRUSH) Select_button(BUTTON_AIRBRUSH,LEFT_SIDE); } // -- Gestion des boutons de polygone vide et plein ------------------------- void Button_polygon(void) { Hide_cursor(); Start_operation_stack(OPERATION_POLYGON); Display_cursor(); } void Button_Polyform(void) { Hide_cursor(); Start_operation_stack(OPERATION_POLYFORM); Display_cursor(); } void Button_Polyfill(void) { Hide_cursor(); Start_operation_stack(OPERATION_POLYFILL); Display_cursor(); } void Button_Filled_polyform(void) { Hide_cursor(); Start_operation_stack(OPERATION_FILLED_POLYFORM); Display_cursor(); } // -- Boutons d'ajustement de l'image --------------------------------------- void Button_Adjust(void) { Hide_cursor(); Start_operation_stack(OPERATION_SCROLL); Display_cursor(); } // -- Menu des effets (Shade, Stencil, etc...) ------------------------------ void Display_effect_sprite(short sprite_number, short start_x, short start_y) { short x,y,x_pos,y_pos; for (y=0,y_pos=start_y;yEffect_sprite[sprite_number][y][x]); Update_rect(ToWinX(start_x),ToWinY(start_y),EFFECT_SPRITE_WIDTH*Menu_factor_X,EFFECT_SPRITE_HEIGHT*Menu_factor_Y); } void Display_effect_state(short x, short y, char * label, byte state) { Block(Window_pos_X+(x*Menu_factor_X),Window_pos_Y+(y*Menu_factor_Y), 12*Menu_factor_X,Menu_factor_Y<<3,MC_Light); Print_in_window(x,y,label,(state)?MC_White:MC_Black,MC_Light); if (state) Print_in_window(x+56,y,":ON ",MC_White,MC_Light); else Print_in_window(x+56,y,":OFF",MC_Black,MC_Light); } void Display_effect_states(void) { Display_effect_state( 30, 24,"Shade" ,Shade_mode); Display_effect_state( 30, 43,"Q-shade",Quick_shade_mode); Display_effect_state( 30, 62,"Transp.",Colorize_mode); Display_effect_state( 30, 81,"Smooth" ,Smooth_mode); Display_effect_state( 30,100,"Smear" ,Smear_mode); Display_effect_state(176, 24,"Stencil",Stencil_mode); Display_effect_state(176, 43,"Mask" ,Mask_mode); Display_effect_state(176, 62,"Sieve" ,Sieve_mode); Display_effect_state(176, 81,"Grid" ,Snap_mode); Display_effect_state(176,100,"Tiling" ,Tiling_mode); } void Display_feedback_state(void) { Print_in_window(159,134,(Config.FX_Feedback)?"YES":" NO",MC_Black,MC_Light); } void Button_Effects(void) { short clicked_button; byte exit_by_close_button=0; Open_window(270,152,"Drawing modes (effects)"); Window_set_normal_button( 7, 19, 16,16,"",0,1,Config_Key[SPECIAL_SHADE_MODE][0]); // 1 Window_set_normal_button( 7, 38, 16,16,"",0,1,Config_Key[SPECIAL_QUICK_SHADE_MODE][0]); // 2 Window_set_normal_button( 7, 57, 16,16,"",0,1,Config_Key[SPECIAL_COLORIZE_MODE][0]); // 3 Window_set_normal_button( 7, 76, 16,16,"",0,1,Config_Key[SPECIAL_SMOOTH_MODE][0]); // 4 Window_set_normal_button( 7, 95, 16,16,"",0,1,Config_Key[SPECIAL_SMEAR_MODE][0]); // 5 Window_set_normal_button(153, 19, 16,16,"",0,1,Config_Key[SPECIAL_STENCIL_MODE][0]); // 6 Window_set_normal_button(153, 38, 16,16,"",0,1,Config_Key[SPECIAL_MASK_MODE][0]); // 7 Window_set_normal_button(153, 57, 16,16,"",0,1,Config_Key[SPECIAL_SIEVE_MODE][0]); // 8 Window_set_normal_button(153, 76, 16,16,"",0,1,Config_Key[SPECIAL_GRID_MODE][0]); // 9 Window_set_normal_button(153, 95, 16,16,"",0,1,Config_Key[SPECIAL_TILING_MODE][0]); // 10 Window_set_normal_button(195,131, 68,14,"Close",0,1,SDLK_RETURN); // 11 Window_set_normal_button( 7,131, 68,14,"All off",0,1,SDLK_DELETE); // 12 Window_set_normal_button( 83,131,104,14,"Feedback: ",1,1,SDLK_f); // 13 Display_feedback_state(); Display_effect_sprite(0, 8,20); Display_effect_sprite(0, 8,39); Display_effect_sprite(1, 8,58); Display_effect_sprite(2, 8,77); Display_effect_sprite(8, 8,96); Display_effect_sprite(4,154,20); Display_effect_sprite(7,154,39); Display_effect_sprite(5,154,58); Display_effect_sprite(6,154,77); Display_effect_sprite(3,154,96); Display_effect_states(); Print_in_window(12,117,"click: Left:Switch / Right:Edit",MC_Dark,MC_Light); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); if (Key==KEY_ESC || Is_shortcut(Key,0x100+BUTTON_EFFECTS)) { clicked_button=11; Key=0; } else if (Is_shortcut(Key,0x100+BUTTON_HELP)) { // Aide contextuelle switch(Window_get_clicked_button()) { case 1: Window_help(BUTTON_EFFECTS, "SHADE"); break; case 2: Window_help(BUTTON_EFFECTS, "QUICK SHADE"); break; case 3: Window_help(BUTTON_EFFECTS, "TRANSPARENCY"); break; case 4: Window_help(BUTTON_EFFECTS, "SMOOTH"); break; case 5: Window_help(BUTTON_EFFECTS, "SMEAR"); break; case 6: Window_help(BUTTON_EFFECTS, "STENCIL"); break; case 7: Window_help(BUTTON_EFFECTS, "MASK"); break; case 8: Window_help(BUTTON_EFFECTS, "SIEVE"); break; case 9: Window_help(BUTTON_EFFECTS, "GRID"); break; case 10: Window_help(BUTTON_EFFECTS, "TILING"); break; default: Window_help(BUTTON_EFFECTS, NULL); } // Hack because we have used Window_get_clicked_button() Input_sticky_control=0; // } switch (clicked_button) { case 1 : // Shade if (Window_attribute1==LEFT_SIDE) { Button_Shade_mode(); Hide_cursor(); Display_effect_states(); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Shade_menu(); clicked_button=11; } break; case 2 : // Quick-shade if (Window_attribute1==LEFT_SIDE) { Button_Quick_shade_mode(); Hide_cursor(); Display_effect_states(); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Quick_shade_menu(); clicked_button=11; } break; case 3 : // Colorize / Transparency if (Window_attribute1==LEFT_SIDE) { Button_Colorize_mode(); Hide_cursor(); Display_effect_states(); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Colorize_menu(); clicked_button=11; } break; case 4 : // Smooth if (Window_attribute1==LEFT_SIDE) { Button_Smooth_mode(); Hide_cursor(); Display_effect_states(); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Smooth_menu(); clicked_button=11; } break; case 5 : // Smear Button_Smear_mode(); Hide_cursor(); Display_effect_states(); Display_cursor(); break; case 6 : // Stencil if (Window_attribute1==LEFT_SIDE) { Button_Stencil_mode(); Hide_cursor(); Display_effect_state(176,24,"Stencil",Stencil_mode); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Stencil_menu(); clicked_button=11; } break; case 7 : // Mask if (Window_attribute1==LEFT_SIDE) { Button_Mask_mode(); Hide_cursor(); Display_effect_state(176,43,"Mask",Mask_mode); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Mask_menu(); clicked_button=11; } break; case 8 : // Sieve if (Window_attribute1==LEFT_SIDE) { Button_Sieve_mode(); Hide_cursor(); Display_effect_state(176,62,"Sieve",Sieve_mode); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Sieve_menu(); clicked_button=11; } break; case 9 : // Grid if (Window_attribute1==LEFT_SIDE) { Button_Snap_mode(); Hide_cursor(); Display_effect_state(176,81,"Grid",Snap_mode); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Grid_menu(); clicked_button=11; } break; case 10 : // Tiling if (Window_attribute1==LEFT_SIDE) { Button_Tiling_mode(); Hide_cursor(); Display_effect_states(); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Tiling_menu(); clicked_button=11; } break; case 11 : // Close exit_by_close_button=1; break; case 12 : // All off Effects_off(); Hide_cursor(); Display_effect_states(); Display_cursor(); break; case 13 : // Feedback (pour Colorize et Shade) Config.FX_Feedback = !Config.FX_Feedback; Update_FX_feedback(Config.FX_Feedback); Hide_cursor(); Display_feedback_state(); Display_cursor(); break; } } while (clicked_button!=11); if (exit_by_close_button) Close_window(); else Hide_cursor(); if (!(Shade_mode||Quick_shade_mode||Colorize_mode||Smooth_mode||Tiling_mode||Smear_mode||Stencil_mode||Mask_mode||Sieve_mode||Snap_mode)) Unselect_button(BUTTON_EFFECTS); Display_cursor(); } // Callback to display a font name in the list void Draw_one_font_name(word x, word y, word index, byte highlighted) { Print_in_window(x,y,Font_label(index), MC_Black, (highlighted)?MC_Dark:MC_Light); } void Button_Text(void) { static char str[256]=""; static int font_size=32; static int antialias=1; static short list_start=0; // index de le premiere fonte dans le selector static short cursor_position=0; // index de la ligne active dans le selector static short selected_font_index=0; static short is_bold=0; static short is_italic=0; byte * new_brush=NULL; T_Palette text_palette; int new_width; int new_height; int clicked_button; const int NB_FONTS=8; char size_buffer[4]; T_Special_button * input_size_button; T_Special_button * input_text_button; T_Special_button * preview_button; T_Special_button * font_list_button; T_Scroller_button * font_scroller; T_List_button * font_list; byte redraw_is_needed=1; byte preview_is_needed=1; Open_window(288,180,"Text"); // Texte saisi Print_in_window(6,20,"Text:",MC_Dark,MC_Light); input_text_button = Window_set_input_button(48,18,29); // 1 // TrueType options Window_display_frame_in(182,34,100,68); Print_in_window(199,31,"TrueType", MC_Dark, MC_Light); // AA Window_set_normal_button(188,58,13,11,antialias?"X":" ",0,1,SDLK_a); // 2 Print_in_window(206,60,"AntiAlias", MC_Dark, MC_Light); // Bold Window_set_normal_button(188,72,13,11,is_bold?"X":" ",0,1,SDLK_b); // 3 Print_in_window(206,75,"Bold", MC_Dark, MC_Light); // Italic Window_set_normal_button(188,86,13,11,is_italic?"X":" ",0,1,SDLK_i); // 4 Print_in_window(206,89,"Italic", MC_Dark, MC_Light); // Scroller des fontes font_scroller = Window_set_scroller_button(165,35,NB_FONTS*8,Nb_fonts,NB_FONTS,list_start); // 5 // Liste des fontes disponibles font_list_button = Window_set_special_button(8,35,152,NB_FONTS*8); // 6 Window_display_frame_in(7, 33, 154, NB_FONTS*8+4); // Taille texte input_size_button = Window_set_input_button(220,43,3); // 7 Window_set_repeatable_button(202,43,13,11,"-",0,1,SDLK_LAST); // 8 Window_set_repeatable_button(251,43,13,11,"+",0,1,SDLK_LAST); // 9 // Preview preview_button = Window_set_special_button(8,106,273,50); // 10 Window_display_frame_in(7, 105, 275, 52); Window_set_normal_button(8,160,40,14,"OK",0,1,SDLK_RETURN); // 11 Window_set_normal_button(54,160,60,14,"Cancel",0,1,KEY_ESC); // 12 // List of fonts font_list = Window_set_list_button(font_list_button, font_scroller, Draw_one_font_name, 2); // 13 // Restore its settings from last passage in screen font_list->List_start = list_start; font_list->Cursor_position = cursor_position; Window_redraw_list(font_list); Update_window_area(0,0,Window_width, Window_height); // str texte Window_input_content(input_text_button,str); // Taille police redraw_is_needed=1; // -- while (1) { if (redraw_is_needed) { // Taille Num2str(font_size,size_buffer,3); Window_input_content(input_size_button,size_buffer); } if (preview_is_needed) { const char * preview_string = "AaBbCcDdEeFf012345"; byte is_truetype; if (str[0]) preview_string=str; is_truetype=TrueType_font(selected_font_index); free(new_brush); new_brush = Render_text(preview_string, selected_font_index, font_size, antialias, is_bold, is_italic, &new_width, &new_height, text_palette); // Background: if (antialias&&is_truetype) // Solid Window_rectangle(8, 106, 273, 50,MC_Black); else if (is_truetype) { long l = text_palette[Fore_color].R+text_palette[Fore_color].G+text_palette[Fore_color].B; Window_rectangle(8, 106, 273, 50,l>128*3? MC_Black:MC_Light); } else { long l = text_palette[Back_color].R+text_palette[Back_color].G+text_palette[Back_color].B; Window_rectangle(8, 106, 273, 50,l>128*3? MC_Light:MC_Black); } if (new_brush) { if (!is_truetype || (is_truetype&&antialias)) { // Display brush in remapped form. byte *remapped_brush; remapped_brush=(byte *)malloc(new_width*new_height); if (remapped_brush) { // This code is mostly copied from Remap_brush() short x_pos; short y_pos; int color; byte colmap[256]; for (color=0;color<=255;color++) colmap[color]=0; for (y_pos=0;y_posPos_X*Menu_factor_X, Window_pos_Y+preview_button->Pos_Y*Menu_factor_Y, 0, 0, Min(preview_button->Width*Menu_factor_X, new_width), Min(preview_button->Height*Menu_factor_Y, new_height), Back_color, new_width); free(remapped_brush); } } else { // Solid Display_brush( new_brush, Window_pos_X+preview_button->Pos_X*Menu_factor_X, Window_pos_Y+preview_button->Pos_Y*Menu_factor_Y, 0, 0, Min(preview_button->Width*Menu_factor_X, new_width), Min(preview_button->Height*Menu_factor_Y, new_height), Back_color, new_width); } } Update_rect( Window_pos_X+preview_button->Pos_X*Menu_factor_X, Window_pos_Y+preview_button->Pos_Y*Menu_factor_Y, preview_button->Width*Menu_factor_X, preview_button->Height*Menu_factor_Y); } if (redraw_is_needed || preview_is_needed) { redraw_is_needed=0; preview_is_needed=0; Display_cursor(); } clicked_button=Window_clicked_button(); if (clicked_button==0) { if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_TEXT, NULL); else if (Is_shortcut(Key,0x100+BUTTON_TEXT)) clicked_button=12; } switch(clicked_button) { case 1: // Texte saisi Readline_ex(50,20,str,29,250,INPUT_TYPE_STRING,0); preview_is_needed=1; break; case 2: // AA antialias = (antialias==0); Hide_cursor(); Print_in_window(191,60,antialias?"X":" ", MC_Black, MC_Light); preview_is_needed=1; break; case 3: // Bold is_bold = (is_bold==0); Hide_cursor(); Print_in_window(191,74,is_bold?"X":" ", MC_Black, MC_Light); preview_is_needed=1; break; case 4: // Italic is_italic = (is_italic==0); Hide_cursor(); Print_in_window(191,88,is_italic?"X":" ", MC_Black, MC_Light); preview_is_needed=1; break; case 5: // Scroller des fontes /* Cannot happen, event is catched by the list control */ break; case 13: // Font selection selected_font_index = Window_attribute2; Hide_cursor(); preview_is_needed=1; break; case 7: // Taille du texte (nombre) Readline(222,45,size_buffer,3,INPUT_TYPE_INTEGER); font_size=atoi(size_buffer); // On corrige les dimensions if (font_size < 1) { font_size = 1; } else if (font_size>500) { font_size = 500; } redraw_is_needed=1; preview_is_needed=1; break; case 8: // Taille - if (font_size > 1) { font_size--; Hide_cursor(); redraw_is_needed=1; preview_is_needed=1; } break; case 9: // Taille + if (font_size < 255) { font_size++; Hide_cursor(); redraw_is_needed=1; preview_is_needed=1; } break; case 6: // Double-click font selector case 11: // OK // Save the selector settings list_start = font_list->List_start; cursor_position = font_list->Cursor_position; if (!new_brush) { // Si echec de rendu Close_window(); Unselect_button(BUTTON_TEXT); Display_cursor(); Error(0); return; } if (Realloc_brush(new_width, new_height, new_brush, NULL)) { free(new_brush); Close_window(); Unselect_button(BUTTON_TEXT); Display_cursor(); Error(0); } // Grab palette memcpy(Brush_original_palette, text_palette,sizeof(T_Palette)); // Remap to image's palette Remap_brush(); Brush_offset_X=Brush_width>>1; Brush_offset_Y=Brush_height>>1; // Fermeture Close_window(); Unselect_button(BUTTON_TEXT); // On passe en brosse: Display_cursor(); if (antialias || !TrueType_font(selected_font_index)) Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); else Change_paintbrush_shape(PAINTBRUSH_SHAPE_MONO_BRUSH); // Activate alpha mode if (antialias && TrueType_font(selected_font_index)) { Shade_mode=0; Quick_shade_mode=0; Smooth_mode=0; Tiling_mode=0; Smear_mode=0; Colorize_mode=1; Colorize_current_mode=3; Effect_function=Effect_alpha_colorize; Draw_menu_button(BUTTON_EFFECTS,BUTTON_PRESSED); } Select_button(BUTTON_DRAW,LEFT_SIDE); if (Config.Auto_discontinuous) { // On se place en mode Dessin discontinu la main while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW) Select_button(BUTTON_DRAW,RIGHT_SIDE); } //Display_cursor(); return; case 12: // Cancel // Save the selector settings list_start = font_list->List_start; cursor_position = font_list->Cursor_position; free(new_brush); new_brush = NULL; Close_window(); Unselect_button(BUTTON_TEXT); Display_cursor(); return; } } } void Display_stored_brush_in_window(word x_pos,word y_pos,int index) { if (Brush_container[index].Paintbrush_shape < PAINTBRUSH_SHAPE_MAX) { int x,y; int offset_x=0, offset_y=0; //int brush_offset_x=0, brush_offset_y=0; // Determine draw offset (small brushes are stacked on corner of their preview) if (Brush_container[index].WidthBRUSH_CONTAINER_PREVIEW_WIDTH) brush_offset_x = (Paintbrush_width-BRUSH_CONTAINER_PREVIEW_WIDTH)/2; if (Paintbrush_height>BRUSH_CONTAINER_PREVIEW_HEIGHT) brush_offset_y = (Paintbrush_height-BRUSH_CONTAINER_PREVIEW_HEIGHT)/2; for (y=0; yBRUSH_CONTAINER_PREVIEW_WIDTH || Brush_height>BRUSH_CONTAINER_PREVIEW_HEIGHT) { // Scale Rescale(Brush_original_pixels, Brush_width, Brush_height, (byte *)(Brush_container[index].Thumbnail), BRUSH_CONTAINER_PREVIEW_WIDTH, BRUSH_CONTAINER_PREVIEW_HEIGHT, 0, 0); } else { // Direct copy Copy_part_of_image_to_another(Brush_original_pixels, 0,0,Brush_width, Brush_height,Brush_width,(byte *)(Brush_container[index].Thumbnail),0,0,BRUSH_CONTAINER_PREVIEW_WIDTH); } } else { Error(0); } } } /// Retrieve a normal paintbrush void Select_paintbrush(int index) { int x_pos,y_pos; Paintbrush_shape=Paintbrush[index].Shape; if (Paintbrush[index].Width<=PAINTBRUSH_WIDTH && Paintbrush[index].Height<=PAINTBRUSH_HEIGHT) { Paintbrush_width=Paintbrush[index].Width; Paintbrush_height=Paintbrush[index].Height; Paintbrush_offset_X=Paintbrush[index].Offset_X; Paintbrush_offset_Y=Paintbrush[index].Offset_Y; for (y_pos=0; y_posPAINTBRUSH_WIDTH) x_off=(Paintbrush_width-PAINTBRUSH_WIDTH)/2; if (Paintbrush_height>PAINTBRUSH_HEIGHT) y_off=(Paintbrush_height-PAINTBRUSH_HEIGHT)/2; for (y_pos=0; y_pos>1; Paintbrush_offset_Y=Paintbrush_height>>1; } else { // Recreate the brush pixels from its shape and dimensions Set_paintbrush_size(Paintbrush_width,Paintbrush_height); } } // Color brushes if (shape == PAINTBRUSH_SHAPE_COLOR_BRUSH || shape == PAINTBRUSH_SHAPE_MONO_BRUSH) { Paintbrush_shape=shape; if (!Realloc_brush(Brush_container[index].Width,Brush_container[index].Height,NULL,NULL)) { // Recover pixels memcpy(Brush_original_pixels, Brush_container[index].Brush, (long)Brush_height*Brush_width); // Grab palette memcpy(Brush_original_palette, Brush_container[index].Palette, sizeof(T_Palette)); // Recover colormap memcpy(Brush_colormap, Brush_container[index].Colormap, 256); // Remap using current colormap Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); Brush_offset_X=Brush_width>>1; Brush_offset_Y=Brush_height>>1; } } Change_paintbrush_shape(shape); return 1; } void Button_Brush_container(void) { short clicked_button; short x_pos,y_pos; byte index; Open_window(BRUSH_CONTAINER_COLUMNS*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)+8, BRUSH_CONTAINER_ROWS*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+40, "Brushes"); Window_set_normal_button( (BRUSH_CONTAINER_COLUMNS*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)-59)/2, (BRUSH_CONTAINER_ROWS)*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+18, 67,14,"Cancel",0,1,KEY_ESC); // 1 index=0; for (index=0; index < BRUSH_CONTAINER_ROWS*BRUSH_CONTAINER_COLUMNS; index++) { x_pos = (index % BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)+7; y_pos = (index / BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+18; Window_set_normal_button( x_pos, y_pos, BRUSH_CONTAINER_PREVIEW_WIDTH+2, BRUSH_CONTAINER_PREVIEW_HEIGHT+2, "",0,1,SDLK_LAST); Display_stored_brush_in_window(x_pos+1, y_pos+1, index); } Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); //if (Is_shortcut(Key,0x100+BUTTON_HELP)) // Window_help(BUTTON_PAINTBRUSHES, NULL); if (clicked_button == 1) break; if (clicked_button>1) { index = clicked_button-2; if (Window_attribute1==RIGHT_SIDE) { // Store x_pos = (index % BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)+7; y_pos = (index / BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+18; Store_brush(index); Hide_cursor(); Display_stored_brush_in_window(x_pos+1, y_pos+1, index); Display_cursor(); } else { // Restore and exit if (Restore_brush(index)) break; } } } while (1); Close_window(); //Unselect_button(BUTTON_PAINTBRUSHES); Display_cursor(); } grafx2/src/buttons_effects.c0000644000076400010400000010665711521112356016576 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ //////////////////////////////////////////////////////////////////////////// ///@file buttons_effects.c /// Handles all the effects buttons and setup windows in the effects menu. //////////////////////////////////////////////////////////////////////////// #include #include #include #include "buttons.h" #include "engine.h" #include "global.h" #include "graph.h" #include "help.h" #include "input.h" #include "misc.h" #include "readline.h" #include "sdlscreen.h" #include "struct.h" #include "windows.h" #include "brush.h" //---------- Menu dans lequel on tagge des couleurs (genre Stencil) ---------- void Menu_tag_colors(char * window_title, byte * table, byte * mode, byte can_cancel, const char *help_section, word close_shortcut) { short clicked_button; byte backup_table[256]; word index; word old_mouse_x; word old_mouse_y; byte old_mouse_k; byte tagged_color; byte color; byte click; Open_window(176,150,window_title); Window_set_palette_button(6,38); // 1 Window_set_normal_button( 7, 19,78,14,"Clear" ,1,1,SDLK_c); // 2 Window_set_normal_button(91, 19,78,14,"Invert",1,1,SDLK_i); // 3 if (can_cancel) { Window_set_normal_button(91,129,78,14,"OK" ,0,1,SDLK_RETURN); // 4 Window_set_normal_button( 7,129,78,14,"Cancel",0,1,KEY_ESC); // 5 // On enregistre la table dans un backup au cas o on ferait Cancel memcpy(backup_table,table,256); } else Window_set_normal_button(49,129,78,14,"OK" ,0,1,SDLK_RETURN); // 4 // On affiche l'tat actuel de la table for (index=0; index<=255; index++) Stencil_tag_color(index, (table[index])?MC_Black:MC_Light); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { old_mouse_x=Mouse_X; old_mouse_y=Mouse_Y; old_mouse_k=Mouse_K; clicked_button=Window_clicked_button(); switch (clicked_button) { case 0 : break; case -1 : case 1 : // Palette if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) ) { Hide_cursor(); tagged_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); table[tagged_color]=(Mouse_K==LEFT_SIDE); Stencil_tag_color(tagged_color,(Mouse_K==LEFT_SIDE)?MC_Black:MC_Light); Display_cursor(); Stencil_update_color(tagged_color); } break; case 2 : // Clear memset(table,0,256); Hide_cursor(); for (index=0; index<=255; index++) Stencil_tag_color(index,MC_Light); Display_cursor(); Update_window_area(0,0,Window_width, Window_height); break; case 3 : // Invert Hide_cursor(); for (index=0; index<=255; index++) Stencil_tag_color(index,(table[index]^=1)?MC_Black:MC_Light); Display_cursor(); Update_window_area(0,0,Window_width, Window_height); } if (!Mouse_K) switch (Key) { case SDLK_BACKQUOTE : // Rcupration d'une couleur derrire le menu case SDLK_COMMA : Get_color_behind_window(&color,&click); if (click) { Hide_cursor(); tagged_color=color; table[tagged_color]=(click==LEFT_SIDE); Stencil_tag_color(tagged_color,(click==LEFT_SIDE)?MC_Black:MC_Light); Stencil_update_color(tagged_color); Display_cursor(); Wait_end_of_click(); } Key=0; break; default: if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Window_help(BUTTON_EFFECTS, help_section); Key=0; break; } else if (Is_shortcut(Key,close_shortcut)) { clicked_button=4; } } } while (clicked_button<4); Close_window(); if (clicked_button==5) // Cancel memcpy(table,backup_table,256); else // OK *mode=1; Display_cursor(); } //--------------------------------- Stencil ---------------------------------- void Button_Stencil_mode(void) { Stencil_mode=!Stencil_mode; } void Stencil_tag_color(byte color, byte tag_color) { Block(Window_pos_X+(Menu_factor_X*(Window_palette_button_list->Pos_X+4+(color >> 4)*10)), Window_pos_Y+(Menu_factor_Y*(Window_palette_button_list->Pos_Y+3+(color & 15)* 5)), Menu_factor_X<<1,Menu_factor_Y*5,tag_color); } void Stencil_update_color(byte color) { Update_rect(Window_pos_X+(Menu_factor_X*(Window_palette_button_list->Pos_X+4+(color >> 4)*10)), Window_pos_Y+(Menu_factor_Y*(Window_palette_button_list->Pos_Y+3+(color & 15)* 5)), Menu_factor_X<<1,Menu_factor_Y*5); } void Button_Stencil_menu(void) { Menu_tag_colors("Stencil",Stencil,&Stencil_mode,1, "STENCIL", SPECIAL_STENCIL_MENU); } //--------------------------------- Masque ----------------------------------- void Button_Mask_mode(void) { Mask_mode=!Mask_mode; } void Button_Mask_menu(void) { Menu_tag_colors("Mask",Mask_table,&Mask_mode,1, "MASK", SPECIAL_MASK_MENU); } // -------------------------------- Grille ----------------------------------- void Button_Snap_mode(void) { Hide_cursor(); Snap_mode=!Snap_mode; Compute_paintbrush_coordinates(); Display_cursor(); } void Button_Grid_menu(void) { short clicked_button; word chosen_X =Snap_width; word chosen_Y =Snap_height; short dx_selected=Snap_offset_X; short dy_selected=Snap_offset_Y; char showgrid = Show_grid; // if grid is shown check if we snap // if not snap by default (so the window work like before we introduced the "show" option) char snapgrid = Show_grid?Snap_mode:1; T_Special_button * input_x_button; T_Special_button * input_y_button; T_Special_button * input_dx_button; T_Special_button * input_dy_button; char str[3]; Open_window(133,118,"Grid"); Window_set_normal_button(12,92,51,14,"Cancel",0,1,KEY_ESC); // 1 Window_set_normal_button(70,92,51,14,"OK" ,0,1,SDLK_RETURN); // 2 Print_in_window(19,26, "X:",MC_Dark,MC_Light); input_x_button = Window_set_input_button(37,24,2); // 3 Num2str(chosen_X,str,2); Window_input_content(input_x_button,str); Print_in_window(19,47, "Y:",MC_Dark,MC_Light); input_y_button = Window_set_input_button(37,45,2); // 4 Num2str(chosen_Y,str,2); Window_input_content(input_y_button,str); Print_in_window(69,26,"dX:",MC_Dark,MC_Light); input_dx_button = Window_set_input_button(95,24,2); // 5 Num2str(dx_selected,str,2); Window_input_content(input_dx_button,str); Print_in_window(69,47,"dY:",MC_Dark,MC_Light); input_dy_button = Window_set_input_button(95,45,2); // 6 Num2str(dy_selected,str,2); Window_set_normal_button(12, 62, 14, 14, " ", 0, 1, 0); // 7 Window_set_normal_button(70, 62, 14, 14, " ", 0, 1, 0); // 8 if (snapgrid) Print_in_window(16, 65, "X", MC_Black, MC_Light); if (Show_grid) Print_in_window(74, 65, "X", MC_Black, MC_Light); Print_in_window(32, 65,"Snap",MC_Dark,MC_Light); Print_in_window(90, 65,"Show",MC_Dark,MC_Light); Window_input_content(input_dy_button,str); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); switch (clicked_button) { case 3 : Num2str(chosen_X,str,2); Readline(39,26,str,2,INPUT_TYPE_INTEGER); chosen_X=atoi(str); // On corrige les dimensions if ((!chosen_X) || (chosen_X>80)) { if (!chosen_X) chosen_X=1; else chosen_X=80; Num2str(chosen_X,str,2); Window_input_content(input_x_button,str); } if (dx_selected>=chosen_X) { dx_selected=chosen_X-1; Num2str(dx_selected,str,2); Window_input_content(input_dx_button,str); } Display_cursor(); break; case 4 : Num2str(chosen_Y,str,2); Readline(39,47,str,2,INPUT_TYPE_INTEGER); chosen_Y=atoi(str); // On corrige les dimensions if ((!chosen_Y) || (chosen_Y>80)) { if (!chosen_Y) chosen_Y=1; else chosen_Y=80; Num2str(chosen_Y,str,2); Window_input_content(input_y_button,str); } if (dy_selected>=chosen_Y) { dy_selected=chosen_Y-1; Num2str(dy_selected,str,2); Window_input_content(input_dy_button,str); } Display_cursor(); break; case 5 : Num2str(dx_selected,str,2); Readline(97,26,str,2,INPUT_TYPE_INTEGER); dx_selected=atoi(str); // On corrige les dimensions if (dx_selected>79) dx_selected=79; if (dx_selected>=chosen_X) dx_selected=chosen_X-1; Num2str(dx_selected,str,2); Window_input_content(input_dx_button,str); Display_cursor(); break; case 6 : Num2str(dy_selected,str,2); Readline(97,47,str,2,INPUT_TYPE_INTEGER); dy_selected=atoi(str); // On corrige les dimensions if (dy_selected>79) dy_selected=79; if (dy_selected>=chosen_Y) dy_selected=chosen_Y-1; Num2str(dy_selected,str,2); Window_input_content(input_dy_button,str); Display_cursor(); case 7: snapgrid = !snapgrid; Hide_cursor(); Print_in_window(16, 65, snapgrid?"X":" ", MC_Black, MC_Light); Display_cursor(); break; case 8: showgrid = !showgrid; Hide_cursor(); Print_in_window(74, 65, showgrid?"X":" ", MC_Black, MC_Light); Display_cursor(); break; } if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_EFFECTS, "GRID"); } while ( (clicked_button!=1) && (clicked_button!=2) ); if (clicked_button==2) // OK { Snap_width=chosen_X; Snap_height=chosen_Y; Snap_offset_X=dx_selected; Snap_offset_Y=dy_selected; Snap_mode=snapgrid; Show_grid=showgrid; } Close_window(); Display_cursor(); } void Button_Show_grid(void) { Show_grid = !Show_grid; Hide_cursor(); Display_all_screen(); Display_cursor(); } // -- Mode Smooth ----------------------------------------------------------- void Button_Smooth_mode(void) { if (Smooth_mode) Effect_function=No_effect; else { Effect_function=Effect_smooth; Shade_mode=0; Quick_shade_mode=0; Colorize_mode=0; Tiling_mode=0; Smear_mode=0; } Smooth_mode=!Smooth_mode; } byte Smooth_default_matrices[4][3][3]= { { {1,2,1}, {2,4,2}, {1,2,1} }, { {1,3,1}, {3,9,3}, {1,3,1} }, { {0,1,0}, {1,2,1}, {0,1,0} }, { {2,3,2}, {3,1,3}, {2,3,2} } }; void Button_Smooth_menu(void) { short clicked_button; word x,y,i,j; byte chosen_matrix[3][3]; T_Special_button * matrix_input[3][3]; char str[3]; Open_window(142,109,"Smooth"); Window_set_normal_button(82,59,53,14,"Cancel",0,1,KEY_ESC); // 1 Window_set_normal_button(82,88,53,14,"OK" ,0,1,SDLK_RETURN); // 2 Window_display_frame(6,17,130,37); for (x=11,y=0; y<4; x+=31,y++) { Window_set_normal_button(x,22,27,27,"",0,1,SDLK_LAST); // 3,4,5,6 for (j=0; j<3; j++) for (i=0; i<3; i++) Print_char_in_window(x+2+(i<<3),24+(j<<3),'0'+Smooth_default_matrices[y][i][j],MC_Black,MC_Light); } Window_display_frame(6,58, 69,45); for (j=0; j<3; j++) for (i=0; i<3; i++) { matrix_input[i][j]=Window_set_input_button(10+(i*21),62+(j*13),2); // 7..15 chosen_matrix[i][j] = Smooth_matrix[i][j] ; Num2str(chosen_matrix[i][j], str, 2); Window_input_content(matrix_input[i][j],str); } Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); if (clicked_button>2) { if (clicked_button<=6) { memcpy(chosen_matrix,Smooth_default_matrices[clicked_button-3],sizeof(chosen_matrix)); Hide_cursor(); for (j=0; j<3; j++) for (i=0; i<3; i++) { Num2str(chosen_matrix[i][j],str,2); Window_input_content(matrix_input[i][j],str); } Display_cursor(); } else { i=clicked_button-7; x=i%3; y=i/3; Num2str(chosen_matrix[x][y],str,2); Readline(matrix_input[x][y]->Pos_X+2, matrix_input[x][y]->Pos_Y+2, str,2,INPUT_TYPE_INTEGER); chosen_matrix[x][y]=atoi(str); Display_cursor(); } } if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_EFFECTS, "SMOOTH"); else if (Is_shortcut(Key,SPECIAL_SMOOTH_MENU)) clicked_button=2; } while ((clicked_button!=1) && (clicked_button!=2)); Close_window(); if (clicked_button==2) // OK { memcpy(Smooth_matrix,chosen_matrix,sizeof(Smooth_matrix)); Smooth_mode=0; // On le met 0 car la fonct suivante va le passer 1 Button_Smooth_mode(); } Display_cursor(); } // -- Mode Smear ------------------------------------------------------------ void Button_Smear_mode(void) { if (!Smear_mode) { if (!Colorize_mode) Effect_function=No_effect; Shade_mode=0; Quick_shade_mode=0; Smooth_mode=0; Tiling_mode=0; } Smear_mode=!Smear_mode; } // -- Mode Colorize --------------------------------------------------------- void Compute_colorize_table(void) { word index; word factor_a; word factor_b; factor_a=256*(100-Colorize_opacity)/100; factor_b=256*( Colorize_opacity)/100; for (index=0;index<256;index++) { Factors_table[index]=index*factor_a; Factors_inv_table[index]=index*factor_b; } } void Button_Colorize_mode(void) { if (Colorize_mode) Effect_function=No_effect; else { switch(Colorize_current_mode) { case 0 : Effect_function=Effect_interpolated_colorize; break; case 1 : Effect_function=Effect_additive_colorize; break; case 2 : Effect_function=Effect_substractive_colorize; break; case 3 : Effect_function=Effect_alpha_colorize; } Shade_mode=0; Quick_shade_mode=0; Smooth_mode=0; Tiling_mode=0; } Colorize_mode=!Colorize_mode; } void Button_Colorize_display_selection(int mode) { short y_pos=0; // Ligne o afficher les flches de slection // On commence par effacer les anciennes slections: // Partie gauche Print_in_window(4,37," ",MC_Black,MC_Light); Print_in_window(4,57," ",MC_Black,MC_Light); Print_in_window(4,74," ",MC_Black,MC_Light); Print_in_window(4,91," ",MC_Black,MC_Light); // Partie droite Print_in_window(129,37," ",MC_Black,MC_Light); Print_in_window(129,57," ",MC_Black,MC_Light); Print_in_window(129,74," ",MC_Black,MC_Light); Print_in_window(129,91," ",MC_Black,MC_Light); // Ensuite, on affiche la flche l o il le faut: switch(mode) { case 0 : // Mthode interpole y_pos=37; break; case 1 : // Mthode additive y_pos=57; break; case 2 : // Mthode soustractive y_pos=74; break; case 3 : // Mthode alpha y_pos=91; } Print_in_window(4,y_pos,"\020",MC_Black,MC_Light); Print_in_window(129,y_pos,"\021",MC_Black,MC_Light); } void Button_Colorize_menu(void) { short chosen_opacity; short selected_mode; short clicked_button; char str[4]; Open_window(140,135,"Transparency"); Print_in_window(16,23,"Opacity:",MC_Dark,MC_Light); Window_set_input_button(87,21,3); // 1 Print_in_window(117,23,"%",MC_Dark,MC_Light); Window_set_normal_button(16,34,108,14,"Interpolate",1,1,SDLK_i); // 2 Window_display_frame(12,18,116,34); Window_set_normal_button(16,54,108,14,"Additive" ,2,1,SDLK_d); // 3 Window_set_normal_button(16,71,108,14,"Subtractive",1,1,SDLK_s); // 4 Window_set_normal_button(16,88,108,14,"Alpha",1,1,SDLK_a); // 4 Window_set_normal_button(16,111, 51,14,"Cancel" ,0,1,KEY_ESC); // 5 Window_set_normal_button(73,111, 51,14,"OK" ,0,1,SDLK_RETURN); // 6 Num2str(Colorize_opacity,str,3); Window_input_content(Window_special_button_list,str); Button_Colorize_display_selection(Colorize_current_mode); chosen_opacity=Colorize_opacity; selected_mode =Colorize_current_mode; Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); switch(clicked_button) { case 1: // Zone de saisie de l'opacit Num2str(chosen_opacity,str,3); Readline(89,23,str,3,INPUT_TYPE_INTEGER); chosen_opacity=atoi(str); // On corrige le pourcentage if (chosen_opacity>100) { chosen_opacity=100; Num2str(chosen_opacity,str,3); Window_input_content(Window_special_button_list,str); } Display_cursor(); break; case 2: // Interpolated method case 3: // Additive method case 4: // Substractive method case 5: // Alpha method selected_mode=clicked_button-2; Hide_cursor(); Button_Colorize_display_selection(selected_mode); Display_cursor(); } if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_EFFECTS, "TRANSPARENCY"); else if (Is_shortcut(Key,SPECIAL_COLORIZE_MENU)) clicked_button=7; } while (clicked_button<6); Close_window(); if (clicked_button==7) // OK { Colorize_opacity =chosen_opacity; Colorize_current_mode=selected_mode; Compute_colorize_table(); Colorize_mode=0; // On le met 0 car la fonct suivante va le passer 1 Button_Colorize_mode(); } Display_cursor(); } // -- Mode Tiling ----------------------------------------------------------- void Button_Tiling_mode(void) { if (Tiling_mode) Effect_function=No_effect; else { Effect_function=Effect_tiling; Shade_mode=0; Quick_shade_mode=0; Colorize_mode=0; Smooth_mode=0; Smear_mode=0; } Tiling_mode=!Tiling_mode; } void Button_Tiling_menu(void) { short clicked_button; short chosen_offset_x=Tiling_offset_X; short chosen_offset_y=Tiling_offset_Y; char str[5]; T_Special_button * input_offset_x_button; T_Special_button * input_offset_y_button; Open_window(138,79,"Tiling"); Window_set_normal_button(13,55,51,14,"Cancel",0,1,KEY_ESC); // 1 Window_set_normal_button(74,55,51,14,"OK" ,0,1,SDLK_RETURN); // 2 input_offset_x_button = Window_set_input_button(91,21,4); // 3 input_offset_y_button = Window_set_input_button(91,35,4); // 4 Print_in_window(12,23,"Offset X:",MC_Dark,MC_Light); Print_in_window(12,37,"Offset Y:",MC_Dark,MC_Light); Num2str(Tiling_offset_X,str,4); Window_input_content(input_offset_x_button,str); Num2str(Tiling_offset_Y,str,4); Window_input_content(input_offset_y_button,str); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); if (clicked_button==3) // Zone de saisie du dcalage X { Num2str(chosen_offset_x,str,4); Readline(93,23,str,4,INPUT_TYPE_INTEGER); chosen_offset_x=atoi(str); // On corrige le dcalage en X if (chosen_offset_x>=Brush_width) { chosen_offset_x=Brush_width-1; Num2str(chosen_offset_x,str,4); Window_input_content(input_offset_x_button,str); } Display_cursor(); } else if (clicked_button==4) // Zone de saisie du dcalage Y { Num2str(chosen_offset_y,str,4); Readline(93,37,str,4,INPUT_TYPE_INTEGER); chosen_offset_y=atoi(str); // On corrige le dcalage en Y if (chosen_offset_y>=Brush_height) { chosen_offset_y=Brush_height-1; Num2str(chosen_offset_y,str,4); Window_input_content(input_offset_y_button,str); } Display_cursor(); } if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_EFFECTS, "TILING"); } while ( (clicked_button!=1) && (clicked_button!=2) ); Close_window(); if (clicked_button==2) // OK { Tiling_offset_X=chosen_offset_x; Tiling_offset_Y=chosen_offset_y; if (!Tiling_mode) Button_Tiling_mode(); } Display_cursor(); } // -- All modes off --------------------------------------------------------- void Effects_off(void) { Effect_function=No_effect; Shade_mode=0; Quick_shade_mode=0; Colorize_mode=0; Smooth_mode=0; Tiling_mode=0; Smear_mode=0; Stencil_mode=0; Mask_mode=0; Sieve_mode=0; Snap_mode=0; } // -- Mode Sieve (Sieve) ---------------------------------------------------- void Button_Sieve_mode(void) { Sieve_mode=!Sieve_mode; } void Draw_sieve_scaled(short origin_x, short origin_y) { short x_pos; short y_pos; short x_size; short y_size; short start_x=Window_pos_X+(Menu_factor_X*230); short start_y=Window_pos_Y+(Menu_factor_Y*78); x_size=Menu_factor_X*5; // |_ Taille d'une case y_size=Menu_factor_Y*5; // | de la trame zoome // On efface de contenu prcdent Block(origin_x,origin_y, Menu_factor_X*Window_special_button_list->Width, Menu_factor_Y*Window_special_button_list->Height,MC_Light); for (y_pos=0; y_posSieve_pattern[index][j&0xF]>>(15-(i&0xF)))&1)?MC_White:MC_Black); Update_rect(ToWinX(10),ToWinY(22),ToWinL(12*23+16),ToWinH(16)); } void Copy_preset_sieve(byte index) { short i,j; for (j=0; j<16; j++) for (i=0; i<16; i++) Sieve[i][j]=(Gfx->Sieve_pattern[index][j]>>(15-i))&1; Sieve_width=16; Sieve_height=16; } void Invert_trame(void) { byte x_pos,y_pos; for (y_pos=0; y_pos plus grande short preview_y_end; // | rapidit. memcpy(old_sieve,Sieve,256); Open_window(290,179,"Sieve"); preview_x_start=Window_pos_X+(Menu_factor_X*230); preview_y_start=Window_pos_Y+(Menu_factor_Y*78); preview_x_end=preview_x_start+(Menu_factor_X*51); preview_y_end=preview_y_start+(Menu_factor_Y*71); Window_display_frame ( 7, 65,130,43); Window_display_frame ( 7,110,130,43); Window_display_frame_in(142, 68, 82,82); Window_display_frame_in(229, 77, 53,73); Print_in_window(228, 68,"Preview",MC_Dark,MC_Light); Print_in_window( 27, 83,"Scroll" ,MC_Dark,MC_Light); Print_in_window( 23,120,"Width:" ,MC_Dark,MC_Light); Print_in_window( 15,136,"Height:",MC_Dark,MC_Light); Window_set_special_button(143,69,80,80); // 1 Window_set_normal_button(175,157,51,14,"Cancel",0,1,KEY_ESC); // 2 Window_set_normal_button(230,157,51,14,"OK" ,0,1,SDLK_RETURN); // 3 Window_set_normal_button( 8,157,51,14,"Clear" ,1,1,SDLK_c); // 4 Window_set_normal_button( 63,157,51,14,"Invert",1,1,SDLK_i); // 5 Window_set_normal_button( 8,46,131,14,"Get from brush" ,1,1,SDLK_g); // 6 Window_set_normal_button(142,46,139,14,"Transfer to brush",1,1,SDLK_t); // 7 Window_set_normal_button(109,114,11,11,"\030",0,1,SDLK_UP|MOD_SHIFT); // 8 Window_set_normal_button(109,138,11,11,"\031",0,1,SDLK_DOWN|MOD_SHIFT); // 9 Window_set_normal_button( 97,126,11,11,"\033",0,1,SDLK_LEFT|MOD_SHIFT); // 10 Window_set_normal_button(121,126,11,11,"\032",0,1,SDLK_RIGHT|MOD_SHIFT); // 11 button_bg_color = Window_set_normal_button(109,126,11,11,"" ,0,1,SDLK_INSERT); // 12 Block(Window_pos_X+(Menu_factor_X*(button_bg_color->Pos_X+2)), Window_pos_Y+(Menu_factor_Y*(button_bg_color->Pos_Y+2)), Menu_factor_X*7, Menu_factor_Y*7, (default_bg_color)?MC_White:MC_Black); Window_set_repeatable_button(109, 69,11,11,"\030",0,1,SDLK_UP); // 13 Window_set_repeatable_button(109, 93,11,11,"\031",0,1,SDLK_DOWN); // 14 Window_set_repeatable_button( 97, 81,11,11,"\033",0,1,SDLK_LEFT); // 15 Window_set_repeatable_button(121, 81,11,11,"\032",0,1,SDLK_RIGHT); // 16 for (index=0; index<12; index++) Window_set_normal_button((index*23)+8,20,20,20,"",0,1,SDLK_F1+index); // 17 -> 28 Draw_preset_sieve_patterns(); origin_x=Window_pos_X+(Menu_factor_X*Window_special_button_list->Pos_X); origin_y=Window_pos_Y+(Menu_factor_Y*Window_special_button_list->Pos_Y); Num2str(Sieve_width,str,2); Print_in_window(71,120,str,MC_Black,MC_Light); Num2str(Sieve_height,str,2); Print_in_window(71,136,str,MC_Black,MC_Light); Draw_sieve_scaled(origin_x,origin_y); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); origin_x=Window_pos_X+(Menu_factor_X*Window_special_button_list->Pos_X); origin_y=Window_pos_Y+(Menu_factor_Y*Window_special_button_list->Pos_Y); switch (clicked_button) { case -1 : case 0 : break; case 1 : // Zone de dessin de la trame /* // Version qui n'accepte pas les clicks sur la grille x_pos=(Mouse_X-origin_x)/Menu_factor_X; y_pos=(Mouse_Y-origin_y)/Menu_factor_Y; if ( (x_pos%5<4) && (y_pos%5<4) ) { x_pos/=5; y_pos/=5; if ( (x_pos16)?16:Brush_width; Sieve_height=(Brush_height>16)?16:Brush_height; for (y_pos=0; y_pos>1); Brush_offset_Y=(Brush_height>>1); Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); break; case 8 : // Rduire hauteur if (Sieve_height>1) { Hide_cursor(); Sieve_height--; Num2str(Sieve_height,str,2); Print_in_window(71,136,str,MC_Black,MC_Light); Draw_sieve_scaled(origin_x,origin_y); Display_cursor(); Update_sieve_area(origin_x, origin_y); } break; case 9 : // Agrandir hauteur if (Sieve_height<16) { Hide_cursor(); for (index=0; index1) { Hide_cursor(); Sieve_width--; Num2str(Sieve_width,str,2); Print_in_window(71,120,str,MC_Black,MC_Light); Draw_sieve_scaled(origin_x,origin_y); Display_cursor(); Update_sieve_area(origin_x, origin_y); } break; case 11 : // Agrandir largeur if (Sieve_width<16) { Hide_cursor(); for (index=0; indexPos_X+2)), Window_pos_Y+(Menu_factor_Y*(button_bg_color->Pos_Y+2)), Menu_factor_X*7, Menu_factor_Y*7, (default_bg_color)?MC_White:MC_Black); Display_cursor(); Update_rect( Window_pos_X+(Menu_factor_X*(button_bg_color->Pos_X+2)), Window_pos_Y+(Menu_factor_Y*(button_bg_color->Pos_Y+2)), Menu_factor_X*7, Menu_factor_Y*7); break; case 13 : // Scroll vers le haut Hide_cursor(); for (x_pos=0; x_pos0; y_pos--) Sieve[x_pos][y_pos]=Sieve[x_pos][y_pos-1]; Sieve[x_pos][0]=temp; } Draw_sieve_scaled(origin_x,origin_y); Display_cursor(); Update_sieve_area(origin_x, origin_y); break; case 15 : // Scroll vers la gauche Hide_cursor(); for (y_pos=0; y_pos0; x_pos--) Sieve[x_pos][y_pos]=Sieve[x_pos-1][y_pos]; Sieve[0][y_pos]=temp; } Draw_sieve_scaled(origin_x,origin_y); Display_cursor(); Update_sieve_area(origin_x, origin_y); break; default : // Boutons de trames prdfinies Hide_cursor(); Copy_preset_sieve(clicked_button-17); Draw_sieve_scaled(origin_x,origin_y); Num2str(Sieve_width,str,2); Print_in_window(71,120,str,MC_Black,MC_Light); Num2str(Sieve_height,str,2); Print_in_window(71,136,str,MC_Black,MC_Light); Draw_sieve_scaled(origin_x,origin_y); Display_cursor(); Update_sieve_area(origin_x, origin_y); } if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Key=0; Window_help(BUTTON_EFFECTS, "SIEVE"); } } while ( (clicked_button!=2) && (clicked_button!=3) ); Close_window(); if (clicked_button==2) // Cancel { Sieve_width=old_sieve_width; Sieve_height=old_sieve_height; memcpy(Sieve,old_sieve,256); } if ( (clicked_button==3) && (!Sieve_mode) ) // OK Button_Sieve_mode(); Display_cursor(); } grafx2/src/engine.c0000644000076400010400000033525411545652460014656 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ /// @file engine.c: Window engine and interface management #include #include #include #include "const.h" #include "struct.h" #include "global.h" #include "graph.h" #include "misc.h" #include "special.h" #include "buttons.h" #include "operatio.h" #include "shade.h" #include "errors.h" #include "sdlscreen.h" #include "windows.h" #include "brush.h" #include "input.h" #include "engine.h" #include "pages.h" #include "layers.h" #include "factory.h" #include "loadsave.h" #include "io.h" // we need this as global short Old_MX = -1; short Old_MY = -1; //---------- Annuler les effets des modes de dessin (sauf la grille) --------- // Variables mmorisants les anciens effets byte Shade_mode_before_cancel; byte Quick_shade_mode_before_cancel; byte Stencil_mode_before_cancel; byte Sieve_mode_before_cancel; byte Colorize_mode_before_cancel; byte Smooth_mode_before_cancel; byte Tiling_mode_before_cancel; Func_effect Effect_function_before_cancel; ///This table holds pointers to the saved window backgrounds. We can have up to 8 windows open at a time. byte* Window_background[8]; ///Table of tooltip texts for menu buttons char * Menu_tooltip[NB_BUTTONS]= { "Hide toolbars / Select ", "Layers manager ", "Get/Set transparent col.", "Merge layer ", "Add layer ", "Drop layer ", "Raise layer ", "Lower layer ", "Layer select / toggle ", "Paintbrush choice ", "Adjust / Transform menu ", "Freehand draw. / Toggle ", "Splines / Toggle ", "Lines / Toggle ", "Spray / Menu ", "Floodfill / Replace col.", "Polylines / Polyforms ", "Polyfill / Filled Pforms", "Empty rectangles ", "Filled rectangles ", "Empty circles / ellipses", "Filled circles / ellips.", "Grad. rect / Grad. menu ", "Grad. spheres / ellipses", "Brush grab. / Restore ", "Lasso / Restore brush ", #ifdef __ENABLE_LUA__ "Brush effects / factory ", #else "Brush effects ", #endif "Drawing modes (effects) ", "Text ", "Magnify mode / Menu ", "Pipette / Invert colors ", "Screen size / Safe. res.", "Go / Copy to other page ", "Save as / Save ", "Load / Re-load ", "Settings / Skins ", "Clear / with backcolor ", "Help / Statistics ", "Undo / Redo ", "Kill current page ", "Quit ", "Palette editor / setup ", "Scroll pal. bkwd / Fast ", "Scroll pal. fwd / Fast ", "Color #" , }; ///Save a screen block (usually before erasing it with a new window or a dropdown menu) void Save_background(byte **buffer, int x_pos, int y_pos, int width, int height) { int index; if(*buffer != NULL) DEBUG("WARNING : buffer already allocated !!!",0); *buffer=(byte *) malloc(width*Menu_factor_X*height*Menu_factor_Y*Pixel_width); if(*buffer==NULL) Error(0); for (index=0; index<(height*Menu_factor_Y); index++) Read_line(x_pos,y_pos+index,width*Menu_factor_X,(*buffer)+((int)index*width*Menu_factor_X*Pixel_width)); } ///Restores a screen block void Restore_background(byte *buffer, int x_pos, int y_pos, int width, int height) { int index; for (index=0; index= Menu_Y+Menu_factor_Y*(Menu_bars[current_menu].Top) && Mouse_Y < Menu_Y+Menu_factor_Y*(Menu_bars[current_menu].Top + Menu_bars[current_menu].Height)) break; } } if (current_menu==MENUBAR_COUNT) return -1; y_pos=(Mouse_Y - Menu_Y)/Menu_factor_Y - Menu_bars[current_menu].Top; if (current_menu == 0) first_button = 0; else first_button = Menu_bars[current_menu - 1].Last_button_index + 1; for (btn_number=first_button;btn_number<=Menu_bars[current_menu].Last_button_index;btn_number++) { switch(Buttons_Pool[btn_number].Shape) { case BUTTON_SHAPE_NO_FRAME : case BUTTON_SHAPE_RECTANGLE : if ((x_pos>=Buttons_Pool[btn_number].X_offset) && (y_pos>=Buttons_Pool[btn_number].Y_offset) && (x_pos<=Buttons_Pool[btn_number].X_offset+Buttons_Pool[btn_number].Width) && (y_pos<=Buttons_Pool[btn_number].Y_offset+Buttons_Pool[btn_number].Height)) return btn_number; break; case BUTTON_SHAPE_TRIANGLE_TOP_LEFT: if ((x_pos>=Buttons_Pool[btn_number].X_offset) && (y_pos>=Buttons_Pool[btn_number].Y_offset) && (x_pos+y_pos-(short)Buttons_Pool[btn_number].Y_offset-(short)Buttons_Pool[btn_number].X_offset<=Buttons_Pool[btn_number].Width)) return btn_number; break; case BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT: if ((x_pos<=Buttons_Pool[btn_number].X_offset+Buttons_Pool[btn_number].Width) && (y_pos<=Buttons_Pool[btn_number].Y_offset+Buttons_Pool[btn_number].Height) && (x_pos+y_pos-(short)Buttons_Pool[btn_number].Y_offset-(short)Buttons_Pool[btn_number].X_offset>=Buttons_Pool[btn_number].Width)) return btn_number; break; } } return -1; } ///Draw a menu button, selected or not void Draw_menu_button(byte btn_number,byte pressed) { word start_x; word start_y; word width; word height; byte * bitmap; word bitmap_width; word x_pos; word y_pos; byte current_menu; byte color; signed char icon; // Find in which menu the button is for (current_menu = 0; current_menu < MENUBAR_COUNT; current_menu++) { // We found the right bar ! if (Menu_bars[current_menu].Last_button_index >= btn_number && (current_menu==0 || Menu_bars[current_menu -1].Last_button_index < btn_number)) { break; } } start_x = Buttons_Pool[btn_number].X_offset; start_y = Buttons_Pool[btn_number].Y_offset; width = Buttons_Pool[btn_number].Width+1; height = Buttons_Pool[btn_number].Height+1; icon = Buttons_Pool[btn_number].Icon; if (icon==-1) { // Standard button bitmap_width = Menu_bars[current_menu].Skin_width; bitmap=&(Menu_bars[current_menu].Skin[pressed][start_y*Menu_bars[current_menu].Skin_width+start_x]); } else { // From Menu_buttons bitmap_width = MENU_SPRITE_WIDTH; bitmap=Gfx->Menu_sprite[pressed][(byte)icon][0]; // For bottom right: offset +1,+1 if (Buttons_Pool[btn_number].Shape==BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT) bitmap += MENU_SPRITE_WIDTH+1; } switch(Buttons_Pool[btn_number].Shape) { case BUTTON_SHAPE_NO_FRAME : break; case BUTTON_SHAPE_RECTANGLE : for (y_pos=0;y_posPages); flimit = Find_last_slash(Drop_file_name); *(flimit++) = '\0'; Hide_cursor(); old_cursor_shape=Cursor_shape; Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); Init_context_layered_image(&context, flimit, Drop_file_name); Load_image(&context); if (File_error!=1) { Compute_limits(); Compute_paintbrush_coordinates(); Redraw_layered_image(); End_of_modification(); Display_all_screen(); Main_image_is_modified=0; } Destroy_context(&context); Compute_optimal_menu_colors(Main_palette); Display_menu(); if (Config.Display_image_limits) Display_image_limits(); Hide_cursor(); Cursor_shape=old_cursor_shape; Display_all_screen(); Display_cursor(); } free(Drop_file_name); Drop_file_name=NULL; } if(Get_input(0)) { action = 0; // Inhibit all keys if a drawing operation is in progress. // We make an exception for the freehand operations, but these will // only accept a very limited number of shortcuts. if (Operation_stack_size!=0 && !Allow_color_change_during_operation) Key=0; // Evenement de fermeture if (Quit_is_required) { Quit_is_required=0; Button_Quit(); } if (Key) { effect_modified = 0; for (key_index=SPECIAL_CLICK_RIGHT+1;key_index>2)); else Scroll_screen(0,-(Screen_height>>3)); action++; break; case SPECIAL_SCROLL_DOWN : // Scroll down if (Main_magnifier_mode) Scroll_magnifier(0,(Main_magnifier_height>>2)); else Scroll_screen(0,(Screen_height>>3)); action++; break; case SPECIAL_SCROLL_LEFT : // Scroll left if (Main_magnifier_mode) Scroll_magnifier(-(Main_magnifier_width>>2),0); else Scroll_screen(-(Screen_width>>3),0); action++; break; case SPECIAL_SCROLL_RIGHT : // Scroll right if (Main_magnifier_mode) Scroll_magnifier((Main_magnifier_width>>2),0); else Scroll_screen((Screen_width>>3),0); action++; break; case SPECIAL_SCROLL_UP_FAST : // Scroll up faster if (Main_magnifier_mode) Scroll_magnifier(0,-(Main_magnifier_height>>1)); else Scroll_screen(0,-(Screen_height>>2)); action++; break; case SPECIAL_SCROLL_DOWN_FAST : // Scroll down faster if (Main_magnifier_mode) Scroll_magnifier(0,(Main_magnifier_height>>1)); else Scroll_screen(0,(Screen_height>>2)); action++; break; case SPECIAL_SCROLL_LEFT_FAST : // Scroll left faster if (Main_magnifier_mode) Scroll_magnifier(-(Main_magnifier_width>>1),0); else Scroll_screen(-(Screen_width>>2),0); action++; break; case SPECIAL_SCROLL_RIGHT_FAST : // Scroll right faster if (Main_magnifier_mode) Scroll_magnifier((Main_magnifier_width>>1),0); else Scroll_screen((Screen_width>>2),0); action++; break; case SPECIAL_SCROLL_UP_SLOW : // Scroll up slower if (Main_magnifier_mode) Scroll_magnifier(0,-1); else Scroll_screen(0,-1); action++; break; case SPECIAL_SCROLL_DOWN_SLOW : // Scroll down slower if (Main_magnifier_mode) Scroll_magnifier(0,1); else Scroll_screen(0,1); action++; break; case SPECIAL_SCROLL_LEFT_SLOW : // Scroll left slower if (Main_magnifier_mode) Scroll_magnifier(-1,0); else Scroll_screen(-1,0); action++; break; case SPECIAL_SCROLL_RIGHT_SLOW : // Scroll right slower if (Main_magnifier_mode) Scroll_magnifier(1,0); else Scroll_screen(1,0); action++; break; case SPECIAL_SHOW_HIDE_CURSOR : // Show / Hide cursor Hide_cursor(); Cursor_hidden=!Cursor_hidden; Display_cursor(); action++; break; case SPECIAL_DOT_PAINTBRUSH : // Paintbrush = "." Hide_cursor(); Paintbrush_shape=PAINTBRUSH_SHAPE_ROUND; Set_paintbrush_size(1,1); Change_paintbrush_shape(PAINTBRUSH_SHAPE_ROUND); Display_cursor(); action++; break; case SPECIAL_CONTINUOUS_DRAW : // Continuous freehand drawing Select_button(BUTTON_DRAW,LEFT_SIDE); // ATTENTION CE TRUC EST MOCHE ET VA MERDER SI ON SE MET A UTILISER DES BOUTONS POPUPS while (Current_operation!=OPERATION_CONTINUOUS_DRAW) Select_button(BUTTON_DRAW,RIGHT_SIDE); action++; break; case SPECIAL_FLIP_X : // Flip X Hide_cursor(); Flip_X_lowlevel(Brush_original_pixels, Brush_width, Brush_height); // Remap according to the last used remap table Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); Display_cursor(); action++; break; case SPECIAL_FLIP_Y : // Flip Y Hide_cursor(); Flip_Y_lowlevel(Brush_original_pixels, Brush_width, Brush_height); // Remap according to the last used remap table Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); Display_cursor(); action++; break; case SPECIAL_ROTATE_90 : // 90 brush rotation Hide_cursor(); Rotate_90_deg(); Display_cursor(); action++; break; case SPECIAL_ROTATE_180 : // 180 brush rotation Hide_cursor(); Rotate_180_deg_lowlevel(Brush, Brush_width, Brush_height); // Remap according to the last used remap table Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); Display_cursor(); action++; break; case SPECIAL_STRETCH : // Stretch brush Hide_cursor(); Start_operation_stack(OPERATION_STRETCH_BRUSH); Display_cursor(); action++; break; case SPECIAL_DISTORT : // Distort brush Hide_cursor(); Start_operation_stack(OPERATION_DISTORT_BRUSH); Display_cursor(); action++; break; case SPECIAL_ROTATE_ANY_ANGLE : // Rotate brush by any angle Hide_cursor(); Start_operation_stack(OPERATION_ROTATE_BRUSH); Display_cursor(); action++; break; case SPECIAL_BRUSH_DOUBLE: if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH) { Hide_cursor(); Stretch_brush(1,1,Brush_width*2,Brush_height*2); Display_cursor(); } action++; break; case SPECIAL_BRUSH_DOUBLE_WIDTH: if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH) { Hide_cursor(); Stretch_brush(1,1,Brush_width*2,Brush_height); Display_cursor(); } action++; break; case SPECIAL_BRUSH_DOUBLE_HEIGHT: if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH) { Hide_cursor(); Stretch_brush(1,1,Brush_width,Brush_height*2); Display_cursor(); } action++; break; case SPECIAL_BRUSH_HALVE: if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH) { Hide_cursor(); Stretch_brush(1,1,Brush_width/2,Brush_height/2); Display_cursor(); } action++; break; case SPECIAL_OUTLINE : // Outline brush Hide_cursor(); Outline_brush(); Display_cursor(); action++; break; case SPECIAL_NIBBLE : // Nibble brush Hide_cursor(); Nibble_brush(); Display_cursor(); action++; break; case SPECIAL_GET_BRUSH_COLORS : // Get colors from brush Get_colors_from_brush(); action++; break; case SPECIAL_RECOLORIZE_BRUSH : // Recolorize brush Hide_cursor(); Remap_brush(); Display_cursor(); action++; break; case SPECIAL_LOAD_BRUSH : Load_picture(0); action++; break; case SPECIAL_SAVE_BRUSH : Save_picture(0); action++; break; case SPECIAL_ZOOM_IN : // Zoom in Zoom(+1); action++; break; case SPECIAL_ZOOM_OUT : // Zoom out Zoom(-1); action++; break; case SPECIAL_CENTER_ATTACHMENT : // Center brush attachment Hide_cursor(); Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); Display_cursor(); action++; break; case SPECIAL_TOP_LEFT_ATTACHMENT : // Top-left brush attachment Hide_cursor(); Brush_offset_X=0; Brush_offset_Y=0; Display_cursor(); action++; break; case SPECIAL_TOP_RIGHT_ATTACHMENT : // Top-right brush attachment Hide_cursor(); Brush_offset_X=(Brush_width-1); Brush_offset_Y=0; Display_cursor(); action++; break; case SPECIAL_BOTTOM_LEFT_ATTACHMENT : // Bottom-left brush attachment Hide_cursor(); Brush_offset_X=0; Brush_offset_Y=(Brush_height-1); Display_cursor(); action++; break; case SPECIAL_BOTTOM_RIGHT_ATTACHMENT : // Bottom right brush attachment Hide_cursor(); Brush_offset_X=(Brush_width-1); Brush_offset_Y=(Brush_height-1); Display_cursor(); action++; break; case SPECIAL_EXCLUDE_COLORS_MENU : // Exclude colors menu Menu_tag_colors("Tag colors to exclude",Exclude_color,&temp,1, NULL, SPECIAL_EXCLUDE_COLORS_MENU); action++; break; case SPECIAL_INVERT_SIEVE : Invert_trame(); action++; break; case SPECIAL_SHADE_MODE : Button_Shade_mode(); effect_modified = 1; action++; break; case SPECIAL_SHADE_MENU : Button_Shade_menu(); effect_modified = 1; action++; break; case SPECIAL_QUICK_SHADE_MODE : Button_Quick_shade_mode(); effect_modified = 1; action++; break; case SPECIAL_QUICK_SHADE_MENU : Button_Quick_shade_menu(); effect_modified = 1; action++; break; case SPECIAL_STENCIL_MODE : Button_Stencil_mode(); effect_modified = 1; action++; break; case SPECIAL_STENCIL_MENU : Button_Stencil_menu(); effect_modified = 1; action++; break; case SPECIAL_MASK_MODE : Button_Mask_mode(); effect_modified = 1; action++; break; case SPECIAL_MASK_MENU : Button_Mask_menu(); effect_modified = 1; action++; break; case SPECIAL_GRID_MODE : Button_Snap_mode(); effect_modified = 1; action++; break; case SPECIAL_GRID_MENU : Button_Grid_menu(); effect_modified = 1; action++; break; case SPECIAL_SHOW_GRID : Button_Show_grid(); effect_modified = 1; action++; break; case SPECIAL_SIEVE_MODE : Button_Sieve_mode(); effect_modified = 1; action++; break; case SPECIAL_SIEVE_MENU : Button_Sieve_menu(); effect_modified = 1; action++; break; case SPECIAL_COLORIZE_MODE : Button_Colorize_mode(); effect_modified = 1; action++; break; case SPECIAL_COLORIZE_MENU : Button_Colorize_menu(); effect_modified = 1; action++; break; case SPECIAL_SMOOTH_MODE : Button_Smooth_mode(); effect_modified = 1; action++; break; case SPECIAL_SMOOTH_MENU : Button_Smooth_menu(); effect_modified = 1; action++; break; case SPECIAL_SMEAR_MODE : Button_Smear_mode(); effect_modified = 1; action++; break; case SPECIAL_TILING_MODE : Button_Tiling_mode(); effect_modified = 1; action++; break; case SPECIAL_TILING_MENU : effect_modified = 1; Button_Tiling_menu(); action++; break; case SPECIAL_EFFECTS_OFF : Effects_off(); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_1 : Transparency_set(1); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_2 : Transparency_set(2); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_3 : Transparency_set(3); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_4 : Transparency_set(4); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_5 : Transparency_set(5); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_6 : Transparency_set(6); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_7 : Transparency_set(7); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_8 : Transparency_set(8); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_9 : Transparency_set(9); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_0 : Transparency_set(0); effect_modified = 1; action++; break; case SPECIAL_ZOOM_1 : Zoom_set(-1); action++; break; case SPECIAL_ZOOM_2 : Zoom_set(0); action++; break; case SPECIAL_ZOOM_3 : Zoom_set(1); action++; break; case SPECIAL_ZOOM_4 : Zoom_set(2); action++; break; case SPECIAL_ZOOM_5 : Zoom_set(3); action++; break; case SPECIAL_ZOOM_6 : Zoom_set(4); action++; break; case SPECIAL_ZOOM_8 : Zoom_set(5); action++; break; case SPECIAL_ZOOM_10 : Zoom_set(6); action++; break; case SPECIAL_ZOOM_12 : Zoom_set(7); action++; break; case SPECIAL_ZOOM_14 : Zoom_set(8); action++; break; case SPECIAL_ZOOM_16 : Zoom_set(9); action++; break; case SPECIAL_ZOOM_18 : Zoom_set(10); action++; break; case SPECIAL_ZOOM_20 : Zoom_set(11); action++; break; case SPECIAL_LAYER1_SELECT: case SPECIAL_LAYER2_SELECT: case SPECIAL_LAYER3_SELECT: case SPECIAL_LAYER4_SELECT: case SPECIAL_LAYER5_SELECT: case SPECIAL_LAYER6_SELECT: case SPECIAL_LAYER7_SELECT: case SPECIAL_LAYER8_SELECT: Layer_activate((key_index-SPECIAL_LAYER1_SELECT)/2, LEFT_SIDE); action++; break; case SPECIAL_LAYER1_TOGGLE: case SPECIAL_LAYER2_TOGGLE: case SPECIAL_LAYER3_TOGGLE: case SPECIAL_LAYER4_TOGGLE: case SPECIAL_LAYER5_TOGGLE: case SPECIAL_LAYER6_TOGGLE: case SPECIAL_LAYER7_TOGGLE: case SPECIAL_LAYER8_TOGGLE: Layer_activate((key_index-SPECIAL_LAYER1_TOGGLE)/2, RIGHT_SIDE); action++; break; case SPECIAL_REPEAT_SCRIPT: #ifdef __ENABLE_LUA__ Repeat_script(); action++; #endif break; case SPECIAL_RUN_SCRIPT_1: case SPECIAL_RUN_SCRIPT_2: case SPECIAL_RUN_SCRIPT_3: case SPECIAL_RUN_SCRIPT_4: case SPECIAL_RUN_SCRIPT_5: case SPECIAL_RUN_SCRIPT_6: case SPECIAL_RUN_SCRIPT_7: case SPECIAL_RUN_SCRIPT_8: case SPECIAL_RUN_SCRIPT_9: case SPECIAL_RUN_SCRIPT_10: #ifdef __ENABLE_LUA__ Run_numbered_script(key_index-SPECIAL_RUN_SCRIPT_1); action++; #endif break; case SPECIAL_CYCLE_MODE: Cycling_mode= !Cycling_mode; // Restore palette if (!Cycling_mode) Set_palette(Main_palette); action++; break; } } } // End of special keys // Shortcut for clicks of Menu buttons. // Disable all of them when an operation is in progress if (Operation_stack_size==0) { // Some functions open windows that clear the Key variable, // so we need to use a temporary replacement. key_pressed = Key; for (button_index=0;button_index=Menu_Y) || ( (Main_magnifier_mode) && (Mouse_X>=Main_separator_position) && (Mouse_XHover_effect && prev_button_number > -1 && !Buttons_Pool[prev_button_number].Pressed) Draw_menu_button(prev_button_number, BUTTON_RELEASED); */ Block(18*Menu_factor_X,Menu_status_Y,192*Menu_factor_X,Menu_factor_Y<<3,MC_Light); Update_rect(18*Menu_factor_X,Menu_status_Y,192*Menu_factor_X,Menu_factor_Y<<3); Display_cursor(); } } else { if ( (prev_button_number!=BUTTON_CHOOSE_COL) || (temp_color!=First_color_in_palette) || (Old_MX!=Mouse_X) || (Old_MY!=Mouse_Y) ) { // Le curseur est sur un nouveau bouton if (button_index!=BUTTON_CHOOSE_COL) { Hide_cursor(); /*if (Gfx->Hover_effect && prev_button_number > -1 && !Buttons_Pool[prev_button_number].Pressed) Draw_menu_button(prev_button_number, BUTTON_RELEASED); */ Print_in_menu(Menu_tooltip[button_index],0); /*if (Gfx->Hover_effect && !Buttons_Pool[button_index].Pressed) Draw_menu_button(button_index, BUTTON_HIGHLIGHTED); */ Display_cursor(); } else { // Le curseur est-il sur une couleur de la palette? int color; if ((color=Pick_color_in_palette())!=-1) { Hide_cursor(); Status_print_palette_color(color); Display_cursor(); } else { if ( (Old_MX!=Mouse_X) || (Old_MY!=Mouse_Y) ) { Hide_cursor(); Block(18*Menu_factor_X,Menu_status_Y,192*Menu_factor_X,Menu_factor_Y<<3,MC_Light); Update_rect(18*Menu_factor_X,Menu_status_Y,192*Menu_factor_X,8*Menu_factor_Y); Display_cursor(); } } } } } } prev_button_number=button_index; // Gestion des clicks if (Mouse_K) { if (Mouse_Y>=Menu_Y) { if (button_index>=0) { Select_button(button_index,Mouse_K); prev_button_number=-1; } } else if (Main_magnifier_mode) Move_separator(); } } // we need to refresh that one as we may come from a sub window Cursor_in_menu=(Mouse_Y>=Menu_Y) || ( (Main_magnifier_mode) && (Mouse_X>=Main_separator_position) && (Mouse_XHover_effect && prev_button_number > -1 && !Buttons_Pool[prev_button_number].Pressed) Draw_menu_button(prev_button_number, BUTTON_RELEASED); */ if ( (Current_operation!=OPERATION_COLORPICK) && (Current_operation!=OPERATION_REPLACE) ) { Print_in_menu("X: Y: ",0); } else { Print_in_menu("X: Y: ( )",0); } Display_cursor(); Cursor_in_menu_previous = 0; } } if(Cursor_in_menu) { Cursor_in_menu_previous = 1; } else { blink=Operation[Current_operation][Mouse_K_unique][Operation_stack_size].Hide_cursor; if (blink) Hide_cursor(); Operation[Current_operation][Mouse_K_unique][Operation_stack_size].Action(); if (blink) Display_cursor(); } Old_MX=Mouse_X; Old_MY=Mouse_Y; } while (!Quitting); } ////////////////////////////////////////////////////////////////////////////// // diffrentes fonctions d'affichage utilises dans les fentres // ////////////////////////////////////////////////////////////////////////////// //----------------------- Tracer une fentre d'options ----------------------- void Open_window(word width,word height, const char * title) // Lors de l'appel cette procdure, la souris doit tre affiche. // En sortie de cette procedure, la souris est efface. { //word i,j; size_t title_length; Hide_cursor(); /*if (Windows_open == 0 && Gfx->Hover_effect) { if (Cursor_in_menu) { int button_index=Button_under_mouse(); if (button_index > -1 && !Buttons_Pool[button_index].Pressed) Draw_menu_button(button_index, BUTTON_RELEASED); } }*/ Windows_open++; Window_width=width; Window_height=height; // Positionnement de la fentre Window_pos_X=(Screen_width-(width*Menu_factor_X))>>1; Window_pos_Y=(Screen_height-(height*Menu_factor_Y))>>1; Window_draggable=1; // Sauvegarde de ce que la fentre remplace Save_background(&(Window_background[Windows_open-1]), Window_pos_X, Window_pos_Y, width, height); // Fentre grise Block(Window_pos_X+(Menu_factor_X<<1),Window_pos_Y+(Menu_factor_Y<<1),(width-4)*Menu_factor_X,(height-4)*Menu_factor_Y,MC_Window); // -- Frame de la fentre ----- --- -- - - // Frame noir puis en relief Window_display_frame_mono(0,0,width,height,MC_Black); Window_display_frame_out(1,1,width-2,height-2); // Barre sous le titre Block(Window_pos_X+(Menu_factor_X<<3),Window_pos_Y+(11*Menu_factor_Y),(width-16)*Menu_factor_X,Menu_factor_Y,MC_Dark); Block(Window_pos_X+(Menu_factor_X<<3),Window_pos_Y+(12*Menu_factor_Y),(width-16)*Menu_factor_X,Menu_factor_Y,MC_White); title_length = strlen(title); if (title_length+2 > width/8) title_length = width/8-2; Print_in_window_limited((width-(title_length<<3))>>1,3,title,title_length,MC_Black,MC_Light); if (Windows_open == 1) { Menu_is_visible_before_window=Menu_is_visible; Menu_is_visible=0; Menu_Y_before_window=Menu_Y; Menu_Y=Screen_height; Cursor_shape_before_window=Cursor_shape; Cursor_shape=CURSOR_SHAPE_ARROW; Paintbrush_hidden_before_window=Paintbrush_hidden; Paintbrush_hidden=1; if (Allow_colorcycling) { Allow_colorcycling=0; // Restore palette Set_palette(Main_palette); } Allow_drag_and_drop(0); } // Initialisation des listes de boutons de la fentre Window_normal_button_list =NULL; Window_palette_button_list =NULL; Window_scroller_button_list=NULL; Window_special_button_list =NULL; Window_dropdown_button_list=NULL; Window_nb_buttons =0; } //----------------------- Fermer une fentre d'options ----------------------- void Close_window(void) // Lors de l'appel cette procedure, la souris doit tre affiche. // En sortie de cette procedure, la souris est efface. { T_Normal_button * temp1; T_Palette_button * temp2; T_Scroller_button * temp3; T_Special_button * temp4; T_Dropdown_button * temp5; T_List_button * temp6; Hide_cursor(); while (Window_normal_button_list) { temp1=Window_normal_button_list->Next; free(Window_normal_button_list); Window_normal_button_list=temp1; } while (Window_palette_button_list) { temp2=Window_palette_button_list->Next; free(Window_palette_button_list); Window_palette_button_list=temp2; } while (Window_scroller_button_list) { temp3=Window_scroller_button_list->Next; free(Window_scroller_button_list); Window_scroller_button_list=temp3; } while (Window_special_button_list) { temp4=Window_special_button_list->Next; free(Window_special_button_list); Window_special_button_list=temp4; } while (Window_dropdown_button_list) { temp5=Window_dropdown_button_list->Next; Window_dropdown_clear_items(Window_dropdown_button_list); free(Window_dropdown_button_list); Window_dropdown_button_list=temp5; } while (Window_list_button_list) { temp6=Window_list_button_list->Next; free(Window_list_button_list); Window_list_button_list=temp6; } if (Windows_open != 1) { // Restore de ce que la fentre cachait Restore_background(Window_background[Windows_open-1], Window_pos_X, Window_pos_Y, Window_width, Window_height); Window_background[Windows_open-1]=NULL; Update_rect(Window_pos_X,Window_pos_Y,Window_width*Menu_factor_X,Window_height*Menu_factor_Y); Windows_open--; } else { free(Window_background[Windows_open-1]); Window_background[Windows_open-1]=NULL; Windows_open--; Paintbrush_hidden=Paintbrush_hidden_before_window; Compute_paintbrush_coordinates(); Menu_Y=Menu_Y_before_window; Menu_is_visible=Menu_is_visible_before_window; Cursor_shape=Cursor_shape_before_window; Display_all_screen(); Display_menu(); Allow_colorcycling=1; Allow_drag_and_drop(1); } Key=0; Mouse_K=0; Old_MX = -1; Old_MY = -1; } //---------------- Dessiner un bouton normal dans une fentre ---------------- void Window_draw_normal_bouton(word x_pos,word y_pos,word width,word height, const char * title,byte undersc_letter,byte clickable) { byte title_color; word text_x_pos,text_y_pos; if (clickable) { Window_display_frame_out(x_pos,y_pos,width,height); Window_display_frame_generic(x_pos-1,y_pos-1,width+2,height+2,MC_Black,MC_Black,MC_Dark,MC_Dark,MC_Dark); title_color=MC_Black; } else { Window_display_frame_out(x_pos,y_pos,width,height); Window_display_frame_mono(x_pos-1,y_pos-1,width+2,height+2,MC_Light); title_color=MC_Dark; } text_x_pos=x_pos+( (width-(strlen(title)<<3)+1) >>1 ); text_y_pos=y_pos+((height-7)>>1); Print_in_window(text_x_pos,text_y_pos,title,title_color,MC_Light); if (undersc_letter) Block(Window_pos_X+((text_x_pos+((undersc_letter-1)<<3))*Menu_factor_X), Window_pos_Y+((text_y_pos+8)*Menu_factor_Y), Menu_factor_X<<3,Menu_factor_Y,MC_Dark); } // -- Button normal enfonc dans la fentre -- void Window_select_normal_button(word x_pos,word y_pos,word width,word height) { Window_display_frame_generic(x_pos,y_pos,width,height,MC_Dark,MC_Black,MC_Dark,MC_Dark,MC_Black); Update_rect(Window_pos_X+x_pos*Menu_factor_X, Window_pos_Y+y_pos*Menu_factor_Y, width*Menu_factor_X, height*Menu_factor_Y); } // -- Button normal dsenfonc dans la fentre -- void Window_unselect_normal_button(word x_pos,word y_pos,word width,word height) { Window_display_frame_out(x_pos,y_pos,width,height); Update_rect(Window_pos_X+x_pos*Menu_factor_X, Window_pos_Y+y_pos*Menu_factor_Y, width*Menu_factor_X, height*Menu_factor_Y); } //--------------- Dessiner un bouton palette dans une fentre ---------------- void Window_draw_palette_bouton(word x_pos,word y_pos) { word color; for (color=0; color<=255; color++) Block( Window_pos_X+((((color >> 4)*10)+x_pos+6)*Menu_factor_X),Window_pos_Y+((((color & 15)*5)+y_pos+3)*Menu_factor_Y),Menu_factor_X*5,Menu_factor_Y*5,color); Window_display_frame(x_pos,y_pos,164,86); } // -------------------- Effacer les TAGs sur les palette --------------------- // Cette fonct ne sert plus que lorsqu'on efface les tags dans le menu Spray. void Window_clear_tags(void) { word origin_x; word origin_y; word x_pos; word window_x_pos; //word window_y_pos; origin_x=Window_pos_X+(Window_palette_button_list->Pos_X+3)*Menu_factor_X; origin_y=Window_pos_Y+(Window_palette_button_list->Pos_Y+3)*Menu_factor_Y; for (x_pos=0,window_x_pos=origin_x;x_pos<16;x_pos++,window_x_pos+=(Menu_factor_X*10)) Block(window_x_pos,origin_y,Menu_factor_X*3,Menu_factor_Y*80,MC_Light); Update_rect(origin_x,origin_y,ToWinL(160),ToWinH(80)); } // ---- Tracer les TAGs sur les palettes du menu Palette ou du menu Shade ---- void Tag_color_range(byte start,byte end) { word origin_x; word origin_y; //word x_pos; word y_pos; //word window_x_pos; word window_y_pos; word index; // On efface les anciens TAGs for (index=0;index<=start;index++) Window_rectangle(Window_palette_button_list->Pos_X+3+((index>>4)*10), Window_palette_button_list->Pos_Y+3+((index&15)* 5), 3,5,MC_Light); for (index=end;index<256;index++) Window_rectangle(Window_palette_button_list->Pos_X+3+((index>>4)*10), Window_palette_button_list->Pos_Y+3+((index&15)* 5), 3,5,MC_Light); // On affiche le 1er TAG origin_x=(Window_palette_button_list->Pos_X+3)+(start>>4)*10; origin_y=(Window_palette_button_list->Pos_Y+3)+(start&15)* 5; for (y_pos=0,window_y_pos=origin_y ;y_pos<5;y_pos++,window_y_pos++) Pixel_in_window(origin_x ,window_y_pos,MC_Black); for (y_pos=0,window_y_pos=origin_y+1;y_pos<3;y_pos++,window_y_pos++) Pixel_in_window(origin_x+1,window_y_pos,MC_Black); Pixel_in_window(origin_x+2,origin_y+2,MC_Black); if (start!=end) { // On complte le 1er TAG Pixel_in_window(origin_x+1,origin_y+4,MC_Black); // On affiche le 2me TAG origin_x=(Window_palette_button_list->Pos_X+3)+(end>>4)*10; origin_y=(Window_palette_button_list->Pos_Y+3)+(end&15)* 5; for (y_pos=0,window_y_pos=origin_y; y_pos<5; y_pos++,window_y_pos++) Pixel_in_window(origin_x ,window_y_pos,MC_Black); for (y_pos=0,window_y_pos=origin_y; y_pos<4; y_pos++,window_y_pos++) Pixel_in_window(origin_x+1,window_y_pos,MC_Black); Pixel_in_window(origin_x+2,origin_y+2,MC_Black); // On TAG toutes les couleurs intermdiaires for (index=start+1;indexPos_X+3+((index>>4)*10), Window_palette_button_list->Pos_Y+3+((index&15)* 5), 2,5,MC_Black); // On efface l'ventuelle pointe d'une ancienne extrmit de l'intervalle Pixel_in_window(Window_palette_button_list->Pos_X+5+((index>>4)*10), Window_palette_button_list->Pos_Y+5+((index&15)* 5), MC_Light); } } Update_window_area(Window_palette_button_list->Pos_X+3,Window_palette_button_list->Pos_Y+3,12*16,5*16); } //------------------ Dessiner un scroller dans une fentre ------------------- void Compute_slider_cursor_length(T_Scroller_button * button) { if (button->Nb_elements>button->Nb_visibles) { button->Cursor_length=(button->Nb_visibles*(button->Length-24))/button->Nb_elements; if (!(button->Cursor_length)) button->Cursor_length=1; } else { button->Cursor_length=button->Length-24; } } void Window_draw_slider(T_Scroller_button * button) { word slider_position; if (button->Is_horizontal) { slider_position=button->Pos_X+12; Window_rectangle(slider_position, button->Pos_Y, button->Length-24,11,MC_Black/*MC_Dark*/); if (button->Nb_elements>button->Nb_visibles) slider_position+= ((button->Length-24-button->Cursor_length)*(button->Position)+(button->Nb_elements-button->Nb_visibles)/2)/(button->Nb_elements-button->Nb_visibles); Window_rectangle(slider_position, button->Pos_Y, button->Cursor_length,11,MC_OnBlack/*MC_White*/); Update_window_area(button->Pos_X, button->Pos_Y, button->Length,11); } else { slider_position=button->Pos_Y+12; Window_rectangle(button->Pos_X, slider_position, 11,button->Length-24,MC_Black/*MC_Dark*/); if (button->Nb_elements>button->Nb_visibles) slider_position+= ((button->Length-24-button->Cursor_length)*(button->Position)+(button->Nb_elements-button->Nb_visibles)/2)/(button->Nb_elements-button->Nb_visibles); // //(button->Position*) / (button->Nb_elements-button->Nb_visibles)); Window_rectangle(button->Pos_X, slider_position, 11,button->Cursor_length,MC_OnBlack/*MC_White*/); Update_window_area(button->Pos_X, button->Pos_Y, 11,button->Length); } } void Window_draw_scroller_button(T_Scroller_button * button) { if (button->Is_horizontal) { Window_display_frame_generic(button->Pos_X-1,button->Pos_Y-1,button->Length+2,13,MC_Black,MC_Black,MC_Dark,MC_Dark,MC_Dark); Window_display_frame_mono(button->Pos_X+11,button->Pos_Y-1,button->Length-22,13,MC_Black); Window_display_frame_out(button->Pos_X,button->Pos_Y,11,11); Window_display_frame_out(button->Pos_X+button->Length-11,button->Pos_Y,11,11); Print_in_window(button->Pos_X+2,button->Pos_Y+2,"\033",MC_Black,MC_Light); Print_in_window(button->Pos_X+button->Length-9,button->Pos_Y+2,"\032",MC_Black,MC_Light); } else { Window_display_frame_generic(button->Pos_X-1,button->Pos_Y-1,13,button->Length+2,MC_Black,MC_Black,MC_Dark,MC_Dark,MC_Dark); Window_display_frame_mono(button->Pos_X-1,button->Pos_Y+11,13,button->Length-22,MC_Black); Window_display_frame_out(button->Pos_X,button->Pos_Y,11,11); Window_display_frame_out(button->Pos_X,button->Pos_Y+button->Length-11,11,11); Print_in_window(button->Pos_X+2,button->Pos_Y+2,"\030",MC_Black,MC_Light); Print_in_window(button->Pos_X+2,button->Pos_Y+button->Length-9,"\031",MC_Black,MC_Light); } Window_draw_slider(button); } //--------------- Dessiner une zone de saisie dans une fentre --------------- void Window_draw_input_bouton(word x_pos,word y_pos,word width_in_characters) { Window_display_frame_in(x_pos,y_pos,(width_in_characters<<3)+3,11); } //------------ Modifier le contenu (caption) d'une zone de saisie ------------ void Window_input_content(T_Special_button * button, char * content) { Print_in_window_limited(button->Pos_X+2,button->Pos_Y+2,content,button->Width/8,MC_Black,MC_Light); } //------------ Effacer le contenu (caption) d'une zone de saisie ------------ void Window_clear_input_button(T_Special_button * button) { Block((button->Pos_X+2)*Menu_factor_X+Window_pos_X,(button->Pos_Y+2)*Menu_factor_Y+Window_pos_Y,(button->Width/8)*8*Menu_factor_X,8*Menu_factor_Y,MC_Light); Update_rect((button->Pos_X+2)*Menu_factor_X+Window_pos_X,(button->Pos_Y+2)*Menu_factor_Y+Window_pos_Y,button->Width/8*8*Menu_factor_X,8*Menu_factor_Y); } //------ Rajout d'un bouton la liste de ceux prsents dans la fentre ------ T_Normal_button * Window_set_normal_button(word x_pos, word y_pos, word width, word height, const char * title, byte undersc_letter, byte clickable, word shortcut) { T_Normal_button * temp=NULL; Window_nb_buttons++; if (clickable) { temp=(T_Normal_button *)malloc(sizeof(T_Normal_button)); temp->Number =Window_nb_buttons; temp->Pos_X =x_pos; temp->Pos_Y =y_pos; temp->Width =width; temp->Height =height; temp->Clickable=clickable; temp->Shortcut =shortcut; temp->Repeatable=0; temp->Next=Window_normal_button_list; Window_normal_button_list=temp; } Window_draw_normal_bouton(x_pos,y_pos,width,height,title,undersc_letter,clickable); return temp; } //------ Rajout d'un bouton la liste de ceux prsents dans la fentre ------ T_Normal_button * Window_set_repeatable_button(word x_pos, word y_pos, word width, word height, const char * title, byte undersc_letter, byte clickable, word shortcut) { T_Normal_button * temp=NULL; Window_nb_buttons++; if (clickable) { temp=(T_Normal_button *)malloc(sizeof(T_Normal_button)); temp->Number =Window_nb_buttons; temp->Pos_X =x_pos; temp->Pos_Y =y_pos; temp->Width =width; temp->Height =height; temp->Shortcut=shortcut; temp->Repeatable=1; temp->Next=Window_normal_button_list; Window_normal_button_list=temp; } Window_draw_normal_bouton(x_pos,y_pos,width,height,title,undersc_letter,clickable); return temp; } T_Palette_button * Window_set_palette_button(word x_pos, word y_pos) { T_Palette_button * temp; temp=(T_Palette_button *)malloc(sizeof(T_Palette_button)); temp->Number =++Window_nb_buttons; temp->Pos_X =x_pos; temp->Pos_Y =y_pos; temp->Next=Window_palette_button_list; Window_palette_button_list=temp; Window_draw_palette_bouton(x_pos,y_pos); return temp; } T_Scroller_button * Window_set_scroller_button(word x_pos, word y_pos, word height, word nb_elements, word nb_elements_visible, word initial_position) { T_Scroller_button * temp; temp=(T_Scroller_button *)malloc(sizeof(T_Scroller_button)); temp->Number =++Window_nb_buttons; temp->Is_horizontal =0; temp->Pos_X =x_pos; temp->Pos_Y =y_pos; temp->Length =height; temp->Nb_elements =nb_elements; temp->Nb_visibles =nb_elements_visible; temp->Position =initial_position; Compute_slider_cursor_length(temp); temp->Next=Window_scroller_button_list; Window_scroller_button_list=temp; Window_draw_scroller_button(temp); return temp; } T_Scroller_button * Window_set_horizontal_scroller_button(word x_pos, word y_pos, word width, word nb_elements, word nb_elements_visible, word initial_position) { T_Scroller_button * temp; temp=(T_Scroller_button *)malloc(sizeof(T_Scroller_button)); temp->Number =++Window_nb_buttons; temp->Is_horizontal =1; temp->Pos_X =x_pos; temp->Pos_Y =y_pos; temp->Length =width; temp->Nb_elements =nb_elements; temp->Nb_visibles =nb_elements_visible; temp->Position =initial_position; Compute_slider_cursor_length(temp); temp->Next=Window_scroller_button_list; Window_scroller_button_list=temp; Window_draw_scroller_button(temp); return temp; } T_Special_button * Window_set_special_button(word x_pos,word y_pos,word width,word height) { T_Special_button * temp; temp=(T_Special_button *)malloc(sizeof(T_Special_button)); temp->Number =++Window_nb_buttons; temp->Pos_X =x_pos; temp->Pos_Y =y_pos; temp->Width =width; temp->Height =height; temp->Next=Window_special_button_list; Window_special_button_list=temp; return temp; } T_Special_button * Window_set_input_button(word x_pos,word y_pos,word width_in_characters) { T_Special_button *temp; temp=Window_set_special_button(x_pos,y_pos,(width_in_characters<<3)+3,11); Window_draw_input_bouton(x_pos,y_pos,width_in_characters); return temp; } T_Dropdown_button * Window_set_dropdown_button(word x_pos,word y_pos,word width,word height,word dropdown_width,const char *label,byte display_choice,byte display_centered,byte display_arrow,byte active_button, byte bottom_up) { T_Dropdown_button *temp; temp=(T_Dropdown_button *)malloc(sizeof(T_Dropdown_button)); temp->Number =++Window_nb_buttons; temp->Pos_X =x_pos; temp->Pos_Y =y_pos; temp->Width =width; temp->Height =height; temp->Display_choice =display_choice; temp->First_item=NULL; temp->Dropdown_width=dropdown_width?dropdown_width:width; temp->Display_centered=display_centered; temp->Display_arrow=display_arrow; temp->Active_button=active_button; temp->Bottom_up=bottom_up; temp->Next=Window_dropdown_button_list; Window_dropdown_button_list=temp; Window_draw_normal_bouton(x_pos,y_pos,width,height,"",-1,1); if (label && label[0]) Print_in_window(temp->Pos_X+2,temp->Pos_Y+(temp->Height-7)/2,label,MC_Black,MC_Light); if (display_arrow) Window_display_icon_sprite(temp->Pos_X+temp->Width-10,temp->Pos_Y+(temp->Height-7)/2,ICON_DROPDOWN); return temp; } // Ajoute un choix une dropdown. Le libell est seulement rfrenc, // il doit pointer sur une zone qui doit tre encore valide la fermeture // de la fentre (comprise). void Window_dropdown_add_item(T_Dropdown_button * dropdown, word btn_number, const char *label) { T_Dropdown_choice *temp; T_Dropdown_choice *last; temp=(T_Dropdown_choice *)malloc(sizeof(T_Dropdown_choice)); temp->Number =btn_number; temp->Label=label; temp->Next=NULL; last=dropdown->First_item; if (last) { // On cherche le dernier lment for (;last->Next;last=last->Next) ; last->Next=temp; } else { dropdown->First_item=temp; } } // ------------- Suppression de tous les choix d'une dropdown --------- void Window_dropdown_clear_items(T_Dropdown_button * dropdown) { T_Dropdown_choice * next_choice; while (dropdown->First_item) { next_choice=dropdown->First_item->Next; free(dropdown->First_item); dropdown->First_item=next_choice; } } //----------------------- Create a List control ----------------------- // These controls are special. They work over two controls previously created: // - entry_button is the textual area where the list values will be printed. // - scroller is a scroller button attached to it T_List_button * Window_set_list_button(T_Special_button * entry_button, T_Scroller_button * scroller, Func_draw_list_item draw_list_item, byte color_index) { T_List_button *temp; temp=(T_List_button *)malloc(sizeof(T_List_button)); temp->Number =++Window_nb_buttons; temp->List_start = 0; temp->Cursor_position = 0; temp->Entry_button = entry_button; temp->Scroller = scroller; temp->Draw_list_item = draw_list_item; temp->Color_index = color_index; temp->Next=Window_list_button_list; Window_list_button_list=temp; return temp; } void Window_redraw_list(T_List_button * list) { int i; for (i=Min(list->Scroller->Nb_visibles-1, list->Scroller->Nb_elements-1); i>=0; i--) { list->Draw_list_item( list->Entry_button->Pos_X, list->Entry_button->Pos_Y + i * 8, list->List_start + i, i == list->Cursor_position); } // Remaining rectangle under list i=list->Scroller->Nb_visibles-list->Scroller->Nb_elements; if (i>0) { byte color; color = list->Color_index == 0 ? MC_Black : (list->Color_index == 1 ? MC_Dark : (list->Color_index == 2 ? MC_Light : MC_White)); Window_rectangle( list->Entry_button->Pos_X, list->Entry_button->Pos_Y+list->Scroller->Nb_elements*8, list->Entry_button->Width, i*8, color); } } //----------------------- Ouverture d'un pop-up ----------------------- void Open_popup(word x_pos, word y_pos, word width,word height) // Lors de l'appel cette procdure, la souris doit tre affiche. // En sortie de cette procedure, la souris est efface. // Note : les pop-ups sont grs comme s'ils taient des sous-fentres, ils ont donc leur propre boucle d'vnements et tout, on peut ajouter des widgets dedans, ... // Les diffrences sont surtout graphiques : // -Possibilit de prciser la position XY // -Pas de titre // -Pas de cadre en relief mais seulement un plat, et il est blanc au lieu de noir. { Windows_open++; Window_width=width; Window_height=height; Window_pos_X=x_pos; Window_pos_Y=y_pos; Window_draggable=0; // Sauvegarde de ce que la fentre remplace Save_background(&(Window_background[Windows_open-1]), Window_pos_X, Window_pos_Y, width, height); /* // Fentre grise Block(Window_pos_X+1*Menu_factor_X, Window_pos_Y+1*Menu_factor_Y, (width-2)*Menu_factor_X,(height-2)*Menu_factor_Y,MC_Light); // Frame noir puis en relief Window_display_frame_mono(0,0,width,height,MC_White); */ if (Windows_open == 1) { Menu_is_visible_before_window=Menu_is_visible; Menu_is_visible=0; Menu_Y_before_window=Menu_Y; Menu_Y=Screen_height; Cursor_shape_before_window=Cursor_shape; Cursor_shape=CURSOR_SHAPE_ARROW; Paintbrush_hidden_before_window=Paintbrush_hidden; Paintbrush_hidden=1; } // Initialisation des listes de boutons de la fentre Window_normal_button_list =NULL; Window_palette_button_list =NULL; Window_scroller_button_list=NULL; Window_special_button_list =NULL; Window_dropdown_button_list =NULL; Window_nb_buttons =0; } //----------------------- Fermer une fentre d'options ----------------------- void Close_popup(void) // Lors de l'appel cette procedure, la souris doit tre affiche. // En sortie de cette procedure, la souris est efface. { T_Normal_button * temp1; T_Palette_button * temp2; T_Scroller_button * temp3; T_Special_button * temp4; T_Dropdown_button * temp5; T_List_button * temp6; Hide_cursor(); while (Window_normal_button_list) { temp1=Window_normal_button_list->Next; free(Window_normal_button_list); Window_normal_button_list=temp1; } while (Window_palette_button_list) { temp2=Window_palette_button_list->Next; free(Window_palette_button_list); Window_palette_button_list=temp2; } while (Window_scroller_button_list) { temp3=Window_scroller_button_list->Next; free(Window_scroller_button_list); Window_scroller_button_list=temp3; } while (Window_special_button_list) { temp4=Window_special_button_list->Next; free(Window_special_button_list); Window_special_button_list=temp4; } while (Window_dropdown_button_list) { Window_dropdown_clear_items(Window_dropdown_button_list); temp5=Window_dropdown_button_list->Next; free(Window_dropdown_button_list); Window_dropdown_button_list=temp5; } while (Window_list_button_list) { temp6=Window_list_button_list->Next; free(Window_list_button_list); Window_list_button_list=temp6; } if (Windows_open != 1) { // Restore de ce que la fentre cachait Restore_background(Window_background[Windows_open-1], Window_pos_X, Window_pos_Y, Window_width, Window_height); Window_background[Windows_open-1]=NULL; Update_rect(Window_pos_X,Window_pos_Y,Window_width*Menu_factor_X,Window_height*Menu_factor_Y); Windows_open--; } else { free(Window_background[Windows_open-1]); Window_background[Windows_open-1] = NULL; Windows_open--; Paintbrush_hidden=Paintbrush_hidden_before_window; Compute_paintbrush_coordinates(); Menu_Y=Menu_Y_before_window; Menu_is_visible=Menu_is_visible_before_window; Cursor_shape=Cursor_shape_before_window; Display_all_screen(); Display_menu(); } Key=0; Mouse_K=0; Old_MX = -1; Old_MY = -1; } ////////////////////////////////////////////////////////////////////////////// // // // Mini-MOTEUR utilis dans les fentres (menus des boutons...) // // // ////////////////////////////////////////////////////////////////////////////// // -- Indique si on a cliqu dans une zone dfinie par deux points extremes -- byte Window_click_in_rectangle(short start_x,short start_y,short end_x,short end_y) { short x_pos,y_pos; x_pos=((short)Mouse_X-Window_pos_X)/Menu_factor_X; y_pos=((short)Mouse_Y-Window_pos_Y)/Menu_factor_Y; return ((x_pos>=start_x) && (y_pos>=start_y) && (x_pos<=end_x) && (y_pos<=end_y)); } // --- Attend que l'on clique dans la palette pour renvoyer la couleur choisie // ou bien renvoie -1 si on a annul l'action pas click-droit ou Escape ------ short Wait_click_in_palette(T_Palette_button * button) { short start_x=button->Pos_X+5; short start_y=button->Pos_Y+3; short end_x =button->Pos_X+160; short end_y =button->Pos_Y+82; byte selected_color; byte old_hide_cursor; byte old_main_magnifier_mode; Hide_cursor(); old_hide_cursor=Cursor_hidden; old_main_magnifier_mode=Main_magnifier_mode; Main_magnifier_mode=0; Cursor_hidden=0; Cursor_shape=CURSOR_SHAPE_TARGET; Display_cursor(); for (;;) { while (Get_input(20)) ; if (Mouse_K==LEFT_SIDE) { if (Window_click_in_rectangle(start_x,start_y,end_x,end_y)) { Hide_cursor(); selected_color=(((Mouse_X-Window_pos_X)/Menu_factor_X)-(button->Pos_X+2)) / 10 * 16 + (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-(button->Pos_Y+3)) / 5; Cursor_shape=CURSOR_SHAPE_ARROW; Cursor_hidden=old_hide_cursor; Main_magnifier_mode=old_main_magnifier_mode; Display_cursor(); return selected_color; } if ((Mouse_X=Window_pos_X+(Window_width*Menu_factor_X)) || (Mouse_Y>=Window_pos_Y+(Window_height*Menu_factor_Y)) ) { Hide_cursor(); selected_color=Read_pixel(Mouse_X,Mouse_Y); Cursor_shape=CURSOR_SHAPE_ARROW; Cursor_hidden=old_hide_cursor; Main_magnifier_mode=old_main_magnifier_mode; Display_cursor(); return selected_color; } } if ((Mouse_K==RIGHT_SIDE) || (Key==KEY_ESC)) { Hide_cursor(); Cursor_shape=CURSOR_SHAPE_ARROW; Cursor_hidden=old_hide_cursor; Main_magnifier_mode=old_main_magnifier_mode; Display_cursor(); return -1; } } } // -------------- Rcupration d'une couleur derrire un menu ---------------- void Get_color_behind_window(byte * color, byte * click) { short old_x=-1; short old_y=-1; short index; short a,b,c,d; // Variables temporaires et multitches... byte * buffer = NULL; char str[25]; byte cursor_was_hidden; Hide_cursor(); cursor_was_hidden=Cursor_hidden; Cursor_hidden=0; Save_background(&buffer,Window_pos_X,Window_pos_Y,Window_width,Window_height); a=Menu_Y; Menu_Y=Menu_Y_before_window; b=Menu_is_visible; Menu_is_visible=Menu_is_visible_before_window; Display_all_screen(); Display_menu(); Menu_Y=a; Menu_is_visible=b; Cursor_shape=CURSOR_SHAPE_COLORPICKER; b=Paintbrush_hidden; Paintbrush_hidden=1; c=-1; // color pointe: au dbut aucune, comme a on initialise tout if (Menu_is_visible_before_window) Print_in_menu(Menu_tooltip[BUTTON_CHOOSE_COL],0); Display_cursor(); do { Get_input(20); if ((Mouse_X!=old_x) || (Mouse_Y!=old_y)) { Hide_cursor(); a=Read_pixel(Mouse_X,Mouse_Y); if (a!=c) { c=a; // Mise jour de la couleur pointe if (Menu_is_visible_before_window) { sprintf(str,"%d",a); d=strlen(str); strcat(str," ("); sprintf(str+strlen(str),"%d",Main_palette[a].R); strcat(str,","); sprintf(str+strlen(str),"%d",Main_palette[a].G); strcat(str,","); sprintf(str+strlen(str),"%d",Main_palette[a].B); strcat(str,")"); a=24-d; for (index=strlen(str); indexScreen_width-width) { new_x=Screen_width-width; dx = Mouse_X - new_x; } new_y=Mouse_Y-dy; if (new_y<0) { new_y=0; dy = Mouse_Y; } if (new_y>Screen_height-height) { new_y=Screen_height-height; dy = Mouse_Y - new_y; } if ((new_x!=old_x) || (new_y!=old_y)) { Hide_cursor(); Horizontal_XOR_line(old_x,old_y,width); Vertical_XOR_line(old_x,old_y+1,height-2); Vertical_XOR_line(old_x+width-1,old_y+1,height-2); Horizontal_XOR_line(old_x,old_y+height-1,width); Horizontal_XOR_line(new_x,new_y,width); Vertical_XOR_line(new_x,new_y+1,height-2); Vertical_XOR_line(new_x+width-1,new_y+1,height-2); Horizontal_XOR_line(new_x,new_y+height-1,width); Display_cursor(); Update_rect(old_x,old_y,width,height); Update_rect(new_x,new_y,width,height); } } Hide_cursor(); Horizontal_XOR_line(new_x,new_y,width); Vertical_XOR_line(new_x,new_y+1,height-2); Vertical_XOR_line(new_x+width-1,new_y+1,height-2); Horizontal_XOR_line(new_x,new_y+height-1,width); if ((new_x!=Window_pos_X) || (new_y!=Window_pos_Y)) { a=Menu_Y; Menu_Y=Menu_Y_before_window; b=Menu_is_visible; Menu_is_visible=Menu_is_visible_before_window; //Display_all_screen(); //Display_menu(); Menu_Y=a; Menu_is_visible=b; // Sauvegarde du contenu actuel de la fentre Save_background(&buffer, Window_pos_X, Window_pos_Y, Window_width, Window_height); // Restore de ce que la fentre cachait Restore_background(Window_background[Windows_open-1], Window_pos_X, Window_pos_Y, Window_width, Window_height); Window_background[Windows_open-1] = NULL; // Sauvegarde de ce que la fentre remplace Save_background(&(Window_background[Windows_open-1]), new_x, new_y, Window_width, Window_height); // Raffichage de la fentre Restore_background(buffer, new_x, new_y, Window_width, Window_height); buffer = NULL; // Mise jour du rectangle englobant Update_rect( (new_x>Window_pos_X)?Window_pos_X:new_x, (new_y>Window_pos_Y)?Window_pos_Y:new_y, ((new_x>Window_pos_X)?(new_x-Window_pos_X):(Window_pos_X-new_x)) + Window_width*Menu_factor_X, ((new_y>Window_pos_Y)?(new_y-Window_pos_Y):(Window_pos_Y-new_y)) + Window_height*Menu_factor_Y); Window_pos_X=new_x; Window_pos_Y=new_y; } else { // Update pour effacer le rectangle XOR Update_rect(Window_pos_X, Window_pos_Y, Window_width*Menu_factor_X, Window_height*Menu_factor_Y); } Cursor_shape=CURSOR_SHAPE_ARROW; Display_cursor(); } /// /// Displays a dropped-down menu and handles the UI logic until the user /// releases a mouse button. /// This function then clears the dropdown and returns the selected item, /// or NULL if the user wasn't highlighting an item when he closed. T_Dropdown_choice * Dropdown_activate(T_Dropdown_button *button, short off_x, short off_y) { short nb_choices; short choice_index; short selected_index; short old_selected_index; short box_height; T_Dropdown_choice *item; // Taille de l'ombre porte (en plus des dimensions normales) #define SHADOW_RIGHT 3 #define SHADOW_BOTTOM 4 // Comptage des items pour calculer la taille nb_choices=0; for (item=button->First_item; item!=NULL; item=item->Next) { nb_choices++; } box_height=3+nb_choices*8+1; // Open a new stacked "window" to serve as drawing area. Open_popup( off_x+(button->Pos_X)*Menu_factor_X, off_y+(button->Pos_Y+(button->Bottom_up?-box_height:button->Height))*Menu_factor_Y, button->Dropdown_width+SHADOW_RIGHT, box_height+SHADOW_BOTTOM); // Dessin de la boite // Bord gauche Block(Window_pos_X,Window_pos_Y,Menu_factor_X,box_height*Menu_factor_Y,MC_Black); // Frame fonce et blanc Window_display_frame_out(1,0,button->Dropdown_width-1,box_height); // Ombre porte if (SHADOW_BOTTOM) { Block(Window_pos_X+SHADOW_RIGHT*Menu_factor_X, Window_pos_Y+box_height*Menu_factor_Y, button->Dropdown_width*Menu_factor_X, SHADOW_BOTTOM*Menu_factor_Y, MC_Black); Block(Window_pos_X, Window_pos_Y+box_height*Menu_factor_Y, SHADOW_RIGHT*Menu_factor_X, Menu_factor_Y, MC_Black); } if (SHADOW_RIGHT) { Block(Window_pos_X+button->Dropdown_width*Menu_factor_X, Window_pos_Y+SHADOW_BOTTOM*Menu_factor_Y, SHADOW_RIGHT*Menu_factor_X, (box_height-SHADOW_BOTTOM)*Menu_factor_Y, MC_Black); Block(Window_pos_X+button->Dropdown_width*Menu_factor_X, Window_pos_Y, Menu_factor_X, SHADOW_BOTTOM*Menu_factor_Y, MC_Black); } selected_index=-1; while (1) { old_selected_index = selected_index; // Fentre grise Block(Window_pos_X+2*Menu_factor_X, Window_pos_Y+1*Menu_factor_Y, (button->Dropdown_width-3)*Menu_factor_X,(box_height-2)*Menu_factor_Y,MC_Light); // Affichage des items for(item=button->First_item,choice_index=0; item!=NULL; item=item->Next,choice_index++) { byte color_1; byte color_2; if (choice_index==selected_index) { color_1=MC_White; color_2=MC_Dark; Block(Window_pos_X+3*Menu_factor_X, Window_pos_Y+((2+choice_index*8)*Menu_factor_Y), (button->Dropdown_width-5)*Menu_factor_X,(8)*Menu_factor_Y,MC_Dark); } else { color_1=MC_Black; color_2=MC_Light; } Print_in_window(3,2+choice_index*8,item->Label,color_1,color_2); } Update_rect(Window_pos_X,Window_pos_Y,Window_width*Menu_factor_X,Window_height*Menu_factor_Y); Display_cursor(); do { // Attente Get_input(20); // Mise jour du survol selected_index=Window_click_in_rectangle(2,2,button->Dropdown_width-2,box_height-1)? (((Mouse_Y-Window_pos_Y)/Menu_factor_Y-2)>>3) : -1; } while (Mouse_K && selected_index==old_selected_index); if (!Mouse_K) break; Hide_cursor(); } Close_popup(); if (selected_index>=0 && selected_indexFirst_item; selected_index; item=item->Next,selected_index--) ; return item; } return NULL; } // Gestion des dropdown short Window_dropdown_on_click(T_Dropdown_button *button) { T_Dropdown_choice * item; // Highlight the button Hide_cursor(); Window_select_normal_button(button->Pos_X,button->Pos_Y,button->Width,button->Height); // Handle the dropdown's logic item = Dropdown_activate(button, Window_pos_X, Window_pos_Y); // Unhighlight the button Window_unselect_normal_button(button->Pos_X,button->Pos_Y,button->Width,button->Height); Display_cursor(); if (item == NULL) { Window_attribute2=-1; return 0; } if (button->Display_choice) { // Automatically update the label of the dropdown list. int text_length = (button->Width-4-(button->Display_arrow?8:0))/8; // Clear original label area Window_rectangle(button->Pos_X+2,button->Pos_Y+(button->Height-7)/2,text_length*8,8,MC_Light); Print_in_window_limited(button->Pos_X+2,button->Pos_Y+(button->Height-7)/2,item->Label,text_length ,MC_Black,MC_Light); } Window_attribute2=item->Number; return button->Number; } // --- Fonction de clic sur un bouton a peu prs ordinaire: // Attend que l'on relache le bouton, et renvoie le numero du bouton si on // est rest dessus, 0 si on a annul en sortant du bouton. short Window_normal_button_onclick(word x_pos, word y_pos, word width, word height, short btn_number) { while(1) { Hide_cursor(); Window_select_normal_button(x_pos,y_pos,width,height); Display_cursor(); while (Window_click_in_rectangle(x_pos,y_pos,x_pos+width-1,y_pos+height-1)) { Get_input(20); if (!Mouse_K) { Hide_cursor(); Window_unselect_normal_button(x_pos,y_pos,width,height); Display_cursor(); return btn_number; } } Hide_cursor(); Window_unselect_normal_button(x_pos,y_pos,width,height); Display_cursor(); while (!(Window_click_in_rectangle(x_pos,y_pos,x_pos+width-1,y_pos+height-1))) { Get_input(20); if (!Mouse_K) return 0; } } } // --- Returns the number of the clicked button (-1:out of the window, 0:none) --- short Window_get_clicked_button(void) { T_Normal_button * temp1; T_Palette_button * temp2; T_Scroller_button * temp3; T_Special_button * temp4; T_Dropdown_button * temp5; Window_attribute1=Mouse_K; // Test click on normal buttons for (temp1=Window_normal_button_list; temp1; temp1=temp1->Next) { if ((Input_sticky_control == 0 || Input_sticky_control == temp1->Number) && Window_click_in_rectangle(temp1->Pos_X,temp1->Pos_Y,temp1->Pos_X+temp1->Width-1,temp1->Pos_Y+temp1->Height-1)) { Input_sticky_control = temp1->Number; if (temp1->Repeatable) { Hide_cursor(); Window_select_normal_button(temp1->Pos_X,temp1->Pos_Y,temp1->Width,temp1->Height); Display_cursor(); Delay_with_active_mouse((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); Hide_cursor(); Window_unselect_normal_button(temp1->Pos_X,temp1->Pos_Y,temp1->Width,temp1->Height); Display_cursor(); return temp1->Number; } return Window_normal_button_onclick(temp1->Pos_X,temp1->Pos_Y,temp1->Width,temp1->Height,temp1->Number); } } // Test click on "Palette" buttons for (temp2=Window_palette_button_list; temp2; temp2=temp2->Next) { if ((Input_sticky_control == 0 || Input_sticky_control == temp2->Number) && Window_click_in_rectangle(temp2->Pos_X+5,temp2->Pos_Y+3,temp2->Pos_X+160,temp2->Pos_Y+82)) { Input_sticky_control = temp2->Number; // We store the clicked color in Attribute2 Window_attribute2 = (((Mouse_X-Window_pos_X)/Menu_factor_X)-(temp2->Pos_X+2)) / 10 * 16 + (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-(temp2->Pos_Y+3)) / 5; return temp2->Number; } } // Test click on slider/scroller bars for (temp3=Window_scroller_button_list; temp3; temp3=temp3->Next) { // Button Up arrow if ((Input_sticky_control == 0 || Input_sticky_control == (temp3->Number|1024)) && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y,temp3->Pos_X+10,temp3->Pos_Y+10)) { Input_sticky_control = temp3->Number | 1024; Hide_cursor(); Window_select_normal_button(temp3->Pos_X,temp3->Pos_Y,11,11); if (temp3->Position) { temp3->Position--; Window_attribute1=1; Window_attribute2=temp3->Position; Window_draw_slider(temp3); } else Window_attribute1=0; Display_cursor(); Delay_with_active_mouse((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); Hide_cursor(); Window_unselect_normal_button(temp3->Pos_X,temp3->Pos_Y,11,11); Display_cursor(); return (Window_attribute1)? temp3->Number : 0; } // Button Down arrow if ((Input_sticky_control == 0 || Input_sticky_control == (temp3->Number|2048)) && ((temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X+temp3->Length-11,temp3->Pos_Y,temp3->Pos_X+temp3->Length-1,temp3->Pos_Y+10)) || (!temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+temp3->Length-11,temp3->Pos_X+10,temp3->Pos_Y+temp3->Length-1)))) { Input_sticky_control = temp3->Number | 2048; Hide_cursor(); if (temp3->Is_horizontal) Window_select_normal_button(temp3->Pos_X+temp3->Length-11,temp3->Pos_Y,11,11); else Window_select_normal_button(temp3->Pos_X,temp3->Pos_Y+temp3->Length-11,11,11); if (temp3->Position+temp3->Nb_visiblesNb_elements) { temp3->Position++; Window_attribute1=2; Window_attribute2=temp3->Position; Window_draw_slider(temp3); } else Window_attribute1=0; Display_cursor(); Delay_with_active_mouse((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); Hide_cursor(); if (temp3->Is_horizontal) Window_unselect_normal_button(temp3->Pos_X+temp3->Length-11,temp3->Pos_Y,11,11); else Window_unselect_normal_button(temp3->Pos_X,temp3->Pos_Y+temp3->Length-11,11,11); Display_cursor(); return (Window_attribute1)? temp3->Number : 0; } // Middle slider if ((Input_sticky_control == temp3->Number) || (Input_sticky_control==0 && ((!temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+12,temp3->Pos_X+10,temp3->Pos_Y+temp3->Length-13)) ||(temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X+12,temp3->Pos_Y,temp3->Pos_X+temp3->Length-13,temp3->Pos_Y+10))))) { Input_sticky_control = temp3->Number; if (temp3->Nb_elements>temp3->Nb_visibles) { // If there is enough room to make the cursor move: long mouse_pos; long origin; // Window_attribute2 receives the position of the cursor. if (temp3->Is_horizontal) mouse_pos =(Mouse_X-Window_pos_X) / Menu_factor_X - (temp3->Pos_X+12); else mouse_pos =(Mouse_Y-Window_pos_Y) / Menu_factor_Y - (temp3->Pos_Y+12); // The following formula is wicked. The issue is that you want two // different behaviors: // *) If the range is bigger than the pixel precision, the last pixel // should map to max value, exactly. // *) Otherwise, the possible cursor positions are separated by // at least one full pixel, so we should find the valid position // closest to the center of the mouse cursor position pixel. origin = (temp3->Nb_visibles-1)*(temp3->Length-24)/temp3->Nb_elements/2; Window_attribute2 = (mouse_pos - origin) * (temp3->Nb_elements-(temp3->Cursor_length>1?0:1)) / (temp3->Length-24-1); if (Window_attribute2<0) Window_attribute2=0; else if (Window_attribute2+temp3->Nb_visibles>temp3->Nb_elements) Window_attribute2=temp3->Nb_elements-temp3->Nb_visibles; // If the cursor moved if (temp3->Position!=Window_attribute2) { temp3->Position=Window_attribute2; Window_attribute1=3; Hide_cursor(); Window_draw_slider(temp3); Display_cursor(); } else // If the cursor moved Window_attribute1=0; } else // If there's not enough room to make the cursor move: Window_attribute1=0; return (Window_attribute1)? temp3->Number : 0; } } // Test click on a special button for (temp4=Window_special_button_list; temp4; temp4=temp4->Next) { if ((Input_sticky_control == 0 || Input_sticky_control == temp4->Number) && Window_click_in_rectangle(temp4->Pos_X,temp4->Pos_Y,temp4->Pos_X+temp4->Width-1,temp4->Pos_Y+temp4->Height-1)) { Input_sticky_control = temp4->Number; return temp4->Number; } } // Test click on a dropdown box for (temp5=Window_dropdown_button_list; temp5; temp5=temp5->Next) { if ((Input_sticky_control == 0 || Input_sticky_control == temp5->Number) && Window_click_in_rectangle(temp5->Pos_X,temp5->Pos_Y,temp5->Pos_X+temp5->Width-1,temp5->Pos_Y+temp5->Height-1)) { Input_sticky_control = temp5->Number; if (Mouse_K & temp5->Active_button) return Window_dropdown_on_click(temp5); else { Window_attribute2=-1; return Window_normal_button_onclick(temp5->Pos_X,temp5->Pos_Y,temp5->Width,temp5->Height,temp5->Number); } } } return 0; } short Window_get_button_shortcut(void) { T_Normal_button * temp; if (Key & MOD_SHIFT) Window_attribute1=RIGHT_SIDE; else Window_attribute1=LEFT_SIDE; // On fait une premire recherche temp=Window_normal_button_list; while (temp!=NULL) { if (temp->Shortcut==Key) { Hide_cursor(); Window_select_normal_button(temp->Pos_X,temp->Pos_Y,temp->Width,temp->Height); Display_cursor(); Delay_with_active_mouse(Config.Delay_right_click_on_slider); Hide_cursor(); Window_unselect_normal_button(temp->Pos_X,temp->Pos_Y,temp->Width,temp->Height); Display_cursor(); return temp->Number; } temp=temp->Next; } // Si la recherche n'a pas t fructueuse ET que l'utilisateur appuyait sur // , on regarde si un bouton ne pourrait pas ragir comme si // n'tait pas appuy. if (Window_attribute1==RIGHT_SIDE) { temp=Window_normal_button_list; while (temp!=NULL) { if (temp->Shortcut==(Key&0x0FFF)) return temp->Number; temp=temp->Next; } } // Handle arrow keys, end/home, and mouse wheel that have // a certain behavior if a list control is present. if (Window_list_button_list) { T_List_button *list = Window_list_button_list; // If there's more than one of such control, only capture // events if the mouse cursor is over it. if (list->Next) { // to do } } return 0; } short Window_clicked_button(void) { short Button; byte old_mouse_k; old_mouse_k=Mouse_K; Get_input(20); // Handle clicks if (Mouse_K) { if ((Mouse_X=Window_pos_X+(Window_width*Menu_factor_X)) || (Mouse_Y>=Window_pos_Y+(Window_height*Menu_factor_Y))) { if (Input_sticky_control == 0 || Input_sticky_control == -1) { Input_sticky_control = -1; return -1; } else { return 0; } } if (!Input_sticky_control && Window_draggable && Mouse_Y < Window_pos_Y+(12*Menu_factor_Y)) { Move_window(Mouse_X-Window_pos_X,Mouse_Y-Window_pos_Y); } else { short clicked_button; T_List_button * list; static Uint32 time_last_click = 0; static int last_list_number = -1; Uint32 time_now; // Check which controls was clicked (by rectangular area) clicked_button = Window_get_clicked_button(); // Check if it's part of a list control for (list=Window_list_button_list; list!=NULL; list=list->Next) { if (list->Entry_button->Number == clicked_button) { // Click in the textual part of a list. short clicked_line; clicked_line = (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-list->Entry_button->Pos_Y)>>3; if (clicked_line >= list->Scroller->Nb_elements) // Below last line return 0; time_now = SDL_GetTicks(); if (clicked_line == list->Cursor_position) { // Double click check if (old_mouse_k==0 && last_list_number==list->Number && time_now - time_last_click < Config.Double_click_speed) { time_last_click = time_now; Input_sticky_control=0; // Store the selected value as attribute2 Window_attribute2=list->List_start + list->Cursor_position; // Return the control ID of the "special button" that covers the list. return list->Entry_button->Number; } time_last_click = time_now; last_list_number=list->Number; // Already selected : don't activate anything return 0; } Hide_cursor(); // Redraw one item as disabled if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) list->Draw_list_item( list->Entry_button->Pos_X, list->Entry_button->Pos_Y + list->Cursor_position * 8, list->List_start + list->Cursor_position, 0); list->Cursor_position = clicked_line; // Redraw one item as enabled if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) list->Draw_list_item( list->Entry_button->Pos_X, list->Entry_button->Pos_Y + list->Cursor_position * 8, list->List_start + list->Cursor_position, 1); Display_cursor(); // Store the selected value as attribute2 Window_attribute2=list->List_start + list->Cursor_position; // Return the control ID of the list. return list->Number; } else if (list->Scroller->Number == clicked_button) { // Click in the scroller part of a list if (list->List_start == list->Scroller->Position) return 0; // Didn't actually move // Update scroller indices list->Cursor_position += list->List_start; list->List_start = list->Scroller->Position; list->Cursor_position -= list->List_start; // Need to redraw all Hide_cursor(); Window_redraw_list(list); Display_cursor(); } } return clicked_button; } } // Intercept keys if (Key) { T_List_button * list; Button=Window_get_button_shortcut(); if (Button) { Key=0; return Button; } // Check if there's a list control and the keys can control it for (list=Window_list_button_list; list!=NULL; list=list->Next) { // FIXME: Make only one list have the keyboard focus. if (1) { if (Key==SDLK_UP && (list->Cursor_position+list->List_start)>0) { Key=0; Hide_cursor(); list->Cursor_position--; if (list->Cursor_position<0) { list->List_start=list->List_start+list->Cursor_position; list->Cursor_position=0; // Mise jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); } Window_redraw_list(list); Display_cursor(); // Store the selected value as attribute2 Window_attribute2=list->List_start + list->Cursor_position; // Return the control ID of the list. return list->Number; } if (Key==SDLK_DOWN && (list->Cursor_position+list->List_start)<(list->Scroller->Nb_elements-1)) { Key=0; Hide_cursor(); list->Cursor_position++; if (list->Cursor_position>(list->Scroller->Nb_visibles-1)) { list->List_start=list->List_start+list->Cursor_position-(list->Scroller->Nb_visibles-1); list->Cursor_position=(list->Scroller->Nb_visibles-1); // Mise jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); } Window_redraw_list(list); Display_cursor(); // Store the selected value as attribute2 Window_attribute2=list->List_start + list->Cursor_position; // Return the control ID of the list. return list->Number; } if (Key==SDLK_HOME && (list->Cursor_position!=0 || list->List_start!=0)) { Key=0; Hide_cursor(); list->Cursor_position=0; list->List_start=0; // Mise jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); Window_redraw_list(list); Display_cursor(); // Store the selected value as attribute2 Window_attribute2=list->List_start + list->Cursor_position; // Return the control ID of the list. return list->Number; } if (Key==SDLK_END && (list->Cursor_position+list->List_start)<(list->Scroller->Nb_elements-1)) { Key=0; Hide_cursor(); list->Cursor_position=(list->Scroller->Nb_elements-1)-list->List_start; if (list->Cursor_position>(list->Scroller->Nb_visibles-1)) { list->List_start=list->List_start+list->Cursor_position-(list->Scroller->Nb_visibles-1); list->Cursor_position=(list->Scroller->Nb_visibles-1); // Mise jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); } Window_redraw_list(list); Display_cursor(); // Store the selected value as attribute2 Window_attribute2=list->List_start + list->Cursor_position; // Return the control ID of the list. return list->Number; } if (Key==SDLK_PAGEDOWN && (list->Cursor_position+list->List_start)<(list->Scroller->Nb_elements-1)) { Key=0; Hide_cursor(); if (list->Scroller->Nb_elementsScroller->Nb_visibles) { list->Cursor_position=list->Scroller->Nb_elements-1; } else if(list->Cursor_position!=list->Scroller->Nb_visibles-1) { list->Cursor_position=list->Scroller->Nb_visibles-1; } else { list->List_start+=list->Scroller->Nb_visibles; if (list->List_start+list->Scroller->Nb_visibles>list->Scroller->Nb_elements) { list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles; } // Mise jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); } Window_redraw_list(list); Display_cursor(); // Store the selected value as attribute2 Window_attribute2=list->List_start + list->Cursor_position; // Return the control ID of the list. return list->Number; } if (Key==SDLK_PAGEUP && (list->Cursor_position+list->List_start)>0) { Key=0; Hide_cursor(); if(list->Cursor_position!=0) { list->Cursor_position=0; } else { list->List_start-=list->Scroller->Nb_visibles; if (list->List_start<0) { list->List_start=0; } // Mise jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); } Window_redraw_list(list); Display_cursor(); // Store the selected value as attribute2 Window_attribute2=list->List_start + list->Cursor_position; // Return the control ID of the list. return list->Number; } if (Key == KEY_MOUSEWHEELUP && list->List_start>0) { list->Cursor_position+=list->List_start; if (list->List_start>=3) list->List_start-=3; else list->List_start=0; list->Cursor_position-=list->List_start; // On affiche nouveau la liste Hide_cursor(); Window_redraw_list(list); // Mise jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); Display_cursor(); } if (Key==KEY_MOUSEWHEELDOWN && list->List_startScroller->Nb_elements-list->Scroller->Nb_visibles) { list->Cursor_position+=list->List_start; list->List_start+=3; if (list->List_start+list->Scroller->Nb_visibles>list->Scroller->Nb_elements) { list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles; } list->Cursor_position-=list->List_start; // On affiche nouveau la liste Hide_cursor(); Window_redraw_list(list); // Mise jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); Display_cursor(); } } } } return 0; } // Fonction qui sert remapper les parties sauvegardes derriere les // fenetres ouvertes. C'est utilis par exemple par la fenetre de palette // Qui remappe des couleurs, afin de propager les changements. void Remap_window_backgrounds(byte * conversion_table, int Min_Y, int Max_Y) { int window_index; byte* EDI; int dx,cx; for (window_index=0; window_indexMax_Y) return; if (dx+Window_stack[window_index].Pos_Y0;cx--) { *EDI = conversion_table[*EDI]; EDI ++; } } } } void Delay_with_active_mouse(int speed) { Uint32 end; byte original_mouse_k = Mouse_K; end = SDL_GetTicks()+speed*10; do { Get_input(20); } while (Mouse_K == original_mouse_k && SDL_GetTicks() */ /*! \file factory.c * \brief Brush factory - generates brush from lua scripts * * The brush factory allows you to generate brushes with Lua code. */ #include #include "brush.h" #include "buttons.h" #include "engine.h" #include "errors.h" #include "filesel.h" // Get_item_by_index #include "global.h" #include "graph.h" #include "io.h" // find_last_slash #include "misc.h" #include "pages.h" // Backup() #include "readline.h" #include "sdlscreen.h" #include "windows.h" #include "palette.h" #include "input.h" // Is_shortcut() #include "help.h" // Window_help() #include "graph.h" #include "filesel.h" // Read_list_of_drives() #include "realpath.h" /// Lua scripts bound to shortcut keys. char * Bound_script[10]; #ifdef __ENABLE_LUA__ #include #include #include #include // for DBL_MAX #include // chdir() #include //for INT_MIN /// /// Number of characters for name in fileselector. /// Window is adjusted according to it. #define NAME_WIDTH 34 /// Number of characters for the description block #define DESC_WIDTH ((NAME_WIDTH+2)*8/6) /// Position of fileselector top, in window space #define FILESEL_Y 18 // Work data that can be used during a script static byte * Brush_backup = NULL; static word Brush_backup_width; static word Brush_backup_height; static byte Palette_has_changed; static byte Brush_was_altered; static byte Original_fore_color; static byte Original_back_color; /// Helper function to clamp a double to 0-255 range static inline byte clamp_byte(double value) { if (value<0.0) return 0; else if (value>255.0) return 255; else return (byte)value; } /// /// This macro reads a Lua argument into a double or integral lvalue. /// If argument is invalid, it will break the caller and raise a verbose message. /// This macro uses 2 existing symbols: L for the context, and nb_args=lua_gettop(L) /// @param index Index of the argument to check, starting at 1. /// @param func_name The name of the lua callback, to display a message in case of error. /// @param dest Destination lvalue. Can be a double, or any integral type. Conversion will "floor". /// @param min_value Check for minimum value. Pass a double, or if you don't care, -DBL_MAX. /// @param max_value Check for maximum value. Pass a double, or if you don't care, DBL_MAX. #define LUA_ARG_NUMBER(index, func_name, dest, min_value, max_value) \ do { \ double value; \ if (nb_args < (index)) return luaL_error(L, "%s: Argument %d is missing.", func_name, (index)); \ if (!lua_isnumber(L, (index))) return luaL_error(L, "%s: Argument %d is not a number.", func_name, (index)); \ value = lua_tonumber(L, (index)); \ if ((min_value) != -DBL_MAX && value<(min_value)) return luaL_error(L, "%s: Argument %d was too small, it had value of %f and minimum should be %f.", func_name, (index), value, (double)(min_value)); \ if ((max_value) != DBL_MAX && value>(max_value)) return luaL_error(L, "%s: Argument %d was too big, it had value of %f and maximum should be %f.", func_name, (index), value, (double)(max_value)); \ dest = value; \ } while(0) /// /// This macro reads a Lua argument into a string. /// If argument is invalid, it will break the caller and raise a verbose message. /// This macro uses 2 existing symbols: L for the context, and nb_args=lua_gettop(L) /// @param index Index of the argument to check, starting at 1. /// @param func_name The name of the lua callback, to display a message in case of error. /// @param dest Destination string pointer, ideally a const char *. #define LUA_ARG_STRING(index, func_name, dest) \ do { \ if (nb_args < (index)) return luaL_error(L, "%s: Argument %d is missing.", func_name, index); \ if (!lua_isstring(L, (index))) return luaL_error(L, "%s: Argument %d is not a string.", func_name, index); \ dest = lua_tostring(L, (index)); \ } while (0) /// /// This macro checks that a Lua argument is a function. /// If argument is invalid, it will break the caller and raise a verbose message. /// This macro uses 2 existing symbols: L for the context, and nb_args=lua_gettop(L) /// @param index Index of the argument to check, starting at 1. /// @param func_name The name of the lua callback, to display a message in case of error. #define LUA_ARG_FUNCTION(index, func_name) \ do { \ if (nb_args < (index)) return luaL_error(L, "%s: Argument %d is missing.", func_name, index); \ if (!lua_isfunction(L, (index))) return luaL_error(L, "%s: Argument %d is not a function.", func_name, index); \ } while (0) /// Check if 'num' arguments were provided exactly #define LUA_ARG_LIMIT(num, func_name) \ do { \ if (nb_args != (num)) \ return luaL_error(L, "%s: Expected %d arguments, but found %d.", func_name, (num), nb_args); \ } while(0) // Updates the screen colors after a running screen has modified the palette. void Update_colors_during_script(void) { if (Palette_has_changed) { Set_palette(Main_palette); Compute_optimal_menu_colors(Main_palette); Display_menu(); Palette_has_changed=0; } } /// Paint a pixel in image without updating the screen void Pixel_figure_no_screen(short x_pos,short y_pos,byte color) { if (x_pos>0 && y_pos >0 && x_pos>1); Brush_offset_Y=(Brush_height>>1); return 0; } int L_GetBrushSize(lua_State* L) { lua_pushinteger(L, Brush_width); lua_pushinteger(L, Brush_height); return 2; } int L_GetBrushTransparentColor(lua_State* L) { lua_pushinteger(L, Back_color); return 1; } int L_PutBrushPixel(lua_State* L) { int x; int y; uint8_t c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (3, "putbrushpixel"); LUA_ARG_NUMBER(1, "putbrushpixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "putbrushpixel", y, INT_MIN, INT_MAX); LUA_ARG_NUMBER(3, "putbrushpixel", c, INT_MIN, INT_MAX); if (!Brush_was_altered) { int i; // First time writing in brush: // Adopt the current palette. memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette)); memcpy(Brush_original_pixels, Brush, Brush_width*Brush_height); for (i=0; i<256; i++) Brush_colormap[i]=i; //-- Brush_was_altered=1; } if (x<0 || y<0 || x>=Brush_width || y>=Brush_height) ; else { Pixel_in_brush(x, y, c); } return 0; // no values returned for lua } int L_GetBrushPixel(lua_State* L) { int x; int y; uint8_t c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (2, "getbrushpixel"); LUA_ARG_NUMBER(1, "getbrushpixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "getbrushpixel", y, INT_MIN, INT_MAX); if (x<0 || y<0 || x>=Brush_width || y>=Brush_height) { c = Back_color; // Return 'transparent' } else { c = Read_pixel_from_brush(x, y); } lua_pushinteger(L, c); return 1; } int L_GetBrushBackupPixel(lua_State* L) { int x; int y; uint8_t c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (2, "getbrushbackuppixel"); LUA_ARG_NUMBER(1, "getbrushbackuppixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "getbrushbackuppixel", y, INT_MIN, INT_MAX); if (x<0 || y<0 || x>=Brush_backup_width || y>=Brush_backup_height) { c = Back_color; // Return 'transparent' } else { c = *(Brush_backup + y * Brush_backup_width + x); } lua_pushinteger(L, c); return 1; } int L_SetPictureSize(lua_State* L) { int w; int h; int nb_args=lua_gettop(L); int i; LUA_ARG_LIMIT (2, "setpicturesize"); LUA_ARG_NUMBER(1, "setpicturesize", w, 1, 9999); LUA_ARG_NUMBER(2, "setpicturesize", h, 1, 9999); Backup_in_place(w, h); // part of Resize_image() : the pixel copy part. for (i=0; iPages->Nb_layers; i++) { Copy_part_of_image_to_another( Main_backups->Pages->Next->Image[i],0,0,Min(Main_backups->Pages->Next->Width,Main_image_width), Min(Main_backups->Pages->Next->Height,Main_image_height),Main_backups->Pages->Next->Width, Main_backups->Pages->Image[i],0,0,Main_image_width); } Redraw_layered_image(); return 0; } int L_GetPictureSize(lua_State* L) { lua_pushinteger(L, Main_image_width); lua_pushinteger(L, Main_image_height); return 2; } int L_ClearPicture(lua_State* L) { int c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (1, "clearpicture"); LUA_ARG_NUMBER(1, "clearpicture", c, INT_MIN, INT_MAX); if (Stencil_mode && Config.Clear_with_stencil) Clear_current_image_with_stencil(c,Stencil); else Clear_current_image(c); Redraw_layered_image(); return 0; // no values returned for lua } int L_PutPicturePixel(lua_State* L) { int x; int y; int c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (3, "putpicturepixel"); LUA_ARG_NUMBER(1, "putpicturepixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "putpicturepixel", y, INT_MIN, INT_MAX); LUA_ARG_NUMBER(3, "putpicturepixel", c, INT_MIN, INT_MAX); // Bound check if (x<0 || y<0 || x>=Main_image_width || y>=Main_image_height) { // Silently ignored return 0; } Pixel_in_current_screen(x, y, c, 0); return 0; // no values returned for lua } int L_DrawLine(lua_State* L) { int x1, y1, x2, y2, c; int nb_args = lua_gettop(L); LUA_ARG_LIMIT(5, "drawline"); LUA_ARG_NUMBER(1, "drawline", x1, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "drawline", y1, INT_MIN, INT_MAX); LUA_ARG_NUMBER(3, "drawline", x2, INT_MIN, INT_MAX); LUA_ARG_NUMBER(4, "drawline", y2, INT_MIN, INT_MAX); LUA_ARG_NUMBER(5, "drawline", c, INT_MIN, INT_MAX); Pixel_figure = (void (*) (word,word,byte))Pixel_figure_no_screen; Draw_line_general(x1, y1, x2, y2, c); return 0; } int L_DrawFilledRect(lua_State* L) { int x1, y1, x2, y2, c; int min_x,min_y,max_x,max_y, x_pos, y_pos; int nb_args = lua_gettop(L); LUA_ARG_LIMIT(5, "drawfilledrect"); LUA_ARG_NUMBER(1, "drawfilledrect", x1, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "drawfilledrect", y1, INT_MIN, INT_MAX); LUA_ARG_NUMBER(3, "drawfilledrect", x2, INT_MIN, INT_MAX); LUA_ARG_NUMBER(4, "drawfilledrect", y2, INT_MIN, INT_MAX); LUA_ARG_NUMBER(5, "drawfilledrect", c, INT_MIN, INT_MAX); // Put bounds in ascending order if (x2>x1) { min_x=x1; max_x=x2; } else { min_x=x2; max_x=x1; } if (y2>y1) { min_y=y1; max_y=y2; } else { min_y=y2; max_y=y1; } // Clipping limits if (max_x>Main_image_width) max_x=Main_image_width-1; if (max_y>Main_image_height) max_y=Main_image_height-1; if (min_x<0) min_x=0; if (min_y<0) min_y=0; // Perform drawing for (y_pos=min_y; y_pos<=max_y;y_pos++) for (x_pos=min_x; x_pos<=max_x;x_pos++) Pixel_in_current_screen(x_pos,y_pos,c,0); return 0; } int L_DrawCircle(lua_State* L) { int x1, y1, r, c; int nb_args = lua_gettop(L); LUA_ARG_LIMIT(4, "drawcircle"); LUA_ARG_NUMBER(1, "drawcircle", x1, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "drawcircle", y1, INT_MIN, INT_MAX); LUA_ARG_NUMBER(3, "drawcircle", r, INT_MIN, INT_MAX); LUA_ARG_NUMBER(4, "drawcircle", c, INT_MIN, INT_MAX); Pixel_figure = (void (*) (word,word,byte))Pixel_figure_no_screen; Circle_limit = r*r; Draw_empty_circle_general(x1, y1, r, c); return 0; } int L_DrawDisk(lua_State* L) { int center_x, center_y, r, c; long circle_limit; short x_pos,y_pos; short min_x,max_x,min_y,max_y; int nb_args = lua_gettop(L); LUA_ARG_LIMIT(4, "drawdisk"); LUA_ARG_NUMBER(1, "drawdisk", center_x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "drawdisk", center_y, INT_MIN, INT_MAX); LUA_ARG_NUMBER(3, "drawdisk", r, INT_MIN, INT_MAX); LUA_ARG_NUMBER(4, "drawdisk", c, INT_MIN, INT_MAX); circle_limit = r*r; // Compute clipping limits min_x=center_x-r<0 ? 0 : center_x-r; max_x=center_x+r>=Main_image_width? Main_image_width-1 : center_x+r; min_y=center_y-r<0 ? 0 : center_y-r; max_y=center_y+r>=Main_image_height? Main_image_height-1 : center_y+r; for (y_pos=min_y;y_pos<=max_y;y_pos++) for (x_pos=min_x;x_pos<=max_x;x_pos++) Pixel_in_current_screen(x_pos,y_pos,c,0); return 0; } int L_GetPicturePixel(lua_State* L) { int x; int y; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (2, "getpicturepixel"); LUA_ARG_NUMBER(1, "getpicturepixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "getpicturepixel", y, INT_MIN, INT_MAX); // Bound check if (x<0 || y<0 || x>=Main_image_width || y>=Main_image_height) { // Silently return the image's transparent color lua_pushinteger(L, Main_backups->Pages->Transparent_color); return 1; } lua_pushinteger(L, Read_pixel_from_current_screen(x,y)); return 1; } int L_GetBackupPixel(lua_State* L) { int x; int y; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (2, "getbackuppixel"); LUA_ARG_NUMBER(1, "getbackuppixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "getbackuppixel", y, INT_MIN, INT_MAX); // Bound check if (x<0 || y<0 || x>=Main_backups->Pages->Next->Width || y>=Main_backups->Pages->Next->Height) { // Silently return the image's transparent color lua_pushinteger(L, Main_backups->Pages->Next->Transparent_color); return 1; } // Can't use Read_pixel_from_backup_screen(), because in a Lua script // the "backup" can use a different screen dimension. lua_pushinteger(L, *(Screen_backup + x + Main_backups->Pages->Next->Width * y)); return 1; } int L_GetLayerPixel(lua_State* L) { int x; int y; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (2, "getlayerpixel"); LUA_ARG_NUMBER(1, "getlayerpixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "getlayerpixel", y, INT_MIN, INT_MAX); // Bound check if (x<0 || y<0 || x>=Main_image_width || y>=Main_image_height) { // Silently return the image's transparent color lua_pushinteger(L, Main_backups->Pages->Transparent_color); return 1; } lua_pushinteger(L, Read_pixel_from_current_layer(x,y)); return 1; } // Spare int L_GetSparePictureSize(lua_State* L) { lua_pushinteger(L, Spare_image_width); lua_pushinteger(L, Spare_image_height); return 2; } int L_GetSpareLayerPixel(lua_State* L) { int x; int y; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (2, "getsparelayerpixel"); LUA_ARG_NUMBER(1, "getsparelayerpixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "getsparelayerpixel", y, INT_MIN, INT_MAX); // Bound check if (x<0 || y<0 || x>=Spare_image_width || y>=Spare_image_height) { // Silently return the image's transparent color lua_pushinteger(L, Spare_backups->Pages->Transparent_color); return 1; } lua_pushinteger(L, *(Spare_backups->Pages->Image[Spare_current_layer] + y*Spare_image_width + x)); return 1; } int L_GetSparePicturePixel(lua_State* L) { int x; int y; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (2, "getsparepicturepixel"); LUA_ARG_NUMBER(1, "getsparepicturepixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "getsparepicturepixel", y, INT_MIN, INT_MAX); // Some bound checking is done by the function itself, here's the rest. if (x<0 || y<0) { // Silently return the image's transparent color lua_pushinteger(L, Spare_backups->Pages->Transparent_color); return 1; } lua_pushinteger(L, Read_pixel_from_spare_screen(x,y)); return 1; } int L_GetSpareColor(lua_State* L) { byte c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (1, "getsparecolor"); LUA_ARG_NUMBER(1, "getsparecolor", c, INT_MIN, INT_MAX); lua_pushinteger(L, Spare_palette[c].R); lua_pushinteger(L, Spare_palette[c].G); lua_pushinteger(L, Spare_palette[c].B); return 3; } int L_GetSpareTransColor(lua_State* L) { lua_pushinteger(L, Spare_backups->Pages->Transparent_color); return 1; } int L_SetColor(lua_State* L) { byte c; double r, g, b; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (4, "setcolor"); LUA_ARG_NUMBER(1, "setcolor", c, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "setcolor", r, INT_MIN, INT_MAX); LUA_ARG_NUMBER(3, "setcolor", g, INT_MIN, INT_MAX); LUA_ARG_NUMBER(4, "setcolor", b, INT_MIN, INT_MAX); Main_palette[c].R=Round_palette_component(clamp_byte(r)); Main_palette[c].G=Round_palette_component(clamp_byte(g)); Main_palette[c].B=Round_palette_component(clamp_byte(b)); // Set_color(c, r, g, b); Not needed. Update screen when script is finished Palette_has_changed=1; return 0; } int L_GetColor(lua_State* L) { byte c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (1, "getcolor"); LUA_ARG_NUMBER(1, "getcolor", c, INT_MIN, INT_MAX); lua_pushinteger(L, Main_palette[c].R); lua_pushinteger(L, Main_palette[c].G); lua_pushinteger(L, Main_palette[c].B); return 3; } int L_GetBackupColor(lua_State* L) { byte c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (1, "getbackupcolor"); LUA_ARG_NUMBER(1, "getbackupcolor", c, INT_MIN, INT_MAX); lua_pushinteger(L, Main_backups->Pages->Next->Palette[c].R); lua_pushinteger(L, Main_backups->Pages->Next->Palette[c].G); lua_pushinteger(L, Main_backups->Pages->Next->Palette[c].B); return 3; } int L_MatchColor(lua_State* L) { double r, g, b; int c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (3, "matchcolor"); LUA_ARG_NUMBER(1, "matchcolor", r, -DBL_MAX, DBL_MAX); LUA_ARG_NUMBER(2, "matchcolor", g, -DBL_MAX, DBL_MAX); LUA_ARG_NUMBER(3, "matchcolor", b, -DBL_MAX, DBL_MAX); c = Best_color_nonexcluded(clamp_byte(r),clamp_byte(g),clamp_byte(b)); lua_pushinteger(L, c); return 1; } int L_GetForeColor(lua_State* L) { lua_pushinteger(L, Fore_color); return 1; } int L_GetBackColor(lua_State* L) { lua_pushinteger(L, Back_color); return 1; } int L_GetTransColor(lua_State* L) { lua_pushinteger(L, Main_backups->Pages->Transparent_color); return 1; } int L_SetForeColor(lua_State* L) { byte c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (1, "setforecolor"); LUA_ARG_NUMBER(1, "setforecolor", c, -DBL_MAX, DBL_MAX); Fore_color = c; return 0; } int L_SetBackColor(lua_State* L) { byte c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (1, "setbackcolor"); LUA_ARG_NUMBER(1, "setbackcolor", c, -DBL_MAX, DBL_MAX); Back_color = c; return 0; } int L_InputBox(lua_State* L) { const int max_settings = 9; const int args_per_setting = 5; double min_value[max_settings]; double max_value[max_settings]; double decimal_places[max_settings]; double current_value[max_settings]; const char * label[max_settings]; unsigned short control[max_settings*3+1]; // Each value has at most 3 widgets. enum CONTROL_TYPE { CONTROL_OK = 0x0100, CONTROL_CANCEL = 0x0200, CONTROL_INPUT = 0x0300, CONTROL_INPUT_MINUS = 0x0400, CONTROL_INPUT_PLUS = 0x0500, CONTROL_CHECKBOX = 0x0600, CONTROL_VALUE_MASK = 0x00FF, CONTROL_TYPE_MASK = 0xFF00 }; const char * window_caption; int caption_length; int nb_settings; int nb_args; unsigned int max_label_length; int setting; short clicked_button; char str[40]; short close_window = 0; nb_args = lua_gettop (L); if (nb_args < 6) { return luaL_error(L, "inputbox: Less than 6 arguments"); } if ((nb_args - 1) % args_per_setting) { return luaL_error(L, "inputbox: Wrong number of arguments"); } nb_settings = (nb_args-1)/args_per_setting; if (nb_settings > max_settings) { return luaL_error(L, "inputbox: Too many settings, limit reached"); } max_label_length=4; // Minimum size to account for OK / Cancel buttons // First argument is window caption LUA_ARG_STRING(1, "inputbox", window_caption); caption_length = strlen(window_caption); if ( caption_length > 14) max_label_length = caption_length - 10; for (setting=0; setting max_label_length) max_label_length = strlen(label[setting]); LUA_ARG_NUMBER(setting*args_per_setting+3, "inputbox", current_value[setting], -DBL_MAX, DBL_MAX); LUA_ARG_NUMBER(setting*args_per_setting+4, "inputbox", min_value[setting], -DBL_MAX, DBL_MAX); /*if (min_value[setting] < -999999999999999.0) min_value[setting] = -999999999999999.0;*/ LUA_ARG_NUMBER(setting*args_per_setting+5, "inputbox", max_value[setting], -DBL_MAX, DBL_MAX); /*if (max_value[setting] > 999999999999999.0) max_value[setting] = 999999999999999.0;*/ LUA_ARG_NUMBER(setting*args_per_setting+6, "inputbox", decimal_places[setting], -15.0, 15.0); if (decimal_places[setting]>15) decimal_places[setting]=15; if (min_value[setting]!=0 || max_value[setting]!=1) if (decimal_places[setting]<0) decimal_places[setting]=0; // Keep current value in range if (decimal_places[setting]>=0) current_value[setting] = Fround(current_value[setting], decimal_places[setting]); if (current_value[setting] < min_value[setting]) current_value[setting] = min_value[setting]; else if (current_value[setting] > max_value[setting]) current_value[setting] = max_value[setting]; } // Max is 25 to keep window under 320 pixel wide if (max_label_length>25) max_label_length=25; Update_colors_during_script(); Open_window(115+max_label_length*8,44+nb_settings*17,window_caption); // Normally this index is unused, but this initialization avoids // any weird behavior if it was used by mistake. control[0]=0; // OK Window_set_normal_button( 7, 25 + 17 * nb_settings, 51,14,"OK" , 0,1,SDLK_RETURN); control[Window_nb_buttons] = CONTROL_OK; // Cancel Window_set_normal_button( 64, 25 + 17 * nb_settings, 51,14,"Cancel" , 0,1,KEY_ESC); control[Window_nb_buttons] = CONTROL_CANCEL; for (setting=0; setting0) { setting = control[clicked_button] & (CONTROL_VALUE_MASK); switch (control[clicked_button] & CONTROL_TYPE_MASK) { case CONTROL_OK: close_window = CONTROL_OK; break; case CONTROL_CANCEL: close_window = CONTROL_CANCEL; break; case CONTROL_INPUT: Sprint_double(str,current_value[setting],decimal_places[setting],0); Readline_ex(12+max_label_length*8+23, 22+setting*17,str,7,40,INPUT_TYPE_DECIMAL,decimal_places[setting]); current_value[setting]=atof(str); if (current_value[setting] < min_value[setting]) current_value[setting] = min_value[setting]; else if (current_value[setting] > max_value[setting]) current_value[setting] = max_value[setting]; // Print editable value Sprint_double(str,current_value[setting],decimal_places[setting],7); Print_in_window_limited(12+max_label_length*8+23, 22+setting*17, str, 7,MC_Black,MC_Light); // Display_cursor(); break; case CONTROL_INPUT_MINUS: if (current_value[setting] > min_value[setting]) { current_value[setting]--; if (current_value[setting] < min_value[setting]) current_value[setting] = min_value[setting]; Hide_cursor(); // Print editable value Sprint_double(str,current_value[setting],decimal_places[setting],7); Print_in_window_limited(12+max_label_length*8+23, 22+setting*17, str, 7,MC_Black,MC_Light); // Display_cursor(); } break; case CONTROL_INPUT_PLUS: if (current_value[setting] < max_value[setting]) { current_value[setting]++; if (current_value[setting] > max_value[setting]) current_value[setting] = max_value[setting]; Hide_cursor(); // Print editable value Sprint_double(str,current_value[setting],decimal_places[setting],7); Print_in_window_limited(12+max_label_length*8+23, 22+setting*17, str, 7,MC_Black,MC_Light); // Display_cursor(); } break; case CONTROL_CHECKBOX: if (decimal_places[setting]==0 || current_value[setting]==0.0) { current_value[setting] = (current_value[setting]==0.0); Hide_cursor(); Print_in_window(12+max_label_length*8+46, 22+setting*17, current_value[setting]?"X":" ",MC_Black,MC_Light); // Uncheck other buttons of same family if (decimal_places[setting]<0) { byte button; for (button=3; button<=Window_nb_buttons; button++) { if (button != clicked_button && control[button] & CONTROL_CHECKBOX) { byte other_setting = control[button] & (CONTROL_VALUE_MASK); if (decimal_places[other_setting] == decimal_places[setting]) { // Same family: unset and uncheck current_value[other_setting]=0.0; Print_in_window(12+max_label_length*8+46, 22+other_setting*17, " ",MC_Black,MC_Light); } } } } Display_cursor(); } break; } } } Close_window(); Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); // Return values: // One boolean to tell if user pressed ok or cancel lua_pushboolean(L, (close_window == CONTROL_OK)); // One value per control for (setting=0; setting max_label_length) max_label_length = caption_length; for (button=0; button max_label_length) max_label_length = strlen(label[button]); LUA_ARG_FUNCTION(button*2+3, "selectbox"); } // Max is 25 to keep window under 320 pixel wide if (max_label_length>25) max_label_length=25; Update_colors_during_script(); Open_window(28+max_label_length*8,26+nb_buttons*17,window_caption); for (button=0; button24) msg2[24] = 0; // Cut off long messages Print_in_menu(msg2,0); free(msg2); return 0; } int L_FinalizePicture(lua_State* L) { int nb_args=lua_gettop(L); LUA_ARG_LIMIT (0, "finalizepicture"); Update_colors_during_script(); End_of_modification(); Backup(); return 0; } // Handlers for window internals T_Fileselector Scripts_selector; // Callback to display a skin name in the list void Draw_script_name(word x, word y, word index, byte highlighted) { T_Fileselector_item * current_item; if (Scripts_selector.Nb_elements) { byte fg, bg; current_item = Get_item_by_index(&Scripts_selector, index); if (current_item->Type==0) // Files { fg=(highlighted)?MC_White:MC_Light; bg=(highlighted)?MC_Dark:MC_Black; } else if (current_item->Type==1) // Directories { fg=(highlighted)?MC_Light:MC_Dark; bg=(highlighted)?MC_Dark:MC_Black; } else // Drives { fg=(highlighted)?MC_Light:MC_Dark; bg=(highlighted)?MC_Dark:MC_Black; Window_display_icon_sprite(x,y,current_item->Icon); x+=8; } Print_in_window(x, y, current_item->Short_name, fg,bg); Update_window_area(x,y,NAME_WIDTH*8,8); } } /// /// Displays first lines of comments from a lua script in the window. void Draw_script_information(T_Fileselector_item * script_item, const char *full_directory) { FILE *script_file; char text_block[3][DESC_WIDTH+1]; int x, y; int i; // Blank the target area Window_rectangle(7, FILESEL_Y + 89, DESC_WIDTH*6+2, 4*8, MC_Black); if (script_item && script_item->Type==0 && script_item->Full_name && script_item->Full_name[0]!='\0') { char full_name[MAX_PATH_CHARACTERS]; strcpy(full_name, full_directory); Append_path(full_name, script_item->Full_name, NULL); x=0; y=0; text_block[0][0] = text_block[1][0] = text_block[2][0] = '\0'; // Start reading script_file = fopen(full_name, "r"); if (script_file != NULL) { int c; c = fgetc(script_file); while (c != EOF && y<3) { if (c == '\n') { if (x<2) break; // Carriage return without comment: Stopping y++; x=0; } else if (x==0 || x==1) { if (c != '-') break; // Non-comment line was encountered. Stopping. x++; } else { if (x < DESC_WIDTH+2) { // Adding character text_block[y][x-2] = (c<32 || c>255) ? ' ' : c; text_block[y][x-1] = '\0'; } x++; } // Read next c = fgetc(script_file); } fclose(script_file); } Print_help(8, FILESEL_Y + 89 , text_block[0], 'N', 0, 0); Print_help(8, FILESEL_Y + 89+ 8, text_block[1], 'N', 0, 0); Print_help(8, FILESEL_Y + 89+16, text_block[2], 'N', 0, 0); // Display a line with the keyboard shortcut Print_help(8, FILESEL_Y + 89+24, "Key:", 'N', 0, 0); for (i=0; i<10; i++) if (Bound_script[i]!=NULL && !strcmp(Bound_script[i], full_name)) break; if (i<10) { const char *shortcut; shortcut=Keyboard_shortcut_value(SPECIAL_RUN_SCRIPT_1+i); Print_help(8+4*6, FILESEL_Y + 89+24, shortcut, 'K', 0, strlen(shortcut)); } else { Print_help(8+4*6, FILESEL_Y + 89+24, "None", 'K', 0, 4); } } Update_window_area(8, FILESEL_Y + 89, DESC_WIDTH*6+2, 4*8); } // Add a script to the list void Add_script(const char *name, byte is_file, byte is_directory, byte is_hidden) { const char * file_name; int len; file_name=Find_last_slash(name)+1; if (is_file) { // Only files ending in ".lua" len=strlen(file_name); if (len<=4 || strcasecmp(file_name+len-4, ".lua")) return; // Hidden if (is_hidden && !Config.Show_hidden_files) return; Add_element_to_list(&Scripts_selector, file_name, Format_filename(file_name, NAME_WIDTH+1, 0), 0, ICON_NONE); } else if (is_directory) { // Ignore current directory if ( !strcmp(file_name, ".")) return; // Ignore parent directory entry if (!strcmp(file_name, PARENT_DIR)) return; // Hidden if (is_hidden && !Config.Show_hidden_directories) return; Add_element_to_list(&Scripts_selector, file_name, Format_filename(file_name, NAME_WIDTH+1, 1), 1, ICON_NONE); } } void Highlight_script(T_Fileselector *selector, T_List_button *list, const char *selected_file) { short index; index=Find_file_in_fileselector(selector, selected_file); Locate_list_item(list, index); } static char Last_run_script[MAX_PATH_CHARACTERS]=""; // Before: Cursor hidden // After: Cursor shown void Run_script(const char *script_subdirectory, const char *script_filename) { lua_State* L; const char* message; byte old_cursor_shape=Cursor_shape; char buf[MAX_PATH_CHARACTERS]; // Some scripts are slow Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); Flush_update(); if (script_subdirectory && script_subdirectory[0]!='\0') { strcpy(Last_run_script, script_subdirectory); Append_path(Last_run_script, script_filename, NULL); } else { strcpy(Last_run_script, script_filename); } // This chdir is for the script's sake. Grafx2 itself will (try to) // not rely on what is the system's current directory. Extract_path(buf,Last_run_script); chdir(buf); L = lua_open(); strcpy(buf, "LUA_PATH="); strcat(buf, Data_directory); Append_path(buf+9, "scripts", NULL); Append_path(buf+9, "libs", NULL); Append_path(buf+9, "?.lua", NULL); putenv(buf); // writing and reading pixels lua_register(L,"putbrushpixel",L_PutBrushPixel); lua_register(L,"putpicturepixel",L_PutPicturePixel); lua_register(L, "drawline",L_DrawLine); lua_register(L, "drawfilledrect",L_DrawFilledRect); lua_register(L, "drawcircle",L_DrawCircle); lua_register(L, "drawdisk",L_DrawDisk); lua_register(L,"getbrushpixel",L_GetBrushPixel); lua_register(L,"getbrushbackuppixel",L_GetBrushBackupPixel); lua_register(L,"getpicturepixel",L_GetPicturePixel); lua_register(L,"getlayerpixel",L_GetLayerPixel); lua_register(L,"getbackuppixel",L_GetBackupPixel); lua_register(L,"getsparelayerpixel",L_GetSpareLayerPixel); lua_register(L,"getsparepicturepixel",L_GetSparePicturePixel); // resizing stuff lua_register(L,"setbrushsize",L_SetBrushSize); lua_register(L,"setpicturesize",L_SetPictureSize); lua_register(L,"getbrushsize",L_GetBrushSize); lua_register(L,"getpicturesize",L_GetPictureSize); lua_register(L,"getsparepicturesize",L_GetSparePictureSize); // color and palette lua_register(L,"setcolor",L_SetColor); lua_register(L,"setforecolor",L_SetForeColor); lua_register(L,"setbackcolor",L_SetBackColor); lua_register(L,"getcolor",L_GetColor); lua_register(L,"getbackupcolor",L_GetBackupColor); lua_register(L,"getbrushtransparentcolor",L_GetBrushTransparentColor); lua_register(L,"getsparecolor",L_GetSpareColor); lua_register(L,"getsparetranscolor",L_GetSpareTransColor); lua_register(L,"getforecolor",L_GetForeColor); lua_register(L,"getbackcolor",L_GetBackColor); lua_register(L,"gettranscolor",L_GetTransColor); lua_register(L,"matchcolor",L_MatchColor); // ui lua_register(L,"inputbox",L_InputBox); lua_register(L,"messagebox",L_MessageBox); lua_register(L,"statusmessage",L_StatusMessage); lua_register(L,"selectbox",L_SelectBox); // misc. stuff lua_register(L,"clearpicture",L_ClearPicture); lua_register(L,"wait",L_Wait); lua_register(L,"waitbreak",L_WaitBreak); lua_register(L,"waitinput",L_WaitInput); lua_register(L,"updatescreen",L_UpdateScreen); lua_register(L,"finalizepicture",L_FinalizePicture); // Load all standard libraries luaL_openlibs(L); /* luaopen_base(L); //luaopen_package(L); // crashes on Windows, for unknown reason luaopen_table(L); //luaopen_io(L); // crashes on Windows, for unknown reason //luaopen_os(L); luaopen_string(L); luaopen_math(L); //luaopen_debug(L); */ // TODO The script may modify the picture, so we do a backup here. // If the script is only touching the brush, this isn't needed... // The backup also allows the script to read from it to make something // like a feedback off effect (convolution matrix comes to mind). Backup(); Palette_has_changed=0; Brush_was_altered=0; Original_back_color=Back_color; Original_fore_color=Fore_color; // Backup the brush Brush_backup=(byte *)malloc(((long)Brush_height)*Brush_width); Brush_backup_width = Brush_width; Brush_backup_height = Brush_height; if (Brush_backup == NULL) { Verbose_message("Error!", "Out of memory!"); } else { memcpy(Brush_backup, Brush, ((long)Brush_height)*Brush_width); if (luaL_loadfile(L,Last_run_script) != 0) { int stack_size; stack_size= lua_gettop(L); if (stack_size>0 && (message = lua_tostring(L, stack_size))!=NULL) Verbose_message("Error!", message); else Warning_message("Unknown error loading script!"); } else if (lua_pcall(L, 0, 0, 0) != 0) { int stack_size; stack_size= lua_gettop(L); Update_colors_during_script(); if (stack_size>0 && (message = lua_tostring(L, stack_size))!=NULL) Verbose_message("Error running script", message); else Warning_message("Unknown error running script!"); } } // Cleanup free(Brush_backup); Brush_backup=NULL; Update_colors_during_script(); End_of_modification(); Print_in_menu(" ",0); lua_close(L); if (Brush_was_altered) { // Copy Brush to original memcpy(Brush_original_pixels, Brush, (long)Brush_width*Brush_height); Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); } Hide_cursor(); Display_all_screen(); // Update changed pen colors. if (Back_color!=Original_back_color || Fore_color!=Original_fore_color) { // This is done at end of script, in case somebody would use the // functions in a custom window. if (Back_color!=Original_back_color) { byte new_color = Back_color; Back_color = Original_back_color; Set_back_color(new_color); } if (Fore_color!=Original_fore_color) { byte new_color = Fore_color; Fore_color = Original_fore_color; Set_fore_color(new_color); } } Cursor_shape=old_cursor_shape; Display_cursor(); } void Run_numbered_script(byte index) { if (index>=10) return; if (Bound_script[index]==NULL) return; Hide_cursor(); Run_script(NULL, Bound_script[index]); } void Repeat_script(void) { if (Last_run_script==NULL || Last_run_script[0]=='\0') { Warning_message("No script to repeat."); return; } Hide_cursor(); Run_script(NULL, Last_run_script); } void Set_script_shortcut(T_Fileselector_item * script_item, const char *full_directory) { int i; char full_name[MAX_PATH_CHARACTERS]; if (script_item && script_item->Full_name && script_item->Full_name[0]!='\0') { strcpy(full_name, full_directory); Append_path(full_name, script_item->Full_name, NULL); // Find if it already has a shortcut for (i=0; i<10; i++) if (Bound_script[i]!=NULL && !strcmp(Bound_script[i], full_name)) break; if (i<10) { // Existing shortcut } else { // Try to find a "free" one. for (i=0; i<10; i++) if (Bound_script[i]==NULL || !Has_shortcut(SPECIAL_RUN_SCRIPT_1+i) || !File_exists(full_name)) break; if (i<10) { free(Bound_script[i]); Bound_script[i]=strdup(full_name); } else { Warning_message("Already 10 scripts have shortcuts."); return; } } Window_set_shortcut(SPECIAL_RUN_SCRIPT_1+i); if (!Has_shortcut(SPECIAL_RUN_SCRIPT_1+i)) { // User cancelled or deleted all shortcuts free(Bound_script[i]); Bound_script[i]=NULL; } // Refresh display Hide_cursor(); Draw_script_information(script_item, full_directory); Display_cursor(); } } void Reload_scripts_list(void) { // Reinitialize the list Free_fileselector_list(&Scripts_selector); if (Config.Scripts_directory[0]=='\0') { Read_list_of_drives(&Scripts_selector,NAME_WIDTH+1); } else { Add_element_to_list(&Scripts_selector, PARENT_DIR, Format_filename(PARENT_DIR, NAME_WIDTH+1, 1), 1, ICON_NONE); // Add each found file to the list For_each_directory_entry(Config.Scripts_directory, Add_script); } // Sort it Sort_list_of_files(&Scripts_selector); // } void Button_Brush_Factory(void) { static char selected_file[MAX_PATH_CHARACTERS]=""; short clicked_button; T_List_button* scriptlist; T_Scroller_button* scriptscroll; T_Special_button* scriptarea; T_Fileselector_item *item; int last_selected_item=-1; Reload_scripts_list(); Open_window(33+8*NAME_WIDTH, 180, "Brush Factory"); Window_set_normal_button(85, 149, 67, 14, "Cancel", 0, 1, KEY_ESC); // 1 Window_display_frame_in(6, FILESEL_Y - 2, NAME_WIDTH*8+4, 84); // File selector // Fileselector scriptarea=Window_set_special_button(8, FILESEL_Y + 0, NAME_WIDTH*8, 80); // 2 // Scroller for the fileselector scriptscroll = Window_set_scroller_button(NAME_WIDTH*8+14, FILESEL_Y - 1, 82, Scripts_selector.Nb_elements,10, 0); // 3 scriptlist = Window_set_list_button(scriptarea,scriptscroll,Draw_script_name, 0); // 4 Window_set_normal_button(10, 149, 67, 14, "Run", 0, 1, SDLK_RETURN); // 5 Window_display_frame_in(6, FILESEL_Y + 88, DESC_WIDTH*6+4, 4*8+2); // Descr. Window_set_special_button(7, FILESEL_Y + 89+24,DESC_WIDTH*6,8); // 6 while (1) { // Locate selected file in view Highlight_script(&Scripts_selector, scriptlist, selected_file); // Update the scroller position scriptscroll->Position=scriptlist->List_start; Window_draw_slider(scriptscroll); Window_redraw_list(scriptlist); Draw_script_information(Get_item_by_index(&Scripts_selector, scriptlist->List_start + scriptlist->Cursor_position), Config.Scripts_directory); Update_window_area(0, 0, Window_width, Window_height); Display_cursor(); // Wait for mouse release (needed for example after a double-click // that navigates to a subdirectory) while (last_selected_item==-1 && Mouse_K) { Get_input(20); } Reset_quicksearch(); do { clicked_button = Window_clicked_button(); if (Key==SDLK_BACKSPACE && Config.Scripts_directory[0]!='\0') { // Make it select first entry (parent directory) scriptlist->List_start=0; scriptlist->Cursor_position=0; clicked_button=5; } if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_BRUSH_EFFECTS, "BRUSH FACTORY"); else if (Is_shortcut(Key,0x200+BUTTON_BRUSH_EFFECTS)) clicked_button=1; // Cancel // Quicksearch if (clicked_button==4) Reset_quicksearch(); else if (clicked_button==0 && Key_ANSI) clicked_button=Quicksearch_list(scriptlist, &Scripts_selector); switch (clicked_button) { case 2: // Double-click an entry in script list clicked_button=5; break; case 4: // Select script last_selected_item = scriptlist->List_start + scriptlist->Cursor_position; Hide_cursor(); Draw_script_information(Get_item_by_index(&Scripts_selector, scriptlist->List_start + scriptlist->Cursor_position), Config.Scripts_directory); Display_cursor(); break; case 6: Set_script_shortcut(Get_item_by_index(&Scripts_selector, scriptlist->List_start + scriptlist->Cursor_position), Config.Scripts_directory); break; default: break; } } while (clicked_button != 1 && clicked_button != 5); // Cancel if (clicked_button==1) break; // OK if (Scripts_selector.Nb_elements == 0) { // No items : same as Cancel clicked_button=1; break; } // Examine selected file item = Get_item_by_index(&Scripts_selector, scriptlist->List_start + scriptlist->Cursor_position); if (item->Type==0) // File { strcpy(selected_file, item->Full_name); break; } else if (item->Type==1 || item->Type==2) // Directory { if (item->Type==2) { // Selecting one drive root strcpy(selected_file, PARENT_DIR); strcat(Config.Scripts_directory, item->Full_name); } else { // Going down one or up by one directory Append_path(Config.Scripts_directory, item->Full_name, selected_file); } // No break: going back up to beginning of loop Reload_scripts_list(); scriptlist->Scroller->Nb_elements=Scripts_selector.Nb_elements; Compute_slider_cursor_length(scriptlist->Scroller); last_selected_item = -1; Hide_cursor(); } } Close_window(); Unselect_button(BUTTON_BRUSH_EFFECTS); if (clicked_button == 5) // Run the script { Run_script(Config.Scripts_directory, selected_file); } else { Display_cursor(); } } #else // NOLUA void Button_Brush_Factory(void) { Verbose_message("Error!", "The brush factory is not available in this build of GrafX2."); } #endif grafx2/src/fileformats.c0000644000076400010400000041413411536457152015720 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2009 Petter Lindquist 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 */ ///@file fileformats.c /// Saving and loading different picture formats. #ifndef __no_pnglib__ #include #if !defined(PNG_HAVE_PLTE) #define PNG_HAVE_PLTE 0x02 #endif #if (PNG_LIBPNG_VER_MAJOR <= 1) && (PNG_LIBPNG_VER_MINOR < 4) // Compatibility layer to allow us to use libng 1.4 or any older one. // This function is renamed in 1.4 #define png_set_expand_gray_1_2_4_to_8(x) png_set_gray_1_2_4_to_8(x) // Wrappers that are mandatory in 1.4. Older version allowed direct access. #define png_get_rowbytes(png_ptr,info_ptr) ((info_ptr)->rowbytes) #define png_get_image_width(png_ptr,info_ptr) ((info_ptr)->width) #define png_get_image_height(png_ptr,info_ptr) ((info_ptr)->height) #define png_get_bit_depth(png_ptr,info_ptr) ((info_ptr)->bit_depth) #define png_get_color_type(png_ptr,info_ptr) ((info_ptr)->color_type) #endif #endif #include #include "errors.h" #include "global.h" #include "loadsave.h" #include "misc.h" #include "struct.h" #include "io.h" #include "windows.h" // Best_color() #include "pages.h" // Add_layer() //////////////////////////////////// IMG //////////////////////////////////// // -- Tester si un fichier est au format IMG -------------------------------- void Test_IMG(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier T_IMG_Header IMG_header; byte signature[6]={0x01,0x00,0x47,0x12,0x6D,0xB0}; Get_full_filename(filename, context->File_name, context->File_directory); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Lecture et vrification de la signature if (Read_bytes(file,IMG_header.Filler1,6) && Read_word_le(file,&(IMG_header.Width)) && Read_word_le(file,&(IMG_header.Height)) && Read_bytes(file,IMG_header.Filler2,118) && Read_bytes(file,IMG_header.Palette,sizeof(T_Palette)) ) { if ( (!memcmp(IMG_header.Filler1,signature,6)) && IMG_header.Width && IMG_header.Height) File_error=0; } // Fermeture du fichier fclose(file); } } // -- Lire un fichier au format IMG ----------------------------------------- void Load_IMG(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier byte * buffer; FILE *file; word x_pos,y_pos; long width_read; long file_size; T_IMG_Header IMG_header; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); if (Read_bytes(file,IMG_header.Filler1,6) && Read_word_le(file,&(IMG_header.Width)) && Read_word_le(file,&(IMG_header.Height)) && Read_bytes(file,IMG_header.Filler2,118) && Read_bytes(file,IMG_header.Palette,sizeof(T_Palette)) ) { buffer=(byte *)malloc(IMG_header.Width); Pre_load(context, IMG_header.Width,IMG_header.Height,file_size,FORMAT_IMG,PIXEL_SIMPLE,0); if (File_error==0) { memcpy(context->Palette,IMG_header.Palette,sizeof(T_Palette)); Palette_loaded(context); context->Width=IMG_header.Width; context->Height=IMG_header.Height; width_read=IMG_header.Width; for (y_pos=0;(y_posHeight) && (!File_error);y_pos++) { if (Read_bytes(file,buffer,context->Width)) { for (x_pos=0; x_posWidth;x_pos++) Set_pixel(context, x_pos,y_pos,buffer[x_pos]); } else File_error=2; } } free(buffer); buffer = NULL; } else File_error=1; fclose(file); } else File_error=1; } // -- Sauver un fichier au format IMG --------------------------------------- void Save_IMG(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; short x_pos,y_pos; T_IMG_Header IMG_header; byte signature[6]={0x01,0x00,0x47,0x12,0x6D,0xB0}; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; // Ouverture du fichier if ((file=fopen(filename,"wb"))) { memcpy(IMG_header.Filler1,signature,6); IMG_header.Width=context->Width; IMG_header.Height=context->Height; memset(IMG_header.Filler2,0,118); IMG_header.Filler2[4]=0xFF; IMG_header.Filler2[22]=64; // Lo(Longueur de la signature) IMG_header.Filler2[23]=0; // Hi(Longueur de la signature) memcpy(IMG_header.Filler2+23,"GRAFX2 by SunsetDesign (IMG format taken from PV (c)W.Wiedmann)",64); memcpy(IMG_header.Palette,context->Palette,sizeof(T_Palette)); if (Write_bytes(file,IMG_header.Filler1,6) && Write_word_le(file,IMG_header.Width) && Write_word_le(file,IMG_header.Height) && Write_bytes(file,IMG_header.Filler2,118) && Write_bytes(file,IMG_header.Palette,sizeof(T_Palette)) ) { Init_write_buffer(); for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) for (x_pos=0; x_posWidth; x_pos++) Write_one_byte(file,Get_pixel(context, x_pos,y_pos)); End_write(file); fclose(file); if (File_error) remove(filename); } else // Error d'criture (disque plein ou protg) { fclose(file); remove(filename); File_error=1; } } else { fclose(file); remove(filename); File_error=1; } } //////////////////////////////////// LBM //////////////////////////////////// typedef struct { word Width; word Height; word X_org; // Inutile word Y_org; // Inutile byte BitPlanes; byte Mask; byte Compression; byte Pad1; // Inutile word Transp_col; byte X_aspect; // Inutile byte Y_aspect; // Inutile word X_screen; word Y_screen; } T_LBM_Header; byte * LBM_buffer; FILE *LBM_file; // -- Tester si un fichier est au format LBM -------------------------------- void Test_LBM(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; char format[4]; char section[4]; dword dummy; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((LBM_file=fopen(filename, "rb"))) { if (! Read_bytes(LBM_file,section,4)) File_error=1; else if (memcmp(section,"FORM",4)) File_error=1; else { Read_dword_be(LBM_file, &dummy); // On aurait pu vrifier que ce long est gal la taille // du fichier - 8, mais a aurait interdit de charger des // fichiers tronqus (et dj que c'est chiant de perdre // une partie du fichier il faut quand mme pouvoir en // garder un peu... Sinon, moi je pleure :'( !!! ) if (! Read_bytes(LBM_file,format,4)) File_error=1; else if ( (memcmp(format,"ILBM",4)) && (memcmp(format,"PBM ",4)) ) File_error=1; } fclose(LBM_file); } else File_error=1; } // -- Lire un fichier au format LBM ----------------------------------------- byte Image_HAM; // ---------------- Adapter la palette pour les images HAM ---------------- void Adapt_palette_HAM(T_IO_Context * context) { short i,j,temp; byte color; if (Image_HAM==6) { for (i=1; i<=14; i++) { // On recopie a palette de base memcpy(context->Palette+(i<<4),context->Palette,48); // On modifie les teintes de cette palette for (j=0; j<16; j++) { color=(i<<4)+j; if (i<=7) { if (i&1) { temp=context->Palette[j].R+16; context->Palette[color].R=(temp<63)?temp:63; } if (i&2) { temp=context->Palette[j].G+16; context->Palette[color].G=(temp<63)?temp:63; } if (i&4) { temp=context->Palette[j].B+16; context->Palette[color].B=(temp<63)?temp:63; } } else { if ((i-7)&1) { temp=context->Palette[j].R-16; context->Palette[color].R=(temp>=0)?temp:0; } if ((i-7)&2) { temp=context->Palette[j].G-16; context->Palette[color].G=(temp>=0)?temp:0; } if ((i-7)&4) { temp=context->Palette[j].B-16; context->Palette[color].B=(temp>=0)?temp:0; } } } } // Ici, il reste les 16 dernires couleurs modifier for (i=240,j=0; j<16; i++,j++) { temp=context->Palette[j].R+8; context->Palette[i].R=(temp<63)?temp:63; temp=context->Palette[j].G+8; context->Palette[i].G=(temp<63)?temp:63; temp=context->Palette[j].B+8; context->Palette[i].B=(temp<63)?temp:63; } } else if (Image_HAM==8) { for (i=1; i<=3; i++) { // On recopie la palette de base memcpy(context->Palette+(i<<6),context->Palette,192); // On modifie les teintes de cette palette for (j=0; j<64; j++) { color=(i<<6)+j; switch (i) { case 1 : temp=context->Palette[j].R+16; context->Palette[color].R=(temp<63)?temp:63; break; case 2 : temp=context->Palette[j].G+16; context->Palette[color].G=(temp<63)?temp:63; break; default: temp=context->Palette[j].B+16; context->Palette[color].B=(temp<63)?temp:63; } } } } else // Image 64 couleurs sauve en 32. { for (i=0; i<32; i++) { j=i+32; context->Palette[j].R=context->Palette[i].R>>1; context->Palette[j].G=context->Palette[i].G>>1; context->Palette[j].B=context->Palette[i].B>>1; } } } // Inspired by Allegro: storing a 4-character identifier as a 32bit litteral #define ID4(a,b,c,d) ((((a)&255)<<24) | (((b)&255)<<16) | (((c)&255)<<8) | (((d)&255))) /// Skips the current section in an ILBM file. /// This function should be called while the file pointer is right /// after the 4-character code that identifies the section. int LBM_Skip_section(void) { dword size; if (!Read_dword_be(LBM_file,&size)) return 0; if (size&1) size++; if (fseek(LBM_file,size,SEEK_CUR)) return 0; return 1; } // ------------------------- Attendre une section ------------------------- byte LBM_Wait_for(byte * expected_section) { // Valeur retourne: 1=Section trouve, 0=Section non trouve (erreur) byte section_read[4]; if (! Read_bytes(LBM_file,section_read,4)) return 0; while (memcmp(section_read,expected_section,4)) // Sect. pas encore trouve { if (!LBM_Skip_section()) return 0; if (! Read_bytes(LBM_file,section_read,4)) return 0; } return 1; } // Les images ILBM sont stocks en bitplanes donc on doit trifouiller les bits pour // en faire du chunky byte Color_ILBM_line(word x_pos, word real_line_size, byte HBPm1) { // Renvoie la couleur du pixel (ILBM) en x_pos. // CL sera le rang auquel on extrait les bits de la couleur byte cl = 7 - (x_pos & 7); int ax,bh,dx; byte bl=0; for(dx=HBPm1;dx>=0;dx--) { //CIL_Loop ax = (real_line_size * dx + x_pos) >> 3; bh = (LBM_buffer[ax] >> cl) & 1; bl = (bl << 1) + bh; } return bl; } byte HBPm1; // header.BitPlanes-1 // ----------------------- Afficher une ligne ILBM ------------------------ void Draw_ILBM_line(T_IO_Context *context, short y_pos, short real_line_size) { byte color; byte red,green,blue; byte temp; short x_pos; if (Image_HAM<=1) // ILBM { for (x_pos=0; x_posWidth; x_pos++) { Set_pixel(context, x_pos,y_pos,Color_ILBM_line(x_pos,real_line_size, HBPm1)); } } else { color=0; red=context->Palette[0].R; green =context->Palette[0].G; blue =context->Palette[0].B; if (Image_HAM==6) for (x_pos=0; x_posWidth; x_pos++) // HAM6 { temp=Color_ILBM_line(x_pos,real_line_size, HBPm1); switch (temp & 0xF0) { case 0x10: // blue blue=(temp&0x0F)<<2; color=Best_color(red,green,blue); break; case 0x20: // red red=(temp&0x0F)<<2; color=Best_color(red,green,blue); break; case 0x30: // green green=(temp&0x0F)<<2; color=Best_color(red,green,blue); break; default: // Nouvelle couleur color=temp; red=context->Palette[color].R; green =context->Palette[color].G; blue =context->Palette[color].B; } Set_pixel(context, x_pos,y_pos,color); } else for (x_pos=0; x_posWidth; x_pos++) // HAM8 { temp=Color_ILBM_line(x_pos,real_line_size, HBPm1); switch (temp & 0x03) { case 0x01: // blue blue=temp>>2; color=Best_color(red,green,blue); break; case 0x02: // red red=temp>>2; color=Best_color(red,green,blue); break; case 0x03: // green green=temp>>2; color=Best_color(red,green,blue); break; default: // Nouvelle couleur color=temp; red=context->Palette[color].R; green =context->Palette[color].G; blue =context->Palette[color].B; } Set_pixel(context, x_pos,y_pos,color); } } } void Load_LBM(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; T_LBM_Header header; char format[4]; char section[4]; byte temp_byte; short b256; dword nb_colors; dword section_size; short x_pos; short y_pos; short counter; short line_size; // Taille d'une ligne en octets short real_line_size; // Taille d'une ligne en pixels byte color; long file_size; dword dummy; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((LBM_file=fopen(filename, "rb"))) { file_size=File_length_file(LBM_file); // On avance dans le fichier (pas besoin de tester ce qui l'a dj t) Read_bytes(LBM_file,section,4); Read_dword_be(LBM_file,&dummy); Read_bytes(LBM_file,format,4); if (!LBM_Wait_for((byte *)"BMHD")) File_error=1; Read_dword_be(LBM_file,&dummy); // Maintenant on lit le header pour pouvoir commencer le chargement de l'image if ( (Read_word_be(LBM_file,&header.Width)) && (Read_word_be(LBM_file,&header.Height)) && (Read_word_be(LBM_file,&header.X_org)) && (Read_word_be(LBM_file,&header.Y_org)) && (Read_byte(LBM_file,&header.BitPlanes)) && (Read_byte(LBM_file,&header.Mask)) && (Read_byte(LBM_file,&header.Compression)) && (Read_byte(LBM_file,&header.Pad1)) && (Read_word_be(LBM_file,&header.Transp_col)) && (Read_byte(LBM_file,&header.X_aspect)) && (Read_byte(LBM_file,&header.Y_aspect)) && (Read_word_be(LBM_file,&header.X_screen)) && (Read_word_be(LBM_file,&header.Y_screen)) && header.Width && header.Height) { if ( (header.BitPlanes) && (LBM_Wait_for((byte *)"CMAP")) ) { Read_dword_be(LBM_file,&nb_colors); nb_colors/=3; if (((dword)1< il faut copier les 32 coul. } // sur les 32 suivantes et assombrir ces dernires. else { if ((header.BitPlanes==6) || (header.BitPlanes==8)) Image_HAM=header.BitPlanes; else /* File_error=1;*/ /* C'est cens tre incorrect mais j'ai */ Image_HAM=0; /* trouv un fichier comme a, alors... */ } } else Image_HAM=0; if ( (!File_error) && (nb_colors>=2) && (nb_colors<=256) ) { HBPm1=header.BitPlanes-1; if (header.Mask==1) header.BitPlanes++; // Deluxe paint le fait... alors on le fait... Back_color=header.Transp_col; // On commence par passer la palette en 256 comme a, si la nouvelle // palette a moins de 256 coul, la prcdente ne souffrira pas d'un // assombrissement prjudiciable. if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); else Palette_64_to_256(context->Palette); // On peut maintenant charger la nouvelle palette if (Read_bytes(LBM_file,context->Palette,3*nb_colors)) { Palette_256_to_64(context->Palette); if (Image_HAM) Adapt_palette_HAM(context); Palette_64_to_256(context->Palette); Palette_loaded(context); // On lit l'octet de padding du CMAP si la taille est impaire if (nb_colors&1) if (Read_byte(LBM_file,&temp_byte)) File_error=2; // Keep reading sections until we find the body while (1) { if (! Read_bytes(LBM_file,section,4)) { File_error=2; break; } // Found body : stop searching if (!memcmp(section,"BODY",4)) break; else if (!memcmp(section,"CRNG",4)) { // Handle CRNG // The content of a CRNG is as follows: word padding; word rate; word flags; byte min_col; byte max_col; // if ( (Read_dword_be(LBM_file,§ion_size)) && (Read_word_be(LBM_file,&padding)) && (Read_word_be(LBM_file,&rate)) && (Read_word_be(LBM_file,&flags)) && (Read_byte(LBM_file,&min_col)) && (Read_byte(LBM_file,&max_col))) { if (section_size == 8 && min_col != max_col) { // Valid cycling range if (max_colCycle_range[context->Color_cycles].Start=min_col; context->Cycle_range[context->Color_cycles].End=max_col; context->Cycle_range[context->Color_cycles].Inverse=(flags&2)?1:0; context->Cycle_range[context->Color_cycles].Speed=(flags&1) ? rate/78 : 0; context->Color_cycles++; } } else { File_error=2; break; } } else { // ignore any number of unknown sections if (!LBM_Skip_section()) { File_error=2; break; } } } if ( !File_error ) { Read_dword_be(LBM_file,§ion_size); context->Width = header.Width; context->Height = header.Height; Original_screen_X = header.X_screen; Original_screen_Y = header.Y_screen; Pre_load(context, context->Width,context->Height,file_size,FORMAT_LBM,PIXEL_SIMPLE,0); if (File_error==0) { if (!memcmp(format,"ILBM",4)) // "ILBM": InterLeaved BitMap { // Calcul de la taille d'une ligne ILBM (pour les images ayant des dimensions exotiques) if (context->Width & 15) { real_line_size=( (context->Width+16) >> 4 ) << 4; line_size=( (context->Width+16) >> 4 )*(header.BitPlanes<<1); } else { real_line_size=context->Width; line_size=(context->Width>>3)*header.BitPlanes; } if (!header.Compression) { // non compress LBM_buffer=(byte *)malloc(line_size); for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) { if (Read_bytes(LBM_file,LBM_buffer,line_size)) Draw_ILBM_line(context, y_pos,real_line_size); else File_error=2; } free(LBM_buffer); LBM_buffer = NULL; } else { // compress /*Init_lecture();*/ LBM_buffer=(byte *)malloc(line_size); for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) { for (x_pos=0; ((x_pos 127 alors il faut rpter 256-'temp_byte' fois la couleur de l'octet suivant // Si temp_byte <= 127 alors il faut afficher directement les 'temp_byte' octets suivants if (temp_byte>127) { if(Read_byte(LBM_file, &color)!=1) { File_error=2; break; } b256=(short)(256-temp_byte); for (counter=0; counter<=b256; counter++) if (x_pos=line_size || Read_byte(LBM_file, &(LBM_buffer[x_pos++]))!=1) File_error=2; } if (!File_error) Draw_ILBM_line(context, y_pos,real_line_size); } free(LBM_buffer); LBM_buffer = NULL; /*Close_lecture();*/ } } else // "PBM ": Planar(?) BitMap { real_line_size=context->Width+(context->Width&1); if (!header.Compression) { // non compress LBM_buffer=(byte *)malloc(real_line_size); for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) { if (Read_bytes(LBM_file,LBM_buffer,real_line_size)) for (x_pos=0; x_posWidth; x_pos++) Set_pixel(context, x_pos,y_pos,LBM_buffer[x_pos]); else File_error=2; } free(LBM_buffer); LBM_buffer = NULL; } else { // compress /*Init_lecture();*/ for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) { for (x_pos=0; ((x_pos127) { if(Read_byte(LBM_file, &color)!=1) { File_error=2; break; } b256=256-temp_byte; for (counter=0; counter<=b256; counter++) Set_pixel(context, x_pos++,y_pos,color); } else for (counter=0; counter<=temp_byte; counter++) { byte byte_read=0; if(Read_byte(LBM_file, &byte_read)!=1) { File_error=2; break; } Set_pixel(context, x_pos++,y_pos,byte_read); } } } /*Close_lecture();*/ } } } } else Set_file_error(2); } else { File_error=1; } } else Set_file_error(1); } else File_error=1; } else File_error=1; fclose(LBM_file); } else File_error=1; } // -- Sauver un fichier au format LBM --------------------------------------- byte LBM_color_list[129]; word LBM_list_size; byte LBM_repetition_mode; // ------------- Ecrire les couleurs que l'on vient de traiter ------------ void Transfer_colors(void) { byte index; if (LBM_list_size>0) { if (LBM_repetition_mode) { Write_one_byte(LBM_file,257-LBM_list_size); Write_one_byte(LBM_file,LBM_color_list[0]); } else { Write_one_byte(LBM_file,LBM_list_size-1); for (index=0; index et on a 3 couleurs qui se suivent { LBM_list_size-=2; Transfer_colors(); LBM_color_list[0]=color; LBM_color_list[1]=color; LBM_color_list[2]=color; LBM_list_size=3; LBM_repetition_mode=1; } } else // La couleur n'est pas la mme que la prcdente { if (!LBM_repetition_mode) // On conserve le mode... { LBM_color_list[LBM_list_size++]=color; if (LBM_list_size==128) Transfer_colors(); } else // On change de mode... { Transfer_colors(); LBM_color_list[LBM_list_size]=color; LBM_list_size++; } } } } void Save_LBM(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; T_LBM_Header header; word x_pos; word y_pos; byte temp_byte; word real_width; int file_size; int i; File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); // Ouverture du fichier if ((LBM_file=fopen(filename,"wb"))) { Write_bytes(LBM_file,"FORM",4); Write_dword_be(LBM_file,0); // On mettra la taille jour la fin Write_bytes(LBM_file,"PBM BMHD",8); Write_dword_be(LBM_file,20); // On corrige la largeur de l'image pour qu'elle soit multiple de 2 real_width=context->Width+(context->Width&1); header.Width=context->Width; header.Height=context->Height; header.X_org=0; header.Y_org=0; header.BitPlanes=8; header.Mask=0; header.Compression=1; header.Pad1=0; header.Transp_col=Back_color; header.X_aspect=1; header.Y_aspect=1; header.X_screen = Screen_width; header.Y_screen = Screen_height; Write_word_be(LBM_file,header.Width); Write_word_be(LBM_file,header.Height); Write_word_be(LBM_file,header.X_org); Write_word_be(LBM_file,header.Y_org); Write_bytes(LBM_file,&header.BitPlanes,1); Write_bytes(LBM_file,&header.Mask,1); Write_bytes(LBM_file,&header.Compression,1); Write_bytes(LBM_file,&header.Pad1,1); Write_word_be(LBM_file,header.Transp_col); Write_bytes(LBM_file,&header.X_aspect,1); Write_bytes(LBM_file,&header.Y_aspect,1); Write_word_be(LBM_file,header.X_screen); Write_word_be(LBM_file,header.Y_screen); Write_bytes(LBM_file,"CMAP",4); Write_dword_be(LBM_file,sizeof(T_Palette)); Write_bytes(LBM_file,context->Palette,sizeof(T_Palette)); for (i=0; iColor_cycles; i++) { word flags=0; flags|= context->Cycle_range[i].Speed?1:0; // Cycling or not flags|= context->Cycle_range[i].Inverse?2:0; // Inverted Write_bytes(LBM_file,"CRNG",4); Write_dword_be(LBM_file,8); // Section size Write_word_be(LBM_file,0); // Padding Write_word_be(LBM_file,context->Cycle_range[i].Speed*78); // Rate Write_word_be(LBM_file,flags); // Flags Write_byte(LBM_file,context->Cycle_range[i].Start); // Min color Write_byte(LBM_file,context->Cycle_range[i].End); // Max color // No padding, size is multiple of 2 } Write_bytes(LBM_file,"BODY",4); Write_dword_be(LBM_file,0); // On mettra la taille jour la fin Init_write_buffer(); LBM_list_size=0; for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) { for (x_pos=0; ((x_posColor_cycles*16,SEEK_SET); Write_dword_be(LBM_file,file_size-824-context->Color_cycles*16); if (!File_error) { fseek(LBM_file,4,SEEK_SET); // Si la taille de la section de l'image (taille fichier-8) est // impaire, on rajoute un 0 (Padding) la fin. if ((file_size) & 1) { Write_dword_be(LBM_file,file_size-7); fseek(LBM_file,0,SEEK_END); temp_byte=0; if (! Write_bytes(LBM_file,&temp_byte,1)) File_error=1; } else Write_dword_be(LBM_file,file_size-8); fclose(LBM_file); if (File_error) remove(filename); } else { File_error=1; fclose(LBM_file); remove(filename); } } else // Il y a eu une erreur lors du compactage => on efface le fichier remove(filename); } else File_error=1; } //////////////////////////////////// BMP //////////////////////////////////// typedef struct { byte Signature[2]; // ='BM' = 0x4D42 dword Size_1; // file size word Reserved_1; // 0 word Reserved_2; // 0 dword Offset; // Offset of bitmap data start dword Size_2; // 40 dword Width; dword Height; word Planes; // 1 word Nb_bits; // 1,4,8 ou 24 dword Compression; dword Size_3; dword XPM; dword YPM; dword Nb_Clr; dword Clr_Imprt; } T_BMP_Header; // -- Tester si un fichier est au format BMP -------------------------------- void Test_BMP(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; T_BMP_Header header; File_error=1; Get_full_filename(filename, context->File_name, context->File_directory); if ((file=fopen(filename, "rb"))) { if (Read_bytes(file,&(header.Signature),2) // "BM" && Read_dword_le(file,&(header.Size_1)) && Read_word_le(file,&(header.Reserved_1)) && Read_word_le(file,&(header.Reserved_2)) && Read_dword_le(file,&(header.Offset)) && Read_dword_le(file,&(header.Size_2)) && Read_dword_le(file,&(header.Width)) && Read_dword_le(file,&(header.Height)) && Read_word_le(file,&(header.Planes)) && Read_word_le(file,&(header.Nb_bits)) && Read_dword_le(file,&(header.Compression)) && Read_dword_le(file,&(header.Size_3)) && Read_dword_le(file,&(header.XPM)) && Read_dword_le(file,&(header.YPM)) && Read_dword_le(file,&(header.Nb_Clr)) && Read_dword_le(file,&(header.Clr_Imprt)) ) { if ( header.Signature[0]=='B' && header.Signature[1]=='M' && header.Size_2==40 && header.Width && header.Height ) File_error=0; } fclose(file); } } // Find the 8 important bits in a dword byte Bitmap_mask(dword pixel, dword mask) { byte result; int i; int bits_found; switch(mask) { // Shortcuts to quickly handle the common 24/32bit cases case 0x000000FF: return (pixel & 0x000000FF); case 0x0000FF00: return (pixel & 0x0000FF00)>>8; case 0x00FF0000: return (pixel & 0x00FF0000)>>16; case 0xFF000000: return (pixel & 0xFF000000)>>24; } // Uncommon : do it bit by bit. bits_found=0; result=0; // Process the mask from low to high bit for (i=0;i<32;i++) { // Found a bit in the mask if (mask & (1<=8) return result; } } // Less than 8 bits in the mask: scale the result to 8 bits return result << (8-bits_found); } // -- Charger un fichier au format BMP -------------------------------------- void Load_BMP(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; T_BMP_Header header; byte * buffer; word index; byte local_palette[256][4]; // R,G,B,0 word nb_colors = 0; short x_pos; short y_pos; word line_size; byte a,b,c=0; long file_size; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); if (Read_bytes(file,header.Signature,2) && Read_dword_le(file,&(header.Size_1)) && Read_word_le(file,&(header.Reserved_1)) && Read_word_le(file,&(header.Reserved_2)) && Read_dword_le(file,&(header.Offset)) && Read_dword_le(file,&(header.Size_2)) && Read_dword_le(file,&(header.Width)) && Read_dword_le(file,&(header.Height)) && Read_word_le(file,&(header.Planes)) && Read_word_le(file,&(header.Nb_bits)) && Read_dword_le(file,&(header.Compression)) && Read_dword_le(file,&(header.Size_3)) && Read_dword_le(file,&(header.XPM)) && Read_dword_le(file,&(header.YPM)) && Read_dword_le(file,&(header.Nb_Clr)) && Read_dword_le(file,&(header.Clr_Imprt)) ) { switch (header.Nb_bits) { case 1 : case 4 : case 8 : if (header.Nb_Clr) nb_colors=header.Nb_Clr; else nb_colors=1<Palette,0,sizeof(T_Palette)); // On peut maintenant transfrer la nouvelle palette for (index=0; indexPalette[index].R=local_palette[index][2]; context->Palette[index].G=local_palette[index][1]; context->Palette[index].B=local_palette[index][0]; } Palette_loaded(context); context->Width=header.Width; context->Height=header.Height; switch (header.Compression) { case 0 : // Pas de compression line_size=context->Width; x_pos=(32/header.Nb_bits); // x_pos sert de variable temporaire // On arrondit line_size au premier multiple de x_pos suprieur if (line_size % x_pos) line_size=((line_size/x_pos)*x_pos)+x_pos; // On convertit cette taille en octets line_size=(line_size*header.Nb_bits)>>3; buffer=(byte *)malloc(line_size); for (y_pos=context->Height-1; ((y_pos>=0) && (!File_error)); y_pos--) { if (Read_bytes(file,buffer,line_size)) for (x_pos=0; x_posWidth; x_pos++) switch (header.Nb_bits) { case 8 : Set_pixel(context, x_pos,y_pos,buffer[x_pos]); break; case 4 : if (x_pos & 1) Set_pixel(context, x_pos,y_pos,buffer[x_pos>>1] & 0xF); else Set_pixel(context, x_pos,y_pos,buffer[x_pos>>1] >> 4 ); break; case 1 : if ( buffer[x_pos>>3] & (0x80>>(x_pos&7)) ) Set_pixel(context, x_pos,y_pos,1); else Set_pixel(context, x_pos,y_pos,0); } else File_error=2; } free(buffer); buffer = NULL; break; case 1 : // Compression RLE 8 bits x_pos=0; y_pos=context->Height-1; /*Init_lecture();*/ if(Read_byte(file, &a)!=1 || Read_byte(file, &b)!=1) File_error=2; while (!File_error) { if (a) // Encoded mode for (index=1; index<=a; index++) Set_pixel(context, x_pos++,y_pos,b); else // Absolute mode switch (b) { case 0 : // End of line x_pos=0; y_pos--; break; case 1 : // End of bitmap break; case 2 : // Delta if(Read_byte(file, &a)!=1 || Read_byte(file, &b)!=1) File_error=2; x_pos+=a; y_pos-=b; break; default: // Nouvelle srie while (b) { if(Read_byte(file, &a)!=1) File_error=2; //Read_one_byte(file, &c); Set_pixel(context, x_pos++,y_pos,a); //if (--c) //{ // Set_pixel(context, x_pos++,y_pos,c); // b--; //} b--; } if (ftell(file) & 1) fseek(file, 1, SEEK_CUR); } if (a==0 && b==1) break; if(Read_byte(file, &a) !=1 || Read_byte(file, &b)!=1) { File_error=2; } } /*Close_lecture();*/ break; case 2 : // Compression RLE 4 bits x_pos=0; y_pos=context->Height-1; /*Init_lecture();*/ if(Read_byte(file, &a)!=1 || Read_byte(file, &b) != 1) File_error =2; while ( (!File_error) && ((a)||(b!=1)) ) { if (a) // Encoded mode (A fois les 1/2 pixels de B) for (index=1; index<=a; index++) { if (index & 1) Set_pixel(context, x_pos,y_pos,b>>4); else Set_pixel(context, x_pos,y_pos,b&0xF); x_pos++; } else // Absolute mode switch (b) { case 0 : //End of line x_pos=0; y_pos--; break; case 1 : // End of bitmap break; case 2 : // Delta if(Read_byte(file, &a)!=1 || Read_byte(file, &b)!=1) File_error=2; x_pos+=a; y_pos-=b; break; default: // Nouvelle srie (B 1/2 pixels bruts) for (index=1; ((index<=b) && (!File_error)); index++,x_pos++) { if (index&1) { if(Read_byte(file, &c)!=1) File_error=2; Set_pixel(context, x_pos,y_pos,c>>4); } else Set_pixel(context, x_pos,y_pos,c&0xF); } // On lit l'octet rendant le nombre d'octets pair, si // ncessaire. Encore un truc de crtin "made in MS". if ( ((b&3)==1) || ((b&3)==2) ) { byte dummy; if(Read_byte(file, &dummy)!=1) File_error=2; } } if(Read_byte(file, &a)!=1 || Read_byte(file, &b)!=1) File_error=2; } /*Close_lecture();*/ } fclose(file); } else { fclose(file); File_error=1; } } } else { // Image 16/24/32 bits dword red_mask; dword green_mask; dword blue_mask; if (header.Nb_bits == 16) { red_mask = 0x00007C00; green_mask = 0x000003E0; blue_mask = 0x0000001F; } else { red_mask = 0x00FF0000; green_mask = 0x0000FF00; blue_mask = 0x000000FF; } File_error=0; context->Width=header.Width; context->Height=header.Height; Pre_load(context,header.Width,header.Height,file_size,FORMAT_BMP,PIXEL_SIMPLE,1); if (File_error==0) { switch (header.Compression) { case 3: // BI_BITFIELDS if (!Read_dword_le(file,&red_mask) || !Read_dword_le(file,&green_mask) || !Read_dword_le(file,&blue_mask)) File_error=2; break; default: break; } if (fseek(file, header.Offset, SEEK_SET)) File_error=2; } if (File_error==0) { switch (header.Nb_bits) { // 24bit bitmap default: case 24: line_size=context->Width*3; x_pos=(line_size % 4); // x_pos sert de variable temporaire if (x_pos>0) line_size+=(4-x_pos); buffer=(byte *)malloc(line_size); for (y_pos=context->Height-1; ((y_pos>=0) && (!File_error)); y_pos--) { if (Read_bytes(file,buffer,line_size)) for (x_pos=0,index=0; x_posWidth; x_pos++,index+=3) Set_pixel_24b(context, x_pos,y_pos,buffer[index+2],buffer[index+1],buffer[index+0]); else File_error=2; } break; // 32bit bitmap case 32: line_size=context->Width*4; buffer=(byte *)malloc(line_size); for (y_pos=context->Height-1; ((y_pos>=0) && (!File_error)); y_pos--) { if (Read_bytes(file,buffer,line_size)) for (x_pos=0; x_posWidth; x_pos++) { dword pixel=*(((dword *)buffer)+x_pos); Set_pixel_24b(context, x_pos,y_pos,Bitmap_mask(pixel,red_mask),Bitmap_mask(pixel,green_mask),Bitmap_mask(pixel,blue_mask)); } else File_error=2; } break; // 16bit bitmap case 16: line_size=(context->Width*2) + (context->Width&1)*2; buffer=(byte *)malloc(line_size); for (y_pos=context->Height-1; ((y_pos>=0) && (!File_error)); y_pos--) { if (Read_bytes(file,buffer,line_size)) for (x_pos=0; x_posWidth; x_pos++) { word pixel=*(((word *)buffer)+x_pos); Set_pixel_24b(context, x_pos,y_pos,Bitmap_mask(pixel,red_mask),Bitmap_mask(pixel,green_mask),Bitmap_mask(pixel,blue_mask)); } else File_error=2; } break; } free(buffer); buffer = NULL; fclose(file); } } } else { fclose(file); File_error=1; } } else File_error=1; } // -- Sauvegarder un fichier au format BMP ---------------------------------- void Save_BMP(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; T_BMP_Header header; short x_pos; short y_pos; long line_size; word index; byte local_palette[256][4]; // R,G,B,0 File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); // Ouverture du fichier if ((file=fopen(filename,"wb"))) { // Image width must be a multiple of 4 bytes line_size = context->Width; if (line_size & 3) line_size += (4 - (line_size & 3)); header.Signature[0] = 'B'; header.Signature[1] = 'M'; header.Size_1 =(line_size*context->Height)+1078; header.Reserved_1 =0; header.Reserved_2 =0; header.Offset =1078; // Size of header data (including palette) header.Size_2 =40; // Size of header header.Width =context->Width; header.Height =context->Height; header.Planes =1; header.Nb_bits =8; header.Compression=0; header.Size_3 =0; header.XPM =0; header.YPM =0; header.Nb_Clr =0; header.Clr_Imprt =0; if (Write_bytes(file,header.Signature,2) && Write_dword_le(file,header.Size_1) && Write_word_le(file,header.Reserved_1) && Write_word_le(file,header.Reserved_2) && Write_dword_le(file,header.Offset) && Write_dword_le(file,header.Size_2) && Write_dword_le(file,header.Width) && Write_dword_le(file,header.Height) && Write_word_le(file,header.Planes) && Write_word_le(file,header.Nb_bits) && Write_dword_le(file,header.Compression) && Write_dword_le(file,header.Size_3) && Write_dword_le(file,header.XPM) && Write_dword_le(file,header.YPM) && Write_dword_le(file,header.Nb_Clr) && Write_dword_le(file,header.Clr_Imprt)) { // Chez Bill, ils ont dit: "On va mettre les couleur dans l'ordre // inverse, et pour faire chier, on va les mettre sur une chelle de // 0 255 parce que le standard VGA c'est de 0 63 (logique!). Et // puis comme c'est pas assez dbile, on va aussi y rajouter un octet // toujours 0 pour forcer les gens s'acheter des gros disques // durs... Comme a, a fera passer la pillule lorsqu'on sortira // Windows 95." ... for (index=0; index<256; index++) { local_palette[index][0]=context->Palette[index].B; local_palette[index][1]=context->Palette[index].G; local_palette[index][2]=context->Palette[index].R; local_palette[index][3]=0; } if (Write_bytes(file,local_palette,1024)) { Init_write_buffer(); // ... Et Bill, il a dit: "OK les gars! Mais seulement si vous rangez // les pixels dans l'ordre inverse, mais que sur les Y quand-mme // parce que faut pas pousser." for (y_pos=context->Height-1; ((y_pos>=0) && (!File_error)); y_pos--) for (x_pos=0; x_posFile_name, context->File_directory); if ((file=fopen(filename, "rb"))) { if ( (Read_bytes(file,signature,6)) && ((!memcmp(signature,"GIF87a",6))||(!memcmp(signature,"GIF89a",6))) ) File_error=0; fclose(file); } } // -- Lire un fichier au format GIF ----------------------------------------- // -- Lire un fichier au format GIF ----------------------------------------- // Dfinition de quelques variables globales au chargement du GIF87a word GIF_nb_bits; // Nb de bits composants un code complet word GIF_remainder_bits; // Nb de bits encore dispos dans GIF_last_byte byte GIF_remainder_byte; // Nb d'octets avant le prochain bloc de Raster Data word GIF_current_code; // Code trait (qui vient d'tre lu en gnral) byte GIF_last_byte; // Octet de lecture des bits word GIF_pos_X; // Coordonnes d'affichage de l'image word GIF_pos_Y; word GIF_interlaced; // L'image est entrelace word GIF_finished_interlaced_image; // L'image entrelace est finie de charger word GIF_pass; // index de passe de l'image entrelace FILE *GIF_file; // L'handle du fichier // -- Lit le code GIF_nb_bits suivant -- word GIF_get_next_code(void) { word nb_bits_to_process=GIF_nb_bits; word nb_bits_processed =0; word current_nb_bits; GIF_current_code=0; while (nb_bits_to_process) { if (GIF_remainder_bits==0) // Il ne reste plus de bits... { // Lire l'octet suivant: // Si on a atteint la fin du bloc de Raster Data if (GIF_remainder_byte==0) // Lire l'octet nous donnant la taille du bloc de Raster Data suivant if(Read_byte(GIF_file, &GIF_remainder_byte)!=1) File_error=2; if(Read_byte(GIF_file,&GIF_last_byte)!=1) File_error = 2; GIF_remainder_byte--; GIF_remainder_bits=8; } current_nb_bits=(nb_bits_to_process<=GIF_remainder_bits)?nb_bits_to_process:GIF_remainder_bits; GIF_current_code|=(GIF_last_byte & ((1<>=current_nb_bits; nb_bits_processed +=current_nb_bits; nb_bits_to_process-=current_nb_bits; GIF_remainder_bits -=current_nb_bits; } return GIF_current_code; } // -- Affiche un nouveau pixel -- void GIF_new_pixel(T_IO_Context * context, T_GIF_IDB *idb, byte color) { Set_pixel(context, idb->Pos_X+GIF_pos_X, idb->Pos_Y+GIF_pos_Y,color); GIF_pos_X++; if (GIF_pos_X>=idb->Image_width) { GIF_pos_X=0; if (!GIF_interlaced) GIF_pos_Y++; else { switch (GIF_pass) { case 0 : GIF_pos_Y+=8; break; case 1 : GIF_pos_Y+=8; break; case 2 : GIF_pos_Y+=4; break; default: GIF_pos_Y+=2; } if (GIF_pos_Y>=idb->Image_height) { switch(++GIF_pass) { case 1 : GIF_pos_Y=4; break; case 2 : GIF_pos_Y=2; break; case 3 : GIF_pos_Y=1; break; case 4 : GIF_finished_interlaced_image=1; } } } } } void Load_GIF(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; char signature[6]; word * alphabet_stack; // Pile de dcodage d'une chane word * alphabet_prefix; // Table des prfixes des codes word * alphabet_suffix; // Table des suffixes des codes word alphabet_free; // Position libre dans l'alphabet word alphabet_max; // Nombre d'entres possibles dans l'alphabet word alphabet_stack_pos; // Position dans la pile de dcodage d'un chane T_GIF_LSDB LSDB; T_GIF_IDB IDB; T_GIF_GCE GCE; word nb_colors; // Nombre de couleurs dans l'image word color_index; // index de traitement d'une couleur byte size_to_read; // Nombre de donnes lire (divers) byte block_identifier; // Code indicateur du type de bloc en cours byte initial_nb_bits; // Nb de bits au dbut du traitement LZW word special_case=0; // Mmoire pour le cas spcial word old_code=0; // Code prcdent word byte_read; // Sauvegarde du code en cours de lecture word value_clr; // Valeur <=> Clear tables word value_eof; // Valeur <=> End d'image long file_size; int number_LID; // Nombre d'images trouves dans le fichier short current_layer = 0; /////////////////////////////////////////////////// FIN DES DECLARATIONS // number_LID=0; Get_full_filename(filename, context->File_name, context->File_directory); if ((GIF_file=fopen(filename, "rb"))) { file_size=File_length_file(GIF_file); if ( (Read_bytes(GIF_file,signature,6)) && ( (memcmp(signature,"GIF87a",6)==0) || (memcmp(signature,"GIF89a",6)==0) ) ) { // Allocation de mmoire pour les tables & piles de traitement: alphabet_stack =(word *)malloc(4096*sizeof(word)); alphabet_prefix=(word *)malloc(4096*sizeof(word)); alphabet_suffix=(word *)malloc(4096*sizeof(word)); if (Read_word_le(GIF_file,&(LSDB.Width)) && Read_word_le(GIF_file,&(LSDB.Height)) && Read_byte(GIF_file,&(LSDB.Resol)) && Read_byte(GIF_file,&(LSDB.Backcol)) && Read_byte(GIF_file,&(LSDB.Aspect)) ) { // Lecture du Logical Screen Descriptor Block russie: Original_screen_X=LSDB.Width; Original_screen_Y=LSDB.Height; Pre_load(context, LSDB.Width,LSDB.Height,file_size,FORMAT_GIF,PIXEL_SIMPLE,0); context->Width=LSDB.Width; context->Height=LSDB.Height; // Palette globale dispo = (LSDB.Resol and $80) // Profondeur de couleur =((LSDB.Resol and $70) shr 4)+1 // Nombre de bits/pixel = (LSDB.Resol and $07)+1 // Ordre de Classement = (LSDB.Aspect and $80) nb_colors=(1 << ((LSDB.Resol & 0x07)+1)); if (LSDB.Resol & 0x80) { // Palette globale dispo: if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); // Load the palette for(color_index=0;color_indexPalette[color_index].R)); Read_byte(GIF_file,&(context->Palette[color_index].G)); Read_byte(GIF_file,&(context->Palette[color_index].B)); } } // On lit un indicateur de block Read_byte(GIF_file,&block_identifier); while (block_identifier!=0x3B && !File_error) { switch (block_identifier) { case 0x21: // Bloc d'extension { byte function_code; // Lecture du code de fonction: Read_byte(GIF_file,&function_code); // Lecture de la taille du bloc: Read_byte(GIF_file,&size_to_read); while (size_to_read!=0 && !File_error) { switch(function_code) { case 0xFE: // Comment Block Extension // On rcupre le premier commentaire non-vide, // on jette les autres. if (context->Comment[0]=='\0') { int nb_char_to_keep=Min(size_to_read,COMMENT_SIZE); Read_bytes(GIF_file,context->Comment,nb_char_to_keep); context->Comment[nb_char_to_keep+1]='\0'; // Si le commentaire etait trop long, on fait avance-rapide // sur la suite. if (size_to_read>nb_char_to_keep) fseek(GIF_file,size_to_read-nb_char_to_keep,SEEK_CUR); } // Lecture de la taille du bloc suivant: Read_byte(GIF_file,&size_to_read); break; case 0xF9: // Graphics Control Extension // Prvu pour la transparence if ( Read_byte(GIF_file,&(GCE.Packed_fields)) && Read_word_le(GIF_file,&(GCE.Delay_time)) && Read_byte(GIF_file,&(GCE.Transparent_color))) { if (GCE.Packed_fields & 1) { if (number_LID == 0) context->Background_transparent = 1; context->Transparent_color= GCE.Transparent_color; } else { if (number_LID == 0) context->Background_transparent = 0; context->Transparent_color = 0; // Reset transparent color } } else File_error=2; // Lecture de la taille du bloc suivant: Read_byte(GIF_file,&size_to_read); break; case 0xFF: // Application Extension // Normally, always a 11-byte block if (size_to_read == 0x0B) { char aeb[0x0B]; Read_bytes(GIF_file,aeb, 0x0B); if (File_error) ; else if (!memcmp(aeb,"NETSCAPE2.0",0x0B)) { // The well-known Netscape extension. // Nothing to do, just skip sub-block do { if (! Read_byte(GIF_file,&size_to_read)) File_error=1; fseek(GIF_file,size_to_read,SEEK_CUR); } while (!File_error && size_to_read!=0); } else if (!memcmp(aeb,"GFX2PATH\x00\x00\x00",0x0B)) { // Original file path if (context->Original_file_name && context->Original_file_directory) { Read_byte(GIF_file,&size_to_read); if (!File_error && size_to_read) { Read_bytes(GIF_file,context->Original_file_directory, size_to_read); Read_byte(GIF_file,&size_to_read); if (!File_error && size_to_read) { Read_bytes(GIF_file,context->Original_file_name, size_to_read); Read_byte(GIF_file,&size_to_read); // Normally 0 } } } else { // Nothing to do, just skip sub-block Read_byte(GIF_file,&size_to_read); while (size_to_read!=0 && !File_error) { fseek(GIF_file,size_to_read,SEEK_CUR); Read_byte(GIF_file,&size_to_read); } } } else if (!memcmp(aeb,"CRNG\0\0\0\0" "1.0",0x0B)) { // Color animation. Similar to a LBM CRNG chunk. word rate; word flags; byte min_col; byte max_col; // Read_byte(GIF_file,&size_to_read); for(;size_to_read>0 && !File_error;size_to_read-=6) { if ( (Read_word_be(GIF_file,&rate)) && (Read_word_be(GIF_file,&flags)) && (Read_byte(GIF_file,&min_col)) && (Read_byte(GIF_file,&max_col))) { if (min_col != max_col) { // Valid cycling range if (max_colCycle_range[context->Color_cycles].Start=min_col; context->Cycle_range[context->Color_cycles].End=max_col; context->Cycle_range[context->Color_cycles].Inverse=(flags&2)?1:0; context->Cycle_range[context->Color_cycles].Speed=(flags&1)?rate/78:0; context->Color_cycles++; } } else { File_error=1; } } // Read end-of-block delimiter if (!File_error) Read_byte(GIF_file,&size_to_read); if (size_to_read!=0) File_error=1; } else { // Unknown extension, skip. Read_byte(GIF_file,&size_to_read); while (size_to_read!=0 && !File_error) { fseek(GIF_file,size_to_read,SEEK_CUR); Read_byte(GIF_file,&size_to_read); } } } else { fseek(GIF_file,size_to_read,SEEK_CUR); // Lecture de la taille du bloc suivant: Read_byte(GIF_file,&size_to_read); } break; default: // On saute le bloc: fseek(GIF_file,size_to_read,SEEK_CUR); // Lecture de la taille du bloc suivant: Read_byte(GIF_file,&size_to_read); break; } } } break; case 0x2C: // Local Image Descriptor { if (number_LID!=0) { // This a second layer/frame, or more. // Attempt to add a layer to current image current_layer++; Set_layer(context, current_layer); } number_LID++; // lecture de 10 derniers octets if ( Read_word_le(GIF_file,&(IDB.Pos_X)) && Read_word_le(GIF_file,&(IDB.Pos_Y)) && Read_word_le(GIF_file,&(IDB.Image_width)) && Read_word_le(GIF_file,&(IDB.Image_height)) && Read_byte(GIF_file,&(IDB.Indicator)) && IDB.Image_width && IDB.Image_height) { // Palette locale dispo = (IDB.Indicator and $80) // Image entrelace = (IDB.Indicator and $40) // Ordre de classement = (IDB.Indicator and $20) // Nombre de bits/pixel = (IDB.Indicator and $07)+1 (si palette locale dispo) if (IDB.Indicator & 0x80) { // Palette locale dispo if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); nb_colors=(1 << ((IDB.Indicator & 0x07)+1)); // Load the palette for(color_index=0;color_indexPalette[color_index].R)); Read_byte(GIF_file,&(context->Palette[color_index].G)); Read_byte(GIF_file,&(context->Palette[color_index].B)); } } Palette_loaded(context); File_error=0; if (!Read_byte(GIF_file,&(initial_nb_bits))) File_error=1; value_clr =(1<value_clr) { alphabet_stack[alphabet_stack_pos++]=alphabet_suffix[GIF_current_code]; GIF_current_code=alphabet_prefix[GIF_current_code]; } special_case=alphabet_stack[alphabet_stack_pos++]=GIF_current_code; do GIF_new_pixel(context, &IDB, alphabet_stack[--alphabet_stack_pos]); while (alphabet_stack_pos!=0); alphabet_prefix[alphabet_free ]=old_code; alphabet_suffix[alphabet_free++]=GIF_current_code; old_code=byte_read; if (alphabet_free>alphabet_max) { if (GIF_nb_bits<12) alphabet_max =((1 << (++GIF_nb_bits))-1); } } else // Code Clear rencontr { GIF_nb_bits =initial_nb_bits + 1; alphabet_max =((1 << GIF_nb_bits)-1); alphabet_free =(1<=0) if ( /* (GIF_pos_X!=0) || */ ( ( (!GIF_interlaced) && (GIF_pos_Y!=IDB.Image_height) && (GIF_pos_X!=0)) || ( (GIF_interlaced) && (!GIF_finished_interlaced_image) ) ) ) File_error=2; } // Le fichier contenait un IDB else File_error=2; } default: break; } // Lecture du code de fonction suivant: if (!Read_byte(GIF_file,&block_identifier)) File_error=2; } } // Le fichier contenait un LSDB else File_error=1; // Libration de la mmoire utilise par les tables & piles de traitement: free(alphabet_suffix); free(alphabet_prefix); free(alphabet_stack); alphabet_suffix = alphabet_prefix = alphabet_stack = NULL; } // Le fichier contenait au moins la signature GIF87a ou GIF89a else File_error=1; fclose(GIF_file); } // Le fichier tait ouvrable else File_error=1; } // -- Sauver un fichier au format GIF --------------------------------------- int GIF_stop; // "On peut arrter la sauvegarde du fichier" byte GIF_buffer[256]; // buffer d'criture de bloc de donnes compiles // -- Vider le buffer GIF dans le buffer KM -- void GIF_empty_buffer(void) { word index; if (GIF_remainder_byte) { GIF_buffer[0]=GIF_remainder_byte; for (index=0;index<=GIF_remainder_byte;index++) Write_one_byte(GIF_file,GIF_buffer[index]); GIF_remainder_byte=0; } } // -- Ecrit un code GIF_nb_bits -- void GIF_set_code(word Code) { word nb_bits_to_process=GIF_nb_bits; word nb_bits_processed =0; word current_nb_bits; while (nb_bits_to_process) { current_nb_bits=(nb_bits_to_process<=(8-GIF_remainder_bits))?nb_bits_to_process:(8-GIF_remainder_bits); GIF_last_byte|=(Code & ((1<>=current_nb_bits; GIF_remainder_bits +=current_nb_bits; nb_bits_processed +=current_nb_bits; nb_bits_to_process-=current_nb_bits; if (GIF_remainder_bits==8) // Il ne reste plus de bits coder sur l'octet courant { // Ecrire l'octet balancer: GIF_buffer[++GIF_remainder_byte]=GIF_last_byte; // Si on a atteint la fin du bloc de Raster Data if (GIF_remainder_byte==255) // On doit vider le buffer qui est maintenant plein GIF_empty_buffer(); GIF_last_byte=0; GIF_remainder_bits=0; } } } // -- Lire le pixel suivant -- byte GIF_next_pixel(T_IO_Context *context, T_GIF_IDB *idb) { byte temp; temp=Get_pixel(context, GIF_pos_X,GIF_pos_Y); if (++GIF_pos_X>=idb->Image_width) { GIF_pos_X=0; if (++GIF_pos_Y>=idb->Image_height) GIF_stop=1; } return temp; } void Save_GIF(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; word * alphabet_prefix; // Table des prfixes des codes word * alphabet_suffix; // Table des suffixes des codes word * alphabet_daughter; // Table des chanes filles (plus longues) word * alphabet_sister; // Table des chanes soeurs (mme longueur) word alphabet_free; // Position libre dans l'alphabet word alphabet_max; // Nombre d'entres possibles dans l'alphabet word start; // Code prcdent (sert au linkage des chanes) int descend; // Boolen "On vient de descendre" T_GIF_LSDB LSDB; T_GIF_IDB IDB; byte block_identifier; // Code indicateur du type de bloc en cours word current_string; // Code de la chane en cours de traitement byte current_char; // Caractre coder word index; // index de recherche de chane short current_layer; /////////////////////////////////////////////////// FIN DES DECLARATIONS // File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); if ((GIF_file=fopen(filename,"wb"))) { // On crit la signature du fichier if (Write_bytes(GIF_file,"GIF89a",6)) { // La signature du fichier a t correctement crite. // Allocation de mmoire pour les tables alphabet_prefix=(word *)malloc(4096*sizeof(word)); alphabet_suffix=(word *)malloc(4096*sizeof(word)); alphabet_daughter =(word *)malloc(4096*sizeof(word)); alphabet_sister =(word *)malloc(4096*sizeof(word)); // On initialise le LSDB du fichier if (Config.Screen_size_in_GIF) { LSDB.Width=Screen_width; LSDB.Height=Screen_height; } else { LSDB.Width=context->Width; LSDB.Height=context->Height; } LSDB.Resol =0x97; // Image en 256 couleurs, avec une palette LSDB.Backcol=context->Transparent_color; LSDB.Aspect =0; // Palette normale // On sauve le LSDB dans le fichier if (Write_word_le(GIF_file,LSDB.Width) && Write_word_le(GIF_file,LSDB.Height) && Write_byte(GIF_file,LSDB.Resol) && Write_byte(GIF_file,LSDB.Backcol) && Write_byte(GIF_file,LSDB.Aspect) ) { // Le LSDB a t correctement crit. int i; // On sauve la palette for(i=0;i<256 && !File_error;i++) { if (!Write_byte(GIF_file,context->Palette[i].R) ||!Write_byte(GIF_file,context->Palette[i].G) ||!Write_byte(GIF_file,context->Palette[i].B)) File_error=1; } if (!File_error) { // La palette a t correctement crite. // Ecriture de la transparence //Write_bytes(GIF_file,"\x21\xF9\x04\x01\x00\x00\xNN\x00",8); // "Netscape" animation extension // Write_bytes(GIF_file,"\x21\xFF\x0BNETSCAPE2.0\x03\xLL\xSS\xSS\x00",19); // LL : 01 to loop // SSSS : number of loops // Ecriture du commentaire if (context->Comment[0]) { Write_bytes(GIF_file,"\x21\xFE",2); Write_byte(GIF_file,strlen(context->Comment)); Write_bytes(GIF_file,context->Comment,strlen(context->Comment)+1); } // Write cycling colors if (context->Color_cycles) { int i; Write_bytes(GIF_file,"\x21\xff\x0B" "CRNG\0\0\0\0" "1.0",14); Write_byte(GIF_file,context->Color_cycles*6); for (i=0; iColor_cycles; i++) { word flags=0; flags|= context->Cycle_range[i].Speed?1:0; // Cycling or not flags|= context->Cycle_range[i].Inverse?2:0; // Inverted Write_word_be(GIF_file,context->Cycle_range[i].Speed*78); // Rate Write_word_be(GIF_file,flags); // Flags Write_byte(GIF_file,context->Cycle_range[i].Start); // Min color Write_byte(GIF_file,context->Cycle_range[i].End); // Max color } Write_byte(GIF_file,0); } // Loop on all layers for (current_layer=0; current_layer < context->Nb_layers && !File_error; current_layer++) { // Write a Graphic Control Extension byte GCE_block[] = "\x21\xF9\x04\x04\x05\x00\x00\x00"; // 'Default' values: // Disposal method "Do not dispose" // Duration 5/100s (minimum viable value for current web browsers) if (current_layer > 0 || context->Background_transparent) GCE_block[3] |= 1; // Transparent color flag GCE_block[6] = context->Transparent_color; Set_layer(context, current_layer); if (current_layer == context->Nb_layers -1) { // "Infinite" delay for last frame GCE_block[4] = 255; GCE_block[5] = 255; } if (Write_bytes(GIF_file,GCE_block,8)) { // On va crire un block indicateur d'IDB et l'IDB du fichier block_identifier=0x2C; IDB.Pos_X=0; IDB.Pos_Y=0; IDB.Image_width=context->Width; IDB.Image_height=context->Height; IDB.Indicator=0x07; // Image non entrelace, pas de palette locale. IDB.Nb_bits_pixel=8; // Image 256 couleurs; if ( Write_byte(GIF_file,block_identifier) && Write_word_le(GIF_file,IDB.Pos_X) && Write_word_le(GIF_file,IDB.Pos_Y) && Write_word_le(GIF_file,IDB.Image_width) && Write_word_le(GIF_file,IDB.Image_height) && Write_byte(GIF_file,IDB.Indicator) && Write_byte(GIF_file,IDB.Nb_bits_pixel)) { // Le block indicateur d'IDB et l'IDB ont ts correctements // crits. Init_write_buffer(); GIF_pos_X=0; GIF_pos_Y=0; GIF_last_byte=0; GIF_remainder_bits=0; GIF_remainder_byte=0; index=4096; File_error=0; GIF_stop=0; // Rintialisation de la table: alphabet_free=258; GIF_nb_bits =9; alphabet_max =511; GIF_set_code(256); for (start=0;start<4096;start++) { alphabet_daughter[start]=4096; alphabet_sister[start]=4096; } ////////////////////////////////////////////// COMPRESSION LZW // start=current_string=GIF_next_pixel(context, &IDB); descend=1; do { current_char=GIF_next_pixel(context, &IDB); // On regarde si dans la table on aurait pas une chane // quivalente current_string+Caractere while ( (index0xFFF) { // Rintialisation de la table: GIF_set_code(256); alphabet_free=258; GIF_nb_bits =9; alphabet_max =511; for (start=0;start<4096;start++) { alphabet_daughter[start]=4096; alphabet_sister[start]=4096; } } else if (alphabet_free>alphabet_max+1) { // On augmente le nb de bits GIF_nb_bits++; alphabet_max=(1< // // 00 if (context->Original_file_name != NULL && context->Original_file_directory != NULL) { long name_size = 1+strlen(context->Original_file_name); long dir_size = 1+strlen(context->Original_file_directory); if (name_size<256 && dir_size<256) { if (! Write_bytes(GIF_file,"\x21\xFF\x0BGFX2PATH\x00\x00\x00", 14) || ! Write_byte(GIF_file,dir_size) || ! Write_bytes(GIF_file, context->Original_file_directory, dir_size) || ! Write_byte(GIF_file,name_size) || ! Write_bytes(GIF_file, context->Original_file_name, name_size) || ! Write_byte(GIF_file,0)) File_error=1; } } // On crit un GIF TERMINATOR, exig par SVGA et SEA. if (! Write_byte(GIF_file,'\x3B')) File_error=1; } } // On a pu crire la palette else File_error=1; } // On a pu crire le LSDB else File_error=1; // Libration de la mmoire utilise par les tables free(alphabet_sister); free(alphabet_daughter); free(alphabet_suffix); free(alphabet_prefix); } // On a pu crire la signature du fichier else File_error=1; fclose(GIF_file); if (File_error) remove(filename); } // On a pu ouvrir le fichier en criture else File_error=1; } //////////////////////////////////// PCX //////////////////////////////////// typedef struct { byte Manufacturer; // |_ Il font chier ces cons! Ils auraient pu byte Version; // | mettre une vraie signature! byte Compression; // L'image est-elle compresse? byte Depth; // Nombre de bits pour coder un pixel (inutile puisqu'on se sert de Plane) word X_min; // |_ Coin haut-gauche | word Y_min; // | de l'image |_ (Crtin!) word X_max; // |_ Coin bas-droit | word Y_max; // | de l'image | word X_dpi; // |_ Densit de |_ (Presque inutile parce que word Y_dpi; // | l'image | aucun moniteur n'est pareil!) byte Palette_16c[48]; // Palette 16 coul (inutile pour 256c) (dbile!) byte Reserved; // Ca me plait a aussi! byte Plane; // 4 => 16c , 1 => 256c , ... word Bytes_per_plane_line;// Doit toujours tre pair word Palette_info; // 1 => color , 2 => Gris (ignor partir de la version 4) word Screen_X; // |_ Dimensions de word Screen_Y; // | l'cran d'origine byte Filler[54]; // Ca... J'adore! } T_PCX_Header; T_PCX_Header PCX_header; // -- Tester si un fichier est au format PCX -------------------------------- void Test_PCX(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); if ((file=fopen(filename, "rb"))) { if (Read_byte(file,&(PCX_header.Manufacturer)) && Read_byte(file,&(PCX_header.Version)) && Read_byte(file,&(PCX_header.Compression)) && Read_byte(file,&(PCX_header.Depth)) && Read_word_le(file,&(PCX_header.X_min)) && Read_word_le(file,&(PCX_header.Y_min)) && Read_word_le(file,&(PCX_header.X_max)) && Read_word_le(file,&(PCX_header.Y_max)) && Read_word_le(file,&(PCX_header.X_dpi)) && Read_word_le(file,&(PCX_header.Y_dpi)) && Read_bytes(file,&(PCX_header.Palette_16c),48) && Read_byte(file,&(PCX_header.Reserved)) && Read_byte(file,&(PCX_header.Plane)) && Read_word_le(file,&(PCX_header.Bytes_per_plane_line)) && Read_word_le(file,&(PCX_header.Palette_info)) && Read_word_le(file,&(PCX_header.Screen_X)) && Read_word_le(file,&(PCX_header.Screen_Y)) && Read_bytes(file,&(PCX_header.Filler),54) ) { // Vu que ce header a une signature de merde et peu significative, il // va falloir que je teste diffrentes petites valeurs dont je connais // l'intervalle. Grrr! if ( (PCX_header.Manufacturer!=10) || (PCX_header.Compression>1) || ( (PCX_header.Depth!=1) && (PCX_header.Depth!=2) && (PCX_header.Depth!=4) && (PCX_header.Depth!=8) ) || ( (PCX_header.Plane!=1) && (PCX_header.Plane!=2) && (PCX_header.Plane!=4) && (PCX_header.Plane!=8) && (PCX_header.Plane!=3) ) || (PCX_header.X_maxWidth; x_pos++) { color=(LBM_buffer[x_pos/reduction]>>((reduction_minus_one-(x_pos%reduction))*depth)) & byte_mask; Set_pixel(context, x_pos,y_pos,color); } } void Load_PCX(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; short line_size; short real_line_size; // width de l'image corrige short width_read; short x_pos; short y_pos; byte byte1; byte byte2; byte index; dword nb_colors; long file_size; byte palette_CGA[9]={ 84,252,252, 252, 84,252, 252,252,252}; long position; long image_size; byte * buffer; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); if (Read_byte(file,&(PCX_header.Manufacturer)) && Read_byte(file,&(PCX_header.Version)) && Read_byte(file,&(PCX_header.Compression)) && Read_byte(file,&(PCX_header.Depth)) && Read_word_le(file,&(PCX_header.X_min)) && Read_word_le(file,&(PCX_header.Y_min)) && Read_word_le(file,&(PCX_header.X_max)) && Read_word_le(file,&(PCX_header.Y_max)) && Read_word_le(file,&(PCX_header.X_dpi)) && Read_word_le(file,&(PCX_header.Y_dpi)) && Read_bytes(file,&(PCX_header.Palette_16c),48) && Read_byte(file,&(PCX_header.Reserved)) && Read_byte(file,&(PCX_header.Plane)) && Read_word_le(file,&(PCX_header.Bytes_per_plane_line)) && Read_word_le(file,&(PCX_header.Palette_info)) && Read_word_le(file,&(PCX_header.Screen_X)) && Read_word_le(file,&(PCX_header.Screen_Y)) && Read_bytes(file,&(PCX_header.Filler),54) ) { context->Width=PCX_header.X_max-PCX_header.X_min+1; context->Height=PCX_header.Y_max-PCX_header.Y_min+1; Original_screen_X=PCX_header.Screen_X; Original_screen_Y=PCX_header.Screen_Y; if (PCX_header.Plane!=3) { Pre_load(context, context->Width,context->Height,file_size,FORMAT_PCX,PIXEL_SIMPLE,0); if (File_error==0) { // On prpare la palette accueillir les valeurs du fichier PCX if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); nb_colors=(dword)(1<4) memcpy(context->Palette,PCX_header.Palette_16c,48); else { context->Palette[1].R=0; context->Palette[1].G=0; context->Palette[1].B=0; byte1=PCX_header.Palette_16c[3]>>5; if (nb_colors==4) { // Pal. CGA "alakon" (du Turc Allahkoum qui signifie " la con" :)) memcpy(context->Palette+1,palette_CGA,9); if (!(byte1&2)) { context->Palette[1].B=84; context->Palette[2].B=84; context->Palette[3].B=84; } } // Palette monochrome (on va dire que c'est du N&B) else { context->Palette[1].R=252; context->Palette[1].G=252; context->Palette[1].B=252; } } // On se positionne la fin du fichier - 769 octets pour voir s'il y // a une palette. if ( (PCX_header.Depth==8) && (PCX_header.Version>=5) && (file_size>(256*3)) ) { fseek(file,file_size-((256*3)+1),SEEK_SET); // On regarde s'il y a une palette aprs les donnes de l'image if (Read_byte(file,&byte1)) if (byte1==12) // Lire la palette si c'est une image en 256 couleurs { int index; // On lit la palette 256c que ces crtins ont foutue la fin du fichier for(index=0;index<256;index++) if ( ! Read_byte(file,&(context->Palette[index].R)) || ! Read_byte(file,&(context->Palette[index].G)) || ! Read_byte(file,&(context->Palette[index].B)) ) { File_error=2; DEBUG("ERROR READING PCX PALETTE !",index); break; } } } Palette_loaded(context); // Maintenant qu'on a lu la palette que ces crtins sont alls foutre // la fin, on retourne juste aprs le header pour lire l'image. fseek(file,128,SEEK_SET); if (!File_error) { line_size=PCX_header.Bytes_per_plane_line*PCX_header.Plane; real_line_size=(short)PCX_header.Bytes_per_plane_line<<3; // On se sert de donnes LBM car le dessin de ligne en moins de 256 // couleurs se fait comme avec la structure ILBM. Image_HAM=0; HBPm1=PCX_header.Plane-1; LBM_buffer=(byte *)malloc(line_size); // Chargement de l'image if (PCX_header.Compression) // Image compresse { /*Init_lecture();*/ image_size=(long)PCX_header.Bytes_per_plane_line*context->Height; if (PCX_header.Depth==8) // 256 couleurs (1 plan) { for (position=0; ((positionHeight) && (!File_error)); y_pos++) { for (x_pos=0; ((x_posHeight) && (!File_error);y_pos++) { if ((width_read=Read_bytes(file,LBM_buffer,line_size))) { if (PCX_header.Plane==1) for (x_pos=0; x_posWidth;x_pos++) Set_pixel(context, x_pos,y_pos,LBM_buffer[x_pos]); else { if (PCX_header.Depth==1) Draw_ILBM_line(context, y_pos,real_line_size); else Draw_PCX_line(context, y_pos,PCX_header.Depth); } } else File_error=2; } } free(LBM_buffer); LBM_buffer = NULL; } } } else { // Image 24 bits!!! Pre_load(context,context->Width,context->Height,file_size,FORMAT_PCX,PIXEL_SIMPLE,1); if (File_error==0) { line_size=PCX_header.Bytes_per_plane_line*3; buffer=(byte *)malloc(line_size); if (!PCX_header.Compression) { for (y_pos=0;(y_posHeight) && (!File_error);y_pos++) { if (Read_bytes(file,buffer,line_size)) { for (x_pos=0; x_posWidth; x_pos++) Set_pixel_24b(context, x_pos,y_pos,buffer[x_pos+(PCX_header.Bytes_per_plane_line*0)],buffer[x_pos+(PCX_header.Bytes_per_plane_line*1)],buffer[x_pos+(PCX_header.Bytes_per_plane_line*2)]); } else File_error=2; } } else { /*Init_lecture();*/ for (y_pos=0,position=0;(y_posHeight) && (!File_error);) { // Lecture et dcompression de la ligne if(Read_byte(file,&byte1)!=1) File_error=2; if (!File_error) { if ((byte1 & 0xC0)==0xC0) { byte1-=0xC0; // facteur de rptition if(Read_byte(file,&byte2)!=1) File_error=2; // octet rpter if (!File_error) { for (index=0; (index=line_size) { for (x_pos=0; x_posWidth; x_pos++) Set_pixel_24b(context, x_pos,y_pos,buffer[x_pos+(PCX_header.Bytes_per_plane_line*0)],buffer[x_pos+(PCX_header.Bytes_per_plane_line*1)],buffer[x_pos+(PCX_header.Bytes_per_plane_line*2)]); y_pos++; position=0; } } } } else { buffer[position++]=byte1; if (position>=line_size) { for (x_pos=0; x_posWidth; x_pos++) Set_pixel_24b(context, x_pos,y_pos,buffer[x_pos+(PCX_header.Bytes_per_plane_line*0)],buffer[x_pos+(PCX_header.Bytes_per_plane_line*1)],buffer[x_pos+(PCX_header.Bytes_per_plane_line*2)]); y_pos++; position=0; } } } } if (position!=0) File_error=2; /*Close_lecture();*/ } free(buffer); buffer = NULL; } } } else { File_error=1; } fclose(file); } else File_error=1; } // -- Ecrire un fichier au format PCX --------------------------------------- void Save_PCX(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; short line_size; short x_pos; short y_pos; byte counter; byte last_pixel; byte pixel_read; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename,"wb"))) { PCX_header.Manufacturer=10; PCX_header.Version=5; PCX_header.Compression=1; PCX_header.Depth=8; PCX_header.X_min=0; PCX_header.Y_min=0; PCX_header.X_max=context->Width-1; PCX_header.Y_max=context->Height-1; PCX_header.X_dpi=0; PCX_header.Y_dpi=0; memcpy(PCX_header.Palette_16c,context->Palette,48); PCX_header.Reserved=0; PCX_header.Plane=1; PCX_header.Bytes_per_plane_line=(context->Width&1)?context->Width+1:context->Width; PCX_header.Palette_info=1; PCX_header.Screen_X=Screen_width; PCX_header.Screen_Y=Screen_height; memset(PCX_header.Filler,0,54); if (Write_bytes(file,&(PCX_header.Manufacturer),1) && Write_bytes(file,&(PCX_header.Version),1) && Write_bytes(file,&(PCX_header.Compression),1) && Write_bytes(file,&(PCX_header.Depth),1) && Write_word_le(file,PCX_header.X_min) && Write_word_le(file,PCX_header.Y_min) && Write_word_le(file,PCX_header.X_max) && Write_word_le(file,PCX_header.Y_max) && Write_word_le(file,PCX_header.X_dpi) && Write_word_le(file,PCX_header.Y_dpi) && Write_bytes(file,&(PCX_header.Palette_16c),48) && Write_bytes(file,&(PCX_header.Reserved),1) && Write_bytes(file,&(PCX_header.Plane),1) && Write_word_le(file,PCX_header.Bytes_per_plane_line) && Write_word_le(file,PCX_header.Palette_info) && Write_word_le(file,PCX_header.Screen_X) && Write_word_le(file,PCX_header.Screen_Y) && Write_bytes(file,&(PCX_header.Filler),54) ) { line_size=PCX_header.Bytes_per_plane_line*PCX_header.Plane; Init_write_buffer(); for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) { pixel_read=Get_pixel(context, 0,y_pos); // Compression et criture de la ligne for (x_pos=0; ((x_pos1) || (last_pixel>=0xC0) ) Write_one_byte(file,counter|0xC0); Write_one_byte(file,last_pixel); } } // Ecriture de l'octet (12) indiquant que la palette arrive if (!File_error) Write_one_byte(file,12); End_write(file); // Ecriture de la palette if (!File_error) { if (! Write_bytes(file,context->Palette,sizeof(T_Palette))) File_error=1; } } else File_error=1; fclose(file); if (File_error) remove(filename); } else File_error=1; } //////////////////////////////////// SCx //////////////////////////////////// typedef struct { byte Filler1[4]; word Width; word Height; byte Filler2; byte Planes; } T_SCx_Header; // -- Tester si un fichier est au format SCx -------------------------------- void Test_SCx(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier //byte Signature[3]; T_SCx_Header SCx_header; Get_full_filename(filename, context->File_name, context->File_directory); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Lecture et vrification de la signature if (Read_bytes(file,SCx_header.Filler1,4) && Read_word_le(file, &(SCx_header.Width)) && Read_word_le(file, &(SCx_header.Height)) && Read_byte(file, &(SCx_header.Filler2)) && Read_byte(file, &(SCx_header.Planes)) ) { if ( (!memcmp(SCx_header.Filler1,"RIX",3)) && SCx_header.Width && SCx_header.Height) File_error=0; } // Fermeture du fichier fclose(file); } } // -- Lire un fichier au format SCx ----------------------------------------- void Load_SCx(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; word x_pos,y_pos; long size,real_size; long file_size; T_SCx_Header SCx_header; T_Palette SCx_Palette; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); if (Read_bytes(file,SCx_header.Filler1,4) && Read_word_le(file, &(SCx_header.Width)) && Read_word_le(file, &(SCx_header.Height)) && Read_byte(file, &(SCx_header.Filler2)) && Read_byte(file, &(SCx_header.Planes)) ) { Pre_load(context, SCx_header.Width,SCx_header.Height,file_size,FORMAT_SCx,PIXEL_SIMPLE,0); if (File_error==0) { if (!SCx_header.Planes) size=sizeof(T_Palette); else size=sizeof(T_Components)*(1<Palette,0,sizeof(T_Palette)); Palette_64_to_256(SCx_Palette); memcpy(context->Palette,SCx_Palette,size); Palette_loaded(context); context->Width=SCx_header.Width; context->Height=SCx_header.Height; if (!SCx_header.Planes) { // 256 couleurs (raw) LBM_buffer=(byte *)malloc(context->Width); for (y_pos=0;(y_posHeight) && (!File_error);y_pos++) { if (Read_bytes(file,LBM_buffer,context->Width)) for (x_pos=0; x_posWidth;x_pos++) Set_pixel(context, x_pos,y_pos,LBM_buffer[x_pos]); else File_error=2; } } else { // moins de 256 couleurs (planar) size=((context->Width+7)>>3)*SCx_header.Planes; real_size=(size/SCx_header.Planes)<<3; LBM_buffer=(byte *)malloc(size); HBPm1=SCx_header.Planes-1; Image_HAM=0; for (y_pos=0;(y_posHeight) && (!File_error);y_pos++) { if (Read_bytes(file,LBM_buffer,size)) Draw_ILBM_line(context, y_pos,real_size); else File_error=2; } } free(LBM_buffer); LBM_buffer = NULL; } else File_error=1; } } else File_error=1; fclose(file); } else File_error=1; } // -- Sauver un fichier au format SCx --------------------------------------- void Save_SCx(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; short x_pos,y_pos; T_SCx_Header SCx_header; byte last_char; last_char=strlen(context->File_name)-1; if (context->File_name[last_char]=='?') { if (context->Width<=320) context->File_name[last_char]='I'; else { if (context->Width<=360) context->File_name[last_char]='Q'; else { if (context->Width<=640) context->File_name[last_char]='F'; else { if (context->Width<=800) context->File_name[last_char]='N'; else context->File_name[last_char]='O'; } } } } Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; // Ouverture du fichier if ((file=fopen(filename,"wb"))) { T_Palette palette_64; memcpy(palette_64,context->Palette,sizeof(T_Palette)); Palette_256_to_64(palette_64); memcpy(SCx_header.Filler1,"RIX3",4); SCx_header.Width=context->Width; SCx_header.Height=context->Height; SCx_header.Filler2=0xAF; SCx_header.Planes=0x00; if (Write_bytes(file,SCx_header.Filler1,4) && Write_word_le(file, SCx_header.Width) && Write_word_le(file, SCx_header.Height) && Write_byte(file, SCx_header.Filler2) && Write_byte(file, SCx_header.Planes) && Write_bytes(file,&palette_64,sizeof(T_Palette)) ) { Init_write_buffer(); for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) for (x_pos=0; x_posWidth; x_pos++) Write_one_byte(file,Get_pixel(context, x_pos,y_pos)); End_write(file); fclose(file); if (File_error) remove(filename); } else // Error d'criture (disque plein ou protg) { fclose(file); remove(filename); File_error=1; } } else { fclose(file); remove(filename); File_error=1; } } //////////////////////////////////// XPM //////////////////////////////////// void Save_XPM(T_IO_Context* context) { FILE* file; char filename[MAX_PATH_CHARACTERS]; int i,j; Get_full_filename(filename, context->File_name, context->File_directory); File_error = 0; file = fopen(filename, "w"); if (file == NULL) { File_error = 1; return; } fprintf(file, "/* XPM */\nstatic char* pixmap[] = {\n"); fprintf(file, "\"%d %d 256 2\",\n", context->Width, context->Height); for (i = 0; i < 256; i++) { fprintf(file,"\"%2.2X c #%2.2x%2.2x%2.2x\",\n", i, context->Palette[i].R, context->Palette[i].G, context->Palette[i].B); } for (j = 0; j < context->Height; j++) { fprintf(file, "\""); for (i = 0; i < context->Width; i++) { fprintf(file, "%2.2X", Get_pixel(context, i, j)); } fprintf(file,"\"\n"); } fclose(file); } //////////////////////////////////// PNG //////////////////////////////////// #ifndef __no_pnglib__ // -- Tester si un fichier est au format PNG -------------------------------- void Test_PNG(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier byte png_header[8]; Get_full_filename(filename, context->File_name, context->File_directory); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Lecture du header du fichier if (Read_bytes(file,png_header,8)) { if ( !png_sig_cmp(png_header, 0, 8)) File_error=0; } fclose(file); } } /// Used by a callback in Load_PNG T_IO_Context * PNG_current_context; int PNG_read_unknown_chunk(__attribute__((unused)) png_structp ptr, png_unknown_chunkp chunk) { // png_unknown_chunkp members: // png_byte name[5]; // png_byte *data; // png_size_t size; if (!strcmp((const char *)chunk->name, "crNg")) { // Color animation. Similar to a LBM CRNG chunk. unsigned int i; byte *chunk_ptr = chunk->data; // Should be a multiple of 6 if (chunk->size % 6) return (-1); for(i=0;isize/6 && i<16; i++) { word rate; word flags; byte min_col; byte max_col; // Rate (big-endian word) rate = *(chunk_ptr++) << 8; rate |= *(chunk_ptr++); // Flags (big-endian) flags = *(chunk_ptr++) << 8; flags |= *(chunk_ptr++); // Min color min_col = *(chunk_ptr++); // Max color max_col = *(chunk_ptr++); // Check validity if (min_col != max_col) { // Valid cycling range if (max_colCycle_range[i].Start=min_col; PNG_current_context->Cycle_range[i].End=max_col; PNG_current_context->Cycle_range[i].Inverse=(flags&2)?1:0; PNG_current_context->Cycle_range[i].Speed=(flags&1) ? rate/78 : 0; PNG_current_context->Color_cycles=i+1; } } return (1); // >0 = success } return (0); /* did not recognize */ } png_bytep * Row_pointers; // -- Lire un fichier au format PNG ----------------------------------------- void Load_PNG(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier byte png_header[8]; byte row_pointers_allocated; png_bytep trans; int num_trans; png_color_16p trans_values; png_structp png_ptr; png_infop info_ptr; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename, "rb"))) { // Load header (8 first bytes) if (Read_bytes(file,png_header,8)) { // Do we recognize a png file signature ? if ( !png_sig_cmp(png_header, 0, 8)) { // Prepare internal PNG loader png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr) { // Prepare internal PNG loader info_ptr = png_create_info_struct(png_ptr); if (info_ptr) { png_byte color_type; png_byte bit_depth; png_voidp user_chunk_ptr; // Setup a return point. If a pnglib loading error occurs // in this if(), the else will be executed. if (!setjmp(png_jmpbuf(png_ptr))) { png_init_io(png_ptr, file); // Inform pnglib we already loaded the header. png_set_sig_bytes(png_ptr, 8); // Hook the handler for unknown chunks user_chunk_ptr = png_get_user_chunk_ptr(png_ptr); png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, &PNG_read_unknown_chunk); // This is a horrid way to pass parameters, but we don't get // much choice. PNG loader can't be reintrant. PNG_current_context=context; // Load file information png_read_info(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr,info_ptr); bit_depth = png_get_bit_depth(png_ptr,info_ptr); // If it's any supported file // (Note: As of writing this, this test covers every possible // image format of libpng) if (color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA ) { int num_text; png_text *text_ptr; int unit_type; png_uint_32 res_x; png_uint_32 res_y; // Comment (tEXt) context->Comment[0]='\0'; // Clear the previous comment if ((num_text=png_get_text(png_ptr, info_ptr, &text_ptr, NULL))) { while (num_text--) { if (!strcmp(text_ptr[num_text].key,"Title")) { int size; size = Min(text_ptr[num_text].text_length, COMMENT_SIZE); strncpy(context->Comment, text_ptr[num_text].text, size); context->Comment[size]='\0'; break; // Skip all others tEXt chunks } } } // Pixel Ratio (pHYs) if (png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type)) { // Ignore unit, and use the X/Y ratio as a hint for // WIDE or TALL pixels if (res_x>0 && res_y>0) { if (res_y/res_x>1) { context->Ratio=PIXEL_WIDE; } else if (res_x/res_y>1) { context->Ratio=PIXEL_TALL; } } } if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) Pre_load(context,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr),File_length_file(file),FORMAT_PNG,PIXEL_SIMPLE,1); else Pre_load(context,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr),File_length_file(file),FORMAT_PNG,context->Ratio,0); if (File_error==0) { int x,y; png_colorp palette; int num_palette; // 16-bit images if (bit_depth == 16) { // Reduce to 8-bit png_set_strip_16(png_ptr); } else if (bit_depth < 8) { // Inform libpng we want one byte per pixel, // even though the file was less than 8bpp png_set_packing(png_ptr); } // Images with alpha channel if (color_type & PNG_COLOR_MASK_ALPHA) { // Tell libpng to ignore it png_set_strip_alpha(png_ptr); } // Greyscale images : if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { // Map low bpp greyscales to full 8bit (0-255 range) if (bit_depth < 8) { #if (PNG_LIBPNG_VER_MAJOR <= 1) && (PNG_LIBPNG_VER_MINOR < 4) // Works well with png 1.2.8, but deprecated in 1.4 ... png_set_gray_1_2_4_to_8(png_ptr); #else // ...where this seems to replace it: png_set_expand_gray_1_2_4_to_8(png_ptr); #endif } // Create greyscale palette for (x=0;x<256;x++) { context->Palette[x].R=x; context->Palette[x].G=x; context->Palette[x].B=x; } } else if (color_type == PNG_COLOR_TYPE_PALETTE) // Palette images { if (bit_depth < 8) { // Clear unused colors if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); } // Load the palette png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); for (x=0;xPalette[x].R=palette[x].red; context->Palette[x].G=palette[x].green; context->Palette[x].B=palette[x].blue; } free(palette); palette = NULL; } if (color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA) { Palette_loaded(context); } // Transparency (tRNS) if (png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)) { if (color_type == PNG_COLOR_TYPE_PALETTE && trans!=NULL) { int i; for (i=0; iTransparent_color = i; context->Background_transparent = 1; break; } } } else if ((color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_RGB) && trans_values!=NULL) { // In this case, num_trans is supposed to be "1", // and trans_values[0] contains the reference color // (RGB triplet) that counts as transparent. // Ideally, we should reserve this color in the palette, // (so it's not merged and averaged with a neighbor one) // and after creating the optimized palette, find its // index and mark it transparent. // Current implementation: ignore. } } context->Width=png_get_image_width(png_ptr,info_ptr); context->Height=png_get_image_height(png_ptr,info_ptr); png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); // Allocate row pointers Row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * context->Height); row_pointers_allocated = 0; /* read file */ if (!setjmp(png_jmpbuf(png_ptr))) { if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_PALETTE ) { // 8bpp for (y=0; yHeight; y++) Row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr)); row_pointers_allocated = 1; png_read_image(png_ptr, Row_pointers); for (y=0; yHeight; y++) for (x=0; xWidth; x++) Set_pixel(context, x, y, Row_pointers[y][x]); } else { switch (context->Type) { case CONTEXT_PREVIEW: // 24bpp // It's a preview // Unfortunately we need to allocate loads of memory for (y=0; yHeight; y++) Row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr)); row_pointers_allocated = 1; png_read_image(png_ptr, Row_pointers); for (y=0; yHeight; y++) for (x=0; xWidth; x++) Set_pixel_24b(context, x, y, Row_pointers[y][x*3],Row_pointers[y][x*3+1],Row_pointers[y][x*3+2]); break; case CONTEXT_MAIN_IMAGE: case CONTEXT_BRUSH: case CONTEXT_SURFACE: // It's loading an actual image // We'll save memory and time by writing directly into // our pre-allocated 24bit buffer for (y=0; yHeight; y++) Row_pointers[y] = (png_byte*) (&(context->Buffer_image_24b[y * context->Width])); png_read_image(png_ptr, Row_pointers); break; } } } else File_error=2; /* cleanup heap allocation */ if (row_pointers_allocated) { for (y=0; yHeight; y++) { free(Row_pointers[y]); Row_pointers[y] = NULL; } } free(Row_pointers); Row_pointers = NULL; } else File_error=2; } else // Unsupported image type File_error=1; } else File_error=1; } else File_error=1; } } /*Close_lecture();*/ } else // Lecture header impossible: Error ne modifiant pas l'image File_error=1; fclose(file); } else // Ouv. fichier impossible: Error ne modifiant pas l'image File_error=1; } void Save_PNG(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; int y; byte * pixel_ptr; png_structp png_ptr; png_infop info_ptr; png_unknown_chunk crng_chunk; byte cycle_data[16*6]; // Storage for color-cycling data, referenced by crng_chunk Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; Row_pointers = NULL; // Ouverture du fichier if ((file=fopen(filename,"wb"))) { /* initialisation */ if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) && (info_ptr = png_create_info_struct(png_ptr))) { if (!setjmp(png_jmpbuf(png_ptr))) { png_init_io(png_ptr, file); /* en-tete */ if (!setjmp(png_jmpbuf(png_ptr))) { png_set_IHDR(png_ptr, info_ptr, context->Width, context->Height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_PLTE(png_ptr, info_ptr, (png_colorp)context->Palette, 256); { // Commentaires texte PNG // Cette partie est optionnelle #ifdef PNG_iTXt_SUPPORTED png_text text_ptr[2] = { {-1, "Software", "Grafx2", 6, 0, NULL, NULL}, {-1, "Title", NULL, 0, 0, NULL, NULL} #else png_text text_ptr[2] = { {-1, "Software", "Grafx2", 6}, {-1, "Title", NULL, 0} #endif }; int nb_text_chunks=1; if (context->Comment[0]) { text_ptr[1].text=context->Comment; text_ptr[1].text_length=strlen(context->Comment); nb_text_chunks=2; } png_set_text(png_ptr, info_ptr, text_ptr, nb_text_chunks); } if (context->Background_transparent) { // Transparency byte opacity[256]; // Need to fill a segment with '255', up to the transparent color // which will have a 0. This piece of data (1 to 256 bytes) // will be stored in the file. memset(opacity, 255,context->Transparent_color); opacity[context->Transparent_color]=0; png_set_tRNS(png_ptr, info_ptr, opacity, (int)1 + context->Transparent_color,0); } switch(Pixel_ratio) { case PIXEL_WIDE: case PIXEL_WIDE2: png_set_pHYs(png_ptr, info_ptr, 3000, 6000, PNG_RESOLUTION_METER); break; case PIXEL_TALL: case PIXEL_TALL2: png_set_pHYs(png_ptr, info_ptr, 6000, 3000, PNG_RESOLUTION_METER); break; default: break; } // Write cycling colors if (context->Color_cycles) { // Save a chunk called 'crNg' // The case is selected by the following rules from PNG standard: // char 1: non-mandatory = lowercase // char 2: private (not standard) = lowercase // char 3: reserved = always uppercase // char 4: can be copied by editors = lowercase // First, turn our nice structure into byte array // (just to avoid padding in structures) byte *chunk_ptr = cycle_data; int i; for (i=0; iColor_cycles; i++) { word flags=0; flags|= context->Cycle_range[i].Speed?1:0; // Cycling or not flags|= context->Cycle_range[i].Inverse?2:0; // Inverted // Big end of Rate *(chunk_ptr++) = (context->Cycle_range[i].Speed*78) >> 8; // Low end of Rate *(chunk_ptr++) = (context->Cycle_range[i].Speed*78) & 0xFF; // Big end of Flags *(chunk_ptr++) = (flags) >> 8; // Low end of Flags *(chunk_ptr++) = (flags) & 0xFF; // Min color *(chunk_ptr++) = context->Cycle_range[i].Start; // Max color *(chunk_ptr++) = context->Cycle_range[i].End; } // Build one unknown_chuck structure memcpy(crng_chunk.name, "crNg",5); crng_chunk.data=cycle_data; crng_chunk.size=context->Color_cycles*6; crng_chunk.location=PNG_HAVE_PLTE; // Give it to libpng png_set_unknown_chunks(png_ptr, info_ptr, &crng_chunk, 1); // libpng seems to ignore the location I provided earlier. png_set_unknown_chunk_location(png_ptr, info_ptr, 0, PNG_HAVE_PLTE); } png_write_info(png_ptr, info_ptr); /* ecriture des pixels de l'image */ Row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * context->Height); pixel_ptr = context->Target_address; for (y=0; yHeight; y++) Row_pointers[y] = (png_byte*)(pixel_ptr+y*context->Pitch); if (!setjmp(png_jmpbuf(png_ptr))) { png_write_image(png_ptr, Row_pointers); /* cloture png */ if (!setjmp(png_jmpbuf(png_ptr))) { png_write_end(png_ptr, NULL); } else File_error=1; } else File_error=1; } else File_error=1; } else { File_error=1; } png_destroy_write_struct(&png_ptr, &info_ptr); } else File_error=1; // fermeture du fichier fclose(file); } // S'il y a eu une erreur de sauvegarde, on ne va tout de mme pas laisser // ce fichier pourri trainait... Ca fait pas propre. if (File_error) remove(filename); if (Row_pointers) { free(Row_pointers); Row_pointers=NULL; } } #endif // __no_pnglib__ grafx2/src/filesel.c0000644000076400010400000017261311550336122015020 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2009 Franck Charlet Copyright 2008 Peter Gordon 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 */ #include #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) #include #include #include #elif defined (__MINT__) #include #include #elif defined(__WIN32__) #include #include #include #else #include #endif #include #include #include #include #include #include #include #include #include #include "const.h" #include "struct.h" #include "global.h" #include "misc.h" #include "errors.h" #include "io.h" #include "windows.h" #include "sdlscreen.h" #include "loadsave.h" #include "mountlist.h" #include "engine.h" #include "readline.h" #include "input.h" #include "help.h" #include "filesel.h" #define NORMAL_FILE_COLOR MC_Light // color du texte pour une ligne de // fichier non slectionn #define NORMAL_DIRECTORY_COLOR MC_Dark // color du texte pour une ligne de // rpertoire non slectionn #define NORMAL_BACKGROUND_COLOR MC_Black // color du fond pour une ligne // non slectionne #define SELECTED_FILE_COLOR MC_White // color du texte pour une ligne de // fichier slectionne #define SELECTED_DIRECTORY_COLOR MC_Light // color du texte pour une ligne de // reprtoire slectionne #define SELECTED_BACKGROUND_COLOR MC_Dark // color du fond pour une ligne // slectionne // -- Native fileselector for WIN32 // Returns 0 if all ok, something else if failed byte Native_filesel(byte load) { //load = load; #ifdef __WIN32__ OPENFILENAME ofn; char szFileName[MAX_PATH] = ""; SDL_SysWMinfo wminfo; HWND hwnd; SDL_VERSION(&wminfo.version); SDL_GetWMInfo(&wminfo); hwnd = wminfo.window; ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwnd; ofn.lpstrFilter = "Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0"; ofn.lpstrFile = szFileName; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_EXPLORER; if(load) ofn.Flags |= OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrDefExt = "txt"; if(load) { if (GetOpenFileName(&ofn)) // Do something usefull with the filename stored in szFileName return 0; else // error - check if its just user pressing cancel or something else return CommDlgExtendedError(); } else if(GetSaveFileName(&ofn)) { return 0; } else { // Check if cancel return CommDlgExtendedError(); } #else return 255; // fail ! #endif } // -- "Standard" fileselector for other platforms // -- Fileselector data T_Fileselector Filelist; /// Name of the current directory //static char Selector_directory[1024]; /// Filename (without directory) of the highlighted file static char Selector_filename[256]; // Conventions: // // * Le fileselect modifie le rpertoire courant. Ceci permet de n'avoir // qu'un findfirst dans le rpertoire courant faire: void Recount_files(T_Fileselector *list) { T_Fileselector_item *item; list->Nb_files=0; list->Nb_directories=0; list->Nb_elements=0; for (item = list->First; item != NULL; item = item->Next) { if (item->Type == 0) list->Nb_files ++; else list->Nb_directories ++; list->Nb_elements ++; } if (list->Index) { free(list->Index); list->Index = NULL; } if (list->Nb_elements>0) { int i; list->Index = (T_Fileselector_item **) malloc(list->Nb_elements * sizeof(T_Fileselector_item **)); if (list->Index) { // Fill the index for (item = list->First, i=0; item != NULL; item = item->Next, i++) { list->Index[i] = item; } } // If the malloc failed, we're probably in trouble, but I don't know // how to recover from that..I'll just make the index bulletproof. } } // -- Destruction de la liste chane --------------------------------------- void Free_fileselector_list(T_Fileselector *list) // Cette procdure dtruit la chaine des fichiers. Elle doit tre appele // avant de rappeler la fonction Read_list_of_files, ainsi qu'en fin de // programme. { // Pointeur temporaire de destruction T_Fileselector_item * temp_item; while (list->First!=NULL) { // On mmorise l'adresse du premier lment de la liste temp_item =list->First; // On fait avancer la tte de la liste list->First=list->First->Next; // Et on efface l'ancien premier lment de la liste free(temp_item); temp_item = NULL; } Recount_files(list); } char * Format_filename(const char * fname, word max_length, int type) { static char result[40]; int c; int other_cursor; int pos_last_dot; // safety if (max_length>40) max_length=40; if (strcmp(fname,PARENT_DIR)==0) { strcpy(result,"<-PARENT DIRECTORY"); // Append spaces for (c=18; c= max_length-1) result[max_length-2]=ELLIPSIS_CHARACTER; } else { // Initialize as all spaces for (c = 0; c max_length-6) { result[max_length-6]=ELLIPSIS_CHARACTER; break; } result[c]=fname[c]; } // Ensuite on recopie la partie qui suit le point (si ncessaire): if (pos_last_dot != -1) { for (c = pos_last_dot+1,other_cursor=max_length-4;fname[c]!='\0' && other_cursor < max_length-1;c++,other_cursor++) result[other_cursor]=fname[c]; } } return result; } // -- Rajouter a la liste des elements de la liste un element --------------- void Add_element_to_list(T_Fileselector *list, const char * full_name, const char *short_name, int type, byte icon) // Cette procedure ajoute a la liste chainee un fichier pass en argument. { // Working element T_Fileselector_item * temp_item; // Allocate enough room for one struct + the visible label temp_item=(T_Fileselector_item *)malloc(sizeof(T_Fileselector_item)+strlen(short_name)); // Initialize element strcpy(temp_item->Short_name,short_name); strcpy(temp_item->Full_name,full_name); temp_item->Type = type; temp_item->Icon = icon; // Doubly-linked temp_item->Next =list->First; temp_item->Previous=NULL; if (list->First!=NULL) list->First->Previous=temp_item; // Put new element at the beginning list->First=temp_item; } /// /// Checks if a file has the requested file extension. /// The extension string can end with a ';' (remainder is ignored) /// This function allows wildcard '?', and '*' if it's the only character. int Check_extension(const char *filename, const char * filter) { int pos_last_dot = -1; int c = 0; if (filter[0] == '*') return 1; // On recherche la position du dernier . dans le nom for (c = 0; filename[c]!='\0'; c++) if (filename[c]=='.') pos_last_dot = c; // Fichier sans extension (ca arrive) if (pos_last_dot == -1) return (filter[0] == '\0' || filter[0] == ';'); // Vrification caractre par caractre, case-insensitive. c = 0; while (1) { if (filter[c] == '\0' || filter[c] == ';') return filename[pos_last_dot + 1 + c] == '\0'; if (filter[c] != '?' && tolower(filter[c]) != tolower(filename[pos_last_dot + 1 + c])) return 0; c++; } } // -- Lecture d'une liste de fichiers --------------------------------------- void Read_list_of_files(T_Fileselector *list, byte selected_format) // Cette procdure charge dans la liste chaine les fichiers dont l'extension // correspond au format demand. { DIR* current_directory; //Rpertoire courant struct dirent* entry; // Structure de lecture des lments char * filter = "*"; // Extension demande struct stat Infos_enreg; char * current_path; // Tout d'abord, on dduit du format demand un filtre utiliser: filter = Get_fileformat(selected_format)->Extensions; // Ensuite, on vide la liste actuelle: Free_fileselector_list(list); // Aprs effacement, il ne reste ni fichier ni rpertoire dans la liste // On lit tous les rpertoires: #if defined (__MINT__) static char path[1024]; static char path2[1024]; path[0]='\0'; path2[0]='\0'; char currentDrive='A'; currentDrive=currentDrive+Dgetdrv(); Dgetpath(path,0); sprintf(path2,"%c:\%s",currentDrive,path); strcat(path2,PATH_SEPARATOR); current_directory=opendir(path2); #else current_path=getcwd(NULL,0); current_directory=opendir(current_path); #endif while ((entry=readdir(current_directory))) { // On ignore le rpertoire courant if ( !strcmp(entry->d_name, ".")) { continue; } stat(entry->d_name,&Infos_enreg); // et que l'lment trouv est un rpertoire if( S_ISDIR(Infos_enreg.st_mode) && // et que c'est ".." (!strcmp(entry->d_name, PARENT_DIR) || // ou qu'il n'est pas cach Config.Show_hidden_directories || !File_is_hidden(entry->d_name, entry->d_name))) { // On rajoute le rpertoire la liste Add_element_to_list(list, entry->d_name, Format_filename(entry->d_name, 19, 1), 1, ICON_NONE); list->Nb_directories++; } else if (S_ISREG(Infos_enreg.st_mode) && //Il s'agit d'un fichier (Config.Show_hidden_files || //Il n'est pas cach !File_is_hidden(entry->d_name, entry->d_name))) { const char * ext = filter; while (ext!=NULL) { if (Check_extension(entry->d_name, ext)) { // On rajoute le fichier la liste Add_element_to_list(list, entry->d_name, Format_filename(entry->d_name, 19, 0), 0, ICON_NONE); list->Nb_files++; // Stop searching ext=NULL; } else { ext = strchr(ext, ';'); if (ext) ext++; } } } } #if defined(__MORPHOS__) || defined(__AROS__) || defined (__amigaos4__) || defined(__amigaos__) Add_element_to_list(list, "/", Format_filename("/",19,1), 1, ICON_NONE); // on amiga systems, / means parent. And there is no .. list->Nb_directories ++; #elif defined (__MINT__) T_Fileselector_item *item=NULL; // check if ".." exists if not add it // FreeMinT lists ".." already, but this is not so for TOS // simply adding it will cause double PARENT_DIR under FreeMiNT bool bFound= false; for (item = list->First; (((item != NULL) && (bFound==false))); item = item->Next){ if (item->Type == 1){ if(strncmp(item->Full_name,"..",(sizeof(char)*2))==0) bFound=true; } } if(!bFound){ Add_element_to_list(list, "..",1,Format_filename("/",19,1),ICON_NONE); // add if not present list->Nb_directories ++; } #endif closedir(current_directory); #if defined (__MINT__) #else free(current_path); #endif current_path = NULL; Recount_files(list); } #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) void bstrtostr( BSTR in, STRPTR out, TEXT max ) { STRPTR iptr; dword i; iptr = BADDR( in ); if( max > iptr[0] ) max = iptr[0]; #if defined(__AROS__) for ( i=0 ; iNb_files=0; list->Nb_directories=0; #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) { struct DosList *dl; char tmp[256]; dl = LockDosList( LDF_VOLUMES | LDF_READ ); if( dl ) { while( ( dl = NextDosEntry( dl, LDF_VOLUMES | LDF_READ ) ) ) { bstrtostr( dl->dol_Name, tmp, 254 ); strcat( tmp, ":" ); Add_element_to_list(list, tmp, Format_filename(tmp, name_length, 2), 2, ICON_NONE ); list->Nb_directories++; } UnLockDosList( LDF_VOLUMES | LDF_READ ); } } #elif defined (__WIN32__) { char drive_name[]="A:\\"; int drive_bits = GetLogicalDrives(); int drive_index; int bit_index; byte icon; // Sous Windows, on a la totale, presque aussi bien que sous DOS: drive_index = 0; for (bit_index=0; bit_index<26 && drive_index<23; bit_index++) { if ( (1 << bit_index) & drive_bits ) { // On a ce lecteur, il faut maintenant dterminer son type "physique". // pour profiter des jolies icones de X-man. char drive_path[]="A:\\"; // Cette API Windows est trange, je dois m'y faire... drive_path[0]='A'+bit_index; switch (GetDriveType(drive_path)) { case DRIVE_CDROM: icon=ICON_CDROM; break; case DRIVE_REMOTE: icon=ICON_NETWORK; break; case DRIVE_REMOVABLE: icon=ICON_FLOPPY_3_5; break; case DRIVE_FIXED: icon=ICON_HDD; break; default: icon=ICON_NETWORK; break; } drive_name[0]='A'+bit_index; Add_element_to_list(list, drive_name, Format_filename(drive_name,name_length-1,2), 2, icon); list->Nb_directories++; drive_index++; } } } #elif defined(__MINT__) char drive_name[]="A:\\"; unsigned long drive_bits = Drvmap(); //get drive map bitfield int drive_index; int bit_index; drive_index = 0; for (bit_index=0; bit_index<32; bit_index++) { if ( (1 << bit_index) & drive_bits ) { drive_name[0]='A'+bit_index; Add_element_to_list(list, drive_name,Format_filename(drive_name,name_length,2),2,ICON_NONE); list->Nb_directories++; drive_index++; } } #else { //Sous les diffrents unix, on va mettre // un disque dur qui pointera vers la racine, // et un autre vers le home directory de l'utilisateur. // Ensuite on utilise read_file_system_list pour complter struct mount_entry* mount_points_list; struct mount_entry* next; #if defined(__BEOS__) || defined(__HAIKU__) char * home_dir = getenv("$HOME"); #else char * home_dir = getenv("HOME"); #endif Add_element_to_list(list, "/", Format_filename("/",name_length,2), 2, ICON_NONE); list->Nb_directories++; if(home_dir) { Add_element_to_list(list, home_dir, Format_filename(home_dir, name_length, 2), 2, ICON_NONE); list->Nb_directories++; } mount_points_list = read_file_system_list(0); while(mount_points_list != NULL) { if(mount_points_list->me_dummy == 0 && strcmp(mount_points_list->me_mountdir,"/") && strcmp(mount_points_list->me_mountdir,"/home")) { Add_element_to_list(list, mount_points_list->me_mountdir, Format_filename(mount_points_list->me_mountdir, name_length, 2), 2, ICON_NONE); list->Nb_directories++; } next = mount_points_list -> me_next; #if !(defined(__macosx__) || defined(__FreeBSD__)) free(mount_points_list -> me_type); #endif free(mount_points_list -> me_devname); free(mount_points_list -> me_mountdir); free(mount_points_list); mount_points_list = next; } } #endif Recount_files(list); } // Comparison of file names: #ifdef WIN32 // case-insensitive #define FILENAME_COMPARE strcasecmp #else // case-sensitive #define FILENAME_COMPARE strcmp #endif // -- Tri de la liste des fichiers et rpertoires --------------------------- void Sort_list_of_files(T_Fileselector *list) // Tri la liste chaine existante dans l'ordre suivant: // // * Les rpertoires d'abord, dans l'ordre alphabtique de leur nom // * Les fichiers ensuite, dans l'ordre alphabtique de leur nom { byte list_is_sorted; // Boolen "La liste est trie" byte need_swap; // Boolen "Il faut inverser les lments" T_Fileselector_item * prev_item; T_Fileselector_item * current_item; T_Fileselector_item * next_item; T_Fileselector_item * next_to_next_item; // Check there are at least two elements before sorting if (list->First && list->First->Next) { do { // Par dfaut, on considre que la liste est trie list_is_sorted=1; current_item=list->First; next_item=current_item->Next; while ( (current_item!=NULL) && (next_item!=NULL) ) { // On commence par supposer qu'il n'y pas pas besoin d'inversion need_swap=0; // Ensuite, on vrifie si les deux lments sont bien dans l'ordre ou // non: // Si l'lment courant est un fichier est que le suivant est // un rpertoire -> need_swap if ( current_item->Type < next_item->Type ) need_swap=1; // Si les deux lments sont de mme type et que le nom du suivant // est plus petit que celui du courant -> need_swap else if ( (current_item->Type==next_item->Type) && (FILENAME_COMPARE(current_item->Full_name,next_item->Full_name)>0) ) need_swap=1; if (need_swap) { // Si les deux lments ncessitent d'tre invers: // On les inverses: // On note avant tout les lments qui encapsulent nos deux amis prev_item =current_item->Previous; next_to_next_item=next_item->Next; // On permute le chanage des deux lments entree eux current_item->Next =next_to_next_item; current_item->Previous=next_item; next_item->Next =current_item; next_item->Previous=prev_item; // On tente un chanage des lments encapsulant les compres: if (prev_item!=NULL) prev_item->Next=next_item; if (next_to_next_item!=NULL) next_to_next_item->Previous=current_item; // On fait bien attention modifier la tte de liste en cas de besoin if (current_item==list->First) list->First=next_item; // Ensuite, on se prpare tudier les lments prcdents: current_item=prev_item; // Et on constate que la liste n'tait pas encore gnialement trie list_is_sorted=0; } else { // Si les deux lments sont dans l'ordre: // On passe aux suivants current_item=current_item->Next; next_item=next_item->Next; } } } while (!list_is_sorted); } // Force a recount / re-index Recount_files(list); } T_Fileselector_item * Get_item_by_index(T_Fileselector *list, short index) { // Safety if (index >= list->Nb_elements) index=list->Nb_elements-1; if (list->Index) { return list->Index[index]; } else { // Index not available. // Can only happen in case of malloc error. // Fall back anyway on iterative search T_Fileselector_item * item = list->First; for (;index>0;index--) item = item->Next; return item; } } // -- Affichage des lments de la liste de fichier / rpertoire ------------ void Display_file_list(T_Fileselector *list, short offset_first,short selector_offset) // // offset_first = Dcalage entre le premier fichier visible dans le // slecteur et le premier fichier de la liste // // selector_offset = Dcalage entre le premier fichier visible dans le // slecteur et le fichier slectionn dans la liste // { T_Fileselector_item * current_item; byte index; // index du fichier qu'on affiche (0 -> 9) byte text_color; byte background_color; // On vrifie s'il y a au moins 1 fichier dans la liste: if (list->Nb_elements>0) { // On commence par chercher pointer sur le premier fichier visible: current_item = Get_item_by_index(list, offset_first); // Pour chacun des 10 lments inscriptibles l'cran for (index=0;index<10;index++) { // S'il est slectionn: if (!selector_offset) { // Si c'est un fichier if (current_item->Type==0) text_color=SELECTED_FILE_COLOR; else text_color=SELECTED_DIRECTORY_COLOR; background_color=SELECTED_BACKGROUND_COLOR; } else { // Si c'est un fichier if (current_item->Type==0) text_color=NORMAL_FILE_COLOR; else text_color=NORMAL_DIRECTORY_COLOR; background_color=NORMAL_BACKGROUND_COLOR; } // On affiche l'lment if (current_item->Icon != ICON_NONE) { // Name preceded by an icon Print_in_window(16,95+index*8,current_item->Short_name,text_color,background_color); Window_display_icon_sprite(8,95+index*8,current_item->Icon); } else // Name without icon Print_in_window(8,95+index*8,current_item->Short_name,text_color,background_color); // On passe la ligne suivante selector_offset--; current_item=current_item->Next; if (!current_item) break; } // End de la boucle d'affichage } // End du test d'existence de fichiers } // -- Rcuprer le libell d'un lment de la liste ------------------------- void Get_selected_item(T_Fileselector *list, short offset_first,short selector_offset,char * label,int *type) // // offset_first = Dcalage entre le premier fichier visible dans le // slecteur et le premier fichier de la liste // // selector_offset = Dcalage entre le premier fichier visible dans le // slecteur et le fichier rcuprer // // label = str de rception du libell de l'lment // // type = Rcupration du type: 0 fichier, 1 repertoire, 2 lecteur. // Passer NULL si pas interess. { T_Fileselector_item * current_item; // On vrifie s'il y a au moins 1 fichier dans la liste: if (list->Nb_elements>0) { // On commence par chercher pointer sur le premier fichier visible: // Ensuite, on saute autant d'lments que le dcalage demand: current_item = Get_item_by_index(list, offset_first + selector_offset); // On recopie la chane strcpy(label, current_item->Full_name); if (type != NULL) *type=current_item->Type; } // End du test d'existence de fichiers } // ----------------- Dplacements dans la liste de fichiers ----------------- void Selector_scroll_down(short * offset_first,short * selector_offset) // Fait scroller vers le bas le slecteur de fichier... (si possible) { if ( ((*selector_offset)<9) && ( (*selector_offset)+1 < Filelist.Nb_elements ) ) // Si la slection peut descendre Display_file_list(&Filelist, *offset_first,++(*selector_offset)); else // Sinon, descendre la fentre (si possible) if ((*offset_first)+100) // Si la slection peut monter Display_file_list(&Filelist, *offset_first,--(*selector_offset)); else // Sinon, monter la fentre (si possible) if ((*offset_first)>0) Display_file_list(&Filelist, --(*offset_first),*selector_offset); } void Selector_page_down(short * offset_first,short * selector_offset, short lines) { if (Filelist.Nb_elements-1>*offset_first+*selector_offset) { if (*selector_offset<9) { if (Filelist.Nb_elements<10) { *offset_first=0; *selector_offset=Filelist.Nb_elements-1; } else *selector_offset=9; } else { if (Filelist.Nb_elements>*offset_first+18) *offset_first+=lines; else { *offset_first=Filelist.Nb_elements-10; *selector_offset=9; } } } Display_file_list(&Filelist, *offset_first,*selector_offset); } void Selector_page_up(short * offset_first,short * selector_offset, short lines) { if (*offset_first+*selector_offset>0) { if (*selector_offset>0) *selector_offset=0; else { if (*offset_first>lines) *offset_first-=lines; else *offset_first=0; } } Display_file_list(&Filelist, *offset_first,*selector_offset); } void Selector_end(short * offset_first,short * selector_offset) { if (Filelist.Nb_elements<10) { *offset_first=0; *selector_offset=Filelist.Nb_elements-1; } else { *offset_first=Filelist.Nb_elements-10; *selector_offset=9; } Display_file_list(&Filelist, *offset_first,*selector_offset); } void Selector_home(short * offset_first,short * selector_offset) { Display_file_list(&Filelist, (*offset_first)=0,(*selector_offset)=0); } short Compute_click_offset_in_fileselector(void) /* Renvoie le dcalage dans le slecteur de fichier sur lequel on a click. Renvoie le dcalage du dernier fichier si on a click au del. Renvoie -1 si le slecteur est vide. */ { short computed_offset; computed_offset=(((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-95)>>3; if (computed_offset>=Filelist.Nb_elements) computed_offset=Filelist.Nb_elements-1; return computed_offset; } void Display_bookmark(T_Dropdown_button * Button, int bookmark_number) { if (Config.Bookmark_directory[bookmark_number]) { int label_size; // Libell Print_in_window_limited(Button->Pos_X+3+10,Button->Pos_Y+2,Config.Bookmark_label[bookmark_number],8,MC_Black,MC_Light); label_size=strlen(Config.Bookmark_label[bookmark_number]); if (label_size<8) Window_rectangle(Button->Pos_X+3+10+label_size*8,Button->Pos_Y+2,(8-label_size)*8,8,MC_Light); // Menu apparait sur clic droit Button->Active_button=RIGHT_SIDE; // item actifs Window_dropdown_clear_items(Button); Window_dropdown_add_item(Button,0,"Set"); Window_dropdown_add_item(Button,1,"Rename"); Window_dropdown_add_item(Button,2,"Clear"); } else { // Libell Print_in_window(Button->Pos_X+3+10,Button->Pos_Y+2,"--------",MC_Dark,MC_Light); // Menu apparait sur clic droit ou gauche Button->Active_button=RIGHT_SIDE|LEFT_SIDE; // item actifs Window_dropdown_clear_items(Button); Window_dropdown_add_item(Button,0,"Set"); } } //------------------------ Chargements et sauvegardes ------------------------ void Print_current_directory(void) // // Affiche Main_current_directory sur 37 caractres // { char temp_name[MAX_DISPLAYABLE_PATH+1]; // Nom tronqu int length; // length du rpertoire courant int index; // index de parcours de la chaine complte Window_rectangle(10,84,37*8,8,MC_Light); length=strlen(Main_current_directory); if (length>MAX_DISPLAYABLE_PATH) { // Doh! il va falloir tronquer le rpertoire (bouh !) // On commence par copier btement les 3 premiers caractres (e.g. "C:\") for (index=0;index<3;index++) temp_name[index]=Main_current_directory[index]; // On y rajoute 3 petits points: strcpy(temp_name+3,"..."); // Ensuite, on cherche un endroit partir duquel on pourrait loger tout // le reste de la chaine (Ouaaaaaah!!! Vachement fort le mec!!) for (index++;indexNb_elements=Filelist.Nb_elements; button->Position=Position; Compute_slider_cursor_length(button); Window_draw_slider(button); // On efface les anciens noms de fichier: Window_rectangle(8-1,95-1,144+2,80+2,MC_Black); // On affiche les nouveaux: Display_file_list(&Filelist, Position,offset); Update_window_area(8-1,95-1,144+2,80+2); // On rcupre le nom du schmilblick "accder" Get_selected_item(&Filelist, Position,offset,Selector_filename,&Selected_type); // On affiche le nouveau nom de fichier Print_filename_in_fileselector(); // On affiche le nom du rpertoire courant Print_current_directory(); } void Reload_list_of_files(byte filter, T_Scroller_button * button) { Read_list_of_files(&Filelist, filter); Sort_list_of_files(&Filelist); // // Check and fix the fileselector positions, because // the directory content may have changed. // // Make the offset absolute Main_fileselector_offset += Main_fileselector_position; // Ensure it's within limits if (Main_fileselector_offset >= Filelist.Nb_elements) { Main_fileselector_offset = Filelist.Nb_elements-1; } // Ensure the position doesn't show "too many files" if (Main_fileselector_position!=0 && Main_fileselector_position>(Filelist.Nb_elements-10)) { if (Filelist.Nb_elements<10) { Main_fileselector_position=0; } else { Main_fileselector_position=Filelist.Nb_elements-10; } } // Restore the offset as relative to the position. Main_fileselector_offset -= Main_fileselector_position; Prepare_and_display_filelist(Main_fileselector_position,Main_fileselector_offset,button); } void Scroll_fileselector(T_Scroller_button * file_scroller) { char old_filename[MAX_PATH_CHARACTERS]; strcpy(old_filename,Selector_filename); // On regarde si la liste a boug if (file_scroller->Position!=Main_fileselector_position) { // Si c'est le cas, il faut mettre jour la jauge file_scroller->Position=Main_fileselector_position; Window_draw_slider(file_scroller); } // On rcupre le nom du schmilblick "accder" Get_selected_item(&Filelist, Main_fileselector_position,Main_fileselector_offset,Selector_filename,&Selected_type); if (strcmp(old_filename,Selector_filename)) New_preview_is_needed=1; // On affiche le nouveau nom de fichier Print_filename_in_fileselector(); Display_cursor(); } short Find_file_in_fileselector(T_Fileselector *list, const char * fname) { T_Fileselector_item * item; short index; short close_match=0; index=0; for (item=list->First; item!=NULL; item=item->Next) { if (strcmp(item->Full_name,fname)==0) return index; if (strcasecmp(item->Full_name,fname)==0) close_match=index; index++; } return close_match; } void Highlight_file(short index) { if ((Filelist.Nb_elements<=10) || (index<5)) { Main_fileselector_position=0; Main_fileselector_offset=index; } else { if (index>=Filelist.Nb_elements-5) { Main_fileselector_position=Filelist.Nb_elements-10; Main_fileselector_offset=index-Main_fileselector_position; } else { Main_fileselector_position=index-4; Main_fileselector_offset=4; } } } short Find_filename_match(T_Fileselector *list, char * fname) { short best_match; T_Fileselector_item * current_item; short item_number; byte matching_letters=0; byte counter; best_match=-1; item_number=0; for (current_item=list->First; current_item!=NULL; current_item=current_item->Next) { if ( (!Config.Find_file_fast) || (Config.Find_file_fast==(current_item->Type+1)) ) { // On compare et si c'est mieux, on stocke dans Meilleur_nom for (counter=0; fname[counter]!='\0' && tolower(current_item->Full_name[counter])==tolower(fname[counter]); counter++); if (counter>matching_letters) { matching_letters=counter; best_match=item_number; } } item_number++; } return best_match; } // Quicksearch system char quicksearch_filename[MAX_PATH_CHARACTERS]=""; void Reset_quicksearch(void) { quicksearch_filename[0]='\0'; } short Quicksearch(T_Fileselector *selector) { int len; short most_matching_item; // Autre => On se place sur le nom de fichier qui correspond len=strlen(quicksearch_filename); if (Key_ANSI>= ' ' && Key_ANSI < 255 && len<50) { quicksearch_filename[len]=Key_ANSI; quicksearch_filename[len+1]='\0'; most_matching_item=Find_filename_match(selector, quicksearch_filename); if ( most_matching_item >= 0 ) { return most_matching_item; } *quicksearch_filename=0; } return -1; } // Translated from Highlight_file void Locate_list_item(T_List_button * list, short selected_item) { // Safety bounds if (selected_item<0) selected_item=0; else if (selected_item>=list->Scroller->Nb_elements) selected_item=list->Scroller->Nb_elements-1; if ((list->Scroller->Nb_elements<=list->Scroller->Nb_visibles) || (selected_item<(list->Scroller->Nb_visibles/2))) { list->List_start=0; list->Cursor_position=selected_item; } else { if (selected_item>=list->Scroller->Nb_elements-(list->Scroller->Nb_visibles/2)) { list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles; list->Cursor_position=selected_item-list->List_start; } else { list->List_start=selected_item-(list->Scroller->Nb_visibles/2-1); list->Cursor_position=(list->Scroller->Nb_visibles/2-1); } } } int Quicksearch_list(T_List_button * list, T_Fileselector * selector) { // Try Quicksearch short selected_item=Quicksearch(selector); if (selected_item>=0 && selected_item!=list->Cursor_position+list->List_start) { Locate_list_item(list, selected_item); Hide_cursor(); // Mise jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); Window_redraw_list(list); Display_cursor(); // Store the selected value as attribute2 Window_attribute2=list->List_start + list->Cursor_position; // Return the control ID of the list. return list->Number; } return 0; } byte Button_Load_or_Save(byte load, T_IO_Context *context) // load=1 => On affiche le menu du bouton LOAD // load=0 => On affiche le menu du bouton SAVE { short clicked_button; T_Scroller_button * file_scroller; T_Dropdown_button * formats_dropdown; T_Dropdown_button * bookmark_dropdown[4]; short temp; unsigned int format; int dummy=0; // Sert appeler SDL_GetKeyState byte save_or_load_image=0; byte has_clicked_ok=0;// Indique si on a click sur Load ou Save ou sur //un bouton enclenchant Load ou Save juste aprs. byte initial_back_color; // | fout en l'air (c'te conne). char previous_directory[MAX_PATH_CHARACTERS]; // Rpertoire d'o l'on vient aprs un CHDIR char save_filename[MAX_PATH_CHARACTERS]; char initial_comment[COMMENT_SIZE+1]; short window_shortcut; Reset_quicksearch(); // if (Native_filesel(load) != 0); // TODO : handle this if (context->Type == CONTEXT_MAIN_IMAGE) window_shortcut = load?(0x100+BUTTON_LOAD):(0x100+BUTTON_SAVE); else window_shortcut = load?SPECIAL_LOAD_BRUSH:SPECIAL_SAVE_BRUSH; // Backup data that needs be restored on "cancel" initial_back_color=Back_color; strcpy(initial_comment,context->Comment); if (load) { if (context->Type == CONTEXT_MAIN_IMAGE) Open_window(310,200,"Load picture"); else Open_window(310,200,"Load brush"); Window_set_normal_button(198,180,51,14,"Load",0,1,SDLK_RETURN); // 1 } else { if (context->Type == CONTEXT_MAIN_IMAGE) Open_window(310,200,"Save picture"); else Open_window(310,200,"Save brush"); Window_set_normal_button(198,180,51,14,"Save",0,1,SDLK_RETURN); // 1 if (Main_format<=FORMAT_ALL_FILES) // Correction du *.* { Main_format=Main_fileformat; Main_fileselector_position=0; Main_fileselector_offset=0; } if (Get_fileformat(Main_format)->Save == NULL) // Correction d'un format insauvable { Main_format=DEFAULT_FILEFORMAT; Main_fileselector_position=0; Main_fileselector_offset=0; } // Affichage du commentaire if (Get_fileformat(Main_format)->Comment) Print_in_window(45,70,context->Comment,MC_Black,MC_Light); } Window_set_normal_button(253,180,51,14,"Cancel",0,1,KEY_ESC); // 2 Window_set_normal_button(7,180,51,14,"Delete",0,1,SDLK_DELETE); // 3 // Frame autour des infos sur le fichier de dessin Window_display_frame_in(6, 44,299, 37); // Frame autour de la preview Window_display_frame_in(181,93,124,84); // Frame autour du fileselector Window_display_frame_in(6,93,148,84); // Fileselector Window_set_special_button(9,95,144,80); // 4 // Scroller du fileselector file_scroller = Window_set_scroller_button(160,94,82,1,10,0); // 5 // Dropdown pour les formats de fichier formats_dropdown= Window_set_dropdown_button(68,28,52,11,0, Get_fileformat(Main_format)->Label, 1,0,1,RIGHT_SIDE|LEFT_SIDE,0); // 6 for (format=0; format < Nb_known_formats(); format++) { if ((load && (File_formats[format].Identifier <= FORMAT_ALL_FILES || File_formats[format].Load)) || (!load && File_formats[format].Save)) Window_dropdown_add_item(formats_dropdown,File_formats[format].Identifier,File_formats[format].Label); } Print_in_window(70,18,"Format",MC_Dark,MC_Light); // Texte de commentaire des dessins Print_in_window(9,70,"Txt:",MC_Dark,MC_Light); Window_set_input_button(43,68,COMMENT_SIZE); // 7 // Saisie du nom de fichier Window_set_input_button(80,46,27); // 8 Print_in_window(9,47,"Filename",MC_Dark,MC_Light); Print_in_window(9,59,"Image:",MC_Dark,MC_Light); Print_in_window(101,59,"Size:",MC_Dark,MC_Light); Print_in_window(228,59,"(",MC_Dark,MC_Light); Print_in_window(292,59,")",MC_Dark,MC_Light); // Selecteur de Lecteur / Volume Window_set_normal_button(7,18,53,23,"",0,1,SDLK_LAST); // 9 Print_in_window(10,22,"Select",MC_Black,MC_Light); Print_in_window(14,30,"drive",MC_Black,MC_Light); // Bookmarks for (temp=0;tempPos_X+3,bookmark_dropdown[temp]->Pos_Y+2,ICON_STAR); Display_bookmark(bookmark_dropdown[temp],temp); } // On prend bien soin de passer dans le rpertoire courant (le bon qui faut! Oui madame!) if (load) { #if defined(__MINT__) chdir(Main_current_directory); static char path[1024]={0}; Dgetpath(path,0); strcat(path,PATH_SEPARATOR); strcpy(Main_current_directory,path); #else chdir(Main_current_directory); getcwd(Main_current_directory,256); #endif } else { #if defined(__MINT__) static char path[1024]={0}; chdir(context->File_directory); Dgetpath(path,0); strcat(path,PATH_SEPARATOR); strcpy(Main_current_directory,path); #else chdir(context->File_directory); getcwd(Main_current_directory,256); #endif } // Affichage des premiers fichiers visibles: Reload_list_of_files(Main_format,file_scroller); if (!load) { // On initialise le nom de fichier celui en cours et non pas celui sous // la barre de slection strcpy(Selector_filename,context->File_name); // On affiche le nouveau nom de fichier Print_filename_in_fileselector(); Highlight_file(Find_file_in_fileselector(&Filelist, context->File_name)); Prepare_and_display_filelist(Main_fileselector_position,Main_fileselector_offset,file_scroller); } New_preview_is_needed=1; Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); switch (clicked_button) { case -1 : case 0 : break; case 1 : // Load ou Save if(load) { // Determine the type if(File_exists(Selector_filename)) { Selected_type = 0; if(Directory_exists(Selector_filename)) Selected_type = 1; } else { Selected_type = 1; } } else { if(Directory_exists(Selector_filename)) Selected_type = 1; else Selected_type = 0; } has_clicked_ok=1; break; case 2 : // Cancel break; case 3 : // Delete if (Filelist.Nb_elements && (*Selector_filename!='.') && Selected_type!=2) { char * message; Hide_cursor(); // On affiche une demande de confirmation if (Main_fileselector_position+Main_fileselector_offset>=Filelist.Nb_directories) { message="Delete file ?"; } else { message="Remove directory ?"; } if (Confirmation_box(message)) { // Si c'est un fichier if (Main_fileselector_position+Main_fileselector_offset>=Filelist.Nb_directories) // On efface le fichier (si on peut) temp=(!remove(Selector_filename)); else // Si c'est un repertoire // On efface le repertoire (si on peut) temp=(!rmdir(Selector_filename)); if (temp) // temp indique si l'effacement s'est bien pass { // On remonte si c'tait le dernier lment de la liste if (Main_fileselector_position+Main_fileselector_offset==Filelist.Nb_elements-1) { if (Main_fileselector_position) Main_fileselector_position--; else if (Main_fileselector_offset) Main_fileselector_offset--; } else // Si ce n'tait pas le dernier, il faut faire gaffe ce { // que ses copains d'en dessous ne remontent pas trop. if ( (Main_fileselector_position) && (Main_fileselector_position+10==Filelist.Nb_elements) ) { Main_fileselector_position--; Main_fileselector_offset++; } } // On relit les informations Reload_list_of_files(Main_format,file_scroller); // On demande la preview du nouveau fichier sur lequel on se trouve New_preview_is_needed=1; } else Error(0); // On place la barre de slection du brouillon au dbut s'il a le // mme rpertoire que l'image principale. if (!strcmp(Main_current_directory,Spare_current_directory)) { Spare_fileselector_position=0; Spare_fileselector_offset=0; } } } break; case 4 : // Zone d'affichage de la liste de fichiers Hide_cursor(); temp=Compute_click_offset_in_fileselector(); if (temp>=0) { if (temp!=Main_fileselector_offset) { // On met jour le dcalage Main_fileselector_offset=temp; // On rcupre le nom du schmilblick "accder" Get_selected_item(&Filelist, Main_fileselector_position,Main_fileselector_offset,Selector_filename,&Selected_type); // On affiche le nouveau nom de fichier Print_filename_in_fileselector(); // On affiche nouveau la liste Display_file_list(&Filelist, Main_fileselector_position,Main_fileselector_offset); // On vient de changer de nom de fichier, donc on doit s'appreter // a rafficher une preview New_preview_is_needed=1; Reset_quicksearch(); } else { // En sauvegarde, si on a double-click sur un rpertoire, il // faut mettre le nom de fichier au nom du rpertoire. Sinon, dans // certains cas, on risque de sauvegarder avec le nom du fichier // actuel au lieu de changer de rpertoire. if (Main_fileselector_position+Main_fileselector_offsetDefault_extension[0] != '\0' && Selector_filename[nameLength - 4] == '.') { strcpy(Selector_filename + nameLength - 3, Get_fileformat(Main_format)->Default_extension); } free(savename); Print_filename_in_fileselector(); Display_cursor(); } break; case 7 : // Saisie d'un commentaire pour la sauvegarde if ( (!load) && (Get_fileformat(Main_format)->Comment) ) { Readline(45, 70, context->Comment, 32, INPUT_TYPE_STRING); Display_cursor(); } break; case 8 : // Saisie du nom de fichier // Save the filename strcpy(save_filename, Selector_filename); if (Readline(82,48,Selector_filename,27,INPUT_TYPE_FILENAME)) { // On regarde s'il faut rajouter une extension. C'est--dire s'il // n'y a pas de '.' dans le nom du fichier. for(temp=0,dummy=0; ((Selector_filename[temp]) && (!dummy)); temp++) if (Selector_filename[temp]=='.') dummy=1; if (!dummy) { if (Get_fileformat(Main_format)->Default_extension) { if(!Directory_exists(Selector_filename)) { strcat(Selector_filename, "."); strcat(Selector_filename, Get_fileformat(Main_format)->Default_extension); } } else { // put default extension // (but maybe we should browse through all available ones until we find // something suitable ?) if(!Directory_exists(Selector_filename)) { strcat(Selector_filename, ".pkm"); } } } if(load) { // Determine the type if(File_exists(Selector_filename)) { Selected_type = 0; if(Directory_exists(Selector_filename)) Selected_type = 1; } else { Selected_type = 1; } } else { if(Directory_exists(Selector_filename)) Selected_type = 1; else Selected_type = 0; } // Now load immediately, but only if the user exited readline by pressing ENTER if (Mouse_K == 0) has_clicked_ok = 1; } else { // Restore the old filename strcpy(Selector_filename, save_filename); Print_filename_in_fileselector(); } Display_cursor(); break; case 9 : // Volume Select Hide_cursor(); // Comme on tombe sur un disque qu'on connait pas, on se place en // dbut de liste: Main_fileselector_position=0; Main_fileselector_offset=0; // Affichage des premiers fichiers visibles: Read_list_of_drives(&Filelist,19); Sort_list_of_files(&Filelist); Prepare_and_display_filelist(Main_fileselector_position,Main_fileselector_offset,file_scroller); Display_cursor(); New_preview_is_needed=1; Reset_quicksearch(); break; default: if (clicked_button>=10 && clicked_button<10+NB_BOOKMARKS) { // Bookmark char * directory_name; switch(Window_attribute2) { case -1: // bouton lui-mme: aller au rpertoire mmoris if (Config.Bookmark_directory[clicked_button-10]) { strcpy(Selector_filename,Config.Bookmark_directory[clicked_button-10]); Selected_type=1; has_clicked_ok=1; Reset_quicksearch(); } break; case 0: // Set free(Config.Bookmark_directory[clicked_button-10]); Config.Bookmark_directory[clicked_button-10] = NULL; Config.Bookmark_label[clicked_button-10][0]='\0'; temp=strlen(Main_current_directory); Config.Bookmark_directory[clicked_button-10]=malloc(temp+1); strcpy(Config.Bookmark_directory[clicked_button-10],Main_current_directory); directory_name=Find_last_slash(Main_current_directory); if (directory_name && directory_name[1]!='\0') directory_name++; else directory_name=Main_current_directory; temp=strlen(directory_name); strncpy(Config.Bookmark_label[clicked_button-10],directory_name,8); if (temp>8) { Config.Bookmark_label[clicked_button-10][7]=ELLIPSIS_CHARACTER; Config.Bookmark_label[clicked_button-10][8]='\0'; } Display_bookmark(bookmark_dropdown[clicked_button-10],clicked_button-10); break; case 1: // Rename if (Config.Bookmark_directory[clicked_button-10]) { // On enlve les "..." avant l'dition char bookmark_label[8+1]; strcpy(bookmark_label, Config.Bookmark_label[clicked_button-10]); if (bookmark_label[7]==ELLIPSIS_CHARACTER) bookmark_label[7]='\0'; if (Readline_ex(bookmark_dropdown[clicked_button-10]->Pos_X+3+10,bookmark_dropdown[clicked_button-10]->Pos_Y+2,bookmark_label,8,8,INPUT_TYPE_STRING,0)) strcpy(Config.Bookmark_label[clicked_button-10],bookmark_label); Display_bookmark(bookmark_dropdown[clicked_button-10],clicked_button-10); Display_cursor(); } break; case 2: // Clear if (Config.Bookmark_directory[clicked_button-10] && Confirmation_box("Erase bookmark ?")) { free(Config.Bookmark_directory[clicked_button-10]); Config.Bookmark_directory[clicked_button-10]=NULL; Config.Bookmark_label[clicked_button-10][0]='\0'; Display_bookmark(bookmark_dropdown[clicked_button-10],clicked_button-10); } break; } } break; } switch (Key) { case SDLK_UNKNOWN : break; case SDLK_DOWN : // Bas Reset_quicksearch(); Hide_cursor(); Selector_scroll_down(&Main_fileselector_position,&Main_fileselector_offset); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_UP : // Haut Reset_quicksearch(); Hide_cursor(); Selector_scroll_up(&Main_fileselector_position,&Main_fileselector_offset); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_PAGEDOWN : // PageDown Reset_quicksearch(); Hide_cursor(); Selector_page_down(&Main_fileselector_position,&Main_fileselector_offset,9); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_PAGEUP : // PageUp Reset_quicksearch(); Hide_cursor(); Selector_page_up(&Main_fileselector_position,&Main_fileselector_offset,9); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_END : // End Reset_quicksearch(); Hide_cursor(); Selector_end(&Main_fileselector_position,&Main_fileselector_offset); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_HOME : // Home Reset_quicksearch(); Hide_cursor(); Selector_home(&Main_fileselector_position,&Main_fileselector_offset); Scroll_fileselector(file_scroller); Key=0; break; case KEY_MOUSEWHEELDOWN : Reset_quicksearch(); Hide_cursor(); Selector_page_down(&Main_fileselector_position,&Main_fileselector_offset,3); Scroll_fileselector(file_scroller); Key=0; break; case KEY_MOUSEWHEELUP : Reset_quicksearch(); Hide_cursor(); Selector_page_up(&Main_fileselector_position,&Main_fileselector_offset,3); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_BACKSPACE : // Backspace Reset_quicksearch(); // Si le choix ".." est bien en tte des propositions... if (!strcmp(Filelist.First->Full_name,PARENT_DIR)) { // On va dans le rpertoire parent. strcpy(Selector_filename,PARENT_DIR); Selected_type=1; has_clicked_ok=1; } Key=0; break; default: if (clicked_button<=0) { short selected_item; if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Window_help(load?BUTTON_LOAD:BUTTON_SAVE, NULL); break; } if (Is_shortcut(Key,window_shortcut)) { clicked_button=2; break; } selected_item=Quicksearch(&Filelist); if (selected_item>=0) { temp=Main_fileselector_position+Main_fileselector_offset; Hide_cursor(); Highlight_file(selected_item); Prepare_and_display_filelist(Main_fileselector_position,Main_fileselector_offset,file_scroller); Display_cursor(); if (temp!=Main_fileselector_position+Main_fileselector_offset) New_preview_is_needed=1; } // Key=0; ? } else Reset_quicksearch(); } if (has_clicked_ok) { // Si c'est un rpertoire, on annule "has_clicked_ok" et on passe // dedans. if (Selected_type!=0) { Hide_cursor(); has_clicked_ok=0; // On mmorise le rpertoire dans lequel on tait if (strcmp(Selector_filename,PARENT_DIR)) { strcpy(previous_directory,PARENT_DIR); } else { Extract_filename(previous_directory, Main_current_directory); } // On doit rentrer dans le rpertoire: if (!chdir(Selector_filename)) { #if defined (__MINT__) static char path[1024]={0}; char currentDrive='A'; currentDrive=currentDrive+Dgetdrv(); Dgetpath(path,0); sprintf(Main_current_directory,"%c:\%s",currentDrive,path); #else getcwd(Main_current_directory,256); #endif // On lit le nouveau rpertoire Read_list_of_files(&Filelist, Main_format); Sort_list_of_files(&Filelist); // On place la barre de slection sur le rpertoire d'o l'on vient Highlight_file(Find_file_in_fileselector(&Filelist, previous_directory)); } else Error(0); // Affichage des premiers fichiers visibles: Prepare_and_display_filelist(Main_fileselector_position,Main_fileselector_offset,file_scroller); Display_cursor(); New_preview_is_needed=1; // On est dans un nouveau rpertoire, donc on remet le quicksearch 0 Reset_quicksearch(); } else // Sinon on essaye de charger ou sauver le fichier { strcpy(context->File_directory,Main_current_directory); if (!load && !Get_fileformat(Main_format)->Palette_only) Main_fileformat=Main_format; save_or_load_image=1; } } // Gestion du chrono et des previews if (New_preview_is_needed) { // On efface les infos de la preview prcdente s'il y en a une // d'affiche if (Timer_state==2) { Hide_cursor(); // On efface le commentaire prcdent Window_rectangle(45,70,32*8,8,MC_Light); // On nettoie la zone o va s'afficher la preview: Window_rectangle(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT,MC_Light); // On efface les dimensions de l'image Window_rectangle(143,59,72,8,MC_Light); // On efface la taille du fichier Window_rectangle(236,59,56,8,MC_Light); // On efface le format du fichier Window_rectangle(59,59,5*8,8,MC_Light); // Affichage du commentaire if ( (!load) && (Get_fileformat(Main_format)->Comment) ) { Print_in_window(45,70,context->Comment,MC_Black,MC_Light); } Display_cursor(); // Un update pour couvrir les 4 zones: 3 libells plus le commentaire Update_window_area(45,48,256,30); // Zone de preview Update_window_area(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT); } New_preview_is_needed=0; Timer_state=0; // State du chrono = Attente d'un Xme de seconde // On lit le temps de dpart du chrono Init_chrono(Config.Timer_delay); } if (!Timer_state) // Prendre une nouvelle mesure du chrono et regarder Check_timer(); // s'il ne faut pas afficher la preview if (Timer_state==1) // Il faut afficher la preview { if ( (Main_fileselector_position+Main_fileselector_offset>=Filelist.Nb_directories) && (Filelist.Nb_elements) ) { T_IO_Context preview_context; Init_context_preview(&preview_context, Selector_filename, Main_current_directory); Hide_cursor(); Load_image(&preview_context); Destroy_context(&preview_context); Update_window_area(0,0,Window_width,Window_height); Display_cursor(); } Timer_state=2; // On arrte le chrono } } while ( (!has_clicked_ok) && (clicked_button!=2) ); if (has_clicked_ok) { strcpy(context->File_name, Selector_filename); strcpy(context->File_directory, Main_current_directory); if (!load) context->Format = Main_format; } else { // Data to restore strcpy(context->Comment, initial_comment); } // On restaure les donnes de l'image qui ont certainement t modifies // par la preview. Set_palette(Main_palette); Back_color=initial_back_color; Compute_optimal_menu_colors(Main_palette); temp=(Window_pos_Y+(Window_height*Menu_factor_Y) ******************************************************************************** Drawing functions and effects. */ #include #include #include #include "global.h" #include "struct.h" #include "engine.h" #include "buttons.h" #include "pages.h" #include "errors.h" #include "sdlscreen.h" #include "graph.h" #include "misc.h" #include "pxsimple.h" #include "pxtall.h" #include "pxwide.h" #include "pxdouble.h" #include "pxtriple.h" #include "pxwide2.h" #include "pxtall2.h" #include "pxquad.h" #include "windows.h" #include "input.h" #include "brush.h" #ifdef __VBCC__ #define __attribute__(x) #endif #if defined(__VBCC__) || defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) #define M_PI 3.141592653589793238462643 #endif // Generic pixel-drawing function. Func_pixel Pixel_figure; // Fonction qui met jour la zone de l'image donne en paramtre sur l'cran. // Tient compte du dcalage X et Y et du zoom, et fait tous les controles ncessaires void Update_part_of_screen(short x, short y, short width, short height) { short effective_w, effective_h; short effective_X; short effective_Y; short diff; // Premire tape, si L ou H est ngatif, on doit remettre la zone l'endroit if (width < 0) { x += width; width = - width; } if (height < 0) { y += height; height = - height; } // D'abord on met jour dans la zone cran normale diff = x-Main_offset_X; if (diff<0) { effective_w = width + diff; effective_X = 0; } else { effective_w = width; effective_X = diff; } diff = y-Main_offset_Y; if (diff<0) { effective_h = height + diff; effective_Y = 0; } else { effective_h = height; effective_Y = diff; } // Normalement il ne faudrait pas updater au del du split quand on est en mode loupe, // mais personne ne devrait demander d'update en dehors de cette limite, mme le fill est contraint // a rester dans la zone visible de l'image // ...Sauf l'affichage de brosse en preview - yr if(Main_magnifier_mode && effective_X + effective_w > Main_separator_position) effective_w = Main_separator_position - effective_X; else if(effective_X + effective_w > Screen_width) effective_w = Screen_width - effective_X; if(effective_Y + effective_h > Menu_Y) effective_h = Menu_Y - effective_Y; /* SDL_Rect r; r.x=effective_X; r.y=effective_Y; r.h=effective_h; r.w=effective_w; SDL_FillRect(Screen_SDL,&r,3); */ Update_rect(effective_X,effective_Y,effective_w,effective_h); // Et ensuite dans la partie zoome if(Main_magnifier_mode) { // Clipping en X effective_X = (x-Main_magnifier_offset_X)*Main_magnifier_factor; effective_Y = (y-Main_magnifier_offset_Y)*Main_magnifier_factor; effective_w = width * Main_magnifier_factor; effective_h = height * Main_magnifier_factor; if (effective_X < 0) { effective_w+=effective_X; if (effective_w<0) return; effective_X = Main_separator_position + SEPARATOR_WIDTH*Menu_factor_X; } else effective_X += Main_separator_position + SEPARATOR_WIDTH*Menu_factor_X; diff = effective_X+effective_w-Min(Screen_width, Main_X_zoom+(Main_image_width-Main_magnifier_offset_X)*Main_magnifier_factor); if (diff>0) { effective_w -=diff; if (effective_w<0) return; } // Clipping en Y if (effective_Y < 0) { effective_h+=effective_Y; if (effective_h<0) return; effective_Y = 0; } diff = effective_Y+effective_h-Min(Menu_Y, (Main_image_height-Main_magnifier_offset_Y)*Main_magnifier_factor); if (diff>0) { effective_h -=diff; if (effective_h<0) return; } // Trs utile pour le debug :) /*SDL_Rect r; r.x=effective_X; r.y=effective_Y; r.h=effective_h; r.w=effective_w; SDL_FillRect(Screen_SDL,&r,3);*/ Redraw_grid(effective_X,effective_Y,effective_w,effective_h); Update_rect(effective_X,effective_Y,effective_w,effective_h); } } void Transform_point(short x, short y, float cos_a, float sin_a, short * rx, short * ry) { *rx=Round(((float)x*cos_a)+((float)y*sin_a)); *ry=Round(((float)y*cos_a)-((float)x*sin_a)); } //--------------------- Initialisation d'un mode vido ----------------------- int Init_mode_video(int width, int height, int fullscreen, int pix_ratio) { int index; int factor; int pix_width; int pix_height; byte screen_changed; byte pixels_changed; int absolute_mouse_x=Mouse_X*Pixel_width; int absolute_mouse_y=Mouse_Y*Pixel_height; static int Wrong_resize; try_again: switch (pix_ratio) { default: case PIXEL_SIMPLE: pix_width=1; pix_height=1; break; case PIXEL_TALL: pix_width=1; pix_height=2; break; case PIXEL_WIDE: pix_width=2; pix_height=1; break; case PIXEL_DOUBLE: 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 || Screen_height*Pixel_height!=height || Video_mode[Current_resolution].Fullscreen != fullscreen); // Valeurs raisonnables: minimum 320x200 if (!fullscreen) { if (Wrong_resize>20 && (width < 320*pix_width || height < 200*pix_height)) { if(pix_ratio != PIXEL_SIMPLE) { pix_ratio = PIXEL_SIMPLE; Verbose_message("Error!", "Your WM is forcing GrafX2 to resize to something " "smaller than the minimal resolution.\n" "GrafX2 switched to a smaller\npixel scaler to avoid problems "); goto try_again; } } if (width > 320*pix_width && height > 200*pix_height) Wrong_resize = 0; if (width < 320*pix_width) { width = 320*pix_width; screen_changed=1; Wrong_resize++; } if (height < 200*pix_height) { height = 200*pix_height; screen_changed=1; Wrong_resize++; } Video_mode[0].Width = width; Video_mode[0].Height = height; } else { if (width < 320*pix_width || height < 200*pix_height) return 1; } // La largeur doit tre un multiple de 4 #ifdef __amigaos4__ // On AmigaOS the systems adds some more constraints on that ... width = (width + 15) & 0xFFFFFFF0; #else //width = (width + 3 ) & 0xFFFFFFFC; #endif pixels_changed = (Pixel_ratio!=pix_ratio); if (!screen_changed && !pixels_changed) return 0; if (screen_changed) { Set_mode_SDL(&width, &height,fullscreen); } if (screen_changed || pixels_changed) { Pixel_ratio=pix_ratio; Pixel_width=pix_width; Pixel_height=pix_height; switch (Pixel_ratio) { default: case PIXEL_SIMPLE: Pixel = Pixel_simple ; Read_pixel= Read_pixel_simple ; Display_screen = Display_part_of_screen_simple ; Block = Block_simple ; Pixel_preview_normal = Pixel_preview_normal_simple ; Pixel_preview_magnifier = Pixel_preview_magnifier_simple ; Horizontal_XOR_line = Horizontal_XOR_line_simple ; Vertical_XOR_line = Vertical_XOR_line_simple ; Display_brush_color = Display_brush_color_simple ; Display_brush_mono = Display_brush_mono_simple ; Clear_brush = Clear_brush_simple ; Remap_screen = Remap_screen_simple ; Display_line = Display_line_on_screen_simple ; Display_line_fast = Display_line_on_screen_simple ; Read_line = Read_line_screen_simple ; Display_zoomed_screen = Display_part_of_screen_scaled_simple ; Display_brush_color_zoom = Display_brush_color_zoom_simple ; Display_brush_mono_zoom = Display_brush_mono_zoom_simple ; Clear_brush_scaled = Clear_brush_scaled_simple ; Display_brush = Display_brush_simple ; break; case PIXEL_TALL: Pixel = Pixel_tall; Read_pixel= Read_pixel_tall; Display_screen = Display_part_of_screen_tall; Block = Block_tall; Pixel_preview_normal = Pixel_preview_normal_tall; Pixel_preview_magnifier = Pixel_preview_magnifier_tall; Horizontal_XOR_line = Horizontal_XOR_line_tall; Vertical_XOR_line = Vertical_XOR_line_tall; Display_brush_color = Display_brush_color_tall; Display_brush_mono = Display_brush_mono_tall; Clear_brush = Clear_brush_tall; Remap_screen = Remap_screen_tall; Display_line = Display_line_on_screen_tall; Display_line_fast = Display_line_on_screen_tall; Read_line = Read_line_screen_tall; Display_zoomed_screen = Display_part_of_screen_scaled_tall; Display_brush_color_zoom = Display_brush_color_zoom_tall; Display_brush_mono_zoom = Display_brush_mono_zoom_tall; Clear_brush_scaled = Clear_brush_scaled_tall; Display_brush = Display_brush_tall; break; case PIXEL_WIDE: Pixel = Pixel_wide ; Read_pixel= Read_pixel_wide ; Display_screen = Display_part_of_screen_wide ; Block = Block_wide ; Pixel_preview_normal = Pixel_preview_normal_wide ; Pixel_preview_magnifier = Pixel_preview_magnifier_wide ; Horizontal_XOR_line = Horizontal_XOR_line_wide ; Vertical_XOR_line = Vertical_XOR_line_wide ; Display_brush_color = Display_brush_color_wide ; Display_brush_mono = Display_brush_mono_wide ; Clear_brush = Clear_brush_wide ; Remap_screen = Remap_screen_wide ; Display_line = Display_line_on_screen_wide ; Display_line_fast = Display_line_on_screen_fast_wide ; Read_line = Read_line_screen_wide ; Display_zoomed_screen = Display_part_of_screen_scaled_wide ; Display_brush_color_zoom = Display_brush_color_zoom_wide ; Display_brush_mono_zoom = Display_brush_mono_zoom_wide ; Clear_brush_scaled = Clear_brush_scaled_wide ; Display_brush = Display_brush_wide ; break; case PIXEL_DOUBLE: Pixel = Pixel_double ; Read_pixel= Read_pixel_double ; Display_screen = Display_part_of_screen_double ; Block = Block_double ; Pixel_preview_normal = Pixel_preview_normal_double ; Pixel_preview_magnifier = Pixel_preview_magnifier_double ; Horizontal_XOR_line = Horizontal_XOR_line_double ; Vertical_XOR_line = Vertical_XOR_line_double ; Display_brush_color = Display_brush_color_double ; Display_brush_mono = Display_brush_mono_double ; Clear_brush = Clear_brush_double ; Remap_screen = Remap_screen_double ; Display_line = Display_line_on_screen_double ; Display_line_fast = Display_line_on_screen_fast_double ; Read_line = Read_line_screen_double ; Display_zoomed_screen = Display_part_of_screen_scaled_double ; Display_brush_color_zoom = Display_brush_color_zoom_double ; Display_brush_mono_zoom = Display_brush_mono_zoom_double ; 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; Screen_height = height/Pixel_height; Clear_border(MC_Black); // Requires up-to-date Screen_* and Pixel_* // Set menu size (software zoom) if (Screen_width/320 > Screen_height/200) factor=Screen_height/200; else factor=Screen_width/320; switch (Config.Ratio) { case 1: // Always the biggest possible Menu_factor_X=factor; Menu_factor_Y=factor; break; case 2: // Only keep the aspect ratio Menu_factor_X=factor-1; if (Menu_factor_X<1) Menu_factor_X=1; Menu_factor_Y=factor-1; if (Menu_factor_Y<1) Menu_factor_Y=1; break; case 0: // Always smallest possible Menu_factor_X=1; Menu_factor_Y=1; break; default: // Stay below some reasonable size if (factor>Max(Pixel_width,Pixel_height)) factor/=Max(Pixel_width,Pixel_height); Menu_factor_X=Min(factor,abs(Config.Ratio)); Menu_factor_Y=Min(factor,abs(Config.Ratio)); } if (Pixel_height>Pixel_width && Screen_width>=Menu_factor_X*2*320) Menu_factor_X*=2; else if (Pixel_width>Pixel_height && Screen_height>=Menu_factor_Y*2*200) Menu_factor_Y*=2; free(Horizontal_line_buffer); Horizontal_line_buffer=(byte *)malloc(Pixel_width * ((Screen_width>Main_image_width)?Screen_width:Main_image_width)); Set_palette(Main_palette); Current_resolution=0; if (fullscreen) { for (index=1; index=Screen_width) Mouse_X=Screen_width-1; Mouse_Y=absolute_mouse_y/Pixel_height; if (Mouse_Y>=Screen_height) Mouse_Y=Screen_height-1; if (fullscreen) Set_mouse_position(); Spare_offset_X=0; // | Il faut penser viter les incohrences Spare_offset_Y=0; // |- de dcalage du brouillon par rapport Spare_magnifier_mode=0; // | la rsolution. if (Main_magnifier_mode) { Pixel_preview=Pixel_preview_magnifier; } else { Pixel_preview=Pixel_preview_normal; // Recaler la vue (meme clipping que dans Scroll_screen()) if (Main_offset_X+Screen_width>Main_image_width) Main_offset_X=Main_image_width-Screen_width; if (Main_offset_X<0) Main_offset_X=0; if (Main_offset_Y+Menu_Y>Main_image_height) Main_offset_Y=Main_image_height-Menu_Y; if (Main_offset_Y<0) Main_offset_Y=0; } Compute_magnifier_data(); if (Main_magnifier_mode) Position_screen_according_to_zoom(); Compute_limits(); Compute_paintbrush_coordinates(); Resize_width=0; Resize_height=0; return 0; } // -- Redimentionner l'image (nettoie l'cran virtuel) -- void Resize_image(word chosen_width,word chosen_height) { word old_width=Main_image_width; word old_height=Main_image_height; int i; // +-+-+ // |C| | A+B+C = Ancienne image // +-+A| // |B| | C = Nouvelle image // +-+-+ Upload_infos_page_main(Main_backups->Pages); if (Backup_with_new_dimensions(chosen_width,chosen_height)) { // La nouvelle page a pu tre alloue, 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. for (i=0; iPages->Nb_layers; i++) { Copy_part_of_image_to_another( Main_backups->Pages->Next->Image[i],0,0,Min(old_width,Main_image_width), Min(old_height,Main_image_height),old_width, Main_backups->Pages->Image[i],0,0,Main_image_width); } Redraw_layered_image(); } else { // Afficher un message d'erreur Display_cursor(); Message_out_of_memory(); Hide_cursor(); } } void Remap_spare(void) { short x_pos; // Variable de balayage de la brosse short y_pos; // Variable de balayage de la brosse byte used[256]; // Tableau de boolens "La couleur est utilise" int color; byte layer; // On commence par initialiser le tableau de boolens faux for (color=0;color<=255;color++) used[color]=0; // On calcule la table d'utilisation des couleurs for (layer=0; layerPages->Nb_layers; layer++) for (y_pos=0;y_posPages->Image[layer]+(y_pos*Spare_image_width+x_pos))]=1; // On va maintenant se servir de la table "used" comme table de // conversion: pour chaque indice, la table donne une couleur de // remplacement. // Note : Seules les couleurs utilises on besoin d'tres recalcules: les // autres ne seront jamais consultes dans la nouvelle table de // conversion puisque elles n'existent pas dans l'image, donc elles // ne seront pas utilises par Remap_general_lowlevel. for (color=0;color<=255;color++) if (used[color]) used[color]=Best_color_perceptual(Spare_palette[color].R,Spare_palette[color].G,Spare_palette[color].B); // Maintenant qu'on a une super table de conversion qui n'a que le nom // qui craint un peu, on peut faire l'change dans la brosse de toutes les // teintes. for (layer=0; layerPages->Nb_layers; layer++) Remap_general_lowlevel(used,Spare_backups->Pages->Image[layer],Spare_backups->Pages->Image[layer],Spare_image_width,Spare_image_height,Spare_image_width); // Change transparent color index Spare_backups->Pages->Transparent_color=used[Spare_backups->Pages->Transparent_color]; } void Get_colors_from_brush(void) { short x_pos; // Variable de balayage de la brosse short y_pos; // Variable de balayage de la brosse byte brush_used[256]; // Tableau de boolens "La couleur est utilise" dword usage[256]; int color; int image_color; //if (Confirmation_box("Modify current palette ?")) // Backup with unchanged layers, only palette is modified Backup_layers(0); // Init array of new colors for (color=0;color<=255;color++) brush_used[color]=0; // Tag used colors for (y_pos=0;y_posLimit_left) && (Read_pixel_from_current_layer(start_x-1,line)==2)) || // Test de la prsence d'un point droite du segment ((end_x-1Limit_top)) for (x_pos=start_x;x_pos*right_reached) *right_reached=end_x; // On remplit le segment de start_x end_x-1. for (x_pos=start_x;x_posLimit_top) current_limit_top--; for (line=current_limit_bottom;line>=current_limit_top;line--) { line_is_modified=0; // On va traiter le cas de la ligne n line. // On commence le traitement la gauche de l'cran start_x=Limit_left; // Pour chaque segment de couleur 1 que peut contenir la ligne while (start_x<=Limit_right) { // On cherche son dbut for (;(start_x<=Limit_right) && (Read_pixel_from_current_layer(start_x,line)!=1);start_x++); if (start_x<=Limit_right) { // Un segment de couleur 1 existe et commence la position start_x. // On va donc en chercher la fin. for (end_x=start_x+1;(end_x<=Limit_right) && (Read_pixel_from_current_layer(end_x,line)==1);end_x++); // On sait qu'il existe un segment de couleur 1 qui commence en // start_x et qui se termine en end_x-1. // On va maintenant regarder si une couleur sur la priphrie // permet de colorier ce segment avec la couleur 2. can_propagate=( // Test de la prsence d'un point gauche du segment ((start_x>Limit_left) && (Read_pixel_from_current_layer(start_x-1,line)==2)) || // Test de la prsence d'un point droite du segment ((end_x-1*right_reached) *right_reached=end_x; // On remplit le segment de start_x end_x-1. for (x_pos=start_x;x_posLimit_top) ) current_limit_top--; // On monte cette limite vers le haut } } *top_reached=current_limit_top; *bottom_reached =current_limit_bottom; (*right_reached)--; } // end de la routine de remplissage "Fill" byte Read_pixel_from_backup_layer(word x,word y) { return *((y)*Main_image_width+(x)+Main_backups->Pages->Next->Image[Main_current_layer]); } void Fill_general(byte fill_color) // // Cette fonction fait un remplissage qui gre tous les effets. Elle fait // appel "Fill()". // { byte cursor_shape_before_fill; short x_pos,y_pos; short top_reached ,bottom_reached; short left_reached,right_reached; byte replace_table[256]; // Avant toute chose, on vrifie que l'on n'est pas en train de remplir // en dehors de l'image: if ( (Paintbrush_X>=Limit_left) && (Paintbrush_X<=Limit_right) && (Paintbrush_Y>=Limit_top) && (Paintbrush_Y<=Limit_bottom) ) { // On suppose que le curseur est dj cach. // Hide_cursor(); // On va faire patienter l'utilisateur en lui affichant un joli petit // sablier: cursor_shape_before_fill=Cursor_shape; Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); // On commence par effectuer un backup de l'image. Backup(); // On fait attention au Feedback qui DOIT se faire avec le backup. Update_FX_feedback(0); // On va maintenant "purer" la zone visible de l'image: memset(replace_table,0,256); replace_table[Read_pixel_from_backup_layer(Paintbrush_X,Paintbrush_Y)]=1; Replace_colors_within_limits(replace_table); // On fait maintenant un remplissage classique de la couleur 1 avec la 2 Fill(&top_reached ,&bottom_reached, &left_reached,&right_reached); // On s'apprte faire des oprations qui ncessitent un affichage. Il // faut donc retirer de l'cran le curseur: Hide_cursor(); Cursor_shape=cursor_shape_before_fill; // Il va maintenant falloir qu'on "turn" ce gros caca "into" un truc qui // ressemble un peu plus ce quoi l'utilisateur peut s'attendre. if (top_reached>Limit_top) Copy_part_of_image_to_another(Main_backups->Pages->Next->Image[Main_current_layer], // source Limit_left,Limit_top, // Pos X et Y dans source (Limit_right-Limit_left)+1, // width copie top_reached-Limit_top,// height copie Main_image_width, // width de la source Main_backups->Pages->Image[Main_current_layer], // Destination Limit_left,Limit_top, // Pos X et Y destination Main_image_width); // width destination if (bottom_reachedPages->Next->Image[Main_current_layer], Limit_left,bottom_reached+1, (Limit_right-Limit_left)+1, Limit_bottom-bottom_reached, Main_image_width,Main_backups->Pages->Image[Main_current_layer], Limit_left,bottom_reached+1,Main_image_width); if (left_reached>Limit_left) Copy_part_of_image_to_another(Main_backups->Pages->Next->Image[Main_current_layer], Limit_left,top_reached, left_reached-Limit_left, (bottom_reached-top_reached)+1, Main_image_width,Main_backups->Pages->Image[Main_current_layer], Limit_left,top_reached,Main_image_width); if (right_reachedPages->Next->Image[Main_current_layer], right_reached+1,top_reached, Limit_right-right_reached, (bottom_reached-top_reached)+1, Main_image_width,Main_backups->Pages->Image[Main_current_layer], right_reached+1,top_reached,Main_image_width); for (y_pos=top_reached;y_pos<=bottom_reached;y_pos++) for (x_pos=left_reached;x_pos<=right_reached;x_pos++) if (Read_pixel_from_current_layer(x_pos,y_pos)==2) { // Si le pixel en cours de traitement a t touch par le Fill() // on se doit d'afficher le pixel modifi par la couleur de // remplissage: // Ceci se fait en commenant par restaurer la couleur qu'il y avait // prcdemment (c'est important pour que les effets ne s'emmlent // pas le pinceaux) Pixel_in_current_screen(x_pos,y_pos,Read_pixel_from_backup_layer(x_pos,y_pos),0); // Enfin, on peut afficher le pixel, en le soumettant aux effets en // cours: Display_pixel(x_pos,y_pos,fill_color); } else Pixel_in_current_screen(x_pos,y_pos,Read_pixel_from_backup_layer(x_pos,y_pos),0); // Restore original feedback value Update_FX_feedback(Config.FX_Feedback); // A la fin, on n'a pas besoin de rafficher le curseur puisque c'est // l'appelant qui s'en charge, et on n'a pas besoin de rafficher l'image // puisque les seuls points qui ont chang dans l'image ont t raffichs // par l'utilisation de "Display_pixel()", et que les autres... eh bein // on n'y a jamais touch l'cran les autres: ils sont donc corrects. if(Main_magnifier_mode) { short w,h; w=Min(Screen_width-Main_X_zoom, (Main_image_width-Main_magnifier_offset_X)*Main_magnifier_factor); h=Min(Menu_Y, (Main_image_height-Main_magnifier_offset_Y)*Main_magnifier_factor); Redraw_grid(Main_X_zoom,0,w,h); } Update_rect(0,0,0,0); End_of_modification(); } } ////////////////////////////////////////////////////////////////////////////// ////////////////// TRACS DE FIGURES GOMTRIQUES STANDARDS ////////////////// ////////////////////////// avec gestion de previews ////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Data used by ::Init_permanent_draw() and ::Pixel_figure_permanent() static Uint32 Permanent_draw_next_refresh=0; static int Permanent_draw_count=0; void Init_permanent_draw(void) { Permanent_draw_count = 0; Permanent_draw_next_refresh = SDL_GetTicks() + 100; } // Affichage d'un point de faon dfinitive (utilisation du pinceau) void Pixel_figure_permanent(word x_pos,word y_pos,byte color) { Display_paintbrush(x_pos,y_pos,color,0); Permanent_draw_count ++; // Check every 8 pixels if (! (Permanent_draw_count&7)) { Uint32 now = SDL_GetTicks(); SDL_PumpEvents(); if (now>= Permanent_draw_next_refresh) { Permanent_draw_next_refresh = now+100; Flush_update(); } } } // Affichage d'un point de faon dfinitive void Pixel_clipped(word x_pos,word y_pos,byte color) { if ( (x_pos>=Limit_left) && (x_pos<=Limit_right) && (y_pos>=Limit_top) && (y_pos<=Limit_bottom) ) Display_pixel(x_pos,y_pos,color); } // Affichage d'un point pour une preview void Pixel_figure_preview(word x_pos,word y_pos,byte color) { if ( (x_pos>=Limit_left) && (x_pos<=Limit_right) && (y_pos>=Limit_top) && (y_pos<=Limit_bottom) ) Pixel_preview(x_pos,y_pos,color); } // Affichage d'un point pour une preview, avec sa propre couleur void Pixel_figure_preview_auto(word x_pos,word y_pos) { if ( (x_pos>=Limit_left) && (x_pos<=Limit_right) && (y_pos>=Limit_top) && (y_pos<=Limit_bottom) ) Pixel_preview(x_pos,y_pos,Read_pixel_from_current_screen(x_pos,y_pos)); } // Affichage d'un point pour une preview en xor void Pixel_figure_preview_xor(word x_pos,word y_pos,__attribute__((unused)) byte color) { if ( (x_pos>=Limit_left) && (x_pos<=Limit_right) && (y_pos>=Limit_top) && (y_pos<=Limit_bottom) ) Pixel_preview(x_pos,y_pos,~Read_pixel(x_pos-Main_offset_X, y_pos-Main_offset_Y)); } // Affichage d'un point pour une preview en xor additif // (Il lit la couleur depuis la page backup) void Pixel_figure_preview_xorback(word x_pos,word y_pos,__attribute__((unused)) byte color) { if ( (x_pos>=Limit_left) && (x_pos<=Limit_right) && (y_pos>=Limit_top) && (y_pos<=Limit_bottom) ) Pixel_preview(x_pos,y_pos,~Screen_backup[x_pos+y_pos*Main_image_width]); } // Effacement d'un point de preview void Pixel_figure_clear_preview(word x_pos,word y_pos,__attribute__((unused)) byte color) { if ( (x_pos>=Limit_left) && (x_pos<=Limit_right) && (y_pos>=Limit_top) && (y_pos<=Limit_bottom) ) Pixel_preview(x_pos,y_pos,Read_pixel_from_current_screen(x_pos,y_pos)); } // Affichage d'un point dans la brosse void Pixel_figure_in_brush(word x_pos,word y_pos,byte color) { x_pos-=Brush_offset_X; y_pos-=Brush_offset_Y; if ( (x_posLimit_bottom) end_y=Limit_bottom; if (start_xLimit_right) end_x=Limit_right; // Affichage du cercle for (y_pos=start_y,Circle_cursor_Y=(long)start_y-center_y;y_pos<=end_y;y_pos++,Circle_cursor_Y++) for (x_pos=start_x,Circle_cursor_X=(long)start_x-center_x;x_pos<=end_x;x_pos++,Circle_cursor_X++) if (Pixel_in_circle()) Display_pixel(x_pos,y_pos,color); Update_part_of_screen(start_x,start_y,end_x+1-start_x,end_y+1-start_y); } // -- Tracer gnral d'une ellipse vide ----------------------------------- void Draw_empty_ellipse_general(short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color) { short start_x; short start_y; short x_pos; short y_pos; start_x=center_x-horizontal_radius; start_y=center_y-vertical_radius; // Calcul des limites de l'ellipse Ellipse_compute_limites(horizontal_radius+1,vertical_radius+1); // Affichage des extremites de l'ellipse sur chaque quart de l'ellipse: for (y_pos=start_y,Ellipse_cursor_Y=-vertical_radius;y_posLimit_bottom) end_y=Limit_bottom; if (start_xLimit_right) end_x=Limit_right; // Affichage de l'ellipse for (y_pos=start_y,Ellipse_cursor_Y=start_y-center_y;y_pos<=end_y;y_pos++,Ellipse_cursor_Y++) for (x_pos=start_x,Ellipse_cursor_X=start_x-center_x;x_pos<=end_x;x_pos++,Ellipse_cursor_X++) if (Pixel_in_ellipse()) Display_pixel(x_pos,y_pos,color); Update_part_of_screen(center_x-horizontal_radius,center_y-vertical_radius,2*horizontal_radius+1,2*vertical_radius+1); } /****************** * TRAC DE LIGNES * ******************/ /// Alters bx and by so the (AX,AY)-(BX,BY) segment becomes either horizontal, /// vertical, 45degrees, or isometrical for pixelart (ie 2:1 ratio) void Clamp_coordinates_regular_angle(short ax, short ay, short* bx, short* by) { int dx, dy; float angle; dx = *bx-ax; dy = *by-ay; // No mouse move: no need to clamp anything if (dx==0 || dy == 0) return; // Determine angle (heading) angle = atan2(dx, dy); // Get absolute values, useful from now on: //dx=abs(dx); //dy=abs(dy); // Negative Y if (angle < M_PI*(-15.0/16.0) || angle > M_PI*(15.0/16.0)) { *bx=ax; *by=ay + dy; } // Iso close to negative Y else if (angle < M_PI*(-13.0/16.0)) { dy=dy | 1; // Round up to next odd number *bx=ax + dy/2; *by=ay + dy; } // 45deg else if (angle < M_PI*(-11.0/16.0)) { *by = (*by + ay + dx)/2; *bx = ax - ay + *by; } // Iso close to negative X else if (angle < M_PI*(-9.0/16.0)) { dx=dx | 1; // Round up to next odd number *bx=ax + dx; *by=ay + dx/2; } // Negative X else if (angle < M_PI*(-7.0/16.0)) { *bx=ax + dx; *by=ay; } // Iso close to negative X else if (angle < M_PI*(-5.0/16.0)) { dx=dx | 1; // Round up to next odd number *bx=ax + dx; *by=ay - dx/2; } // 45 degrees else if (angle < M_PI*(-3.0/16.0)) { *by = (*by + ay - dx)/2; *bx = ax + ay - *by; } // Iso close to positive Y else if (angle < M_PI*(-1.0/16.0)) { dy=dy | 1; // Round up to next odd number *bx=ax - dy/2; *by=ay + dy; } // Positive Y else if (angle < M_PI*(1.0/16.0)) { *bx=ax; *by=ay + dy; } // Iso close to positive Y else if (angle < M_PI*(3.0/16.0)) { dy=dy | 1; // Round up to next odd number *bx=ax + dy/2; *by=ay + dy; } // 45 degrees else if (angle < M_PI*(5.0/16.0)) { *by = (*by + ay + dx)/2; *bx = ax - ay + *by; } // Iso close to positive X else if (angle < M_PI*(7.0/16.0)) { dx=dx | 1; // Round up to next odd number *bx=ax + dx; *by=ay + dx/2; } // Positive X else if (angle < M_PI*(9.0/16.0)) { *bx=ax + dx; *by=ay; } // Iso close to positive X else if (angle < M_PI*(11.0/16.0)) { dx=dx | 1; // Round up to next odd number *bx=ax + dx; *by=ay - dx/2; } // 45 degrees else if (angle < M_PI*(13.0/16.0)) { *by = (*by + ay - dx)/2; *bx = ax + ay - *by; } // Iso close to negative Y else //if (angle < M_PI*(15.0/16.0)) { dy=dy | 1; // Round up to next odd number *bx=ax - dy/2; *by=ay + dy; } return; } // -- Tracer gnral d'une ligne ------------------------------------------ void Draw_line_general(short start_x,short start_y,short end_x,short end_y, byte color) { short x_pos,y_pos; short incr_x,incr_y; short i,cumul; short delta_x,delta_y; x_pos=start_x; y_pos=start_y; if (start_xdelta_x) { cumul=delta_y>>1; for (i=1; i=delta_y) { cumul-=delta_y; x_pos+=incr_x; } Pixel_figure(x_pos,y_pos,color); } } else { cumul=delta_x>>1; for (i=1; i=delta_x) { cumul-=delta_x; y_pos+=incr_y; } Pixel_figure(x_pos,y_pos,color); } } if ( (start_x!=end_x) || (start_y!=end_y) ) Pixel_figure(end_x,end_y,color); } // -- Tracer dfinitif d'une ligne -- void Draw_line_permanent(short start_x,short start_y,short end_x,short end_y, byte color) { int w = end_x-start_x, h = end_y - start_y; Pixel_figure=Pixel_figure_permanent; Init_permanent_draw(); Draw_line_general(start_x,start_y,end_x,end_y,color); Update_part_of_screen((start_xend_x) { temp=start_x; start_x=end_x; end_x=temp; } if (start_y>end_y) { temp=start_y; start_y=end_y; end_y=temp; } // On trace le rectangle: Init_permanent_draw(); for (x_pos=start_x;x_pos<=end_x;x_pos++) { Pixel_figure_permanent(x_pos,start_y,color); Pixel_figure_permanent(x_pos, end_y,color); } for (y_pos=start_y+1;y_posend_x) { temp=start_x; start_x=end_x; end_x=temp; } if (start_y>end_y) { temp=start_y; start_y=end_y; end_y=temp; } // Correction en cas de dpassement des limites de l'image if (end_x>Limit_right) end_x=Limit_right; if (end_y>Limit_bottom) end_y=Limit_bottom; // On trace le rectangle: for (y_pos=start_y;y_pos<=end_y;y_pos++) for (x_pos=start_x;x_pos<=end_x;x_pos++) // Display_pixel traite chaque pixel avec tous les effets ! (smear, ...) // Donc on ne peut pas otimiser en traant ligne par ligne avec memset :( Display_pixel(x_pos,y_pos,color); Update_part_of_screen(start_x,start_y,end_x-start_x,end_y-start_y); } // -- Tracer une courbe de Bzier -- void Draw_curve_general(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, byte color) { float delta,t,t2,t3; short x,y,old_x,old_y; word i; int cx[4]; int cy[4]; // Calcul des vecteurs de coefficients cx[0]= - x1 + 3*x2 - 3*x3 + x4; cx[1]= + 3*x1 - 6*x2 + 3*x3; cx[2]= - 3*x1 + 3*x2; cx[3]= + x1; cy[0]= - y1 + 3*y2 - 3*y3 + y4; cy[1]= + 3*y1 - 6*y2 + 3*y3; cy[2]= - 3*y1 + 3*y2; cy[3]= + y1; // Traage de la courbe old_x=x1; old_y=y1; Pixel_figure(old_x,old_y,color); delta=0.05; // 1.0/20 t=0; for (i=1; i<=20; i++) { t=t+delta; t2=t*t; t3=t2*t; x=Round(t3*cx[0] + t2*cx[1] + t*cx[2] + cx[3]); y=Round(t3*cy[0] + t2*cy[1] + t*cy[2] + cy[3]); Draw_line_general(old_x,old_y,x,y,color); old_x=x; old_y=y; } x = Min(Min(x1,x2),Min(x3,x4)); y = Min(Min(y1,y2),Min(y3,y4)); old_x = Max(Max(x1,x2),Max(x3,x4)) - x; old_y = Max(Max(y1,y2),Max(y3,y4)) - y; Update_part_of_screen(x,y,old_x+1,old_y+1); } // -- Tracer une courbe de Bzier dfinitivement -- void Draw_curve_permanent(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, byte color) { Pixel_figure=Pixel_figure_permanent; Init_permanent_draw(); Draw_curve_general(x1,y1,x2,y2,x3,y3,x4,y4,color); } // -- Tracer la preview d'une courbe de Bzier -- void Draw_curve_preview(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, byte color) { Pixel_figure=Pixel_figure_preview; Draw_curve_general(x1,y1,x2,y2,x3,y3,x4,y4,color); } // -- Effacer la preview d'une courbe de Bzier -- void Hide_curve_preview(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, byte color) { Pixel_figure=Pixel_figure_clear_preview; Draw_curve_general(x1,y1,x2,y2,x3,y3,x4,y4,color); } // -- Spray : un petit coup de Pschiitt! -- void Airbrush(short clicked_button) { short x_pos,y_pos; short radius=Airbrush_size>>1; long radius_squared=(long)radius*radius; short index,count; byte color_index; byte direction; Hide_cursor(); if (Airbrush_mode) { for (count=1; count<=Airbrush_mono_flow; count++) { x_pos=(rand()%Airbrush_size)-radius; y_pos=(rand()%Airbrush_size)-radius; if ( (x_pos*x_pos)+(y_pos*y_pos) <= radius_squared ) { x_pos+=Paintbrush_X; y_pos+=Paintbrush_Y; if (clicked_button==1) Display_paintbrush(x_pos,y_pos,Fore_color,0); else Display_paintbrush(x_pos,y_pos,Back_color,0); } } } else { // On essaye de se balader dans la table des flux de faon ce que ce // ne soit pas toujours la dernire couleur qui soit affiche en dernier // Pour a, on part d'une couleur au pif dans une direction alatoire. direction=rand()&1; for (index=0,color_index=rand()/*%256*/; index<256; index++) { for (count=1; count<=Airbrush_multi_flow[color_index]; count++) { x_pos=(rand()%Airbrush_size)-radius; y_pos=(rand()%Airbrush_size)-radius; if ( (x_pos*x_pos)+(y_pos*y_pos) <= radius_squared ) { x_pos+=Paintbrush_X; y_pos+=Paintbrush_Y; if (clicked_button==LEFT_SIDE) Display_paintbrush(x_pos,y_pos,color_index,0); else Display_paintbrush(x_pos,y_pos,Back_color,0); } } if (direction) color_index++; else color_index--; } } Display_cursor(); } ////////////////////////////////////////////////////////////////////////// ////////////////////////// GESTION DES DEGRADES ////////////////////////// ////////////////////////////////////////////////////////////////////////// // -- Gestion d'un dgrad de base (le plus moche) -- void Gradient_basic(long index,short x_pos,short y_pos) { long position; // On fait un premier calcul partiel position=(index*Gradient_bounds_range); // On gre un dplacement au hasard position+=(Gradient_total_range*(rand()%Gradient_random_factor)) >>6; position-=(Gradient_total_range*Gradient_random_factor) >>7; position/=Gradient_total_range; // On va vrifier que nos petites idioties n'ont pas ject la valeur hors // des valeurs autorises par le dgrad dfini par l'utilisateur. if (position<0) position=0; else if (position>=Gradient_bounds_range) position=Gradient_bounds_range-1; // On ramne ensuite la position dans le dgrad vers un numro de couleur if (Gradient_is_inverted) Gradient_pixel(x_pos,y_pos,Gradient_upper_bound-position); else Gradient_pixel(x_pos,y_pos,Gradient_lower_bound+position); } // -- Gestion d'un dgrad par trames simples -- void Gradient_dithered(long index,short x_pos,short y_pos) { long position_in_gradient; long position_in_segment; // // But de l'opration: en plus de calculer la position de base (dsigne // dans cette procdure par "position_in_gradient", on calcule la position // de l'indice dans le schma suivant: // // | Les indices qui tranent de ce ct du segment se voient subir // | une incrmentation conditionnelle leur position dans l'cran. // v // |---|---|---|---- - - - // ^ // |_ Les indices qui tranent de ce ct du segment se voient subir une // dcrmentation conditionnelle leur position dans l'cran. // On fait d'abord un premier calcul partiel position_in_gradient=(index*Gradient_bounds_range); // On gre un dplacement au hasard... position_in_gradient+=(Gradient_total_range*(rand()%Gradient_random_factor)) >>6; position_in_gradient-=(Gradient_total_range*Gradient_random_factor) >>7; if (position_in_gradient<0) position_in_gradient=0; // ... qui nous permet de calculer la position dans le segment position_in_segment=((position_in_gradient<<2)/Gradient_total_range)&3; // On peut ensuite terminer le calcul de l'indice dans le dgrad position_in_gradient/=Gradient_total_range; // On va pouvoir discuter de la valeur de position_in_gradient en fonction // de la position dans l'cran et de la position_in_segment. switch (position_in_segment) { case 0 : // On est sur la gauche du segment if (((x_pos+y_pos)&1)==0) position_in_gradient--; break; // On n'a pas traiter les cas 1 et 2 car ils reprsentent des valeurs // suffisament au centre du segment pour ne pas avoir subir la trame case 3 : // On est sur la droite du segment if (((x_pos+y_pos)&1)!=0) // Note: on doit faire le test inverse au cas gauche pour synchroniser les 2 cts de la trame. position_in_gradient++; } // On va vrifier que nos petites idioties n'ont pas ject la valeur hors // des valeurs autorises par le dgrad dfini par l'utilisateur. if (position_in_gradient<0) position_in_gradient=0; else if (position_in_gradient>=Gradient_bounds_range) position_in_gradient=Gradient_bounds_range-1; // On ramne ensuite la position dans le dgrad vers un numro de couleur if (Gradient_is_inverted) position_in_gradient=Gradient_upper_bound-position_in_gradient; else position_in_gradient=Gradient_lower_bound+position_in_gradient; Gradient_pixel(x_pos,y_pos,position_in_gradient); } // -- Gestion d'un dgrad par trames tendues -- void Gradient_extra_dithered(long index,short x_pos,short y_pos) { long position_in_gradient; long position_in_segment; // // But de l'opration: en plus de calculer la position de base (dsigne // dans cette procdure par "position_in_gradient", on calcule la position // de l'indice dans le schma suivant: // // | Les indices qui tranent de ce ct du segment se voient subir // | une incrmentation conditionnelle leur position dans l'cran. // v // |---|---|---|---- - - - // ^ // |_ Les indices qui tranent de ce ct du segment se voient subir une // dcrmentation conditionnelle leur position dans l'cran. // On fait d'abord un premier calcul partiel position_in_gradient=(index*Gradient_bounds_range); // On gre un dplacement au hasard position_in_gradient+=(Gradient_total_range*(rand()%Gradient_random_factor)) >>6; position_in_gradient-=(Gradient_total_range*Gradient_random_factor) >>7; if (position_in_gradient<0) position_in_gradient=0; // Qui nous permet de calculer la position dans le segment position_in_segment=((position_in_gradient<<3)/Gradient_total_range)&7; // On peut ensuite terminer le calcul de l'indice dans le dgrad position_in_gradient/=Gradient_total_range; // On va pouvoir discuter de la valeur de position_in_gradient en fonction // de la position dans l'cran et de la position_in_segment. switch (position_in_segment) { case 0 : // On est sur l'extrme gauche du segment if (((x_pos+y_pos)&1)==0) position_in_gradient--; break; case 1 : // On est sur la gauche du segment case 2 : // On est sur la gauche du segment if (((x_pos & 1)==0) && ((y_pos & 1)==0)) position_in_gradient--; break; // On n'a pas traiter les cas 3 et 4 car ils reprsentent des valeurs // suffisament au centre du segment pour ne pas avoir subir la trame case 5 : // On est sur la droite du segment case 6 : // On est sur la droite du segment if (((x_pos & 1)==0) && ((y_pos & 1)!=0)) position_in_gradient++; break; case 7 : // On est sur l'extreme droite du segment if (((x_pos+y_pos)&1)!=0) // Note: on doit faire le test inverse au cas gauche pour synchroniser les 2 cts de la trame. position_in_gradient++; } // On va vrifier que nos petites idioties n'ont pas ject la valeur hors // des valeurs autorises par le dgrad dfini par l'utilisateur. if (position_in_gradient<0) position_in_gradient=0; else if (position_in_gradient>=Gradient_bounds_range) position_in_gradient=Gradient_bounds_range-1; // On ramne ensuite la position dans le dgrad vers un numro de couleur if (Gradient_is_inverted) position_in_gradient=Gradient_upper_bound-position_in_gradient; else position_in_gradient=Gradient_lower_bound+position_in_gradient; Gradient_pixel(x_pos,y_pos,position_in_gradient); } // -- Tracer un cercle degrad (une sphre) -- void Draw_grad_circle(short center_x,short center_y,short radius,short spot_x,short spot_y) { long start_x; long start_y; long x_pos; long y_pos; long end_x; long end_y; long distance_x; // Distance (au carr) sur les X du point en cours au centre d'clairage long distance_y; // Distance (au carr) sur les Y du point en cours au centre d'clairage start_x=center_x-radius; start_y=center_y-radius; end_x=center_x+radius; end_y=center_y+radius; // Correction des bornes d'aprs les limites if (start_yLimit_bottom) end_y=Limit_bottom; if (start_xLimit_right) end_x=Limit_right; Gradient_total_range=Circle_limit+ ((center_x-spot_x)*(center_x-spot_x))+ ((center_y-spot_y)*(center_y-spot_y))+ (2L*radius*sqrt( ((center_x-spot_x)*(center_x-spot_x))+ ((center_y-spot_y)*(center_y-spot_y)))); if (Gradient_total_range==0) Gradient_total_range=1; // Affichage du cercle for (y_pos=start_y,Circle_cursor_Y=(long)start_y-center_y;y_pos<=end_y;y_pos++,Circle_cursor_Y++) { distance_y =(y_pos-spot_y); distance_y*=distance_y; for (x_pos=start_x,Circle_cursor_X=(long)start_x-center_x;x_pos<=end_x;x_pos++,Circle_cursor_X++) if (Pixel_in_circle()) { distance_x =(x_pos-spot_x); distance_x*=distance_x; Gradient_function(distance_x+distance_y,x_pos,y_pos); } } Update_part_of_screen(center_x-radius,center_y-radius,2*radius+1,2*radius+1); } // -- Tracer une ellipse degrade -- void Draw_grad_ellipse(short center_x,short center_y,short horizontal_radius,short vertical_radius,short spot_x,short spot_y) { long start_x; long start_y; long x_pos; long y_pos; long end_x; long end_y; long distance_x; // Distance (au carr) sur les X du point en cours au centre d'clairage long distance_y; // Distance (au carr) sur les Y du point en cours au centre d'clairage start_x=center_x-horizontal_radius; start_y=center_y-vertical_radius; end_x=center_x+horizontal_radius; end_y=center_y+vertical_radius; // Calcul des limites de l'ellipse Ellipse_compute_limites(horizontal_radius+1,vertical_radius+1); // On calcule la distance maximale: Gradient_total_range=(horizontal_radius*horizontal_radius)+ (vertical_radius*vertical_radius)+ ((center_x-spot_x)*(center_x-spot_x))+ ((center_y-spot_y)*(center_y-spot_y))+ (2L *sqrt( (horizontal_radius*horizontal_radius)+ (vertical_radius *vertical_radius )) *sqrt( ((center_x-spot_x)*(center_x-spot_x))+ ((center_y-spot_y)*(center_y-spot_y)))); if (Gradient_total_range==0) Gradient_total_range=1; // Correction des bornes d'aprs les limites if (start_yLimit_bottom) end_y=Limit_bottom; if (start_xLimit_right) end_x=Limit_right; // Affichage de l'ellipse for (y_pos=start_y,Ellipse_cursor_Y=start_y-center_y;y_pos<=end_y;y_pos++,Ellipse_cursor_Y++) { distance_y =(y_pos-spot_y); distance_y*=distance_y; for (x_pos=start_x,Ellipse_cursor_X=start_x-center_x;x_pos<=end_x;x_pos++,Ellipse_cursor_X++) if (Pixel_in_ellipse()) { distance_x =(x_pos-spot_x); distance_x*=distance_x; Gradient_function(distance_x+distance_y,x_pos,y_pos); } } Update_part_of_screen(start_x,start_y,end_x-start_x+1,end_y-start_y+1); } // Trac d'un rectangle (rax ray - rbx rby) dgrad selon le vecteur (vax vay - vbx - vby) void Draw_grad_rectangle(short rax,short ray,short rbx,short rby,short vax,short vay, short vbx, short vby) { short y_pos, x_pos; // On commence par s'assurer que le rectangle est l'endroit if(rbx < rax) { x_pos = rbx; rbx = rax; rax = x_pos; } if(rby < ray) { y_pos = rby; rby = ray; ray = y_pos; } // Correction des bornes d'aprs les limites if (rayLimit_bottom) rby=Limit_bottom; if (raxLimit_right) rbx=Limit_right; if(vbx == vax) { // Le vecteur est vertical, donc on vite la partie en dessous qui foirerait avec une division par 0... if (vby == vay) return; // L'utilisateur fait n'importe quoi Gradient_total_range = abs(vby - vay); for(y_pos=ray;y_pos<=rby;y_pos++) for(x_pos=rax;x_pos<=rbx;x_pos++) Gradient_function(abs(vby - y_pos),x_pos,y_pos); } else { float a; float b; float distance_x, distance_y; Gradient_total_range = sqrt(pow(vby - vay,2)+pow(vbx - vax,2)); a = (float)(vby - vay)/(float)(vbx - vax); b = vay - a*vax; for (y_pos=ray;y_pos<=rby;y_pos++) for (x_pos = rax;x_pos<=rbx;x_pos++) { // On calcule ou on en est dans le dgrad distance_x = pow((y_pos - vay),2)+pow((x_pos - vax),2); distance_y = pow((-a * x_pos + y_pos - b),2)/(a*a+1); Gradient_function((int)sqrt(distance_x - distance_y),x_pos,y_pos); } } Update_part_of_screen(rax,ray,rbx,rby); } // -- Tracer un polygne plein -- typedef struct T_Polygon_edge /* an active edge */ { short top; /* top y position */ short bottom; /* bottom y position */ float x, dx; /* floating point x position and gradient */ float w; /* width of line segment */ struct T_Polygon_edge *prev; /* doubly linked list */ struct T_Polygon_edge *next; } T_Polygon_edge; /* Fill_edge_structure: * Polygon helper function: initialises an edge structure for the 2d * rasteriser. */ void Fill_edge_structure(T_Polygon_edge *edge, short *i1, short *i2) { short *it; if (i2[1] < i1[1]) { it = i1; i1 = i2; i2 = it; } edge->top = i1[1]; edge->bottom = i2[1] - 1; edge->dx = ((float) i2[0] - (float) i1[0]) / ((float) i2[1] - (float) i1[1]); edge->x = i1[0] + 0.4999999; edge->prev = NULL; edge->next = NULL; if (edge->dx+1 < 0.0) edge->x += edge->dx+1; if (edge->dx >= 0.0) edge->w = edge->dx; else edge->w = -(edge->dx); if (edge->w-1.0<0.0) edge->w = 0.0; else edge->w = edge->w-1; } /* Add_edge: * Adds an edge structure to a linked list, returning the new head pointer. */ T_Polygon_edge * Add_edge(T_Polygon_edge *list, T_Polygon_edge *edge, int sort_by_x) { T_Polygon_edge *pos = list; T_Polygon_edge *prev = NULL; if (sort_by_x) { while ( (pos) && ((pos->x+((pos->w+pos->dx)/2)) < (edge->x+((edge->w+edge->dx)/2))) ) { prev = pos; pos = pos->next; } } else { while ((pos) && (pos->top < edge->top)) { prev = pos; pos = pos->next; } } edge->next = pos; edge->prev = prev; if (pos) pos->prev = edge; if (prev) { prev->next = edge; return list; } else return edge; } /* Remove_edge: * Removes an edge structure from a list, returning the new head pointer. */ T_Polygon_edge * Remove_edge(T_Polygon_edge *list, T_Polygon_edge *edge) { if (edge->next) edge->next->prev = edge->prev; if (edge->prev) { edge->prev->next = edge->next; return list; } else return edge->next; } /* polygon: * Draws a filled polygon with an arbitrary number of corners. Pass the * number of vertices, then an array containing a series of x, y points * (a total of vertices*2 values). */ void Polyfill_general(int vertices, short * points, int color) { short c; short top = 0x7FFF; short bottom = 0; short *i1, *i2; short x_pos,end_x; T_Polygon_edge *edge, *next_edge, *initial_edge; T_Polygon_edge *active_edges = NULL; T_Polygon_edge *inactive_edges = NULL; /* allocate some space and fill the edge table */ initial_edge=edge=(T_Polygon_edge *) malloc(sizeof(T_Polygon_edge) * vertices); i1 = points; i2 = points + ((vertices-1)<<1); for (c=0; cbottom >= edge->top) { if (edge->top < top) top = edge->top; if (edge->bottom > bottom) bottom = edge->bottom; inactive_edges = Add_edge(inactive_edges, edge, 0); edge++; } } i2 = i1; i1 += 2; } /* for each scanline in the polygon... */ for (c=top; c<=bottom; c++) { /* check for newly active edges */ edge = inactive_edges; while ((edge) && (edge->top == c)) { next_edge = edge->next; inactive_edges = Remove_edge(inactive_edges, edge); active_edges = Add_edge(active_edges, edge, 1); edge = next_edge; } /* draw horizontal line segments */ if ((c>=Limit_top) && (c<=Limit_bottom)) { edge = active_edges; while ((edge) && (edge->next)) { x_pos=/*Round*/(edge->x); end_x=/*Round*/(edge->next->x+edge->next->w); if (x_posLimit_right) end_x=Limit_right; for (; x_pos<=end_x; x_pos++) Pixel_figure(x_pos,c,color); edge = edge->next->next; } } /* update edges, sorting and removing dead ones */ edge = active_edges; while (edge) { next_edge = edge->next; if (c >= edge->bottom) active_edges = Remove_edge(active_edges, edge); else { edge->x += edge->dx; while ((edge->prev) && ( (edge->x+(edge->w/2)) < (edge->prev->x+(edge->prev->w/2))) ) { if (edge->next) edge->next->prev = edge->prev; edge->prev->next = edge->next; edge->next = edge->prev; edge->prev = edge->prev->prev; edge->next->prev = edge; if (edge->prev) edge->prev->next = edge; else active_edges = edge; } } edge = next_edge; } } free(initial_edge); initial_edge = NULL; // On ne connait pas simplement les xmin et xmax ici, mais de toutes faon ce n'est pas utilis en preview Update_part_of_screen(0,top,Main_image_width,bottom-top+1); } void Polyfill(int vertices, short * points, int color) { int index; Pixel_clipped(points[0],points[1],color); if (vertices==1) { Update_part_of_screen(points[0],points[1],1,1); return; } // Comme pour le Fill, cette operation fait un peu d'"overdraw" // (pixels dessins plus d'une fois) alors on force le FX Feedback OFF Update_FX_feedback(0); Pixel_figure=Pixel_clipped; Polyfill_general(vertices,points,color); // Remarque: pour dessiner la bordure avec la brosse en cours au lieu // d'un pixel de couleur premier-plan, il suffit de mettre ici: // Pixel_figure=Pixel_figure_permanent; // Dessin du contour for (index=0; index255)) index++; // On note la position de la premire case de la squence first=index; // On recherche la position de la dernire case de la squence for (last=first;list[last+1]<256;last++); // Pour toutes les cases non vides (et non inhibes) qui suivent switch (mode) { case SHADE_MODE_NORMAL : for (;(index<512) && (list[index]<256);index++) { // On met jour les tables de conversion color=list[index]; table_inc[color]=list[(index+step<=last)?index+step:last]; table_dec[color]=list[(index-step>=first)?index-step:first]; } break; case SHADE_MODE_LOOP : temp=1+last-first; for (;(index<512) && (list[index]<256);index++) { // On met jour les tables de conversion color=list[index]; table_inc[color]=list[first+((step+index-first)%temp)]; table_dec[color]=list[first+(((temp-step)+index-first)%temp)]; } break; default : // SHADE_MODE_NOSAT for (;(index<512) && (list[index]<256);index++) { // On met jour les tables de conversion color=list[index]; if (index+step<=last) table_inc[color]=list[index+step]; if (index-step>=first) table_dec[color]=list[index-step]; } } } } // -- Interface avec l'image, affecte par le facteur de grossissement ------- // fonction d'affichage "Pixel" utilise pour les oprations dfinitivement // Ne doit aucune condition tre appele en dehors de la partie visible // de l'image dans l'cran (a pourrait tre grave) void Display_pixel(word x,word y,byte color) // x & y sont la position d'un point dans l'IMAGE // color est la couleur du point // Le Stencil est gr. // Les effets sont grs par appel Effect_function(). // La Loupe est gre par appel Pixel_preview(). { if ( ( (!Sieve_mode) || (Effect_sieve(x,y)) ) && (!((Stencil_mode) && (Stencil[Read_pixel_from_current_layer(x,y)]))) && (!((Mask_mode) && (Mask_table[Read_pixel_from_spare_screen(x,y)]))) ) { color=Effect_function(x,y,color); Pixel_in_current_screen(x,y,color,1); } } // -- Calcul des diffrents effets ------------------------------------------- // -- Aucun effet en cours -- byte No_effect(__attribute__((unused)) word x,__attribute__((unused)) word y,byte color) { return color; } // -- Effet de Shading -- byte Effect_shade(word x,word y,__attribute__((unused)) byte color) { return Shade_table[Read_pixel_from_feedback_screen(x,y)]; } byte Effect_quick_shade(word x,word y,byte color) { int c=color=Read_pixel_from_feedback_screen(x,y); int direction=(Fore_color<=Back_color); byte start,end; int width; if (direction) { start=Fore_color; end =Back_color; } else { start=Back_color; end =Fore_color; } if ((c>=start) && (c<=end) && (start!=end)) { width=1+end-start; if ( ((Shade_table==Shade_table_left) && direction) || ((Shade_table==Shade_table_right) && (!direction)) ) c-=Quick_shade_step%width; else c+=Quick_shade_step%width; if (cend) switch (Quick_shade_loop) { case SHADE_MODE_NORMAL : return end; case SHADE_MODE_LOOP : return (c-width); default : return color; } } return c; } // -- Effet de Tiling -- byte Effect_tiling(word x,word y,__attribute__((unused)) byte color) { return Read_pixel_from_brush((x+Brush_width-Tiling_offset_X)%Brush_width, (y+Brush_height-Tiling_offset_Y)%Brush_height); } // -- Effet de Smooth -- byte Effect_smooth(word x,word y,__attribute__((unused)) byte color) { int r,g,b; byte c; int weight,total_weight; byte x2=((x+1)Pages->Transparent_color) // transparent color return color; depth = *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width); return *(Main_backups->Pages->Image[depth] + x+y*Main_image_width); #else return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer]); #endif } void Pixel_in_current_screen (word x,word y,byte color,int with_preview) { #ifndef NOLAYERS byte depth = *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width); *(Main_backups->Pages->Image[Main_current_layer] + x+y*Main_image_width)=color; if ( depth <= Main_current_layer) { if (color == Main_backups->Pages->Transparent_color) // transparent color // fetch pixel color from the topmost visible layer color=*(Main_backups->Pages->Image[depth] + x+y*Main_image_width); *(x+y*Main_image_width+Main_screen)=color; if (with_preview) Pixel_preview(x,y,color); } #else *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer])=color; if (with_preview) Pixel_preview(x,y,color); #endif } void Pixel_in_current_layer(word x,word y, byte color) { *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer])=color; } byte Read_pixel_from_current_layer(word x,word y) { return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer]); } grafx2/src/help.c0000644000076400010400000006401311546441744014333 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2008 Peter Gordon 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 */ #include #include #if defined(__WIN32__) #include #elif defined(__macosx__) || defined(__FreeBSD__) #include #include #elif defined (__linux__) #include #elif defined(__HAIKU__) #include "haiku.h" #elif defined (__MINT__) #include #include #include #endif #include "const.h" #include "struct.h" #include "global.h" #include "misc.h" #include "engine.h" #include "helpfile.h" #include "help.h" #include "sdlscreen.h" #include "text.h" #include "keyboard.h" #include "windows.h" #include "input.h" #include "hotkeys.h" #include "errors.h" #include "pages.h" extern char Program_version[]; // generated in pversion.c extern char SVN_revision[]; // generated in pversion.c // Recherche un raccourci clavier: word * Shortcut(word shortcut_number) { if (shortcut_number & 0x100) return &(Buttons_Pool[shortcut_number & 0xFF].Left_shortcut[0]); if (shortcut_number & 0x200) return &(Buttons_Pool[shortcut_number & 0xFF].Right_shortcut[0]); return &(Config_Key[shortcut_number & 0xFF][0]); } // Nom de la touche actuallement assignée à un raccourci d'après son numéro // de type 0x100+BOUTON_* ou SPECIAL_* const char * Keyboard_shortcut_value(word shortcut_number) { static char shortcuts_name[80]; word * pointer = Shortcut(shortcut_number); if (pointer == NULL) return "(Problem)"; else { if (pointer[0] == 0 && pointer[1] == 0) return "None"; if (pointer[0] != 0 && pointer[1] == 0) return Key_name(pointer[0]); if (pointer[0] == 0 && pointer[1] != 0) return Key_name(pointer[1]); strcpy(shortcuts_name, Key_name(pointer[0])); strcat(shortcuts_name, " or "); strcat(shortcuts_name, Key_name(pointer[1])); return shortcuts_name; } } void Redefine_control(word *shortcut, int x_pos, int y_pos) { Hide_cursor(); Print_in_window(x_pos,y_pos,"*PRESS KEY OR BUTTON*",MC_Black,MC_Light); Display_cursor(); while (1) { Get_input(20); if (Key==KEY_ESC) return; if (Key!=0) { *shortcut=Key; return; } } } void Window_set_shortcut(int action_id) { short clicked_button; short order_index; short config_index; short redraw_controls=1; word * shortcut_ptr=NULL; word backup_shortcut[2]; shortcut_ptr=Shortcut(action_id); backup_shortcut[0]=shortcut_ptr[0]; backup_shortcut[1]=shortcut_ptr[1]; // Recherche dans hotkeys order_index=0; while (Ordering[order_index]!=action_id) { order_index++; if (order_index>=NB_SHORTCUTS) { Error(0); return; } } /* config_index=0; while (ConfigKey[config_index].Number!=order_index) { config_index++; if (config_index>=NB_SHORTCUTS) { Error(0); return; } } */ config_index=order_index; // Comprends pas... a devrait pas marcher Open_window(302,131,"Keyboard shortcut"); Window_set_normal_button(181,111,55,14,"Cancel",0,1,KEY_ESC); // 1 Window_set_normal_button(241,111,55,14,"OK",0,1,SDLK_RETURN); // 2 Window_set_normal_button(6,111,111,14,"Reset default",0,1,KEY_NONE); // 3 // Titre Block(Window_pos_X+(Menu_factor_X*5), Window_pos_Y+(Menu_factor_Y*16), Menu_factor_X*292,Menu_factor_Y*11,MC_Black); Print_in_window(7,18,ConfigKey[config_index].Label,MC_White,MC_Black); // Zone de description Window_display_frame_in(5,68,292,37); Print_in_window(8,70,ConfigKey[config_index].Explanation1,MC_Black,MC_Light); Print_in_window(8,78,ConfigKey[config_index].Explanation2,MC_Black,MC_Light); Print_in_window(8,86,ConfigKey[config_index].Explanation3,MC_Black,MC_Light); // Shortcut 0 Window_set_normal_button(27,30,177,14,"",0,1,KEY_NONE); // 4 Window_set_normal_button(209,30,56,14,"Remove",0,1,KEY_NONE); // 5 // Shortcut 1 Window_set_normal_button(27,49,177,14,"",0,1,KEY_NONE); // 6 Window_set_normal_button(209,49,56,14,"Remove",0,1,KEY_NONE); // 7 Display_cursor(); do { if (redraw_controls) { Hide_cursor(); Block(Window_pos_X+(Menu_factor_X*32), Window_pos_Y+(Menu_factor_Y*33), Menu_factor_X*21*8,Menu_factor_Y*8,MC_Light); Print_in_window_limited(32,33,Key_name(shortcut_ptr[0]),21,MC_Black,MC_Light); Block(Window_pos_X+(Menu_factor_X*32), Window_pos_Y+(Menu_factor_Y*52), Menu_factor_X*21*8,Menu_factor_Y*8,MC_Light); Print_in_window_limited(32,52,Key_name(shortcut_ptr[1]),21,MC_Black,MC_Light); Update_rect(Window_pos_X,Window_pos_Y,302*Menu_factor_X,131*Menu_factor_Y); Display_cursor(); redraw_controls=0; } clicked_button=Window_clicked_button(); switch (clicked_button) { case -1: case 0: break; case 4: // Change 0 Redefine_control(&shortcut_ptr[0], 32, 33); redraw_controls=1; break; case 6: // Change 1 Redefine_control(&shortcut_ptr[1], 32, 52); redraw_controls=1; break; case 5: // Remove 0 shortcut_ptr[0]=0; redraw_controls=1; break; case 7: // Remove 1 shortcut_ptr[1]=0; redraw_controls=1; break; case 3: // Defaults shortcut_ptr[0]=ConfigKey[config_index].Key; shortcut_ptr[1]=ConfigKey[config_index].Key2; redraw_controls=1; break; case 1: // Cancel shortcut_ptr[0]=backup_shortcut[0]; shortcut_ptr[1]=backup_shortcut[1]; case 2: // OK // Replace twice by single if (shortcut_ptr[0]==shortcut_ptr[1]) shortcut_ptr[1]=0; // Remove all other shortcuts that use same keys if (!Config.Allow_multi_shortcuts) { int n; for (n=0; n<2; n++) { if (shortcut_ptr[n]!=0) { int i; for(i=0; i'_' || line[char_index/2]<' ') char_pixel=&(Gfx->Help_font_norm['!'][0][0]); // Caractre pas gr else if (char_index & 1) char_pixel=&(Gfx->Help_font_t2[(unsigned char)(line[char_index/2])-' '][0][0]); else char_pixel=&(Gfx->Help_font_t1[(unsigned char)(line[char_index/2])-' '][0][0]); } else if (line_type=='-') { if (line[char_index/2]>'_' || line[char_index/2]<' ') char_pixel=&(Gfx->Help_font_norm['!'][0][0]); // Caractre pas gr else if (char_index & 1) char_pixel=&(Gfx->Help_font_t4[(unsigned char)(line[char_index/2])-' '][0][0]); else char_pixel=&(Gfx->Help_font_t3[(unsigned char)(line[char_index/2])-' '][0][0]); } else if (line_type=='S') char_pixel=&(Gfx->Bold_font[(unsigned char)(line[char_index])][0][0]); else if (line_type=='N' || line_type=='K') char_pixel=&(Gfx->Help_font_norm[(unsigned char)(line[char_index])][0][0]); else char_pixel=&(Gfx->Help_font_norm['!'][0][0]); // Un garde-fou en cas de probleme for (x=0;x<6;x++) for (repeat_menu_x_factor=0;repeat_menu_x_factor=link_position && char_index<(link_position+link_size)) { if (color == MC_Light) color=MC_White; else if (color == MC_Dark) color=MC_Light; else if (y<7) color=MC_Dark; } Horizontal_line_buffer[x_position++]=color; while (repetition--) Horizontal_line_buffer[x_position++]=color; } } // On la splotche for (repeat_menu_y_factor=0;repeat_menu_y_factor= Help_section[Current_help_section].Length) { Window_rectangle (x_pos, y_pos + line_index*8, 44*6, // 44 = Nb max de char (+1 pour viter les plantages en mode X // causs par une largeur = 0) (16 - line_index)*8, MC_Black); break; } // On affiche la ligne line = Help_section[Current_help_section].Help_table[start_line + line_index].Text; line_type = Help_section[Current_help_section].Help_table[start_line + line_index].Line_type; // Si c'est une sous-ligne de titre, on utilise le texte de la ligne prcdente if (line_type == '-' && (start_line + line_index > 0)) line = Help_section[Current_help_section].Help_table[start_line + line_index - 1].Text; else if (line_type == 'K') { const char *hyperlink; const char * escaped_percent_pos; // Determine link position: link_position = strstr(line,"%s") - line; // Adjust for any escaped %% that would precede it. escaped_percent_pos = line; do { escaped_percent_pos = strstr(escaped_percent_pos,"%%"); if (escaped_percent_pos && escaped_percent_pos - line < link_position) { link_position--; escaped_percent_pos+=2; } } while (escaped_percent_pos); // hyperlink=Keyboard_shortcut_value(Help_section[Current_help_section].Help_table[start_line + line_index].Line_parameter); link_size=strlen(hyperlink); snprintf(buffer, 44, line, hyperlink); if (strlen(line)+link_size-2>44) { buffer[43]=ELLIPSIS_CHARACTER; buffer[44]='\0'; } line = buffer; } width=Print_help(x_pos, y_pos+(line_index<<3), line, line_type, link_position, link_size); // On efface la fin de la ligne: if (width<44) Window_rectangle (x_pos+width*6, y_pos+(line_index<<3), (44-width)*6, 8, MC_Black); } Update_window_area(x_pos,y_pos,44*6,16*8); } void Scroll_help(T_Scroller_button * scroller) { Hide_cursor(); scroller->Position=Help_position; Compute_slider_cursor_length(scroller); Window_draw_slider(scroller); Display_help(); Display_cursor(); } void Button_Help(void) { short btn_number; // Aide contextuelle if (Key!=0) { btn_number = Button_under_mouse(); if (btn_number != -1) { Window_help(btn_number, NULL); return; } } Window_help(-1, NULL); } // Ouvre l'ecran d'aide. Passer -1 pour la section par dfaut (ou derniere,) // Ou un nombre de l'enumration BUTTON_NUMBERS pour l'aide contextuelle. void Window_help(int section, const char *sub_section) { short clicked_button; short nb_lines; T_Scroller_button * scroller; if (section!=-1) { Current_help_section = 4 + section; Help_position = 0; } nb_lines=Help_section[Current_help_section].Length; if (section!=-1 && sub_section!=NULL) { int index=0; for (index=0; index2) { Current_help_section=clicked_button-3; Help_position=0; nb_lines=Help_section[Current_help_section].Length; scroller->Position=0; scroller->Nb_elements=nb_lines; Compute_slider_cursor_length(scroller); Window_draw_slider(scroller); } else Help_position=Window_attribute2; Display_help(); Display_cursor(); } // Gestion des touches de dplacement dans la liste switch (Key) { case SDLK_UP : // Haut if (Help_position>0) Help_position--; Scroll_help(scroller); Key=0; break; case SDLK_DOWN : // Bas if (Help_position15) Help_position-=15; else Help_position=0; Scroll_help(scroller); Key=0; break; case (KEY_MOUSEWHEELUP) : // WheelUp if (Help_position>3) Help_position-=3; else Help_position=0; Scroll_help(scroller); Key=0; break; case SDLK_PAGEDOWN : // PageDown if (nb_lines>16) { if (Help_position16) { if (Help_position16) { Help_position=nb_lines-16; Scroll_help(scroller); Key=0; } break; } if (Is_shortcut(Key,0x100+BUTTON_HELP)) clicked_button=1; } while ((clicked_button!=1) && (Key!=SDLK_RETURN)); Key=0; Close_window(); Unselect_button(BUTTON_HELP); Display_cursor(); } #define STATS_TITLE_COLOR MC_White #define STATS_DATA_COLOR MC_Light void Button_Stats(void) { short clicked_button; char buffer[37]; dword color_usage[256]; unsigned long long freeRam; qword mem_size = 0; Open_window(310,174,"Statistics"); // Dessin de la fenetre ou va s'afficher le texte Window_display_frame_in(8,17,294,132); Block(Window_pos_X+(Menu_factor_X*9), Window_pos_Y+(Menu_factor_Y*18), Menu_factor_X*292,Menu_factor_Y*130,MC_Black); Window_set_normal_button(120,153,70,14,"OK",0,1,KEY_ESC); // 1 // Affichage du numro de version Print_in_window(10,19,"Program version:",STATS_TITLE_COLOR,MC_Black); sprintf(buffer,"%s.%s",Program_version, SVN_revision); Print_in_window(146,19,buffer,STATS_DATA_COLOR,MC_Black); Print_in_window(10,35,"Build options:",STATS_TITLE_COLOR,MC_Black); Print_in_window(146,35,TrueType_is_supported()?"TTF fonts":"no TTF fonts",STATS_DATA_COLOR,MC_Black); #if defined (__MINT__) // Affichage de la mmoire restante Print_in_window(10,43,"Free memory: ",STATS_TITLE_COLOR,MC_Black); freeRam=0; char helpBuf[64]; unsigned long STRAM,TTRAM; Atari_Memory_free(&STRAM,&TTRAM); freeRam=STRAM+TTRAM; buffer[0]='\0'; if(STRAM > (100*1024*1024)) sprintf(helpBuf,"ST:%u Mb ",(unsigned int)(STRAM/(1024*1024))); else if(freeRam > 100*1024) sprintf(helpBuf,"ST:%u Kb ",(unsigned int)(STRAM/1024)); else sprintf(helpBuf,"ST:%u b ",(unsigned int)STRAM); strncat(buffer,helpBuf,sizeof(char)*37); if(TTRAM > (100ULL*1024*1024*1024)) sprintf(helpBuf,"TT:%u Gb",(unsigned int)(TTRAM/(1024*1024*1024))); else if(TTRAM > (100*1024*1024)) sprintf(helpBuf,"TT:%u Mb",(unsigned int)(TTRAM/(1024*1024))); else if(freeRam > 100*1024) sprintf(helpBuf,"TT:%u Kb",(unsigned int)(TTRAM/1024)); else sprintf(helpBuf,"TT:%u b",(unsigned int)TTRAM); strncat(buffer,helpBuf,sizeof(char)*37); if(freeRam > (100ULL*1024*1024*1024)) sprintf(helpBuf,"(%u Gb)",(unsigned int)(freeRam/(1024*1024*1024))); else if(freeRam > (100*1024*1024)) sprintf(helpBuf,"(%u Mb)",(unsigned int)(freeRam/(1024*1024))); else if(freeRam > 100*1024) sprintf(helpBuf,"(%u Kb)",(unsigned int)(freeRam/1024)); else sprintf(helpBuf,"(%u b)",(unsigned int)freeRam); strncat(buffer,helpBuf,sizeof(char)*37); Print_in_window(18,51,buffer,STATS_DATA_COLOR,MC_Black); #else // Affichage de la mmoire restante Print_in_window(10,51,"Free memory: ",STATS_TITLE_COLOR,MC_Black); freeRam = Memory_free(); if(freeRam > (100ULL*1024*1024*1024)) sprintf(buffer,"%u Gigabytes",(unsigned int)(freeRam/(1024*1024*1024))); else if(freeRam > (100*1024*1024)) sprintf(buffer,"%u Megabytes",(unsigned int)(freeRam/(1024*1024))); else if(freeRam > 100*1024) sprintf(buffer,"%u Kilobytes",(unsigned int)(freeRam/1024)); else sprintf(buffer,"%u bytes",(unsigned int)freeRam); Print_in_window(114,51,buffer,STATS_DATA_COLOR,MC_Black); #endif // Used memory Print_in_window(10,59,"Used memory pages: ",STATS_TITLE_COLOR,MC_Black); if(Stats_pages_memory > (100LL*1024*1024*1024)) sprintf(buffer,"%ld (%lld Gb)",Stats_pages_number, Stats_pages_memory/(1024*1024*1024)); else if(Stats_pages_memory > (100*1024*1024)) sprintf(buffer,"%ld (%lld Mb)",Stats_pages_number, Stats_pages_memory/(1024*1024)); else sprintf(buffer,"%ld (%lld Kb)",Stats_pages_number, Stats_pages_memory/1024); Print_in_window(162,59,buffer,STATS_DATA_COLOR,MC_Black); // Affichage de l'espace disque libre sprintf(buffer,"Free space on %c:",Main_current_directory[0]); Print_in_window(10,67,buffer,STATS_TITLE_COLOR,MC_Black); #if defined(__WIN32__) { ULARGE_INTEGER tailleU; GetDiskFreeSpaceEx(Main_current_directory,&tailleU,NULL,NULL); mem_size = tailleU.QuadPart; } #elif defined(__linux__) || defined(__macosx__) || defined(__FreeBSD__) // Note: under MacOSX, both macros are defined anyway. { struct statfs disk_info; statfs(Main_current_directory,&disk_info); mem_size=(qword) disk_info.f_bfree * (qword) disk_info.f_bsize; } #elif defined(__HAIKU__) mem_size = haiku_get_free_space(Main_current_directory); #elif defined (__MINT__) _DISKINFO drvInfo; mem_size=0; Dfree(&drvInfo,0); //number of free clusters*sectors per cluster*bytes per sector; // reports current drive mem_size=drvInfo.b_free*drvInfo.b_clsiz*drvInfo.b_secsiz; #else // Free disk space is only for shows. Other platforms can display 0. #warning "Missing code for your platform !!! Check and correct please :)" mem_size=0; #endif if(mem_size > (100ULL*1024*1024*1024)) sprintf(buffer,"%u Gigabytes",(unsigned int)(mem_size/(1024*1024*1024))); else if(mem_size > (100*1024*1024)) sprintf(buffer,"%u Megabytes",(unsigned int)(mem_size/(1024*1024))); else if(mem_size > (100*1024)) sprintf(buffer,"%u Kilobytes",(unsigned int)(mem_size/1024)); else sprintf(buffer,"%u bytes",(unsigned int)mem_size); Print_in_window(146,67,buffer,STATS_DATA_COLOR,MC_Black); // Affichage des informations sur l'image Print_in_window(10,83,"Picture info.:",STATS_TITLE_COLOR,MC_Black); // Affichage des dimensions de l'image Print_in_window(18,91,"Dimensions :",STATS_TITLE_COLOR,MC_Black); sprintf(buffer,"%dx%d",Main_image_width,Main_image_height); Print_in_window(122,91,buffer,STATS_DATA_COLOR,MC_Black); // Affichage du nombre de couleur utilis Print_in_window(18,99,"Colors used:",STATS_TITLE_COLOR,MC_Black); memset(color_usage,0,sizeof(color_usage)); sprintf(buffer,"%d",Count_used_colors(color_usage)); Print_in_window(122,99,buffer,STATS_DATA_COLOR,MC_Black); // Affichage des dimensions de l'cran Print_in_window(10,115,"Resolution:",STATS_TITLE_COLOR,MC_Black); sprintf(buffer,"%dx%d",Screen_width,Screen_height); Print_in_window(106,115,buffer,STATS_DATA_COLOR,MC_Black); Update_rect(Window_pos_X,Window_pos_Y,Menu_factor_X*310,Menu_factor_Y*174); Display_cursor(); do { clicked_button=Window_clicked_button(); if (Is_shortcut(Key,0x200+BUTTON_HELP)) clicked_button=1; } while ( (clicked_button!=1) && (Key!=SDLK_RETURN) ); if(Key==SDLK_RETURN)Key=0; Close_window(); Unselect_button(BUTTON_HELP); Display_cursor(); } grafx2/src/hotkeys.c0000644000076400010400000012046111450742454015065 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2008 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 */ #include "struct.h" #include "global.h" #include "hotkeys.h" #ifdef __VBCC__ #define false 0 #define true 1 #endif T_Key_config ConfigKey[NB_SHORTCUTS] = { {0, "Scroll up", "Scrolls the picture up, both in", "magnify and normal mode.", "", false, SDLK_UP, // HAUT 0}, {1, "Scroll down", "Scrolls the picture down, both in", "magnify and normal mode.", "", false, SDLK_DOWN, // BAS 0}, {2, "Scroll left", "Scrolls the picture to the left,", "both in magnify and normal mode.", "", false, SDLK_LEFT, // GAUCHE 0}, {3, "Scroll right", "Scrolls the picture to the right,", "both in magnify and normal mode.", "", false, SDLK_RIGHT, // DROITE 0}, {4, "Faster scroll up", "Used to scroll upwards in the", "picture fast, either in magnify and", "normal mode.", true, SDLK_UP|MOD_SHIFT, // Shift + Haut 0}, {5, "Faster scroll down", "Used to scroll downwards in the", "picture fast, either in magnify and", "normal mode.", true, SDLK_DOWN|MOD_SHIFT, // Shift + Bas 0}, {6, "Faster scroll left", "Used to scroll to the left in the", "picture fast, either in magnify and", "normal mode.", true, SDLK_LEFT|MOD_SHIFT, // Shift + Gauche 0}, {7, "Faster scroll right", "Used to scroll to the right in the", "picture fast, either in magnify and", "normal mode.", true, SDLK_RIGHT|MOD_SHIFT, // Shift + Droite 0}, {8, "Slower scroll up", "Used to scroll upwards in the", "picture pixel by pixel, either in", "magnify and normal mode.", true, SDLK_UP|MOD_ALT, // Alt + Haut 0}, {9, "Slower scroll down", "Used to scroll downwards in the", "picture pixel by pixel, either in", "magnify and normal mode.", true, SDLK_DOWN|MOD_ALT, // Alt + Bas 0}, {10, "Slower scroll left", "Used to scroll to the left in the", "picture pixel by pixel, either in", "magnify and normal mode.", true, SDLK_LEFT|MOD_ALT, // Alt + Gauche 0}, {11, "Slower scroll right", "Used to scroll to the right in the", "picture pixel by pixel, either in", "magnify and normal mode.", true, SDLK_RIGHT|MOD_ALT, // Alt + Droite 0}, {12, "Move mouse cursor 1 pixel up", "Used to simulate a very small mouse", "deplacement up.It's very useful", "when you want ultra-high precision.", true, SDLK_UP|MOD_CTRL, // Ctrl + Haut 0}, {13, "Move mouse cursor 1 pixel down", "Used to simulate a very small mouse", "deplacement down.It's very useful", "when you want ultra-high precision.", true, SDLK_DOWN|MOD_CTRL, // Ctrl + Bas 0}, {14, "Move mouse cursor 1 pixel left", "Used to simulate a very small mouse", "deplacement left.It's very useful", "when you want ultra-high precision.", true, SDLK_LEFT|MOD_CTRL, // Ctrl + Gauche 0}, {15, "Move mouse cursor 1 pixel right", "Used to simulate a very small mouse", "deplacement right.It's very useful", "when you want ultra-high precision.", true, SDLK_RIGHT|MOD_CTRL, // Ctrl + Droite 0}, {16, "Simulate left mouse click", "Used to simulate a click with the", "left mouse button. It's useful", "when you want ultra-high precision.", true, SDLK_SPACE, // Space 0}, {17, "Simulate right mouse click", "Used to simulate a click with the", "right mouse button.. It's useful", "when you want ultra-high precision.", true, SDLK_SPACE|MOD_SHIFT, // Shift + Space 0}, {18, "Show/hide menu toolbars", "Hides all toolbar menus, or shows", "them back.", "", false, SDLK_F10, // F10 0}, {19, "Show/hide cursor", "Switch the cursor display on/off.", "This only works on the \"small cross\"", "and \"hand\" cursors.", true, SDLK_F9, // F9 0}, {20, "Set paintbrush to 1 pixel", "Useful when you want to use a", "\"single-pixel-brush\".", "", true, SDLK_DELETE, // Del 0}, {21, "Paintbrush choice", "Opens a menu where you can choose a", "paintbrush out of 24 predefined", "ones.", true, SDLK_F4, // F4 0}, {22, "Monochrome brush", "Turn your current user-defined brush", "into a single colored one. All non-", "transparent colors are set to FG.", true, SDLK_F4|MOD_SHIFT, // Shift + F4 0}, {23, "Freehand drawing", "Set the drawing mode to the", "classical freehand one.", "", true, SDLK_d, // D 0}, {24, "Switch freehand drawing mode", "Alternates between: continuous,", "discontinuous, point by point,", "and contour fill", true, SDLK_d|MOD_SHIFT, // Shift + D 0}, {25, "Continuous freehand drawing", "Switch directly to continuous", "freehand drawing mode.", "", true, SDLK_d|MOD_CTRL, // Ctrl + D 0}, {26, "Line", "Allows you to draw lines.", "", "", true, SDLK_l, // L 0}, {27, "Knotted lines", "Allows you to draw linked lines.", "This mode can also be called", "\"Polyline\".", true, SDLK_l|MOD_SHIFT, // Shift + L 0}, {28, "Spray", "Allows you to spray brushes", "randomly in the picture.", "", true, SDLK_a, // A (Q en AZERTY) 0}, {29, "Spray menu", "Opens a menu in which you can", "configure the spray flow and size.", "", true, SDLK_a|MOD_SHIFT, // Shift + A 0}, {30, "Flood-fill", "Allows you to fill an area of the", "picture made of pixels of the same", "color.", true, SDLK_f, // F 0}, {124, "Replace color", "This tool replaces all the pixels of", "the clicked color to the fore-color", "or the back-color.", true, SDLK_f|MOD_SHIFT, // Shift + F 0}, {31, "Bezier's curves", "Allows you to draw Bezier's curves.", "", "", true, SDLK_i, // I 0}, {32, "Bezier's curve with 3 or 4 points", "Allows you to choose whether you", "want to draw Bezier's curves with", "3 or 4 points.", true, SDLK_i|MOD_SHIFT, // Shift + I 0}, {33, "Empty rectangle", "Allows you to draw a rectangle using", "the brush.", "", true, SDLK_r, // R 0}, {34, "Filled rectangle", "Allows you to draw a filled", "rectangle.", "", true, SDLK_r|MOD_SHIFT, // Shift + R 0}, {35, "Empty circle", "Allows you to draw a circle using", "the brush.", "", true, SDLK_c, // C 0}, {36, "Empty ellipse", "Allows you to draw an ellipse using", "the brush.", "", true, SDLK_c|MOD_CTRL, // Ctrl + C 0}, {37, "Filled circle", "Allows you to draw a filled circle.", "", "", true, SDLK_c|MOD_SHIFT, // Shift + C 0}, {38, "Filled ellipse", "Allows you to draw a filled ellipse.", "", "", true, SDLK_c|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + C 0}, {39, "Empty polygon", "Allows you to draw a polygon using", "the brush.", "", true, SDLK_n, // N 0}, {40, "Empty \"polyform\"", "Allows you to draw a freehand", "polygon using the brush.", "", true, SDLK_n|MOD_CTRL, // Ctrl + N 0}, {41, "Filled polygon", "Allows you to draw a filled polygon.", "", "", true, SDLK_n|MOD_SHIFT, // Shift + N 0}, {42, "Filled \"polyform\"", "Allows you to draw a filled freehand", "polygon.", "", true, SDLK_n|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + N 0}, {43, "Rectangle with gradation", "Allows you to draw a rectangle with", "a color gradation.", "", true, SDLK_r|MOD_ALT, // Alt + R 0}, {44, "Gradation menu", "Allows you to configure the way", "color gradations are calculated.", "", true, SDLK_g|MOD_ALT, // Alt + G 0}, {45, "Sphere with gradation", "Allows you to draw a rectangle with", "a color gradation.", "", true, SDLK_c|MOD_ALT, // Alt + C 0}, {46, "Ellipse with gradation", "Allows you to draw an ellipse filled", "with a color gradation.", "", true, SDLK_c|MOD_SHIFT|MOD_ALT, // Shift + Alt + C 0}, {47, "Adjust picture", "Allows you to move the whole picture", "Around. What gets out from a side", "reappears on the other.", true, SDLK_KP5, // Kpad5 0}, {48, "Picture effects", "Opens the 'Picture effects' window.", "", "", true, SDLK_KP5|MOD_SHIFT, // Shift + Kpad5 0}, {49, "Drawing effects", "Opens a menu where you can enable/", "disable and configure the drawing", "effects.", true, SDLK_e, // E 0}, {50, "Shade mode", "Enables or disables Shade mode", "", "", true, SDLK_F5, // F5 0}, {51, "Shade menu", "Opens a the menu for Shade settings.", "", "", true, SDLK_F5|MOD_SHIFT, // Shift + F5 0}, {131, "Quick-shade mode", "Enables or disables Quick-shade", "mode.", "", true, SDLK_F5|MOD_CTRL, // Ctrl + F5 0}, {132, "Quick-shade menu", "Opens a the menu for Quick-shade", "settings.", "", true, SDLK_F5|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + F5 0}, {52, "Stencil mode", "Enables or disables Stencil mode.", "", "", true, SDLK_F6, // F6 0}, {53, "Stencil menu", "Opens a the menu for Stencil", "settings.", "", true, SDLK_F6|MOD_SHIFT, // Shift + F6 0}, {54, "Mask mode", "Enables or disables Mask mode.", "", "", true, SDLK_F6|MOD_ALT, // Alt + F6 0}, {55, "Mask menu", "Opens a the menu for Mask settings.", "", "", true, SDLK_F6|MOD_SHIFT|MOD_ALT, // Shift + Alt + F6 0}, {56, "Grid mode", "Enables or disables the Grid mode.", "", "", true, SDLK_g, // G 0}, {57, "Grid menu", "Open a menu where you can configure", "the grid used by Grid mode.", "", true, SDLK_g|MOD_SHIFT, // Shift + G 0}, {58, "Sieve mode", "Enables or disables the Sieve mode.", "", "", true, SDLK_g|MOD_CTRL, // Ctrl + G 0}, {59, "Sieve menu", "Opens a menu where you can configure", "the sieve.", "", true, SDLK_g|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + G 0}, {60, "Invert sieve", "Inverts the pattern defined in the", "Sieve menu.", "", true, SDLK_g|MOD_CTRL|MOD_ALT, // Ctrl + Alt + G 0}, {61, "Colorize mode", "Enables or disables the Colorize", "mode.", "", true, SDLK_F7, // F7 0}, {62, "Colorize menu", "Opens a menu where you can give the", "opacity percentage for Colorize", "mode.", true, SDLK_F7|MOD_SHIFT, // Shift + F7 0}, {63, "Smooth mode", "Enables or disables the Smooth", "mode.", "", true, SDLK_F8, // F8 0}, {123, "Smooth menu", "Opens a menu where you can define", "the Smooth matrix.", "", true, SDLK_F8|MOD_SHIFT, // Shift + F8 0}, {64, "Smear mode", "Enables or disables the Smear mode.", "", "", true, SDLK_F8|MOD_ALT, // Alt + F8 0}, {65, "Tiling mode", "Enables or disables the Tiling", "mode.", "", true, SDLK_b|MOD_ALT, // Alt + B 0}, {66, "Tiling menu", "Opens a menu where you can configure", "the origin of the tiling.", "", true, SDLK_b|MOD_SHIFT|MOD_ALT, // Shift + Alt + B 0}, {67, "Classical brush grabbing", "Allows you to pick a brush defined", "within a rectangle.", "", true, SDLK_b, // B 0}, {68, "\"Lasso\" brush grabbing", "Allows you to pick a brush defined", "within a freehand polygon.", "", true, SDLK_b|MOD_CTRL, // Ctrl + B 0}, {69, "Get previous brush back", "Restore the last user-defined brush.", "", "", true, SDLK_b|MOD_SHIFT, // Shift + B 0}, {70, "Horizontal brush flipping", "Reverse brush horizontally.", "", "", true, SDLK_x, // X 0}, {71, "Vertical brush flipping", "Reverse brush vertically.", "", "", true, SDLK_y, // Y 0}, {72, "90 brush rotation", "Rotate the user-defined brush by 90", "(counter-clockwise).", "", true, SDLK_z, // Z (W en AZERTY) 0}, {73, "180 brush rotation", "Rotate the user-defined brush by", "180.", "", true, SDLK_z|MOD_SHIFT, // Shift + Z 0}, {74, "Strech brush", "Allows you to resize the", "user-defined brush.", "", true, SDLK_s, // S 0}, {75, "Distort brush", "Allows you to distort the", "user-defined brush.", "", true, SDLK_s|MOD_SHIFT, // Shift + S 0}, {76, "Outline brush", "Outlines the user-defined brush", "with the fore color.", "", true, SDLK_o, // O 0}, {77, "Nibble brush", "Deletes the borders of the", "user-defined brush.This does the", "opposite of the Outline option.", true, SDLK_o|MOD_SHIFT, // Shift + O 0}, {78, "Get colors from brush", "Copy colors of the spare page that", "are used in the brush.", "", true, SDLK_F11, // F11 0}, {79, "Recolorize brush", "Recolorize the user-defined brush in", "order to get a brush which looks as", "if it was grabbed in the spare page.", true, SDLK_F12, // F12 0}, {80, "Rotate by any angle", "Rotate the brush by an angle that", "you can define.", "", true, SDLK_w, // W (Z en AZERTY) 0}, {81, "Pipette", "Allows you to copy the color of a", "pixel in the picture into the", "foreground or background color.", true, SDLK_BACKQUOTE, // `~ (Key sous le Esc - en AZERTY) 0}, {82, "Swap foreground/background colors", "Invert foreground and background", "colors.", "", true, SDLK_BACKQUOTE|MOD_SHIFT, // Shift + `~ 0}, {83, "Magnifier mode", "Allows you to zoom into the picture.", "", "", true, SDLK_m, // M (, ? sur AZERTY) KEY_MOUSEMIDDLE}, {84, "Zoom factor menu", "Opens a menu where you can choose a", "magnifying factor.", "", true, SDLK_m|MOD_SHIFT, // Shift + M 0}, {85, "Zoom in", "Increase magnifying factor.", "", "", true, SDLK_KP_PLUS, // Grey + KEY_MOUSEWHEELUP}, {86, "Zoom out", "Decrease magnifying factor.", "", "", true, SDLK_KP_MINUS, // Grey - KEY_MOUSEWHEELDOWN}, {87, "Brush effects menu", "Opens a menu which proposes", "different effects on the", "user-defined brush.", true, SDLK_b|MOD_CTRL|MOD_ALT, // Ctrl + Alt + B 0}, {88, "Text", "Opens a menu which permits you to", "type in a character string and", "render it as a brush.", true, SDLK_t, // T 0}, {89, "Screen resolution menu", "Opens a menu where you can choose", "the screen resolution and image", "dimensions.", true, SDLK_RETURN, // Enter 0}, {90, "\"Safety\" resolution", "Resets the resolution to a 'safe'", "mode that should work everywhere:", "usually a 640x400 window.", false, SDLK_RETURN|MOD_SHIFT, // Shift + Enter 0}, {91, "Help and credits", "Opens a window where you can get", "information about the program,", "or contextual help.", true, SDLK_F1, // F1 0}, {92, "Statistics", "Displays miscellaneous more or less", "useful information.", "", true, SDLK_F1|MOD_SHIFT, // Shift + F1 0}, {93, "Jump to spare page", "Swap current page and spare page.", "", "", true, SDLK_TAB, // Tab 0}, {94, "Copy current page to spare page", "Copy current page to spare page.", "", "", true, SDLK_TAB|MOD_SHIFT, // Shift + Tab 0}, {95, "Save picture as...", "Opens a file-selector that allows", "you to save your picture with a new", "path-name.", true, SDLK_F2, // F2 0}, {96, "Save picture", "Saves your picture with the last", "name you gave it.", "", true, SDLK_F2|MOD_SHIFT, // Shift + F2 0}, {97, "Load picture", "Opens a file-selector that allows", "you to load a new picture.", "", true, SDLK_F3, // F3 0}, {98, "Re-load picture", "Re-load the current picture. This", "allows you to cancel modifications", "made since last saving.", true, SDLK_F3|MOD_SHIFT, // Shift + F3 0}, {99, "Save brush", "Opens a file-selector that allows", "you to save your current", "user-defined brush.", true, SDLK_F2|MOD_CTRL, // Ctrl + F2 0}, {100, "Load brush", "Opens a file-selector that allows", "you to load a brush.", "", true, SDLK_F3|MOD_CTRL, // Ctrl + F3 0}, {101, "Settings", "Opens a menu which permits you to", "modify some parameters of the", "program.", true, SDLK_F10|MOD_SHIFT, // Shift + F10 0}, {102, "Undo (Oops!)", "Cancel the last action which", "modified the picture.", "", true, SDLK_u, // U // Secondary shortcut is button I on the Caanoo, L on the Wiz, unset on others #if defined (__CAANOO__) (KEY_JOYBUTTON+JOY_BUTTON_I) #elif defined (__WIZ__) (KEY_JOYBUTTON+JOY_BUTTON_L) #else 0 #endif // -- }, {103, "Redo", "Redo the last undone action.", "", "", true, SDLK_u|MOD_SHIFT, // Shift + U // Secondary shortcut is button II on the Caanoo, R on the Wiz, unset on others #if defined (__CAANOO__) (KEY_JOYBUTTON+JOY_BUTTON_II) #elif defined (__WIZ__) (KEY_JOYBUTTON+JOY_BUTTON_R) #else 0 #endif // -- }, {133, "Kill", "Kills the current page. It actually", "removes the current page from the", "list of \"Undo\" pages.", true, SDLK_DELETE|MOD_SHIFT, // Shift + Suppr 0}, {104, "Clear page", "Clears the picture with color 0,", "or the transparent color if it's", "a layered image.", true, SDLK_BACKSPACE, // BackSpace 0}, {105, "Clear page with backcolor", "Clears the picture with the", "current backcolor.", "", true, SDLK_BACKSPACE|MOD_SHIFT, // Shift + BackSpace 0}, {106, "Quit program", "Allows you to leave the program.", "If modifications were not saved,", "confirmation is asked.", false, SDLK_q, // Q (A en AZERTY) // Secondary shortcut is button Home on the Caanoo, Menu on the Wiz, unset on others #if defined (__CAANOO__) (KEY_JOYBUTTON+JOY_BUTTON_HOME) #elif defined (__WIZ__) (KEY_JOYBUTTON+JOY_BUTTON_MENU) #else 0 #endif // -- }, {107, "Palette menu", "Opens a menu which allows you to", "modify the current palette.", "", true, SDLK_p, // P 0}, {125, "Secondary palette menu", "Opens a menu which allows you to", "define color series and some tagged", "colors.", true, SDLK_p|MOD_SHIFT, // Shift + P 0}, {130, "Exclude colors menu", "Opens a menu which allows you to", "define the colors you don't want to", "use in Smooth and Transparency", true, SDLK_p|MOD_CTRL, // Ctrl + P 0}, {108, "Scroll palette to the left", "Scroll palette in the tool bar to", "the left, column by column.", "", true, SDLK_PAGEUP, // PgUp 0}, {109, "Scroll palette to the right", "Scroll palette in the tool bar to", "the right, column by column.", "", true, SDLK_PAGEDOWN, // PgDn 0}, {110, "Scroll palette to the left faster", "Scroll palette in the tool bar to", "the left, 8 columns by 8 columns.", "", true, SDLK_PAGEUP|MOD_SHIFT, // Shift + PgUp 0}, {111, "Scroll palette to the right faster", "Scroll palette in the tool bar to", "the right, 8 columns by 8 columns.", "", true, SDLK_PAGEDOWN|MOD_SHIFT, // Shift + PgDn 0}, {112, "Center brush attachment point", "Set the attachement of the", "user-defined brush to its center.", "", true, SDLK_KP5|MOD_CTRL, // Ctrl + 5 (pav numrique) 0}, {113, "Top-left brush attachment point", "Set the attachement of the", "user-defined brush to its top-left", "corner.", true, SDLK_HOME|MOD_CTRL, // Ctrl + 7 0}, {114, "Top-right brush attachment point", "Set the attachement of the", "user-defined brush to its top-right", "corner.", true, SDLK_PAGEUP|MOD_CTRL, // Ctrl + 9 0}, {115, "Bottom-left brush attachment point", "Set the attachement of the", "user-defined brush to its", "bottom-left corner.", true, SDLK_END|MOD_CTRL, // Ctrl + 1 0}, {116, "Bottom-right brush attachment point", "Set the attachement of the", "user-defined brush to its", "bottom-right corner.", true, SDLK_PAGEDOWN|MOD_CTRL, // Ctrl + 3 0}, {117, "Next foreground color", "Set the foreground color to the next", "in the palette.", "", true, SDLK_RIGHTBRACKET, // ] (0x en AZERTY) 0}, {118, "Previous foreground color", "Set the foreground color to the", "previous in the palette.", "", true, SDLK_LEFTBRACKET, // [ (^ en AZERTY) 0}, {119, "Next background color", "Set the background color to the next", "in the palette.", "", true, SDLK_RIGHTBRACKET|MOD_SHIFT, // Shift + ] 0}, {120, "Previous background color", "Set the background color to the", "previous in the palette.", "", true, SDLK_LEFTBRACKET|MOD_SHIFT, // Shift + [ 0}, {126, "Next user-defined forecolor", "Set the foreground color to the next", "in the user-defined color series.", "", true, SDLK_EQUALS, // "=+" 0}, {127, "Previous user-defined forecolor", "Set the foreground color to the", "previous in the user-defined color", "series.", true, SDLK_MINUS, // "-_" (")" en AZERTY 0}, {128, "Next user-defined backcolor", "Set the background color to the next", "in the user-defined color series.", "", true, SDLK_EQUALS|MOD_SHIFT, // Shift + "=+" 0}, {129, "Previous user-defined backcolor", "Set the background color to the", "previous in the user-defined color", "series.", true, SDLK_MINUS|MOD_SHIFT, // Shift + "-_" (")" en AZERTY 0}, {121, "Shrink paintbrush", "Decrease the width of the paintbrush", "if it is special circle or square.", "", true, SDLK_COMMA, // , < (;. en AZERTY) 0}, {122, "Enlarge paintbrush", "Increase the width of the paintbrush", "if it is special circle or square.", "", true, SDLK_PERIOD, // .> (:/ en AZERTY) 0}, {134, "Effects off", "Turns off all drawing effects. This", "is the same as the 'All off' button", "in the Effects screen", true, SDLK_e|MOD_SHIFT, // Shift-E 0}, {135, "Transparency 10%", "Turns transparency on and sets its", "opacity at 10%.", "", true, SDLK_1, // 1 0}, {136, "Transparency 20%", "Turns transparency on and sets its", "opacity at 20%.", "", true, SDLK_2, // 2 0}, {137, "Transparency 30%", "Turns transparency on and sets its", "opacity at 30%.", "", true, SDLK_3, // 3 0}, {138, "Transparency 40%", "Turns transparency on and sets its", "opacity at 40%.", "", true, SDLK_4, // 4 0}, {139, "Transparency 50%", "Turns transparency on and sets its", "opacity at 50%.", "", true, SDLK_5, // 5 0}, {140, "Transparency 60%", "Turns transparency on and sets its", "opacity at 60%.", "", true, SDLK_6, // 6 0}, {141, "Transparency 70%", "Turns transparency on and sets its", "opacity at 70%.", "", true, SDLK_7, // 7 0}, {142, "Transparency 80%", "Turns transparency on and sets its", "opacity at 80%.", "", true, SDLK_8, // 8 0}, {143, "Transparency 90%", "Turns transparency on and sets its", "opacity at 90%.", "", true, SDLK_9, // 9 0}, {144, "Transparency 0%", "Turns transparency on and sets its", "opacity at 0%.", "", true, SDLK_0, // 0 0}, {145, "Zoom 1:1", "Turns magnifier mode off.", "", "", true, SDLK_1|MOD_CTRL, /* Ctrl + 1 */ 0}, {146, "Zoom 2:1", "Turns magnifier mode on and set its", "factor to 2:1", "", true, SDLK_2|MOD_CTRL, /* Ctrl + 2 */ 0}, {147, "Zoom 3:1", "Turns magnifier mode on and set its", "factor to 3:1", "", true, SDLK_3|MOD_CTRL, /* Ctrl + 3 */ 0}, {148, "Zoom 4:1", "Turns magnifier mode on and set its", "factor to 4:1", "", true, SDLK_4|MOD_CTRL, /* Ctrl + 4 */ 0}, {149, "Zoom 5:1", "Turns magnifier mode on and set its", "factor to 5:1", "", true, SDLK_5|MOD_CTRL, /* Ctrl + 5 */ 0}, {150, "Zoom 6:1", "Turns magnifier mode on and set its", "factor to 6:1", "", true, SDLK_6|MOD_CTRL, /* Ctrl + 6 */ 0}, {151, "Zoom 8:1", "Turns magnifier mode on and set its", "factor to 8:1", "", true, SDLK_7|MOD_CTRL, /* Ctrl + 7 */ 0}, {152, "Zoom 10:1", "Turns magnifier mode on and set its", "factor to 10:1", "", true, SDLK_8|MOD_CTRL, /* Ctrl + 8 */ 0}, {153, "Zoom 12:1", "Turns magnifier mode on and set its", "factor to 12:1", "", true, 0, 0}, {154, "Zoom 14:1", "Turns magnifier mode on and set its", "factor to 14:1", "", true, 0, 0}, {155, "Zoom 16:1", "Turns magnifier mode on and set its", "factor to 16:1", "", true, 0, 0}, {156, "Zoom 18:1", "Turns magnifier mode on and set its", "factor to 18:1", "", true, 0, 0}, {157, "Zoom 20:1", "Turns magnifier mode on and set its", "factor to 20:1", "", true, 0, 0}, {158, "Show/Hide Grid", "Turns on or off the visible grid in ", "the magnified view. Grid cells match", "the size ", true, SDLK_g|MOD_SHIFT|MOD_ALT, // Shift + Alt + G, 0}, {159, "Select layer 1", "Makes the layer 1 visible and", "set it as the active one, where", "you can draw.", true, 0, 0}, {160, "Toggle layer 1", "Makes layer 1 visible or invisible.", "If it's the current active layer,", "toggle all other layers instead.", true, 0, 0}, {161, "Select layer 2", "Makes the layer 2 visible and", "set it as the active one, where", "you can draw.", true, 0, 0}, {162, "Toggle layer 2", "Makes layer 2 visible or invisible.", "If it's the current active layer,", "toggle all other layers instead.", true, 0, 0}, {163, "Select layer 3", "Makes the layer 3 visible and", "set it as the active one, where", "you can draw.", true, 0, 0}, {164, "Toggle layer 3", "Makes layer 3 visible or invisible.", "If it's the current active layer,", "toggle all other layers instead.", true, 0, 0}, {165, "Select layer 4", "Makes the layer 4 visible and", "set it as the active one, where", "you can draw.", true, 0, 0}, {166, "Toggle layer 4", "Makes layer 4 visible or invisible.", "If it's the current active layer,", "toggle all other layers instead.", true, 0, 0}, {167, "Select layer 5", "Makes the layer 5 visible and", "set it as the active one, where", "you can draw.", true, 0, 0}, {168, "Toggle layer 5", "Makes layer 5 visible or invisible.", "If it's the current active layer,", "toggle all other layers instead.", true, 0, 0}, {169, "Select layer 6", "Makes the layer 6 visible and", "set it as the active one, where", "you can draw.", true, 0, 0}, {170, "Toggle layer 6", "Makes layer 6 visible or invisible.", "If it's the current active layer,", "toggle all other layers instead.", true, 0, 0}, {171, "Select layer 7", "Makes the layer 7 visible and", "set it as the active one, where", "you can draw.", true, 0, 0}, {172, "Toggle layer 7", "Makes layer 7 visible or invisible.", "If it's the current active layer,", "toggle all other layers instead.", true, 0, 0}, {173, "Select layer 8", "Makes the layer 8 visible and", "set it as the active one, where", "you can draw.", true, 0, 0}, {174, "Toggle layer 8", "Makes layer 8 visible or invisible.", "If it's the current active layer,", "toggle all other layers instead.", true, 0, 0}, {175, "Add a layer", "Adds a new layer on top of the", "active one. The new layer is filled", "with transparent color.", true, SDLK_INSERT|MOD_ALT, // Alt + Insert 0}, {176, "Delete a layer", "Delete the current layer.", "You can't delete the last", "layer.", true, SDLK_DELETE|MOD_ALT, // Alt + Delete 0}, {177, "Merge a layer", "Merges the current layer with", "the one directly below it.", "", true, SDLK_END|MOD_ALT, // Alt + End 0}, {178, "Swap layer (up)", "Moves the current layer one position", "up the stack. No effect if already", "on top.", true, SDLK_PAGEUP|MOD_ALT, // Alt + PageUp 0}, {179, "Swap layer (down)", "Moves the current layer one position", "down the stack. No effect if already", "on bottom.", true, SDLK_PAGEDOWN|MOD_ALT, // Alt + PageDown 0}, {180, "Layers menu", "Opens a window with options related", "to layers and image transparency.", "", true, SDLK_HOME|MOD_ALT, // Alt + Home 0}, {181, "Brush factory", "Opens a window where you can run a", "Lua script.", "", true, 0, // No shortcut 0}, {182, "Repeat script", "Re-run the last script selected", "in the Brush factory window.", "", true, 0, // No shortcut 0}, {183, "Double brush size", "Resizes the current user brush", "by doubling width and height.", "", true, SDLK_h|MOD_SHIFT, // Shift+H 0}, {184, "Double brush width", "Resizes the current user brush", "by doubling its width.", "", true, SDLK_x|MOD_SHIFT, // Shift+X 0}, {185, "Double brush height", "Resizes the current user brush", "by doubling its height.", "", true, SDLK_y|MOD_SHIFT, // Shift+Y 0}, {186, "Halve brush size", "Resizes the current user brush", "by halving its width and height", "", true, SDLK_h, // H 0}, {187, "Run script #1", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {188, "Run script #2", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {189, "Run script #3", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {190, "Run script #4", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {191, "Run script #5", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {192, "Run script #6", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {193, "Run script #7", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {194, "Run script #8", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {195, "Run script #9", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {196, "Run script #10", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {197, "Toggle color cycling", "Activates or desactivates color", "cycling, if the current image has", "cycling colors. (See gradient menu)", true, SDLK_BACKQUOTE|MOD_CTRL, // Ctrl + `~ 0}, }; word Ordering[NB_SHORTCUTS]= { SPECIAL_SCROLL_UP, // Scroll up SPECIAL_SCROLL_DOWN, // Scroll down SPECIAL_SCROLL_LEFT, // Scroll left SPECIAL_SCROLL_RIGHT, // Scroll right SPECIAL_SCROLL_UP_FAST, // Scroll up faster SPECIAL_SCROLL_DOWN_FAST, // Scroll down faster SPECIAL_SCROLL_LEFT_FAST, // Scroll left faster SPECIAL_SCROLL_RIGHT_FAST, // Scroll right faster SPECIAL_SCROLL_UP_SLOW, // Scroll up slower SPECIAL_SCROLL_DOWN_SLOW, // Scroll down slower SPECIAL_SCROLL_LEFT_SLOW, // Scroll left slower SPECIAL_SCROLL_RIGHT_SLOW, // Scroll right slower SPECIAL_MOUSE_UP, // Emulate mouse up SPECIAL_MOUSE_DOWN, // Emulate mouse down SPECIAL_MOUSE_LEFT, // Emulate mouse left SPECIAL_MOUSE_RIGHT, // Emulate mouse right SPECIAL_CLICK_LEFT, // Emulate mouse click left SPECIAL_CLICK_RIGHT, // Emulate mouse click right 0x100+BUTTON_HIDE, // Show / Hide menus SPECIAL_SHOW_HIDE_CURSOR, // Show / Hide cursor SPECIAL_DOT_PAINTBRUSH, // Paintbrush = "." 0x100+BUTTON_PAINTBRUSHES, // Paintbrush choice 0x200+BUTTON_PAINTBRUSHES, // Monochrome brush 0x100+BUTTON_DRAW, // Freehand drawing 0x200+BUTTON_DRAW, // Switch freehand drawing mode SPECIAL_CONTINUOUS_DRAW, // Continuous freehand drawing 0x100+BUTTON_LINES, // Line 0x200+BUTTON_LINES, // Knotted lines 0x100+BUTTON_AIRBRUSH, // Spray 0x200+BUTTON_AIRBRUSH, // Spray menu 0x100+BUTTON_FLOODFILL, // Floodfill 0x200+BUTTON_FLOODFILL, // Replace color 0x100+BUTTON_CURVES, // Bzier's curves 0x200+BUTTON_CURVES, // Bzier's curve with 3 or 4 points 0x100+BUTTON_RECTANGLES, // Empty rectangle 0x100+BUTTON_FILLRECT, // Filled rectangle 0x100+BUTTON_CIRCLES, // Empty circle 0x200+BUTTON_CIRCLES, // Empty ellipse 0x100+BUTTON_FILLCIRC, // Filled circle 0x200+BUTTON_FILLCIRC, // Filled ellipse 0x100+BUTTON_POLYGONS, // Empty polygon 0x200+BUTTON_POLYGONS, // Empty polyform 0x100+BUTTON_POLYFILL, // Polyfill 0x200+BUTTON_POLYFILL, // Filled polyform 0x100+BUTTON_GRADRECT, // Gradient rectangle 0x200+BUTTON_GRADRECT, // Gradation menu 0x100+BUTTON_SPHERES, // Spheres 0x200+BUTTON_SPHERES, // Gradient ellipses 0x100+BUTTON_ADJUST, // Adjust picture 0x200+BUTTON_ADJUST, // Flip picture menu 0x100+BUTTON_EFFECTS, // Menu des effets SPECIAL_SHADE_MODE, // Shade mode SPECIAL_SHADE_MENU, // Shade menu SPECIAL_QUICK_SHADE_MODE, // Quick-shade mode SPECIAL_QUICK_SHADE_MENU, // Quick-shade menu SPECIAL_STENCIL_MODE, // Stencil mode SPECIAL_STENCIL_MENU, // Stencil menu SPECIAL_MASK_MODE, // Mask mode SPECIAL_MASK_MENU, // Mask menu SPECIAL_GRID_MODE, // Grid mode SPECIAL_GRID_MENU, // Grid menu SPECIAL_SIEVE_MODE, // Sieve mode SPECIAL_SIEVE_MENU, // Sieve menu SPECIAL_INVERT_SIEVE, // Inverser la trame du mode Sieve SPECIAL_COLORIZE_MODE, // Colorize mode SPECIAL_COLORIZE_MENU, // Colorize menu SPECIAL_SMOOTH_MODE, // Smooth mode SPECIAL_SMOOTH_MENU, // Smooth menu SPECIAL_SMEAR_MODE, // Smear mode SPECIAL_TILING_MODE, // Tiling mode SPECIAL_TILING_MENU, // Tiling menu 0x100+BUTTON_BRUSH, // Pick brush 0x100+BUTTON_POLYBRUSH, // Pick polyform brush 0x200+BUTTON_BRUSH, // Restore brush SPECIAL_FLIP_X, // Flip X SPECIAL_FLIP_Y, // Flip Y SPECIAL_ROTATE_90, // 90 brush rotation SPECIAL_ROTATE_180, // 180 brush rotation SPECIAL_STRETCH, // Stretch brush SPECIAL_DISTORT, // Distort brush SPECIAL_OUTLINE, // Outline brush SPECIAL_NIBBLE, // Nibble brush SPECIAL_GET_BRUSH_COLORS, // Get colors from brush SPECIAL_RECOLORIZE_BRUSH, // Recolorize brush SPECIAL_ROTATE_ANY_ANGLE, // Rotate brush by any angle 0x100+BUTTON_COLORPICKER, // Pipette 0x200+BUTTON_COLORPICKER, // Swap fore/back color 0x100+BUTTON_MAGNIFIER, // Magnifier mode 0x200+BUTTON_MAGNIFIER, // Zoom factor menu SPECIAL_ZOOM_IN, // Zoom in SPECIAL_ZOOM_OUT, // Zoom out 0x100+BUTTON_BRUSH_EFFECTS, // Brush effects menu 0x100+BUTTON_TEXT, // Text 0x100+BUTTON_RESOL, // Resolution menu 0x200+BUTTON_RESOL, // Safety resolution 0x100+BUTTON_HELP, // Help & credits 0x200+BUTTON_HELP, // Statistics 0x100+BUTTON_PAGE, // Go to spare page 0x200+BUTTON_PAGE, // Copy to spare page 0x100+BUTTON_SAVE, // Save as 0x200+BUTTON_SAVE, // Save 0x100+BUTTON_LOAD, // Load 0x200+BUTTON_LOAD, // Re-load SPECIAL_SAVE_BRUSH, // Save brush SPECIAL_LOAD_BRUSH, // Load brush 0x100+BUTTON_SETTINGS, // Settings 0x100+BUTTON_UNDO, // Undo 0x200+BUTTON_UNDO, // Redo 0x100+BUTTON_KILL, // Kill 0x100+BUTTON_CLEAR, // Clear 0x200+BUTTON_CLEAR, // Clear with backcolor 0x100+BUTTON_QUIT, // Quit 0x100+BUTTON_PALETTE, // Palette menu 0x200+BUTTON_PALETTE, // Palette menu secondaire SPECIAL_EXCLUDE_COLORS_MENU, // Exclude colors menu 0x100+BUTTON_PAL_LEFT, // Scroll palette left 0x100+BUTTON_PAL_RIGHT, // Scroll palette right 0x200+BUTTON_PAL_LEFT, // Scroll palette left faster 0x200+BUTTON_PAL_RIGHT, // Scroll palette right faster SPECIAL_CENTER_ATTACHMENT, // Center brush attachement SPECIAL_TOP_LEFT_ATTACHMENT, // Top-left brush attachement SPECIAL_TOP_RIGHT_ATTACHMENT, // Top-right brush attachement SPECIAL_BOTTOM_LEFT_ATTACHMENT, // Bottom-left brush attachement SPECIAL_BOTTOM_RIGHT_ATTACHMENT, // Bottom right brush attachement SPECIAL_NEXT_FORECOLOR, // Next foreground color SPECIAL_PREVIOUS_FORECOLOR, // Previous foreground color SPECIAL_NEXT_BACKCOLOR, // Next background color SPECIAL_PREVIOUS_BACKCOLOR, // Previous background color SPECIAL_NEXT_USER_FORECOLOR, // Next user-defined foreground color SPECIAL_PREVIOUS_USER_FORECOLOR, // Previous user-defined foreground color SPECIAL_NEXT_USER_BACKCOLOR, // Next user-defined background color SPECIAL_PREVIOUS_USER_BACKCOLOR, // Previous user-defined background color SPECIAL_SMALLER_PAINTBRUSH, // Sets paintbrush size: smaller SPECIAL_BIGGER_PAINTBRUSH, // Sets paintbrush size: bigger SPECIAL_EFFECTS_OFF, // Turns off all effects SPECIAL_TRANSPARENCY_1, // Sets transparency level 10% SPECIAL_TRANSPARENCY_2, // Sets transparency level 20% SPECIAL_TRANSPARENCY_3, // Sets transparency level 30% SPECIAL_TRANSPARENCY_4, // Sets transparency level 40% SPECIAL_TRANSPARENCY_5, // Sets transparency level 50% SPECIAL_TRANSPARENCY_6, // Sets transparency level 60% SPECIAL_TRANSPARENCY_7, // Sets transparency level 70% SPECIAL_TRANSPARENCY_8, // Sets transparency level 80% SPECIAL_TRANSPARENCY_9, // Sets transparency level 90% SPECIAL_TRANSPARENCY_0, // Sets transparency level 00% SPECIAL_ZOOM_1, /**< Sets zoom factor to 1:1 (no magnification) */ SPECIAL_ZOOM_2, /**< Sets zoom factor to 2:1 */ SPECIAL_ZOOM_3, /**< Sets zoom factor to 3:1 */ SPECIAL_ZOOM_4, /**< Sets zoom factor to 4:1 */ SPECIAL_ZOOM_5, /**< Sets zoom factor to 5:1 */ SPECIAL_ZOOM_6, /**< Sets zoom factor to 6:1 */ SPECIAL_ZOOM_8, /**< Sets zoom factor to 8:1 */ SPECIAL_ZOOM_10, /**< Sets zoom factor to 10:1 */ SPECIAL_ZOOM_12, /**< Sets zoom factor to 12:1 */ SPECIAL_ZOOM_14, /**< Sets zoom factor to 14:1 */ SPECIAL_ZOOM_16, /**< Sets zoom factor to 16:1 */ SPECIAL_ZOOM_18, /**< Sets zoom factor to 18:1 */ SPECIAL_ZOOM_20, /**< Sets zoom factor to 20:1 */ SPECIAL_SHOW_GRID, SPECIAL_LAYER1_SELECT, SPECIAL_LAYER1_TOGGLE, SPECIAL_LAYER2_SELECT, SPECIAL_LAYER2_TOGGLE, SPECIAL_LAYER3_SELECT, SPECIAL_LAYER3_TOGGLE, SPECIAL_LAYER4_SELECT, SPECIAL_LAYER4_TOGGLE, SPECIAL_LAYER5_SELECT, SPECIAL_LAYER5_TOGGLE, SPECIAL_LAYER6_SELECT, SPECIAL_LAYER6_TOGGLE, SPECIAL_LAYER7_SELECT, SPECIAL_LAYER7_TOGGLE, SPECIAL_LAYER8_SELECT, SPECIAL_LAYER8_TOGGLE, 0x100+BUTTON_LAYER_ADD, 0x100+BUTTON_LAYER_REMOVE, 0x100+BUTTON_LAYER_MERGE, 0x100+BUTTON_LAYER_UP, 0x100+BUTTON_LAYER_DOWN, 0x100+BUTTON_LAYER_MENU, 0x200+BUTTON_BRUSH_EFFECTS, SPECIAL_REPEAT_SCRIPT, SPECIAL_BRUSH_DOUBLE, SPECIAL_BRUSH_DOUBLE_WIDTH, SPECIAL_BRUSH_DOUBLE_HEIGHT, SPECIAL_BRUSH_HALVE, SPECIAL_RUN_SCRIPT_1, SPECIAL_RUN_SCRIPT_2, SPECIAL_RUN_SCRIPT_3, SPECIAL_RUN_SCRIPT_4, SPECIAL_RUN_SCRIPT_5, SPECIAL_RUN_SCRIPT_6, SPECIAL_RUN_SCRIPT_7, SPECIAL_RUN_SCRIPT_8, SPECIAL_RUN_SCRIPT_9, SPECIAL_RUN_SCRIPT_10, SPECIAL_CYCLE_MODE, }; grafx2/src/init.c0000644000076400010400000027610411536457150014351 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2009 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 */ #define _XOPEN_SOURCE 500 // Signal handler: I activate it for the two platforms who certainly // support them. Feel free to check with others. #if defined(__WIN32__) || defined(__linux__) #define GRAFX2_CATCHES_SIGNALS #endif #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) #include #include #endif #include //#include #include #ifndef __VBCC__ #include #endif #include #include #include #include #if defined(__WIN32__) #include // GetLogicalDrives(), GetDriveType(), DRIVE_* #endif #ifndef __GP2X__ #include #endif #if defined (__MINT__) #include #endif #ifdef GRAFX2_CATCHES_SIGNALS #include #endif #include "buttons.h" #include "const.h" #include "errors.h" #include "global.h" #include "graph.h" #include "init.h" #include "io.h" #include "factory.h" #include "help.h" #include "hotkeys.h" #include "keyboard.h" #include "loadsave.h" // Image_emergency_backup #include "misc.h" #include "mountlist.h" // read_file_system_list #include "operatio.h" #include "palette.h" #include "sdlscreen.h" #include "setup.h" #include "struct.h" #include "transform.h" #include "windows.h" #include "layers.h" #include "special.h" #include "buttons.h" char Gui_loading_error_message[512]; // Rechercher la liste et le type des lecteurs de la machine #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) void bstrtostr( BSTR in, STRPTR out, TEXT max ); #endif // Fonctions de lecture dans la skin de l'interface graphique byte GUI_seek_down(SDL_Surface *gui, int *start_x, int *start_y, byte neutral_color,char * section) { byte color; int y; y=*start_y; *start_x=0; do { color=Get_SDL_pixel_8(gui,*start_x,y); if (color!=neutral_color) { *start_y=y; return 0; } y++; } while (yh); sprintf(Gui_loading_error_message, "Error in skin file: Was looking down from %d,%d for a '%s', and reached the end of the image\n", *start_x, *start_y, section); return 1; } byte GUI_seek_right(SDL_Surface *gui, int *start_x, int start_y, byte neutral_color, char * section) { byte color; int x; x=*start_x; do { color=Get_SDL_pixel_8(gui,x,start_y); if (color!=neutral_color) { *start_x=x; return 0; } x++; } while (xw); sprintf(Gui_loading_error_message, "Error in skin file: Was looking right from %d,%d for a '%s', and reached the edege of the image\n", *start_x, start_y, section); return 1; } byte Read_GUI_block(T_Gui_skin *gfx, SDL_Surface *gui, int start_x, int start_y, void *dest, int width, int height, char * section, int type) { // type: 0 = normal GUI element, only 4 colors allowed // type: 1 = mouse cursor, 4 colors allowed + transparent // type: 2 = brush icon or sieve pattern (only gui->Color[3] and gui->Color_trans) // type: 3 = raw bitmap (splash screen) byte * dest_ptr=dest; int x,y; byte color; // Verification taille if (start_y+height>=gui->h || start_x+width>=gui->w) { sprintf(Gui_loading_error_message, "Error in skin file: Was looking at %d,%d for a %d*%d object (%s) but it doesn't fit the image.\n", start_x, start_y, height, width, section); return 1; } for (y=start_y; yColor[0] && color != gfx->Color[1] && color != gfx->Color[2] && color != gfx->Color[3])) { sprintf(Gui_loading_error_message, "Error in skin file: Was looking at %d,%d for a %d*%d object (%s) but at %d,%d a pixel was found with color %d which isn't one of the GUI colors (which were detected as %d,%d,%d,%d.\n", start_x, start_y, height, width, section, x, y, color, gfx->Color[0], gfx->Color[1], gfx->Color[2], gfx->Color[3]); return 1; } if (type==1 && (color != gfx->Color[0] && color != gfx->Color[1] && color != gfx->Color[2] && color != gfx->Color[3] && color != gfx->Color_trans)) { sprintf(Gui_loading_error_message, "Error in skin file: Was looking at %d,%d for a %d*%d object (%s) but at %d,%d a pixel was found with color %d which isn't one of the mouse colors (which were detected as %d,%d,%d,%d,%d.\n", start_x, start_y, height, width, section, x, y, color, gfx->Color[0], gfx->Color[1], gfx->Color[2], gfx->Color[3], gfx->Color_trans); return 1; } if (type==2) { if (color != gfx->Color[3] && color != gfx->Color_trans) { sprintf(Gui_loading_error_message, "Error in skin file: Was looking at %d,%d for a %d*%d object (%s) but at %d,%d a pixel was found with color %d which isn't one of the brush colors (which were detected as %d on %d.\n", start_x, start_y, height, width, section, x, y, color, gfx->Color[3], gfx->Color_trans); return 1; } // Conversion en 0/1 pour les brosses monochromes internes color = (color != gfx->Color_trans); } *dest_ptr=color; dest_ptr++; } } return 0; } byte Read_GUI_pattern(T_Gui_skin *gfx, SDL_Surface *gui, int start_x, int start_y, word *dest, char * section) { byte buffer[256]; int x,y; if (Read_GUI_block(gfx, gui, start_x, start_y, buffer, 16, 16, section, 2)) return 1; for (y=0; y<16; y++) { *dest=0; for (x=0; x<16; x++) { *dest=*dest | buffer[y*16+x]<Color_trans) { found=1; break; } } if (found) break; } // Locate first non-empty line found=0; for (start_y=0;start_y<14;start_y++) { for (x=0;x<29;x++) { if (cursor_buffer[start_y*29+x]!=gfx->Color_trans) { found=1; break; } } if (found) break; } gfx->Cursor_offset_X[cursor_number]=14-start_x; gfx->Cursor_offset_Y[cursor_number]=14-start_y; for (y=0;yCursor_sprite[cursor_number][y][x]=cursor_buffer[(start_y+y)*29+start_x+x]; } byte Parse_skin(SDL_Surface * gui, T_Gui_skin *gfx) { int i,j; int cursor_x=0,cursor_y=0; byte color; byte neutral_color; // color neutre utilise pour dlimiter les lments GUI int char_1=0; // Indices utiliss pour les 4 "fontes" qui composent les int char_2=0; // grands titres de l'aide. Chaque indice avance dans int char_3=0; // l'une des fontes dans l'ordre : 1 2 int char_4=0; // 3 4 byte mouse_cursor_area[29][29]; SDL_Palette * SDLPal; // Default palette if (!gui->format || gui->format->BitsPerPixel != 8) { sprintf(Gui_loading_error_message, "Not a 8-bit image"); return 1; } SDLPal=gui->format->palette; if (!SDLPal || SDLPal->ncolors!=256) { sprintf(Gui_loading_error_message, "Not a 256-color palette"); return 1; } // Read the default palette Get_SDL_Palette(SDLPal, gfx->Default_palette); // Carr "noir" gfx->Color[0] = Get_SDL_pixel_8(gui,cursor_x,cursor_y); do { if (++cursor_x>=gui->w) { sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); return 1; } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==gfx->Color[0]); // Carr "fonc" gfx->Color[1] = color; do { if (++cursor_x>=gui->w) { sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); return 1; } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==gfx->Color[1]); // Carr "clair" gfx->Color[2] = color; do { if (++cursor_x>gui->w) { sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); return 1; } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==gfx->Color[2]); // Carr "blanc" gfx->Color[3] = color; do { if (++cursor_x>=gui->w) { sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); return 1; } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==gfx->Color[3]); // Carr "transparent" gfx->Color_trans=color; do { if (++cursor_x>=gui->w) { sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); return 1; } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==gfx->Color_trans); // Reste : couleur neutre neutral_color=color; cursor_x=0; cursor_y=1; while ((color=Get_SDL_pixel_8(gui,cursor_x,cursor_y))==gfx->Color[0]) { cursor_y++; if (cursor_y>=gui->h) { sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); return 1; } } // Menu if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "menu")) return 1; if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Menu_block[0], Menu_bars[MENUBAR_TOOLS].Skin_width, Menu_bars[MENUBAR_TOOLS].Height,"menu",0)) return 1; // Preview cursor_x += Menu_bars[MENUBAR_TOOLS].Skin_width; if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "preview")) return 1; if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Preview, 173, 16, "preview", 0)) return 1; cursor_y+= Menu_bars[MENUBAR_TOOLS].Height; // Layerbar if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "layer bar")) return 1; if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Layerbar_block[0], Menu_bars[MENUBAR_LAYERS].Skin_width, Menu_bars[MENUBAR_LAYERS].Height,"layer bar",0)) return 1; cursor_y+= Menu_bars[MENUBAR_LAYERS].Height; // Status bar if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "status bar")) return 1; if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Statusbar_block[0], Menu_bars[MENUBAR_STATUS].Skin_width, Menu_bars[MENUBAR_STATUS].Height,"status bar",0)) return 1; cursor_y+= Menu_bars[MENUBAR_STATUS].Height; // Menu (selected) if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "selected menu")) return 1; if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Menu_block[1], Menu_bars[MENUBAR_TOOLS].Skin_width, Menu_bars[MENUBAR_TOOLS].Height,"selected menu",0)) return 1; cursor_y+= Menu_bars[MENUBAR_TOOLS].Height; // Layerbar (selected) if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "selected layer bar")) return 1; if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Layerbar_block[1], Menu_bars[MENUBAR_LAYERS].Skin_width, Menu_bars[MENUBAR_LAYERS].Height,"selected layer bar",0)) return 1; cursor_y+= Menu_bars[MENUBAR_LAYERS].Height; // Status bar (selected) if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "selected status bar")) return 1; if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Statusbar_block[1], Menu_bars[MENUBAR_STATUS].Skin_width, Menu_bars[MENUBAR_STATUS].Height,"selected status bar",0)) return 1; cursor_y+= Menu_bars[MENUBAR_STATUS].Height; // Effects for (i=0; iEffect_sprite[i], EFFECT_SPRITE_WIDTH, EFFECT_SPRITE_HEIGHT, "effect sprite",0)) return 1; cursor_x+=EFFECT_SPRITE_WIDTH; } cursor_y+=EFFECT_SPRITE_HEIGHT; // Layer sprite for (j=0; j<3; j++) { for (i=0; i<16; i++) { if (i==0) { if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "layer sprite")) return 1; } else { if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "layer sprite")) return 1; } if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Layer_sprite[j][i], LAYER_SPRITE_WIDTH, LAYER_SPRITE_HEIGHT, "layer sprite",1)) return 1; cursor_x+=LAYER_SPRITE_WIDTH; } cursor_y+=LAYER_SPRITE_HEIGHT; } // Mouse cursors for (i=0; iMenu_sprite[0][i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "menu sprite",1)) return 1; cursor_x+=MENU_SPRITE_WIDTH; } cursor_y+=MENU_SPRITE_HEIGHT; // Menu sprites (selected) for (i=0; iMenu_sprite[1][i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "selected menu sprite",1)) return 1; cursor_x+=MENU_SPRITE_WIDTH; } cursor_y+=MENU_SPRITE_HEIGHT; // Drive sprites for (i=0; iIcon_sprite[i], ICON_SPRITE_WIDTH, ICON_SPRITE_HEIGHT, "sprite drive",1)) return 1; cursor_x+=ICON_SPRITE_WIDTH; } cursor_y+=ICON_SPRITE_HEIGHT; // Logo splash screen if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "logo menu")) return 1; if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Logo_grafx2, 231, 56, "logo menu",3)) return 1; cursor_y+=56; // Trames for (i=0; iSieve_pattern[i],"sieve pattern")) return 1; cursor_x+=16; } cursor_y+=16; // Help font: Normal for (i=0; i<256; i++) { // Each line holds 32 symbols if ((i%32)==0) { if (i!=0) cursor_y+=8; if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "help font (norm)")) return 1; } else { if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "help font (norm)")) return 1; } if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, &(gfx->Help_font_norm[i][0][0]), 6, 8, "help font (norm)",0)) return 1; cursor_x+=6; } cursor_y+=8; // Help font: Bold for (i=0; i<256; i++) { // Each line holds 32 symbols if ((i%32)==0) { if (i!=0) cursor_y+=8; if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "help font (bold)")) return 1; } else { if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "help font (bold)")) return 1; } if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, &(gfx->Bold_font[i][0][0]), 6, 8, "help font (bold)",0)) return 1; cursor_x+=6; } cursor_y+=8; // Help font: Title for (i=0; i<256; i++) { byte * dest; // Each line holds 64 symbols if ((i%64)==0) { if (i!=0) cursor_y+=8; if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "help font (title)")) return 1; } else { if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "help font (title)")) return 1; } if (i&1) if (i&64) dest=&(gfx->Help_font_t4[char_4++][0][0]); else dest=&(gfx->Help_font_t2[char_2++][0][0]); else if (i&64) dest=&(gfx->Help_font_t3[char_3++][0][0]); else dest=&(gfx->Help_font_t1[char_1++][0][0]); if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, dest, 6, 8, "help font (title)",0)) return 1; cursor_x+=6; } cursor_y+=8; // Copy unselected bitmaps to current ones memcpy(gfx->Menu_block[2], gfx->Menu_block[0], Menu_bars[MENUBAR_TOOLS].Skin_width*Menu_bars[MENUBAR_TOOLS].Height); memcpy(gfx->Layerbar_block[2], gfx->Layerbar_block[0], Menu_bars[MENUBAR_LAYERS].Skin_width*Menu_bars[MENUBAR_LAYERS].Height); memcpy(gfx->Statusbar_block[2], gfx->Statusbar_block[0], Menu_bars[MENUBAR_STATUS].Skin_width*Menu_bars[MENUBAR_STATUS].Height); return 0; } T_Gui_skin * Load_graphics(const char * skin_file, T_Gradient_array *gradients) { T_Gui_skin * gfx; char filename[MAX_PATH_CHARACTERS]; SDL_Surface * gui; gfx = (T_Gui_skin *)malloc(sizeof(T_Gui_skin)); if (gfx == NULL) { sprintf(Gui_loading_error_message, "Not enough memory to read skin file\n"); return NULL; } // Read the "skin" file strcpy(filename,Data_directory); strcat(filename,SKINS_SUBDIRECTORY PATH_SEPARATOR); strcat(filename,skin_file); gui=Load_surface(filename, gradients); if (!gui) { sprintf(Gui_loading_error_message, "Unable to load the skin image (missing? not an image file?)\n"); free(gfx); gfx = NULL; return NULL; } if (Parse_skin(gui, gfx)) { SDL_FreeSurface(gui); free(gfx); gfx = NULL; return NULL; } SDL_FreeSurface(gui); return gfx; } // ---- font loading ----- byte Parse_font(SDL_Surface * image, byte * font) { int character; byte color; int x, y; int chars_per_line; // Check image size if (image->w % 8) { sprintf(Gui_loading_error_message, "Error in font file: Image width is not a multiple of 8.\n"); return 1; } if (image->w * image->h < 8*8*256) { sprintf(Gui_loading_error_message, "Error in font file: Image is too small to be a 256-character 8x8 font.\n"); return 1; } chars_per_line = image->w/8; for (character=0; character < 256; character++) { for (y=0; y<8; y++) { for (x=0;x<8; x++) { // Pick pixel color = Get_SDL_pixel_8(image, (character % chars_per_line)*8+x, (character / chars_per_line)*8+y); if (color > 1) { sprintf(Gui_loading_error_message, "Error in font file: Only colors 0 and 1 can be used for the font.\n"); return 1; } // Put it in font. 0 = BG, 1 = FG. font[character*64 + y*8 + x]=color; } } } return 0; } byte * Load_font(const char * font_name) { byte * font; char filename[MAX_PATH_CHARACTERS]; SDL_Surface * image; font = (byte *)malloc(8*8*256); if (font == NULL) { sprintf(Gui_loading_error_message, "Not enough memory to read font file\n"); return NULL; } // Read the file containing the image sprintf(filename,"%s" SKINS_SUBDIRECTORY "%s%s", Data_directory, PATH_SEPARATOR, font_name); image=Load_surface(filename, NULL); if (!image) { sprintf(Gui_loading_error_message, "Unable to load the skin image (missing? not an image file?)\n"); free(font); return NULL; } if (Parse_font(image, font)) { SDL_FreeSurface(image); free(font); return NULL; } SDL_FreeSurface(image); return font; } // Initialisation des boutons: // Action factice: void Do_nothing(void) {} // Initialiseur d'un bouton: void Init_button(byte btn_number, word x_offset , word y_offset, word width , word height, byte shape, Func_action left_action, Func_action right_action, byte left_instant, byte right_instant, Func_action unselect_action, byte family) { Buttons_Pool[btn_number].X_offset =x_offset; Buttons_Pool[btn_number].Y_offset =y_offset; Buttons_Pool[btn_number].Width =width-1; Buttons_Pool[btn_number].Height =height-1; Buttons_Pool[btn_number].Pressed =0; Buttons_Pool[btn_number].Icon =-1; Buttons_Pool[btn_number].Shape =shape; Buttons_Pool[btn_number].Left_action =left_action; Buttons_Pool[btn_number].Right_action =right_action; Buttons_Pool[btn_number].Left_instant =left_instant; Buttons_Pool[btn_number].Right_instant =right_instant; Buttons_Pool[btn_number].Unselect_action =unselect_action; Buttons_Pool[btn_number].Family =family; } // Initiliseur de tous les boutons: void Init_buttons(void) { byte button_index; for (button_index=0;button_index= MAX_VIDEO_MODES-1) { DEBUG("Error! Attempt to create too many videomodes. Maximum is:", MAX_VIDEO_MODES); return; } if (!fullscreen) supported = 128; // Prefere, non modifiable else if (SDL_VideoModeOK(width, height, 8, SDL_FULLSCREEN)) supported = 1; // supported else { // Non supporte : on ne le prend pas return; } Video_mode[Nb_video_modes].Width = width; Video_mode[Nb_video_modes].Height = height; Video_mode[Nb_video_modes].Mode = mode; Video_mode[Nb_video_modes].Fullscreen = fullscreen; Video_mode[Nb_video_modes].State = supported; Nb_video_modes ++; } // Utilis pour trier les modes retourns par SDL int Compare_video_modes(const void *p1, const void *p2) { const T_Video_mode *mode1 = (const T_Video_mode *)p1; const T_Video_mode *mode2 = (const T_Video_mode *)p2; // Tris par largeur if(mode1->Width - mode2->Width) return mode1->Width - mode2->Width; // Tri par hauteur return mode1->Height - mode2->Height; } // Initializes the list of available video modes void Set_all_video_modes(void) { SDL_Rect** Modes; Nb_video_modes=0; // The first mode will have index number 0. // It will be the default mode if an unsupported one // is requested in gfx2.ini #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) // Native GP2X resolution Set_video_mode( 320,240,0, 1); #else // Window mode, with default size of 640x480 Set_video_mode( 640,480,0, 0); #endif Set_video_mode( 320,200,0, 1); Set_video_mode( 320,224,0, 1); #if !defined(__GP2X__) && !defined(__WIZ__) && !defined(__CAANOO__) // For the GP2X, this one is already declared above. Set_video_mode( 320,240,0, 1); #endif Set_video_mode( 320,256,0, 1); Set_video_mode( 320,270,0, 1); Set_video_mode( 320,282,0, 1); Set_video_mode( 320,300,0, 1); Set_video_mode( 320,360,0, 1); Set_video_mode( 320,400,0, 1); Set_video_mode( 320,448,0, 1); Set_video_mode( 320,480,0, 1); Set_video_mode( 320,512,0, 1); Set_video_mode( 320,540,0, 1); Set_video_mode( 320,564,0, 1); Set_video_mode( 320,600,0, 1); Set_video_mode( 360,200,0, 1); Set_video_mode( 360,224,0, 1); Set_video_mode( 360,240,0, 1); Set_video_mode( 360,256,0, 1); Set_video_mode( 360,270,0, 1); Set_video_mode( 360,282,0, 1); Set_video_mode( 360,300,0, 1); Set_video_mode( 360,360,0, 1); Set_video_mode( 360,400,0, 1); Set_video_mode( 360,448,0, 1); Set_video_mode( 360,480,0, 1); Set_video_mode( 360,512,0, 1); Set_video_mode( 360,540,0, 1); Set_video_mode( 360,564,0, 1); Set_video_mode( 360,600,0, 1); Set_video_mode( 400,200,0, 1); Set_video_mode( 400,224,0, 1); Set_video_mode( 400,240,0, 1); Set_video_mode( 400,256,0, 1); Set_video_mode( 400,270,0, 1); Set_video_mode( 400,282,0, 1); Set_video_mode( 400,300,0, 1); Set_video_mode( 400,360,0, 1); Set_video_mode( 400,400,0, 1); Set_video_mode( 400,448,0, 1); Set_video_mode( 400,480,0, 1); Set_video_mode( 400,512,0, 1); Set_video_mode( 400,540,0, 1); Set_video_mode( 400,564,0, 1); Set_video_mode( 400,600,0, 1); Set_video_mode( 640,224,0, 1); Set_video_mode( 640,240,0, 1); Set_video_mode( 640,256,0, 1); Set_video_mode( 640,270,0, 1); Set_video_mode( 640,300,0, 1); Set_video_mode( 640,350,0, 1); Set_video_mode( 640,400,0, 1); Set_video_mode( 640,448,0, 1); Set_video_mode( 640,480,0, 1); Set_video_mode( 640,512,0, 1); Set_video_mode( 640,540,0, 1); Set_video_mode( 640,564,0, 1); Set_video_mode( 640,600,0, 1); Set_video_mode( 800,600,0, 1); Set_video_mode(1024,768,0, 1); Modes = SDL_ListModes(NULL, SDL_FULLSCREEN); if ((Modes != (SDL_Rect**)0) && (Modes!=(SDL_Rect**)-1)) { int index; for (index=0; Modes[index]; index++) { int index2; #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) // On the GP2X the first mode is not windowed, so include it in the search. index2=0; #else index2=1; #endif for (/**/; index2 < Nb_video_modes; index2++) if (Modes[index]->w == Video_mode[index2].Width && Modes[index]->h == Video_mode[index2].Height) { // Was already in the hard-coded list: ok, don't add. break; } if (index2 >= Nb_video_modes && Modes[index]->w>=320 && Modes[index]->h>=200) { // New mode to add to the list Set_video_mode(Modes[index]->w,Modes[index]->h,0, 1); } } // Sort the modes : those found by SDL were listed at the end. // Note that we voluntarily omit the first entry: the default mode. qsort(&Video_mode[1], Nb_video_modes - 1, sizeof(T_Video_mode), Compare_video_modes); } } //--------------------------------------------------------------------------- int Load_CFG(int reload_all) { FILE* Handle; char filename[MAX_PATH_CHARACTERS]; long file_size; int index,index2; T_Config_header cfg_header; T_Config_chunk Chunk; T_Config_shortcut_info cfg_shortcut_info; T_Config_video_mode cfg_video_mode; int key_conversion = 0; strcpy(filename,Config_directory); strcat(filename,"gfx2.cfg"); file_size=File_length(filename); if ((Handle=fopen(filename,"rb"))==NULL) return ERROR_CFG_MISSING; if ( (file_size<7) || (!Read_bytes(Handle, &cfg_header.Signature, 3)) || memcmp(cfg_header.Signature,"CFG",3) || (!Read_byte(Handle, &cfg_header.Version1)) || (!Read_byte(Handle, &cfg_header.Version2)) || (!Read_byte(Handle, &cfg_header.Beta1)) || (!Read_byte(Handle, &cfg_header.Beta2)) ) goto Erreur_lecture_config; // Version DOS de Robinson et X-Man if ( (cfg_header.Version1== 2) && (cfg_header.Version2== 0) && (cfg_header.Beta1== 96)) { // Les touches (scancodes) sont convertir) key_conversion = 1; } // Version SDL jusqu'a 98% else if ( (cfg_header.Version1== 2) && (cfg_header.Version2== 0) && (cfg_header.Beta1== 97)) { // Les touches 00FF (pas de touche) sont a comprendre comme 0x0000 key_conversion = 2; } // Version SDL else if ( (cfg_header.Version1!=VERSION1) || (cfg_header.Version2!=VERSION2) || (cfg_header.Beta1!=BETA1) || (cfg_header.Beta2!=BETA2) ) goto Erreur_config_ancienne; // - Lecture des infos contenues dans le fichier de config - while (Read_byte(Handle, &Chunk.Number)) { Read_word_le(Handle, &Chunk.Size); switch (Chunk.Number) { case CHUNK_KEYS: // Touches if (reload_all) { for (index=0; index<(long)(Chunk.Size/6); index++) { if (!Read_word_le(Handle, &cfg_shortcut_info.Number) || !Read_word_le(Handle, &cfg_shortcut_info.Key) || !Read_word_le(Handle, &cfg_shortcut_info.Key2) ) goto Erreur_lecture_config; else { if (key_conversion==1) { cfg_shortcut_info.Key = Key_for_scancode(cfg_shortcut_info.Key); } else if (key_conversion==2) { if (cfg_shortcut_info.Key == 0x00FF) cfg_shortcut_info.Key = 0x0000; if (cfg_shortcut_info.Key2 == 0x00FF) cfg_shortcut_info.Key2 = 0x0000; } for (index2=0; ((index2>8) { case 0 : Config_Key[Ordering[index2]&0xFF][0]=cfg_shortcut_info.Key; Config_Key[Ordering[index2]&0xFF][1]=cfg_shortcut_info.Key2; break; case 1 : Buttons_Pool[Ordering[index2]&0xFF].Left_shortcut[0] = cfg_shortcut_info.Key; Buttons_Pool[Ordering[index2]&0xFF].Left_shortcut[1] = cfg_shortcut_info.Key2; break; case 2 : Buttons_Pool[Ordering[index2]&0xFF].Right_shortcut[0] = cfg_shortcut_info.Key; Buttons_Pool[Ordering[index2]&0xFF].Right_shortcut[1] = cfg_shortcut_info.Key2; break; } } else goto Erreur_lecture_config; } } } else { if (fseek(Handle,Chunk.Size,SEEK_CUR)==-1) goto Erreur_lecture_config; } break; case CHUNK_VIDEO_MODES: // Modes vido for (index=0; index<(long)(Chunk.Size/5); index++) { if (!Read_byte(Handle, &cfg_video_mode.State) || !Read_word_le(Handle, &cfg_video_mode.Width) || !Read_word_le(Handle, &cfg_video_mode.Height) ) goto Erreur_lecture_config; #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) index2=0; #else index2=1; #endif for (/**/; index2> (i&7))) != 0); } } } else { if (fseek(Handle,Chunk.Size,SEEK_CUR)==-1) goto Erreur_lecture_config; } break; case CHUNK_SCRIPTS: if (reload_all) { int current_size=0; int current_script=0; while(current_size=10) break; } } break; default: // Chunk inconnu goto Erreur_lecture_config; } } if (fclose(Handle)) return ERROR_CFG_CORRUPTED; return 0; Erreur_lecture_config: fclose(Handle); return ERROR_CFG_CORRUPTED; Erreur_config_ancienne: fclose(Handle); return ERROR_CFG_OLD; } int Save_CFG(void) { FILE* Handle; int index; int index2; int modes_to_save; char filename[MAX_PATH_CHARACTERS]; T_Config_header cfg_header; T_Config_chunk Chunk; T_Config_shortcut_info cfg_shortcut_info={0,0,0}; T_Config_video_mode cfg_video_mode={0,0,0}; strcpy(filename,Config_directory); strcat(filename,CONFIG_FILENAME); if ((Handle=fopen(filename,"wb"))==NULL) return ERROR_SAVING_CFG; // Ecriture du header memcpy(cfg_header.Signature,"CFG",3); cfg_header.Version1=VERSION1; cfg_header.Version2=VERSION2; cfg_header.Beta1 =BETA1; cfg_header.Beta2 =BETA2; if (!Write_bytes(Handle, &cfg_header.Signature,3) || !Write_byte(Handle, cfg_header.Version1) || !Write_byte(Handle, cfg_header.Version2) || !Write_byte(Handle, cfg_header.Beta1) || !Write_byte(Handle, cfg_header.Beta2) ) goto Erreur_sauvegarde_config; // Enregistrement des touches Chunk.Number=CHUNK_KEYS; Chunk.Size=NB_SHORTCUTS*6; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; for (index=0; index>8) { case 0 : cfg_shortcut_info.Key =Config_Key[Ordering[index]&0xFF][0]; cfg_shortcut_info.Key2=Config_Key[Ordering[index]&0xFF][1]; break; case 1 : cfg_shortcut_info.Key =Buttons_Pool[Ordering[index]&0xFF].Left_shortcut[0]; cfg_shortcut_info.Key2=Buttons_Pool[Ordering[index]&0xFF].Left_shortcut[1]; break; case 2 : cfg_shortcut_info.Key =Buttons_Pool[Ordering[index]&0xFF].Right_shortcut[0]; cfg_shortcut_info.Key2=Buttons_Pool[Ordering[index]&0xFF].Right_shortcut[1]; break; } if (!Write_word_le(Handle, cfg_shortcut_info.Number) || !Write_word_le(Handle, cfg_shortcut_info.Key) || !Write_word_le(Handle, cfg_shortcut_info.Key2) ) goto Erreur_sauvegarde_config; } // D'abord compter les modes pour lesquels l'utilisateur a mis une prfrence modes_to_save=0; #if defined(__GP2X__) || defined (__WIZ__) || defined (__CAANOO__) index = 0; #else index = 1; #endif for (/**/; index> (i&7); if ((i&7) == 7) { // Write one byte if (!Write_byte(Handle, current_byte)) goto Erreur_sauvegarde_config; current_byte=0; } } // Remainder if ((i&7) != 0) { // Write one byte if (!Write_byte(Handle, current_byte)) goto Erreur_sauvegarde_config; } } } // Save script shortcuts { int i; Chunk.Number=CHUNK_SCRIPTS; // Compute size : Data stored as 10 pascal strings Chunk.Size=0; for (i=0; i<10; i++) { if (Bound_script[i]==NULL) Chunk.Size+=1; else Chunk.Size+=strlen(Bound_script[i])+1; } // Header if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; // Strings for (i=0; i<10; i++) { byte size=0; if (Bound_script[i]!=NULL) size=strlen(Bound_script[i]); if (!Write_byte(Handle, size)) goto Erreur_sauvegarde_config; if (size) if (!Write_bytes(Handle, Bound_script[i], size)) goto Erreur_sauvegarde_config; } } if (fclose(Handle)) return ERROR_SAVING_CFG; return 0; Erreur_sauvegarde_config: fclose(Handle); return ERROR_SAVING_CFG; } // (R)assigne toutes les valeurs de configuration par dfaut void Set_config_defaults(void) { int index, index2; // Keyboard shortcuts for (index=0; index>8) { case 0 : Config_Key[Ordering[index]&0xFF][0]=ConfigKey[index].Key; Config_Key[Ordering[index]&0xFF][1]=ConfigKey[index].Key2; break; case 1 : Buttons_Pool[Ordering[index]&0xFF].Left_shortcut[0] = ConfigKey[index].Key; Buttons_Pool[Ordering[index]&0xFF].Left_shortcut[1] = ConfigKey[index].Key2; break; case 2 : Buttons_Pool[Ordering[index]&0xFF].Right_shortcut[0] = ConfigKey[index].Key; Buttons_Pool[Ordering[index]&0xFF].Right_shortcut[1] = ConfigKey[index].Key2; break; } } // Shade Shade_current=0; for (index=0; index<8; index++) { Shade_list[index].Step=1; Shade_list[index].Mode=0; for (index2=0; index2<512; index2++) Shade_list[index].List[index2]=256; } // Shade par dfaut pour la palette standard for (index=0; index<7; index++) for (index2=0; index2<16; index2++) Shade_list[0].List[index*17+index2]=index*16+index2+16; Shade_list_to_lookup_tables(Shade_list[Shade_current].List, Shade_list[Shade_current].Step, Shade_list[Shade_current].Mode, Shade_table_left,Shade_table_right); // Mask for (index=0; index<256; index++) Mask_table[index]=0; // Stencil for (index=0; index<256; index++) Stencil[index]=1; // Smooth Smooth_matrix[0][0]=1; Smooth_matrix[0][1]=2; Smooth_matrix[0][2]=1; Smooth_matrix[1][0]=2; Smooth_matrix[1][1]=4; Smooth_matrix[1][2]=2; Smooth_matrix[2][0]=1; Smooth_matrix[2][1]=2; Smooth_matrix[2][2]=1; // Exclude colors for (index=0; index<256; index++) Exclude_color[index]=0; // Quick shade Quick_shade_step=1; Quick_shade_loop=0; // Grid Snap_width=Snap_height=8; Snap_offset_X=Snap_offset_Y=0; } #ifdef GRAFX2_CATCHES_SIGNALS #if defined(__WIN32__) #define SIGHANDLER_T __p_sig_fn_t #elif defined(__macosx__) typedef void (*sig_t) (int); #define SIGHANDLER_T sig_t #else #define SIGHANDLER_T __sighandler_t #endif // Memorize the signal handlers of SDL SIGHANDLER_T Handler_TERM=SIG_DFL; SIGHANDLER_T Handler_INT=SIG_DFL; SIGHANDLER_T Handler_ABRT=SIG_DFL; SIGHANDLER_T Handler_SEGV=SIG_DFL; SIGHANDLER_T Handler_FPE=SIG_DFL; void Sig_handler(int sig) { // Restore default behaviour signal(SIGTERM, Handler_TERM); signal(SIGINT, Handler_INT); signal(SIGABRT, Handler_ABRT); signal(SIGSEGV, Handler_SEGV); signal(SIGFPE, Handler_FPE); switch(sig) { case SIGTERM: case SIGINT: case SIGABRT: case SIGSEGV: Image_emergency_backup(); default: break; } } #endif void Init_sighandler(void) { #ifdef GRAFX2_CATCHES_SIGNALS Handler_TERM=signal(SIGTERM,Sig_handler); Handler_INT =signal(SIGINT,Sig_handler); Handler_ABRT=signal(SIGABRT,Sig_handler); Handler_SEGV=signal(SIGSEGV,Sig_handler); Handler_FPE =signal(SIGFPE,Sig_handler); #endif } void Init_brush_container(void) { int i; for (i=0; iDefault_palette[gfx->Color[0]]; //Config.Fav_menu_colors[1] = gfx->Default_palette[gfx->Color[1]]; //Config.Fav_menu_colors[2] = gfx->Default_palette[gfx->Color[2]]; //Config.Fav_menu_colors[3] = gfx->Default_palette[gfx->Color[3]]; // Reassign GUI color indices MC_Black = gfx->Color[0]; MC_Dark = gfx->Color[1]; MC_Light = gfx->Color[2]; MC_White = gfx->Color[3]; MC_Trans = gfx->Color_trans; MC_OnBlack=MC_Dark; MC_Window=MC_Light; MC_Lighter=MC_White; MC_Darker=MC_Dark; // Set menubars to point to the new data for (i=0; i<3; i++) { Menu_bars[MENUBAR_TOOLS ].Skin[i] = (byte*)&(gfx->Menu_block[i]); Menu_bars[MENUBAR_LAYERS].Skin[i] = (byte*)&(gfx->Layerbar_block[i]); Menu_bars[MENUBAR_STATUS].Skin[i] = (byte*)&(gfx->Statusbar_block[i]); } } /// /// Based on which toolbars are visible, updates their offsets and /// computes ::Menu_height and ::Menu_Y void Compute_menu_offsets(void) { int i; int offset; // Recompute all offsets offset=0; Menu_height=0; for (i = MENUBAR_COUNT-1; i >=0; i--) { Menu_bars[i].Top = offset; if(Menu_bars[i].Visible) { offset += Menu_bars[i].Height; Menu_height += Menu_bars[i].Height; } } // Update global menu coordinates Menu_Y = Screen_height - Menu_height * Menu_factor_Y; } void Init_paintbrush(int index, int width, int height, byte shape, const char * bitmap) { if (bitmap!=NULL) { int i; Paintbrush[index].Shape=shape; Paintbrush[index].Width=width; Paintbrush[index].Height=height; Paintbrush[index].Offset_X=width>>1; Paintbrush[index].Offset_Y=height>>1; // Decode pixels for (i=0;i> (i&7))) != 0); } } else { Paintbrush_shape=shape; Set_paintbrush_size(width, height); Store_paintbrush(index); } } void Init_paintbrushes(void) { int index; Init_paintbrush( 0, 1, 1,PAINTBRUSH_SHAPE_SQUARE, NULL); Init_paintbrush( 1, 2, 2,PAINTBRUSH_SHAPE_SQUARE, NULL); Init_paintbrush( 2, 3, 3,PAINTBRUSH_SHAPE_SQUARE, NULL); Init_paintbrush( 3, 4, 4,PAINTBRUSH_SHAPE_SQUARE, NULL); Init_paintbrush( 4, 5, 5,PAINTBRUSH_SHAPE_SQUARE, NULL); Init_paintbrush( 5, 7, 7,PAINTBRUSH_SHAPE_SQUARE, NULL); Init_paintbrush( 6, 8, 8,PAINTBRUSH_SHAPE_SQUARE, NULL); Init_paintbrush( 7,12,12,PAINTBRUSH_SHAPE_SQUARE, NULL); Init_paintbrush( 8,16,16,PAINTBRUSH_SHAPE_SQUARE, NULL); Init_paintbrush( 9,16,16,PAINTBRUSH_SHAPE_SIEVE_SQUARE, NULL); Init_paintbrush(10,15,15,PAINTBRUSH_SHAPE_DIAMOND, NULL); Init_paintbrush(11, 5, 5,PAINTBRUSH_SHAPE_DIAMOND, NULL); Init_paintbrush(12, 3, 3,PAINTBRUSH_SHAPE_ROUND, NULL); Init_paintbrush(13, 4, 4,PAINTBRUSH_SHAPE_ROUND, NULL); Init_paintbrush(14, 5, 5,PAINTBRUSH_SHAPE_ROUND, NULL); Init_paintbrush(15, 6, 6,PAINTBRUSH_SHAPE_ROUND, NULL); Init_paintbrush(16, 8, 8,PAINTBRUSH_SHAPE_ROUND, NULL); Init_paintbrush(17,10,10,PAINTBRUSH_SHAPE_ROUND, NULL); Init_paintbrush(18,12,12,PAINTBRUSH_SHAPE_ROUND, NULL); Init_paintbrush(19,14,14,PAINTBRUSH_SHAPE_ROUND, NULL); Init_paintbrush(20,16,16,PAINTBRUSH_SHAPE_ROUND, NULL); Init_paintbrush(21,15,15,PAINTBRUSH_SHAPE_SIEVE_ROUND, NULL); Init_paintbrush(22,11,11,PAINTBRUSH_SHAPE_SIEVE_ROUND, NULL); Init_paintbrush(23, 5, 5,PAINTBRUSH_SHAPE_SIEVE_ROUND, NULL); Init_paintbrush(24, 2, 1,PAINTBRUSH_SHAPE_HORIZONTAL_BAR, NULL); Init_paintbrush(25, 3, 1,PAINTBRUSH_SHAPE_HORIZONTAL_BAR, NULL); Init_paintbrush(26, 4, 1,PAINTBRUSH_SHAPE_HORIZONTAL_BAR, NULL); Init_paintbrush(27, 8, 1,PAINTBRUSH_SHAPE_HORIZONTAL_BAR, NULL); Init_paintbrush(28, 1, 2,PAINTBRUSH_SHAPE_VERTICAL_BAR, NULL); Init_paintbrush(29, 1, 3,PAINTBRUSH_SHAPE_VERTICAL_BAR, NULL); Init_paintbrush(30, 1, 4,PAINTBRUSH_SHAPE_VERTICAL_BAR, NULL); Init_paintbrush(31, 1, 8,PAINTBRUSH_SHAPE_VERTICAL_BAR, NULL); Init_paintbrush(32, 3, 3,PAINTBRUSH_SHAPE_CROSS, NULL); Init_paintbrush(33, 5, 5,PAINTBRUSH_SHAPE_CROSS, NULL); Init_paintbrush(34, 5, 5,PAINTBRUSH_SHAPE_PLUS, NULL); Init_paintbrush(35,15,15,PAINTBRUSH_SHAPE_PLUS, NULL); Init_paintbrush(36, 2, 2,PAINTBRUSH_SHAPE_SLASH, NULL); Init_paintbrush(37, 4, 4,PAINTBRUSH_SHAPE_SLASH, NULL); Init_paintbrush(38, 8, 8,PAINTBRUSH_SHAPE_SLASH, NULL); Init_paintbrush(39, 2, 2,PAINTBRUSH_SHAPE_ANTISLASH, NULL); Init_paintbrush(40, 4, 4,PAINTBRUSH_SHAPE_ANTISLASH, NULL); Init_paintbrush(41, 8, 8,PAINTBRUSH_SHAPE_ANTISLASH, NULL); Init_paintbrush(42, 4, 4,PAINTBRUSH_SHAPE_RANDOM, "\x20\x81"); Init_paintbrush(43, 8, 8,PAINTBRUSH_SHAPE_RANDOM, "\x44\x00\x11\x00\x88\x01\x40\x08"); Init_paintbrush(44,13,13,PAINTBRUSH_SHAPE_RANDOM, "\x08\x00\x08\x90\x00\x10\x42\x10\x02\x06\x02\x02\x04\x02\x08\x42\x10\x44\x00\x00\x44\x00"); Init_paintbrush(45, 3, 3,PAINTBRUSH_SHAPE_MISC, "\x7f\x00"); Init_paintbrush(46, 3, 3,PAINTBRUSH_SHAPE_MISC, "\xdd\x80"); Init_paintbrush(47, 7, 7,PAINTBRUSH_SHAPE_MISC, "\x06\x30\x82\x04\x10\x20\x00"); for (index=0;index>1); Paintbrush[index].Offset_Y=(Paintbrush[index].Height>>1); } } /// Set application icon(s) void Define_icon(void) { #ifdef WIN32 // Specific code for Win32: // Load icon from embedded resource. // This will provide both the 16x16 and 32x32 versions. do { HICON hicon; HRSRC hresource; HINSTANCE hInstance; LPVOID lpResIconDir; LPVOID lpResIcon16; LPVOID lpResIcon32; HGLOBAL hMem; WORD nID; SDL_SysWMinfo info; hInstance = (HINSTANCE)GetModuleHandle(NULL); if (hInstance==NULL) break; // Icon is resource #1 hresource = FindResource(hInstance, MAKEINTRESOURCE(1), RT_GROUP_ICON); if (hresource==NULL) break; // Load and lock the icon directory. hMem = LoadResource(hInstance, hresource); if (hMem==NULL) break; lpResIconDir = LockResource(hMem); if (lpResIconDir==NULL) break; SDL_VERSION(&info.version); SDL_GetWMInfo(&info); // // 16x16 // // Get the identifier of the 16x16 icon nID = LookupIconIdFromDirectoryEx((PBYTE) lpResIconDir, TRUE, 16, 16, LR_DEFAULTCOLOR); if (nID==0) break; // Find the bits for the nID icon. hresource = FindResource(hInstance, MAKEINTRESOURCE(nID), MAKEINTRESOURCE((long)RT_ICON)); if (hresource==NULL) break; // Load and lock the icon. hMem = LoadResource(hInstance, hresource); if (hMem==NULL) break; lpResIcon16 = LockResource(hMem); if (lpResIcon16==NULL) break; // Create a handle to the icon. hicon = CreateIconFromResourceEx((PBYTE) lpResIcon16, SizeofResource(hInstance, hresource), TRUE, 0x00030000, 16, 16, LR_DEFAULTCOLOR); if (hicon==NULL) break; // Set it SetClassLongPtr(info.window, GCL_HICONSM, (LONG_PTR)hicon); // // 32x32 // // Get the identifier of the 32x32 icon nID = LookupIconIdFromDirectoryEx((PBYTE) lpResIconDir, TRUE, 32, 32, LR_DEFAULTCOLOR); if (nID==0) break; // Find the bits for the nID icon. hresource = FindResource(hInstance, MAKEINTRESOURCE(nID), MAKEINTRESOURCE((long)RT_ICON)); if (hresource==NULL) break; // Load and lock the icon. hMem = LoadResource(hInstance, hresource); if (hMem==NULL) break; lpResIcon32 = LockResource(hMem); if (lpResIcon32==NULL) break; // Create a handle to the icon. hicon = CreateIconFromResourceEx((PBYTE) lpResIcon32, SizeofResource(hInstance, hresource), TRUE, 0x00030000, 32, 32, LR_DEFAULTCOLOR); if (hicon==NULL) break; // Set it SetClassLongPtr(info.window, GCL_HICON, (LONG_PTR)hicon); // Success return; } while (0); // Failure: fall back on normal SDL version: #endif // General version: Load icon from the file gfx2.gif { char icon_path[MAX_PATH_CHARACTERS]; SDL_Surface * icon; sprintf(icon_path, "%s%s", Data_directory, "gfx2.gif"); icon = IMG_Load(icon_path); if (icon && icon->w == 32 && icon->h == 32) { Uint32 pink; pink = SDL_MapRGB(icon->format, 255, 0, 255); if (icon->format->BitsPerPixel == 8) { // 8bit image: use color key SDL_SetColorKey(icon, SDL_SRCCOLORKEY, pink); SDL_WM_SetIcon(icon,NULL); } else { // 24bit image: need to build a mask on magic pink byte *icon_mask; int x,y; icon_mask=malloc(128); memset(icon_mask,0,128); for (y=0;y<32;y++) for (x=0;x<32;x++) if (Get_SDL_pixel_hicolor(icon, x, y) != pink) icon_mask[(y*32+x)/8] |=0x80>>(x&7); SDL_WM_SetIcon(icon,icon_mask); free(icon_mask); icon_mask = NULL; } SDL_FreeSurface(icon); } } }grafx2/src/input.c0000644000076400010400000007546711553130562014550 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2009 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 */ #include #include #ifdef __WIN32__ #include #include #endif #include "global.h" #include "keyboard.h" #include "sdlscreen.h" #include "windows.h" #include "errors.h" #include "misc.h" #include "buttons.h" #include "input.h" #include "loadsave.h" #ifdef __VBCC__ #define __attribute__(x) #endif void Handle_window_resize(SDL_ResizeEvent event); void Handle_window_exit(SDL_QuitEvent event); int Color_cycling(__attribute__((unused)) void* useless); // public Globals (available as extern) int Input_sticky_control = 0; int Snap_axis = 0; int Snap_axis_origin_X; int Snap_axis_origin_Y; char * Drop_file_name = NULL; // -- // Digital joystick state byte Directional_up; byte Directional_up_right; byte Directional_right; byte Directional_down_right; byte Directional_down; byte Directional_down_left; byte Directional_left; byte Directional_up_left; byte Directional_click; // Emulated directional controller. // This has a distinct state from Directional_, because some joysticks send // "I'm not moving" SDL events when idle, thus stopping the emulated one. byte Directional_emulated_up; byte Directional_emulated_right; byte Directional_emulated_down; byte Directional_emulated_left; long Directional_first_move; long Directional_last_move; int Mouse_moved; ///< Boolean, Set to true if any cursor movement occurs. word Input_new_mouse_X; word Input_new_mouse_Y; byte Input_new_mouse_K; byte Button_inverter=0; // State of the key that swaps mouse buttons. // Joystick/pad configurations for the various console ports. // See the #else for the documentation of fields. // TODO: Make these user-settable somehow. #if defined(__GP2X__) #define JOYSTICK_THRESHOLD (4096) short Joybutton_shift= JOY_BUTTON_L; short Joybutton_control= JOY_BUTTON_R; short Joybutton_alt= JOY_BUTTON_CLICK; short Joybutton_left_click= JOY_BUTTON_B; short Joybutton_right_click=JOY_BUTTON_Y; #elif defined(__WIZ__) #define JOYSTICK_THRESHOLD (4096) short Joybutton_shift= JOY_BUTTON_X; short Joybutton_control= JOY_BUTTON_SELECT; short Joybutton_alt= JOY_BUTTON_Y; short Joybutton_left_click= JOY_BUTTON_A; short Joybutton_right_click=JOY_BUTTON_B; #elif defined(__CAANOO__) #define JOYSTICK_THRESHOLD (4096) short Joybutton_shift= JOY_BUTTON_L; short Joybutton_control= JOY_BUTTON_R; short Joybutton_alt= JOY_BUTTON_Y; short Joybutton_left_click= JOY_BUTTON_A; short Joybutton_right_click=JOY_BUTTON_B; #else // Default : Any joystick on a computer platform /// /// This is the sensitivity threshold for the directional /// pad of a cheap digital joypad on the PC. It has been set through /// trial and error : If value is too large then the movement is /// randomly interrupted; if the value is too low the cursor will /// move by itself, controlled by parasits. /// YR 04/11/2010: I just observed a -8700 when joystick is idle. #define JOYSTICK_THRESHOLD (10000) /// A button that is marked as "modifier" will short Joybutton_shift=-1; ///< Button number that serves as a "shift" modifier; -1 for none short Joybutton_control=-1; ///< Button number that serves as a "ctrl" modifier; -1 for none short Joybutton_alt=-1; ///< Button number that serves as a "alt" modifier; -1 for none short Joybutton_left_click=0; ///< Button number that serves as left click; -1 for none short Joybutton_right_click=1; ///< Button number that serves as right-click; -1 for none #endif int Has_shortcut(word function) { if (function == 0xFFFF) return 0; if (function & 0x100) { if (Buttons_Pool[function&0xFF].Left_shortcut[0]!=KEY_NONE) return 1; if (Buttons_Pool[function&0xFF].Left_shortcut[1]!=KEY_NONE) return 1; return 0; } if (function & 0x200) { if (Buttons_Pool[function&0xFF].Right_shortcut[0]!=KEY_NONE) return 1; if (Buttons_Pool[function&0xFF].Right_shortcut[1]!=KEY_NONE) return 1; return 0; } if(Config_Key[function][0]!=KEY_NONE) return 1; if(Config_Key[function][1]!=KEY_NONE) return 1; return 0; } int Is_shortcut(word key, word function) { if (key == 0 || function == 0xFFFF) return 0; if (function & 0x100) { if (Buttons_Pool[function&0xFF].Left_shortcut[0]==key) return 1; if (Buttons_Pool[function&0xFF].Left_shortcut[1]==key) return 1; return 0; } if (function & 0x200) { if (Buttons_Pool[function&0xFF].Right_shortcut[0]==key) return 1; if (Buttons_Pool[function&0xFF].Right_shortcut[1]==key) return 1; return 0; } if(key == Config_Key[function][0]) return 1; if(key == Config_Key[function][1]) return 1; return 0; } // Called each time there is a cursor move, either triggered by mouse or keyboard shortcuts int Move_cursor_with_constraints() { int feedback=0; int mouse_blocked=0; ///< Boolean, Set to true if mouse movement was clipped. // 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; mouse_blocked=1; } if (Input_new_mouse_X>=Screen_width) { Input_new_mouse_X=Screen_width-1; mouse_blocked=1; } //Gestion "avance" 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) { //Si le curseur ne se trouve plus dans l'image if(Menu_Y<=Input_new_mouse_Y) { //On bloque le curseur en fin d'image mouse_blocked=1; Input_new_mouse_Y=Menu_Y-1; //La ligne !!au-dessus!! du menu } if(Main_magnifier_mode) { if(Operation_in_magnifier==0) { if(Input_new_mouse_X>=Main_separator_position) { mouse_blocked=1; Input_new_mouse_X=Main_separator_position-1; } } else { if(Input_new_mouse_X Config.Mouse_merge_movement && !Operation[Current_operation][Mouse_K_unique] [Operation_stack_size].Fast_mouse) feedback=1; } if (mouse_blocked) Set_mouse_position(); return feedback; } // WM events management void Handle_window_resize(SDL_ResizeEvent event) { Resize_width = event.w; Resize_height = event.h; } void Handle_window_exit(__attribute__((unused)) SDL_QuitEvent event) { Quit_is_required = 1; } // Mouse events management int Handle_mouse_move(SDL_MouseMotionEvent event) { Input_new_mouse_X = event.x/Pixel_width; Input_new_mouse_Y = event.y/Pixel_height; return Move_cursor_with_constraints(); } int Handle_mouse_click(SDL_MouseButtonEvent event) { switch(event.button) { case SDL_BUTTON_LEFT: if (Button_inverter) Input_new_mouse_K |= 2; else Input_new_mouse_K |= 1; break; break; case SDL_BUTTON_RIGHT: if (Button_inverter) Input_new_mouse_K |= 1; else Input_new_mouse_K |= 2; break; break; case SDL_BUTTON_MIDDLE: Key = KEY_MOUSEMIDDLE|Key_modifiers(SDL_GetModState()); // TODO: repeat system maybe? return 0; case SDL_BUTTON_WHEELUP: Key = KEY_MOUSEWHEELUP|Key_modifiers(SDL_GetModState()); return 0; case SDL_BUTTON_WHEELDOWN: Key = KEY_MOUSEWHEELDOWN|Key_modifiers(SDL_GetModState()); return 0; default: return 0; } return Move_cursor_with_constraints(); } int Handle_mouse_release(SDL_MouseButtonEvent event) { switch(event.button) { case SDL_BUTTON_LEFT: if (Button_inverter) Input_new_mouse_K &= ~2; else Input_new_mouse_K &= ~1; break; case SDL_BUTTON_RIGHT: if (Button_inverter) Input_new_mouse_K &= ~1; else Input_new_mouse_K &= ~2; break; } return Move_cursor_with_constraints(); } // Keyboard management int Handle_key_press(SDL_KeyboardEvent event) { //Appui sur une touche du clavier int modifier; Key = Keysym_to_keycode(event.keysym); Key_ANSI = Keysym_to_ANSI(event.keysym); switch(event.keysym.sym) { case SDLK_RSHIFT: case SDLK_LSHIFT: modifier=MOD_SHIFT; break; case SDLK_RCTRL: case SDLK_LCTRL: modifier=MOD_CTRL; break; case SDLK_RALT: case SDLK_LALT: case SDLK_MODE: modifier=MOD_ALT; break; case SDLK_RMETA: case SDLK_LMETA: modifier=MOD_META; break; default: modifier=0; } if (Config.Swap_buttons && modifier == Config.Swap_buttons && Button_inverter==0) { Button_inverter=1; if (Input_new_mouse_K) { Input_new_mouse_K ^= 3; // Flip bits 0 and 1 return Move_cursor_with_constraints(); } } if(Is_shortcut(Key,SPECIAL_MOUSE_UP)) { Directional_emulated_up=1; return 0; } else if(Is_shortcut(Key,SPECIAL_MOUSE_DOWN)) { Directional_emulated_down=1; return 0; } else if(Is_shortcut(Key,SPECIAL_MOUSE_LEFT)) { Directional_emulated_left=1; return 0; } else if(Is_shortcut(Key,SPECIAL_MOUSE_RIGHT)) { Directional_emulated_right=1; return 0; } else if(Is_shortcut(Key,SPECIAL_CLICK_LEFT) && Keyboard_click_allowed > 0) { Input_new_mouse_K=1; Directional_click=1; return Move_cursor_with_constraints(); } else if(Is_shortcut(Key,SPECIAL_CLICK_RIGHT) && Keyboard_click_allowed > 0) { Input_new_mouse_K=2; Directional_click=2; return Move_cursor_with_constraints(); } return 0; } int Release_control(int key_code, int modifier) { int need_feedback = 0; if (modifier == MOD_SHIFT) { // Disable "snap axis" mode Snap_axis = 0; need_feedback = 1; } if (Config.Swap_buttons && modifier == Config.Swap_buttons && Button_inverter==1) { Button_inverter=0; if (Input_new_mouse_K) { Input_new_mouse_K ^= 3; // Flip bits 0 and 1 return Move_cursor_with_constraints(); } } if((key_code && key_code == (Config_Key[SPECIAL_MOUSE_UP][0]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_UP][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_MOUSE_UP][1]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_UP][1]&modifier)) { Directional_emulated_up=0; } if((key_code && key_code == (Config_Key[SPECIAL_MOUSE_DOWN][0]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_DOWN][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_MOUSE_DOWN][1]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_DOWN][1]&modifier)) { Directional_emulated_down=0; } if((key_code && key_code == (Config_Key[SPECIAL_MOUSE_LEFT][0]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_LEFT][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_MOUSE_LEFT][1]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_LEFT][1]&modifier)) { Directional_emulated_left=0; } if((key_code && key_code == (Config_Key[SPECIAL_MOUSE_RIGHT][0]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_RIGHT][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_MOUSE_RIGHT][1]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_RIGHT][1]&modifier)) { Directional_emulated_right=0; } if((key_code && key_code == (Config_Key[SPECIAL_CLICK_LEFT][0]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_LEFT][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_CLICK_LEFT][1]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_LEFT][1]&modifier)) { if (Directional_click & 1) { Directional_click &= ~1; Input_new_mouse_K &= ~1; return Move_cursor_with_constraints() || need_feedback; } } if((key_code && key_code == (Config_Key[SPECIAL_CLICK_RIGHT][0]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_RIGHT][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_CLICK_RIGHT][1]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_RIGHT][1]&modifier)) { if (Directional_click & 2) { Directional_click &= ~2; Input_new_mouse_K &= ~2; return Move_cursor_with_constraints() || need_feedback; } } // Other keys don't need to be released : they are handled as "events" and procesed only once. // These clicks are apart because they need to be continuous (ie move while key pressed) // We are relying on "hardware" keyrepeat to achieve that. return need_feedback; } int Handle_key_release(SDL_KeyboardEvent event) { int modifier; int released_key = Keysym_to_keycode(event.keysym) & 0x0FFF; switch(event.keysym.sym) { case SDLK_RSHIFT: case SDLK_LSHIFT: modifier=MOD_SHIFT; break; case SDLK_RCTRL: case SDLK_LCTRL: modifier=MOD_CTRL; break; case SDLK_RALT: case SDLK_LALT: case SDLK_MODE: modifier=MOD_ALT; break; case SDLK_RMETA: case SDLK_LMETA: modifier=MOD_META; break; default: modifier=0; } return Release_control(released_key, modifier); } // Joystick management int Handle_joystick_press(SDL_JoyButtonEvent event) { if (event.button == Joybutton_shift) { SDL_SetModState(SDL_GetModState() | KMOD_SHIFT); return 0; } if (event.button == Joybutton_control) { SDL_SetModState(SDL_GetModState() | KMOD_CTRL); if (Config.Swap_buttons == MOD_CTRL && Button_inverter==0) { Button_inverter=1; if (Input_new_mouse_K) { Input_new_mouse_K ^= 3; // Flip bits 0 and 1 return Move_cursor_with_constraints(); } } return 0; } if (event.button == Joybutton_alt) { SDL_SetModState(SDL_GetModState() | (KMOD_ALT|KMOD_META)); if (Config.Swap_buttons == MOD_ALT && Button_inverter==0) { Button_inverter=1; if (Input_new_mouse_K) { Input_new_mouse_K ^= 3; // Flip bits 0 and 1 return Move_cursor_with_constraints(); } } return 0; } if (event.button == Joybutton_left_click) { Input_new_mouse_K = Button_inverter ? 2 : 1; return Move_cursor_with_constraints(); } if (event.button == Joybutton_right_click) { Input_new_mouse_K = Button_inverter ? 1 : 2; return Move_cursor_with_constraints(); } switch(event.button) { #ifdef JOY_BUTTON_UP case JOY_BUTTON_UP: Directional_up=1; break; #endif #ifdef JOY_BUTTON_UPRIGHT case JOY_BUTTON_UPRIGHT: Directional_up_right=1; break; #endif #ifdef JOY_BUTTON_RIGHT case JOY_BUTTON_RIGHT: Directional_right=1; break; #endif #ifdef JOY_BUTTON_DOWNRIGHT case JOY_BUTTON_DOWNRIGHT: Directional_down_right=1; break; #endif #ifdef JOY_BUTTON_DOWN case JOY_BUTTON_DOWN: Directional_down=1; break; #endif #ifdef JOY_BUTTON_DOWNLEFT case JOY_BUTTON_DOWNLEFT: Directional_down_left=1; break; #endif #ifdef JOY_BUTTON_LEFT case JOY_BUTTON_LEFT: Directional_left=1; break; #endif #ifdef JOY_BUTTON_UPLEFT case JOY_BUTTON_UPLEFT: Directional_up_left=1; break; #endif default: break; } Key = (KEY_JOYBUTTON+event.button)|Key_modifiers(SDL_GetModState()); // TODO: systeme de rptition return Move_cursor_with_constraints(); } int Handle_joystick_release(SDL_JoyButtonEvent event) { if (event.button == Joybutton_shift) { SDL_SetModState(SDL_GetModState() & ~KMOD_SHIFT); return Release_control(0,MOD_SHIFT); } if (event.button == Joybutton_control) { SDL_SetModState(SDL_GetModState() & ~KMOD_CTRL); return Release_control(0,MOD_CTRL); } if (event.button == Joybutton_alt) { SDL_SetModState(SDL_GetModState() & ~(KMOD_ALT|KMOD_META)); return Release_control(0,MOD_ALT); } if (event.button == Joybutton_left_click) { Input_new_mouse_K &= ~1; return Move_cursor_with_constraints(); } if (event.button == Joybutton_right_click) { Input_new_mouse_K &= ~2; return Move_cursor_with_constraints(); } switch(event.button) { #ifdef JOY_BUTTON_UP case JOY_BUTTON_UP: Directional_up=1; break; #endif #ifdef JOY_BUTTON_UPRIGHT case JOY_BUTTON_UPRIGHT: Directional_up_right=1; break; #endif #ifdef JOY_BUTTON_RIGHT case JOY_BUTTON_RIGHT: Directional_right=1; break; #endif #ifdef JOY_BUTTON_DOWNRIGHT case JOY_BUTTON_DOWNRIGHT: Directional_down_right=1; break; #endif #ifdef JOY_BUTTON_DOWN case JOY_BUTTON_DOWN: Directional_down=1; break; #endif #ifdef JOY_BUTTON_DOWNLEFT case JOY_BUTTON_DOWNLEFT: Directional_down_left=1; break; #endif #ifdef JOY_BUTTON_LEFT case JOY_BUTTON_LEFT: Directional_left=1; break; #endif #ifdef JOY_BUTTON_UPLEFT case JOY_BUTTON_UPLEFT: Directional_up_left=1; break; #endif default: break; } return Move_cursor_with_constraints(); } void Handle_joystick_movement(SDL_JoyAxisEvent event) { if (event.axis==JOYSTICK_AXIS_X) { Directional_right=Directional_left=0; if (event.value<-JOYSTICK_THRESHOLD) { Directional_left=1; } else if (event.value>JOYSTICK_THRESHOLD) Directional_right=1; } else if (event.axis==JOYSTICK_AXIS_Y) { Directional_up=Directional_down=0; if (event.value<-JOYSTICK_THRESHOLD) { Directional_up=1; } else if (event.value>JOYSTICK_THRESHOLD) Directional_down=1; } } // Attempts to move the mouse cursor by the given deltas (may be more than 1 pixel at a time) int Cursor_displace(short delta_x, short delta_y) { short x=Input_new_mouse_X; short y=Input_new_mouse_Y; if(Main_magnifier_mode && Input_new_mouse_Y < Menu_Y && Input_new_mouse_X > Main_separator_position) { // Cursor in zoomed area if (delta_x<0) Input_new_mouse_X = Max(Main_separator_position, x-Main_magnifier_factor); else if (delta_x>0) Input_new_mouse_X = Min(Screen_width-1, x+Main_magnifier_factor); if (delta_y<0) Input_new_mouse_Y = Max(0, y-Main_magnifier_factor); else if (delta_y>0) Input_new_mouse_Y = Min(Screen_height-1, y+Main_magnifier_factor); } else { if (delta_x<0) Input_new_mouse_X = Max(0, x+delta_x); else if (delta_x>0) Input_new_mouse_X = Min(Screen_width-1, x+delta_x); if (delta_y<0) Input_new_mouse_Y = Max(0, y+delta_y); else if (delta_y>0) Input_new_mouse_Y = Min(Screen_height-1, y+delta_y); } return Move_cursor_with_constraints(); } // This function is the acceleration profile for directional (digital) cursor // controllers. int Directional_acceleration(int msec) { const int initial_delay = 250; const int linear_factor = 200; const int accel_factor = 10000; // At beginning there is 1 pixel move, then nothing for N milliseconds if (msecmsg == WM_DROPFILES) { int file_count; HDROP hdrop = (HDROP)(event.syswm.msg->wParam); if((file_count = DragQueryFile(hdrop,(UINT)-1,(LPTSTR) NULL ,(UINT) 0)) > 0) { long len; // Query filename length len = DragQueryFile(hdrop,0 ,NULL ,0); if (len) { Drop_file_name=calloc(len+1,1); if (Drop_file_name) { if (DragQueryFile(hdrop,0 ,(LPTSTR) Drop_file_name ,(UINT) MAX_PATH)) { // Success } else { free(Drop_file_name); // Don't report name copy error } } else { // Don't report alloc error (for a file name? :/ ) } } else { // Don't report weird Windows error } } else { // Drop of zero files. Thanks for the information, Bill. } } #endif break; default: //DEBUG("Unhandled SDL event number : ",event.type); break; } } // Directional controller if (!(Directional_up||Directional_up_right||Directional_right|| Directional_down_right||Directional_down||Directional_down_left|| Directional_left||Directional_up_left||Directional_emulated_up|| Directional_emulated_right||Directional_emulated_down|| Directional_emulated_left)) { Directional_first_move=0; } else { long time_now; int step=0; time_now=SDL_GetTicks(); if (Directional_first_move==0) { Directional_first_move=time_now; step=1; } else { // Compute how much the cursor has moved since last call. // This tries to make smooth cursor movement // no matter the frequency of calls to Get_input() step = Directional_acceleration(time_now - Directional_first_move) - Directional_acceleration(Directional_last_move - Directional_first_move); // Clip speed at 3 pixel per visible frame. if (step > 3) step=3; } Directional_last_move = time_now; if (step) { // Directional controller UP if ((Directional_up||Directional_emulated_up||Directional_up_left||Directional_up_right) && !(Directional_down_right||Directional_down||Directional_emulated_down||Directional_down_left)) { Cursor_displace(0, -step); } // Directional controller RIGHT if ((Directional_up_right||Directional_right||Directional_emulated_right||Directional_down_right) && !(Directional_down_left||Directional_left||Directional_emulated_left||Directional_up_left)) { Cursor_displace(step,0); } // Directional controller DOWN if ((Directional_down_right||Directional_down||Directional_emulated_down||Directional_down_left) && !(Directional_up_left||Directional_up||Directional_emulated_up||Directional_up_right)) { Cursor_displace(0, step); } // Directional controller LEFT if ((Directional_down_left||Directional_left||Directional_emulated_left||Directional_up_left) && !(Directional_up_right||Directional_right||Directional_emulated_right||Directional_down_right)) { Cursor_displace(-step,0); } } } // If the cursor was moved since last update, // it was erased, so we need to redraw it (with the preview brush) if (Mouse_moved) { Compute_paintbrush_coordinates(); Display_cursor(); return 1; } if (user_feedback_required) return 1; // Nothing significant happened if (sleep_time) SDL_Delay(sleep_time); return 0; } void Adjust_mouse_sensitivity(word fullscreen) { // Deprecated (void)fullscreen; } void Set_mouse_position(void) { SDL_WarpMouse(Mouse_X*Pixel_width, Mouse_Y*Pixel_height); } int Color_cycling(__attribute__((unused)) void* useless) { static byte offset[16]; int i, color; static SDL_Color PaletteSDL[256]; int changed; // boolean : true if the palette needs a change in this tick. long now; static long start=0; if (start==0) { // First run start = SDL_GetTicks(); return 1; } if (!Allow_colorcycling || !Cycling_mode) return 1; now = SDL_GetTicks(); changed=0; // Check all cycles for a change at this tick for (i=0; i<16; i++) { int len; len=Main_backups->Pages->Gradients->Range[i].End-Main_backups->Pages->Gradients->Range[i].Start+1; if (len>1 && Main_backups->Pages->Gradients->Range[i].Speed) { int new_offset; new_offset=(now-start)/(int)(1000.0/(Main_backups->Pages->Gradients->Range[i].Speed*0.2856)) % len; if (!Main_backups->Pages->Gradients->Range[i].Inverse) new_offset=len - new_offset; if (new_offset!=offset[i]) changed=1; offset[i]=new_offset; } } if (changed) { // Initialize the palette for(color=0;color<256;color++) { PaletteSDL[color].r=Main_palette[color].R; PaletteSDL[color].g=Main_palette[color].G; PaletteSDL[color].b=Main_palette[color].B; } for (i=0; i<16; i++) { int len; len=Main_backups->Pages->Gradients->Range[i].End-Main_backups->Pages->Gradients->Range[i].Start+1; if (len>1 && Main_backups->Pages->Gradients->Range[i].Speed) { for(color=Main_backups->Pages->Gradients->Range[i].Start;color<=Main_backups->Pages->Gradients->Range[i].End;color++) { PaletteSDL[color].r=Main_palette[Main_backups->Pages->Gradients->Range[i].Start+((color-Main_backups->Pages->Gradients->Range[i].Start+offset[i])%len)].R; PaletteSDL[color].g=Main_palette[Main_backups->Pages->Gradients->Range[i].Start+((color-Main_backups->Pages->Gradients->Range[i].Start+offset[i])%len)].G; PaletteSDL[color].b=Main_palette[Main_backups->Pages->Gradients->Range[i].Start+((color-Main_backups->Pages->Gradients->Range[i].Start+offset[i])%len)].B; } } } SDL_SetPalette(Screen_SDL, SDL_PHYSPAL | SDL_LOGPAL, PaletteSDL,0,256); } return 0; } grafx2/src/io.c0000644000076400010400000003165011545677504014017 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski 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 */ // Fonctions de lecture/ecriture file, grent les systmes big-endian et // little-endian. #define _XOPEN_SOURCE 500 #include #include #include #include #include #include #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) #include #include #include #elif defined(__WIN32__) #include #include //#include #elif defined(__MINT__) #include #include #include #else #include #endif #include "struct.h" #include "io.h" #include "realpath.h" // Lit un octet // Renvoie -1 si OK, 0 en cas d'erreur int Read_byte(FILE *file, byte *dest) { return fread(dest, 1, 1, file) == 1; } // Ecrit un octet // Renvoie -1 si OK, 0 en cas d'erreur int Write_byte(FILE *file, byte b) { return fwrite(&b, 1, 1, file) == 1; } // Lit des octets // Renvoie -1 si OK, 0 en cas d'erreur int Read_bytes(FILE *file, void *dest, size_t size) { return fread(dest, 1, size, file) == size; } // Ecrit des octets // Renvoie -1 si OK, 0 en cas d'erreur int Write_bytes(FILE *file, void *src, size_t size) { return fwrite(src, 1, size, file) == size; } // Lit un word (little-endian) // Renvoie -1 si OK, 0 en cas d'erreur int Read_word_le(FILE *file, word *dest) { if (fread(dest, 1, sizeof(word), file) != sizeof(word)) return 0; #if SDL_BYTEORDER != SDL_LIL_ENDIAN *dest = SDL_Swap16(*dest); #endif return -1; } // Ecrit un word (little-endian) // Renvoie -1 si OK, 0 en cas d'erreur int Write_word_le(FILE *file, word w) { #if SDL_BYTEORDER != SDL_LIL_ENDIAN w = SDL_Swap16(w); #endif return fwrite(&w, 1, sizeof(word), file) == sizeof(word); } // Lit un word (big-endian) // Renvoie -1 si OK, 0 en cas d'erreur int Read_word_be(FILE *file, word *dest) { if (fread(dest, 1, sizeof(word), file) != sizeof(word)) return 0; #if SDL_BYTEORDER != SDL_BIG_ENDIAN *dest = SDL_Swap16(*dest); #endif return -1; } // Ecrit un word (big-endian) // Renvoie -1 si OK, 0 en cas d'erreur int Write_word_be(FILE *file, word w) { #if SDL_BYTEORDER != SDL_BIG_ENDIAN w = SDL_Swap16(w); #endif return fwrite(&w, 1, sizeof(word), file) == sizeof(word); } // Lit un dword (little-endian) // Renvoie -1 si OK, 0 en cas d'erreur int Read_dword_le(FILE *file, dword *dest) { if (fread(dest, 1, sizeof(dword), file) != sizeof(dword)) return 0; #if SDL_BYTEORDER != SDL_LIL_ENDIAN *dest = SDL_Swap32(*dest); #endif return -1; } // Ecrit un dword (little-endian) // Renvoie -1 si OK, 0 en cas d'erreur int Write_dword_le(FILE *file, dword dw) { #if SDL_BYTEORDER != SDL_LIL_ENDIAN dw = SDL_Swap32(dw); #endif return fwrite(&dw, 1, sizeof(dword), file) == sizeof(dword); } // Lit un dword (big-endian) // Renvoie -1 si OK, 0 en cas d'erreur int Read_dword_be(FILE *file, dword *dest) { if (fread(dest, 1, sizeof(dword), file) != sizeof(dword)) return 0; #if SDL_BYTEORDER != SDL_BIG_ENDIAN *dest = SDL_Swap32(*dest); #endif return -1; } // Ecrit un dword (big-endian) // Renvoie -1 si OK, 0 en cas d'erreur int Write_dword_be(FILE *file, dword dw) { #if SDL_BYTEORDER != SDL_BIG_ENDIAN dw = SDL_Swap32(dw); #endif return fwrite(&dw, 1, sizeof(dword), file) == sizeof(dword); } // Dtermine la position du dernier '/' ou '\\' dans une chaine, // typiquement pour sparer le nom de file d'un chemin. // Attention, sous Windows, il faut s'attendre aux deux car // par exemple un programme lanc sous GDB aura comme argv[0]: // d:\Data\C\GFX2\grafx2/grafx2.exe char * Find_last_slash(const char * str) { const char * position = NULL; for (; *str != '\0'; str++) if (*str == PATH_SEPARATOR[0] #ifdef __WIN32__ || *str == '/' #endif ) position = str; return (char *)position; } // Rcupre la partie "nom de file seul" d'un chemin void Extract_filename(char *dest, const char *source) { const char * position = Find_last_slash(source); if (position) strcpy(dest,position+1); else strcpy(dest,source); } // Rcupre la partie "rpertoire+/" d'un chemin. void Extract_path(char *dest, const char *source) { char * position=NULL; Realpath(source,dest); position = Find_last_slash(dest); if (position) *(position+1) = '\0'; else strcat(dest, PATH_SEPARATOR); } /// /// Appends a file or directory name to an existing directory name. /// As a special case, when the new item is equal to PARENT_DIR, this /// will remove the rightmost directory name. /// reverse_path is optional, if it's non-null, the function will /// write there : /// - if filename is ".." : The name of eliminated directory/file /// - else: ".." void Append_path(char *path, const char *filename, char *reverse_path) { // Parent if (!strcmp(filename, PARENT_DIR)) { // Going up one directory long len; char * slash_pos; // Remove trailing slash len=strlen(path); if (len && (!strcmp(path+len-1,PATH_SEPARATOR) #ifdef __WIN32__ || path[len-1]=='/' #endif )) path[len-1]='\0'; slash_pos=Find_last_slash(path); if (slash_pos) { if (reverse_path) strcpy(reverse_path, slash_pos+1); *slash_pos='\0'; } else { if (reverse_path) strcpy(reverse_path, path); path[0]='\0'; } #if defined(__WIN32__) // Roots of drives need a pending antislash if (path[0]!='\0' && path[1]==':' && path[2]=='\0') { strcat(path, PATH_SEPARATOR); } #endif } else // Sub-directory { long len; // Add trailing slash if needed len=strlen(path); if (len && (strcmp(path+len-1,PATH_SEPARATOR) #ifdef __WIN32__ && path[len-1]!='/' #endif )) { strcpy(path+len, PATH_SEPARATOR); len+=strlen(PATH_SEPARATOR); } strcat(path, filename); if (reverse_path) strcpy(reverse_path, PARENT_DIR); } } int File_exists(char * fname) // Dtermine si un file pass en paramtre existe ou non dans le // rpertoire courant. { struct stat buf; int result; result=stat(fname,&buf); if (result!=0) return(errno!=ENOENT); else return 1; } int Directory_exists(char * directory) // Dtermine si un rpertoire pass en paramtre existe ou non dans le // rpertoire courant. { DIR* entry; // Structure de lecture des lments if (strcmp(directory,PARENT_DIR)==0) return 1; else { // On va chercher si le rpertoire existe l'aide d'un Opendir. S'il // renvoie NULL c'est que le rpertoire n'est pas accessible... entry=opendir(directory); if (entry==NULL) return 0; else { closedir(entry); return 1; } } } #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) || defined(__MINT__) #define FILE_IS_HIDDEN_ATTRIBUTE __attribute__((unused)) #else #define FILE_IS_HIDDEN_ATTRIBUTE #endif /// Check if a file or directory is hidden. int File_is_hidden(FILE_IS_HIDDEN_ATTRIBUTE const char *fname, const char *full_name) { #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) || defined(__MINT__) // False (unable to determine, or irrrelevent for platform) return 0; #elif defined(__WIN32__) unsigned long att; if (full_name!=NULL) att = GetFileAttributesA(full_name); else att = GetFileAttributesA(fname); if (att==INVALID_FILE_ATTRIBUTES) return 0; return (att&FILE_ATTRIBUTE_HIDDEN)?1:0; #else return fname[0]=='.'; #endif } // Taille de fichier, en octets int File_length(const char * fname) { struct stat infos_fichier; if (stat(fname,&infos_fichier)) return 0; return infos_fichier.st_size; } int File_length_file(FILE * file) { struct stat infos_fichier; if (fstat(fileno(file),&infos_fichier)) return 0; return infos_fichier.st_size; } void For_each_file(const char * directory_name, void Callback(const char *)) { // Pour scan de rpertoire DIR* current_directory; //Rpertoire courant struct dirent* entry; // Structure de lecture des lments char full_filename[MAX_PATH_CHARACTERS]; int filename_position; strcpy(full_filename, directory_name); current_directory=opendir(directory_name); if(current_directory == NULL) return; // Rpertoire invalide ... filename_position = strlen(full_filename); if (filename_position==0 || strcmp(full_filename+filename_position-1,PATH_SEPARATOR)) { strcat(full_filename, PATH_SEPARATOR); filename_position = strlen(full_filename); } while ((entry=readdir(current_directory))) { struct stat Infos_enreg; strcpy(&full_filename[filename_position], entry->d_name); stat(full_filename,&Infos_enreg); if (S_ISREG(Infos_enreg.st_mode)) { Callback(full_filename); } } closedir(current_directory); } /// Scans a directory, calls Callback for each file or directory in it, void For_each_directory_entry(const char * directory_name, void Callback(const char *, byte is_file, byte is_directory, byte is_hidden)) { // Pour scan de rpertoire DIR* current_directory; //Rpertoire courant struct dirent* entry; // Structure de lecture des lments char full_filename[MAX_PATH_CHARACTERS]; int filename_position; strcpy(full_filename, directory_name); current_directory=opendir(full_filename); if(current_directory == NULL) return; // Rpertoire invalide ... filename_position = strlen(full_filename); if (filename_position==0 || strcmp(full_filename+filename_position-1,PATH_SEPARATOR)) { strcat(full_filename, PATH_SEPARATOR); filename_position = strlen(full_filename); } while ((entry=readdir(current_directory))) { struct stat Infos_enreg; strcpy(&full_filename[filename_position], entry->d_name); stat(full_filename,&Infos_enreg); Callback( full_filename, S_ISREG(Infos_enreg.st_mode), S_ISDIR(Infos_enreg.st_mode), File_is_hidden(entry->d_name, full_filename)); } closedir(current_directory); } void Get_full_filename(char * output_name, char * file_name, char * directory_name) { strcpy(output_name,directory_name); if (output_name[0] != '\0') { // Append a separator at the end of path, if there isn't one already. // This handles the case of directory variables which contain one, // as well as directories like "/" on Unix. if (output_name[strlen(output_name)-1]!=PATH_SEPARATOR[0]) strcat(output_name,PATH_SEPARATOR); } strcat(output_name,file_name); } /// Lock file used to prevent several instances of grafx2 from harming each others' backups #ifdef __WIN32__ HANDLE Lock_file_handle = INVALID_HANDLE_VALUE; #else int Lock_file_handle = -1; #endif byte Create_lock_file(const char *file_directory) { #if defined (__amigaos__)||(__AROS__) #warning "Missing code for your platform, please check and correct!" #else char lock_filename[MAX_PATH_CHARACTERS]; strcpy(lock_filename,file_directory); strcat(lock_filename,"gfx2.lck"); #ifdef __WIN32__ // Windowzy method for creating a lock file Lock_file_handle = CreateFile( lock_filename, GENERIC_WRITE, 0, // No sharing NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (Lock_file_handle == INVALID_HANDLE_VALUE) { return -1; } #else // Unixy method for lock file Lock_file_handle = open(lock_filename,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR); if (Lock_file_handle == -1) { // Usually write-protected media return -1; } if (lockf(Lock_file_handle, F_TLOCK, 0)==-1) { close(Lock_file_handle); // Usually write-protected media return -1; } #endif #endif // __amigaos__ or __AROS__ return 0; } void Release_lock_file(const char *file_directory) { char lock_filename[MAX_PATH_CHARACTERS]; #ifdef __WIN32__ if (Lock_file_handle != INVALID_HANDLE_VALUE) { CloseHandle(Lock_file_handle); } #else if (Lock_file_handle != -1) { close(Lock_file_handle); Lock_file_handle = -1; } #endif // Actual deletion strcpy(lock_filename,file_directory); strcat(lock_filename,"gfx2.lck"); remove(lock_filename); } grafx2/src/keyboard.c0000644000076400010400000011044611532233320015165 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2010 Alexander Filyanov Copyright 2009 Franck Charlet Copyright 2008 Yves Rizoud 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 */ #include #include #include "global.h" #include "keyboard.h" // Table de correspondance des scancode de clavier IBM PC AT vers // les symboles de touches SDL (sym). // La correspondance est bonne si le clavier est QWERTY US, ou si // l'utilisateur est sous Windows. // Dans l'ordre des colonnes: Normal, +Shift, +Control, +Alt const word Scancode_to_sym[256][4] = { /* 00 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 01 Esc */ { SDLK_ESCAPE ,SDLK_ESCAPE ,SDLK_ESCAPE ,SDLK_ESCAPE }, /* 02 1 ! */ { SDLK_1 ,SDLK_1 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 03 2 @ */ { SDLK_2 ,SDLK_2 ,SDLK_2 ,SDLK_UNKNOWN }, /* 04 3 # */ { SDLK_3 ,SDLK_3 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 05 4 $ */ { SDLK_4 ,SDLK_4 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 06 5 % */ { SDLK_5 ,SDLK_5 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 07 6 ^ */ { SDLK_6 ,SDLK_6 ,SDLK_6 ,SDLK_UNKNOWN }, /* 08 7 & */ { SDLK_7 ,SDLK_7 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 09 8 * */ { SDLK_8 ,SDLK_8 ,SDLK_8 ,SDLK_UNKNOWN }, /* 0A 9 ( */ { SDLK_9 ,SDLK_9 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 0B 0 ) */ { SDLK_0 ,SDLK_0 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 0C - _ */ { SDLK_MINUS ,SDLK_MINUS ,SDLK_MINUS ,SDLK_UNKNOWN }, /* 0D = + */ { SDLK_EQUALS ,SDLK_EQUALS ,SDLK_EQUALS ,SDLK_UNKNOWN }, /* 0E BkSpc */ { SDLK_BACKSPACE ,SDLK_BACKSPACE ,SDLK_BACKSPACE ,SDLK_BACKSPACE }, /* 0F Tab */ { SDLK_TAB ,SDLK_TAB ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 10 Q */ { SDLK_q ,SDLK_q ,SDLK_q ,SDLK_q }, /* 11 W */ { SDLK_w ,SDLK_w ,SDLK_w ,SDLK_w }, /* 12 E */ { SDLK_e ,SDLK_e ,SDLK_e ,SDLK_e }, /* 13 R */ { SDLK_r ,SDLK_r ,SDLK_r ,SDLK_r }, /* 14 T */ { SDLK_t ,SDLK_t ,SDLK_t ,SDLK_t }, /* 15 Y */ { SDLK_y ,SDLK_y ,SDLK_y ,SDLK_y }, /* 16 U */ { SDLK_u ,SDLK_u ,SDLK_u ,SDLK_u }, /* 17 I */ { SDLK_i ,SDLK_i ,SDLK_i ,SDLK_i }, /* 18 O */ { SDLK_o ,SDLK_o ,SDLK_o ,SDLK_o }, /* 19 P */ { SDLK_p ,SDLK_p ,SDLK_p ,SDLK_p }, /* 1A [ */ { SDLK_LEFTBRACKET ,SDLK_LEFTBRACKET ,SDLK_LEFTBRACKET ,SDLK_LEFTBRACKET }, /* 1B ] */ { SDLK_RIGHTBRACKET,SDLK_RIGHTBRACKET,SDLK_RIGHTBRACKET,SDLK_RIGHTBRACKET}, /* 1C Retrn */ { SDLK_RETURN ,SDLK_RETURN ,SDLK_RETURN ,SDLK_RETURN }, /* 1D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 1E A */ { SDLK_a ,SDLK_a ,SDLK_a ,SDLK_a }, /* 1F S */ { SDLK_s ,SDLK_s ,SDLK_s ,SDLK_s }, /* 20 D */ { SDLK_d ,SDLK_d ,SDLK_d ,SDLK_d }, /* 21 F */ { SDLK_f ,SDLK_f ,SDLK_f ,SDLK_f }, /* 22 G */ { SDLK_g ,SDLK_g ,SDLK_g ,SDLK_g }, /* 23 H */ { SDLK_h ,SDLK_h ,SDLK_h ,SDLK_h }, /* 24 J */ { SDLK_j ,SDLK_j ,SDLK_j ,SDLK_j }, /* 25 K */ { SDLK_k ,SDLK_k ,SDLK_k ,SDLK_k }, /* 26 L */ { SDLK_l ,SDLK_l ,SDLK_l ,SDLK_l }, /* 27 ; : */ { SDLK_SEMICOLON ,SDLK_SEMICOLON ,SDLK_SEMICOLON ,SDLK_SEMICOLON }, /* 28 ' */ { SDLK_QUOTE ,SDLK_QUOTE ,SDLK_UNKNOWN ,SDLK_QUOTE }, /* 29 ` ~ */ { SDLK_BACKQUOTE ,SDLK_BACKQUOTE ,SDLK_UNKNOWN ,SDLK_BACKQUOTE }, /* 2A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 2B \\ */ { SDLK_BACKSLASH ,SDLK_BACKSLASH ,SDLK_BACKSLASH ,SDLK_BACKSLASH }, /* 2C Z */ { SDLK_z ,SDLK_z ,SDLK_z ,SDLK_z }, /* 2D X */ { SDLK_x ,SDLK_x ,SDLK_x ,SDLK_x }, /* 2E C */ { SDLK_c ,SDLK_c ,SDLK_c ,SDLK_c }, /* 2F V */ { SDLK_v ,SDLK_v ,SDLK_v ,SDLK_v }, /* 30 B */ { SDLK_b ,SDLK_b ,SDLK_b ,SDLK_b }, /* 31 N */ { SDLK_n ,SDLK_n ,SDLK_n ,SDLK_n }, /* 32 M */ { SDLK_m ,SDLK_m ,SDLK_m ,SDLK_m }, /* 33 , < */ { SDLK_COMMA ,SDLK_COMMA ,SDLK_UNKNOWN ,SDLK_COMMA }, /* 34 . > */ { SDLK_PERIOD ,SDLK_PERIOD ,SDLK_UNKNOWN ,SDLK_PERIOD }, /* 35 / ? */ { SDLK_SLASH ,SDLK_SLASH ,SDLK_UNKNOWN ,SDLK_SLASH }, /* 36 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 37 Grey* */ { SDLK_KP_MULTIPLY ,SDLK_KP_MULTIPLY ,SDLK_UNKNOWN ,SDLK_KP_MULTIPLY }, /* 38 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 39 Space */ { SDLK_SPACE ,SDLK_SPACE ,SDLK_SPACE ,SDLK_SPACE }, /* 3A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 3B F1 */ { SDLK_F1 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 3C F2 */ { SDLK_F2 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 3D F3 */ { SDLK_F3 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 3E F4 */ { SDLK_F4 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 3F F5 */ { SDLK_F5 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 40 F6 */ { SDLK_F6 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 41 F7 */ { SDLK_F7 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 42 F8 */ { SDLK_F8 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 43 F9 */ { SDLK_F9 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 44 F10 */ { SDLK_F10 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 45 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 46 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 47 Home */ { SDLK_HOME ,SDLK_HOME ,SDLK_UNKNOWN ,SDLK_HOME }, /* 48 Up */ { SDLK_UP ,SDLK_UP ,SDLK_UNKNOWN ,SDLK_UP }, /* 49 PgUp */ { SDLK_PAGEUP ,SDLK_PAGEUP ,SDLK_UNKNOWN ,SDLK_PAGEUP }, /* 4A Grey- */ { SDLK_KP_MINUS ,SDLK_KP_MINUS ,SDLK_UNKNOWN ,SDLK_KP_MINUS }, /* 4B Left */ { SDLK_LEFT ,SDLK_LEFT ,SDLK_UNKNOWN ,SDLK_LEFT }, /* 4C Kpad5 */ { SDLK_KP5 ,SDLK_KP5 ,SDLK_UNKNOWN ,SDLK_KP5 }, /* 4D Right */ { SDLK_RIGHT ,SDLK_RIGHT ,SDLK_UNKNOWN ,SDLK_RIGHT }, /* 4E Grey+ */ { SDLK_KP_PLUS ,SDLK_KP_PLUS ,SDLK_UNKNOWN ,SDLK_KP_PLUS }, /* 4F End */ { SDLK_END ,SDLK_END ,SDLK_UNKNOWN ,SDLK_END }, /* 50 Down */ { SDLK_DOWN ,SDLK_DOWN ,SDLK_UNKNOWN ,SDLK_DOWN }, /* 51 PgDn */ { SDLK_PAGEDOWN ,SDLK_PAGEDOWN ,SDLK_UNKNOWN ,SDLK_PAGEDOWN }, /* 52 Ins */ { SDLK_INSERT ,SDLK_INSERT ,SDLK_UNKNOWN ,SDLK_INSERT }, /* 53 Del */ { SDLK_DELETE ,SDLK_DELETE ,SDLK_UNKNOWN ,SDLK_DELETE }, /* 54 ??? */ { SDLK_UNKNOWN ,SDLK_F1 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 55 ??? */ { SDLK_UNKNOWN ,SDLK_F2 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 56 Lft| */ { SDLK_UNKNOWN ,SDLK_F3 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 57 ??? */ { SDLK_UNKNOWN ,SDLK_F4 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 58 ??? */ { SDLK_UNKNOWN ,SDLK_F5 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 59 ??? */ { SDLK_UNKNOWN ,SDLK_F6 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 5A ??? */ { SDLK_UNKNOWN ,SDLK_F7 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 5B ??? */ { SDLK_UNKNOWN ,SDLK_F8 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 5C ??? */ { SDLK_UNKNOWN ,SDLK_F9 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 5D ??? */ { SDLK_UNKNOWN ,SDLK_F10 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 5E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F1 ,SDLK_UNKNOWN }, /* 5F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F2 ,SDLK_UNKNOWN }, /* 60 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F3 ,SDLK_UNKNOWN }, /* 61 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F4 ,SDLK_UNKNOWN }, /* 62 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F5 ,SDLK_UNKNOWN }, /* 63 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F6 ,SDLK_UNKNOWN }, /* 64 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F7 ,SDLK_UNKNOWN }, /* 65 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F8 ,SDLK_UNKNOWN }, /* 66 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F9 ,SDLK_UNKNOWN }, /* 67 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F10 ,SDLK_UNKNOWN }, /* 68 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F1 }, /* 69 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F2 }, /* 6A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F3 }, /* 6B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F4 }, /* 6C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F5 }, /* 6D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F6 }, /* 6E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F7 }, /* 6F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F8 }, /* 70 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F9 }, /* 71 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F10 }, /* 72 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 73 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LEFT ,SDLK_UNKNOWN }, /* 74 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RIGHT ,SDLK_UNKNOWN }, /* 75 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_END ,SDLK_UNKNOWN }, /* 76 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEDOWN ,SDLK_UNKNOWN }, /* 77 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_HOME ,SDLK_UNKNOWN }, /* 78 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_1 }, /* 79 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_2 }, /* 7A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_3 }, /* 7B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_4 }, /* 7C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_5 }, /* 7D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_6 }, /* 7E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_7 }, /* 7F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_8 }, /* 80 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_9 }, /* 81 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_0 }, /* 82 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_MINUS }, /* 83 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_EQUALS }, /* 84 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEUP ,SDLK_UNKNOWN }, /* 85 F11 */ { SDLK_F11 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 86 F12 */ { SDLK_F12 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 87 ??? */ { SDLK_UNKNOWN ,SDLK_F11 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 88 ??? */ { SDLK_UNKNOWN ,SDLK_F12 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 89 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F11 ,SDLK_UNKNOWN }, /* 8A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F12 ,SDLK_UNKNOWN }, /* 8B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F11 }, /* 8C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F12 }, /* 8D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UP ,SDLK_UNKNOWN }, /* 8E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_MINUS ,SDLK_UNKNOWN }, /* 8F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP5 ,SDLK_UNKNOWN }, /* 90 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_PLUS ,SDLK_UNKNOWN }, /* 91 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DOWN ,SDLK_UNKNOWN }, /* 92 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_INSERT ,SDLK_UNKNOWN }, /* 93 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DELETE ,SDLK_UNKNOWN }, /* 94 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_TAB ,SDLK_UNKNOWN }, /* 95 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_DIVIDE ,SDLK_UNKNOWN }, /* 96 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_MULTIPLY ,SDLK_UNKNOWN }, /* 97 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_HOME }, /* 98 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UP }, /* 99 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEUP }, /* 9A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 9B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LEFT }, /* 9C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 9D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RIGHT }, /* 9E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 9F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_END }, /* A0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DOWN }, /* A1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEUP }, /* A2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_INSERT }, /* A3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DELETE }, /* A4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_DIVIDE }, /* A5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_TAB }, /* A6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_ENTER }, /* A7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* A8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* A9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* AA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* AB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* AC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* AD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* AE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* AF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B6 Win L */ { SDLK_LSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B7 Win R */ { SDLK_RSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B8 Win M */ { SDLK_MENU ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* BA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* BB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* BC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* BD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* BE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* BF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C2 ??? */ { SDLK_UNKNOWN ,SDLK_LSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C3 ??? */ { SDLK_UNKNOWN ,SDLK_RSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* CA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* CB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* CC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* CD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* CE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LSUPER ,SDLK_UNKNOWN }, /* CF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RSUPER ,SDLK_UNKNOWN }, /* D0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_MENU ,SDLK_UNKNOWN }, /* D1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* D2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* D3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* D4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* D5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* D6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* D7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* D8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* D9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* DA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LSUPER }, /* DB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RSUPER }, /* DC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_MENU }, /* DD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* DE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* DF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* E0 Enter */ { SDLK_KP_ENTER ,SDLK_KP_ENTER ,SDLK_KP_ENTER ,SDLK_UNKNOWN }, /* E1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* E2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* E3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* E4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* E5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* E6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* E7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* E8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* E9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* EA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* EB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* EC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* ED ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* EE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* EF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* FA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* FB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* FC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* FD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* FE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* FF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, }; // Conversion de l'ancien codage des touches: // 0x00FF le scancode (maintenant code sym sur 0x0FFF) // 0x0100 shift (maintenant 0x1000) // 0x0200 control (maintenant 0x2000) // 0x0400 alt (maintenant 0x4000) word Key_for_scancode(word scancode) { if (scancode & 0x0400) return Scancode_to_sym[scancode & 0xFF][3] | (scancode & 0x0700) << 4; else if (scancode & 0x0200) return Scancode_to_sym[scancode & 0xFF][2] | (scancode & 0x0700) << 4; else if (scancode & 0x0100) return Scancode_to_sym[scancode & 0xFF][1] | (scancode & 0x0700) << 4; else return Scancode_to_sym[scancode & 0xFF][0]; } // Convertit des modificateurs de touches SDL en modificateurs GrafX2 word Key_modifiers(SDLMod mod) { word modifiers=0; if (mod & KMOD_CTRL ) modifiers|=MOD_CTRL; if (mod & KMOD_SHIFT ) modifiers|=MOD_SHIFT; if (mod & (KMOD_ALT|KMOD_MODE)) modifiers|=MOD_ALT; if (mod & (KMOD_META)) modifiers|=MOD_META; return modifiers; } word Keysym_to_keycode(SDL_keysym keysym) { word key_code = 0; word mod; // On ignore shift, alt et control isols. if (keysym.sym == SDLK_RSHIFT || keysym.sym == SDLK_LSHIFT || keysym.sym == SDLK_RCTRL || keysym.sym == SDLK_LCTRL || keysym.sym == SDLK_RALT || keysym.sym == SDLK_LALT || keysym.sym == SDLK_RMETA || keysym.sym == SDLK_LMETA || keysym.sym == SDLK_MODE) // AltGr return 0; // Les touches qui n'ont qu'une valeur unicode (trs rares) // seront codes sur 11 bits, le 12e bit est mis 1 (0x0800) if (keysym.sym != 0) key_code = keysym.sym; else if (keysym.scancode != 0) { key_code = (keysym.scancode & 0x07FF) | 0x0800; } // Normally I should test keysym.mod here, but on windows the implementation // is buggy: if you release a modifier key, the following keys (when they repeat) // still name the original modifiers. mod=Key_modifiers(SDL_GetModState()); // SDL_GetModState() seems to get the right up-to-date info. key_code |= mod; return key_code; } const char * Key_name(word key) { typedef struct { word keysym; char *Key_name; } T_key_label; T_key_label key_labels[] = { { SDLK_BACKSPACE , "Backspace" }, { SDLK_TAB , "Tab" }, { SDLK_CLEAR , "Clear" }, { SDLK_RETURN , "Return" }, { SDLK_PAUSE , "Pause" }, { SDLK_ESCAPE , "Esc" }, { SDLK_DELETE , "Del" }, { SDLK_KP0 , "KP 0" }, { SDLK_KP1 , "KP 1" }, { SDLK_KP2 , "KP 2" }, { SDLK_KP3 , "KP 3" }, { SDLK_KP4 , "KP 4" }, { SDLK_KP5 , "KP 5" }, { SDLK_KP6 , "KP 6" }, { SDLK_KP7 , "KP 7" }, { SDLK_KP8 , "KP 8" }, { SDLK_KP9 , "KP 9" }, { SDLK_KP_PERIOD , "KP ." }, { SDLK_KP_DIVIDE , "KP /" }, { SDLK_KP_MULTIPLY, "KP *" }, { SDLK_KP_MINUS , "KP -" }, { SDLK_KP_PLUS , "KP +" }, { SDLK_KP_ENTER , "KP Enter" }, { SDLK_KP_EQUALS , "KP =" }, { SDLK_UP , "Up" }, { SDLK_DOWN , "Down" }, { SDLK_RIGHT , "Right" }, { SDLK_LEFT , "Left" }, { SDLK_INSERT , "Ins" }, { SDLK_HOME , "Home" }, { SDLK_END , "End" }, { SDLK_PAGEUP , "PgUp" }, { SDLK_PAGEDOWN , "PgDn" }, { SDLK_F1 , "F1" }, { SDLK_F2 , "F2" }, { SDLK_F3 , "F3" }, { SDLK_F4 , "F4" }, { SDLK_F5 , "F5" }, { SDLK_F6 , "F6" }, { SDLK_F7 , "F7" }, { SDLK_F8 , "F8" }, { SDLK_F9 , "F9" }, { SDLK_F10 , "F10" }, { SDLK_F11 , "F11" }, { SDLK_F12 , "F12" }, { SDLK_F13 , "F13" }, { SDLK_F14 , "F14" }, { SDLK_F15 , "F15" }, { SDLK_NUMLOCK , "NumLock" }, { SDLK_CAPSLOCK , "CapsLck" }, { SDLK_SCROLLOCK , "ScrlLock" }, { SDLK_RSHIFT , "RShift" }, { SDLK_LSHIFT , "LShift" }, { SDLK_RCTRL , "RCtrl" }, { SDLK_LCTRL , "LCtrl" }, { SDLK_RALT , "RAlt" }, { SDLK_LALT , "LAlt" }, { SDLK_RMETA , "RMeta" }, { SDLK_LMETA , "LMeta" }, { SDLK_LSUPER , "LWin" }, { SDLK_RSUPER , "RWin" }, { SDLK_MODE , "AltGr" }, { SDLK_COMPOSE , "Comp" }, { SDLK_HELP , "Help" }, { SDLK_PRINT , "Print" }, { SDLK_SYSREQ , "SysReq" }, { SDLK_BREAK , "Break" }, { SDLK_MENU , "Menu" }, { SDLK_POWER , "Power" }, { SDLK_EURO , "Euro" }, { SDLK_UNDO , "Undo" }, { KEY_MOUSEMIDDLE, "Mouse3" }, { KEY_MOUSEWHEELUP, "WheelUp" }, { KEY_MOUSEWHEELDOWN, "WheelDown" } }; int index; static char buffer[41]; buffer[0] = '\0'; if (key == SDLK_UNKNOWN) return "None"; if (key & MOD_CTRL) strcat(buffer, "Ctrl+"); if (key & MOD_ALT) strcat(buffer, "Alt+"); if (key & MOD_SHIFT) strcat(buffer, "Shift+"); if (key & MOD_META) strcat(buffer, "\201"); // Note: Apple's "command" character is not present in the ANSI table, so we // recycled an ANSI value that doesn't have any displayable character // associated. key=key & ~(MOD_CTRL|MOD_ALT|MOD_SHIFT); // 99 is only a sanity check if (key>=KEY_JOYBUTTON && key<=KEY_JOYBUTTON+99) { char *button_name; switch(key-KEY_JOYBUTTON) { #ifdef JOY_BUTTON_UP case JOY_BUTTON_UP: button_name="[UP]"; break; #endif #ifdef JOY_BUTTON_DOWN case JOY_BUTTON_DOWN: button_name="[DOWN]"; break; #endif #ifdef JOY_BUTTON_LEFT case JOY_BUTTON_LEFT: button_name="[LEFT]"; break; #endif #ifdef JOY_BUTTON_RIGHT case JOY_BUTTON_RIGHT: button_name="[RIGHT]"; break; #endif #ifdef JOY_BUTTON_UPLEFT case JOY_BUTTON_UPLEFT: button_name="[UP-LEFT]"; break; #endif #ifdef JOY_BUTTON_UPRIGHT case JOY_BUTTON_UPRIGHT: button_name="[UP-RIGHT]"; break; #endif #ifdef JOY_BUTTON_DOWNLEFT case JOY_BUTTON_DOWNLEFT: button_name="[DOWN-LEFT]"; break; #endif #ifdef JOY_BUTTON_DOWNRIGHT case JOY_BUTTON_DOWNRIGHT: button_name="[DOWN-RIGHT]"; break; #endif #ifdef JOY_BUTTON_CLICK case JOY_BUTTON_CLICK: button_name="[CLICK]"; break; #endif #ifdef JOY_BUTTON_A case JOY_BUTTON_A: button_name="[A]"; break; #endif #ifdef JOY_BUTTON_B case JOY_BUTTON_B: button_name="[B]"; break; #endif #ifdef JOY_BUTTON_X case JOY_BUTTON_X: button_name="[X]"; break; #endif #ifdef JOY_BUTTON_Y case JOY_BUTTON_Y: button_name="[Y]"; break; #endif #ifdef JOY_BUTTON_L case JOY_BUTTON_L: button_name="[L]"; break; #endif #ifdef JOY_BUTTON_R case JOY_BUTTON_R: button_name="[R]"; break; #endif #ifdef JOY_BUTTON_START case JOY_BUTTON_START: button_name="[START]"; break; #endif #ifdef JOY_BUTTON_SELECT case JOY_BUTTON_SELECT: button_name="[SELECT]"; break; #endif #ifdef JOY_BUTTON_VOLUP case JOY_BUTTON_VOLUP: button_name="[VOL UP]"; break; #endif #ifdef JOY_BUTTON_VOLDOWN case JOY_BUTTON_VOLDOWN: button_name="[VOL DOWN]"; break; #endif #ifdef JOY_BUTTON_MENU case JOY_BUTTON_MENU: button_name="[MENU]"; break; #endif #ifdef JOY_BUTTON_HOME case JOY_BUTTON_HOME: button_name="[HOME]"; break; #endif #ifdef JOY_BUTTON_HOLD case JOY_BUTTON_HOLD: button_name="[HOLD]"; break; #endif #ifdef JOY_BUTTON_I case JOY_BUTTON_I: button_name="[BUTTON I]"; break; #endif #ifdef JOY_BUTTON_II case JOY_BUTTON_II: button_name="[BUTTON II]"; break; #endif #ifdef JOY_BUTTON_JOY case JOY_BUTTON_JOY: button_name="[THUMB JOY]"; break; #endif default: sprintf(buffer+strlen(buffer), "[B%d]", key-KEY_JOYBUTTON);return buffer; } strcat(buffer,button_name); return buffer; } if (key & 0x800) { sprintf(buffer+strlen(buffer), "[%d]", key & 0x7FF); return buffer; } key = key & 0x7FF; // Touches ASCII if (key>=' ' && key < 127) { sprintf(buffer+strlen(buffer), "'%c'", toupper(key)); return buffer; } // Touches 'World' if (key>=SDLK_WORLD_0 && key <= SDLK_WORLD_95) { sprintf(buffer+strlen(buffer), "w%d", key - SDLK_WORLD_0); return buffer; } // Touches au libell connu for (index=0; index < (long)sizeof(key_labels)/(long)sizeof(T_key_label);index++) { if (key == key_labels[index].keysym) { sprintf(buffer+strlen(buffer), "%s", key_labels[index].Key_name); return buffer; } } // Autres touches inconnues sprintf(buffer+strlen(buffer), "0x%X", key & 0x7FF); return buffer; } // Obtient le caractre ANSI tap, partir d'un keysym. // (Valeur 32 255) // Renvoie 0 s'il n'y a pas de caractre associ (shift, backspace, etc) word Keysym_to_ANSI(SDL_keysym keysym) { // This part was removed from the MacOSX port, but I put it back for others // as on Linux and Windows, it's what allows editing a text line with the keys // SDLK_LEFT, SDLK_RIGHT, SDLK_HOME, SDLK_END etc. #if !(defined(__macosx__) || defined(__FreeBSD__)) if ( keysym.unicode == 0) { switch(keysym.sym) { case SDLK_DELETE: case SDLK_LEFT: case SDLK_RIGHT: case SDLK_HOME: case SDLK_END: case SDLK_BACKSPACE: case KEY_ESC: return keysym.sym; case SDLK_RETURN: // Case alt-enter if (SDL_GetModState() & (KMOD_ALT|KMOD_META)) return '\n'; return keysym.sym; default: return 0; } } #endif // if ( keysym.unicode > 32 && keysym.unicode < 127) { return keysym.unicode; // Pas de souci, on est en ASCII standard } // Quelques conversions Unicode-ANSI switch(keysym.unicode) { case 0x8100: return ''; // case 0x1A20: return ''; // case 0x201A: return ''; // case 0x9201: return ''; // case 0x1E20: return ''; // case 0x2620: return ''; // case 0x2020: return ''; // case 0x2120: return ''; // case 0xC602: return ''; // case 0x3020: return ''; // case 0x6001: return ''; // case 0x3920: return ''; // case 0x5201: return ''; // case 0x8D00: return ''; // case 0x1C20: return ''; // case 0x1D20: return ''; // case 0x2220: return ''; // case 0x1320: return ''; // case 0x1420: return ''; // case 0xDC02: return ''; // case 0x5301: return ''; // case 0xA000: return ''; // case 0xA100: return ''; // case 0xA200: return ''; // case 0xA300: return ''; // case 0xA400: return ''; // case 0xA700: return ''; // case 0xC600: return ''; // } // Key entre 127 et 255 if (keysym.unicode<256) { #if defined(__macosx__) || defined(__FreeBSD__) // fc: Looks like there's a mismatch with delete & backspace // i don't why SDLK_DELETE was returned instead of SDLK_BACKSPACE if(keysym.unicode == 127) { return(SDLK_BACKSPACE); } // We don't make any difference between return & enter in the app context. if(keysym.unicode == 3) { return(SDLK_RETURN); } #endif return keysym.unicode; } // Sinon c'est une touche spciale, on retourne son scancode return keysym.sym; } grafx2/src/layers.c0000644000076400010400000002373211343525170014674 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2009 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 */ #include "const.h" #include "struct.h" #include "global.h" #include "windows.h" #include "engine.h" #include "pages.h" #include "sdlscreen.h" #include "input.h" #include "help.h" #include "misc.h" void Layer_activate(byte layer, short side) { word old_layers; if (layer >= Main_backups->Pages->Nb_layers) return; // Keep a copy of which layers were visible old_layers = Main_layers_visible; #ifndef NOLAYERS if (side == RIGHT_SIDE) { // Right-click on current layer if (Main_current_layer == layer) { if (Main_layers_visible == (dword)(1<Pages); //Update_FX_feedback(Config.FX_Feedback); Display_all_screen(); Display_layerbar(); Display_cursor(); } void Button_Layer_add(void) { Hide_cursor(); if (Main_backups->Pages->Nb_layers < MAX_NB_LAYERS) { // Backup with unchanged layers Backup_layers(0); if (!Add_layer(Main_backups,Main_current_layer+1)) { Update_depth_buffer(); Display_all_screen(); Display_layerbar(); End_of_modification(); } } Unselect_button(BUTTON_LAYER_ADD); Display_cursor(); } void Button_Layer_remove(void) { Hide_cursor(); if (Main_backups->Pages->Nb_layers > 1) { // Backup with unchanged layers Backup_layers(0); if (!Delete_layer(Main_backups,Main_current_layer)) { Update_screen_targets(); Redraw_layered_image(); Display_all_screen(); Display_layerbar(); End_of_modification(); } } Unselect_button(BUTTON_LAYER_REMOVE); Display_cursor(); } void Button_Layer_select(void) { short layer; // Determine which button is clicked according to mouse position layer = (Mouse_X/Menu_factor_X - Menu_bars[MENUBAR_LAYERS].Skin_width) / Layer_button_width; // Safety required because the mouse cursor can have slided outside button. if (layer < 0) layer=0; else if (layer > Main_backups->Pages->Nb_layers-1) layer=Main_backups->Pages->Nb_layers-1; Layer_activate(layer, LEFT_SIDE); } void Button_Layer_toggle(void) { short layer; // Determine which button is clicked according to mouse position layer = (Mouse_X/Menu_factor_X - Menu_bars[MENUBAR_LAYERS].Skin_width) / Layer_button_width; // Safety required because the mouse cursor can have slided outside button. if (layer < 0) layer=0; else if (layer > Main_backups->Pages->Nb_layers-1) layer=Main_backups->Pages->Nb_layers-1; Layer_activate(layer, RIGHT_SIDE); } static void Draw_transparent_color(byte color) { char buf[4]; Num2str(color, buf, 3); Print_in_window(63,39,buf,MC_Black,MC_Light); Window_rectangle(90,39,13,7,color); } static void Draw_transparent_background(byte background) { Print_in_window(99,57,background?"X":" ",MC_Black,MC_Light); } void Button_Layer_menu(void) { byte transparent_color = Main_backups->Pages->Transparent_color; byte transparent_background = Main_backups->Pages->Background_transparent; short clicked_button; byte color; byte click; Open_window(122,100,"Layers"); Window_display_frame_in( 6, 21,110, 52); Print_in_window(14,18,"Transparency",MC_Dark,MC_Light); Print_in_window(11,38,"Color",MC_Black,MC_Light); Window_set_normal_button(54, 36, 56,13,"" , 0,1,KEY_NONE); // 1 Draw_transparent_color(transparent_color); Print_in_window(11,57,"Background",MC_Black,MC_Light); Window_set_normal_button(95, 54, 15,13,"" , 0,1,KEY_NONE); // 2 Draw_transparent_background(transparent_background); Window_set_normal_button( 7, 78, 51,14,"OK" , 0,1,SDLK_RETURN); // 3 Window_set_normal_button(63, 78, 51,14,"Cancel", 0,1,KEY_ESC); // 4 Update_window_area(0,0,Window_width, Window_height); do { clicked_button=Window_clicked_button(); if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_LAYER_MENU, NULL); switch(clicked_button) { case 1: // color Get_color_behind_window(&color,&click); if (click && transparent_color!=color) { transparent_color=color; Hide_cursor(); Draw_transparent_color(transparent_color); Display_cursor(); Wait_end_of_click(); } break; case 2: // background transparent_background = !transparent_background; Hide_cursor(); Draw_transparent_background(transparent_background); Display_cursor(); break; } } while (clicked_button<3); // On exit Hide_cursor(); Close_window(); if (clicked_button==3) { // Accept changes if (Main_backups->Pages->Transparent_color != transparent_color || Main_backups->Pages->Background_transparent != transparent_background) { Backup_layers(-1); Main_backups->Pages->Transparent_color = transparent_color; Main_backups->Pages->Background_transparent = transparent_background; Redraw_layered_image(); Display_all_screen(); End_of_modification(); } } Unselect_button(BUTTON_LAYER_MENU); Display_cursor(); } void Button_Layer_set_transparent(void) { Hide_cursor(); if (Main_backups->Pages->Transparent_color != Back_color) { Backup_layers(-1); Main_backups->Pages->Transparent_color = Back_color; Redraw_layered_image(); Display_all_screen(); End_of_modification(); } Unselect_button(BUTTON_LAYER_COLOR); Display_cursor(); } void Button_Layer_get_transparent(void) { Hide_cursor(); if (Main_backups->Pages->Transparent_color != Back_color) { Set_back_color(Main_backups->Pages->Transparent_color); } Unselect_button(BUTTON_LAYER_COLOR); Display_cursor(); } void Button_Layer_merge(void) { Hide_cursor(); if (Main_current_layer>0) { // Backup layer below the current Backup_layers(1<<(Main_current_layer-1)); Merge_layer(); Update_screen_targets(); Redraw_layered_image(); Display_all_screen(); Display_layerbar(); End_of_modification(); } Unselect_button(BUTTON_LAYER_MERGE); Display_cursor(); } void Button_Layer_up(void) { Hide_cursor(); if (Main_current_layer < (Main_backups->Pages->Nb_layers-1)) { byte * tmp; dword layer_flags; // Backup with unchanged layers Backup_layers(0); // swap tmp = Main_backups->Pages->Image[Main_current_layer]; Main_backups->Pages->Image[Main_current_layer] = Main_backups->Pages->Image[Main_current_layer+1]; Main_backups->Pages->Image[Main_current_layer+1] = tmp; // Swap visibility indicators layer_flags = (Main_layers_visible >> Main_current_layer) & 3; // Only needed if they are different. if (layer_flags == 1 || layer_flags == 2) { // One is on, the other is off. Negating them will // perform the swap. Main_layers_visible ^= (3 << Main_current_layer); } Main_current_layer++; Update_screen_targets(); Redraw_layered_image(); Display_all_screen(); Display_layerbar(); End_of_modification(); } Unselect_button(BUTTON_LAYER_UP); Display_cursor(); } void Button_Layer_down(void) { Hide_cursor(); if (Main_current_layer > 0) { byte * tmp; dword layer_flags; // Backup with unchanged layers Backup_layers(0); // swap tmp = Main_backups->Pages->Image[Main_current_layer]; Main_backups->Pages->Image[Main_current_layer] = Main_backups->Pages->Image[Main_current_layer-1]; Main_backups->Pages->Image[Main_current_layer-1] = tmp; // Swap visibility indicators layer_flags = (Main_layers_visible >> (Main_current_layer-1)) & 3; // Only needed if they are different. if (layer_flags == 1 || layer_flags == 2) { // Only needed if they are different. // One is on, the other is off. Negating them will // perform the swap. Main_layers_visible ^= (3 << (Main_current_layer-1)); } Main_current_layer--; Update_screen_targets(); Redraw_layered_image(); Display_layerbar(); Display_all_screen(); End_of_modification(); } Unselect_button(BUTTON_LAYER_DOWN); Display_cursor(); } grafx2/src/libraw2crtc.c0000644000076400010400000001072411343525170015610 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* GFX2CRTC - libraw2crtc.c * CloudStrife - 20080921 * Diffus sous licence libre CeCILL v2 * Voire LICENCE */ #include #include #include #include "const.h" #include "global.h" #include "struct.h" #include "loadsave.h" unsigned short addrCalc(unsigned char vcc, unsigned char rcc, unsigned char hcc, unsigned char cclk, unsigned char r1, unsigned char r12, unsigned char r13) { unsigned short MA; unsigned short addr; //MA = vcc*r1 + hcc + (0x0C)*256; MA = vcc*r1 + hcc + r12*256 + r13; addr = cclk | ((MA & 0x03FF) << 1); addr = addr | ((rcc & 0x07) << 11); addr = addr | ((MA & 0x3000) << 2); return addr; } unsigned char mode0interlace(T_IO_Context * context, unsigned char x, unsigned char y) { unsigned char mode0pixel[] = {0, 64, 4, 68, 16, 80, 20, 84, 1, 65, 5, 69, 17, 81, 21, 85}; return mode0pixel[Get_pixel(context,x,y)] << 1 | mode0pixel[Get_pixel(context,x+1,y)]; } unsigned char mode1interlace(T_IO_Context * context, unsigned char x, unsigned char y) { unsigned char mode1pixel[] = {0, 16, 1, 17}; return mode1pixel[Get_pixel(context,x,y)] << 3 | mode1pixel[Get_pixel(context,x+1,y)] << 2 | mode1pixel[Get_pixel(context,x+2,y)] << 1 | mode1pixel[Get_pixel(context,x+3,y)]; } unsigned char mode2interlace(T_IO_Context * context, unsigned char x, unsigned char y) { unsigned char out = 0; int i; for(i = 0; i < 8; i++) out += ((Get_pixel(context,x+7-i,y)&1) << i); return out; } unsigned char mode3interlace(T_IO_Context * context, unsigned char x, unsigned char y) { unsigned char mode3pixel[] = {0, 16, 1, 17}; return mode3pixel[Get_pixel(context, x,y)] << 3 | mode3pixel[Get_pixel(context,x+1,y)] << 2; } unsigned char (*ptrMode)(T_IO_Context * context, unsigned char x, unsigned char y); unsigned char *raw2crtc(T_IO_Context *context, unsigned short width, unsigned short height, unsigned char mode, unsigned char r9, unsigned long *outSize, unsigned char *r1, unsigned char r12, unsigned char r13) { unsigned char *outBuffer; unsigned char *tmpBuffer; unsigned char *allocationBuffer; unsigned short minAddr = 0; unsigned char minAddrIsDefined = 0; unsigned short maxAddr = 0; unsigned char nbPixPerByte; int y,x; unsigned char r6; unsigned short i; unsigned char *ptrTmp; unsigned char *ptrOut; unsigned char vcc; unsigned char rcc; unsigned char hcc; unsigned char cclk; switch(mode) { case 0: { *r1 = (width+3)/4; nbPixPerByte = 2; ptrMode = mode0interlace; break; } case 1: { *r1 = (width+7)/8; nbPixPerByte = 4; ptrMode = mode1interlace; break; } case 2: { *r1 = (width+15)/16; nbPixPerByte = 8; ptrMode = mode2interlace; break; } case 3: { *r1 = (width+3)/4; nbPixPerByte = 2; ptrMode = mode3interlace; break; } default: { exit(4); } } tmpBuffer = (unsigned char*)malloc(0xFFFF); if (tmpBuffer == NULL) { printf("Allocation tmpBuffer rat\n"); exit(4); } allocationBuffer = (unsigned char*)malloc(0xFFFF); if(allocationBuffer == NULL) { printf("Allocation allocationBuffer rat\n"); exit(4); } memset(allocationBuffer, 0, 0xFFFF); r6 = height/(r9+1); for(vcc = 0; vcc < r6; vcc++) { for(rcc = 0; rcc < (r9+1); rcc++) { for(hcc = 0; hcc < *r1; hcc++) { for(cclk = 0; cclk < 2; cclk++) { x = (hcc << 1 | cclk); y = vcc*(r9+1) + rcc; *(tmpBuffer + addrCalc(vcc, rcc, hcc, cclk, *r1, r12, r13)) = (*ptrMode)(context,x,y); *(allocationBuffer + addrCalc(vcc, rcc, hcc, cclk, *r1, r12, r13)) += 1; } } } } for(i = 0; i < 0xFFFF; i++) { if(*(allocationBuffer + i) > 1) { printf("Attention : Ecriture multiple a l'adresse mmoire %d\n",i); } if(*(allocationBuffer + i) > 0) { maxAddr = i; } if((*(allocationBuffer + i) == 1) && (minAddrIsDefined == 0)) { minAddr = i; minAddrIsDefined = 1; } } *outSize = (maxAddr + 1) - minAddr; outBuffer = (unsigned char*)malloc((*outSize)); if (outBuffer == NULL) { printf("Allocation outBuffer rat\n"); exit(4); } ptrTmp = tmpBuffer + minAddr; ptrOut = outBuffer; for(i = minAddr; i <= maxAddr; i++) { *(ptrOut++) = *(ptrTmp++); } free(tmpBuffer); tmpBuffer = NULL; free(allocationBuffer); allocationBuffer = NULL; return outBuffer; } grafx2/src/loadsave.c0000644000076400010400000013376111551413222015172 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2010 Alexander Filyanov Copyright 2009 Petter Lindquist 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 */ #define _XOPEN_SOURCE 500 #include #include #include #include #include #include #include #include #include "buttons.h" #include "const.h" #include "errors.h" #include "global.h" #include "io.h" #include "loadsave.h" #include "misc.h" #include "graph.h" #include "op_c.h" #include "pages.h" #include "palette.h" #include "sdlscreen.h" #include "struct.h" #include "windows.h" #include "engine.h" #include "brush.h" #include "setup.h" // -- PKM ------------------------------------------------------------------- void Test_PKM(T_IO_Context *); void Load_PKM(T_IO_Context *); void Save_PKM(T_IO_Context *); // -- LBM ------------------------------------------------------------------- void Test_LBM(T_IO_Context *); void Load_LBM(T_IO_Context *); void Save_LBM(T_IO_Context *); // -- GIF ------------------------------------------------------------------- void Test_GIF(T_IO_Context *); void Load_GIF(T_IO_Context *); void Save_GIF(T_IO_Context *); // -- PCX ------------------------------------------------------------------- void Test_PCX(T_IO_Context *); void Load_PCX(T_IO_Context *); void Save_PCX(T_IO_Context *); // -- BMP ------------------------------------------------------------------- void Test_BMP(T_IO_Context *); void Load_BMP(T_IO_Context *); void Save_BMP(T_IO_Context *); // -- IMG ------------------------------------------------------------------- void Test_IMG(T_IO_Context *); void Load_IMG(T_IO_Context *); void Save_IMG(T_IO_Context *); // -- SCx ------------------------------------------------------------------- void Test_SCx(T_IO_Context *); void Load_SCx(T_IO_Context *); void Save_SCx(T_IO_Context *); // -- CEL ------------------------------------------------------------------- void Test_CEL(T_IO_Context *); void Load_CEL(T_IO_Context *); void Save_CEL(T_IO_Context *); // -- KCF ------------------------------------------------------------------- void Test_KCF(T_IO_Context *); void Load_KCF(T_IO_Context *); void Save_KCF(T_IO_Context *); // -- PAL ------------------------------------------------------------------- void Test_PAL(T_IO_Context *); void Load_PAL(T_IO_Context *); void Save_PAL(T_IO_Context *); // -- PI1 ------------------------------------------------------------------- void Test_PI1(T_IO_Context *); void Load_PI1(T_IO_Context *); void Save_PI1(T_IO_Context *); // -- PC1 ------------------------------------------------------------------- void Test_PC1(T_IO_Context *); void Load_PC1(T_IO_Context *); void Save_PC1(T_IO_Context *); // -- NEO ------------------------------------------------------------------- void Test_NEO(T_IO_Context *); void Load_NEO(T_IO_Context *); void Save_NEO(T_IO_Context *); // -- C64 ------------------------------------------------------------------- void Test_C64(T_IO_Context *); void Load_C64(T_IO_Context *); void Save_C64(T_IO_Context *); // -- SCR (Amstrad CPC) void Save_SCR(T_IO_Context *); // -- XPM (X PixMap) // Loading is done through SDL_Image void Save_XPM(T_IO_Context*); // -- PNG ------------------------------------------------------------------- #ifndef __no_pnglib__ void Test_PNG(T_IO_Context *); void Load_PNG(T_IO_Context *); void Save_PNG(T_IO_Context *); #endif // -- SDL_Image ------------------------------------------------------------- // (TGA, BMP, PNM, XPM, XCF, PCX, GIF, JPG, TIF, LBM, PNG, ICO) void Load_SDL_Image(T_IO_Context *); // ENUM Name TestFunc LoadFunc SaveFunc PalOnly Comment Layers Ext Exts T_Format File_formats[] = { {FORMAT_ALL_IMAGES, "(all)", NULL, NULL, NULL, 0, 0, 0, "", "gif;png;bmp;pcx;pkm;lbm;ilbm;iff;img;sci;scq;scf;scn;sco;pi1;pc1;cel;neo;kcf;pal;c64;koa;tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico"}, {FORMAT_ALL_FILES, "(*.*)", NULL, NULL, NULL, 0, 0, 0, "", "*"}, {FORMAT_GIF, " gif", Test_GIF, Load_GIF, Save_GIF, 0, 1, 1, "gif", "gif"}, #ifndef __no_pnglib__ {FORMAT_PNG, " png", Test_PNG, Load_PNG, Save_PNG, 0, 1, 0, "png", "png"}, #endif {FORMAT_BMP, " bmp", Test_BMP, Load_BMP, Save_BMP, 0, 0, 0, "bmp", "bmp"}, {FORMAT_PCX, " pcx", Test_PCX, Load_PCX, Save_PCX, 0, 0, 0, "pcx", "pcx"}, {FORMAT_PKM, " pkm", Test_PKM, Load_PKM, Save_PKM, 0, 1, 0, "pkm", "pkm"}, {FORMAT_LBM, " lbm", Test_LBM, Load_LBM, Save_LBM, 0, 0, 0, "lbm", "lbm;iff;ilbm"}, {FORMAT_IMG, " img", Test_IMG, Load_IMG, Save_IMG, 0, 0, 0, "img", "img"}, {FORMAT_SCx, " sc?", Test_SCx, Load_SCx, Save_SCx, 0, 0, 0, "sc?", "sci;scq;scf;scn;sco"}, {FORMAT_PI1, " pi1", Test_PI1, Load_PI1, Save_PI1, 0, 0, 0, "pi1", "pi1"}, {FORMAT_PC1, " pc1", Test_PC1, Load_PC1, Save_PC1, 0, 0, 0, "pc1", "pc1"}, {FORMAT_CEL, " cel", Test_CEL, Load_CEL, Save_CEL, 0, 0, 0, "cel", "cel"}, {FORMAT_NEO, " neo", Test_NEO, Load_NEO, Save_NEO, 0, 0, 0, "neo", "neo"}, {FORMAT_KCF, " kcf", Test_KCF, Load_KCF, Save_KCF, 1, 0, 0, "kcf", "kcf"}, {FORMAT_PAL, " pal", Test_PAL, Load_PAL, Save_PAL, 1, 0, 0, "pal", "pal"}, {FORMAT_C64, " c64", Test_C64, Load_C64, Save_C64, 0, 1, 0, "c64", "c64;koa"}, {FORMAT_SCR, " cpc", NULL, NULL, Save_SCR, 0, 0, 0, "cpc", "cpc;scr"}, {FORMAT_XPM, " xpm", NULL, NULL, Save_XPM, 0, 0, 0, "xpm", "xpm"}, {FORMAT_MISC,"misc.",NULL, NULL, NULL, 0, 0, 0, "", "tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico"}, }; /// Total number of known file formats unsigned int Nb_known_formats(void) { return sizeof(File_formats)/sizeof(File_formats[0]); } /// Set the color of a pixel (on load) void Set_pixel(T_IO_Context *context, short x_pos, short y_pos, byte color) { // Clipping if ((x_pos>=context->Width) || (y_pos>=context->Height)) return; switch (context->Type) { // Chargement des pixels dans l'cran principal case CONTEXT_MAIN_IMAGE: Pixel_in_current_screen(x_pos,y_pos,color,0); break; // Chargement des pixels dans la brosse case CONTEXT_BRUSH: //Pixel_in_brush(x_pos,y_pos,color); *(context->Buffer_image + y_pos * context->Pitch + x_pos)=color; break; // Chargement des pixels dans la preview case CONTEXT_PREVIEW: // Skip pixels of transparent index if : // it's a layer above the first one if (color == context->Transparent_color && context->Current_layer > 0) break; if (((x_pos % context->Preview_factor_X)==0) && ((y_pos % context->Preview_factor_Y)==0)) { // Tag the color as 'used' context->Preview_usage[color]=1; // Store pixel if (context->Ratio == PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) { context->Preview_bitmap[x_pos/context->Preview_factor_X*2 + (y_pos/context->Preview_factor_Y)*PREVIEW_WIDTH*Menu_factor_X]=color; context->Preview_bitmap[x_pos/context->Preview_factor_X*2+1 + (y_pos/context->Preview_factor_Y)*PREVIEW_WIDTH*Menu_factor_X]=color; } else if (context->Ratio == PIXEL_TALL && Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2) { context->Preview_bitmap[x_pos/context->Preview_factor_X + (y_pos/context->Preview_factor_Y*2)*PREVIEW_WIDTH*Menu_factor_X]=color; context->Preview_bitmap[x_pos/context->Preview_factor_X + (y_pos/context->Preview_factor_Y*2+1)*PREVIEW_WIDTH*Menu_factor_X]=color; } else context->Preview_bitmap[x_pos/context->Preview_factor_X + (y_pos/context->Preview_factor_Y)*PREVIEW_WIDTH*Menu_factor_X]=color; } break; // Load pixels in a SDL_Surface case CONTEXT_SURFACE: if (x_pos>=0 && y_pos>=0 && x_posSurface->w && y_posSurface->h) *(((byte *)(context->Surface->pixels)) + context->Surface->pitch * y_pos + x_pos) = color; break; } } void Palette_loaded(T_IO_Context *context) { // Update the current screen to the loaded palette switch (context->Type) { case CONTEXT_MAIN_IMAGE: case CONTEXT_PREVIEW: case CONTEXT_BRUSH: case CONTEXT_SURFACE: break; } switch (context->Type) { case CONTEXT_PREVIEW: case CONTEXT_MAIN_IMAGE: case CONTEXT_BRUSH: case CONTEXT_SURFACE: break; } } // Chargement des pixels dans le buffer 24b void Set_pixel_24b(T_IO_Context *context, short x_pos, short y_pos, byte r, byte g, byte b) { byte color; // Clipping if (x_pos<0 || y_pos<0 || x_pos>=context->Width || y_pos>=context->Height) return; switch(context->Type) { case CONTEXT_MAIN_IMAGE: case CONTEXT_BRUSH: case CONTEXT_SURFACE: { int index; index=(y_pos*context->Width)+x_pos; context->Buffer_image_24b[index].R=r; context->Buffer_image_24b[index].G=g; context->Buffer_image_24b[index].B=b; } break; case CONTEXT_PREVIEW: if (((x_pos % context->Preview_factor_X)==0) && ((y_pos % context->Preview_factor_Y)==0)) { color=((r >> 5) << 5) | ((g >> 5) << 2) | ((b >> 6)); // Tag the color as 'used' context->Preview_usage[color]=1; context->Preview_bitmap[x_pos/context->Preview_factor_X + (y_pos/context->Preview_factor_Y)*PREVIEW_WIDTH*Menu_factor_X]=color; } break; } } // Cration d'une palette fake void Set_palette_fake_24b(T_Palette palette) { int color; // Gnration de la palette for (color=0;color<256;color++) { palette[color].R=((color & 0xE0)>>5)<<5; palette[color].G=((color & 0x1C)>>2)<<5; palette[color].B=((color & 0x03)>>0)<<6; } } /// /// Generic allocation and similar stuff, done at beginning of image load, /// as soon as size is known. void Pre_load(T_IO_Context *context, short width, short height, long file_size, int format, enum PIXEL_RATIO ratio, byte truecolor) { char str[10]; context->Pitch = width; // default context->Width = width; context->Height = height; context->Ratio = ratio; context->Nb_layers = 1; context->Transparent_color=0; context->Background_transparent=0; switch(context->Type) { // Preview case CONTEXT_PREVIEW: // Prparation du chargement d'une preview: context->Preview_bitmap=malloc(PREVIEW_WIDTH*PREVIEW_HEIGHT*Menu_factor_X*Menu_factor_Y); if (!context->Preview_bitmap) File_error=1; // Affichage des donnes "Image size:" if ((width<10000) && (height<10000)) { Num2str(width,str,4); Num2str(height,str+5,4); str[4]='x'; Print_in_window(143,59,str,MC_Black,MC_Light); } else { Print_in_window(143,59,"VERY BIG!",MC_Black,MC_Light); } // Affichage de la taille du fichier if (file_size<1048576) { // Le fichier fait moins d'un Mega, on affiche sa taille direct Num2str(file_size,str,7); Print_in_window(236,59,str,MC_Black,MC_Light); } else if ((file_size/1024)<100000) { // Le fichier fait plus d'un Mega, on peut afficher sa taille en Ko Num2str(file_size/1024,str,5); strcpy(str+5,"Kb"); Print_in_window(236,59,str,MC_Black,MC_Light); } else { // Le fichier fait plus de 100 Mega octets (cas trs rare :)) Print_in_window(236,59,"LARGE!!",MC_Black,MC_Light); } // Affichage du vrai format if (format!=Main_format) { Print_in_window( 59,59,Get_fileformat(format)->Label,MC_Black,MC_Light); } // On efface le commentaire prcdent Window_rectangle(45,70,32*8,8,MC_Light); // Calcul des donnes ncessaires l'affichage de la preview: if (ratio == PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) width*=2; else if (ratio == PIXEL_TALL && Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2) height*=2; context->Preview_factor_X=Round_div_max(width,120*Menu_factor_X); context->Preview_factor_Y=Round_div_max(height, 80*Menu_factor_Y); if ( (!Config.Maximize_preview) && (context->Preview_factor_X!=context->Preview_factor_Y) ) { if (context->Preview_factor_X>context->Preview_factor_Y) context->Preview_factor_Y=context->Preview_factor_X; else context->Preview_factor_X=context->Preview_factor_Y; } context->Preview_pos_X=Window_pos_X+183*Menu_factor_X; context->Preview_pos_Y=Window_pos_Y+ 95*Menu_factor_Y; // On nettoie la zone o va s'afficher la preview: Window_rectangle(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT,MC_Light); // Un update pour couvrir les 4 zones: 3 libells plus le commentaire Update_window_area(45,48,256,30); // Zone de preview Update_window_area(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT); break; // Other loading case CONTEXT_MAIN_IMAGE: if (Backup_new_image(1,width,height)) { // La nouvelle page a pu tre alloue, elle est pour l'instant pleine // de 0s. Elle fait Main_image_width de large. // Normalement tout va bien, tout est sous contrle... // Load into layer 0, by default. context->Nb_layers=1; Main_current_layer=0; Main_layers_visible=1<<0; Set_layer(context,0); // Remove previous comment, unless we load just a palette if (! Get_fileformat(context->Format)->Palette_only) context->Comment[0]='\0'; } else { // Afficher un message d'erreur // Pour tre sr que ce soit lisible. Compute_optimal_menu_colors(context->Palette); Message_out_of_memory(); File_error=1; // 1 => On n'a pas perdu l'image courante } break; case CONTEXT_BRUSH: context->Buffer_image = (byte *)malloc(width*height); if (! context->Buffer_image) { File_error=3; return; } context->Target_address=context->Buffer_image; break; case CONTEXT_SURFACE: context->Surface = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCCOLORKEY, width, height, 8, 0, 0, 0, 0); if (! context->Surface) { File_error=1; return; } //context->Pitch = context->Surface->pitch; //context->Target_address = context->Surface->pixels; break; } if (File_error) return; // Extra process for truecolor images if (truecolor) { //context->Is_truecolor = 1; switch(context->Type) { case CONTEXT_MAIN_IMAGE: case CONTEXT_BRUSH: case CONTEXT_SURFACE: // Allocate 24bit buffer context->Buffer_image_24b= (T_Components *)malloc(width*height*sizeof(T_Components)); if (!context->Buffer_image_24b) { // Print an error message // The following is to be sure the message is readable Compute_optimal_menu_colors(context->Palette); Message_out_of_memory(); File_error=1; } break; case CONTEXT_PREVIEW: // Load palette Set_palette_fake_24b(context->Palette); Palette_loaded(context); break; } } } ///////////////////////////////////////////////////////////////////////////// // Gestion des lectures et critures // ///////////////////////////////////////////////////////////////////////////// byte * Write_buffer; word Write_buffer_index; void Init_write_buffer(void) { Write_buffer=(byte *)malloc(64000); Write_buffer_index=0; } void Write_one_byte(FILE *file, byte b) { Write_buffer[Write_buffer_index++]=b; if (Write_buffer_index>=64000) { if (! Write_bytes(file,Write_buffer,64000)) File_error=1; Write_buffer_index=0; } } void End_write(FILE *file) { if (Write_buffer_index) if (! Write_bytes(file,Write_buffer,Write_buffer_index)) File_error=1; free(Write_buffer); Write_buffer = NULL; } ///////////////////////////////////////////////////////////////////////////// // -------- Modifier la valeur du code d'erreur d'accs un fichier -------- // On n'est pas oblig d'utiliser cette fonction chaque fois mais il est // important de l'utiliser dans les cas du type: // if (!File_error) *** else File_error=***; // En fait, dans le cas o l'on modifie File_error alors qu'elle contient // dj un code d'erreur. void Set_file_error(int value) { if (File_error>=0) File_error=value; } // -- Charger n'importe connu quel type de fichier d'image (ou palette) ----- void Load_image(T_IO_Context *context) { unsigned int index; // index de balayage des formats T_Format *format = &(File_formats[2]); // Format du fichier charger int i; // Not sure it's the best place... context->Color_cycles=0; // On place par dfaut File_error vrai au cas o on ne sache pas // charger le format du fichier: File_error=1; if (context->Format>FORMAT_ALL_FILES) { format = Get_fileformat(context->Format); if (format->Test) format->Test(context); } if (File_error) { // Sinon, on va devoir scanner les diffrents formats qu'on connait pour // savoir quel format est le fichier: for (index=0; index < Nb_known_formats(); index++) { format = Get_fileformat(index); // Loadable format if (format->Test == NULL) continue; // On appelle le testeur du format: format->Test(context); // On s'arrte si le fichier est au bon format: if (File_error==0) break; } } if (File_error) { context->Format = DEFAULT_FILEFORMAT; // Last try: with SDL_image Load_SDL_Image(context); if (File_error) { // Sinon, l'appelant sera au courant de l'chec grace File_error; // et si on s'apprtait faire un chargement dfinitif de l'image (pas // une preview), alors on flash l'utilisateur. //if (Pixel_load_function!=Pixel_load_in_preview) // Error(0); return; } } else // Si on a su dterminer avec succs le format du fichier: { context->Format = format->Identifier; // On peut charger le fichier: // Dans certains cas il est possible que le chargement plante // aprs avoir modifi la palette. TODO format->Load(context); } if (File_error>0) { fprintf(stderr,"Unable to load file %s!\n",context->File_name); if (context->Type!=CONTEXT_SURFACE) Error(0); } // Post-load if (context->Buffer_image_24b) { // On vient de charger une image 24b if (!File_error) { switch(context->Type) { case CONTEXT_MAIN_IMAGE: // Cas d'un chargement dans l'image Hide_cursor(); Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); Flush_update(); if (Convert_24b_bitmap_to_256(Main_backups->Pages->Image[0],context->Buffer_image_24b,context->Width,context->Height,context->Palette)) File_error=2; else { Palette_loaded(context); } Hide_cursor(); Cursor_shape=CURSOR_SHAPE_ARROW; Display_cursor(); break; case CONTEXT_BRUSH: // Cas d'un chargement dans la brosse Hide_cursor(); Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); Flush_update(); if (Convert_24b_bitmap_to_256(Brush,context->Buffer_image_24b,context->Width,context->Height,context->Palette)) File_error=2; Hide_cursor(); Cursor_shape=CURSOR_SHAPE_ARROW; Display_cursor(); break; case CONTEXT_PREVIEW: // nothing to do break; case CONTEXT_SURFACE: if (Convert_24b_bitmap_to_256(context->Surface->pixels,context->Buffer_image_24b,context->Width,context->Height,context->Palette)) File_error=1; break; } } free(context->Buffer_image_24b); context->Buffer_image_24b = NULL; } else if (context->Type == CONTEXT_MAIN_IMAGE) { // Non-24b main image: Add menu colors if (Config.Safety_colors) { dword color_usage[256]; memset(color_usage,0,sizeof(color_usage)); if (Count_used_colors(color_usage)<252) { int gui_index; // From white to black for (gui_index=3; gui_index>=0; gui_index--) { int c; T_Components gui_color; gui_color=*Favorite_GUI_color(gui_index); // Try find a very close match (ignore last 2 bits) for (c=255; c>=0; c--) { if ((context->Palette[c].R|3) == (gui_color.R|3) && (context->Palette[c].G|3) == (gui_color.G|3) && (context->Palette[c].B|3) == (gui_color.B|3) ) break; } if (c<0) // Not found { // Find an unused slot at end of palette for (c=255; c>=0; c--) { if (color_usage[c]==0) { context->Palette[c]=gui_color; // Tag as a used color color_usage[c]=1; break; } } } } } } } if (context->Type == CONTEXT_MAIN_IMAGE) { if ( File_error!=1) { Set_palette(context->Palette); if (format->Palette_only) { // Make a backup step Backup_layers(0); } // Copy the loaded palette memcpy(Main_palette, context->Palette, sizeof(T_Palette)); memcpy(Main_backups->Pages->Palette, context->Palette, sizeof(T_Palette)); // For formats that handle more than just the palette: // Transfer the data to main image. if (!format->Palette_only) { if (context->Original_file_name && context->Original_file_name[0] && context->Original_file_directory && context->Original_file_directory[0]) { strcpy(Main_backups->Pages->Filename,context->Original_file_name); strcpy(Main_backups->Pages->File_directory,context->Original_file_directory); } else { strcpy(Main_backups->Pages->Filename,context->File_name); strcpy(Main_backups->Pages->File_directory,context->File_directory); } // On considre que l'image charge n'est plus modifie Main_image_is_modified=0; // Et on documente la variable Main_fileformat avec la valeur: Main_fileformat=format->Identifier; // already done initially on Backup_with_new_dimensions //Main_image_width= context->Width; //Main_image_height= context->Height; Main_current_layer = context->Nb_layers - 1; Main_layers_visible = (2<Pages->Transparent_color = context->Transparent_color; Main_backups->Pages->Background_transparent = context->Background_transparent; // Correction des dimensions if (Main_image_width<1) Main_image_width=1; if (Main_image_height<1) Main_image_height=1; // Color cyling ranges: for (i=0; i<16; i++) Main_backups->Pages->Gradients->Range[i].Speed=0; for (i=0; iColor_cycles; i++) { Main_backups->Pages->Gradients->Range[i].Start=context->Cycle_range[i].Start; Main_backups->Pages->Gradients->Range[i].End=context->Cycle_range[i].End; Main_backups->Pages->Gradients->Range[i].Inverse=context->Cycle_range[i].Inverse; Main_backups->Pages->Gradients->Range[i].Speed=context->Cycle_range[i].Speed; } // Comment strcpy(Main_comment, context->Comment); } } else if (File_error!=1) { // On considre que l'image charge est encore modifie Main_image_is_modified=1; // Et on documente la variable Main_fileformat avec la valeur: Main_fileformat=format->Identifier; } else { // Dans ce cas, on sait que l'image n'a pas chang, mais ses // paramtres (dimension, palette, ...) si. Donc on les restaures. Download_infos_page_main(Main_backups->Pages); } } else if (context->Type == CONTEXT_BRUSH && File_error==0) { if (Realloc_brush(context->Width, context->Height, context->Buffer_image, NULL)) { File_error=3; free(context->Buffer_image); } memcpy(Brush_original_palette, context->Palette, sizeof(T_Palette)); Remap_brush(); context->Buffer_image = NULL; } else if (context->Type == CONTEXT_SURFACE) { if (File_error == 0) { // Copy the palette SDL_Color colors[256]; int i; for (i=0; i<256; i++) { colors[i].r=context->Palette[i].R; colors[i].g=context->Palette[i].G; colors[i].b=context->Palette[i].B; } SDL_SetColors(context->Surface, colors, 0, 256); } } else if (context->Type == CONTEXT_PREVIEW /*&& !context->Buffer_image_24b*/ /*&& !Get_fileformat(context->Format)->Palette_only*/) { // Try to adapt the palette to accomodate the GUI. int c; int count_unused; byte unused_color[4]; count_unused=0; // Try find 4 unused colors and insert good colors there for (c=255; c>=0 && count_unused<4; c--) { if (!context->Preview_usage[c]) { unused_color[count_unused]=c; count_unused++; } } // Found! replace them with some favorites if (count_unused==4) { int gui_index; for (gui_index=0; gui_index<4; gui_index++) { context->Palette[unused_color[gui_index]]=*Favorite_GUI_color(gui_index); } } // All preview display is here // Update palette and screen first Compute_optimal_menu_colors(context->Palette); Remap_screen_after_menu_colors_change(); Set_palette(context->Palette); // Display palette preview if (Get_fileformat(context->Format)->Palette_only) { short index; if (context->Type == CONTEXT_PREVIEW) for (index=0; index<256; index++) Window_rectangle(183+(index/16)*7,95+(index&15)*5,5,5,index); } // Display normal image else if (context->Preview_bitmap) { int x_pos,y_pos; int width,height; width=context->Width/context->Preview_factor_X; height=context->Height/context->Preview_factor_Y; if (context->Ratio == PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) width*=2; else if (context->Ratio == PIXEL_TALL && Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2) height*=2; for (y_pos=0; y_posPreview_bitmap[x_pos+y_pos*PREVIEW_WIDTH*Menu_factor_X]; // Skip transparent if image has transparent background. if (color == context->Transparent_color && context->Background_transparent) color=MC_Window; Pixel(context->Preview_pos_X+x_pos, context->Preview_pos_Y+y_pos, color); } } // Refresh modified part Update_window_area(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT); // Preview comment Print_in_window(45,70,context->Comment,MC_Black,MC_Light); //Update_window_area(45,70,32*8,8); } } // -- Sauver n'importe quel type connu de fichier d'image (ou palette) ------ void Save_image(T_IO_Context *context) { T_Format *format; // On place par dfaut File_error vrai au cas o on ne sache pas // sauver le format du fichier: (Est-ce vraiment utile??? Je ne crois pas!) File_error=1; switch (context->Type) { case CONTEXT_MAIN_IMAGE: if (!File_formats[context->Format-1].Supports_layers && Main_backups->Pages->Nb_layers > 1) { if (! Confirmation_box("This format doesn't support layers\nand will save a flattened copy of\nyour image. Proceed?")) { // File_error is already set to 1. return; } } break; case CONTEXT_BRUSH: break; case CONTEXT_PREVIEW: break; case CONTEXT_SURFACE: break; } format = Get_fileformat(context->Format); if (format->Save) format->Save(context); if (File_error) { Error(0); return; } } void Load_SDL_Image(T_IO_Context *context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier word x_pos,y_pos; // long file_size; dword pixel; long file_size; SDL_Surface * surface; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; surface = IMG_Load(filename); if (!surface) { File_error=1; return; } file_size=File_length(filename); if (surface->format->BytesPerPixel == 1) { // 8bpp image Pre_load(context, surface->w, surface->h, file_size ,FORMAT_MISC, PIXEL_SIMPLE, 0); // Read palette if (surface->format->palette) { Get_SDL_Palette(surface->format->palette, context->Palette); } for (y_pos=0; y_posHeight; y_pos++) { for (x_pos=0; x_posWidth; x_pos++) { Set_pixel(context, x_pos, y_pos, Get_SDL_pixel_8(surface, x_pos, y_pos)); } } } else { { // Hi/Trucolor Pre_load(context, surface->w, surface->h, file_size ,FORMAT_ALL_IMAGES, PIXEL_SIMPLE, 1); } for (y_pos=0; y_posHeight; y_pos++) { for (x_pos=0; x_posWidth; x_pos++) { pixel = Get_SDL_pixel_hicolor(surface, x_pos, y_pos); Set_pixel_24b( context, x_pos, y_pos, ((pixel & surface->format->Rmask) >> surface->format->Rshift) << surface->format->Rloss, ((pixel & surface->format->Gmask) >> surface->format->Gshift) << surface->format->Gloss, ((pixel & surface->format->Bmask) >> surface->format->Bshift) << surface->format->Bloss); } } } SDL_FreeSurface(surface); } /// /// Load an arbitrary SDL_Surface. /// @param gradients Pass the address of a target T_Gradient_array if you want the gradients, NULL otherwise SDL_Surface * Load_surface(char *full_name, T_Gradient_array *gradients) { SDL_Surface * bmp=NULL; T_IO_Context context; Init_context_surface(&context, full_name, ""); Load_image(&context); if (context.Surface) { bmp=context.Surface; // Caller wants the gradients: if (gradients != NULL) { int i; memset(gradients, 0, sizeof(T_Gradient_array)); for (i=0; iRange[i].Start=context.Cycle_range[i].Start; gradients->Range[i].End=context.Cycle_range[i].End; gradients->Range[i].Inverse=context.Cycle_range[i].Inverse; gradients->Range[i].Speed=context.Cycle_range[i].Speed; } } } Destroy_context(&context); return bmp; } /// Saves an image. /// This routine will only be called when all hope is lost, memory thrashed, etc /// It's the last chance to save anything, but the code has to be extremely /// careful, anything could happen. /// The chosen format is IMG since it's extremely simple, difficult to make it /// create an unusable image. void Emergency_backup(const char *fname, byte *source, int width, int height, T_Palette *palette) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; short x_pos,y_pos; T_IMG_Header IMG_header; if (width == 0 || height == 0 || source == NULL) return; strcpy(filename,Config_directory); strcat(filename,fname); // Ouverture du fichier file=fopen(filename,"wb"); if (!file) return; memcpy(IMG_header.Filler1,"\x01\x00\x47\x12\x6D\xB0",6); memset(IMG_header.Filler2,0,118); IMG_header.Filler2[4]=0xFF; IMG_header.Filler2[22]=64; // Lo(Longueur de la signature) IMG_header.Filler2[23]=0; // Hi(Longueur de la signature) memcpy(IMG_header.Filler2+23,"GRAFX2 by SunsetDesign (IMG format taken from PV (c)W.Wiedmann)",64); if (!Write_bytes(file,IMG_header.Filler1,6) || !Write_word_le(file,width) || !Write_word_le(file,height) || !Write_bytes(file,IMG_header.Filler2,118) || !Write_bytes(file,palette,sizeof(T_Palette))) { fclose(file); return; } for (y_pos=0; ((y_posPages && Main_backups->Pages->Nb_layers == 1) Emergency_backup(SAFETYBACKUP_PREFIX_A "999999" BACKUP_FILE_EXTENSION,Main_screen, Main_image_width, Main_image_height, &Main_palette); if (Spare_backups && Spare_backups->Pages && Spare_backups->Pages->Nb_layers == 1) Emergency_backup(SAFETYBACKUP_PREFIX_B "999999" BACKUP_FILE_EXTENSION,Spare_visible_image.Image, Spare_image_width, Spare_image_height, &Spare_palette); #endif } T_Format * Get_fileformat(byte format) { unsigned int i; T_Format * safe_default = File_formats; for (i=0; i < Nb_known_formats(); i++) { if (File_formats[i].Identifier == format) return &(File_formats[i]); if (File_formats[i].Identifier == FORMAT_GIF) safe_default=&(File_formats[i]); } // Normally impossible to reach this point, unless called with an invalid // enum.... return safe_default; } /// Query the color of a pixel (to save) byte Get_pixel(T_IO_Context *context, short x, short y) { return *(context->Target_address + y*context->Pitch + x); } /// Cleans up resources void Destroy_context(T_IO_Context *context) { free(context->Buffer_image_24b); free(context->Buffer_image); free(context->Preview_bitmap); memset(context, 0, sizeof(T_IO_Context)); } /// Setup for loading a preview in fileselector void Init_context_preview(T_IO_Context * context, char *file_name, char *file_directory) { memset(context, 0, sizeof(T_IO_Context)); context->Type = CONTEXT_PREVIEW; context->File_name = file_name; context->File_directory = file_directory; context->Format = Main_fileformat; // FIXME ? } // Setup for loading/saving an intermediate backup void Init_context_backup_image(T_IO_Context * context, char *file_name, char *file_directory) { Init_context_layered_image(context, file_name, file_directory); } /// Setup for loading/saving the current main image void Init_context_layered_image(T_IO_Context * context, char *file_name, char *file_directory) { int i; memset(context, 0, sizeof(T_IO_Context)); context->Type = CONTEXT_MAIN_IMAGE; context->File_name = file_name; context->File_directory = file_directory; context->Format = Main_fileformat; memcpy(context->Palette, Main_palette, sizeof(T_Palette)); context->Width = Main_image_width; context->Height = Main_image_height; context->Nb_layers = Main_backups->Pages->Nb_layers; strcpy(context->Comment, Main_comment); context->Transparent_color=Main_backups->Pages->Transparent_color; context->Background_transparent=Main_backups->Pages->Background_transparent; if (Pixel_ratio == PIXEL_WIDE || Pixel_ratio == PIXEL_WIDE2) context->Ratio=PIXEL_WIDE; else if (Pixel_ratio == PIXEL_TALL || Pixel_ratio == PIXEL_TALL2) context->Ratio=PIXEL_TALL; else context->Ratio=PIXEL_SIMPLE; context->Target_address=Main_backups->Pages->Image[0]; context->Pitch=Main_image_width; // Color cyling ranges: for (i=0; i<16; i++) { if (Main_backups->Pages->Gradients->Range[i].Start!=Main_backups->Pages->Gradients->Range[i].End) { context->Cycle_range[context->Color_cycles].Start=Main_backups->Pages->Gradients->Range[i].Start; context->Cycle_range[context->Color_cycles].End=Main_backups->Pages->Gradients->Range[i].End; context->Cycle_range[context->Color_cycles].Inverse=Main_backups->Pages->Gradients->Range[i].Inverse; context->Cycle_range[context->Color_cycles].Speed=Main_backups->Pages->Gradients->Range[i].Speed; context->Color_cycles++; } } } /// Setup for loading/saving the flattened version of current main image //void Init_context_flat_image(T_IO_Context * context, char *file_name, char *file_directory) //{ //} /// Setup for loading/saving the user's brush void Init_context_brush(T_IO_Context * context, char *file_name, char *file_directory) { memset(context, 0, sizeof(T_IO_Context)); context->Type = CONTEXT_BRUSH; context->File_name = file_name; context->File_directory = file_directory; context->Format = Brush_fileformat; // Use main screen's palette memcpy(context->Palette, Main_palette, sizeof(T_Palette)); context->Width = Brush_width; context->Height = Brush_height; context->Nb_layers = 1; // Solid save... could use BG color maybe context->Transparent_color=0; context->Background_transparent=0; context->Ratio=PIXEL_SIMPLE; context->Target_address=Brush; context->Pitch=Brush_width; } // Setup for loading an image into a new SDL surface. void Init_context_surface(T_IO_Context * context, char *file_name, char *file_directory) { memset(context, 0, sizeof(T_IO_Context)); context->Type = CONTEXT_SURFACE; context->File_name = file_name; context->File_directory = file_directory; context->Format = DEFAULT_FILEFORMAT; // context->Palette // context->Width // context->Height context->Nb_layers = 1; context->Transparent_color=0; context->Background_transparent=0; context->Ratio=PIXEL_SIMPLE; //context->Target_address //context->Pitch } /// Function to call when need to switch layers. void Set_layer(T_IO_Context *context, byte layer) { context->Current_layer = layer; if (context->Type == CONTEXT_MAIN_IMAGE) { // This awful thing is the part that happens on load while (layer > (context->Nb_layers-1)) { if (Add_layer(Main_backups, layer)) { // Failure to add a layer on load: // Position on last layer layer = context->Nb_layers-1; break; } context->Nb_layers = Main_backups->Pages->Nb_layers; Main_current_layer = layer; Main_layers_visible = (2<Target_address=Main_backups->Pages->Image[layer]; } } // ============================================ // Safety backups // ============================================ typedef struct T_String_list { char * String; struct T_String_list * Next; } T_String_list; /// A list of files, used for scanning a directory T_String_list *Backups_main = NULL; /// A list of files, used for scanning a directory T_String_list *Backups_spare = NULL; // Settings for safety backup (frequency, numbers, etc) const int Rotation_safety_backup = 8; const int Min_interval_for_safety_backup = 30000; const int Min_edits_for_safety_backup = 10; const int Max_interval_for_safety_backup = 60000; const int Max_edits_for_safety_backup = 30; /// /// Adds a file to Backups_main or Backups_spare lists, if it's a backup. /// void Add_backup_file(const char *name) { T_String_list ** list; T_String_list * elem; int i; char file_name[MAX_PATH_CHARACTERS]; // Only files names of the form a0000000.* and b0000000.* are expected Extract_filename(file_name, name); // Check first character if (file_name[0]==Main_safety_backup_prefix) list = &Backups_main; else if (file_name[0]==Spare_safety_backup_prefix) list = &Backups_spare; else { // Not a good file return; } // Check next characters till file extension i = 1; while (file_name[i]!='\0' && file_name[i]!='.') { if (file_name[i]< '0' || file_name[i] > '9') { // Not a good file return; } i++; } // Add to list (top insertion) elem = (T_String_list *)malloc(sizeof(T_String_list)); elem->String=strdup(file_name); elem->Next=*list; *list=elem; } /// String comparer for sorting int String_compare (const void * a, const void * b) { return strcmp(*(char**)a,*(char**)b); } /// /// Reload safety backups, by loading several files in the right order. /// byte Process_backups(T_String_list **list) { int nb_files; int i; char ** files_vector; T_String_list *element; byte backup_max_undo_pages; if (*list == NULL) return 0; // Save the maximum number of pages // (It's used in Create_new_page() which gets called on each Load_image) backup_max_undo_pages = Config.Max_undo_pages; Config.Max_undo_pages = 99; // Count files nb_files=0; element=*list; while (element != NULL) { nb_files++; element = element->Next; } // Allocate a vector files_vector = (char **)malloc(sizeof(char *) * nb_files); // Copy from list to vector for (i=0;iString; next = (*list)->Next; free(*list); *list = next; } // Sort the vector qsort (files_vector, nb_files , sizeof(char **), String_compare); for (i=0; i < nb_files; i++) { // Load this file T_IO_Context context; char file_name[MAX_PATH_CHARACTERS]=""; char file_directory[MAX_PATH_CHARACTERS]=""; Init_context_backup_image(&context, files_vector[i], Config_directory); // Provide buffers to read original location context.Original_file_name = file_name; context.Original_file_directory = file_directory; Load_image(&context); Main_image_is_modified=1; Destroy_context(&context); Redraw_layered_image(); Display_all_screen(); } // Done with the vector for (i=0; i < nb_files; i++) { free(files_vector[i]); } free(files_vector); files_vector = NULL; // Restore the maximum number of pages Config.Max_undo_pages = backup_max_undo_pages; return nb_files; } /// Global indicator that tells if the safety backup system is active byte Safety_backup_active = 0; /// /// Checks if there are any pending safety backups, and then opens them. /// @return 0 if no problem, -1 if the backup system cannot be activated, >=1 if some backups are restored int Check_recovery(void) { int restored_spare; int restored_main; // First check if can write backups #if defined (__MINT__) //TODO: enable file lock under Freemint only return 0; #else if (Create_lock_file(Config_directory)) return -1; #endif Safety_backup_active=1; Backups_main = NULL; Backups_spare = NULL; For_each_file(Config_directory, Add_backup_file); // Do the processing twice: once for possible backups of the main page, // once for possible backups of the spare. restored_spare = Process_backups(&Backups_spare); if (restored_spare) { Main_offset_X=0; Main_offset_Y=0; Compute_limits(); Compute_paintbrush_coordinates(); if (Backups_main) Button_Page(); } restored_main = Process_backups(&Backups_main); if (restored_main) { Main_offset_X=0; Main_offset_Y=0; Compute_limits(); Compute_paintbrush_coordinates(); } return restored_main + restored_spare; } void Rotate_safety_backups(void) { Uint32 now; T_IO_Context context; char file_name[12+1]; char deleted_file[MAX_PATH_CHARACTERS]; if (!Safety_backup_active) return; now = SDL_GetTicks(); // It's time to save if either: // - Many edits have taken place // - A minimum number of edits have taken place AND a minimum time has passed // - At least one edit was done, and a maximum time has passed if ((Main_edits_since_safety_backup > Max_edits_for_safety_backup) || (Main_edits_since_safety_backup > Min_edits_for_safety_backup && now > Main_time_of_safety_backup + Min_interval_for_safety_backup) || (Main_edits_since_safety_backup > 1 && now > Main_time_of_safety_backup + Max_interval_for_safety_backup)) { // Clear a previous save (rotating saves) sprintf(deleted_file, "%s%c%6.6d" BACKUP_FILE_EXTENSION, Config_directory, Main_safety_backup_prefix, (Uint32)(Main_safety_number + 1000000l - Rotation_safety_backup) % (Uint32)1000000l); remove(deleted_file); // no matter if fail // Reset counters Main_edits_since_safety_backup=0; Main_time_of_safety_backup=now; // Create a new file name and save sprintf(file_name, "%c%6.6d" BACKUP_FILE_EXTENSION, Main_safety_backup_prefix, (Uint32)Main_safety_number); Init_context_backup_image(&context, file_name, Config_directory); context.Format=FORMAT_GIF; // Provide original file data, to store as a GIF Application Extension context.Original_file_name = Main_backups->Pages->Filename; context.Original_file_directory = Main_backups->Pages->File_directory; Save_image(&context); Destroy_context(&context); Main_safety_number++; } } /// Remove safety backups. Need to call on normal program exit. void Delete_safety_backups(void) { T_String_list *element; if (!Safety_backup_active) return; Backups_main = NULL; Backups_spare = NULL; For_each_file(Config_directory, Add_backup_file); chdir(Config_directory); for (element=Backups_main; element!=NULL; element=element->Next) { if(remove(element->String)) printf("Failed to delete %s\n",element->String); } for (element=Backups_spare; element!=NULL; element=element->Next) { if(remove(element->String)) printf("Failed to delete %s\n",element->String); } // Release lock file #if defined (__MINT__) //TODO: release file lock under Freemint only #else Release_lock_file(Config_directory); #endif } grafx2/src/main.c0000644000076400010400000007314711551662206014331 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2009 Pasi Kallinen Copyright 2008 Peter Gordon 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 */ #define GLOBAL_VARIABLES // time.h defines timeval which conflicts with the one in amiga SDK #ifdef __amigaos__ #include #else #include #endif #include #include #include #include #include #include #include // There is no WM on the GP2X... #if !defined(__GP2X__) && !defined(__WIZ__) && !defined(__CAANOO__) #include #endif #include "const.h" #include "struct.h" #include "global.h" #include "graph.h" #include "misc.h" #include "init.h" #include "buttons.h" #include "engine.h" #include "pages.h" #include "loadsave.h" #include "sdlscreen.h" #include "errors.h" #include "readini.h" #include "saveini.h" #include "io.h" #include "text.h" #include "setup.h" #include "windows.h" #include "brush.h" #include "palette.h" #include "realpath.h" #include "input.h" #include "help.h" #if defined(__WIN32__) #include #include #define chdir(dir) SetCurrentDirectory(dir) #elif defined (__MINT__) #include #elif defined(__macosx__) #import #import #elif defined(__FreeBSD__) #import #endif #if defined (__WIN32__) // On Windows, SDL_putenv is not present in any compilable header. // It can be linked anyway, this declaration only avoids // a compilation warning. extern DECLSPEC int SDLCALL SDL_putenv(const char *variable); #endif extern char Program_version[]; // generated in pversion.c //--- Affichage de la syntaxe, et de la liste des modes vidos disponibles --- void Display_syntax(void) { int mode_index; printf("Syntax: grafx2 [] [] []\n\n"); printf(" can be:]\n"); printf("\t-? -h -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-rgb n to reduce RGB precision from 256 to n levels\n"); printf("\t-skin to use an alternate file with the menu graphics\n"); printf("\t-mode to set a video mode\n"); printf("Arguments can be prefixed either by / - or --\n"); printf("They can also be abbreviated.\n\n"); printf("Available video modes:\n\n"); for (mode_index = 0; mode_index < Nb_video_modes; mode_index += 12) { int k; for (k = 0; k < 6; k++) { if (mode_index + k >= Nb_video_modes) break; printf("%12s",Mode_label(mode_index + k)); } puts(""); } } // ---------------------------- Sortie impromptue ---------------------------- void Warning_function(const char *message, const char *filename, int line_number, const char *function_name) { printf("Warning in file %s, line %d, function %s : %s\n", filename, line_number, function_name, message); } // ---------------------------- Sortie impromptue ---------------------------- void Error_function(int error_code, const char *filename, int line_number, const char *function_name) { T_Palette temp_palette; int index; printf("Error number %d occured in file %s, line %d, function %s.\n", error_code, filename,line_number,function_name); if (error_code==0) { // L'erreur 0 n'est pas une vraie erreur, elle fait seulement un flash rouge de l'cran pour dire qu'il y a un problme. // Toutes les autres erreurs dclenchent toujours une sortie en catastrophe du programme ! memcpy(temp_palette,Main_palette,sizeof(T_Palette)); for (index=0;index<=255;index++) temp_palette[index].R=255; Set_palette(temp_palette); Delay_with_active_mouse(50); // Half a second of red flash Set_palette(Main_palette); } else { switch (error_code) { case ERROR_GUI_MISSING : printf("Error: File containing the GUI graphics is missing!\n"); printf("This program cannot run without this file.\n"); break; case ERROR_GUI_CORRUPTED : printf("Error: File containing the GUI graphics couldn't be parsed!\n"); printf("This program cannot run without a correct version of this file.\n"); break; case ERROR_INI_MISSING : printf("Error: File gfx2def.ini is missing!\n"); printf("This program cannot run without this file.\n"); break; case ERROR_MEMORY : printf("Error: Not enough memory!\n\n"); printf("You should try exiting other programs to free some bytes for Grafx2.\n\n"); break; case ERROR_FORBIDDEN_MODE : printf("Error: The requested video mode has been disabled from the resolution menu!\n"); printf("If you want to run the program in this mode, you'll have to start it with an\n"); printf("enabled mode, then enter the resolution menu and enable the mode you want.\n"); printf("Check also if the 'Default_video_mode' parameter in gfx2.ini is correct.\n"); break; case ERROR_COMMAND_LINE : printf("Error: Invalid parameter or file not found.\n\n"); Display_syntax(); break; case ERROR_SAVING_CFG : printf("Error: Write error while saving settings!\n"); printf("Settings have not been saved correctly, and the gfx2.cfg file may have been\n"); printf("corrupt. If so, please delete it and Grafx2 will restore default settings.\n"); break; case ERROR_MISSING_DIRECTORY : printf("Error: Directory you ran the program from not found!\n"); break; case ERROR_INI_CORRUPTED : printf("Error: File gfx2.ini is corrupt!\n"); printf("It contains bad values at line %d.\n",Line_number_in_INI_file); printf("You can re-generate it by deleting the file and running GrafX2 again.\n"); break; case ERROR_SAVING_INI : printf("Error: Cannot rewrite file gfx2.ini!\n"); break; case ERROR_SORRY_SORRY_SORRY : printf("Error: Sorry! Sorry! Sorry! Please forgive me!\n"); break; } SDL_Quit(); exit(error_code); } } enum CMD_PARAMS { CMDPARAM_HELP, CMDPARAM_MODE, CMDPARAM_PIXELRATIO_TALL, CMDPARAM_PIXELRATIO_WIDE, CMDPARAM_PIXELRATIO_DOUBLE, CMDPARAM_PIXELRATIO_TRIPLE, CMDPARAM_PIXELRATIO_QUAD, CMDPARAM_PIXELRATIO_TALL2, CMDPARAM_PIXELRATIO_WIDE2, CMDPARAM_RGB, CMDPARAM_SKIN }; struct { const char *param; int id; } cmdparams[] = { {"?", CMDPARAM_HELP}, {"h", CMDPARAM_HELP}, {"H", CMDPARAM_HELP}, {"help", CMDPARAM_HELP}, {"mode", CMDPARAM_MODE}, {"tall", CMDPARAM_PIXELRATIO_TALL}, {"wide", CMDPARAM_PIXELRATIO_WIDE}, {"double", CMDPARAM_PIXELRATIO_DOUBLE}, {"triple", CMDPARAM_PIXELRATIO_TRIPLE}, {"quadruple", CMDPARAM_PIXELRATIO_QUAD}, {"tall2", CMDPARAM_PIXELRATIO_TALL2}, {"wide2", CMDPARAM_PIXELRATIO_WIDE2}, {"rgb", CMDPARAM_RGB}, {"skin", CMDPARAM_SKIN} }; #define ARRAY_SIZE(x) (int)(sizeof(x) / sizeof(x[0])) // --------------------- Analyse de la ligne de commande --------------------- int Analyze_command_line(int argc, char * argv[], char *main_filename, char *main_directory, char *spare_filename, char *spare_directory) { char *buffer ; int index; int file_in_command_line; file_in_command_line = 0; Resolution_in_command_line = 0; Current_resolution = Config.Default_resolution; for (index = 1; index 256) { Error(ERROR_COMMAND_LINE); Display_syntax(); exit(0); } Set_palette_RGB_scale(scale); } else { Error(ERROR_COMMAND_LINE); Display_syntax(); exit(0); } break; case CMDPARAM_SKIN: // GUI skin file index++; if (index 1) { // Il y a dj 2 noms de fichiers et on vient d'en trouver un 3me Error(ERROR_COMMAND_LINE); Display_syntax(); exit(0); } else if (File_exists(argv[index])) { file_in_command_line ++; buffer = Realpath(argv[index], NULL); if (file_in_command_line == 1) { // Separate path from filename Extract_path(main_directory, buffer); Extract_filename(main_filename, buffer); } else { // Separate path from filename Extract_path(spare_directory, buffer); Extract_filename(spare_filename, buffer); } free(buffer); buffer = NULL; } else { Error(ERROR_COMMAND_LINE); Display_syntax(); exit(0); } break; } } return file_in_command_line; } // Compile-time assertions: #define CT_ASSERT(e) extern char (*ct_assert(void)) [sizeof(char[1 - 2*!(e)])] // This line will raise an error at compile time // when sizeof(T_Components) is not 3. CT_ASSERT(sizeof(T_Components)==3); // This line will raise an error at compile time // when sizeof(T_Palette) is not 768. CT_ASSERT(sizeof(T_Palette)==768); // ------------------------ Initialiser le programme ------------------------- // Returns 0 on fail int Init_program(int argc,char * argv[]) { int temp; int starting_videomode; static char program_directory[MAX_PATH_CHARACTERS]; T_Gui_skin *gfx; int file_in_command_line; T_Gradient_array initial_gradients; static char main_filename [MAX_PATH_CHARACTERS]; static char main_directory[MAX_PATH_CHARACTERS]; static char spare_filename [MAX_PATH_CHARACTERS]; static char spare_directory[MAX_PATH_CHARACTERS]; #if defined(__MINT__) printf("===============================\n"); printf(" /|\\ GrafX2 %.19s\n", Program_version); printf(" compilation date: %.16s\n", __DATE__); printf("===============================\n"); #endif // On cre ds maintenant les descripteurs des listes de pages pour la page // principale et la page de brouillon afin que leurs champs ne soient pas // invalide lors des appels aux multiples fonctions manipules // l'initialisation du programme. Main_backups=(T_List_of_pages *)malloc(sizeof(T_List_of_pages)); Spare_backups=(T_List_of_pages *)malloc(sizeof(T_List_of_pages)); Init_list_of_pages(Main_backups); Init_list_of_pages(Spare_backups); // Determine the executable directory Set_program_directory(argv[0],program_directory); // Choose directory for data (read only) Set_data_directory(program_directory,Data_directory); // Choose directory for settings (read/write) Set_config_directory(program_directory,Config_directory); #if defined(__MINT__) strcpy(Main_current_directory,program_directory); #else // On dtermine le rpertoire courant: getcwd(Main_current_directory,256); #endif // On en profite pour le mmoriser dans le rpertoire principal: strcpy(Initial_directory,Main_current_directory); // On initialise les donnes sur le nom de fichier de l'image de brouillon: strcpy(Spare_current_directory,Main_current_directory); Main_fileformat=DEFAULT_FILEFORMAT; Spare_fileformat =Main_fileformat; strcpy(Brush_current_directory,Main_current_directory); strcpy(Brush_file_directory,Main_current_directory); strcpy(Brush_filename ,"NO_NAME.GIF"); Brush_fileformat =Main_fileformat; // On initialise ce qu'il faut pour que les fileselects ne plantent pas: Main_fileselector_position=0; // Au dbut, le fileselect est en haut de la liste des fichiers Main_fileselector_offset=0; // Au dbut, le fileselect est en haut de la liste des fichiers Main_format=FORMAT_ALL_IMAGES; Main_current_layer=0; Main_layers_visible=0xFFFFFFFF; Spare_current_layer=0; Spare_layers_visible=0xFFFFFFFF; Spare_fileselector_position=0; Spare_fileselector_offset=0; Spare_format=FORMAT_ALL_IMAGES; Brush_fileselector_position=0; Brush_fileselector_offset=0; Brush_format=FORMAT_ALL_IMAGES; // On initialise les commentaires des images des chanes vides Main_comment[0]='\0'; Brush_comment[0]='\0'; // On initialise d'ot' trucs Main_offset_X=0; Main_offset_Y=0; Main_separator_position=0; Main_X_zoom=0; Main_separator_proportion=INITIAL_SEPARATOR_PROPORTION; Main_magnifier_mode=0; Main_magnifier_factor=DEFAULT_ZOOM_FACTOR; Main_magnifier_height=0; Main_magnifier_width=0; Main_magnifier_offset_X=0; Main_magnifier_offset_Y=0; Spare_offset_X=0; Spare_offset_Y=0; Spare_separator_position=0; Spare_X_zoom=0; Spare_separator_proportion=INITIAL_SEPARATOR_PROPORTION; Spare_magnifier_mode=0; Spare_magnifier_factor=DEFAULT_ZOOM_FACTOR; Spare_magnifier_height=0; Spare_magnifier_width=0; Spare_magnifier_offset_X=0; Spare_magnifier_offset_Y=0; Keyboard_click_allowed = 1; Main_safety_backup_prefix = SAFETYBACKUP_PREFIX_A[0]; Spare_safety_backup_prefix = SAFETYBACKUP_PREFIX_B[0]; Main_time_of_safety_backup = 0; Spare_time_of_safety_backup = 0; // SDL if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_JOYSTICK) < 0) { // The program can't continue without that anyway printf("Couldn't initialize SDL.\n"); return(0); } Joystick = SDL_JoystickOpen(0); SDL_EnableKeyRepeat(250, 32); SDL_EnableUNICODE(SDL_ENABLE); SDL_WM_SetCaption("GrafX2","GrafX2"); Define_icon(); // Texte Init_text(); // On initialise tous les modes vido Set_all_video_modes(); Pixel_ratio=PIXEL_SIMPLE; // On initialise les donnes sur l'tat du programme: // Donne sur la sortie du programme: Quit_is_required=0; Quitting=0; // Donnes sur l'tat du menu: Menu_is_visible=1; // Donnes sur les couleurs et la palette: First_color_in_palette=0; // Donnes sur le curseur: Cursor_shape=CURSOR_SHAPE_TARGET; Cursor_hidden=0; // Donnes sur le pinceau: Paintbrush_X=0; Paintbrush_Y=0; Paintbrush_hidden=0; // On initialise tout ce qui concerne les oprations et les effets Operation_stack_size=0; Selected_freehand_mode=OPERATION_CONTINUOUS_DRAW; Selected_line_mode =OPERATION_LINE; Selected_curve_mode =OPERATION_3_POINTS_CURVE; Effect_function=No_effect; // On initialise les infos de la loupe: Main_magnifier_mode=0; Main_magnifier_factor=DEFAULT_ZOOM_FACTOR; Main_separator_proportion=INITIAL_SEPARATOR_PROPORTION; Spare_separator_proportion=INITIAL_SEPARATOR_PROPORTION; // On initialise les infos du mode smear: Smear_mode=0; Smear_brush_width=PAINTBRUSH_WIDTH; Smear_brush_height=PAINTBRUSH_HEIGHT; // On initialise les infos du mode smooth: Smooth_mode=0; // On initialise les infos du mode shade: Shade_mode=0; // Les autres infos du Shade sont charges avec la config Quick_shade_mode=0; // idem // On initialise les infos sur les dgrads: Gradient_pixel =Display_pixel; // Les autres infos sont charges avec la config // On initialise les infos de la grille: Snap_mode=0; Snap_width=8; Snap_height=8; Snap_offset_X=0; Snap_offset_Y=0; // On initialise les infos du mode Colorize: Colorize_mode=0; // Mode colorize inactif par dfaut Colorize_opacity=50; // Une interpolation de 50% par dfaut Colorize_current_mode=0; // Par dfaut, la mthode par interpolation Compute_colorize_table(); // On initialise les infos du mode Tiling: Tiling_mode=0; // Pas besoin d'initialiser les dcalages car a se fait // en prenant une brosse (toujours mis 0). // On initialise les infos du mode Mask: Mask_mode=0; // Infos du Spray Airbrush_mode=1; // Mode Mono Airbrush_size=31; Airbrush_delay=1; Airbrush_mono_flow=10; memset(Airbrush_multi_flow,0,256); srand(time(NULL)); // On randomize un peu tout a... // Initialisation des boutons Init_buttons(); // Initialisation des oprations Init_operations(); // Initialize the brush container Init_brush_container(); Windows_open=0; // Paintbrush if (!(Paintbrush_sprite=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE))) Error(ERROR_MEMORY); // Load preset paintbrushes (uses Paintbrush_ variables) Init_paintbrushes(); // Set a valid paintbrush afterwards *Paintbrush_sprite=1; Paintbrush_width=1; Paintbrush_height=1; Paintbrush_offset_X=0; Paintbrush_offset_Y=0; Paintbrush_shape=PAINTBRUSH_SHAPE_ROUND; #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) // Prefer cycling active by default Cycling_mode=1; #endif // Charger la configuration des touches Set_config_defaults(); switch(Load_CFG(1)) { case ERROR_CFG_MISSING: // Pas un problme, on a les valeurs par dfaut. break; case ERROR_CFG_CORRUPTED: DEBUG("Corrupted CFG file.",0); break; case ERROR_CFG_OLD: DEBUG("Unknown CFG file version, not loaded.",0); break; } // Charger la configuration du .INI temp=Load_INI(&Config); if (temp) Error(temp); if(!Config.Allow_multi_shortcuts) { Remove_duplicate_shortcuts(); } Compute_menu_offsets(); file_in_command_line=Analyze_command_line(argc, argv, main_filename, main_directory, spare_filename, spare_directory); Current_help_section=0; Help_position=0; // Load sprites, palette etc. gfx = Load_graphics(Config.Skin_file, &initial_gradients); if (gfx == NULL) { gfx = Load_graphics(DEFAULT_SKIN_FILENAME, &initial_gradients); if (gfx == NULL) { printf("%s", Gui_loading_error_message); Error(ERROR_GUI_MISSING); } } Set_current_skin(Config.Skin_file, gfx); // Override colors // Gfx->Default_palette[MC_Black]=Config.Fav_menu_colors[0]; // Gfx->Default_palette[MC_Dark] =Config.Fav_menu_colors[1]; // Gfx->Default_palette[MC_Light]=Config.Fav_menu_colors[2]; // Gfx->Default_palette[MC_White]=Config.Fav_menu_colors[3]; // Even when using the skin's palette, if RGB range is small // the colors will be unusable. Compute_optimal_menu_colors(Gfx->Default_palette); // Infos sur les trames (Sieve) Sieve_mode=0; Copy_preset_sieve(0); // Font if (!(Menu_font=Load_font(Config.Font_file))) if (!(Menu_font=Load_font(DEFAULT_FONT_FILENAME))) { printf("Unable to open the default font file: %s\n", DEFAULT_FONT_FILENAME); Error(ERROR_GUI_MISSING); } memcpy(Main_palette, Gfx->Default_palette, sizeof(T_Palette)); Fore_color=Best_color_nonexcluded(255,255,255); Back_color=Best_color_nonexcluded(0,0,0); // Allocation de mmoire pour la brosse if (!(Brush =(byte *)malloc( 1* 1))) Error(ERROR_MEMORY); if (!(Smear_brush =(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE))) Error(ERROR_MEMORY); starting_videomode=Current_resolution; Horizontal_line_buffer=NULL; Screen_width=Screen_height=Current_resolution=0; Init_mode_video( Video_mode[starting_videomode].Width, Video_mode[starting_videomode].Height, Video_mode[starting_videomode].Fullscreen, Pixel_ratio); // Windows only: move back the window to its original position. #if defined(__WIN32__) if (!Video_mode[starting_videomode].Fullscreen) { if (Config.Window_pos_x != 9999 && Config.Window_pos_y != 9999) { //RECT r; static SDL_SysWMinfo pInfo; SDL_VERSION(&pInfo.version); SDL_GetWMInfo(&pInfo); //GetWindowRect(pInfo.window, &r); SetWindowPos(pInfo.window, 0, Config.Window_pos_x, Config.Window_pos_y, 0, 0, SWP_NOSIZE); } } // Open a console for debugging... //ActivateConsole(); #endif Main_image_width=Screen_width/Pixel_width; Main_image_height=Screen_height/Pixel_height; Spare_image_width=Screen_width/Pixel_width; Spare_image_height=Screen_height/Pixel_height; // Allocation de mmoire pour les diffrents crans virtuels (et brosse) if (Init_all_backup_lists(Screen_width,Screen_height)==0) Error(ERROR_MEMORY); // Nettoyage de l'cran virtuel (les autres recevront celui-ci par copie) memset(Main_screen,0,Main_image_width*Main_image_height); // Now that the backup system is there, we can store the gradients. memcpy(Main_backups->Pages->Gradients->Range, initial_gradients.Range, sizeof(initial_gradients.Range)); memcpy(Spare_backups->Pages->Gradients->Range, initial_gradients.Range, sizeof(initial_gradients.Range)); Gradient_function=Gradient_basic; Gradient_lower_bound=0; Gradient_upper_bound=0; Gradient_random_factor=1; Gradient_bounds_range=1; Current_gradient=0; // Initialisation de diverses variables par calcul: Compute_magnifier_data(); Compute_limits(); Compute_paintbrush_coordinates(); // On affiche le menu: Display_paintbrush_in_menu(); Display_sprite_in_menu(BUTTON_PAL_LEFT,Config.Palette_vertical?MENU_SPRITE_VERTICAL_PALETTE_SCROLL:-1); Display_menu(); Draw_menu_button(BUTTON_PAL_LEFT,BUTTON_RELEASED); Draw_menu_button(BUTTON_PAL_RIGHT,BUTTON_RELEASED); // On affiche le curseur pour dbutter correctement l'tat du programme: Display_cursor(); Spare_image_is_modified=0; Main_image_is_modified=0; // Gestionnaire de signaux, quand il ne reste plus aucun espoir Init_sighandler(); // Le programme dbute en mode de dessin la main Select_button(BUTTON_DRAW,LEFT_SIDE); // On initialise la brosse initiale 1 pixel blanc: Brush_width=1; Brush_height=1; for (temp=0;temp<256;temp++) Brush_colormap[temp]=temp; Capture_brush(0,0,0,0,0); *Brush=MC_White; *Brush_original_pixels=MC_White; // Test de recuperation de fichiers sauvs switch (Check_recovery()) { T_IO_Context context; default: // Some files were loaded from last crash-exit. // Do not load files from command-line, nor show splash screen. Compute_optimal_menu_colors(Main_palette); Display_all_screen(); Display_menu(); Display_cursor(); Verbose_message("Images recovered", "Grafx2 has recovered images from\n" "last session, before a crash or\n" "shutdown. Browse the history using\n" "the Undo/Redo button, and when\n" "you find a state that you want to\n" "save, use the 'Save as' button to\n" "save the image.\n" "Some backups can be present in\n" "the spare page too.\n"); break; case -1: // Unable to write lock file Verbose_message("Warning", "Safety backups (every minute) are\n" "disabled because Grafx2 is running\n" "from a read-only device, or other\n" "instances are running."); break; case 0: switch (file_in_command_line) { case 0: if (Config.Opening_message) Button_Message_initial(); break; case 2: // Load this file Init_context_layered_image(&context, spare_filename, spare_directory); Load_image(&context); Destroy_context(&context); Redraw_layered_image(); End_of_modification(); Button_Page(); // no break ! proceed with the other file now case 1: Init_context_layered_image(&context, main_filename, main_directory); Load_image(&context); Destroy_context(&context); Redraw_layered_image(); End_of_modification(); Hide_cursor(); Compute_optimal_menu_colors(Main_palette); Display_all_screen(); Display_menu(); Display_cursor(); Resolution_in_command_line = 0; break; default: break; } } Allow_drag_and_drop(1); return(1); } // ------------------------- Fermeture du programme -------------------------- void Program_shutdown(void) { int return_code; // Windows only: Recover the window position. #if defined(__WIN32__) { RECT r; static SDL_SysWMinfo pInfo; SDL_GetWMInfo(&pInfo); GetWindowRect(pInfo.window, &r); Config.Window_pos_x = r.left; Config.Window_pos_y = r.top; } #else // All other targets: irrelevant dimensions. // Do not attempt to force them back on next program run. Config.Window_pos_x = 9999; Config.Window_pos_y = 9999; #endif // Remove the safety backups, this is normal exit Delete_safety_backups(); // On libre le buffer de gestion de lignes free(Horizontal_line_buffer); Horizontal_line_buffer = NULL; // On libre le pinceau spcial free(Paintbrush_sprite); Paintbrush_sprite = NULL; // On libre les diffrents crans virtuels et brosse: free(Brush); Brush = NULL; Set_number_of_backups(0); // Free the skin (Gui graphics) data free(Gfx); Gfx=NULL; // On prend bien soin de passer dans le rpertoire initial: if (chdir(Initial_directory)!=-1) { // On sauvegarde les donnes dans le .CFG et dans le .INI if (Config.Auto_save) { return_code=Save_CFG(); if (return_code) Error(return_code); return_code=Save_INI(&Config); if (return_code) Error(return_code); } } else Error(ERROR_MISSING_DIRECTORY); SDL_Quit(); #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) chdir("/usr/gp2x"); execl("/usr/gp2x/gp2xmenu", "/usr/gp2x/gp2xmenu", NULL); #endif } // -------------------------- Procdure principale --------------------------- int main(int argc,char * argv[]) { if(!Init_program(argc,argv)) { Program_shutdown(); return 0; } Main_handler(); Program_shutdown(); return 0; } grafx2/src/misc.c0000644000076400010400000005433411523553600014331 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski 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 */ #include #include #include #include #include #include "struct.h" #include "sdlscreen.h" #include "global.h" #include "errors.h" #include "buttons.h" #include "engine.h" #include "misc.h" #include "keyboard.h" #include "sdlscreen.h" #include "windows.h" #include "palette.h" #include "input.h" #include "graph.h" #include "pages.h" ///Count used palette indexes in the whole picture ///Return the total number of different colors ///Fill in "usage" with the count for each color word Count_used_colors(dword* usage) { int nb_pixels = 0; Uint8* current_pixel; Uint8 color; word nb_colors = 0; int i; int layer; for (i = 0; i < 256; i++) usage[i]=0; // Compute total number of pixels in the picture nb_pixels = Main_image_height * Main_image_width; // For each layer for (layer = 0; layer < Main_backups->Pages->Nb_layers; layer++) { current_pixel = Main_backups->Pages->Image[layer]; // For each pixel in picture for (i = 0; i < nb_pixels; i++) { color=*current_pixel; // get color in picture for this pixel usage[color]++; // add it to the counter // go to next pixel current_pixel++; } } // count the total number of unique used colors for (i = 0; i < 256; i++) { if (usage[i]!=0) nb_colors++; } return nb_colors; } /// Same as ::Count_used_colors, but use a block screen memory instead of /// picture data. Used to count colors in the loading screen. word Count_used_colors_screen_area(dword* usage, word start_x, word start_y, word width, word height) { Uint8 color; word x, y; word nb_colors = 0; int i; // Init usage table for (i = 0; i < 256; i++) usage[i]=0; // For each pixel in screen area for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { // Get color in screen memory color=*(Screen_pixels+((start_x + x)+(start_y + y) * Screen_width * Pixel_height) * Pixel_width); usage[color]++; //Un point de plus pour cette couleur } } //On va maintenant compter dans la table les couleurs utilises: for (i = 0; i < 256; i++) { if (usage[i]!=0) nb_colors++; } return nb_colors; } /// Same as ::Count_used_colors, but for a given rectangle in the picture only. /// Used bu the C64 block constraint checker. word Count_used_colors_area(dword* usage, word start_x, word start_y, word width, word height) { Uint8 color; word x, y; word nb_colors = 0; int i; // Init usage table for (i = 0; i < 256; i++) usage[i]=0; // On parcourt l'cran courant pour compter les utilisations des couleurs for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { // Get color from picture color=*(Main_screen+((start_x + x)+(start_y + y)*Main_image_width)); usage[color]++; //Un point de plus pour cette couleur } } //On va maintenant compter dans la table les couleurs utilises: for (i = 0; i < 256; i++) { if (usage[i]!=0) nb_colors++; } return nb_colors; } void Set_palette(T_Palette palette) { register int i; SDL_Color PaletteSDL[256]; for(i=0;i<256;i++) { PaletteSDL[i].r=(palette[i].R=Round_palette_component(palette[i].R)); PaletteSDL[i].g=(palette[i].G=Round_palette_component(palette[i].G)); PaletteSDL[i].b=(palette[i].B=Round_palette_component(palette[i].B)); } SDL_SetPalette(Screen_SDL, SDL_PHYSPAL | SDL_LOGPAL, PaletteSDL,0,256); } void Set_color(byte color, byte red, byte green, byte blue) { SDL_Color comp; comp.r=red; comp.g=green; comp.b=blue; SDL_SetPalette(Screen_SDL, SDL_PHYSPAL | SDL_LOGPAL, &comp, color, 1); } void Wait_end_of_click(void) { // On dsactive tous les raccourcis clavier while(Mouse_K) Get_input(20); } void Clear_current_image_with_stencil(byte color, byte * stencil) //Effacer l'image courante avec une certaine couleur en mode Stencil { int nb_pixels=0; //ECX //al=color //edi=Screen_pixels byte* pixel=Main_backups->Pages->Image[Main_current_layer]; int i; nb_pixels=Main_image_height*Main_image_width; for(i=0;iPages->Image[Main_current_layer], color , Main_image_width * Main_image_height ); } void Init_chrono(dword delay) // Dmarrer le chrono { Timer_delay = delay; Timer_start = SDL_GetTicks()/55; return; } void Pixel_in_brush (word x, word y, byte color) { *(Brush + y * Brush_width + x)=color; } byte Read_pixel_from_brush (word x, word y) { return *(Brush + y * Brush_width + x); } void Replace_a_color(byte old_color, byte new_color) { word x; word y; // Update all pixels for (y=0; y=Spare_image_width || y>=Spare_image_height) return Spare_backups->Pages->Transparent_color; #ifndef NOLAYERS return *(Spare_visible_image.Image + y*Spare_image_width + x); #else return *(Spare_backups->Pages->Image[Spare_current_layer] + y*Spare_image_width + x); #endif } void Rotate_90_deg_lowlevel(byte * source, byte * dest, short width, short height) { word x,y; for(y=0;y0;dx--) { // Pour chaque pixel for(cx=width;cx>0;cx--) { *out_buffer = conversion_table[*in_buffer]; in_buffer++; out_buffer++; } in_buffer += buffer_width-width; out_buffer += buffer_width-width; } } void Copy_image_to_brush(short start_x,short start_y,short Brush_width,short Brush_height,word image_width) { byte* src=start_y*image_width+start_x+Main_backups->Pages->Image[Main_current_layer]; //Adr dpart image (ESI) byte* dest=Brush_original_pixels; //Adr dest brosse (EDI) int dx; for (dx=Brush_height;dx!=0;dx--) //Pour chaque ligne { // On fait une copie de la ligne memcpy(dest,src,Brush_width); // On passe la ligne suivante src+=image_width; dest+=Brush_width; } } byte Read_pixel_from_feedback_screen (word x,word y) { return *(FX_feedback_screen+y*Main_image_width+x); } dword Round_div(dword numerator,dword divisor) { return numerator/divisor; } byte Effect_sieve(word x,word y) { return Sieve[x % Sieve_width][y % Sieve_height]; } void Replace_colors_within_limits(byte * replace_table) { int y; int x; byte* pixel; // Pour chaque ligne : for(y = Limit_top;y <= Limit_bottom; y++) { // Pour chaque pixel sur la ligne : for (x = Limit_left;x <= Limit_right;x ++) { pixel = Main_backups->Pages->Image[Main_current_layer]+y*Main_image_width+x; *pixel = replace_table[*pixel]; } } } byte Read_pixel_from_backup_screen (word x,word y) { return *(Screen_backup + x + Main_image_width * y); } void Palette_256_to_64(T_Palette palette) { int i; for(i=0;i<256;i++) { palette[i].R = palette[i].R >> 2; palette[i].G = palette[i].G >> 2; palette[i].B = palette[i].B >> 2; } } void Palette_64_to_256(T_Palette palette) { int i; for(i=0;i<256;i++) { palette[i].R = (palette[i].R << 2)|(palette[i].R >> 4); palette[i].G = (palette[i].G << 2)|(palette[i].G >> 4); palette[i].B = (palette[i].B << 2)|(palette[i].B >> 4); } } byte Effect_interpolated_colorize (word x,word y,byte color) { // factor_a = 256*(100-Colorize_opacity)/100 // factor_b = 256*( Colorize_opacity)/100 // // (Couleur_dessous*factor_a+color*facteur_B)/256 // // On place dans ESI 3*Couleur_dessous ( = position de cette couleur dans la // palette des teintes) et dans EDI, 3*color. byte color_under = Read_pixel_from_feedback_screen(x,y); byte blue_under=Main_palette[color_under].B; byte blue=Main_palette[color].B; byte green_under=Main_palette[color_under].G; byte green=Main_palette[color].G; byte red_under=Main_palette[color_under].R; byte red=Main_palette[color].R; // On rcupre les 3 composantes RVB // blue blue = (Factors_inv_table[blue] + Factors_table[blue_under]) / 256; green = (Factors_inv_table[green] + Factors_table[green_under]) / 256; red = (Factors_inv_table[red] + Factors_table[red_under]) / 256; return Best_color(red,green,blue); } byte Effect_additive_colorize (word x,word y,byte color) { byte color_under = Read_pixel_from_feedback_screen(x,y); byte blue_under=Main_palette[color_under].B; byte green_under=Main_palette[color_under].G; byte red_under=Main_palette[color_under].R; byte blue=Main_palette[color].B; byte green=Main_palette[color].G; byte red=Main_palette[color].R; return Best_color( red>red_under?red:red_under, green>green_under?green:green_under, blue>blue_under?blue:blue_under); } byte Effect_substractive_colorize(word x,word y,byte color) { byte color_under = Read_pixel_from_feedback_screen(x,y); byte blue_under=Main_palette[color_under].B; byte green_under=Main_palette[color_under].G; byte red_under=Main_palette[color_under].R; byte blue=Main_palette[color].B; byte green=Main_palette[color].G; byte red=Main_palette[color].R; return Best_color( redTimer_start) Timer_state=1; } 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 = src ; byte* EDI = src + (height - 1) *width; byte tmp; word cx; while(ESI < EDI) { // Il faut inverser les lignes pointes par ESI et // EDI ("Brush_width" octets en tout) for(cx = width;cx>0;cx--) { tmp = *ESI; *ESI = *EDI; *EDI = tmp; ESI++; EDI++; } // On change de ligne : // ESI pointe dj sur le dbut de la ligne suivante // EDI pointe sur la fin de la ligne en cours, il // doit pointer sur le dbut de la prcdente... EDI -= 2 * width; // On recule de 2 lignes } } void Flip_X_lowlevel(byte *src, short width, short height) { // ESI pointe sur la partie gauche et EDI sur la partie // droite byte* ESI = src; byte* EDI = src + width - 1; byte* line_start; byte* line_end; byte tmp; word cx; while(ESI0;cx--) { tmp=*ESI; *ESI=*EDI; *EDI=tmp; EDI+=width; ESI+=width; } // On change de colonne // ESI > colonne suivante // EDI > colonne prcdente ESI = line_start + 1; EDI = line_end - 1; } } // Rotate a pixel buffer 180 on itself. void Rotate_180_deg_lowlevel(byte *src, short width, short height) { // ESI pointe sur la partie suprieure de la brosse // EDI pointe sur la partie basse 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 pointes par EDI et // ESI (Brush_width octets) // En mme temps, on change les pixels, donc EDI // pointe sur la FIN de sa ligne for(cx=width;cx>0;cx--) { tmp = *ESI; *ESI = *EDI; *EDI = tmp; EDI--; // Attention ici on recule ! ESI++; } } } 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 incrmental" du point prcdent int delta_y_in_brush; int initial_x_pos; // Position X de dbut de parcours de ligne // Calcul du "vecteur incrmental": 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 Scroll_picture(byte * main_src, byte * main_dest, short x_offset,short y_offset) { byte* src = main_src; //source de la copie byte* dest = main_dest + y_offset * Main_image_width + x_offset; const word length = Main_image_width - x_offset; // Nombre de pixels copier droite word y; for(y = Main_image_height - y_offset;y>0;y--) { // Pour chaque ligne memcpy(dest,src,length); memcpy(dest - x_offset,src+length,x_offset); // On passe la ligne suivante dest += Main_image_width; src += Main_image_width; } // On vient de faire le traitement pour otutes les lignes au-dessous de y_offset // Maintenant on traite celles au dessus dest = x_offset + main_dest; for(y = y_offset;y>0;y--) { memcpy(dest,src,length); memcpy(dest - x_offset,src+length,x_offset); dest += Main_image_width; src += Main_image_width; } Update_rect(0,0,0,0); } void Zoom_a_line(byte* original_line, byte* zoomed_line, word factor, word width ) { byte color; word x; // Pour chaque pixel for(x=0;x #elif defined(__macosx__) || defined(__FreeBSD__) || defined(__NetBSD__) #include #elif defined(__BEOS__) || defined(__HAIKU__) // sysinfo not implemented #elif defined(__AROS__) || defined(__amigaos4__) || defined(__MORPHOS__) || defined(__amigaos__) #include #elif defined(__MINT__) #include #include #elif defined(__SKYOS__) #include #else #include // sysinfo() for free RAM #endif #if defined (__MINT__) // atari have two kinds of memory // standard and fast ram void Atari_Memory_free(unsigned long *stRam,unsigned long *ttRam){ //TODO: return STRAM/TT-RAM unsigned long mem=0; *stRam=Mxalloc(-1L,0); *ttRam = Mxalloc(-1L,1); } #else // Indique quelle est la mmoire disponible unsigned long Memory_free(void) { // Memory is no longer relevant. If there is ANY problem or doubt here, // you can simply return 10*1024*1024 (10Mb), to make the "Pages"something // memory allocation functions happy. // However, it is still a good idea to make a proper function if you can... // If Grafx2 thinks the memory is full, weird things may happen. And if memory // ever becomes full and you're still saying there are 10MB free here, the // program will crash without saving any picture backup ! You've been warned... #if defined(__WIN32__) MEMORYSTATUS mstt; mstt.dwLength = sizeof(MEMORYSTATUS); GlobalMemoryStatus(&mstt); return mstt.dwAvailPhys; #elif defined(__macosx__) || defined(__FreeBSD__) || defined(__NetBSD__) int mib[2]; int maxmem; size_t len; mib[0] = CTL_HW; mib[1] = HW_USERMEM; len = sizeof(maxmem); sysctl(mib,2,&maxmem,&len,NULL,0); return maxmem; #elif defined(__BEOS__) || defined(__HAIKU__) || defined(__SKYOS__) || defined(__amigaos4__) || defined(__TRU64__) // No on BeOS or Haiku // AvailMem is misleading on os4 (os4 caches stuff in memory that you can still allocate) #warning "There is missing code there for your platform ! please check and correct :)" return 10*1024*1024; #elif defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) return AvailMem(MEMF_ANY); #else struct sysinfo info; sysinfo(&info); return info.freeram*info.mem_unit; #endif } #endif // Arrondir un nombre rel la valeur entire la plus proche // TODO : this should probably be replaced with round() from C99... short Round(float value) { short temp=value; if (value>=0) { if ((value-temp)>= 0.5) temp++; } else { if ((value-temp)<=-0.5) temp--; } return temp; } // Arrondir le rsultat d'une division la valeur entire suprieure short Round_div_max(short numerator,short divisor) { if (!(numerator % divisor)) return (numerator/divisor); else return (numerator/divisor)+1; } // Retourne le minimum entre deux nombres int Min(int a,int b) { return (ab)?a:b; } /* Round number n to d decimal points */ double Fround(double n, unsigned d) { double exp; exp = pow(10.0, d); return floor(n * exp + 0.5) / exp; } // Fonction retournant le libell d'une mode (ex: " 320x200") char * Mode_label(int mode) { static char str[24]; if (! Video_mode[mode].Fullscreen) return "window"; sprintf(str, "%dx%d", Video_mode[mode].Width, Video_mode[mode].Height); return str; } // Trouve un mode video partir d'une chaine: soit "window", // soit de la forme "320x200" // Renvoie -1 si la chaine n'est pas convertible int Convert_videomode_arg(const char *argument) { // Je suis paresseux alors je vais juste tester les libells int mode_index; for (mode_index=0; mode_index */ ///@file miscfileformats.c /// Formats that aren't fully saving, either because of palette restrictions or other things #include #include #include "engine.h" #include "errors.h" #include "global.h" #include "io.h" #include "libraw2crtc.h" #include "limits.h" #include "loadsave.h" #include "misc.h" #include "sdlscreen.h" #include "struct.h" #include "windows.h" //////////////////////////////////// PAL //////////////////////////////////// // // -- Tester si un fichier est au format PAL -------------------------------- void Test_PAL(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier long file_size; // Taille du fichier Get_full_filename(filename, context->File_name, context->File_directory); File_error = 1; // Ouverture du fichier if ((file = fopen(filename, "rb"))) { // Lecture de la taille du fichier file_size = File_length_file(file); // Le fichier ne peut tre au format PAL que si sa taille vaut 768 octets if (file_size == sizeof(T_Palette)) File_error = 0; else { // Sinon c'est peut tre un fichier palette ASCII "Jasc" fread(filename, 1, 8, file); if (strncmp(filename,"JASC-PAL",8) == 0) { File_error = 0; } } fclose(file); } } // -- Lire un fichier au format PAL ----------------------------------------- void Load_PAL(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier //long file_size; // Taille du fichier Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { long file_size = File_length_file(file); // Le fichier ne peut tre au format PAL que si sa taille vaut 768 octets if (file_size == sizeof(T_Palette)) { T_Palette palette_64; // Pre_load(context, ?); // Pas possible... pas d'image... // Lecture du fichier dans context->Palette if (Read_bytes(file, palette_64, sizeof(T_Palette))) { Palette_64_to_256(palette_64); memcpy(context->Palette, palette_64, sizeof(T_Palette)); Palette_loaded(context); } else File_error = 2; } else { fread(filename, 1, 8, file); if (strncmp(filename,"JASC-PAL",8) == 0) { int i, n, r, g, b; fscanf(file, "%d",&n); if(n != 100) { File_error = 2; fclose(file); return; } // Read color count fscanf(file, "%d",&n); for (i = 0; i < n; i++) { fscanf(file, "%d %d %d",&r, &g, &b); context->Palette[i].R = r; context->Palette[i].G = g; context->Palette[i].B = b; } Palette_loaded(context); } else File_error = 2; } // Fermeture du fichier fclose(file); } else // Si on n'a pas russi ouvrir le fichier, alors il y a eu une erreur File_error=1; } // -- Sauver un fichier au format PAL --------------------------------------- void Save_PAL(T_IO_Context * context) { FILE *file; char filename[MAX_PATH_CHARACTERS]; ///< full filename Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; // Open output file if ((file=fopen(filename,"w"))) { int i; if (fputs("JASC-PAL\n0100\n256\n", file)==EOF) File_error=1; for (i = 0; i < 256 && File_error==0; i++) { if (fprintf(file,"%d %d %d\n",context->Palette[i].R, context->Palette[i].G, context->Palette[i].B) <= 0) File_error=1; } fclose(file); if (File_error) remove(filename); } else { // unable to open output file, nothing saved. File_error=1; } } //////////////////////////////////// PKM //////////////////////////////////// typedef struct { char Ident[3]; // String "PKM" } byte Method; // Compression method // 0 = per-line compression (c)KM // others = unknown at the moment byte Recog1; // Recognition byte 1 byte Recog2; // Recognition byte 2 word Width; // Image width word Height; // Image height T_Palette Palette;// RGB Palette 256*3, on a 1-64 scale for each component word Jump; // Size of the jump between header and image: // Used to insert a comment } T_PKM_Header; // -- Tester si un fichier est au format PKM -------------------------------- void Test_PKM(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier T_PKM_Header header; Get_full_filename(filename, context->File_name, context->File_directory); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Lecture du header du fichier if (Read_bytes(file,&header.Ident,3) && Read_byte(file,&header.Method) && Read_byte(file,&header.Recog1) && Read_byte(file,&header.Recog2) && Read_word_le(file,&header.Width) && Read_word_le(file,&header.Height) && Read_bytes(file,&header.Palette,sizeof(T_Palette)) && Read_word_le(file,&header.Jump)) { // On regarde s'il y a la signature PKM suivie de la mthode 0. // La constante "PKM" tant un chane, elle se termine toujours par 0. // Donc pas la peine de s'emm...er regarder si la mthode est 0. if ( (!memcmp(&header,"PKM",4)) && header.Width && header.Height) File_error=0; } fclose(file); } } // -- Lire un fichier au format PKM ----------------------------------------- void Load_PKM(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier T_PKM_Header header; byte color; byte temp_byte; word len; word index; dword Compteur_de_pixels; dword Compteur_de_donnees_packees; dword image_size; dword Taille_pack; long file_size; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); if (Read_bytes(file,&header.Ident,3) && Read_byte(file,&header.Method) && Read_byte(file,&header.Recog1) && Read_byte(file,&header.Recog2) && Read_word_le(file,&header.Width) && Read_word_le(file,&header.Height) && Read_bytes(file,&header.Palette,sizeof(T_Palette)) && Read_word_le(file,&header.Jump)) { context->Comment[0]='\0'; // On efface le commentaire if (header.Jump) { index=0; while ( (indexCOMMENT_SIZE) { color=temp_byte; // On se sert de color comme temp_byte=COMMENT_SIZE; // variable temporaire color-=COMMENT_SIZE; } else color=0; if (Read_bytes(file,context->Comment,temp_byte)) { index+=temp_byte; context->Comment[temp_byte]='\0'; if (color) if (fseek(file,color,SEEK_CUR)) File_error=2; } else File_error=2; } else File_error=2; break; case 1 : // Dimensions de l'cran d'origine if (Read_byte(file,&temp_byte)) { if (temp_byte==4) { index+=4; if ( ! Read_word_le(file,(word *) &Original_screen_X) || !Read_word_le(file,(word *) &Original_screen_Y) ) File_error=2; } else File_error=2; } else File_error=2; break; case 2 : // color de transparence if (Read_byte(file,&temp_byte)) { if (temp_byte==1) { index++; if (! Read_byte(file,&Back_color)) File_error=2; } else File_error=2; } else File_error=2; break; default: if (Read_byte(file,&temp_byte)) { index+=temp_byte; if (fseek(file,temp_byte,SEEK_CUR)) File_error=2; } else File_error=2; } } else File_error=2; } if ( (!File_error) && (index!=header.Jump) ) File_error=2; } /*Init_lecture();*/ if (!File_error) { Pre_load(context, header.Width,header.Height,file_size,FORMAT_PKM,PIXEL_SIMPLE,0); if (File_error==0) { context->Width=header.Width; context->Height=header.Height; image_size=(dword)(context->Width*context->Height); // Palette lue en 64 memcpy(context->Palette,header.Palette,sizeof(T_Palette)); Palette_64_to_256(context->Palette); Palette_loaded(context); Compteur_de_donnees_packees=0; Compteur_de_pixels=0; // Header size is 780 Taille_pack=(file_size)-780-header.Jump; // Boucle de dcompression: while ( (Compteur_de_pixelsWidth, Compteur_de_pixels / context->Width, temp_byte); Compteur_de_donnees_packees++; Compteur_de_pixels++; } else // Sinon, On regarde si on va dcompacter un... { // ... nombre de pixels tenant sur un byte if (temp_byte==header.Recog1) { if(Read_byte(file, &color)!=1) { File_error=2; break; } if(Read_byte(file, &temp_byte)!=1) { File_error=2; break; } for (index=0; indexWidth, (Compteur_de_pixels+index) / context->Width, color); Compteur_de_pixels+=temp_byte; Compteur_de_donnees_packees+=3; } else // ... nombre de pixels tenant sur un word { if(Read_byte(file, &color)!=1) { File_error=2; break; } Read_word_be(file, &len); for (index=0; indexWidth, (Compteur_de_pixels+index) / context->Width, color); Compteur_de_pixels+=len; Compteur_de_donnees_packees+=4; } } } } } /*Close_lecture();*/ } else // Lecture header impossible: Error ne modifiant pas l'image File_error=1; fclose(file); } else // Ouv. fichier impossible: Error ne modifiant pas l'image File_error=1; } // -- Sauver un fichier au format PKM --------------------------------------- // Trouver quels sont les octets de reconnaissance void Find_recog(byte * recog1, byte * recog2) { dword Find_recon[256]; // Table d'utilisation de couleurs byte best; // Meilleure couleur pour recon (recon1 puis recon2) dword NBest; // Nombre d'occurences de cette couleur word index; // On commence par compter l'utilisation de chaque couleurs Count_used_colors(Find_recon); // Ensuite recog1 devient celle la moins utilise de celles-ci *recog1=0; best=1; NBest=INT_MAX; // Une mme couleur ne pourra jamais tre utilise 1M de fois. for (index=1;index<=255;index++) if (Find_recon[index]Width; header.Height=context->Height; memcpy(header.Palette,context->Palette,sizeof(T_Palette)); Palette_256_to_64(header.Palette); // Calcul de la taille du Post-header header.Jump=9; // 6 pour les dimensions de l'ecran + 3 pour la back-color comment_size=strlen(context->Comment); if (comment_size) header.Jump+=comment_size+2; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; // Ouverture du fichier if ((file=fopen(filename,"wb"))) { // Ecriture du header if (Write_bytes(file,&header.Ident,3) && Write_byte(file,header.Method) && Write_byte(file,header.Recog1) && Write_byte(file,header.Recog2) && Write_word_le(file,header.Width) && Write_word_le(file,header.Height) && Write_bytes(file,&header.Palette,sizeof(T_Palette)) && Write_word_le(file,header.Jump)) { Init_write_buffer(); // Ecriture du commentaire // (Compteur_de_pixels est utilis ici comme simple index de comptage) if (comment_size) { Write_one_byte(file,0); Write_one_byte(file,comment_size); for (Compteur_de_pixels=0; Compteur_de_pixelsComment[Compteur_de_pixels]); } // Ecriture des dimensions de l'cran Write_one_byte(file,1); Write_one_byte(file,4); Write_one_byte(file,Screen_width&0xFF); Write_one_byte(file,Screen_width>>8); Write_one_byte(file,Screen_height&0xFF); Write_one_byte(file,Screen_height>>8); // Ecriture de la back-color Write_one_byte(file,2); Write_one_byte(file,1); Write_one_byte(file,Back_color); // Routine de compression PKM de l'image image_size=(dword)(context->Width*context->Height); Compteur_de_pixels=0; pixel_value=Get_pixel(context, 0,0); while ( (Compteur_de_pixelsWidth,Compteur_de_pixels / context->Width); } while ( (pixel_value==last_color) && (Compteur_de_pixels=image_size) break; pixel_value=Get_pixel(context, Compteur_de_pixels % context->Width,Compteur_de_pixels / context->Width); } if ( (last_color!=header.Recog1) && (last_color!=header.Recog2) ) { if (repetitions==1) Write_one_byte(file,last_color); else if (repetitions==2) { Write_one_byte(file,last_color); Write_one_byte(file,last_color); } else if ( (repetitions>2) && (repetitions<256) ) { // RECON1/couleur/nombre Write_one_byte(file,header.Recog1); Write_one_byte(file,last_color); Write_one_byte(file,repetitions&0xFF); } else if (repetitions>=256) { // RECON2/couleur/hi(nombre)/lo(nombre) Write_one_byte(file,header.Recog2); Write_one_byte(file,last_color); Write_one_byte(file,repetitions>>8); Write_one_byte(file,repetitions&0xFF); } } else { if (repetitions<256) { Write_one_byte(file,header.Recog1); Write_one_byte(file,last_color); Write_one_byte(file,repetitions&0xFF); } else { Write_one_byte(file,header.Recog2); Write_one_byte(file,last_color); Write_one_byte(file,repetitions>>8); Write_one_byte(file,repetitions&0xFF); } } } End_write(file); } else File_error=1; fclose(file); } else { File_error=1; fclose(file); } // S'il y a eu une erreur de sauvegarde, on ne va tout de mme pas laisser // ce fichier pourri traner... Ca fait pas propre. if (File_error) remove(filename); } //////////////////////////////////// CEL //////////////////////////////////// typedef struct { word Width; // width de l'image word Height; // height de l'image } T_CEL_Header1; typedef struct { byte Signature[4]; // Signature du format byte Kind; // Type de fichier ($10=PALette $20=BitMaP) byte Nb_bits; // Nombre de bits word Filler1; // ??? word Width; // width de l'image word Height; // height de l'image word X_offset; // Offset en X de l'image word Y_offset; // Offset en Y de l'image byte Filler2[16]; // ??? } T_CEL_Header2; // -- Tester si un fichier est au format CEL -------------------------------- void Test_CEL(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; int size; FILE *file; T_CEL_Header1 header1; T_CEL_Header2 header2; int file_size; File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); file_size=File_length(filename); if (file_size==0) { File_error = 1; // Si on ne peut pas faire de stat il vaut mieux laisser tomber return; } if (! (file=fopen(filename, "rb"))) { File_error = 1; return; } if (Read_word_le(file,&header1.Width) && Read_word_le(file,&header1.Height) ) { // Vu que ce header n'a pas de signature, il va falloir tester la // cohrence de la dimension de l'image avec celle du fichier. size=file_size-4; if ( (!size) || ( (((header1.Width+1)>>1)*header1.Height)!=size ) ) { // Tentative de reconnaissance de la signature des nouveaux fichiers fseek(file,0,SEEK_SET); if (Read_bytes(file,&header2.Signature,4) && !memcmp(header2.Signature,"KiSS",4) && Read_byte(file,&header2.Kind) && (header2.Kind==0x20) && Read_byte(file,&header2.Nb_bits) && Read_word_le(file,&header2.Filler1) && Read_word_le(file,&header2.Width) && Read_word_le(file,&header2.Height) && Read_word_le(file,&header2.X_offset) && Read_word_le(file,&header2.Y_offset) && Read_bytes(file,&header2.Filler2,16)) { // ok } else File_error=1; } else File_error=1; } else { File_error=1; } fclose(file); } // -- Lire un fichier au format CEL ----------------------------------------- void Load_CEL(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; T_CEL_Header1 header1; T_CEL_Header2 header2; short x_pos; short y_pos; byte last_byte=0; long file_size; const long int header_size = 4; File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); if ((file=fopen(filename, "rb"))) { if (Read_word_le(file,&(header1.Width)) && Read_word_le(file,&(header1.Height))) { file_size=File_length_file(file); if ( (file_size>header_size) && ( (((header1.Width+1)>>1)*header1.Height)==(file_size-header_size) ) ) { // Chargement d'un fichier CEL sans signature (vieux fichiers) context->Width=header1.Width; context->Height=header1.Height; Original_screen_X=context->Width; Original_screen_Y=context->Height; Pre_load(context, context->Width,context->Height,file_size,FORMAT_CEL,PIXEL_SIMPLE,0); if (File_error==0) { // Chargement de l'image /*Init_lecture();*/ for (y_pos=0;((y_posHeight) && (!File_error));y_pos++) for (x_pos=0;((x_posWidth) && (!File_error));x_pos++) if ((x_pos & 1)==0) { if(Read_byte(file,&last_byte)!=1) File_error = 2; Set_pixel(context, x_pos,y_pos,(last_byte >> 4)); } else Set_pixel(context, x_pos,y_pos,(last_byte & 15)); /*Close_lecture();*/ } } else { // On ressaye avec le nouveau format fseek(file,0,SEEK_SET); if (Read_bytes(file,header2.Signature,4) && Read_byte(file,&(header2.Kind)) && Read_byte(file,&(header2.Nb_bits)) && Read_word_le(file,&(header2.Filler1)) && Read_word_le(file,&(header2.Width)) && Read_word_le(file,&(header2.Height)) && Read_word_le(file,&(header2.X_offset)) && Read_word_le(file,&(header2.Y_offset)) && Read_bytes(file,header2.Filler2,16) ) { // Chargement d'un fichier CEL avec signature (nouveaux fichiers) context->Width=header2.Width+header2.X_offset; context->Height=header2.Height+header2.Y_offset; Original_screen_X=context->Width; Original_screen_Y=context->Height; Pre_load(context, context->Width,context->Height,file_size,FORMAT_CEL,PIXEL_SIMPLE,0); if (File_error==0) { // Chargement de l'image /*Init_lecture();*/ if (!File_error) { // Effacement du dcalage for (y_pos=0;y_posWidth;x_pos++) Set_pixel(context, x_pos,y_pos,0); for (y_pos=header2.Y_offset;y_posHeight;y_pos++) for (x_pos=0;x_pos> 4)); } else Set_pixel(context, x_pos+header2.X_offset,y_pos+header2.Y_offset,(last_byte & 15)); break; case 8: for (y_pos=0;((y_posFile_name, context->File_directory); if ((file=fopen(filename,"wb"))) { // On regarde si des couleurs >16 sont utilises dans l'image for (x_pos=16;((x_pos<256) && (!Utilisation[x_pos]));x_pos++); if (x_pos==256) { // Cas d'une image 16 couleurs (criture l'ancien format) header1.Width =context->Width; header1.Height=context->Height; if (Write_word_le(file,header1.Width) && Write_word_le(file,header1.Height) ) { // Sauvegarde de l'image Init_write_buffer(); for (y_pos=0;((y_posHeight) && (!File_error));y_pos++) { for (x_pos=0;((x_posWidth) && (!File_error));x_pos++) if ((x_pos & 1)==0) last_byte=(Get_pixel(context, x_pos,y_pos) << 4); else { last_byte=last_byte | (Get_pixel(context, x_pos,y_pos) & 15); Write_one_byte(file,last_byte); } if ((x_pos & 1)==1) Write_one_byte(file,last_byte); } End_write(file); } else File_error=1; fclose(file); } else { // Cas d'une image 256 couleurs (criture au nouveau format) // Recherche du dcalage for (y_pos=0;y_posHeight;y_pos++) { for (x_pos=0;x_posWidth;x_pos++) if (Get_pixel(context, x_pos,y_pos)!=0) break; if (Get_pixel(context, x_pos,y_pos)!=0) break; } header2.Y_offset=y_pos; for (x_pos=0;x_posWidth;x_pos++) { for (y_pos=0;y_posHeight;y_pos++) if (Get_pixel(context, x_pos,y_pos)!=0) break; if (Get_pixel(context, x_pos,y_pos)!=0) break; } header2.X_offset=x_pos; memcpy(header2.Signature,"KiSS",4); // Initialisation de la signature header2.Kind=0x20; // Initialisation du type (BitMaP) header2.Nb_bits=8; // Initialisation du nombre de bits header2.Filler1=0; // Initialisation du filler 1 (?) header2.Width=context->Width-header2.X_offset; // Initialisation de la largeur header2.Height=context->Height-header2.Y_offset; // Initialisation de la hauteur for (x_pos=0;x_pos<16;x_pos++) // Initialisation du filler 2 (?) header2.Filler2[x_pos]=0; if (Write_bytes(file,header2.Signature,4) && Write_byte(file,header2.Kind) && Write_byte(file,header2.Nb_bits) && Write_word_le(file,header2.Filler1) && Write_word_le(file,header2.Width) && Write_word_le(file,header2.Height) && Write_word_le(file,header2.X_offset) && Write_word_le(file,header2.Y_offset) && Write_bytes(file,header2.Filler2,14) ) { // Sauvegarde de l'image Init_write_buffer(); for (y_pos=0;((y_posFile_name, context->File_directory); if ((file=fopen(filename, "rb"))) { if (File_length_file(file)==320) { for (pal_index=0;pal_index<10 && !File_error;pal_index++) for (color_index=0;color_index<16 && !File_error;color_index++) if (!Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte1) || !Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte2)) File_error=1; // On vrifie une proprit de la structure de palette: for (pal_index=0;pal_index<10;pal_index++) for (color_index=0;color_index<16;color_index++) if ((header1.Palette[pal_index].color[color_index].Byte2>>4)!=0) File_error=1; } else { if (Read_bytes(file,header2.Signature,4) && Read_byte(file,&(header2.Kind)) && Read_byte(file,&(header2.Nb_bits)) && Read_word_le(file,&(header2.Filler1)) && Read_word_le(file,&(header2.Width)) && Read_word_le(file,&(header2.Height)) && Read_word_le(file,&(header2.X_offset)) && Read_word_le(file,&(header2.Y_offset)) && Read_bytes(file,header2.Filler2,14) ) { if (memcmp(header2.Signature,"KiSS",4)==0) { if (header2.Kind!=0x10) File_error=1; } else File_error=1; } else File_error=1; } fclose(file); } else File_error=1; } // -- Lire un fichier au format KCF ----------------------------------------- void Load_KCF(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; T_KCF_Header header1; T_CEL_Header2 header2; byte bytes[3]; int pal_index; int color_index; int index; long file_size; File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); if (file_size==320) { // Fichier KCF l'ancien format for (pal_index=0;pal_index<10 && !File_error;pal_index++) for (color_index=0;color_index<16 && !File_error;color_index++) if (!Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte1) || !Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte2)) File_error=1; if (!File_error) { // Pre_load(context, ?); // Pas possible... pas d'image... if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); // Chargement de la palette for (pal_index=0;pal_index<10;pal_index++) for (color_index=0;color_index<16;color_index++) { index=16+(pal_index*16)+color_index; context->Palette[index].R=((header1.Palette[pal_index].color[color_index].Byte1 >> 4) << 4); context->Palette[index].B=((header1.Palette[pal_index].color[color_index].Byte1 & 15) << 4); context->Palette[index].G=((header1.Palette[pal_index].color[color_index].Byte2 & 15) << 4); } for (index=0;index<16;index++) { context->Palette[index].R=context->Palette[index+16].R; context->Palette[index].G=context->Palette[index+16].G; context->Palette[index].B=context->Palette[index+16].B; } Palette_loaded(context); } else File_error=1; } else { // Fichier KCF au nouveau format if (Read_bytes(file,header2.Signature,4) && Read_byte(file,&(header2.Kind)) && Read_byte(file,&(header2.Nb_bits)) && Read_word_le(file,&(header2.Filler1)) && Read_word_le(file,&(header2.Width)) && Read_word_le(file,&(header2.Height)) && Read_word_le(file,&(header2.X_offset)) && Read_word_le(file,&(header2.Y_offset)) && Read_bytes(file,header2.Filler2,14) ) { // Pre_load(context, ?); // Pas possible... pas d'image... index=(header2.Nb_bits==12)?16:0; for (pal_index=0;pal_indexPalette[index].R=(bytes[0] >> 4) << 4; context->Palette[index].B=(bytes[0] & 15) << 4; context->Palette[index].G=(bytes[1] & 15) << 4; break; case 24: // RRRR RRRR | VVVV VVVV | BBBB BBBB Read_bytes(file,bytes,3); context->Palette[index].R=bytes[0]; context->Palette[index].G=bytes[1]; context->Palette[index].B=bytes[2]; } index++; } } if (header2.Nb_bits==12) for (index=0;index<16;index++) { context->Palette[index].R=context->Palette[index+16].R; context->Palette[index].G=context->Palette[index+16].G; context->Palette[index].B=context->Palette[index+16].B; } Palette_loaded(context); } else File_error=1; } fclose(file); } else File_error=1; } // -- Ecrire un fichier au format KCF --------------------------------------- void Save_KCF(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; T_KCF_Header header1; T_CEL_Header2 header2; byte bytes[3]; int pal_index; int color_index; int index; dword Utilisation[256]; // Table d'utilisation de couleurs // On commence par compter l'utilisation de chaque couleurs Count_used_colors(Utilisation); File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); if ((file=fopen(filename,"wb"))) { // Sauvegarde de la palette // On regarde si des couleurs >16 sont utilises dans l'image for (index=16;((index<256) && (!Utilisation[index]));index++); if (index==256) { // Cas d'une image 16 couleurs (criture l'ancien format) for (pal_index=0;pal_index<10;pal_index++) for (color_index=0;color_index<16;color_index++) { index=16+(pal_index*16)+color_index; header1.Palette[pal_index].color[color_index].Byte1=((context->Palette[index].R>>4)<<4) | (context->Palette[index].B>>4); header1.Palette[pal_index].color[color_index].Byte2=context->Palette[index].G>>4; } // Write all for (pal_index=0;pal_index<10 && !File_error;pal_index++) for (color_index=0;color_index<16 && !File_error;color_index++) if (!Write_byte(file,header1.Palette[pal_index].color[color_index].Byte1) || !Write_byte(file,header1.Palette[pal_index].color[color_index].Byte2)) File_error=1; } else { // Cas d'une image 256 couleurs (criture au nouveau format) memcpy(header2.Signature,"KiSS",4); // Initialisation de la signature header2.Kind=0x10; // Initialisation du type (PALette) header2.Nb_bits=24; // Initialisation du nombre de bits header2.Filler1=0; // Initialisation du filler 1 (?) header2.Width=256; // Initialisation du nombre de couleurs header2.Height=1; // Initialisation du nombre de palettes header2.X_offset=0; // Initialisation du dcalage X header2.Y_offset=0; // Initialisation du dcalage Y for (index=0;index<16;index++) // Initialisation du filler 2 (?) header2.Filler2[index]=0; if (!Write_bytes(file,header2.Signature,4) || !Write_byte(file,header2.Kind) || !Write_byte(file,header2.Nb_bits) || !Write_word_le(file,header2.Filler1) || !Write_word_le(file,header2.Width) || !Write_word_le(file,header2.Height) || !Write_word_le(file,header2.X_offset) || !Write_word_le(file,header2.Y_offset) || !Write_bytes(file,header2.Filler2,14) ) File_error=1; for (index=0;(index<256) && (!File_error);index++) { bytes[0]=context->Palette[index].R; bytes[1]=context->Palette[index].G; bytes[2]=context->Palette[index].B; if (! Write_bytes(file,bytes,3)) File_error=1; } } fclose(file); if (File_error) remove(filename); } else File_error=1; } //////////////////////////////////// PI1 //////////////////////////////////// //// DECODAGE d'une partie d'IMAGE //// void PI1_8b_to_16p(byte * src,byte * dest) { int i; // index du pixel calculer word byte_mask; // Masque de decodage word w0,w1,w2,w3; // Les 4 words bien ordonns de la source byte_mask=0x8000; w0=(((word)src[0])<<8) | src[1]; w1=(((word)src[2])<<8) | src[3]; w2=(((word)src[4])<<8) | src[5]; w3=(((word)src[6])<<8) | src[7]; for (i=0;i<16;i++) { // Pour dcoder le pixel ni, il faut traiter les 4 words sur leur bit // correspondant celui du masque dest[i]=((w0 & byte_mask)?0x01:0x00) | ((w1 & byte_mask)?0x02:0x00) | ((w2 & byte_mask)?0x04:0x00) | ((w3 & byte_mask)?0x08:0x00); byte_mask>>=1; } } //// CODAGE d'une partie d'IMAGE //// void PI1_16p_to_8b(byte * src,byte * dest) { int i; // index du pixel calculer word byte_mask; // Masque de codage word w0,w1,w2,w3; // Les 4 words bien ordonns de la destination byte_mask=0x8000; w0=w1=w2=w3=0; for (i=0;i<16;i++) { // Pour coder le pixel ni, il faut modifier les 4 words sur leur bit // correspondant celui du masque w0|=(src[i] & 0x01)?byte_mask:0x00; w1|=(src[i] & 0x02)?byte_mask:0x00; w2|=(src[i] & 0x04)?byte_mask:0x00; w3|=(src[i] & 0x08)?byte_mask:0x00; byte_mask>>=1; } dest[0]=w0 >> 8; dest[1]=w0 & 0x00FF; dest[2]=w1 >> 8; dest[3]=w1 & 0x00FF; dest[4]=w2 >> 8; dest[5]=w2 & 0x00FF; dest[6]=w3 >> 8; dest[7]=w3 & 0x00FF; } //// DECODAGE de la PALETTE //// void PI1_decode_palette(byte * src,byte * palette) { int i; // Numro de la couleur traite int ip; // index dans la palette word w; // Word contenant le code // Schma d'un word = // // Low High // VVVV RRRR | 0000 BBBB // 0321 0321 | 0321 ip=0; for (i=0;i<16;i++) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN w=(((word)src[(i*2)+1]<<8) | (src[(i*2)+0])); // Traitement des couleurs rouge, verte et bleue: palette[ip++]=(((w & 0x0007) << 1) | ((w & 0x0008) >> 3)) << 4; palette[ip++]=(((w & 0x7000) >> 11) | ((w & 0x8000) >> 15)) << 4; palette[ip++]=(((w & 0x0700) >> 7) | ((w & 0x0800) >> 11)) << 4; #else w=(((word)src[(i*2+1)])|(((word)src[(i*2)])<<8)); palette[ip++] = (((w & 0x0700)>>7) | ((w & 0x0800) >> 7))<<4 ; palette[ip++]=(((w & 0x0070)>>3) | ((w & 0x0080) >> 3))<<4 ; palette[ip++] = (((w & 0x0007)<<1) | ((w & 0x0008)))<<4 ; #endif } } //// CODAGE de la PALETTE //// void PI1_code_palette(byte * palette,byte * dest) { int i; // Numro de la couleur traite int ip; // index dans la palette word w; // Word contenant le code // Schma d'un word = // // Low High // VVVV RRRR | 0000 BBBB // 0321 0321 | 0321 ip=0; for (i=0;i<16;i++) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN // Traitement des couleurs rouge, verte et bleue: w =(((word)(palette[ip]>>2) & 0x38) >> 3) | (((word)(palette[ip]>>2) & 0x04) << 1); ip++; w|=(((word)(palette[ip]>>2) & 0x38) << 9) | (((word)(palette[ip]>>2) & 0x04) << 13); ip++; w|=(((word)(palette[ip]>>2) & 0x38) << 5) | (((word)(palette[ip]>>2) & 0x04) << 9); ip++; dest[(i*2)+0]=w & 0x00FF; dest[(i*2)+1]=(w>>8); #else w=(((word)(palette[ip]<<3))&0x0700);ip++; w|=(((word)(palette[ip]>>1))&0x0070);ip++; w|=(((word)(palette[ip]>>5))&0x0007);ip++; dest[(i*2)+1]=w & 0x00FF; dest[(i*2)+0]=(w>>8); #endif } } // -- Tester si un fichier est au format PI1 -------------------------------- void Test_PI1(T_IO_Context * context) { FILE * file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier int size; // Taille du fichier word resolution; // Rsolution de l'image Get_full_filename(filename, context->File_name, context->File_directory); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Vrification de la taille size=File_length_file(file); if ((size==32034) || (size==32066)) { // Lecture et vrification de la rsolution if (Read_word_le(file,&resolution)) { if (resolution==0x0000) File_error=0; } } // Fermeture du fichier fclose(file); } } // -- Lire un fichier au format PI1 ----------------------------------------- void Load_PI1(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; word x_pos,y_pos; byte * buffer; byte * ptr; byte pixels[320]; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename, "rb"))) { // allocation d'un buffer mmoire buffer=(byte *)malloc(32034); if (buffer!=NULL) { // Lecture du fichier dans le buffer if (Read_bytes(file,buffer,32034)) { // Initialisation de la preview Pre_load(context, 320,200,File_length_file(file),FORMAT_PI1,PIXEL_SIMPLE,0); if (File_error==0) { // Initialisation de la palette if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); PI1_decode_palette(buffer+2,(byte *)context->Palette); Palette_loaded(context); context->Width=320; context->Height=200; // Chargement/dcompression de l'image ptr=buffer+34; for (y_pos=0;y_pos<200;y_pos++) { for (x_pos=0;x_pos<(320>>4);x_pos++) { PI1_8b_to_16p(ptr,pixels+(x_pos<<4)); ptr+=8; } for (x_pos=0;x_pos<320;x_pos++) Set_pixel(context, x_pos,y_pos,pixels[x_pos]); } } } else File_error=1; free(buffer); buffer = NULL; } else File_error=1; fclose(file); } else File_error=1; } // -- Sauver un fichier au format PI1 --------------------------------------- void Save_PI1(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; short x_pos,y_pos; byte * buffer; byte * ptr; byte pixels[320]; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; // Ouverture du fichier if ((file=fopen(filename,"wb"))) { // allocation d'un buffer mmoire buffer=(byte *)malloc(32066); // Codage de la rsolution buffer[0]=0x00; buffer[1]=0x00; // Codage de la palette PI1_code_palette((byte *)context->Palette,buffer+2); // Codage de l'image ptr=buffer+34; for (y_pos=0;y_pos<200;y_pos++) { // Codage de la ligne memset(pixels,0,320); if (y_posHeight) { for (x_pos=0;(x_pos<320) && (x_posWidth);x_pos++) pixels[x_pos]=Get_pixel(context, x_pos,y_pos); } for (x_pos=0;x_pos<(320>>4);x_pos++) { PI1_16p_to_8b(pixels+(x_pos<<4),ptr); ptr+=8; } } memset(buffer+32034,0,32); // 32 extra NULL bytes at the end of the file to make ST Deluxe Paint happy if (Write_bytes(file,buffer,32066)) { fclose(file); } else // Error d'criture (disque plein ou protg) { fclose(file); remove(filename); File_error=1; } // Libration du buffer mmoire free(buffer); buffer = NULL; } else { fclose(file); remove(filename); File_error=1; } } //////////////////////////////////// PC1 //////////////////////////////////// //// DECOMPRESSION d'un buffer selon la mthode PACKBITS //// void PC1_uncompress_packbits(byte * src,byte * dest) { int is,id; // Les indices de parcour des buffers int n; // Octet de contrle for (is=id=0;id<32000;) { n=src[is++]; if (n & 0x80) { // Recopier src[is] -n+1 fois n=257-n; for (;(n>0) && (id<32000);n--) dest[id++]=src[is]; is++; } else { // Recopier n+1 octets littralement n=n+1; for (;(n>0) && (id<32000);n--) dest[id++]=src[is++]; } // Contrle des erreurs if (n>0) File_error=1; } } //// COMPRESSION d'un buffer selon la mthode PACKBITS //// void PC1_compress_packbits(byte * src,byte * dest,int source_size,int * dest_size) { int is; // index dans la source int id; // index dans la destination int ir; // index de la rptition int n; // Taille des squences int repet; // "Il y a rptition" for (is=id=0;is0;n--) dest[id++]=src[is++]; } // On code la partie sans rptitions if (repet) { // On compte la quantit de fois qu'il faut rpter la valeur for (ir+=3;ir>=1; } } } //// CODAGE d'une partie d'IMAGE //// // Transformation d'1 ligne de pixels en 4 plans de bits void PC1_1line_to_4bp(byte * src,byte * dst0,byte * dst1,byte * dst2,byte * dst3) { int i,j; // Compteurs int ip; // index du pixel calculer byte byte_mask; // Masque de decodage byte b0,b1,b2,b3; // Les 4 octets des plans bits sources ip=0; // Pour chacun des 40 octets des plans de bits for (i=0;i<40;i++) { // Pour chacun des 8 bits des octets byte_mask=0x80; b0=b1=b2=b3=0; for (j=0;j<8;j++) { b0|=(src[ip] & 0x01)?byte_mask:0x00; b1|=(src[ip] & 0x02)?byte_mask:0x00; b2|=(src[ip] & 0x04)?byte_mask:0x00; b3|=(src[ip] & 0x08)?byte_mask:0x00; ip++; byte_mask>>=1; } dst0[i]=b0; dst1[i]=b1; dst2[i]=b2; dst3[i]=b3; } } // -- Tester si un fichier est au format PC1 -------------------------------- void Test_PC1(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier int size; // Taille du fichier word resolution; // Rsolution de l'image Get_full_filename(filename, context->File_name, context->File_directory); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Vrification de la taille size=File_length_file(file); if ((size<=32066)) { // Lecture et vrification de la rsolution if (Read_word_le(file,&resolution)) { if (resolution==0x0080) File_error=0; } } // Fermeture du fichier fclose(file); } } // -- Lire un fichier au format PC1 ----------------------------------------- void Load_PC1(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; int size; word x_pos,y_pos; byte * buffercomp; byte * bufferdecomp; byte * ptr; byte pixels[320]; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename, "rb"))) { size=File_length_file(file); // allocation des buffers mmoire buffercomp=(byte *)malloc(size); bufferdecomp=(byte *)malloc(32000); if ( (buffercomp!=NULL) && (bufferdecomp!=NULL) ) { // Lecture du fichier dans le buffer if (Read_bytes(file,buffercomp,size)) { // Initialisation de la preview Pre_load(context, 320,200,File_length_file(file),FORMAT_PC1,PIXEL_SIMPLE,0); if (File_error==0) { // Initialisation de la palette if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); PI1_decode_palette(buffercomp+2,(byte *)context->Palette); Palette_loaded(context); context->Width=320; context->Height=200; // Dcompression du buffer PC1_uncompress_packbits(buffercomp+34,bufferdecomp); // Dcodage de l'image ptr=bufferdecomp; for (y_pos=0;y_pos<200;y_pos++) { // Dcodage de la scanline PC1_4bp_to_1line(ptr,ptr+40,ptr+80,ptr+120,pixels); ptr+=160; // Chargement de la ligne for (x_pos=0;x_pos<320;x_pos++) Set_pixel(context, x_pos,y_pos,pixels[x_pos]); } } } else File_error=1; free(bufferdecomp); free(buffercomp); buffercomp = bufferdecomp = NULL; } else { File_error=1; free(bufferdecomp); free(buffercomp); buffercomp = bufferdecomp = NULL; } fclose(file); } else File_error=1; } // -- Sauver un fichier au format PC1 --------------------------------------- void Save_PC1(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; int size; short x_pos,y_pos; byte * buffercomp; byte * bufferdecomp; byte * ptr; byte pixels[320]; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; // Ouverture du fichier if ((file=fopen(filename,"wb"))) { // Allocation des buffers mmoire bufferdecomp=(byte *)malloc(32000); buffercomp =(byte *)malloc(64066); // Codage de la rsolution buffercomp[0]=0x80; buffercomp[1]=0x00; // Codage de la palette PI1_code_palette((byte *)context->Palette,buffercomp+2); // Codage de l'image ptr=bufferdecomp; for (y_pos=0;y_pos<200;y_pos++) { // Codage de la ligne memset(pixels,0,320); if (y_posHeight) { for (x_pos=0;(x_pos<320) && (x_posWidth);x_pos++) pixels[x_pos]=Get_pixel(context, x_pos,y_pos); } // Encodage de la scanline PC1_1line_to_4bp(pixels,ptr,ptr+40,ptr+80,ptr+120); ptr+=160; } // Compression du buffer PC1_compress_packbits(bufferdecomp,buffercomp+34,32000,&size); size+=34; for (x_pos=0;x_pos<16;x_pos++) buffercomp[size++]=0; if (Write_bytes(file,buffercomp,size)) { fclose(file); } else // Error d'criture (disque plein ou protg) { fclose(file); remove(filename); File_error=1; } // Libration des buffers mmoire free(bufferdecomp); free(buffercomp); buffercomp = bufferdecomp = NULL; } else { fclose(file); remove(filename); File_error=1; } } //////////////////////////////////// NEO //////////////////////////////////// void Test_NEO(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier int size; // Taille du fichier word resolution; // Rsolution de l'image Get_full_filename(filename, context->File_name, context->File_directory); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Vrification de la taille size=File_length_file(file); if ((size==32128)) { // Flag word : toujours 0 if (Read_word_le(file,&resolution)) { if (resolution == 0) File_error = 0; } // Lecture et vrification de la rsolution if (Read_word_le(file,&resolution)) { if (resolution==0 || resolution==1 || resolution==2) File_error |= 0; } } // Fermeture du fichier fclose(file); } } void Load_NEO(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; word x_pos,y_pos; byte * buffer; byte * ptr; byte pixels[320]; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename, "rb"))) { // allocation d'un buffer mmoire buffer=(byte *)malloc(32128); if (buffer!=NULL) { // Lecture du fichier dans le buffer if (Read_bytes(file,buffer,32128)) { // Initialisation de la preview Pre_load(context, 320,200,File_length_file(file),FORMAT_NEO,PIXEL_SIMPLE,0); if (File_error==0) { // Initialisation de la palette if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); // on saute la rsolution et le flag, chacun 2 bits PI1_decode_palette(buffer+4,(byte *)context->Palette); Palette_loaded(context); context->Width=320; context->Height=200; // Chargement/dcompression de l'image ptr=buffer+128; for (y_pos=0;y_pos<200;y_pos++) { for (x_pos=0;x_pos<(320>>4);x_pos++) { PI1_8b_to_16p(ptr,pixels+(x_pos<<4)); ptr+=8; } for (x_pos=0;x_pos<320;x_pos++) Set_pixel(context, x_pos,y_pos,pixels[x_pos]); } } } else File_error=1; free(buffer); buffer = NULL; } else File_error=1; fclose(file); } else File_error=1; } void Save_NEO(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; short x_pos,y_pos; byte * buffer; byte * ptr; byte pixels[320]; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; // Ouverture du fichier if ((file=fopen(filename,"wb"))) { // allocation d'un buffer mmoire buffer=(byte *)malloc(32128); // Codage de la rsolution buffer[0]=0x00; buffer[1]=0x00; buffer[2]=0x00; buffer[3]=0x00; // Codage de la palette PI1_code_palette((byte *)context->Palette,buffer+4); // Codage de l'image ptr=buffer+128; for (y_pos=0;y_pos<200;y_pos++) { // Codage de la ligne memset(pixels,0,320); if (y_posHeight) { for (x_pos=0;(x_pos<320) && (x_posWidth);x_pos++) pixels[x_pos]=Get_pixel(context, x_pos,y_pos); } for (x_pos=0;x_pos<(320>>4);x_pos++) { PI1_16p_to_8b(pixels+(x_pos<<4),ptr); ptr+=8; } } if (Write_bytes(file,buffer,32128)) { fclose(file); } else // Error d'criture (disque plein ou protg) { fclose(file); remove(filename); File_error=1; } // Libration du buffer mmoire free(buffer); buffer = NULL; } else { fclose(file); remove(filename); File_error=1; } } //////////////////////////////////// C64 //////////////////////////////////// void Test_C64(T_IO_Context * context) { FILE* file; char filename[MAX_PATH_CHARACTERS]; long file_size; Get_full_filename(filename, context->File_name, context->File_directory); file = fopen(filename,"rb"); if (file) { file_size = File_length_file(file); switch (file_size) { case 1000: // screen or color case 1002: // (screen or color) + loadaddr case 8000: // raw bitmap case 8002: // raw bitmap with loadaddr case 9000: // bitmap + screen case 9002: // bitmap + screen + loadaddr case 10001: // multicolor case 10003: // multicolor + loadaddr File_error = 0; break; default: // then we don't know for now. File_error = 1; } fclose (file); } else { File_error = 1; } } void Load_C64_hires(T_IO_Context *context, byte *bitmap, byte *colors) { int cx,cy,x,y,c[4],pixel,color; for(cy=0; cy<25; cy++) { for(cx=0; cx<40; cx++) { c[0]=colors[cy*40+cx]&15; c[1]=colors[cy*40+cx]>>4; for(y=0; y<8; y++) { pixel=bitmap[cy*320+cx*8+y]; for(x=0; x<8; x++) { color=c[pixel&(1<<(7-x))?1:0]; Set_pixel(context, cx*8+x,cy*8+y,color); } } } } } void Load_C64_multi(T_IO_Context *context, byte *bitmap, byte *colors, byte *nybble, byte background) { int cx,cy,x,y,c[4],pixel,color; c[0]=background&15; for(cy=0; cy<25; cy++) { for(cx=0; cx<40; cx++) { c[1]=colors[cy*40+cx]>>4; c[2]=colors[cy*40+cx]&15; c[3]=nybble[cy*40+cx]&15; for(y=0; y<8; y++) { pixel=bitmap[cy*320+cx*8+y]; for(x=0; x<4; x++) { color=c[(pixel&3)]; pixel>>=2; Set_pixel(context, cx*4+(3-x),cy*8+y,color); } } } } } void Load_C64(T_IO_Context * context) { FILE* file; char filename[MAX_PATH_CHARACTERS]; long file_size; int i; byte background,hasLoadAddr=0; int loadFormat=0; enum c64_format {F_hires,F_multi,F_bitmap,F_screen,F_color}; const char *c64_format_names[]={"hires","multicolor","bitmap","screen","color"}; // Palette from http://www.pepto.de/projects/colorvic/ byte pal[48]={ 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x68, 0x37, 0x2B, 0x70, 0xA4, 0xB2, 0x6F, 0x3D, 0x86, 0x58, 0x8D, 0x43, 0x35, 0x28, 0x79, 0xB8, 0xC7, 0x6F, 0x6F, 0x4F, 0x25, 0x43, 0x39, 0x00, 0x9A, 0x67, 0x59, 0x44, 0x44, 0x44, 0x6C, 0x6C, 0x6C, 0x9A, 0xD2, 0x84, 0x6C, 0x5E, 0xB5, 0x95, 0x95, 0x95}; byte bitmap[8000],colors[1000],nybble[1000]; word width=320, height=200; Get_full_filename(filename, context->File_name, context->File_directory); file = fopen(filename,"rb"); if (file) { File_error=0; file_size = File_length_file(file); switch (file_size) { case 1000: // screen or color hasLoadAddr=0; loadFormat=F_screen; break; case 1002: // (screen or color) + loadaddr hasLoadAddr=1; loadFormat=F_screen; break; case 8000: // raw bitmap hasLoadAddr=0; loadFormat=F_bitmap; break; case 8002: // raw bitmap with loadaddr hasLoadAddr=1; loadFormat=F_bitmap; break; case 9000: // bitmap + screen hasLoadAddr=0; loadFormat=F_hires; break; case 9002: // bitmap + screen + loadaddr hasLoadAddr=1; loadFormat=F_hires; break; case 10001: // multicolor hasLoadAddr=0; loadFormat=F_multi; break; case 10003: // multicolor + loadaddr hasLoadAddr=1; loadFormat=F_multi; break; default: // then we don't know what it is. File_error = 1; } memcpy(context->Palette,pal,48); // this set the software palette for grafx2 Palette_loaded(context); // Always call it if you change the palette if (file_size>9002) width=160; if (hasLoadAddr) { // get load address Read_byte(file,&background); Read_byte(file,&background); sprintf(filename,"load at $%02x00",background); } else { sprintf(filename,"no addr"); } if(file_size>9002) { context->Ratio = PIXEL_WIDE; } sprintf(context->Comment,"C64 %s, %s", c64_format_names[loadFormat],filename); Pre_load(context, width, height, file_size, FORMAT_C64, context->Ratio,0); // Do this as soon as you can context->Width = width ; context->Height = height; Read_bytes(file,bitmap,8000); if (file_size>8002) Read_bytes(file,colors,1000); else { for(i=0;i<1000;i++) { colors[i]=1; } } if(width==160) { Read_bytes(file,nybble,1000); Read_byte(file,&background); Load_C64_multi(context,bitmap,colors,nybble,background); } else { Load_C64_hires(context,bitmap,colors); } File_error = 0; fclose(file); } else File_error = 1; } int Save_C64_window(byte *saveWhat, byte *loadAddr) { int button; unsigned int i; T_Dropdown_button *what, *addr; char * what_label[] = { "All", "Bitmap", "Screen", "Color" }; char * address_label[] = { "None", "$2000", "$4000", "$6000", "$8000", "$A000", "$C000", "$E000" }; Open_window(200,120,"c64 settings"); Window_set_normal_button(110,100,80,15,"Save",1,1,SDLK_RETURN); Window_set_normal_button(10,100,80,15,"Cancel",1,1,SDLK_ESCAPE); Print_in_window(13,18,"Data:",MC_Dark,MC_Light); what=Window_set_dropdown_button(10,28,90,15,70,what_label[*saveWhat],1, 0, 1, LEFT_SIDE,0); Window_dropdown_clear_items(what); for (i=0; i2) { Warning_message("More than 2 colors in 8x8 pixels"); // TODO here we should hilite the offending block printf("\nerror at %dx%d (%d colors)\n",cx*8,cy*8,numcolors); return 1; } c1 = 0; c2 = 0; for(i=0;i<16;i++) { if(cusage[i]) { c2=i; break; } } c1=c2+1; for(i=c2;i<16;i++) { if(cusage[i]) { c1=i; } } colors[cx+cy*40]=(c2<<4)|c1; for(y=0; y<8; y++) { bits=0; for(x=0; x<8; x++) { pixel=Get_pixel(context, x+cx*8,y+cy*8); if(pixel>15) { Warning_message("Color above 15 used"); // TODO hilite offending block here too? // or make it smarter with color allocation? // However, the palette is fixed to the 16 first colors return 1; } bits=bits<<1; if (pixel==c2) bits|=1; } bitmap[pos++]=bits; //Write_byte(file,bits&255); } } } file = fopen(filename,"wb"); if(!file) { Warning_message("File open failed"); File_error = 1; return 1; } if (loadAddr) { Write_byte(file,0); Write_byte(file,loadAddr); } if (saveWhat==0 || saveWhat==1) Write_bytes(file,bitmap,8000); if (saveWhat==0 || saveWhat==2) Write_bytes(file,colors,1000); fclose(file); return 0; } int Save_C64_multi(T_IO_Context *context, char *filename, byte saveWhat, byte loadAddr) { /* BITS COLOR INFORMATION COMES FROM 00 Background color #0 (screen color) 01 Upper 4 bits of screen memory 10 Lower 4 bits of screen memory 11 Color nybble (nybble = 1/2 byte = 4 bits) */ int cx,cy,x,y,c[4]={0,0,0,0},color,lut[16],bits,pixel,pos=0; byte bitmap[8000],screen[1000],nybble[1000]; word numcolors,count; dword cusage[256]; byte i,background=0; FILE *file; numcolors=Count_used_colors(cusage); count=0; for(x=0;x<16;x++) { //printf("color %d, pixels %d\n",x,cusage[x]); if(cusage[x]>count) { count=cusage[x]; background=x; } } for(cy=0; cy<25; cy++) { //printf("\ny:%2d ",cy); for(cx=0; cx<40; cx++) { numcolors=Count_used_colors_area(cusage,cx*4,cy*8,4,8); if(numcolors>4) { Warning_message("More than 4 colors in 4x8"); // TODO hilite offending block return 1; } color=1; c[0]=background; for(i=0; i<16; i++) { lut[i]=0; if(cusage[i]) { if(i!=background) { lut[i]=color; c[color]=i; color++; } else { lut[i]=0; } } } // add to screen and nybble screen[cx+cy*40]=c[1]<<4|c[2]; nybble[cx+cy*40]=c[3]; //printf("%x%x%x ",c[1],c[2],c[3]); for(y=0;y<8;y++) { bits=0; for(x=0;x<4;x++) { pixel=Get_pixel(context, cx*4+x,cy*8+y); if(pixel>15) { Warning_message("Color above 15 used"); // TODO hilite as in hires, you should stay to // the fixed 16 color palette return 1; } bits=bits<<2; bits|=lut[pixel]; } //Write_byte(file,bits&255); bitmap[pos++]=bits; } } } file = fopen(filename,"wb"); if(!file) { Warning_message("File open failed"); File_error = 1; return 1; } if (loadAddr) { Write_byte(file,0); Write_byte(file,loadAddr); } if (saveWhat==0 || saveWhat==1) Write_bytes(file,bitmap,8000); if (saveWhat==0 || saveWhat==2) Write_bytes(file,screen,1000); if (saveWhat==0 || saveWhat==3) Write_bytes(file,nybble,1000); if (saveWhat==0) Write_byte(file,background); fclose(file); //printf("\nbg:%d\n",background); return 0; } void Save_C64(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; static byte saveWhat=0, loadAddr=0; dword numcolors,cusage[256]; numcolors=Count_used_colors(cusage); Get_full_filename(filename, context->File_name, context->File_directory); if (numcolors>16) { Warning_message("Error: Max 16 colors"); File_error = 1; return; } if (((context->Width!=320) && (context->Width!=160)) || context->Height!=200) { Warning_message("must be 320x200 or 160x200"); File_error = 1; return; } if(!Save_C64_window(&saveWhat,&loadAddr)) { File_error = 1; return; } //printf("saveWhat=%d, loadAddr=%d\n",saveWhat,loadAddr); if (context->Width==320) File_error = Save_C64_hires(context,filename,saveWhat,loadAddr); else File_error = Save_C64_multi(context,filename,saveWhat,loadAddr); } // SCR (Amstrad CPC) void Test_SCR(__attribute__((unused)) T_IO_Context * context) { // Mmh... not sure what we could test. Any idea ? // The palette file can be tested, if it exists and have the right size it's // ok. But if it's not there the pixel data may still be valid. And we can't // use the filesize as this depends on the screen format. // An AMSDOS header would be a good indication but in some cases it may not // be there } void Load_SCR(__attribute__((unused)) T_IO_Context * context) { // The Amstrad CPC screen memory is mapped in a weird mode, somewhere // between bitmap and textmode. Basically the only way to decode this is to // emulate the video chip and read the bytes as needed... // Moreover, the hardware allows the screen to have any size from 8x1 to // 800x273 pixels, and there is no indication of that in the file besides // its size. It can also use any of the 3 screen modes. Fortunately this // last bit of information is stored in the palette file. // Oh, and BTW, the picture can be offset, and it's even usual to do it, // because letting 128 pixels unused at the beginning of the file make it a // lot easier to handle screens using more than 16K of VRam. // The pixel encoding change with the video mode so we have to know that // before attempting to load anything... // As if this wasn't enough, Advanced OCP Art Studio, the reference tool on // Amstrad, can use RLE packing when saving files, meaning we also have to // handle that. // All this mess enforces us to load (and unpack if needed) the file to a // temporary 32k buffer before actually decoding it. // 1) Seek for a palette // 2) If palette found get screenmode from there, else ask user // 3) ask user for screen size (or register values) // 4) Load color data from palette (if found) // 5) Close palette // 6) Open the file // 7) Run around the screen to untangle the pixeldata // 8) Close the file } void Save_SCR(T_IO_Context * context) { // TODO : Add possibility to set R9, R12, R13 values // TODO : Add OCP packing support // TODO : Add possibility to include AMSDOS header, with proper loading // address guessed from r12/r13 values. unsigned char* output; unsigned long outsize; unsigned char r1; int cpc_mode; FILE* file; char filename[MAX_PATH_CHARACTERS]; Get_full_filename(filename, context->File_name, context->File_directory); switch(Pixel_ratio) { case PIXEL_WIDE: case PIXEL_WIDE2: cpc_mode = 0; break; case PIXEL_TALL: case PIXEL_TALL2: cpc_mode = 2; break; default: cpc_mode = 1; break; } output = raw2crtc(context->Width,context->Height,cpc_mode,7,&outsize,&r1,0,0); file = fopen(filename,"wb"); Write_bytes(file, output, outsize); fclose(file); free (output); output = NULL; File_error = 0; } grafx2/src/mountlist.c0000644000076400010400000006220111536457152015435 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* mountlist.c -- return a list of mounted file systems Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This program 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; either version 2, or (at your option) any later version. This program 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 this program; if not, see . */ // This file is not used on some platforms, so don't do anything for them #if(!defined(__WIN32__))&&(!defined(__amigaos4__))&&(!defined(__AROS__))&&(!defined(__MORPHOS__))&&(!defined(__amigaos__)) // We don't use autoconf and all that in grafx2, so let's do the config here ... #if defined(__macosx__) || defined(__FreeBSD__) // MacOS X is POSIX compliant #define MOUNTED_GETMNTINFO #if defined(__macosx__) #include #endif #elif defined(__NetBSD__) #define MOUNTED_GETMNTINFO2 #elif defined(__BEOS__) || defined(__HAIKU__) #define MOUNTED_FS_STAT_DEV #elif defined(__TRU64__) #define MOUNTED_GETFSSTAT 1 #define HAVE_SYS_MOUNT_H 1 #include #elif defined(__SKYOS__) #warning "Your platform is missing some specific code here ! please check and fix :)" #else #define MOUNTED_GETMNTENT1 #endif #define _XOPEN_SOURCE 500 // --- END GRAFX2 CUSTOM CONFIG --- #include "mountlist.h" #include #include #include #include #include #include #include #if HAVE_SYS_PARAM_H # include #endif #if defined MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */ # if HAVE_SYS_UCRED_H # include /* needed on OSF V4.0 for definition of NGROUPS, NGROUPS is used as an array dimension in ucred.h */ # include /* needed by powerpc-apple-darwin1.3.7 */ # endif # if HAVE_SYS_MOUNT_H # include # endif # if HAVE_SYS_FS_TYPES_H # include /* needed by powerpc-apple-darwin1.3.7 */ # endif # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME # define FS_TYPE(Ent) ((Ent).f_fstypename) # else # define FS_TYPE(Ent) mnt_names[(Ent).f_type] # endif #endif /* MOUNTED_GETFSSTAT */ #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ # include # if !defined MOUNTED # if defined _PATH_MOUNTED /* GNU libc */ # define MOUNTED _PATH_MOUNTED # endif # if defined MNT_MNTTAB /* HP-UX. */ # define MOUNTED MNT_MNTTAB # endif # if defined MNTTABNAME /* Dynix. */ # define MOUNTED MNTTABNAME # endif # endif #endif #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */ # include #endif #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */ # include #endif #ifdef MOUNTED_GETMNT /* Ultrix. */ # include # include #endif #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */ # include # include #endif #ifdef MOUNTED_FREAD /* SVR2. */ # include #endif #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */ # include # include # include #endif #ifdef MOUNTED_LISTMNTENT # include #endif #ifdef MOUNTED_GETMNTENT2 /* SVR4. */ # include #endif #ifdef MOUNTED_VMOUNT /* AIX. */ # include # include #endif #ifdef DOLPHIN /* So special that it's not worth putting this in autoconf. */ # undef MOUNTED_FREAD_FSTYP # define MOUNTED_GETMNTTBL #endif #if HAVE_SYS_MNTENT_H /* This is to get MNTOPT_IGNORE on e.g. SVR4. */ # include #endif #undef MNT_IGNORE #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE) #else # define MNT_IGNORE(M) 0 #endif #if USE_UNLOCKED_IO # include "unlocked-io.h" #endif #ifndef SIZE_MAX # define SIZE_MAX ((size_t) -1) #endif /* The results of open() in this file are not used with fchdir, therefore save some unnecessary work in fchdir.c. */ #undef open #undef close /* The results of opendir() in this file are not used with dirfd and fchdir, therefore save some unnecessary work in fchdir.c. */ #undef opendir #undef closedir // gcc2 under haiku and beos don't like these macros for some reason. // As they are not used there anyways, we remove them and everyone is happy. #if !defined(__HAIKU__) && !defined(__BEOS__) #ifndef ME_DUMMY # define ME_DUMMY(Fs_name, Fs_type) \ (strcmp (Fs_type, "autofs") == 0 \ || strcmp (Fs_type, "none") == 0 \ || strcmp (Fs_type, "proc") == 0 \ || strcmp (Fs_type, "subfs") == 0 \ || strcmp (Fs_type, "sysfs") == 0 \ || strcmp (Fs_type, "usbfs") == 0 \ || strcmp (Fs_type, "devpts") == 0 \ || strcmp (Fs_type, "tmpfs") == 0 \ /* for NetBSD 3.0 */ \ || strcmp (Fs_type, "kernfs") == 0 \ /* for Irix 6.5 */ \ || strcmp (Fs_type, "ignore") == 0 \ /* for MacOSX */ \ || strcmp (Fs_type, "devfs") == 0 \ || strcmp (Fs_type, "fdesc") == 0 \ || strcmp (Fs_type, "nfs") == 0 \ || strcmp (Fs_type, "volfs") == 0) #endif #ifndef ME_REMOTE /* A file system is `remote' if its Fs_name contains a `:' or if (it is of type (smbfs or cifs) and its Fs_name starts with `//'). */ # define ME_REMOTE(Fs_name, Fs_type) \ (strchr (Fs_name, ':') != NULL \ || ((Fs_name)[0] == '/' \ && (Fs_name)[1] == '/' \ && (strcmp (Fs_type, "smbfs") == 0 \ || strcmp (Fs_type, "cifs") == 0))) #endif #endif // HAIKU / BEOS #ifdef MOUNTED_GETMNTINFO # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME static char * fstype_to_string (short int t) { switch (t) { # ifdef MOUNT_PC case MOUNT_PC: return "pc"; # endif # ifdef MOUNT_MFS case MOUNT_MFS: return "mfs"; # endif # ifdef MOUNT_LO case MOUNT_LO: return "lo"; # endif # ifdef MOUNT_TFS case MOUNT_TFS: return "tfs"; # endif # ifdef MOUNT_TMP case MOUNT_TMP: return "tmp"; # endif # ifdef MOUNT_UFS case MOUNT_UFS: return "ufs" ; # endif # ifdef MOUNT_NFS case MOUNT_NFS: return "nfs" ; # endif # ifdef MOUNT_MSDOS case MOUNT_MSDOS: return "msdos" ; # endif # ifdef MOUNT_LFS case MOUNT_LFS: return "lfs" ; # endif # ifdef MOUNT_LOFS case MOUNT_LOFS: return "lofs" ; # endif # ifdef MOUNT_FDESC case MOUNT_FDESC: return "fdesc" ; # endif # ifdef MOUNT_PORTAL case MOUNT_PORTAL: return "portal" ; # endif # ifdef MOUNT_NULL case MOUNT_NULL: return "null" ; # endif # ifdef MOUNT_UMAP case MOUNT_UMAP: return "umap" ; # endif # ifdef MOUNT_KERNFS case MOUNT_KERNFS: return "kernfs" ; # endif # ifdef MOUNT_PROCFS case MOUNT_PROCFS: return "procfs" ; # endif # ifdef MOUNT_AFS case MOUNT_AFS: return "afs" ; # endif # ifdef MOUNT_CD9660 case MOUNT_CD9660: return "cd9660" ; # endif # ifdef MOUNT_UNION case MOUNT_UNION: return "union" ; # endif # ifdef MOUNT_DEVFS case MOUNT_DEVFS: return "devfs" ; # endif # ifdef MOUNT_EXT2FS case MOUNT_EXT2FS: return "ext2fs" ; # endif default: return "?"; } } # endif static char * fsp_to_string (const struct statfs *fsp) { # if HAVE_STRUCT_STATFS_F_FSTYPENAME return (char *) (fsp->f_fstypename); # else return fstype_to_string (fsp->f_type); # endif } #endif /* MOUNTED_GETMNTINFO */ #ifdef MOUNTED_VMOUNT /* AIX. */ static char * fstype_to_string (int t) { struct vfs_ent *e; e = getvfsbytype (t); if (!e || !e->vfsent_name) return "none"; else return e->vfsent_name; } #endif /* MOUNTED_VMOUNT */ #ifdef __linux__ #define BROKEN __attribute__((unused)) #else #define BROKEN #endif #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2 /* Return the device number from MOUNT_OPTIONS, if possible. Otherwise return (dev_t) -1. */ static dev_t dev_from_mount_options (BROKEN char const *mount_options) { /* GNU/Linux allows file system implementations to define their own meaning for "dev=" mount options, so don't trust the meaning here. */ # ifndef __linux__ static char const dev_pattern[] = ",dev="; char const *devopt = strstr (mount_options, dev_pattern); if (devopt) { char const *optval = devopt + sizeof dev_pattern - 1; char *optvalend; unsigned long int dev; errno = 0; dev = strtoul (optval, &optvalend, 16); if (optval != optvalend && (*optvalend == '\0' || *optvalend == ',') && ! (dev == ULONG_MAX && errno == ERANGE) && dev == (dev_t) dev) return dev; } # endif return -1; } #endif /* Return a list of the currently mounted file systems, or NULL on error. Add each entry to the tail of the list so that they stay in order. If NEED_FS_TYPE is true, ensure that the file system type fields in the returned list are valid. Otherwise, they might not be. */ struct mount_entry * read_file_system_list (BROKEN bool need_fs_type) { struct mount_entry *mount_list; struct mount_entry *me; struct mount_entry **mtail = &mount_list; #ifdef MOUNTED_LISTMNTENT { struct tabmntent *mntlist, *p; struct mntent *mnt; struct mount_entry *me; /* the third and fourth arguments could be used to filter mounts, but Crays doesn't seem to have any mounts that we want to remove. Specifically, automount create normal NFS mounts. */ if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0) return NULL; for (p = mntlist; p; p = p->next) { mnt = p->ment; me = xmalloc (sizeof *me); me->me_devname = xstrdup (mnt->mnt_fsname); me->me_mountdir = xstrdup (mnt->mnt_dir); me->me_type = xstrdup (mnt->mnt_type); me->me_type_malloced = 1; me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); me->me_remote = ME_REMOTE (me->me_devname, me->me_type); me->me_dev = -1; *mtail = me; mtail = &me->me_next; } freemntlist (mntlist); } #endif #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ { struct mntent *mnt; char *table = MOUNTED; FILE *fp; fp = setmntent (table, "r"); if (fp == NULL) return NULL; while ((mnt = getmntent (fp))) { me = malloc (sizeof *me); me->me_devname = strdup (mnt->mnt_fsname); me->me_mountdir = strdup (mnt->mnt_dir); me->me_type = strdup (mnt->mnt_type); me->me_type_malloced = 1; me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); me->me_remote = ME_REMOTE (me->me_devname, me->me_type); me->me_dev = dev_from_mount_options (mnt->mnt_opts); /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } if (endmntent (fp) == 0) goto free_then_fail; } #endif /* MOUNTED_GETMNTENT1. */ #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */ { struct statfs *fsp; int entries; entries = getmntinfo (&fsp, MNT_NOWAIT); if (entries < 0) return NULL; for (; entries-- > 0; fsp++) { me = malloc (sizeof *me); me->me_devname = strdup (fsp->f_mntfromname); me->me_mountdir = strdup (fsp->f_mntonname); #if defined(__macosx__) me->me_type = fsp->f_fstypename; #else me->me_type = fsp->fs_typename; #endif me->me_type_malloced = 0; me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); me->me_remote = ME_REMOTE (me->me_devname, me->me_type); me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } } #endif /* MOUNTED_GETMNTINFO */ #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */ { struct statvfs *fsp; int entries; entries = getmntinfo (&fsp, MNT_NOWAIT); if (entries < 0) return NULL; for (; entries-- > 0; fsp++) { me = malloc (sizeof *me); me->me_devname = strdup (fsp->f_mntfromname); me->me_mountdir = strdup (fsp->f_mntonname); me->me_type = strdup (fsp->f_fstypename); me->me_type_malloced = 1; me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); me->me_remote = ME_REMOTE (me->me_devname, me->me_type); me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } } #endif /* MOUNTED_GETMNTINFO2 */ #ifdef MOUNTED_GETMNT /* Ultrix. */ { int offset = 0; int val; struct fs_data fsd; while (errno = 0, 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, (char *) 0))) { me = xmalloc (sizeof *me); me->me_devname = xstrdup (fsd.fd_req.devname); me->me_mountdir = xstrdup (fsd.fd_req.path); me->me_type = gt_names[fsd.fd_req.fstype]; me->me_type_malloced = 0; me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); me->me_remote = ME_REMOTE (me->me_devname, me->me_type); me->me_dev = fsd.fd_req.dev; /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } if (val < 0) goto free_then_fail; } #endif /* MOUNTED_GETMNT. */ #if defined MOUNTED_FS_STAT_DEV /* BeOS */ { /* The next_dev() and fs_stat_dev() system calls give the list of all file systems, including the information returned by statvfs() (fs type, total blocks, free blocks etc.), but without the mount point. But on BeOS all file systems except / are mounted in the rootfs, directly under /. The directory name of the mount point is often, but not always, identical to the volume name of the device. We therefore get the list of subdirectories of /, and the list of all file systems, and match the two lists. */ DIR *dirp; struct rootdir_entry { char *name; dev_t dev; ino_t ino; struct rootdir_entry *next; }; struct rootdir_entry *rootdir_list; struct rootdir_entry **rootdir_tail; int32 pos; dev_t dev; fs_info fi; /* All volumes are mounted in the rootfs, directly under /. */ rootdir_list = NULL; rootdir_tail = &rootdir_list; dirp = opendir ("/"); if (dirp) { struct dirent *d; while ((d = readdir (dirp)) != NULL) { char *name; struct stat statbuf; if (strcmp (d->d_name, "..") == 0) continue; if (strcmp (d->d_name, ".") == 0) name = strdup ("/"); else { name = malloc (1 + strlen (d->d_name) + 1); name[0] = '/'; strcpy (name + 1, d->d_name); } if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode)) { struct rootdir_entry *re = malloc (sizeof *re); re->name = name; re->dev = statbuf.st_dev; re->ino = statbuf.st_ino; /* Add to the linked list. */ *rootdir_tail = re; rootdir_tail = &re->next; } else free (name); } closedir (dirp); } *rootdir_tail = NULL; for (pos = 0; (dev = next_dev (&pos)) >= 0; ) if (fs_stat_dev (dev, &fi) >= 0) { /* Note: fi.dev == dev. */ struct rootdir_entry *re; for (re = rootdir_list; re; re = re->next) if (re->dev == fi.dev && re->ino == fi.root) break; me = malloc (sizeof *me); me->me_devname = strdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name); me->me_mountdir = strdup (re != NULL ? re->name : fi.fsh_name); me->me_type = strdup (fi.fsh_name); me->me_type_malloced = 1; me->me_dev = fi.dev; me->me_dummy = 0; me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0; /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } *mtail = NULL; while (rootdir_list != NULL) { struct rootdir_entry *re = rootdir_list; rootdir_list = re->next; free (re->name); free (re); } } #endif /* MOUNTED_FS_STAT_DEV */ #if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */ { int numsys, counter; size_t bufsize; struct statfs *stats; numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT); if (numsys < 0) return (NULL); /* if (SIZE_MAX / sizeof *stats <= numsys) xalloc_die ();*/ bufsize = (1 + numsys) * sizeof *stats; stats = malloc (bufsize); numsys = getfsstat (stats, bufsize, MNT_NOWAIT); if (numsys < 0) { free (stats); return (NULL); } for (counter = 0; counter < numsys; counter++) { me = malloc (sizeof *me); me->me_devname = strdup (stats[counter].f_mntfromname); me->me_mountdir = strdup (stats[counter].f_mntonname); //me->me_type = strdup (FS_TYPE (stats[counter])); me->me_type_malloced = 1; me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); me->me_remote = ME_REMOTE (me->me_devname, me->me_type); me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } free (stats); } #endif /* MOUNTED_GETFSSTAT */ #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */ { struct mnttab mnt; char *table = "/etc/mnttab"; FILE *fp; fp = fopen (table, "r"); if (fp == NULL) return NULL; while (fread (&mnt, sizeof mnt, 1, fp) > 0) { me = xmalloc (sizeof *me); # ifdef GETFSTYP /* SVR3. */ me->me_devname = xstrdup (mnt.mt_dev); # else me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6); strcpy (me->me_devname, "/dev/"); strcpy (me->me_devname + 5, mnt.mt_dev); # endif me->me_mountdir = xstrdup (mnt.mt_filsys); me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ me->me_type = ""; me->me_type_malloced = 0; # ifdef GETFSTYP /* SVR3. */ if (need_fs_type) { struct statfs fsd; char typebuf[FSTYPSZ]; if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1) { me->me_type = xstrdup (typebuf); me->me_type_malloced = 1; } } # endif me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); me->me_remote = ME_REMOTE (me->me_devname, me->me_type); /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } if (ferror (fp)) { /* The last fread() call must have failed. */ int saved_errno = errno; fclose (fp); errno = saved_errno; goto free_then_fail; } if (fclose (fp) == EOF) goto free_then_fail; } #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */ #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */ { struct mntent **mnttbl = getmnttbl (), **ent; for (ent=mnttbl;*ent;ent++) { me = xmalloc (sizeof *me); me->me_devname = xstrdup ( (*ent)->mt_resource); me->me_mountdir = xstrdup ( (*ent)->mt_directory); me->me_type = xstrdup ((*ent)->mt_fstype); me->me_type_malloced = 1; me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); me->me_remote = ME_REMOTE (me->me_devname, me->me_type); me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } endmnttbl (); } #endif #ifdef MOUNTED_GETMNTENT2 /* SVR4. */ { struct mnttab mnt; char *table = MNTTAB; FILE *fp; int ret; int lockfd = -1; # if defined F_RDLCK && defined F_SETLKW /* MNTTAB_LOCK is a macro name of our own invention; it's not present in e.g. Solaris 2.6. If the SVR4 folks ever define a macro for this file name, we should use their macro name instead. (Why not just lock MNTTAB directly? We don't know.) */ # ifndef MNTTAB_LOCK # define MNTTAB_LOCK "/etc/.mnttab.lock" # endif lockfd = open (MNTTAB_LOCK, O_RDONLY); if (0 <= lockfd) { struct flock flock; flock.l_type = F_RDLCK; flock.l_whence = SEEK_SET; flock.l_start = 0; flock.l_len = 0; while (fcntl (lockfd, F_SETLKW, &flock) == -1) if (errno != EINTR) { int saved_errno = errno; close (lockfd); errno = saved_errno; return NULL; } } else if (errno != ENOENT) return NULL; # endif errno = 0; fp = fopen (table, "r"); if (fp == NULL) ret = errno; else { while ((ret = getmntent (fp, &mnt)) == 0) { me = xmalloc (sizeof *me); me->me_devname = xstrdup (mnt.mnt_special); me->me_mountdir = xstrdup (mnt.mnt_mountp); me->me_type = xstrdup (mnt.mnt_fstype); me->me_type_malloced = 1; me->me_dummy = MNT_IGNORE (&mnt) != 0; me->me_remote = ME_REMOTE (me->me_devname, me->me_type); me->me_dev = dev_from_mount_options (mnt.mnt_mntopts); /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1; } if (0 <= lockfd && close (lockfd) != 0) ret = errno; if (0 <= ret) { errno = ret; goto free_then_fail; } } #endif /* MOUNTED_GETMNTENT2. */ #ifdef MOUNTED_VMOUNT /* AIX. */ { int bufsize; char *entries, *thisent; struct vmount *vmp; int n_entries; int i; /* Ask how many bytes to allocate for the mounted file system info. */ if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0) return NULL; entries = xmalloc (bufsize); /* Get the list of mounted file systems. */ n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries); if (n_entries < 0) { int saved_errno = errno; free (entries); errno = saved_errno; return NULL; } for (i = 0, thisent = entries; i < n_entries; i++, thisent += vmp->vmt_length) { char *options, *ignore; vmp = (struct vmount *) thisent; me = xmalloc (sizeof *me); if (vmp->vmt_flags & MNT_REMOTE) { char *host, *dir; me->me_remote = 1; /* Prepend the remote dirname. */ host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off; dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off; me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2); strcpy (me->me_devname, host); strcat (me->me_devname, ":"); strcat (me->me_devname, dir); } else { me->me_remote = 0; me->me_devname = xstrdup (thisent + vmp->vmt_data[VMT_OBJECT].vmt_off); } me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off); me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype)); me->me_type_malloced = 1; options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off; ignore = strstr (options, "ignore"); me->me_dummy = (ignore && (ignore == options || ignore[-1] == ',') && (ignore[sizeof "ignore" - 1] == ',' || ignore[sizeof "ignore" - 1] == '\0')); me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */ /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } free (entries); } #endif /* MOUNTED_VMOUNT. */ *mtail = NULL; return mount_list; free_then_fail: { int saved_errno = errno; *mtail = NULL; while (mount_list) { me = mount_list->me_next; free (mount_list->me_devname); free (mount_list->me_mountdir); if (mount_list->me_type_malloced) free (mount_list->me_type); free (mount_list); mount_list = me; } errno = saved_errno; return NULL; } } #endif grafx2/src/op_c.c0000644000076400010400000010451311522560062014310 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2010 Alexander Filyanov 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 */ #include #include #include #include #include #include #include #include #include "op_c.h" #include "errors.h" int Convert_24b_bitmap_to_256_fast(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette); /// Convert RGB to HSL. /// Both input and output are in the 0..255 range to use in the palette screen void RGB_to_HSL(int r,int g,int b,byte * hr,byte * sr,byte* lr) { double rd,gd,bd,h,s,l,max,min; // convert RGB to HSV rd = r / 255.0; // rd,gd,bd range 0-1 instead of 0-255 gd = g / 255.0; bd = b / 255.0; // compute maximum of rd,gd,bd if (rd>=gd) { if (rd>=bd) max = rd; else max = bd; } else { if (gd>=bd) max = gd; else max = bd; } // compute minimum of rd,gd,bd if (rd<=gd) { if (rd<=bd) min = rd; else min = bd; } else { if (gd<=bd) min = gd; else min = bd; } l = (max + min) / 2.0; if(max==min) s = h = 0; else { if (l<=0.5) s = (max - min) / (max + min); else s = (max - min) / (2 - (max + min)); if (max == rd) h = 42.5 * (gd-bd)/(max-min); else if (max == gd) h = 42.5 * (bd-rd)/(max-min)+85; else h = 42.5 * (rd-gd)/(max-min)+170; if (h<0) h+=255; } *hr = h; *lr = (l*255.0); *sr = (s*255.0); } /// Convert HSL back to RGB /// Input and output are all in range 0..255 void HSL_to_RGB(byte h,byte s,byte l, byte* r, byte* g, byte* b) { float rf =0 ,gf = 0,bf = 0; float hf,lf,sf; float p,q; if(s==0) { *r=*g=*b=l; return; } hf = h / 255.0; lf = l / 255.0; sf = s / 255.0; if (lf<=0.5) q = lf*(1+sf); else q = lf+sf-lf*sf; p = 2*lf-q; rf = hf + (1 / 3.0); gf = hf; bf = hf - (1 / 3.0); if (rf < 0) rf+=1; if (rf > 1) rf-=1; if (gf < 0) gf+=1; if (gf > 1) gf-=1; if (bf < 0) bf+=1; if (bf > 1) bf-=1; if (rf < 1/6.0) rf = p + ((q-p)*6*rf); else if(rf < 0.5) rf = q; else if(rf < 2/3.0) rf = p + ((q-p)*6*(2/3.0-rf)); else rf = p; if (gf < 1/6.0) gf = p + ((q-p)*6*gf); else if(gf < 0.5) gf = q; else if(gf < 2/3.0) gf = p + ((q-p)*6*(2/3.0-gf)); else gf = p; if (bf < 1/6.0) bf = p + ((q-p)*6*bf); else if(bf < 0.5) bf = q; else if(bf < 2/3.0) bf = p + ((q-p)*6*(2/3.0-bf)); else bf = p; *r = rf * (255); *g = gf * (255); *b = bf * (255); } /// /// Returns a value that is high when color is near white, /// and low when it's darker. Used for sorting. long Perceptual_lightness(T_Components *color) { return 26*color->R*26*color->R + 55*color->G*55*color->G + 19*color->B*19*color->B; } // Conversion table handlers // The conversion table is built after a run of the median cut algorithm and is // used to find the best color index for a given (RGB) color. GIMP avoids // creating the whole table and only create parts of it when they are actually // needed. This may or may not be faster /// Creates a new conversion table /// params: bumber of bits for R, G, B (precision) T_Conversion_table * CT_new(int nbb_r,int nbb_g,int nbb_b) { T_Conversion_table * n; int size; n=(T_Conversion_table *)malloc(sizeof(T_Conversion_table)); if (n!=NULL) { // Copy the passed parameters n->nbb_r=nbb_r; n->nbb_g=nbb_g; n->nbb_b=nbb_b; // Calculate the others // Value ranges (max value actually) n->rng_r=(1<rng_g=(1<rng_b=(1<dec_r=nbb_g+nbb_b; n->dec_g=nbb_b; n->dec_b=0; // Reductions (how many bits are lost) n->red_r=8-nbb_r; n->red_g=8-nbb_g; n->red_b=8-nbb_b; // Allocate the table size=(n->rng_r)*(n->rng_g)*(n->rng_b); n->table=(byte *)calloc(size, 1); if (n->table == NULL) { // Not enough memory free(n); n=NULL; } } return n; } /// Delete a conversion table and release its memory void CT_delete(T_Conversion_table * t) { free(t->table); free(t); t = NULL; } /// Get the best palette index for an (R, G, B) color byte CT_get(T_Conversion_table * t,int r,int g,int b) { int index; // Reduce the number of bits to the table precision r=(r>>t->red_r); g=(g>>t->red_g); b=(b>>t->red_b); // Find the nearest color index=(r<dec_r) | (g<dec_g) | (b<dec_b); return t->table[index]; } /// Set an entry of the table, index (RGB), value i void CT_set(T_Conversion_table * t,int r,int g,int b,byte i) { int index; index=(r<dec_r) | (g<dec_g) | (b<dec_b); t->table[index]=i; } // Handlers for the occurences tables // This table is used to count the occurence of an (RGB) pixel value in the // source 24bit image. These count are then used by the median cut algorithm to // decide which cluster to split. /// Initialize an occurence table void OT_init(T_Occurrence_table * t) { int size; size=(t->rng_r)*(t->rng_g)*(t->rng_b)*sizeof(int); memset(t->table,0,size); // Set it to 0 } /// Allocate an occurence table for given number of bits T_Occurrence_table * OT_new(int nbb_r,int nbb_g,int nbb_b) { T_Occurrence_table * n; int size; n=(T_Occurrence_table *)malloc(sizeof(T_Occurrence_table)); if (n!=0) { // Copy passed parameters n->nbb_r=nbb_r; n->nbb_g=nbb_g; n->nbb_b=nbb_b; // Compute others n->rng_r=(1<rng_g=(1<rng_b=(1<dec_r=nbb_g+nbb_b; n->dec_g=nbb_b; n->dec_b=0; n->red_r=8-nbb_r; n->red_g=8-nbb_g; n->red_b=8-nbb_b; // Allocate the table size=(n->rng_r)*(n->rng_g)*(n->rng_b)*sizeof(int); n->table=(int *)calloc(size, 1); if (n->table == NULL) { // Not enough memory ! free(n); n=NULL; } } return n; } /// Delete a table and free the memory void OT_delete(T_Occurrence_table * t) { free(t->table); free(t); t = NULL; } /// Get number of occurences for a given color int OT_get(T_Occurrence_table * t, int r, int g, int b) { int index; // Drop bits as needed index=(r<dec_r) | (g<dec_g) | (b<dec_b); return t->table[index]; } /// Add 1 to the count for a color void OT_inc(T_Occurrence_table * t,int r,int g,int b) { int index; // Drop bits as needed r=(r>>t->red_r); g=(g>>t->red_g); b=(b>>t->red_b); // Compute the address index=(r<dec_r) | (g<dec_g) | (b<dec_b); t->table[index]++; } /// Count the use of each color in a 24bit picture and fill in the table void OT_count_occurrences(T_Occurrence_table* t, T_Bitmap24B image, int size) { T_Bitmap24B ptr; int index; for (index = size, ptr = image; index > 0; index--, ptr++) OT_inc(t, ptr->R, ptr->G, ptr->B); } /// Count the total number of pixels in an occurence table int OT_count_colors(T_Occurrence_table * t) { int val; // Computed return value int nb; // Number of colors to test int i; // Loop index val = 0; nb=(t->rng_r)*(t->rng_g)*(t->rng_b); for (i = 0; i < nb; i++) if (t->table[i]>0) val++; return val; } // Cluster management // Clusters are boxes in the RGB spaces, defined by 6 corner coordinates : // Rmax, Rmin, Vmax (or Gmax), Vmin, Rmax, Rmin // The median cut algorithm start with a single cluster covering the whole // colorspace then split it in two smaller clusters on the longest axis until // there are 256 non-empty clusters (with some tricks if the original image // actually has less than 256 colors) // Each cluster also store the number of pixels that are inside and the // rmin, rmax, vmin, vmax, bmin, bmax values are the first/last values that // actually are used by a pixel in the cluster // When you split a big cluster there may be some space between the splitting // plane and the first pixel actually in a cluster /// Pack a cluster, ie compute its {r,v,b}{min,max} values void Cluster_pack(T_Cluster * c,T_Occurrence_table * to) { int rmin,rmax,vmin,vmax,bmin,bmax; int r,g,b; // Find min. and max. values actually used for each component in this cluster // Pre-shift everything to avoid using OT_Get and be faster. This will only // work if the occurence table actually has full precision, that is a // 256^3*sizeof(int) = 64MB table. If your computer has less free ram and // malloc fails, this will not work at all ! // GIMP use only 6 bits for G and B components in this table. rmin=c->rmax <<16; rmax=c->rmin << 16; vmin=c->vmax << 8; vmax=c->vmin << 8; bmin=c->bmax; bmax=c->bmin; c->occurences=0; // Unoptimized code kept here for documentation purpose because the optimized // one is unreadable : run over the whole cluster and find the min and max, // and count the occurences at the same time. /* for (r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) for (g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) for (b=c->bmin;b<=c->bmax;b++) { nbocc=to->table[r + g + b]; // OT_get if (nbocc) { if (rrmax) rmax=r; if (gvmax) vmax=g; if (bbmax) bmax=b; c->occurences+=nbocc; } } */ // Optimized version : find the extremums one at a time, so we can reduce the // area to seek for the next one. Start at the edges of the cluster and go to // the center until we find a pixel. for(r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) for(g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) for(b=c->bmin;b<=c->bmax;b++) { if(to->table[r + g + b]) // OT_get { rmin=r; goto RMAX; } } RMAX: for(r=c->rmax<<16;r>=rmin;r-=1<<16) for(g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) for(b=c->bmin;b<=c->bmax;b++) { if(to->table[r + g + b]) // OT_get { rmax=r; goto VMIN; } } VMIN: for(g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) for(r=rmin;r<=rmax;r+=1<<16) for(b=c->bmin;b<=c->bmax;b++) { if(to->table[r + g + b]) // OT_get { vmin=g; goto VMAX; } } VMAX: for(g=c->vmax<<8;g>=vmin;g-=1<<8) for(r=rmin;r<=rmax;r+=1<<16) for(b=c->bmin;b<=c->bmax;b++) { if(to->table[r + g + b]) // OT_get { vmax=g; goto BMIN; } } BMIN: for(b=c->bmin;b<=c->bmax;b++) for(r=rmin;r<=rmax;r+=1<<16) for(g=vmin;g<=vmax;g+=1<<8) { if(to->table[r + g + b]) // OT_get { bmin=b; goto BMAX; } } BMAX: for(b=c->bmax;b>=bmin;b--) for(r=rmin;r<=rmax;r+=1<<16) for(g=vmin;g<=vmax;g+=1<<8) { if(to->table[r + g + b]) // OT_get { bmax=b; goto ENDCRUSH; } } ENDCRUSH: // We still need to seek the internal part of the cluster to count pixels // inside it for(r=rmin;r<=rmax;r+=1<<16) for(g=vmin;g<=vmax;g+=1<<8) for(b=bmin;b<=bmax;b++) { c->occurences+=to->table[r + g + b]; // OT_get } // Unshift the values and put them in the cluster info c->rmin=rmin>>16; c->rmax=rmax>>16; c->vmin=vmin>>8; c->vmax=vmax>>8; c->bmin=bmin; c->bmax=bmax; // Find the longest axis to know which way to split the cluster // This multiplications are supposed to improve the result, but may or may not // work, actually. r=(c->rmax-c->rmin)*299; g=(c->vmax-c->vmin)*587; b=(c->bmax-c->bmin)*114; if (g>=r) { // G>=R if (g>=b) { // G>=R et G>=B c->plus_large=1; } else { // G>=R et Gplus_large=2; } } else { // R>G if (r>=b) { // R>G et R>=B c->plus_large=0; } else { // R>G et Rplus_large=2; } } } /// Split a cluster on its longest axis. /// c = source cluster, c1, c2 = output after split void Cluster_split(T_Cluster * c, T_Cluster * c1, T_Cluster * c2, int hue, T_Occurrence_table * to) { int limit; int cumul; int r, g, b; // Split criterion: each of the cluster will have the same number of pixels limit = c->occurences / 2; cumul = 0; if (hue == 0) // split on red { // Run over the cluster until we reach the requested number of pixels for (r = c->rmin<<16; r<=c->rmax<<16; r+=1<<16) { for (g = c->vmin<<8; g<=c->vmax<<8; g+=1<<8) { for (b = c->bmin; b<=c->bmax; b++) { cumul+=to->table[r + g + b]; if (cumul>=limit) break; } if (cumul>=limit) break; } if (cumul>=limit) break; } r>>=16; g>>=8; // We tried to split on red, but found half of the pixels with r = rmin // so we enforce some split to happen anyway, instead of creating an empty // c2 and c1 == c if (r==c->rmin) r++; c1->Rmin=c->Rmin; c1->Rmax=r-1; c1->rmin=c->rmin; c1->rmax=r-1; c1->Gmin=c->Gmin; c1->Vmax=c->Vmax; c1->vmin=c->vmin; c1->vmax=c->vmax; c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; c1->bmin=c->bmin; c1->bmax=c->bmax; c2->Rmin=r; c2->Rmax=c->Rmax; c2->rmin=r; c2->rmax=c->rmax; c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; c2->vmin=c->vmin; c2->vmax=c->vmax; c2->Bmin=c->Bmin; c2->Bmax=c->Bmax; c2->bmin=c->bmin; c2->bmax=c->bmax; } else if (hue==1) // split on green { for (g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) { for (r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) { for (b=c->bmin;b<=c->bmax;b++) { cumul+=to->table[r + g + b]; if (cumul>=limit) break; } if (cumul>=limit) break; } if (cumul>=limit) break; } r>>=16; g>>=8; if (g==c->vmin) g++; c1->Rmin=c->Rmin; c1->Rmax=c->Rmax; c1->rmin=c->rmin; c1->rmax=c->rmax; c1->Gmin=c->Gmin; c1->Vmax=g-1; c1->vmin=c->vmin; c1->vmax=g-1; c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; c1->bmin=c->bmin; c1->bmax=c->bmax; c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; c2->rmin=c->rmin; c2->rmax=c->rmax; c2->Gmin=g; c2->Vmax=c->Vmax; c2->vmin=g; c2->vmax=c->vmax; c2->Bmin=c->Bmin; c2->Bmax=c->Bmax; c2->bmin=c->bmin; c2->bmax=c->bmax; } else // split on blue { for (b=c->bmin;b<=c->bmax;b++) { for (g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) { for (r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) { cumul+=to->table[r + g + b]; if (cumul>=limit) break; } if (cumul>=limit) break; } if (cumul>=limit) break; } r>>=16; g>>=8; if (b==c->bmin) b++; c1->Rmin=c->Rmin; c1->Rmax=c->Rmax; c1->rmin=c->rmin; c1->rmax=c->rmax; c1->Gmin=c->Gmin; c1->Vmax=c->Vmax; c1->vmin=c->vmin; c1->vmax=c->vmax; c1->Bmin=c->Bmin; c1->Bmax=b-1; c1->bmin=c->bmin; c1->bmax=b-1; c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; c2->rmin=c->rmin; c2->rmax=c->rmax; c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; c2->vmin=c->vmin; c2->vmax=c->vmax; c2->Bmin=b; c2->Bmax=c->Bmax; c2->bmin=b; c2->bmax=c->bmax; } } /// Compute the mean R, G, B (for palette generation) and H, L (for palette sorting) void Cluster_compute_hue(T_Cluster * c,T_Occurrence_table * to) { int cumul_r,cumul_g,cumul_b; int r,g,b; int nbocc; byte s=0; cumul_r=cumul_g=cumul_b=0; for (r=c->rmin;r<=c->rmax;r++) for (g=c->vmin;g<=c->vmax;g++) for (b=c->bmin;b<=c->bmax;b++) { nbocc=OT_get(to,r,g,b); if (nbocc) { cumul_r+=r*nbocc; cumul_g+=g*nbocc; cumul_b+=b*nbocc; } } c->r=(cumul_r<red_r)/c->occurences; c->g=(cumul_g<red_g)/c->occurences; c->b=(cumul_b<red_b)/c->occurences; RGB_to_HSL(c->r, c->g, c->b, &c->h, &s, &c->l); } // Cluster set management // A set of clusters in handled as a list, the median cut algorithm pops a // cluster from the list, split it, and pushes back the two splitted clusters // until the lit grows to 256 items // Debug helper : check if a cluster set has the right count value /* void CS_Check(T_Cluster_set* cs) { int i; T_Cluster* c = cs->clusters; for (i = cs->nb; i > 0; i--) { assert( c != NULL); c = c->next; } assert(c == NULL); } */ /// Setup the first cluster before we start the operations /// This one covers the full palette range void CS_Init(T_Cluster_set * cs, T_Occurrence_table * to) { cs->clusters->Rmin = cs->clusters->rmin = 0; cs->clusters->Gmin = cs->clusters->vmin = 0; cs->clusters->Bmin = cs->clusters->bmin = 0; cs->clusters->Rmax = cs->clusters->rmax = to->rng_r - 1; cs->clusters->Vmax = cs->clusters->vmax = to->rng_g - 1; cs->clusters->Bmax = cs->clusters->bmax = to->rng_b - 1; cs->clusters->next = NULL; Cluster_pack(cs->clusters, to); cs->nb = 1; } /// Allocate a new cluster set T_Cluster_set * CS_New(int nbmax, T_Occurrence_table * to) { T_Cluster_set * n; n=(T_Cluster_set *)malloc(sizeof(T_Cluster_set)); if (n != NULL) { // Copy requested params n->nb_max = OT_count_colors(to); // If the number of colors asked is > 256, we ceil it because we know we // don't want more if (n->nb_max > nbmax) { n->nb_max = nbmax; } // Allocate the first cluster n->clusters=(T_Cluster *)malloc(sizeof(T_Cluster)); if (n->clusters != NULL) CS_Init(n, to); else { // No memory free ! Sorry ! free(n); n = NULL; } } return n; } /// Free a cluster set void CS_Delete(T_Cluster_set * cs) { T_Cluster* nxt; while (cs->clusters != NULL) { nxt = cs->clusters->next; free(cs->clusters); cs->clusters = nxt; } free(cs); cs = NULL; } /// Pop a cluster from the cluster list void CS_Get(T_Cluster_set * cs, T_Cluster * c) { T_Cluster* current = cs->clusters; T_Cluster* prev = NULL; // Search a cluster with at least 2 distinct colors so we can split it // Clusters are sorted by number of occurences, so a cluster may end up // with a lot of pixelsand on top of the list, but only one color. We can't // split it in that case. It should probably be stored on a list of unsplittable // clusters to avoid running on it again on each iteration. do { if ( (current->rmin < current->rmax) || (current->vmin < current->vmax) || (current->bmin < current->bmax) ) break; prev = current; } while((current = current -> next)); // copy it to c *c = *current; // remove it from the list cs->nb--; if(prev) prev->next = current->next; else cs->clusters = current->next; free(current); current = NULL; } /// Push a cluster in the list void CS_Set(T_Cluster_set * cs,T_Cluster * c) { T_Cluster* current = cs->clusters; T_Cluster* prev = NULL; // Search the first cluster that is smaller than ours (less pixels) while (current && current->occurences > c->occurences) { prev = current; current = current->next; } // Now insert our cluster just before the one we found c -> next = current; current = malloc(sizeof(T_Cluster)); *current = *c ; if (prev) prev->next = current; else cs->clusters = current; cs->nb++; } /// This is the main median cut algorithm and the function actually called to /// reduce the palette. We get the number of pixels for each collor in the /// occurence table and generate the cluster set from it. // 1) RGB space is a big box // 2) We seek the pixels with extreme values // 3) We split the box in 2 parts on its longest axis // 4) We pack the 2 resulting boxes again to leave no empty space between the box border and the first pixel // 5) We take the box with the biggest number of pixels inside and we split it again // 6) Iterate until there are 256 boxes. Associate each of them to its middle color void CS_Generate(T_Cluster_set * cs, T_Occurrence_table * to) { T_Cluster current; T_Cluster Nouveau1; T_Cluster Nouveau2; // There are less than 256 boxes while (cs->nbnb_max) { // Get the biggest one CS_Get(cs,¤t); // Split it Cluster_split(¤t, &Nouveau1, &Nouveau2, current.plus_large, to); // Pack the 2 new clusters (the split may leave some empty space between the // box border and the first actual pixel) Cluster_pack(&Nouveau1, to); Cluster_pack(&Nouveau2, to); // Put them back in the list CS_Set(cs,&Nouveau1); CS_Set(cs,&Nouveau2); } } /// Compute the color associated to each box in the list void CS_Compute_colors(T_Cluster_set * cs, T_Occurrence_table * to) { T_Cluster * c; for (c=cs->clusters;c!=NULL;c=c->next) Cluster_compute_hue(c,to); } // We sort the clusters on two criterions to get a somewhat coherent palette. // TODO : It would be better to do this in one single pass. /// Sort the clusters by chrominance value void CS_Sort_by_chrominance(T_Cluster_set * cs) { T_Cluster* nc; T_Cluster* prev = NULL; T_Cluster* place; T_Cluster* newlist = NULL; while (cs->clusters) { // Remove the first cluster from the original list nc = cs->clusters; cs->clusters = cs->clusters->next; // Find his position in the new list for (place = newlist; place != NULL; place = place->next) { if (place->h > nc->h) break; prev = place; } // Chain it there nc->next = place; if (prev) prev->next = nc; else newlist = nc; prev = NULL; } // Put the new list back in place cs->clusters = newlist; } /// Sort the clusters by luminance value void CS_Sort_by_luminance(T_Cluster_set * cs) { T_Cluster* nc; T_Cluster* prev = NULL; T_Cluster* place; T_Cluster* newlist = NULL; while (cs->clusters) { // Remove the first cluster from the original list nc = cs->clusters; cs->clusters = cs->clusters->next; // Find its position in the new list for (place = newlist; place != NULL; place = place->next) { if (place->l > nc->l) break; prev = place; } // Chain it there nc->next = place; if (prev) prev->next = nc; else newlist = nc; // reset prev pointer prev = NULL; } // Put the new list back in place cs->clusters = newlist; } /// Generates the palette from the clusters, then the conversion table to map (RGB) to a palette index void CS_Generate_color_table_and_palette(T_Cluster_set * cs,T_Conversion_table * tc,T_Components * palette) { int index; int r,g,b; T_Cluster* current = cs->clusters; for (index=0;indexnb;index++) { palette[index].R=current->r; palette[index].G=current->g; palette[index].B=current->b; for (r=current->Rmin; r<=current->Rmax; r++) for (g=current->Gmin;g<=current->Vmax;g++) for (b=current->Bmin;b<=current->Bmax;b++) CT_set(tc,r,g,b,index); current = current->next; } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////// Mthodes de gestion des dgrads // ///////////////////////////////////////////////////////////////////////////// void GS_Init(T_Gradient_set * ds,T_Cluster_set * cs) { ds->gradients[0].nb_colors=1; ds->gradients[0].min=cs->clusters->h; ds->gradients[0].max=cs->clusters->h; ds->gradients[0].hue=cs->clusters->h; // Et hop : le 1er ensemble de dgrads est initialis ds->nb=1; } T_Gradient_set * GS_New(T_Cluster_set * cs) { T_Gradient_set * n; n=(T_Gradient_set *)malloc(sizeof(T_Gradient_set)); if (n!=NULL) { // On recopie les paramtres demands n->nb_max=cs->nb_max; // On tente d'allouer la table n->gradients=(T_Gradient *)malloc((n->nb_max)*sizeof(T_Gradient)); if (n->gradients!=0) // C'est bon! On initialise GS_Init(n,cs); else { // Table impossible allouer free(n); n=NULL; } } return n; } void GS_Delete(T_Gradient_set * ds) { free(ds->gradients); free(ds); } void GS_Generate(T_Gradient_set * ds,T_Cluster_set * cs) { int id; // Les indexs de parcours des ensembles int best_gradient; // Meilleur dgrad int best_diff; // Meilleure diffrence de chrominance int diff; // difference de chrominance courante T_Cluster * current = cs->clusters; // Pour chacun des clusters traiter do { // On recherche le dgrad le plus proche de la chrominance du cluster best_gradient=-1; best_diff=99999999; for (id=0;idnb;id++) { diff=abs(current->h - ds->gradients[id].hue); if ((best_diff>diff) && (diff<16)) { best_gradient=id; best_diff=diff; } } // Si on a trouv un dgrad dans lequel inclure le cluster if (best_gradient!=-1) { // On met jour le dgrad if (current->h < ds->gradients[best_gradient].min) ds->gradients[best_gradient].min=current->h; if (current->h > ds->gradients[best_gradient].max) ds->gradients[best_gradient].max=current->h; ds->gradients[best_gradient].hue=((ds->gradients[best_gradient].hue* ds->gradients[best_gradient].nb_colors) +current->h) /(ds->gradients[best_gradient].nb_colors+1); ds->gradients[best_gradient].nb_colors++; } else { // On cre un nouveau dgrad best_gradient=ds->nb; ds->gradients[best_gradient].nb_colors=1; ds->gradients[best_gradient].min=current->h; ds->gradients[best_gradient].max=current->h; ds->gradients[best_gradient].hue=current->h; ds->nb++; } current->h=best_gradient; } while((current = current->next)); // On redistribue les valeurs dans les clusters current = cs -> clusters; do current->h=ds->gradients[current->h].hue; while((current = current ->next)); } /// Compute best palette for given picture. T_Conversion_table * Optimize_palette(T_Bitmap24B image, int size, T_Components * palette, int r, int g, int b) { T_Occurrence_table * to; T_Conversion_table * tc; T_Cluster_set * cs; T_Gradient_set * ds; // Allocate all the elements to = 0; tc = 0; cs = 0; ds = 0; to = OT_new(r, g, b); if (to == NULL) return 0; tc = CT_new(r, g, b); if (tc == NULL) { OT_delete(to); return 0; } // Count pixels for each color OT_count_occurrences(to, image, size); cs = CS_New(256, to); if (cs == NULL) { CT_delete(tc); OT_delete(to); return 0; } //CS_Check(cs); // Ok, everything was allocated // Generate the cluster set with median cut algorithm CS_Generate(cs, to); //CS_Check(cs); // Compute the color data for each cluster (palette entry + HL) CS_Compute_colors(cs, to); //CS_Check(cs); ds = GS_New(cs); if (ds!= NULL) { GS_Generate(ds, cs); GS_Delete(ds); } // Sort the clusters on L and H to get a nice palette CS_Sort_by_luminance(cs); //CS_Check(cs); CS_Sort_by_chrominance(cs); //CS_Check(cs); // And finally generate the conversion table to map RGB > pal. index CS_Generate_color_table_and_palette(cs, tc, palette); //CS_Check(cs); CS_Delete(cs); OT_delete(to); return tc; } /// Change a value with proper ceiling and flooring int Modified_value(int value,int modif) { value+=modif; if (value<0) { value=0; } else if (value>255) { value=255; } return value; } /// Convert a 24b image to 256 colors (with a given palette and conversion table) /// This destroys the 24b picture ! /// Uses floyd steinberg dithering. void Convert_24b_bitmap_to_256_Floyd_Steinberg(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette,T_Conversion_table * tc) { T_Bitmap24B current; T_Bitmap24B c_plus1; T_Bitmap24B u_minus1; T_Bitmap24B next; T_Bitmap24B u_plus1; T_Bitmap256 d; int x_pos,y_pos; int red,green,blue; float e_red,e_green,e_blue; // On initialise les variables de parcours: current =source; // Le pixel dont on s'occupe next =current+width; // Le pixel en dessous c_plus1 =current+1; // Le pixel droite u_minus1=next-1; // Le pixel en bas gauche u_plus1 =next+1; // Le pixel en bas droite d =dest; // On parcours chaque pixel: for (y_pos=0;y_posR; green =current->G; blue =current->B; // Cherche la couleur correspondant dans la palette et la range dans l'image de destination *d=CT_get(tc,red,green,blue); // Puis on calcule pour chaque composante l'erreur de l'approximation red-=palette[*d].R; green -=palette[*d].G; blue -=palette[*d].B; // Et dans chaque pixel voisin on propage l'erreur // A droite: e_red=(red*7)/16.0; e_green =(green *7)/16.0; e_blue =(blue *7)/16.0; if (x_pos+1R=Modified_value(c_plus1->R,e_red); c_plus1->G=Modified_value(c_plus1->G,e_green ); c_plus1->B=Modified_value(c_plus1->B,e_blue ); } // En bas gauche: if (y_pos+10) { u_minus1->R=Modified_value(u_minus1->R,e_red); u_minus1->G=Modified_value(u_minus1->G,e_green ); u_minus1->B=Modified_value(u_minus1->B,e_blue ); } // En bas: e_red=(red*5/16.0); e_green =(green*5 /16.0); e_blue =(blue*5 /16.0); next->R=Modified_value(next->R,e_red); next->G=Modified_value(next->G,e_green ); next->B=Modified_value(next->B,e_blue ); // En bas droite: if (x_pos+1R=Modified_value(u_plus1->R,e_red); u_plus1->G=Modified_value(u_plus1->G,e_green ); u_plus1->B=Modified_value(u_plus1->B,e_blue ); } } // On passe au pixel suivant : current++; c_plus1++; u_minus1++; next++; u_plus1++; d++; } } } /// Converts from 24b to 256c without dithering, using given conversion table void Convert_24b_bitmap_to_256_nearest_neighbor(T_Bitmap256 dest, T_Bitmap24B source, int width, int height, __attribute__((unused)) T_Components * palette, T_Conversion_table * tc) { T_Bitmap24B current; T_Bitmap256 d; int x_pos, y_pos; int red, green, blue; // On initialise les variables de parcours: current =source; // Le pixel dont on s'occupe d =dest; // On parcours chaque pixel: for (y_pos = 0; y_pos < height; y_pos++) { for (x_pos = 0 ;x_pos < width; x_pos++) { // On prends la meilleure couleur de la palette qui traduit la couleur // 24 bits de la source: red = current->R; green = current->G; blue = current->B; // Cherche la couleur correspondant dans la palette et la range dans // l'image de destination *d = CT_get(tc, red, green, blue); // On passe au pixel suivant : current++; d++; } } } // These are the allowed precisions for all the tables. // For some of them only the first one may work because of ugly optimizations static const byte precision_24b[]= { 8,8,8, 6,6,6, 6,6,5, 5,6,5, 5,5,5, 5,5,4, 4,5,4, 4,4,4, 4,4,3, 3,4,3, 3,3,3, 3,3,2}; // Give this one a 24b source, get back the 256c bitmap and its palette int Convert_24b_bitmap_to_256(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette) { #if defined(__GP2X__) || defined(__gp2x__) || defined(__WIZ__) || defined(__CAANOO__) return Convert_24b_bitmap_to_256_fast(dest, source, width, height, palette); #else T_Conversion_table * table; // table de conversion int ip; // index de prcision pour la conversion // On essaye d'obtenir une table de conversion qui loge en mmoire, avec la // meilleure prcision possible for (ip=0;ip<(10*3);ip+=3) { table=Optimize_palette(source,width*height,palette,precision_24b[ip+0], precision_24b[ip+1],precision_24b[ip+2]); if (table!=0) break; } if (table!=0) { //Convert_24b_bitmap_to_256_Floyd_Steinberg(dest,source,width,height,palette,table); Convert_24b_bitmap_to_256_nearest_neighbor(dest,source,width,height,palette,table); CT_delete(table); return 0; } else return 1; #endif } //Really small, fast and ugly converter(just for handhelds) #include "global.h" #include "limits.h" #include "engine.h" #include "windows.h" extern void Set_palette_fake_24b(T_Palette palette); /// Really small, fast and dirty convertor(just for handhelds) int Convert_24b_bitmap_to_256_fast(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette) { int size; Set_palette_fake_24b(palette); size = width*height; while(size--) { //Set palette color index to destination bitmap *dest = ((source->R >> 5) << 5) | ((source->G >> 5) << 2) | ((source->B >> 6)); source++; dest++; } return 0; } grafx2/src/operatio.c0000644000076400010400000027315311534470550015226 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 2009 Franck Charlet 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 */ #include #include #include #include "const.h" #include "struct.h" #include "global.h" #include "misc.h" #include "engine.h" #include "graph.h" #include "operatio.h" #include "buttons.h" #include "pages.h" #include "errors.h" #include "sdlscreen.h" #include "brush.h" #include "windows.h" #include "input.h" // PI is NOT part of math.h according to C standards... #if defined(__GP2X__) || defined(__VBCC__) #define M_PI 3.14159265358979323846 #endif /// Time (in SDL ticks) when the next airbrush drawing should be done. Also used /// for discontinuous freehand drawing. Uint32 Airbrush_next_time; void Start_operation_stack(word new_operation) { Brush_rotation_center_is_defined=0; // On mmorise l'opration prcdente si on dmarre une interruption switch(new_operation) { case OPERATION_MAGNIFY: case OPERATION_COLORPICK: case OPERATION_RMB_COLORPICK: case OPERATION_GRAB_BRUSH: case OPERATION_POLYBRUSH: case OPERATION_STRETCH_BRUSH: case OPERATION_ROTATE_BRUSH: Operation_before_interrupt=Current_operation; // On passe l'operation demande Current_operation=new_operation; break; default : // On passe l'operation demande Current_operation=new_operation; Operation_before_interrupt=Current_operation; } // On spcifie si l'opration autorise le changement de couleur au clavier switch(new_operation) { case OPERATION_CONTINUOUS_DRAW: case OPERATION_DISCONTINUOUS_DRAW: case OPERATION_AIRBRUSH: case OPERATION_CENTERED_LINES: Allow_color_change_during_operation=1; break; default : Allow_color_change_during_operation=0; } // Et on passe au curseur qui va avec Cursor_shape=CURSOR_FOR_OPERATION[new_operation]; Operation_stack_size=0; } void Init_start_operation(void) { Operation_in_magnifier=(Mouse_X>=Main_X_zoom); Smear_start=1; } void Operation_push(short value) { Operation_stack[++Operation_stack_size]=value; } void Operation_pop(short * value) { *value=Operation_stack[Operation_stack_size--]; } byte Paintbrush_shape_before_operation; byte Paintbrush_hidden_before_scroll; short Distance(short x1, short y1, short x2, short y2) { short x2_moins_x1=x2-x1; short y2_minus_y1=y2-y1; return Round( sqrt( (x2_moins_x1*x2_moins_x1) + (y2_minus_y1*y2_minus_y1) ) ); } void Display_coords_rel_or_abs(short start_x, short start_y) { char str[6]; if (Config.Coords_rel) { if (Menu_is_visible) { if (Paintbrush_X>start_x) { Num2str(Paintbrush_X-start_x,str,5); str[0]='+'; } else if (Paintbrush_Xstart_y) { Num2str(Paintbrush_Y-start_y,str,5); str[0]='+'; } else if (Paintbrush_YAirbrush_next_time) { Airbrush_next_time+=Airbrush_delay*10; Hide_cursor(); // On affiche dfinitivement le pinceau Display_paintbrush(Paintbrush_X,Paintbrush_Y,Fore_color,0); Display_cursor(); } } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } // ---------- void Freehand_mode2_2_0(void) // Opration : OPERATION_DISCONTINUOUS_DRAW // Click Souris: 2 // Taille_Pile : 0 // // Souris efface: Oui { if (Rightclick_colorpick(0)) return; Init_start_operation(); Backup(); Shade_table=Shade_table_right; Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Print_coordinates(); Airbrush_next_time = SDL_GetTicks() + Airbrush_delay*10; // On affiche dfinitivement le pinceau Display_paintbrush(Paintbrush_X,Paintbrush_Y,Back_color,0); } void Freehand_mode2_2_2(void) // Opration : OPERATION_DISCONTINUOUS_DRAW // Click Souris: 2 // Taille_Pile : 2 // // Souris efface: Non { short start_x; short start_y; Operation_pop(&start_y); Operation_pop(&start_x); if ( (start_x!=Paintbrush_X) || (start_y!=Paintbrush_Y) ) { Print_coordinates(); if (SDL_GetTicks()>Airbrush_next_time) { Airbrush_next_time+=Airbrush_delay*10; Hide_cursor(); // On affiche dfinitivement le pinceau Display_paintbrush(Paintbrush_X,Paintbrush_Y,Back_color,0); Display_cursor(); } } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } ////////////////////////////////////////////////////// OPERATION_POINT_DRAW void Freehand_mode3_1_0(void) // Opration : OPERATION_POINT_DRAW // Click Souris: 1 // Taille_Pile : 0 // // Souris efface: Oui { Init_start_operation(); Backup(); Shade_table=Shade_table_left; // On affiche dfinitivement le pinceau Display_paintbrush(Paintbrush_X,Paintbrush_Y,Fore_color,0); Operation_push(0); // On change simplement l'tat de la pile... } void Freehand_Mode3_2_0(void) // Opration : OPERATION_POINT_DRAW // Click Souris: 2 // Taille_Pile : 0 // // Souris efface: Oui { if (Rightclick_colorpick(0)) return; Init_start_operation(); Backup(); Shade_table=Shade_table_right; // On affiche dfinitivement le pinceau Display_paintbrush(Paintbrush_X,Paintbrush_Y,Back_color,0); Operation_push(0); // On change simplement l'tat de la pile... } void Freehand_mode3_0_1(void) // Opration : OPERATION_POINT_DRAW // Click Souris: 0 // Taille_Pile : 1 // // Souris efface: Non { End_of_modification(); Operation_stack_size--; } ///////////////////////////////////////////////////////////// OPERATION_LINE void Line_12_0(void) // Opration : OPERATION_LINE // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui // Dbut du trac d'une ligne (premier clic) { if (Rightclick_colorpick(0)) return; Init_start_operation(); Backup(); Paintbrush_shape_before_operation=Paintbrush_shape; Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; if (Mouse_K==LEFT_SIDE) { Shade_table=Shade_table_left; Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Fore_color); Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); Operation_push(Fore_color); } else { Shade_table=Shade_table_right; Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Back_color); Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); Operation_push(Back_color); } if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Line_12_5(void) // Opration : OPERATION_LINE // Click Souris: 1 // Taille_Pile : 5 // // Souris efface: Non // Poursuite du trac d'une ligne (dplacement de la souris en gardant le // curseur appuy) { short start_x; short start_y; short end_x; short end_y; short cursor_x; short cursor_y; Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); cursor_x = Paintbrush_X; cursor_y = Paintbrush_Y; // On corrige les coordonnes de la ligne si la touche shift est appuye... if(SDL_GetModState() & KMOD_SHIFT) Clamp_coordinates_regular_angle(start_x,start_y,&cursor_x,&cursor_y); // On vient de bouger if ((cursor_x!=end_x) || (cursor_y!=end_y)) { Hide_cursor(); Display_coords_rel_or_abs(start_x,start_y); Hide_line_preview(start_x,start_y,end_x,end_y); if (Mouse_K==LEFT_SIDE) { Pixel_figure_preview (start_x,start_y,Fore_color); Draw_line_preview (start_x,start_y,cursor_x,cursor_y,Fore_color); } else { Pixel_figure_preview (start_x,start_y,Back_color); Draw_line_preview (start_x,start_y,cursor_x,cursor_y,Back_color); } Operation_push(start_x); Operation_push(start_y); Operation_push(cursor_x); Operation_push(cursor_y); Display_cursor(); } else { Operation_push(start_x); Operation_push(start_y); Operation_push(end_x); Operation_push(end_y); } } void Line_0_5(void) // Opration : OPERATION_LINE // Click Souris: 0 // Taille_Pile : 5 // // Souris efface: Oui // End du trac d'une ligne (relachage du bouton) { short start_x; short start_y; short end_x; short end_y; short color; Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&color); Paintbrush_shape=Paintbrush_shape_before_operation; Pixel_figure_preview_auto (start_x,start_y); Hide_line_preview (start_x,start_y,end_x,end_y); Display_paintbrush (start_x,start_y,color,0); Draw_line_permanent(start_x,start_y,end_x,end_y,color); End_of_modification(); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } /////////////////////////////////////////////////////////// OPERATION_K_LINE void K_line_12_0(void) // Opration : OPERATION_K_LINE // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui { byte color; if (Rightclick_colorpick(0)) return; Init_start_operation(); Backup(); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; Paintbrush_shape_before_operation=Paintbrush_shape; Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; // On place temporairement le dbut de la ligne qui ne s'afficherait pas sinon Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Operation_push(Mouse_K | 0x80); Operation_push(color); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); // Taille de pile 6 : phase d'appui, non interruptible } void K_line_12_6(void) // Opration : OPERATION_K_LINE // Click Souris: 1 ou 2 | 0 // Taille_Pile : 6 | 7 // // Souris efface: Non { short start_x; short start_y; short end_x; short end_y; short color; Operation_pop(&end_y); Operation_pop(&end_x); if ((Paintbrush_X!=end_x) || (Paintbrush_Y!=end_y)) { Hide_cursor(); Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&color); Display_coords_rel_or_abs(start_x,start_y); Hide_line_preview(start_x,start_y,end_x,end_y); Pixel_figure_preview (start_x,start_y,color); Draw_line_preview (start_x,start_y,Paintbrush_X,Paintbrush_Y,color); Operation_push(color); Operation_push(start_x); Operation_push(start_y); Display_cursor(); } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void K_line_0_6(void) // Opration : OPERATION_K_LINE // Click Souris: 0 // Taille_Pile : 6 // // Souris efface: Oui { short start_x; short start_y; short end_x; short end_y; short color; short direction; Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&color); Operation_pop(&direction); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Pixel_figure_preview_auto (start_x,start_y); Hide_line_preview (start_x,start_y,end_x,end_y); /* Doesn't work if fast moving Pixel_figure_preview_xor (start_x,start_y, 0); Draw_line_preview_xor (start_x,start_y,end_x,end_y,0); */ Paintbrush_shape=Paintbrush_shape_before_operation; if (direction & 0x80) { Display_paintbrush(start_x,start_y,color,0); direction=(direction & 0x7F); } Draw_line_permanent(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; Operation_push(direction); Operation_push(direction); // Valeur bidon servant de nouvel tat de pile Operation_push(color); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); // Taille de pile 7 : phase de "repos", interruptible (comme Elliot Ness :)) } void K_line_12_7(void) // Opration : OPERATION_K_LINE // Click Souris: 1 ou 2 // Taille_Pile : 7 // // Souris efface: Oui { short start_x; short start_y; short end_x; short end_y; short color; short direction; Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&color); Operation_pop(&direction); Operation_pop(&direction); if (direction==Mouse_K) { Operation_push(direction); Operation_push(color); Operation_push(start_x); Operation_push(start_y); Operation_push(end_x); Operation_push(end_y); // Taille de pile 6 : phase d'appui, non interruptible } else { // La srie de ligne est termine, il faut donc effacer la dernire // preview de ligne Pixel_figure_preview_auto (start_x,start_y); Hide_line_preview (start_x,start_y,end_x,end_y); Display_cursor(); Wait_end_of_click(); Hide_cursor(); Paintbrush_shape=Paintbrush_shape_before_operation; End_of_modification(); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } } /////////////////////////////////////////////////// OPERATION_RECTANGLE_????? void Rectangle_12_0(void) // Opration : OPERATION_EMPTY_RECTANGLE / OPERATION_FILLED_RECTANGLE // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui { if (Rightclick_colorpick(0)) return; Init_start_operation(); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("\035: 1 \022: 1",0); // On laisse une trace du curseur l'cran Display_cursor(); if (Mouse_K==LEFT_SIDE) { Shade_table=Shade_table_left; Operation_push(Fore_color); } else { Shade_table=Shade_table_right; Operation_push(Back_color); } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Rectangle_12_5(void) // Opration : OPERATION_EMPTY_RECTANGLE / OPERATION_FILLED_RECTANGLE // Click Souris: 1 ou 2 // Taille_Pile : 5 // // Souris efface: Non { short start_x; short start_y; short old_x; short old_y; char str[5]; Operation_pop(&old_y); Operation_pop(&old_x); if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) { Operation_pop(&start_y); Operation_pop(&start_x); if ((Config.Coords_rel) && (Menu_is_visible)) { Num2str(((start_xcenter_x)?tangent_x-center_x :center_x-tangent_x; vertical_radius =(tangent_y>center_y)?tangent_y-center_y :center_y-tangent_y; Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); horizontal_radius=(Paintbrush_X>center_x)?Paintbrush_X-center_x :center_x-Paintbrush_X; vertical_radius =(Paintbrush_Y>center_y)?Paintbrush_Y-center_y :center_y-Paintbrush_Y; Draw_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius,color); Display_cursor(); } Operation_push(color); Operation_push(center_x); Operation_push(center_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Empty_ellipse_0_5(void) // // Opration : OPERATION_EMPTY_ELLIPSE // Click Souris: 0 // Taille_Pile : 5 (color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) // // Souris efface: Oui // { short tangent_x; short tangent_y; short center_x; short center_y; short color; short horizontal_radius; short vertical_radius; Operation_pop(&tangent_y); Operation_pop(&tangent_x); Operation_pop(¢er_y); Operation_pop(¢er_x); Operation_pop(&color); horizontal_radius=(tangent_x>center_x)?tangent_x-center_x :center_x-tangent_x; vertical_radius =(tangent_y>center_y)?tangent_y-center_y :center_y-tangent_y; Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); Paintbrush_shape=Paintbrush_shape_before_operation; Draw_empty_ellipse_permanent(center_x,center_y,horizontal_radius,vertical_radius,color); End_of_modification(); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } void Filled_ellipse_0_5(void) // // Opration : OPERATION_FILLED_ELLIPSE // Click Souris: 0 // Taille_Pile : 5 (color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) // // Souris efface: Oui // { short tangent_x; short tangent_y; short center_x; short center_y; short color; short horizontal_radius; short vertical_radius; Operation_pop(&tangent_y); Operation_pop(&tangent_x); Operation_pop(¢er_y); Operation_pop(¢er_x); Operation_pop(&color); horizontal_radius=(tangent_x>center_x)?tangent_x-center_x :center_x-tangent_x; vertical_radius =(tangent_y>center_y)?tangent_y-center_y :center_y-tangent_y; Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); Paintbrush_shape=Paintbrush_shape_before_operation; Draw_filled_ellipse(center_x,center_y,horizontal_radius,vertical_radius,color); End_of_modification(); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } ////////////////////////////////////////////////////////////// OPERATION_FILL void Fill_1_0(void) // // Opration : OPERATION_FILL // Click Souris: 1 // Taille_Pile : 0 // // Souris efface: Oui // { Hide_cursor(); // Pas besoin d'initialiser le dbut d'opration car le Smear n'affecte pas // le Fill, et on se fout de savoir si on est dans la partie gauche ou // droite de la loupe. // On ne s'occupe pas de faire un Backup: c'est "Fill_general" qui s'en charge. Shade_table=Shade_table_left; Fill_general(Fore_color); Display_cursor(); End_of_modification(); Wait_end_of_click(); } void Fill_2_0(void) // // Opration : OPERATION_FILL // Click Souris: 2 // Taille_Pile : 0 // // Souris efface: Non // { if (Rightclick_colorpick(1)) return; Hide_cursor(); // Pas besoin d'initialiser le dbut d'opration car le Smear n'affecte pas // le Fill, et on se fout de savoir si on est dans la partie gauche ou // droite de la loupe. // On ne s'occupe pas de faire un Backup: c'est "Fill_general" qui s'en charge. Shade_table=Shade_table_right; Fill_general(Back_color); Display_cursor(); End_of_modification(); Wait_end_of_click(); } ///////////////////////////////////////////////////////// OPERATION_REPLACE void Replace_1_0(void) // // Opration : OPERATION_REPLACE // Click Souris: 1 // Taille_Pile : 0 // // Souris efface: Non // { Hide_cursor(); // Pas besoin d'initialiser le dbut d'opration car le Smear n'affecte pas // le Replace, et on se fout de savoir si on est dans la partie gauche ou // droite de la loupe. Backup(); // Shade_table=Shade_table_left; Replace(Fore_color); Display_cursor(); End_of_modification(); Wait_end_of_click(); } void Replace_2_0(void) // // Opration : OPERATION_REPLACE // Click Souris: 2 // Taille_Pile : 0 // // Souris efface: Non // { if (Rightclick_colorpick(1)) return; Hide_cursor(); // Pas besoin d'initialiser le dbut d'opration car le Smear n'affecte pas // le Replace, et on se fout de savoir si on est dans la partie gauche ou // droite de la loupe. Backup(); // Shade_table=Shade_table_right; Replace(Back_color); Display_cursor(); End_of_modification(); Wait_end_of_click(); } /////////////////////////////////////////////////// OPERATION_4_POINTS_CURVE void Draw_curve_cross(short x_pos, short y_pos) { short start_x,end_x; short start_y,end_y; short i,temp; //byte temp2; if (x_pos>=Limit_left+3) start_x=0; else start_x=3-(x_pos-Limit_left); if (y_pos>=Limit_top+3) start_y=0; else start_y=3-(y_pos-Limit_top); if (x_pos<=Limit_visible_right-3) end_x=6; else end_x=3+(Limit_visible_right-x_pos); if (y_pos<=Limit_visible_bottom-3) end_y=6; else end_y=3+(Limit_visible_bottom-y_pos); if (start_x<=end_x && start_y<=end_y) { for (i=start_x; i<=end_x; i++) { temp=x_pos+i-3; Pixel_preview(temp,y_pos,~Read_pixel(temp -Main_offset_X, y_pos-Main_offset_Y)); } for (i=start_y; i<=end_y; i++) { temp=y_pos+i-3; Pixel_preview(x_pos,temp,~Read_pixel(x_pos-Main_offset_X, temp -Main_offset_Y)); } Update_part_of_screen(x_pos+start_x-3,y_pos+start_y-3,end_x-start_x+1,end_y-start_y+1); } } void Curve_34_points_1_0(void) // // Opration : OPERATION_COURBE_?_POINTS // Click Souris: 1 // Taille_Pile : 0 // // Souris efface: Oui // { Init_start_operation(); Backup(); Shade_table=Shade_table_left; Paintbrush_hidden=1; Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Fore_color); Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Operation_push(Fore_color); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Curve_34_points_2_0(void) // // Opration : OPERATION_COURBE_?_POINTS // Click Souris: 2 // Taille_Pile : 0 // // Souris efface: Oui // { if (Rightclick_colorpick(0)) return; Init_start_operation(); Backup(); Shade_table=Shade_table_right; Paintbrush_hidden=1; Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Back_color); Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Operation_push(Back_color); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Curve_34_points_1_5(void) // // Opration : OPERATION_COURBE_?_POINTS // Click Souris: 1 // Taille_Pile : 5 // // Souris efface: Non // { short x1,x2,y1,y2; Operation_pop(&y2); Operation_pop(&x2); Operation_pop(&y1); Operation_pop(&x1); if ( (y2!=Paintbrush_Y) || (x2!=Paintbrush_X) ) { Hide_cursor(); Display_coords_rel_or_abs(x1,y1); Hide_line_preview(x1,y1,x2,y2); Pixel_figure_preview (x1,y1,Fore_color); Draw_line_preview (x1,y1,Paintbrush_X,Paintbrush_Y,Fore_color); Display_cursor(); } Operation_push(x1); Operation_push(y1); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Curve_34_points_2_5(void) // // Opration : OPERATION_COURBE_?_POINTS // Click Souris: 2 // Taille_Pile : 5 // // Souris efface: Non // { short x1,x2,y1,y2; Operation_pop(&y2); Operation_pop(&x2); Operation_pop(&y1); Operation_pop(&x1); if ( (y2!=Paintbrush_Y) || (x2!=Paintbrush_X) ) { Hide_cursor(); Display_coords_rel_or_abs(x1,y1); Hide_line_preview(x1,y1,x2,y2); Pixel_figure_preview (x1,y1,Back_color); Draw_line_preview (x1,y1,Paintbrush_X,Paintbrush_Y,Back_color); Display_cursor(); } Operation_push(x1); Operation_push(y1); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } byte Cursor_hidden_before_curve; void Curve_4_points_0_5(void) // // Opration : OPERATION_4_POINTS_CURVE // Click Souris: 0 // Taille_Pile : 5 // // Souris efface: Oui // { short x1,y1,x2,y2,x3,y3,x4,y4; short third_x,third_y; short color; Operation_pop(&y4); Operation_pop(&x4); Operation_pop(&y1); Operation_pop(&x1); Operation_pop(&color); third_x=Round_div(abs(x4-x1),3); third_y=Round_div(abs(y4-y1),3); if (x1B=(8/3) * C->P *x3=Round((bx+x4)/2.0); // _/ P3 P2=middle of [P1,B] *y3=Round((by+y4)/2.0); // P4*-- P3=middle of [P4,B] } void Curve_3_points_0_5(void) // // Opration : OPERATION_3_POINTS_CURVE // Click Souris: 0 // Taille_Pile : 5 // // Souris efface: Oui // { short x1,y1,x2,y2,x3,y3,x4,y4; short color; Operation_pop(&y4); Operation_pop(&x4); Operation_pop(&y1); Operation_pop(&x1); Operation_pop(&color); Compute_3_point_curve(x1,y1,x4,y4,&x2,&y2,&x3,&y3); if (!Config.Stylus_mode) { Hide_line_preview(x1,y1,x4,y4); Draw_curve_preview(x1,y1,x2,y2,x3,y3,x4,y4,color); } if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); Print_coordinates(); } Operation_push(color); Operation_push(x1); Operation_push(y1); Operation_push(x2); Operation_push(y2); Operation_push(x3); Operation_push(y3); Operation_push(x4); Operation_push(y4); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); if (Config.Stylus_mode) { Display_cursor(); while(!Mouse_K) Get_input(20); Hide_cursor(); Hide_line_preview(x1,y1,x4,y4); } } void Curve_drag(void) { short x1,y1,x2,y2,x3,y3,x4,y4; short old_x,old_y; short color; Operation_pop(&old_y); Operation_pop(&old_x); if ( (Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) ) { Operation_pop(&y4); Operation_pop(&x4); Operation_pop(&y3); Operation_pop(&x3); Operation_pop(&y2); Operation_pop(&x2); Operation_pop(&y1); Operation_pop(&x1); Operation_pop(&color); Hide_cursor(); Print_coordinates(); Hide_curve_preview(x1,y1,x2,y2,x3,y3,x4,y4,color); Compute_3_point_curve(x1,y1,x4,y4,&x2,&y2,&x3,&y3); Draw_curve_preview (x1,y1,x2,y2,x3,y3,x4,y4,color); Display_cursor(); Operation_push(color); Operation_push(x1); Operation_push(y1); Operation_push(x2); Operation_push(y2); Operation_push(x3); Operation_push(y3); Operation_push(x4); Operation_push(y4); } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Curve_finalize(void) { short x1,y1,x2,y2,x3,y3,x4,y4; short old_x,old_y; short color; Operation_pop(&old_y); Operation_pop(&old_x); Operation_pop(&y4); Operation_pop(&x4); Operation_pop(&y3); Operation_pop(&x3); Operation_pop(&y2); Operation_pop(&x2); Operation_pop(&y1); Operation_pop(&x1); Operation_pop(&color); Paintbrush_hidden=0; Hide_cursor(); Hide_curve_preview (x1,y1,x2,y2,x3,y3,x4,y4,color); Compute_3_point_curve(x1,y1,x4,y4,&x2,&y2,&x3,&y3); Draw_curve_permanent(x1,y1,x2,y2,x3,y3,x4,y4,color); End_of_modification(); Display_cursor(); Wait_end_of_click(); } void Curve_3_points_0_11(void) // // Opration : OPERATION_3_POINTS_CURVE // Click Souris: 0 // Taille_Pile : 11 // // Souris efface: Non // { if (!Config.Stylus_mode) Curve_drag(); else Curve_finalize(); } void Curve_3_points_12_11(void) // // Opration : OPERATION_3_POINTS_CURVE // Click Souris: 1 ou 2 // Taille_Pile : 11 // // Souris efface: Oui // { if (!Config.Stylus_mode) Curve_finalize(); else Curve_drag(); } ///////////////////////////////////////////////////////////// OPERATION_AIRBRUSH void Airbrush_1_0(void) // // Opration : OPERATION_AIRBRUSH // Click Souris: 1 // Taille_Pile : 0 // // Souris efface: Non // { Init_start_operation(); Backup(); Shade_table=Shade_table_left; if (SDL_GetTicks()>Airbrush_next_time) { Airbrush(LEFT_SIDE); Airbrush_next_time = SDL_GetTicks()+Airbrush_delay*10; } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Airbrush_2_0(void) // // Opration : OPERATION_AIRBRUSH // Click Souris: 2 // Taille_Pile : 0 // // Souris efface: Non // { if (Rightclick_colorpick(1)) return; Init_start_operation(); Backup(); Shade_table=Shade_table_right; if (SDL_GetTicks()>Airbrush_next_time) { Airbrush(RIGHT_SIDE); Airbrush_next_time = SDL_GetTicks()+Airbrush_delay*10; } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Airbrush_12_2(void) // // Opration : OPERATION_AIRBRUSH // Click Souris: 1 ou 2 // Taille_Pile : 2 // // Souris efface: Non // { short old_x,old_y; Uint32 now; Operation_pop(&old_y); Operation_pop(&old_x); if ( (Menu_is_visible) && ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) ) { Hide_cursor(); Print_coordinates(); Display_cursor(); } now=SDL_GetTicks(); if (now>Airbrush_next_time) { //Airbrush_next_time+=Airbrush_delay*10; // Time is now reset, because the += was death spiral // if drawing took more time than the frequency. Airbrush_next_time=now+Airbrush_delay*10; Airbrush(Mouse_K_unique); } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Airbrush_0_2(void) // // Opration : OPERATION_AIRBRUSH // Click Souris: 0 // Taille_Pile : 2 // // Souris efface: Non // { Operation_stack_size-=2; End_of_modification(); } ////////////////////////////////////////////////////////// OPERATION_POLYGON void Polygon_12_0(void) // Opration : OPERATION_POLYGON // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui { byte color; if (Rightclick_colorpick(0)) return; Init_start_operation(); Backup(); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; Paintbrush_shape_before_operation=Paintbrush_shape; Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; // On place temporairement le dbut de la ligne qui ne s'afficherait pas sinon Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Mouse_K | 0x80); Operation_push(color); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); // Taille de pile 8 : phase d'appui, non interruptible } void Polygon_12_9(void) // Opration : OPERATION_POLYGON // Click Souris: 1 ou 2 // Taille_Pile : 9 // // Souris efface: Oui { short start_x; short start_y; short end_x; short end_y; short color; short direction; Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&color); Operation_pop(&direction); Operation_pop(&direction); if (direction==Mouse_K) { Operation_push(direction); Operation_push(color); Operation_push(start_x); Operation_push(start_y); Operation_push(end_x); Operation_push(end_y); // Taille de pile 8 : phase d'appui, non interruptible } else { // La srie de ligne est termine, il faut donc effacer la dernire // preview de ligne et relier le dernier point avec le premier Pixel_figure_preview_auto (start_x,start_y); Hide_line_preview (start_x,start_y,end_x,end_y); Operation_pop(&end_y); Operation_pop(&end_x); Paintbrush_shape=Paintbrush_shape_before_operation; // Le pied aurait t de ne pas repasser sur le 1er point de la 1re ligne // mais c'est pas possible :( Draw_line_permanent(start_x,start_y,end_x,end_y,color); Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; Display_cursor(); End_of_modification(); Wait_end_of_click(); Hide_cursor(); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); Print_coordinates(); } Paintbrush_shape=Paintbrush_shape_before_operation; } } ////////////////////////////////////////////////////////// OPERATION_POLYFILL void Polyfill_12_0(void) // Opration : OPERATION_POLYFILL // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui { byte color; if (Rightclick_colorpick(0)) return; Init_start_operation(); Backup(); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; Paintbrush_hidden=1; color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; Polyfill_table_of_points=(short *) malloc((Config.Nb_max_vertices_per_polygon<<1)*sizeof(short)); Polyfill_table_of_points[0]=Paintbrush_X; Polyfill_table_of_points[1]=Paintbrush_Y; Polyfill_number_of_points=1; // On place temporairement le dbut de la ligne qui ne s'afficherait pas sinon Pixel_figure_preview_xor(Paintbrush_X,Paintbrush_Y,0); Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Mouse_K | 0x80); Operation_push(color); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); // Taille de pile 8 : phase d'appui, non interruptible } void Polyfill_0_8(void) // Opration : OPERATION_POLYFILL // Click Souris: 0 // Taille_Pile : 8 // // Souris efface: Oui { short start_x; short start_y; short end_x; short end_y; short color; short direction; Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&color); Operation_pop(&direction); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Draw_line_preview_xor(start_x,start_y,end_x,end_y,0); if (direction & 0x80) direction=(direction & 0x7F); Operation_push(direction); // Valeur bidon servant de nouvel tat de pile Operation_push(direction); Operation_push(color); Draw_line_preview_xor(start_x,start_y,Paintbrush_X,Paintbrush_Y,0); if (Polyfill_number_of_points=center_x) x_offset=(Paintbrush_X-center_x)%Main_image_width; else x_offset=Main_image_width-((center_x-Paintbrush_X)%Main_image_width); if (Paintbrush_Y>=center_y) y_offset=(Paintbrush_Y-center_y)%Main_image_height; else y_offset=Main_image_height-((center_y-Paintbrush_Y)%Main_image_height); Display_coords_rel_or_abs(center_x,center_y); if (side == RIGHT_SIDE) { // All layers at once Scroll_picture(Screen_backup, Main_screen, x_offset,y_offset); } else { // One layer at once Scroll_picture(Main_backups->Pages->Next->Image[Main_current_layer], Main_backups->Pages->Image[Main_current_layer], x_offset, y_offset); Redraw_current_layer(); } Display_all_screen(); } Operation_push(center_x); Operation_push(center_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(side); } void Scroll_0_5(void) // // Opration : OPERATION_SCROLL // Click Souris: 0 // Taille_Pile : 5 // // Souris efface: Oui // { // All layers at once short center_x; short center_y; short x_pos; short y_pos; short x_offset; short y_offset; short side; int i; Operation_pop(&side); Operation_pop(&y_pos); Operation_pop(&x_pos); Operation_pop(¢er_y); Operation_pop(¢er_x); if (side == RIGHT_SIDE) { // All layers at once if (x_pos>=center_x) x_offset=(x_pos-center_x)%Main_image_width; else x_offset=Main_image_width-((center_x-x_pos)%Main_image_width); if (y_pos>=center_y) y_offset=(y_pos-center_y)%Main_image_height; else y_offset=Main_image_height-((center_y-y_pos)%Main_image_height); // Do the actual scroll operation on all layers. for (i=0; iPages->Nb_layers; i++) //if ((1<Pages->Next->Image[i], Main_backups->Pages->Image[i], x_offset, y_offset); // Update the depth buffer too ... // It would be faster to scroll it, but we don't have method // for in-place scrolling. Update_depth_buffer(); } else { // One layer : everything was done while dragging the mouse } Cursor_hidden=Cursor_hidden_before_scroll; End_of_modification(); if ((Config.Coords_rel) && (Menu_is_visible)) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } //////////////////////////////////////////////////// OPERATION_GRAD_CIRCLE void Grad_circle_12_0(void) // // Opration : OPERATION_GRAD_CIRCLE // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui { byte color; Init_start_operation(); Backup(); Load_gradient_data(Current_gradient); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; Paintbrush_hidden_before_scroll=Paintbrush_hidden; Paintbrush_hidden=1; Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("Radius: 0 ",0); Operation_push(Mouse_K); Operation_push(color); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Grad_circle_12_6(void) // // Opration : OPERATION_GRAD_CIRCLE // Click Souris: 1 ou 2 // Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) // // Souris efface: Non // { short tangent_x; short tangent_y; short center_x; short center_y; short color; short radius; char str[5]; Operation_pop(&tangent_y); Operation_pop(&tangent_x); Operation_pop(¢er_y); Operation_pop(¢er_x); Operation_pop(&color); if ( (tangent_x!=Paintbrush_X) || (tangent_y!=Paintbrush_Y) ) { Hide_cursor(); if ((Config.Coords_rel) && (Menu_is_visible)) { Num2str(Distance(center_x,center_y,Paintbrush_X,Paintbrush_Y),str,4); Print_in_menu(str,7); } else Print_coordinates(); Circle_limit=((tangent_x-center_x)*(tangent_x-center_x))+ ((tangent_y-center_y)*(tangent_y-center_y)); radius=sqrt(Circle_limit); Hide_empty_circle_preview(center_x,center_y,radius); Circle_limit=((Paintbrush_X-center_x)*(Paintbrush_X-center_x))+ ((Paintbrush_Y-center_y)*(Paintbrush_Y-center_y)); radius=sqrt(Circle_limit); Draw_empty_circle_preview(center_x,center_y,radius,color); Display_cursor(); } Operation_push(color); Operation_push(center_x); Operation_push(center_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Grad_circle_0_6(void) // // Opration : OPERATION_GRAD_CIRCLE // Click Souris: 0 // Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) // // Souris efface: Oui // { short tangent_x; short tangent_y; short center_x; short center_y; short color; short click; short radius; Operation_pop(&tangent_y); Operation_pop(&tangent_x); Operation_pop(¢er_y); Operation_pop(¢er_x); Operation_pop(&color); Operation_pop(&click); if (click==LEFT_SIDE) { Operation_push(click); Operation_push(color); Operation_push(center_x); Operation_push(center_y); Operation_push(tangent_x); Operation_push(tangent_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); // On change la forme du curseur Cursor_shape=CURSOR_SHAPE_XOR_TARGET; // On affiche une croix XOR au centre du cercle Draw_curve_cross(center_x,center_y); if (Menu_is_visible) { if (Config.Coords_rel) Print_in_menu("X: Y:",0); else Print_in_menu("X: Y: ",0); Display_coords_rel_or_abs(center_x,center_y); } } else { Circle_limit=((tangent_x-center_x)*(tangent_x-center_x))+ ((tangent_y-center_y)*(tangent_y-center_y)); radius=sqrt(Circle_limit); Hide_empty_circle_preview(center_x,center_y,radius); Paintbrush_hidden=Paintbrush_hidden_before_scroll; Cursor_shape=CURSOR_SHAPE_TARGET; Draw_filled_circle(center_x,center_y,radius,Back_color); End_of_modification(); if ((Config.Coords_rel) && (Menu_is_visible)) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } } void Grad_circle_12_8(void) // // Opration : OPERATION_GRAD_CIRCLE // Click Souris: 0 // Taille_Pile : 8 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente, old_x, old_y) // // Souris efface: Oui // { short tangent_x; short tangent_y; short center_x; short center_y; short color; short old_mouse_k; short radius; Operation_stack_size-=2; // On fait sauter les 2 derniers lts de la pile Operation_pop(&tangent_y); Operation_pop(&tangent_x); Operation_pop(¢er_y); Operation_pop(¢er_x); Operation_pop(&color); Operation_pop(&old_mouse_k); Hide_cursor(); // On efface la croix XOR au centre du cercle Draw_curve_cross(center_x,center_y); Circle_limit=((tangent_x-center_x)*(tangent_x-center_x))+ ((tangent_y-center_y)*(tangent_y-center_y)); radius=sqrt(Circle_limit); Hide_empty_circle_preview(center_x,center_y,radius); Paintbrush_hidden=Paintbrush_hidden_before_scroll; Cursor_shape=CURSOR_SHAPE_TARGET; if (Mouse_K==old_mouse_k) Draw_grad_circle(center_x,center_y,radius,Paintbrush_X,Paintbrush_Y); Display_cursor(); End_of_modification(); Wait_end_of_click(); if ((Config.Coords_rel) && (Menu_is_visible)) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } void Grad_circle_or_ellipse_0_8(void) // // Opration : OPERATION_{CERCLE|ELLIPSE}_DEGRADE // Click Souris: 0 // Taille_Pile : 8 // // Souris efface: Non // { short start_x; short start_y; short tangent_x; short tangent_y; short old_x; short old_y; Operation_pop(&old_y); Operation_pop(&old_x); if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) { Operation_pop(&tangent_y); Operation_pop(&tangent_x); Operation_pop(&start_y); Operation_pop(&start_x); Display_coords_rel_or_abs(start_x,start_y); Operation_push(start_x); Operation_push(start_y); Operation_push(tangent_x); Operation_push(tangent_y); } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } ////////////////////////////////////////////////// OPERATION_GRAD_ELLIPSE void Grad_ellipse_12_0(void) // // Opration : OPERATION_GRAD_ELLIPSE // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui { byte color; Init_start_operation(); Backup(); Load_gradient_data(Current_gradient); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; Paintbrush_hidden_before_scroll=Paintbrush_hidden; Paintbrush_hidden=1; Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Operation_push(Mouse_K); Operation_push(color); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Grad_ellipse_12_6(void) // // Opration : OPERATION_GRAD_ELLIPSE // Click Souris: 1 ou 2 // Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) // // Souris efface: Non // { short tangent_x; short tangent_y; short center_x; short center_y; short color; short horizontal_radius; short vertical_radius; Operation_pop(&tangent_y); Operation_pop(&tangent_x); Operation_pop(¢er_y); Operation_pop(¢er_x); Operation_pop(&color); if ( (tangent_x!=Paintbrush_X) || (tangent_y!=Paintbrush_Y) ) { Hide_cursor(); Display_coords_rel_or_abs(center_x,center_y); horizontal_radius=(tangent_x>center_x)?tangent_x-center_x :center_x-tangent_x; vertical_radius =(tangent_y>center_y)?tangent_y-center_y :center_y-tangent_y; Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); horizontal_radius=(Paintbrush_X>center_x)?Paintbrush_X-center_x :center_x-Paintbrush_X; vertical_radius =(Paintbrush_Y>center_y)?Paintbrush_Y-center_y :center_y-Paintbrush_Y; Draw_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius,color); Display_cursor(); } Operation_push(color); Operation_push(center_x); Operation_push(center_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Grad_ellipse_0_6(void) // // Opration : OPERATION_GRAD_ELLIPSE // Click Souris: 0 // Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) // // Souris efface: Oui // { short tangent_x; short tangent_y; short center_x; short center_y; short color; short click; //short radius; short horizontal_radius; short vertical_radius; Operation_pop(&tangent_y); Operation_pop(&tangent_x); Operation_pop(¢er_y); Operation_pop(¢er_x); Operation_pop(&color); Operation_pop(&click); if (click==LEFT_SIDE) { Operation_push(click); Operation_push(color); Operation_push(center_x); Operation_push(center_y); Operation_push(tangent_x); Operation_push(tangent_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); // On change la forme du curseur Cursor_shape=CURSOR_SHAPE_XOR_TARGET; // On affiche une croix XOR au centre du cercle Draw_curve_cross(center_x,center_y); if (Menu_is_visible) { if (Config.Coords_rel) Print_in_menu("X: Y:",0); else Print_in_menu("X: Y: ",0); Display_coords_rel_or_abs(center_x,center_y); } } else { horizontal_radius=(tangent_x>center_x)?tangent_x-center_x :center_x-tangent_x; vertical_radius =(tangent_y>center_y)?tangent_y-center_y :center_y-tangent_y; Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); Paintbrush_hidden=Paintbrush_hidden_before_scroll; Cursor_shape=CURSOR_SHAPE_TARGET; Draw_filled_ellipse(center_x,center_y,horizontal_radius,vertical_radius,Back_color); End_of_modification(); if ((Config.Coords_rel) && (Menu_is_visible)) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } } void Grad_ellipse_12_8(void) // // Opration : OPERATION_GRAD_ELLIPSE // Click Souris: 0 // Taille_Pile : 8 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente, old_x, old_y) // // Souris efface: Oui // { short tangent_x; short tangent_y; short center_x; short center_y; short color; short horizontal_radius; short vertical_radius; short old_mouse_k; Operation_stack_size-=2; // On fait sauter les 2 derniers lts de la pile Operation_pop(&tangent_y); Operation_pop(&tangent_x); Operation_pop(¢er_y); Operation_pop(¢er_x); Operation_pop(&color); Operation_pop(&old_mouse_k); Hide_cursor(); // On efface la croix XOR au centre de l'ellipse Draw_curve_cross(center_x,center_y); horizontal_radius=(tangent_x>center_x)?tangent_x-center_x :center_x-tangent_x; vertical_radius =(tangent_y>center_y)?tangent_y-center_y :center_y-tangent_y; Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); Paintbrush_hidden=Paintbrush_hidden_before_scroll; Cursor_shape=CURSOR_SHAPE_TARGET; if (Mouse_K==old_mouse_k) Draw_grad_ellipse(center_x,center_y,horizontal_radius,vertical_radius,Paintbrush_X,Paintbrush_Y); Display_cursor(); End_of_modification(); Wait_end_of_click(); if ((Config.Coords_rel) && (Menu_is_visible)) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } /****************************** * Operation_Rectangle_Degrade * ******************************/ // 1) trac d'un rectangle classique avec les lignes XOR // 2) trac d'une ligne vecteur de dgrad, comme une ligne normale // 3) dessin du dgrad void Grad_rectangle_12_0(void) // Opration : OPERATION_GRAD_RECTANGLE // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui // Initialisation de l'tape 1, on commence dessiner le rectangle { Init_start_operation(); Backup(); Load_gradient_data(Current_gradient); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("\035: 1 \022: 1",0); // On laisse une trace du curseur l'cran Display_cursor(); if (Mouse_K==LEFT_SIDE) { Shade_table=Shade_table_left; Operation_push(Mouse_K); } else { Shade_table=Shade_table_right; Operation_push(Mouse_K); } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Grad_rectangle_12_5(void) // Opration : OPERATION_GRAD_RECTANGLE // Click Souris: 1 ou 2 // Taille_Pile : 5 // // Souris efface: Non // Modification de la taille du rectangle { short start_x; short start_y; short old_x; short old_y; char str[5]; Operation_pop(&old_y); Operation_pop(&old_x); if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) { Operation_pop(&start_y); Operation_pop(&start_x); if ((Config.Coords_rel) && (Menu_is_visible)) { Num2str(((start_x Min(Main_image_width, Main_magnifier_mode?Main_separator_position:Screen_width)) { offset_width = end_x - Min(Main_image_width, Main_magnifier_mode?Main_separator_position:Screen_width); } if (end_y-Main_offset_Y > Min(Main_image_height, Menu_Y)) offset_height = end_y - Min(Main_image_height, Menu_Y); if (width == 0) { // Single line Vertical_XOR_line(start_x-Main_offset_X, start_y - Main_offset_Y, height - offset_height + 1); } else if (height == 0) { // Single line Horizontal_XOR_line(start_x-Main_offset_X, start_y - Main_offset_Y, width - offset_width + 1); } else { // Dessin dans la zone de dessin normale Horizontal_XOR_line(start_x-Main_offset_X, start_y - Main_offset_Y, width - offset_width + 1); // If not, this line is out of the picture so there is no need to draw it if (offset_height == 0 || end_y - 1 > Menu_Y + Main_offset_Y) { Horizontal_XOR_line(start_x - Main_offset_X, end_y - Main_offset_Y, width - offset_width + 1); } if (height > offset_height + 2) { Vertical_XOR_line(start_x-Main_offset_X, start_y - Main_offset_Y + 1, height - offset_height - 1); if (offset_width == 0) { Vertical_XOR_line(end_x - Main_offset_X, start_y - Main_offset_Y + 1, height - offset_height - 1); } } } Update_rect(start_x - Main_offset_X, start_y - Main_offset_Y, width + 1 - offset_width, height + 1 - offset_height); // Dessin dans la zone zoome if (Main_magnifier_mode && start_x <= Limit_right_zoom && end_x > Limit_left_zoom && start_y <= Limit_bottom_zoom && end_y > Limit_top_zoom ) { offset_width = 0; offset_height = 0; if (start_xLimit_right_zoom) // On dpasse du zoom droite offset_width += end_x - Limit_right_zoom; if(start_yLimit_bottom_zoom) // On dpasse du zoom en bas offset_height += end_y - Limit_bottom_zoom; if(width > offset_width) { if(offset_top==0) // La ligne du haut est visible Horizontal_XOR_line_zoom(offset_left>0?offset_left:start_x,start_y,width-offset_width+1); if(height!=0 && end_y<=Limit_bottom_zoom) // La ligne du bas est visible Horizontal_XOR_line_zoom(offset_left>0?offset_left:start_x,end_y,width-offset_width+1); } if (width==0 && height!=0 && height > offset_height && offset_left==0) { // Single vertical line Vertical_XOR_line_zoom(start_x,offset_top!=0?offset_top:start_y,height-offset_height); } else { if(height > offset_height + 2) { if(offset_left==0) // La ligne de gauche est visible Vertical_XOR_line_zoom(start_x,offset_top!=0?offset_top:(start_y+1),height-offset_height-(offset_top==0)+(end_y>Limit_bottom_zoom)); if(end_x<=Limit_right_zoom) // La ligne de droite est visible Vertical_XOR_line_zoom(end_x,offset_top!=0?offset_top:(start_y+1),height-offset_height-(offset_top==0)+(end_y>Limit_bottom_zoom)); } } } } void Grad_rectangle_0_5(void) // OPERATION_GRAD_RECTANGLE // click souris 0 // Taile pile : 5 // // Souris efface : non // Le rectangle est en place, maintenant il faut tracer le vecteur de dgrad, // on doit donc attendre que l'utilisateur clique quelque part // On stocke tout de suite les coordonnes du pinceau comme a on change d'tat et on passe la suite { // !!! Cette fonction remet start_x start_y end_x end_y dans la pile la fin donc il ne faut pas les modifier ! (sauf ventuellement un tri) short start_x; short start_y; short end_x; short end_y; short width,height; // Trac propre du rectangle Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); // This trick will erase the large crosshair at original position, // in normal and zoomed views. Paintbrush_X = start_x; Paintbrush_Y = start_y; if (start_x>end_x) SWAP_SHORTS(start_x, end_x) if (start_y>end_y) SWAP_SHORTS(start_y, end_y) Hide_cursor(); width = end_x - start_x; height = end_y - start_y; // Check if the rectangle is not fully outside the picture if (start_x > Main_image_width // Rectangle at right of picture || start_y > Main_image_height // Rectangle below picture || start_y - 1 - Main_offset_Y > Menu_Y ) // Rectangle below viewport { Operation_pop(&end_y); // reset the stack return; // cancel the operation } Draw_xor_rect(start_x, start_y, end_x, end_y); Operation_push(start_x); Operation_push(start_y); Operation_push(end_x); Operation_push(end_y); // On ajoute des trucs dans la pile pour forcer le passage l'tape suivante Operation_push(end_x); Operation_push(end_y); } void Grad_rectangle_0_7(void) // OPERATION_GRAD_RECTANGLE // click souris 0 // Taile pile : 5 // // Souris efface : non // On continue attendre que l'utilisateur clique en gardant les coords jour { Operation_stack_size -= 2; Print_coordinates(); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Grad_rectangle_12_7(void) // Opration : OPERATION_GRAD_RECTANGLE // Click Souris: 1 ou 2 // Taille_Pile : 7 // // Souris efface: Oui // Dbut du trac du vecteur (premier clic) // On garde les anciennes coordonnes dans la pile, et on ajoute les nouvelles par dessus // Si l'utilisateur utilise le mauvais bouton, on annule le trac. Mais a nous oblige vider toute la pile pour vrifier :( { short start_x,end_x,start_y,end_y,vax,vay,click; Operation_pop(&vay); Operation_pop(&vax); Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&click); if(click==Mouse_K) { Operation_push(click); Operation_push(start_x); Operation_push(start_y); Operation_push(end_x); Operation_push(end_y); Operation_push(vax); Operation_push(vay); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } else { // Mauvais bouton > anulation de l'opration. // On a dj vid la pile, il reste effacer le rectangle XOR Draw_xor_rect(start_x, start_y, end_x, end_y); } } void Grad_rectangle_12_9(void) // Opration : OPERATION_GRAD_RECTANGLE // Click Souris: 1 // Taille_Pile : 9 // // Souris efface: Oui // Poursuite du trac du vecteur (dplacement de la souris en gardant le curseur appuy) { short start_x; short start_y; short end_x; short end_y; short cursor_x; short cursor_y; Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); cursor_x = Paintbrush_X; cursor_y = Paintbrush_Y; // On corrige les coordonnes de la ligne si la touche shift est appuye... if(SDL_GetModState() & KMOD_SHIFT) Clamp_coordinates_regular_angle(start_x,start_y,&cursor_x,&cursor_y); if ((cursor_x!=end_x) || (cursor_y!=end_y)) { Display_coords_rel_or_abs(start_x,start_y); Draw_line_preview_xor(start_x,start_y,end_x,end_y,0); Draw_line_preview_xor(start_x,start_y,cursor_x,cursor_y,0); } Operation_push(start_x); Operation_push(start_y); Operation_push(cursor_x); Operation_push(cursor_y); } void Grad_rectangle_0_9(void) // Opration : OPERATION_GRAD_RECTANGLE // Click Souris: 0 // Taille_Pile : 9 // // Souris efface: Oui // Ouf, fini ! on dessine enfin le rectangle avec son dgrad { short rect_start_x; short rect_start_y; short rect_end_x; short rect_end_y; short vector_start_x; short vector_start_y; short vector_end_x; short vector_end_y; Operation_pop(&vector_end_y); Operation_pop(&vector_end_x); Operation_pop(&vector_start_y); Operation_pop(&vector_start_x); Operation_pop(&rect_end_y); Operation_pop(&rect_end_x); Operation_pop(&rect_start_y); Operation_pop(&rect_start_x); Operation_stack_size--; Hide_cursor(); // Maintenant on efface tout le bazar temporaire : rectangle et ligne XOR Draw_xor_rect(rect_start_x, rect_start_y, rect_end_x, rect_end_y); Hide_line_preview(vector_start_x,vector_start_y,vector_end_x,vector_end_y); // Et enfin on trace le rectangle avec le dgrad dedans ! if (vector_end_x==vector_start_x && vector_end_y==vector_start_y) { // Vecteur nul > pas de rectangle trac } else { Draw_grad_rectangle(rect_start_x,rect_start_y,rect_end_x,rect_end_y,vector_start_x,vector_start_y,vector_end_x,vector_end_y); } Display_cursor(); End_of_modification(); Wait_end_of_click(); if ((Config.Coords_rel) && (Menu_is_visible)) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } /////////////////////////////////////////////////// OPERATION_CENTERED_LINES void Centered_lines_12_0(void) // Opration : OPERATION_CENTERED_LINES // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui { if (Rightclick_colorpick(0)) return; Init_start_operation(); Backup(); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Operation_push(Mouse_K); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Centered_lines_12_3(void) // Opration : OPERATION_CENTERED_LINES // Click Souris: 1 ou 2 // Taille_Pile : 3 // // Souris efface: Non { short start_x; short start_y; Operation_pop(&start_y); Operation_pop(&start_x); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Centered_lines_0_3(void) // Opration : OPERATION_CENTERED_LINES // Click Souris: 0 // Taille_Pile : 3 // // Souris efface: Oui { short start_x; short start_y; short Button; short color; Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&Button); color=(Button==LEFT_SIDE)?Fore_color:Back_color; Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); Paintbrush_shape_before_operation=Paintbrush_shape; Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; Operation_push(Button); Operation_push(Paintbrush_X); // Nouveau dbut X Operation_push(Paintbrush_Y); // Nouveau dbut Y Operation_push(Paintbrush_X); // Nouvelle dernire fin X Operation_push(Paintbrush_Y); // Nouvelle dernire fin Y Operation_push(Paintbrush_X); // Nouvelle dernire position X Operation_push(Paintbrush_Y); // Nouvelle dernire position Y } void Centered_lines_12_7(void) // Opration : OPERATION_CENTERED_LINES // Click Souris: 1 ou 2 // Taille_Pile : 7 // // Souris efface: Non { short Button; short start_x; short start_y; short end_x; short end_y; short last_x; short last_y; short color; Operation_pop(&last_y); Operation_pop(&last_x); Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&Button); if (Mouse_K==Button) { if ( (end_x!=Paintbrush_X) || (end_y!=Paintbrush_Y) || (last_x!=Paintbrush_X) || (last_y!=Paintbrush_Y) ) { Hide_cursor(); color=(Button==LEFT_SIDE)?Fore_color:Back_color; Paintbrush_shape=Paintbrush_shape_before_operation; Pixel_figure_preview_auto (start_x,start_y); Hide_line_preview (start_x,start_y,last_x,last_y); Smear_start=1; Display_paintbrush (start_x,start_y,color,0); Draw_line_permanent(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); Draw_line_preview(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); Display_cursor(); } Operation_push(Button); Operation_push(start_x); Operation_push(start_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } else { Hide_cursor(); Paintbrush_shape=Paintbrush_shape_before_operation; Pixel_figure_preview_auto (start_x,start_y); Hide_line_preview (start_x,start_y,last_x,last_y); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); Print_coordinates(); } Display_cursor(); End_of_modification(); Wait_end_of_click(); } } void Centered_lines_0_7(void) // Opration : OPERATION_CENTERED_LINES // Click Souris: 0 // Taille_Pile : 7 // // Souris efface: Non { short Button; short start_x; short start_y; short end_x; short end_y; short last_x; short last_y; short color; Operation_pop(&last_y); Operation_pop(&last_x); Operation_pop(&end_y); Operation_pop(&end_x); if ((Paintbrush_X!=last_x) || (Paintbrush_Y!=last_y)) { Hide_cursor(); Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&Button); color=(Button==LEFT_SIDE)?Fore_color:Back_color; Display_coords_rel_or_abs(start_x,start_y); Hide_line_preview(start_x,start_y,last_x,last_y); Pixel_figure_preview(start_x,start_y,color); Draw_line_preview(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); Operation_push(Button); Operation_push(start_x); Operation_push(start_y); Display_cursor(); } Operation_push(end_x); Operation_push(end_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } grafx2/src/pages.c0000644000076400010400000011537711522560062014501 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ ////////////////////////////////////////////////////////////////////////// /////////////////////////// GESTION DU BACKUP //////////////////////////// ////////////////////////////////////////////////////////////////////////// #include #include #include #include "global.h" #include "pages.h" #include "errors.h" #include "loadsave.h" #include "misc.h" #include "windows.h" // -- Layers data /// Array of two images, that contains the "flattened" version of the visible layers. #ifndef NOLAYERS T_Bitmap Main_visible_image; T_Bitmap Main_visible_image_backup; T_Bitmap Main_visible_image_depth_buffer; T_Bitmap Spare_visible_image; #endif /// /// GESTION DES PAGES /// /// Bitfield which records which layers are backed up in Page 0. static dword Last_backed_up_layers=0; /// Total number of unique bitmaps (layers, animation frames, backups) long Stats_pages_number=0; /// Total memory used by bitmaps (layers, animation frames, backups) long long Stats_pages_memory=0; /// Allocate and initialize a new page. T_Page * New_page(byte nb_layers) { T_Page * page; page = (T_Page *)malloc(sizeof(T_Page)+nb_layers*sizeof(byte *)); if (page!=NULL) { int i; for (i=0; iImage[i]=NULL; page->Width=0; page->Height=0; memset(page->Palette,0,sizeof(T_Palette)); page->Comment[0]='\0'; page->File_directory[0]='\0'; page->Filename[0]='\0'; page->File_format=DEFAULT_FILEFORMAT; page->Nb_layers=nb_layers; page->Gradients=NULL; page->Transparent_color=0; // Default transparent color page->Background_transparent=0; page->Next = page->Prev = NULL; } return page; } // ============================================================== // Layers allocation functions. // // Layers are made of a "number of users" (short), followed by // the actual pixel data (a large number of bytes). // Every time a layer is 'duplicated' as a reference, the number // of users is incremented. // Every time a layer is freed, the number of users is decreased, // and only when it reaches zero the pixel data is freed. // ============================================================== /// Allocate a new layer byte * New_layer(long pixel_size) { short * ptr = malloc(sizeof(short)+pixel_size); if (ptr==NULL) return NULL; // Stats Stats_pages_number++; Stats_pages_memory+=pixel_size; *ptr = 1; return (byte *)(ptr+1); } /// Free a layer void Free_layer(T_Page * page, byte layer) { short * ptr; if (page->Image[layer]==NULL) return; ptr = (short *)(page->Image[layer]); if (-- (*(ptr-1))) // Users-- return; else { free(ptr-1); } // Stats Stats_pages_number--; Stats_pages_memory-=page->Width * page->Height; } /// Duplicate a layer (new reference) byte * Dup_layer(byte * layer) { short * ptr = (short *)(layer); if (layer==NULL) return NULL; (*(ptr-1)) ++; // Users ++ return layer; } // ============================================================== /// Adds a shared reference to the gradient data of another page. Pass NULL for new. T_Gradient_array *Dup_gradient(T_Page * page) { // new if (page==NULL || page->Gradients==NULL) { T_Gradient_array *array; array=(T_Gradient_array *)calloc(1, sizeof(T_Gradient_array)); if (!array) return NULL; array->Used=1; return array; } // shared page->Gradients->Used++; return page->Gradients; } void Download_infos_page_main(T_Page * page) // Affiche la page l'cran { //int factor_index; int size_is_modified; if (page!=NULL) { size_is_modified=(Main_image_width!=page->Width) || (Main_image_height!=page->Height); Main_image_width=page->Width; Main_image_height=page->Height; memcpy(Main_palette,page->Palette,sizeof(T_Palette)); strcpy(Main_comment,page->Comment); Main_fileformat=page->File_format; if (size_is_modified) { Main_magnifier_mode=0; Main_offset_X=0; Main_offset_Y=0; Pixel_preview=Pixel_preview_normal; Compute_limits(); Compute_paintbrush_coordinates(); } } //Update_buffers( page->Width, page->Height); //memcpy(Main_screen, page->Image[Main_current_layer], page->Width*page->Height); } void Redraw_layered_image(void) { #ifndef NOLAYERS // Re-construct the image with the visible layers byte layer; // First layer for (layer=0; layerPages->Nb_layers; layer++) { if ((1<Pages->Image[layer], Main_image_width*Main_image_height); // Initialize the depth buffer memset(Main_visible_image_depth_buffer.Image, layer, Main_image_width*Main_image_height); // skip all other layers layer++; break; } } // subsequent layer(s) for (; layerPages->Nb_layers; layer++) { if ((1<Pages->Image[layer]+i); if (color != Main_backups->Pages->Transparent_color) // transparent color { *(Main_visible_image.Image+i) = color; if (layer != Main_current_layer) *(Main_visible_image_depth_buffer.Image+i) = layer; } } } } #else Update_screen_targets(); #endif Update_FX_feedback(Config.FX_Feedback); } void Update_depth_buffer(void) { #ifndef NOLAYERS // Re-construct the depth buffer with the visible layers. // This function doesn't touch the visible buffer, it assumes // that it was already up-to-date. (Ex. user only changed active layer) int layer; // First layer for (layer=0; layerPages->Nb_layers; layer++) { if ((1<Pages->Nb_layers; layer++) { // skip the current layer, whenever we reach it if (layer == Main_current_layer) continue; if ((1<Pages->Image[layer]+i); if (color != Main_backups->Pages->Transparent_color) // transparent color { *(Main_visible_image_depth_buffer.Image+i) = layer; } } } } #endif Update_FX_feedback(Config.FX_Feedback); } void Redraw_spare_image(void) { #ifndef NOLAYERS // Re-construct the image with the visible layers byte layer; // First layer for (layer=0; layerPages->Nb_layers; layer++) { if ((1<Pages->Image[layer], Spare_image_width*Spare_image_height); // No depth buffer in the spare //memset(Spare_visible_image_depth_buffer.Image, // layer, // Spare_image_width*Spare_image_height); // skip all other layers layer++; break; } } // subsequent layer(s) for (; layerPages->Nb_layers; layer++) { if ((1<Pages->Image[layer]+i); if (color != Spare_backups->Pages->Transparent_color) // transparent color { *(Spare_visible_image.Image+i) = color; //if (layer != Spare_current_layer) // *(Spare_visible_image_depth_buffer.Image+i) = layer; } } } } #endif } void Redraw_current_layer(void) { #ifndef NOLAYERS int i; for (i=0; iPages->Image[Main_current_layer]+i); if (color != Main_backups->Pages->Transparent_color) // transparent color { *(Main_visible_image.Image+i) = color; } else { *(Main_visible_image.Image+i) = *(Main_backups->Pages->Image[depth]+i); } } } #endif } void Upload_infos_page_main(T_Page * page) // Sauve l'cran courant dans la page { if (page!=NULL) { //page->Image[Main_current_layer]=Main_screen; page->Width=Main_image_width; page->Height=Main_image_height; memcpy(page->Palette,Main_palette,sizeof(T_Palette)); strcpy(page->Comment,Main_comment); page->File_format=Main_fileformat; } } void Download_infos_page_spare(T_Page * page) { if (page!=NULL) { Spare_image_width=page->Width; Spare_image_height=page->Height; memcpy(Spare_palette,page->Palette,sizeof(T_Palette)); Spare_fileformat=page->File_format; } } void Upload_infos_page_spare(T_Page * page) { if (page!=NULL) { //page->Image[Spare_current_layer]=Spare_screen; page->Width=Spare_image_width; page->Height=Spare_image_height; memcpy(page->Palette,Spare_palette,sizeof(T_Palette)); page->File_format=Spare_fileformat; } } byte * FX_feedback_screen; void Update_FX_feedback(byte with_feedback) { if (with_feedback) FX_feedback_screen=Main_backups->Pages->Image[Main_current_layer]; else FX_feedback_screen=Main_backups->Pages->Next->Image[Main_current_layer]; } void Clear_page(T_Page * page) { // On peut appeler cette fonction sur une page non alloue. int i; for (i=0; iNb_layers; i++) { Free_layer(page, i); page->Image[i]=NULL; } // Free_gradient() : This data is reference-counted if (page->Gradients) { page->Gradients->Used--; if (page->Gradients->Used==0) free(page->Gradients); page->Gradients=NULL; } page->Width=0; page->Height=0; // On ne se proccupe pas de ce que deviens le reste des infos de l'image. } void Copy_S_page(T_Page * dest,T_Page * source) { *dest=*source; dest->Gradients=NULL; } /// /// GESTION DES LISTES DE PAGES /// void Init_list_of_pages(T_List_of_pages * list) { // Important: appeler cette fonction sur toute nouvelle structure // T_List_of_pages! list->List_size=0; list->Pages=NULL; } int Allocate_list_of_pages(T_List_of_pages * list) { // Important: la T_List_of_pages ne doit pas dj dsigner une liste de // pages alloue auquel cas celle-ci serait perdue. T_Page * page; // On initialise chacune des nouvelles pages page=New_page(NB_LAYERS); if (!page) return 0; // Set as first page of the list page->Next = page; page->Prev = page; list->Pages = page; list->List_size=1; page->Gradients=Dup_gradient(NULL); if (!page->Gradients) return 0; return 1; // Succs } void Backward_in_list_of_pages(T_List_of_pages * list) { // Cette fonction fait l'quivalent d'un "Undo" dans la liste de pages. // Elle effectue une sorte de ROL (Rotation Left) sur la liste: // +---+-+-+-+-+-+-+-+-+-+ | // 0123456789A | // +---+-+-+-+-+-+-+-+-+-+ | 0=page courante // |_ A=page la plus ancienne // v v v v v v v v v v v | 1=Dernire page (1er backup) // +---+-+-+-+-+-+-+-+-+-+ | // 123456789A0 | // +---+-+-+-+-+-+-+-+-+-+ | // Pour simuler un vritable Undo, l'appelant doit mettre la structure // de page courante jour avant l'appel, puis en rextraire les infos en // sortie, ainsi que celles relatives la plus rcente page d'undo (1re // page de la liste). if (Last_backed_up_layers) { // First page contains a ready-made backup of its ->Next. // We have swap the first two pages, so the original page 0 // will end up in position 0 again, and then overwrite it with a backup // of the 'new' page1. T_Page * page0; T_Page * page1; page0 = list->Pages; page1 = list->Pages->Next; page0->Next = page1->Next; page1->Prev = page0->Prev; page0->Prev = page1; page1->Next = page0; list->Pages = page0; return; } list->Pages = list->Pages->Next; } void Advance_in_list_of_pages(T_List_of_pages * list) { // Cette fonction fait l'quivalent d'un "Redo" dans la liste de pages. // Elle effectue une sorte de ROR (Rotation Right) sur la liste: // +-+-+-+-+-+-+-+-+-+-+-+ | // |0|1|2|3|4|5|6|7|8|9|A| | // +-+-+-+-+-+-+-+-+-+-+-+ | 0=page courante // | | | | | | | | | | | |_ A=page la plus ancienne // v v v v v v v v v v v | 1=Dernire page (1er backup) // +-+-+-+-+-+-+-+-+-+-+-+ | // |A|0|1|2|3|4|5|6|7|8|9| | // +-+-+-+-+-+-+-+-+-+-+-+ | // Pour simuler un vritable Redo, l'appelant doit mettre la structure // de page courante jour avant l'appel, puis en rextraire les infos en // sortie, ainsi que celles relatives la plus rcente page d'undo (1re // page de la liste). if (Last_backed_up_layers) { // First page contains a ready-made backup of its ->Next. // We have swap the first two pages, so the original page 0 // will end up in position -1 again, and then overwrite it with a backup // of the 'new' page1. T_Page * page0; T_Page * page1; page0 = list->Pages; page1 = list->Pages->Prev; page0->Prev = page1->Prev; page1->Next = page0->Next; page0->Next = page1; page1->Prev = page0; list->Pages = page1; return; } list->Pages = list->Pages->Prev; } void Free_last_page_of_list(T_List_of_pages * list) { if (list!=NULL) { if (list->List_size>0) { T_Page * page; // The last page is the one before first page = list->Pages->Prev; page->Next->Prev = page->Prev; page->Prev->Next = page->Next; Clear_page(page); free(page); page = NULL; list->List_size--; } } } // layer_mask tells which layers have to be fresh copies instead of references int Create_new_page(T_Page * new_page, T_List_of_pages * list, dword layer_mask) { // This function fills the "Image" field of a new Page, // based on the pages's attributes (width,height,...) // then pushes it on front of a Page list. if (list->List_size >= (Config.Max_undo_pages+1)) { // List is full. // If some other memory-limit was to be implemented, here would // be the right place to do it. // For example, we could rely on Stats_pages_memory, // because it's the sum of all bitmaps in use (in bytes). // Destroy the latest page Free_last_page_of_list(list); } { int i; for (i=0; iNb_layers; i++) { if ((1<Image[i]=New_layer(new_page->Height*new_page->Width); else new_page->Image[i]=Dup_layer(list->Pages->Image[i]); } } // Insert as first new_page->Next = list->Pages; new_page->Prev = list->Pages->Prev; list->Pages->Prev->Next = new_page; list->Pages->Prev = new_page; list->Pages = new_page; list->List_size++; return 1; } void Change_page_number_of_list(T_List_of_pages * list,int number) { // Truncate the list if larger than requested while(list->List_size > number) { Free_last_page_of_list(list); } } void Free_page_of_a_list(T_List_of_pages * list) { // On ne peut pas dtruire la page courante de la liste si aprs // destruction il ne reste pas encore au moins une page. if (list->List_size>1) { // On fait faire un undo la liste, comme a, la nouvelle page courante // est la page prcdente Backward_in_list_of_pages(Main_backups); // Puis on dtruit la dernire page, qui est l'ancienne page courante Free_last_page_of_list(list); } } void Update_screen_targets(void) { #ifndef NOLAYERS Main_screen=Main_visible_image.Image; Screen_backup=Main_visible_image_backup.Image; #else Main_screen=Main_backups->Pages->Image[Main_current_layer]; Screen_backup=Main_backups->Pages->Next->Image[Main_current_layer]; #endif } /// Update all the special image buffers, if necessary. int Update_buffers(int width, int height) { #ifndef NOLAYERS // At least one dimension is different if (Main_visible_image.Width*Main_visible_image.Height != width*height) { // Current image free(Main_visible_image.Image); Main_visible_image.Image = (byte *)malloc(width * height); if (Main_visible_image.Image == NULL) return 0; } Main_visible_image.Width = width; Main_visible_image.Height = height; if (Main_visible_image_backup.Width*Main_visible_image_backup.Height != width*height) { // Previous image free(Main_visible_image_backup.Image); Main_visible_image_backup.Image = (byte *)malloc(width * height); if (Main_visible_image_backup.Image == NULL) return 0; } Main_visible_image_backup.Width = width; Main_visible_image_backup.Height = height; if (Main_visible_image_depth_buffer.Width*Main_visible_image_depth_buffer.Height != width*height) { // Depth buffer free(Main_visible_image_depth_buffer.Image); Main_visible_image_depth_buffer.Image = (byte *)malloc(width * height); if (Main_visible_image_depth_buffer.Image == NULL) return 0; } Main_visible_image_depth_buffer.Width = width; Main_visible_image_depth_buffer.Height = height; #endif Update_screen_targets(); return 1; } /// Update all the special image buffers of the spare page, if necessary. int Update_spare_buffers(int width, int height) { #ifndef NOLAYERS // At least one dimension is different if (Spare_visible_image.Width*Spare_visible_image.Height != width*height) { // Current image free(Spare_visible_image.Image); Spare_visible_image.Image = (byte *)malloc(width * height); if (Spare_visible_image.Image == NULL) return 0; } Spare_visible_image.Width = width; Spare_visible_image.Height = height; #endif return 1; } /// /// GESTION DES BACKUPS /// int Init_all_backup_lists(int width,int height) { // width et height correspondent la dimension des images de dpart. int i; if (! Allocate_list_of_pages(Main_backups) || ! Allocate_list_of_pages(Spare_backups)) return 0; // On a russi allouer deux listes de pages dont la taille correspond // celle demande par l'utilisateur. // On cre un descripteur de page correspondant la page principale Upload_infos_page_main(Main_backups->Pages); // On y met les infos sur la dimension de dmarrage Main_backups->Pages->Width=width; Main_backups->Pages->Height=height; strcpy(Main_backups->Pages->File_directory,Main_current_directory); strcpy(Main_backups->Pages->Filename,"NO_NAME.GIF"); for (i=0; iPages->Nb_layers; i++) { Main_backups->Pages->Image[i]=New_layer(width*height); if (! Main_backups->Pages->Image[i]) return 0; memset(Main_backups->Pages->Image[i], 0, width*height); } #ifndef NOLAYERS Main_visible_image.Width = 0; Main_visible_image.Height = 0; Main_visible_image.Image = NULL; Main_visible_image_backup.Image = NULL; Main_visible_image_depth_buffer.Image = NULL; Spare_visible_image.Width = 0; Spare_visible_image.Height = 0; Spare_visible_image.Image = NULL; #endif if (!Update_buffers(width, height)) return 0; if (!Update_spare_buffers(width, height)) return 0; #ifndef NOLAYERS // For speed, instead of Redraw_layered_image() we'll directly set the buffers. memset(Main_visible_image.Image, 0, width*height); memset(Main_visible_image_backup.Image, 0, width*height); memset(Main_visible_image_depth_buffer.Image, 0, width*height); memset(Spare_visible_image.Image, 0, width*height); #endif Download_infos_page_main(Main_backups->Pages); Update_FX_feedback(Config.FX_Feedback); // Default values for spare page Spare_backups->Pages->Width = width; Spare_backups->Pages->Height = height; memcpy(Spare_backups->Pages->Palette,Main_palette,sizeof(T_Palette)); strcpy(Spare_backups->Pages->Comment,""); strcpy(Spare_backups->Pages->File_directory,Main_current_directory); strcpy(Spare_backups->Pages->Filename,"NO_NAME2.GIF"); Spare_backups->Pages->File_format=DEFAULT_FILEFORMAT; // Copy this informations in the global Spare_ variables Download_infos_page_spare(Spare_backups->Pages); // Clear the initial Visible buffer //memset(Main_screen,0,Main_image_width*Main_image_height); // Spare for (i=0; iPages->Image[i]=New_layer(width*height); if (! Spare_backups->Pages->Image[i]) return 0; memset(Spare_backups->Pages->Image[i], 0, width*height); } //memset(Spare_screen,0,Spare_image_width*Spare_image_height); End_of_modification(); return 1; } void Set_number_of_backups(int nb_backups) { Change_page_number_of_list(Main_backups,nb_backups+1); Change_page_number_of_list(Spare_backups,nb_backups+1); // Le +1 vient du fait que dans chaque liste, en 1re position on retrouve // les infos de la page courante sur le brouillon et la page principale. // (nb_backups = Nombre de backups, sans compter les pages courantes) } int Backup_new_image(byte layers,int width,int height) { // Retourne 1 si une nouvelle page est disponible et 0 sinon T_Page * new_page; // On cre un descripteur pour la nouvelle page courante new_page=New_page(layers); if (!new_page) { Error(0); return 0; } new_page->Width=width; new_page->Height=height; new_page->Transparent_color=0; new_page->Gradients=Dup_gradient(NULL); if (!Create_new_page(new_page,Main_backups,0xFFFFFFFF)) { Error(0); return 0; } Update_buffers(width, height); Download_infos_page_main(Main_backups->Pages); return 1; } int Backup_with_new_dimensions(int width,int height) { // Retourne 1 si une nouvelle page est disponible (alors pleine de 0) et // 0 sinon. T_Page * new_page; int i; // On cre un descripteur pour la nouvelle page courante new_page=New_page(Main_backups->Pages->Nb_layers); if (!new_page) { Error(0); return 0; } new_page->Width=width; new_page->Height=height; new_page->Transparent_color=0; if (!Create_new_page(new_page,Main_backups,0xFFFFFFFF)) { Error(0); return 0; } // Copy data from previous history step memcpy(Main_backups->Pages->Palette,Main_backups->Pages->Next->Palette,sizeof(T_Palette)); strcpy(Main_backups->Pages->Comment,Main_backups->Pages->Next->Comment); Main_backups->Pages->File_format=Main_backups->Pages->Next->File_format; strcpy(Main_backups->Pages->Filename, Main_backups->Pages->Next->Filename); strcpy(Main_backups->Pages->File_directory, Main_backups->Pages->Next->File_directory); Main_backups->Pages->Gradients=Dup_gradient(Main_backups->Pages->Next); Main_backups->Pages->Background_transparent=Main_backups->Pages->Next->Background_transparent; Main_backups->Pages->Transparent_color=Main_backups->Pages->Next->Transparent_color; // Fill with transparent color for (i=0; iPages->Nb_layers;i++) { memset(Main_backups->Pages->Image[i], Main_backups->Pages->Transparent_color, width*height); } Update_buffers(width, height); Download_infos_page_main(Main_backups->Pages); // Same code as in End_of_modification(), // Without saving a safety backup: #ifndef NOLAYERS memcpy(Main_visible_image_backup.Image, Main_visible_image.Image, Main_image_width*Main_image_height); #else Update_screen_targets(); #endif Update_FX_feedback(Config.FX_Feedback); // -- return 1; } /// /// Resizes a backup step in-place (doesn't add a Undo/Redo step). /// Should only be called after an actual backup, because it loses the current. /// pixels. This function is meant to be used from within Lua scripts. int Backup_in_place(int width,int height) { // Retourne 1 si une nouvelle page est disponible (alors pleine de 0) et // 0 sinon. int i; byte ** new_layer; // Perform all allocations first new_layer=calloc(Main_backups->Pages->Nb_layers,1); if (!new_layer) return 0; for (i=0; iPages->Nb_layers; i++) { new_layer[i]=New_layer(height*width); if (!new_layer[i]) { // Allocation error for (; i>0; i--) free(new_layer[i]); free(new_layer); return 0; } } // Now ok to proceed for (i=0; iPages->Nb_layers; i++) { // Replace layers Free_layer(Main_backups->Pages,i); Main_backups->Pages->Image[i]=new_layer[i]; // Fill with transparency memset(Main_backups->Pages->Image[i], Main_backups->Pages->Transparent_color, width*height); } Main_backups->Pages->Width=width; Main_backups->Pages->Height=height; Download_infos_page_main(Main_backups->Pages); // The following is part of Update_buffers() // (without changing the backup buffer) #ifndef NOLAYERS // At least one dimension is different if (Main_visible_image.Width*Main_visible_image.Height != width*height) { // Current image free(Main_visible_image.Image); Main_visible_image.Image = (byte *)malloc(width * height); if (Main_visible_image.Image == NULL) return 0; } Main_visible_image.Width = width; Main_visible_image.Height = height; if (Main_visible_image_depth_buffer.Width*Main_visible_image_depth_buffer.Height != width*height) { // Depth buffer free(Main_visible_image_depth_buffer.Image); Main_visible_image_depth_buffer.Image = (byte *)malloc(width * height); if (Main_visible_image_depth_buffer.Image == NULL) return 0; } Main_visible_image_depth_buffer.Width = width; Main_visible_image_depth_buffer.Height = height; #endif Update_screen_targets(); return 1; } int Backup_and_resize_the_spare(int width,int height) { // Retourne 1 si la page de dimension souhaitee est disponible en brouillon // et 0 sinon. T_Page * new_page; int return_code=0; byte nb_layers; nb_layers=Spare_backups->Pages->Nb_layers; // On cre un descripteur pour la nouvelle page de brouillon new_page=New_page(nb_layers); if (!new_page) { Error(0); return 0; } // Fill it with a copy of the latest history Copy_S_page(new_page,Spare_backups->Pages); new_page->Gradients=Dup_gradient(Spare_backups->Pages); new_page->Width=width; new_page->Height=height; if (Create_new_page(new_page,Spare_backups,0xFFFFFFFF)) { byte i; for (i=0; iPages->Image[i], Spare_backups->Pages->Transparent_color, width*height); } // Update_buffers(width, height); // Not for spare Download_infos_page_spare(Spare_backups->Pages); // Light up the 'has unsaved changes' indicator Spare_image_is_modified=1; return_code=1; } return return_code; } void Backup(void) // Sauve la page courante comme premire page de backup et cre une nouvelle page // pur continuer dessiner. Utilis par exemple pour le fill { Backup_layers(1<Pages); // Create a fresh Page descriptor new_page=New_page(Main_backups->Pages->Nb_layers); if (!new_page) { Error(0); return; } // Fill it with a copy of the latest history Copy_S_page(new_page,Main_backups->Pages); new_page->Gradients=Dup_gradient(Main_backups->Pages); Create_new_page(new_page,Main_backups,layer_mask); Download_infos_page_main(new_page); Update_FX_feedback(Config.FX_Feedback); // Copy the actual pixels from the backup to the latest page for (i=0; iPages->Nb_layers;i++) { if ((1<Pages->Image[i], Main_backups->Pages->Next->Image[i], Main_image_width*Main_image_height); } // Light up the 'has unsaved changes' indicator Main_image_is_modified=1; /* Last_backed_up_layers = 1<Pages->Nb_layers); if (!new_page) { Error(0); return; } // Fill it with a copy of the latest history Copy_S_page(new_page,Spare_backups->Pages); new_page->Gradients=Dup_gradient(Spare_backups->Pages); Create_new_page(new_page,Spare_backups,layer_mask); // Copy the actual pixels from the backup to the latest page for (i=0; iPages->Nb_layers;i++) { if ((1<Pages->Image[i], Spare_backups->Pages->Next->Image[i], Spare_image_width*Spare_image_height); } // Light up the 'has unsaved changes' indicator Spare_image_is_modified=1; } void Check_layers_limits() { if (Main_current_layer > Main_backups->Pages->Nb_layers-1) { Main_current_layer = Main_backups->Pages->Nb_layers-1; Main_layers_visible |= 1<Pages); // On fait faire un undo la liste des backups de la page principale Backward_in_list_of_pages(Main_backups); Update_buffers(Main_backups->Pages->Width, Main_backups->Pages->Height); // On extrait ensuite les infos sur la nouvelle page courante Download_infos_page_main(Main_backups->Pages); // Note: le backup n'a pas obligatoirement les mmes dimensions ni la mme // palette que la page courante. Mais en temps normal, le backup // n'est pas utilis la suite d'un Undo. Donc a ne devrait pas // poser de problmes. Check_layers_limits(); Redraw_layered_image(); End_of_modification(); } void Redo(void) { if (Last_backed_up_layers) { Free_page_of_a_list(Main_backups); Last_backed_up_layers=0; } // On remet jour l'tat des infos de la page courante (pour pouvoir les // retrouver plus tard) Upload_infos_page_main(Main_backups->Pages); // On fait faire un redo la liste des backups de la page principale Advance_in_list_of_pages(Main_backups); Update_buffers(Main_backups->Pages->Width, Main_backups->Pages->Height); // On extrait ensuite les infos sur la nouvelle page courante Download_infos_page_main(Main_backups->Pages); // Note: le backup n'a pas obligatoirement les mmes dimensions ni la mme // palette que la page courante. Mais en temps normal, le backup // n'est pas utilis la suite d'un Redo. Donc a ne devrait pas // poser de problmes. Check_layers_limits(); Redraw_layered_image(); End_of_modification(); } void Free_current_page(void) { // On dtruit la page courante de la liste principale Free_page_of_a_list(Main_backups); // On extrait ensuite les infos sur la nouvelle page courante Download_infos_page_main(Main_backups->Pages); // Note: le backup n'a pas obligatoirement les mmes dimensions ni la mme // palette que la page courante. Mais en temps normal, le backup // n'est pas utilis la suite d'une destruction de page. Donc a ne // devrait pas poser de problmes. Update_buffers(Main_backups->Pages->Width, Main_backups->Pages->Height); Check_layers_limits(); Redraw_layered_image(); End_of_modification(); } void Exchange_main_and_spare(void) { T_List_of_pages * temp_list; // On commence par mettre jour dans les descripteurs les infos sur les // pages qu'on s'apprte changer, pour qu'on se retrouve pas avec de // vieilles valeurs qui datent de mathuzalem. Upload_infos_page_main(Main_backups->Pages); Upload_infos_page_spare(Spare_backups->Pages); // On inverse les listes de pages temp_list=Main_backups; Main_backups=Spare_backups; Spare_backups=temp_list; // On extrait ensuite les infos sur les nouvelles pages courante, brouillon // et backup. /* SECTION GROS CACA PROUT PROUT */ // Auparavant on ruse en mettant dj jour les dimensions de la // nouvelle page courante. Si on ne le fait pas, le "Download" va dtecter // un changement de dimensions et va btement sortir du mode loupe, alors // que lors d'un changement de page, on veut bien conserver l'tat du mode // loupe du brouillon. Main_image_width=Main_backups->Pages->Width; Main_image_height=Main_backups->Pages->Height; Download_infos_page_main(Main_backups->Pages); Download_infos_page_spare(Spare_backups->Pages); } void End_of_modification(void) { //Update_buffers(Main_image_width, Main_image_height); #ifndef NOLAYERS // Backup buffer can have "wrong" size if a Lua script // performs a resize. Update_buffers(Main_image_width, Main_image_height); // memcpy(Main_visible_image_backup.Image, Main_visible_image.Image, Main_image_width*Main_image_height); #else Update_screen_targets(); #endif Update_FX_feedback(Config.FX_Feedback); /* Last_backed_up_layers = 0; Backup(); */ // // Processing safety backups // Main_edits_since_safety_backup++; Rotate_safety_backups(); } /// Add a new layer to latest page of a list. Returns 0 on success. byte Add_layer(T_List_of_pages *list, byte layer) { T_Page * source_page; T_Page * new_page; byte * new_image; int i; source_page = list->Pages; if (list->Pages->Nb_layers == MAX_NB_LAYERS) return 1; // Keep the position reasonable if (layer > list->Pages->Nb_layers) layer = list->Pages->Nb_layers; // Allocate the pixel data new_image = New_layer(list->Pages->Height*list->Pages->Width); if (! new_image) { Error(0); return 1; } // Re-allocate the page itself, with room for one more pointer new_page = realloc(source_page, sizeof(T_Page)+(list->Pages->Nb_layers+1)*sizeof(byte *)); if (!new_page) { Error(0); return 1; } if (new_page != source_page) { // Need some housekeeping because the page moved in memory. // Update all pointers that pointed to it: new_page->Prev->Next = new_page; new_page->Next->Prev = new_page; list->Pages = new_page; } list->Pages->Nb_layers++; // Move around the pointers. This part is going to be tricky when we // have 'animations x layers' in this vector. for (i=list->Pages->Nb_layers-1; i>layer ; i--) { new_page->Image[i]=new_page->Image[i-1]; } new_page->Image[layer]=new_image; // Fill with transparency, initially memset(new_image, Main_backups->Pages->Transparent_color, list->Pages->Height*list->Pages->Width); // transparent color // Done. Note that the visible buffer is already ok since we // only inserted a transparent "slide" somewhere. // The depth buffer is all wrong though. // Update the flags of visible layers. { dword layers_before; dword layers_after; dword *visible_layers_flag; // Determine if we're modifying the spare or the main page. if (list == Main_backups) { visible_layers_flag = &Main_layers_visible; Main_current_layer = layer; } else { visible_layers_flag = &Spare_layers_visible; Spare_current_layer = layer; } // Fun with binary! layers_before = ((1<Pages; // Keep the position reasonable if (layer >= list->Pages->Nb_layers) layer = list->Pages->Nb_layers - 1; if (list->Pages->Nb_layers == 1) return 1; // For simplicity, we won't actually shrink the page in terms of allocation. // It would only save the size of a pointer, and anyway, as the user draws, // this page is going to fall off the end of the Undo-list // and so it will be cleared anyway. // Smart freeing of the pixel data Free_layer(list->Pages, layer); list->Pages->Nb_layers--; // Move around the pointers. This part is going to be tricky when we // have 'animations x layers' in this vector. for (i=layer; i < list->Pages->Nb_layers; i++) { list->Pages->Image[i]=list->Pages->Image[i+1]; } // Done. At this point the visible buffer and the depth buffer are // all wrong. // Update the flags of visible layers. { dword layers_before; dword layers_after; dword *visible_layers_flag; byte new_current_layer; // Determine if we're modifying the spare or the main page. if (list == Main_backups) { visible_layers_flag = &Main_layers_visible; if (Main_current_layer>=layer && Main_current_layer>0) Main_current_layer--; new_current_layer = Main_current_layer; } else { visible_layers_flag = &Spare_layers_visible; if (Spare_current_layer>=layer && Spare_current_layer>0) Spare_current_layer--; new_current_layer = Spare_current_layer; } // Fun with binary! layers_before = ((1<>1; *visible_layers_flag = layers_before | layers_after; // Ensure the current layer is part what is shown. *visible_layers_flag |= 1<Pages->Image[Main_current_layer]+i); if (color != Main_backups->Pages->Transparent_color) // transparent color *(Main_backups->Pages->Image[Main_current_layer-1]+i) = color; } return Delete_layer(Main_backups,Main_current_layer); } grafx2/src/palette.c0000644000076400010400000031250411534453426015037 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ #include #include #include #include "const.h" #include "struct.h" #include "global.h" #include "misc.h" #include "engine.h" #include "readline.h" #include "buttons.h" #include "pages.h" #include "help.h" #include "sdlscreen.h" #include "errors.h" #include "op_c.h" #include "windows.h" #include "input.h" #include "palette.h" #include "shade.h" byte Palette_view_is_RGB = 1; // Indique si on est en HSL ou en RGB // Coordinates of the color count (on histogram button) static const int COUNT_X = 258; static const int COUNT_Y = 49; // Nombre de graduations pour une composante RGB int RGB_scale = 256; // 24bit //int RGB_scale = 64; // VGA //int RGB_scale = 16; // Amiga //int RGB_scale = 4; // MSX2 //int RGB_scale = 3; // Amstrad CPC // Nombre de graduations pour une composante dans le mode actuel int Color_count=256; // Les composantes vont de 0 (Color_count-1) int Color_max=255; // Le demi-pas est une quantit que l'on ajoute une composante // avant de faire un arrondi par division. int Color_halfstep=0; void Set_palette_RGB_scale(int scale) { if (scale>= 2 && scale <= 256) RGB_scale = scale; } int Get_palette_RGB_scale(void) { return RGB_scale; } /// /// Round a 0-255 RGB component according to the RGB_scale. /// The result is also in the 0-255 range. byte Round_palette_component(byte comp) { return ((comp+128/RGB_scale)*(RGB_scale-1)/255*255+(RGB_scale&1?1:0))/(RGB_scale-1); } /// /// Turns a RGB component from 0-255 scale to 0-(RGB_scale-1). /// The passed value should come from Round_palette_component(), /// otherwise the rounding will be "down". int Reduce_component(int comp) { return (comp)*255/Color_max; } /// /// Turns a RGB component from 0-(RGB_scale-1) to 0-255. int Expand_component(int comp) { if (Color_max==255) return comp; return (comp+1)*Color_max/255; // The +1 cancel any rounding down, the above test prevents // the only case where it would be too much. } // Dfinir les units pour les graduations R G B ou H S V void Component_unit(int count) { Color_count = count; Color_max = count-1; Color_halfstep = 256/count/2; } void Set_HSL(T_Palette start_palette, T_Palette end_palette, byte color, short diff_h, short diff_s, short diff_l) { byte h, s, l; RGB_to_HSL(start_palette[color].R,start_palette[color].G,start_palette[color].B,&h,&s,&l); // La teinte (Hue) est cyclique h=(diff_h+256+h); // Pour les autres (Saturation, Lightness), au lieu d'additionner, // on va faire un ratio, cela utilise mieux la plage de valeurs 0-255 if (diff_s<0) s=(255+diff_s)*s/255; else if (diff_s>0) s=255-(255-diff_s)*(255-s)/255; if (diff_l<0) l=(255+diff_l)*l/255; else if (diff_l>0) l=255-(255-diff_l)*(255-l)/255; HSL_to_RGB(h,s,l,&end_palette[color].R,&end_palette[color].G,&end_palette[color].B); } void Set_red(byte color, short new_color, T_Palette palette) { if (new_color< 0) new_color= 0; if (new_color>255) new_color=255; // Arrondi new_color=Round_palette_component(new_color); palette[color].R=new_color; } void Set_green(byte color, short new_color, T_Palette palette) { if (new_color< 0) new_color= 0; if (new_color>255) new_color=255; // Arrondi new_color=Round_palette_component(new_color); palette[color].G=new_color; } void Set_blue(byte color, short new_color, T_Palette palette) { if (new_color< 0) new_color= 0; if (new_color>255) new_color=255; // Arrondi new_color=Round_palette_component(new_color); palette[color].B=new_color; } void Format_component(byte value, char *str) // Formate une chaine de 4 caractres+\0 : "nnn " { Num2str(value,str,3); str[3]=' '; str[4]='\0'; } void Spread_colors(short start,short end,T_Palette palette) // Modifie la palette pour obtenir un dgrad de couleur entre les deux bornes // passes en paramtre { short start_red; short start_green; short start_blue; short end_red; short end_green; short end_blue; short index; // On vrifie qu'il y ait assez de couleurs entre le dbut et la fin pour // pouvoir faire un dgrad: if ( (start!=end) && (start+1!=end) ) { start_red=palette[start].R; start_green =palette[start].G; start_blue =palette[start].B; end_red =palette[end ].R; end_green =palette[end ].G; end_blue =palette[end ].B; for (index=start+1;index=Window_pos_Y) && (y_pos=Window_pos_X) && (x_posPages->Nb_layers; layer++) Remap_general_lowlevel(conversion_table,Main_backups->Pages->Image[layer],Main_backups->Pages->Image[layer],Main_image_width,Main_image_height,Main_image_width); // Remap transparent color Main_backups->Pages->Transparent_color = conversion_table[Main_backups->Pages->Transparent_color]; // On calcule les limites l'cran de l'image if (Main_image_height>=Menu_Y_before_window) end_y=Menu_Y_before_window; else end_y=Main_image_height; if (!Main_magnifier_mode) { if (Main_image_width>=Screen_width) end_x=Screen_width; else end_x=Main_image_width; } else { if (Main_image_width>=Main_separator_position) end_x=Main_separator_position; else end_x=Main_image_width; if ((Main_X_zoom+(Main_image_width*Main_magnifier_factor))>=Screen_width) end_x_mag=Screen_width; else end_x_mag=(Main_X_zoom+(Main_image_width*Main_magnifier_factor)); if (Main_image_height*Main_magnifier_factor>=Menu_Y_before_window) end_y_mag=Menu_Y_before_window; else end_y_mag=Main_image_height*Main_magnifier_factor; } // On doit maintenant faire la traduction l'cran Remap_zone_highlevel(0,0,end_x,end_y,conversion_table); if (Main_magnifier_mode) { Remap_zone_highlevel(Main_separator_position,0,end_x_mag,end_y_mag,conversion_table); // Il peut encore rester le bas de la barre de split remapper si la // partie zoome ne descend pas jusqu'en bas... Remap_zone_highlevel(Main_separator_position,end_y_mag, (Main_separator_position+(SEPARATOR_WIDTH*Menu_factor_X)), Menu_Y_before_window,conversion_table); } // Remappe tous les fonds de fenetre (qui doivent contenir un bout d'cran) Remap_window_backgrounds(conversion_table, 0, Menu_Y_before_window); } void Swap(int with_remap,short block_1_start,short block_2_start,short block_size,T_Palette palette, dword * color_usage) { short pos_1; short pos_2; short end_1; short end_2; byte conversion_table[256]; T_Components temp_palette[256]; dword temp_usage[256]; // On fait une copie de la palette memcpy(temp_palette, palette, sizeof(T_Palette)); // On fait une copie de la table d'used des couleurs memcpy(temp_usage, color_usage, sizeof(dword) * 256); // On commence initialiser la table de conversion un tat o elle ne // fera aucune conversion. for (pos_1=0;pos_1<=255;pos_1++) conversion_table[pos_1]=pos_1; // On calcul les dernires couleurs de chaque bloc. end_1=block_1_start+block_size-1; end_2=block_2_start+block_size-1; if ((block_2_start>=block_1_start) && (block_2_start<=end_1)) { // Le bloc destination commence dans le bloc source. for (pos_1=block_1_start,pos_2=end_1+1;pos_1<=end_2;pos_1++) { // Il faut transformer la couleur pos_1 en pos_2: conversion_table[pos_2]=pos_1; color_usage[pos_1]=temp_usage[pos_2]; palette[pos_1].R=temp_palette[pos_2].R; palette[pos_1].G=temp_palette[pos_2].G; palette[pos_1].B=temp_palette[pos_2].B; // On gre la mise jour de pos_2 if (pos_2==end_2) pos_2=block_1_start; else pos_2++; } } else if ((block_2_start=block_1_start)) { // Le bloc destination dborde dans le bloc source. for (pos_1=block_2_start,pos_2=block_1_start;pos_1<=end_1;pos_1++) { // Il faut transformer la couleur pos_1 en pos_2: conversion_table[pos_2]=pos_1; color_usage[pos_1]=temp_usage[pos_2]; palette[pos_1].R=temp_palette[pos_2].R; palette[pos_1].G=temp_palette[pos_2].G; palette[pos_1].B=temp_palette[pos_2].B; // On gre la mise jour de pos_2 if (pos_2==end_1) pos_2=block_2_start; else pos_2++; } } else { // Le bloc source et le bloc destination sont distincts. for (pos_1=block_1_start,pos_2=block_2_start;pos_1<=end_1;pos_1++,pos_2++) { // Il va falloir permutter la couleur pos_1 avec la couleur pos_2 conversion_table[pos_1]=pos_2; conversion_table[pos_2]=pos_1; // On intervertit le nombre d'used des couleurs pour garder une // cohrence lors d'un ventuel "Zap unused". SWAP_DWORDS(color_usage[pos_1], color_usage[pos_2]) // On fait un changement de teinte: SWAP_BYTES(palette[pos_1].R, palette[pos_2].R) SWAP_BYTES(palette[pos_1].G, palette[pos_2].G) SWAP_BYTES(palette[pos_1].B, palette[pos_2].B) } } if (with_remap) { Remap_image_highlevel(conversion_table); } else { // Restore color usage. Shouldn't have reordered it in the first place. memcpy(color_usage, temp_usage, sizeof(dword) * 256); } } void Set_nice_menu_colors(dword * color_usage,int not_picture) { short index,index2; byte color; byte replace_table[256]; T_Components rgb[4]; short new_colors[4]={255,254,253,252}; // On initialise la table de remplacement for (index=0; index<256; index++) replace_table[index]=index; // On recherche les 4 couleurs les moins utilises dans l'image pour pouvoir // les remplacer par les nouvelles couleurs. for (index2=0; index2<4; index2++) for (index=255; index>=0; index--) { if ((index!=new_colors[0]) && (index!=new_colors[1]) && (index!=new_colors[2]) && (index!=new_colors[3]) && (color_usage[index]new_colors[index+1]) { index2 =new_colors[index]; new_colors[index] =new_colors[index+1]; new_colors[index+1]=index2; color=1; } } } while (color); // On sauvegarde dans rgb les teintes qu'on va remplacer et on met les // couleurs du menu par dfaut for (index=0; index<4; index++) { const T_Components * target_rgb; target_rgb=Favorite_GUI_color(index); color=new_colors[index]; rgb[index].R=Main_palette[color].R; rgb[index].G=Main_palette[color].G; rgb[index].B=Main_palette[color].B; Main_palette[color].R=Round_palette_component(target_rgb->R); Main_palette[color].G=Round_palette_component(target_rgb->G); Main_palette[color].B=Round_palette_component(target_rgb->B); } // Maintenant qu'on a plac notre nouvelle palette, on va chercher quelles // sont les couleurs qui peuvent remplacer les anciennes Hide_cursor(); for (index=0; index<4; index++) replace_table[new_colors[index]]=Best_color_nonexcluded (rgb[index].R,rgb[index].G,rgb[index].B); if (not_picture) { // Remap caused by preview. Only remap screen Remap_zone_highlevel(0,0,Screen_width,Screen_height,replace_table); } else { // On fait un changement des couleurs visibles l'cran et dans l'image Remap_image_highlevel(replace_table); } Display_cursor(); } void Reduce_palette(short * used_colors,int nb_colors_asked,T_Palette palette,dword * color_usage) { char str[5]; // buffer d'affichage du compteur byte conversion_table[256]; // Table de conversion int color_1; // |_ Variables de balayages int color_2; // | de la palette int best_color_1=0; int best_color_2=0; int difference; int best_difference; dword used; dword best_used; // On commence par initialiser la table de conversion dans un tat o // aucune conversion ne sera effectue. for (color_1=0; color_1<=255; color_1++) conversion_table[color_1]=color_1; // Si on ne connait pas encore le nombre de couleurs utilises, on le // calcule! (!!! La fonction appele Efface puis Affiche le curseur !!!) if ((*used_colors)<0) Update_color_count(used_colors,color_usage); Hide_cursor(); // On tasse la palette vers le dbut parce qu'elle doit ressembler // du Gruyre (et comme Papouille il aime pas le fromage...) // Pour cela, on va scruter la couleur color_1 et se servir de l'indice // color_2 comme position de destination. for (color_1=color_2=0;color_1<=255;color_1++) { if (color_usage[color_1]) { // On commence par s'occuper des teintes de la palette palette[color_2].R=palette[color_1].R; palette[color_2].G=palette[color_1].G; palette[color_2].B=palette[color_1].B; // Ensuite, on met jour le tableau d'occupation des couleurs. color_usage[color_2]=color_usage[color_1]; // On va maintenant s'occuper de la table de conversion: conversion_table[color_1]=color_2; // Maintenant, la place dsigne par color_2 est occupe, alors on // doit passer un indice de destination suivant. color_2++; } } // On met toutes les couleurs inutilises en noir for (;color_2<256;color_2++) { palette[color_2].R=0; palette[color_2].G=0; palette[color_2].B=0; color_usage[color_2]=0; } // Maintenant qu'on a une palette clean, on va boucler en rduisant // le nombre de couleurs jusqu' ce qu'on atteigne le nombre dsir. // (The stop condition is further down) while (1) { // Il s'agit de trouver les 2 couleurs qui se ressemblent le plus // parmis celles qui sont utilises (bien sr) et de les remplacer par // une seule couleur qui est la moyenne pondre de ces 2 couleurs // en fonction de leur utilisation dans l'image. best_difference =0x7FFF; best_used=0x7FFFFFFF; for (color_1=0;color_1<(*used_colors);color_1++) for (color_2=color_1+1;color_2<(*used_colors);color_2++) if (color_1!=color_2) { difference =abs((short)palette[color_1].R-palette[color_2].R)+ abs((short)palette[color_1].G-palette[color_2].G)+ abs((short)palette[color_1].B-palette[color_2].B); if (difference<=best_difference) { used=color_usage[color_1]+color_usage[color_2]; if ((differencebest_color_2) { // La color_1 va scroller en arrire. // Donc on transfre son utilisation dans l'utilisation de la // couleur qui la prcde. color_usage[color_1-1]=color_usage[color_1]; // Et on transfre ses teintes dans les teintes de la couleur qui // la prcde. palette[color_1-1].R=palette[color_1].R; palette[color_1-1].G=palette[color_1].G; palette[color_1-1].B=palette[color_1].B; } // Une fois la palette et la table d'utilisation gres, on peut // s'occuper de notre table de conversion. if (conversion_table[color_1]>best_color_2) // La color_1 avait l'intention de se faire remplacer par une // couleur que l'on va (ou que l'on a dj) bouger en arrire. conversion_table[color_1]--; } // On vient d'jecter une couleur, donc on peut mettre jour le nombre // de couleurs utilises. (*used_colors)--; // A la fin, on doit passer (dans la palette) les teintes du dernier // lment de notre ensemble en noir. palette[*used_colors].R=0; palette[*used_colors].G=0; palette[*used_colors].B=0; // Au passage, on va s'assurer que l'on a pas oubli de la mettre une // utilisation nulle. color_usage[*used_colors]=0; // Aprs avoir ject une couleur, on le fait savoir l'utilisateur par // l'intermdiaire du compteur de nombre utilises. Num2str(*used_colors,str,3); Print_in_window(COUNT_X,COUNT_Y,str,MC_Black,MC_Light); } // Maintenant, tous ces calculs doivent tres pris en compte dans la // palette, l'image et l'cran. Remap_image_highlevel(conversion_table); // Et voila pour l'image et l'cran Display_cursor(); } // Position of the numeric values of the R G B sliders static const int NUMERIC_R_X = 176; static const int NUMERIC_G_X = 203; static const int NUMERIC_B_X = 230; static const int NUMERIC_Y = 171; // Position of the whole button static const int NUMERIC_BOX_X = 175; static const int NUMERIC_BOX_Y = 169; static const int NUMERIC_BOX_W = 81; static const int NUMERIC_BOX_H = 12; void Set_palette_slider(T_Scroller_button * slider, word nb_elements, word position, char * value, short x_pos) { slider->Nb_elements=nb_elements; slider->Position=position; Compute_slider_cursor_length(slider); Window_draw_slider(slider); Print_counter(x_pos,NUMERIC_Y,value,MC_Black,MC_Light); } void Display_sliders(T_Scroller_button * red_slider, T_Scroller_button * green_slider, T_Scroller_button * blue_slider, byte block_is_selected, T_Components * palette) { char str[5]; if (block_is_selected) { Set_palette_slider(red_slider,Color_max*2+1,Color_max," 0",NUMERIC_R_X); Set_palette_slider(green_slider,Color_max*2+1,Color_max," 0",NUMERIC_G_X); Set_palette_slider(blue_slider,Color_max*2+1,Color_max," 0",NUMERIC_B_X); } else { byte j1, j2, j3; j1= palette[Fore_color].R; j2= palette[Fore_color].G; j3= palette[Fore_color].B; if (!Palette_view_is_RGB) { RGB_to_HSL(j1,j2,j3,&j1,&j2,&j3); } Format_component(j1*Color_count/256,str); Set_palette_slider(red_slider,Color_count,Color_max-Expand_component(j1),str,NUMERIC_R_X); Format_component(j2*Color_count/256,str); Set_palette_slider(green_slider,Color_count,Color_max-Expand_component(j2),str,NUMERIC_G_X); Format_component(j3*Color_count/256,str); Set_palette_slider(blue_slider,Color_count,Color_max-Expand_component(j3),str,NUMERIC_B_X); } } void Draw_all_palette_sliders(T_Scroller_button * red_slider, T_Scroller_button * green_slider, T_Scroller_button * blue_slider, T_Palette palette,byte start,byte end) { char str[5]; Hide_cursor(); // Raffichage des jauges: if (start!=end) { // Dans le cas d'un bloc, tout 0. red_slider->Position =Color_max; Window_draw_slider(red_slider); Print_counter(NUMERIC_R_X,NUMERIC_Y," 0",MC_Black,MC_Light); green_slider->Position =Color_max; Window_draw_slider(green_slider); Print_counter(NUMERIC_G_X,NUMERIC_Y," 0",MC_Black,MC_Light); blue_slider->Position =Color_max; Window_draw_slider(blue_slider); Print_counter(NUMERIC_B_X,NUMERIC_Y," 0",MC_Black,MC_Light); } else { // Dans le cas d'une seule couleur, composantes. byte j1, j2, j3; j1= palette[start].R; j2= palette[start].G; j3= palette[start].B; if (!Palette_view_is_RGB) { RGB_to_HSL(j1,j2,j3,&j1,&j2,&j3); } DEBUG("j1",j1); Format_component(j1*Color_count/256,str); red_slider->Position=Color_max-Expand_component(j1); Window_draw_slider(red_slider); Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); Format_component(j2*Color_count/256,str); green_slider->Position=Color_max-Expand_component(j2); Window_draw_slider(green_slider); Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); Format_component(j3*Color_count/256,str); blue_slider->Position=Color_max-Expand_component(j3); Window_draw_slider(blue_slider); Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } Display_cursor(); } int Window_Histogram(unsigned char block_start, unsigned char block_end, dword* color_usage) { int i, j; unsigned int max_count = 0; int old_height=0; int hovered_color=-1; int new_hovered_color; int bar_width; T_Special_button *histo; int clicked_button; /* Draws an histogram of the selected range in a separate window */ if (block_start == block_end) { // only one color selected: auto-detect the range for (block_start=0; block_start!=255; block_start++) if (color_usage[block_start]) break; for (block_end=255; block_end!=0; block_end--) if (color_usage[block_end]) break; } // Normalize the histogram towards the most used color // Step 1 : find the most used color in the range for(i=block_start; i<= block_end; i++) { if(color_usage[i] > max_count) max_count = color_usage[i]; } if (max_count == 0) { Warning_message("All these colors are unused!"); Hide_cursor(); return -1; } Open_window(263, 150, "Histogram"); Window_set_normal_button(120, 130, 42, 14, "Close",-1,1,SDLK_RETURN); Print_in_window(6, 17, "Color:", MC_Dark, MC_Light); Print_in_window(110+12*8, 17, "Pixels", MC_Dark, MC_Light); // Step 2 : draw bars bar_width=256/(block_end-block_start+1); j = 0; for(i=block_start; i<= block_end; i++) { int height = 100*color_usage[i]/max_count; // Don't draw anything if the color is unused if (color_usage[i]!=0) { // Draw at least one pixel if the color is used if (height==0) height=1; Window_rectangle( 3+j*bar_width, 127-height, bar_width, height, i); //if (i == MC_Light) { Window_rectangle( 3+j*bar_width, 126-height, bar_width, 1,MC_Black); //} } // vertical outline if (height>old_height) Window_rectangle( 2+j*bar_width, 126-height, 1, height-old_height+1,MC_Black); else if (old_height>height) Window_rectangle( 3+j*bar_width, 126-old_height, 1, old_height-height+1,MC_Black); old_height=height; j++; } // Last vertical outline if (old_height!=0) Window_rectangle( 3+j*(256/(block_end-block_start+1)), 126-old_height, 1, old_height+1,MC_Black); histo = Window_set_special_button(3, 27, j*bar_width, 100); // 2 Update_window_area(0,0,263,150); Display_cursor(); do { // Find hovered area if (Window_click_in_rectangle(histo->Pos_X,histo->Pos_Y,histo->Pos_X+histo->Width-1,histo->Pos_Y+histo->Height-1)) { short x_pos; x_pos=((short)Mouse_X-Window_pos_X)/Menu_factor_X; new_hovered_color=block_start+(x_pos-histo->Pos_X)/bar_width; } else new_hovered_color=-1; // When changing hovered color, update the info area if (new_hovered_color!=hovered_color) { char str[12]; hovered_color=new_hovered_color; Hide_cursor(); if (hovered_color==-1) { Window_rectangle(6+6*8,17,3*8,7,MC_Light); Update_window_area(6+6*8,17,3*8,7); Window_rectangle(86,17,2*8,8,MC_Light); Update_window_area(86,17,2*8,8); Window_rectangle(110,17,11*8,7,MC_Light); Update_window_area(110,17,11*8,7); } else { Num2str(hovered_color,str ,3); Print_in_window(6+6*8,17,str,MC_Black,MC_Light); Window_rectangle(86,17,2*8,8,hovered_color); Update_window_area(86,17,2*8,8); Num2str(color_usage[hovered_color],str ,11); Print_in_window(110,17,str,MC_Black,MC_Light); } Display_cursor(); } clicked_button=Window_clicked_button(); if (Key == KEY_ESC) clicked_button=1; } while( clicked_button < 1); Close_window(); if (clicked_button==2) { // This is a counter-hack. Close_window() sets Mouse_K to zero // on exit, I don't know why (It will become 1 again if you move // the mouse slightly) // Here I force it back to 1, so that the Wait_end_of_click() // will really wait for a release of mouse button. Mouse_K=1; return hovered_color; } return -1; } void Print_RGB_or_HSL(byte mode) { Print_in_window(184,68,mode?"H":"R",MC_Dark,MC_Light); Print_in_window(211,68,mode?"S":"G",MC_Dark,MC_Light); Print_in_window(238,68,mode?"L":"B",MC_Dark,MC_Light); } void Tag_used_colors(byte color, dword color_usage[]) { word index; for (index=0;index<=255;index++) { short x_pos=Window_palette_button_list->Pos_X+6+((index>>4)*10); short y_pos=Window_palette_button_list->Pos_Y+3+((index&15)* 5); byte col; col=(color&&color_usage[index])?MC_White:MC_Light; Window_rectangle(x_pos+5,y_pos+0,1,5,col); } Update_window_area(Window_palette_button_list->Pos_X+3,Window_palette_button_list->Pos_Y+3,12*16,5*16); } void Button_Palette(void) { static const int BUTTON_PLUS_X = 268; static const int BUTTON_PLUS_Y = 74; static const int BUTTON_MINUS_X = 268; static const int BUTTON_MINUS_Y = 165; // Coordinates of the block that displays Backcolor static const int BGCOLOR_DISPLAY_X = 262; static const int BGCOLOR_DISPLAY_Y = 89; static const int BGCOLOR_DISPLAY_W = 24; static const int BGCOLOR_DISPLAY_H = 72; // Coordinates of the block that displays Forecolor static const int FGCOLOR_DISPLAY_X = 266; static const int FGCOLOR_DISPLAY_Y = 93; static const int FGCOLOR_DISPLAY_W = 16; static const int FGCOLOR_DISPLAY_H = 64; // Coordinates of the Color# static const int COLOR_X = 111; static const int COLOR_Y = 69; static short reduce_colors_number = 256; short temp_color; // Variable pouvant reservir pour diffrents calculs intermdiaires dword temp; byte color,click; // Variables pouvant reservir pour diffrents calculs intermdiaires short clicked_button; word old_mouse_x; word old_mouse_y; byte old_mouse_k; byte block_start; byte block_end; byte first_color; byte last_color; char str[10]; word i; T_Normal_button * button_used; T_Scroller_button * red_slider; T_Scroller_button * green_slider; T_Scroller_button * blue_slider; T_Dropdown_button * reduce_dropdown; T_Dropdown_button * sort_dropdown; byte image_is_backed_up = 0; byte need_to_remap = 0; dword color_usage[256]; short used_colors = -1; // -1 <=> Inconnu byte conversion_table[256]; //T_Components * backup_palette; //T_Components * temp_palette; //T_Components * working_palette; static byte show_used_colors=0; backup_palette =(T_Components *)malloc(sizeof(T_Palette)); temp_palette=(T_Components *)malloc(sizeof(T_Palette)); working_palette=(T_Components *)malloc(sizeof(T_Palette)); Component_unit(RGB_scale); Open_window(299, 188,"Palette"); memcpy(working_palette, Main_palette, sizeof(T_Palette)); Palette_edit_step(); Window_set_palette_button(5, 79); // 1 Window_display_frame (172, 63, 122, 121); // Graduation des jauges de couleur Window_rectangle(180,106,17,1,MC_Dark); Window_rectangle(207,106,17,1,MC_Dark); Window_rectangle(234,106,17,1,MC_Dark); Window_rectangle(180,122,17,1,MC_Dark); Window_rectangle(207,122,17,1,MC_Dark); Window_rectangle(234,122,17,1,MC_Dark); Window_rectangle(180,138,17,1,MC_Dark); Window_rectangle(207,138,17,1,MC_Dark); Window_rectangle(234,138,17,1,MC_Dark); // Jauges de couleur red_slider = Window_set_scroller_button(183, 79, 88,Color_count,1,Color_max-Reduce_component(working_palette[Fore_color].R));// 2 green_slider = Window_set_scroller_button(210, 79, 88,Color_count,1,Color_max-Reduce_component(working_palette[Fore_color].G));// 3 blue_slider = Window_set_scroller_button(237, 79, 88,Color_count,1,Color_max-Reduce_component(working_palette[Fore_color].B));// 4 if(Palette_view_is_RGB==1) { Print_RGB_or_HSL(0); Component_unit(RGB_scale); } else { Print_RGB_or_HSL(1); Component_unit(256); } first_color=last_color=block_start=block_end=Fore_color; Tag_color_range(block_start,block_end); // Affichage dans le block de visu de la couleur en cours Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H,Back_color); Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); // Affichage des valeurs de la couleur courante (pour 1 couleur) Display_sliders(red_slider,green_slider,blue_slider,(block_start!=block_end),working_palette); Print_in_window(7, 69, "Color number:", MC_Dark, MC_Light); Num2str(Fore_color, str, 3); Print_in_window(COLOR_X, COLOR_Y, str, MC_Black, MC_Light); Window_set_normal_button( 7,16,55,14,"Merge" ,0,1,SDLK_m); // 5 Window_set_normal_button( 63,16,36,14,"Gray" ,1,1,SDLK_g); // 6 Window_set_normal_button( 7,46,55,14,"Swap" ,0,1,KEY_NONE); // 7 Window_set_normal_button( 63,46,72,14,"X-Swap" ,1,1,SDLK_x); // 8 Window_set_normal_button(136,31,54,14,"Copy" ,1,1,SDLK_c); // 9 Window_set_normal_button(136,46,54,14,"Spread" ,4,1,SDLK_e); // 10 reduce_dropdown = Window_set_dropdown_button(209, 46, 83, 14, 84, "Reduce", 0, 0, 1, RIGHT_SIDE|LEFT_SIDE, 0); // 11 Window_dropdown_add_item(reduce_dropdown, 256, "to uniques"); Window_dropdown_add_item(reduce_dropdown, 128, "to 128"); Window_dropdown_add_item(reduce_dropdown, 64, "to 64"); Window_dropdown_add_item(reduce_dropdown, 32, "to 32"); Window_dropdown_add_item(reduce_dropdown, 16, "to 16"); Window_dropdown_add_item(reduce_dropdown, 8, "to 8"); Window_dropdown_add_item(reduce_dropdown, 4, "to 4"); Window_dropdown_add_item(reduce_dropdown, 2, "to 2"); Window_dropdown_add_item(reduce_dropdown, 0, "Other"); Window_set_normal_button( 6,168,35,14,"Undo" ,1,1,SDLK_u); // 12 Window_set_normal_button( 62,168,51,14,"Cancel",0,1,KEY_ESC); // 13 Window_set_normal_button(117,168,51,14,"OK" ,0,1,SDLK_RETURN); // 14 Window_set_normal_button(209,16,37,14,"Used",0,1,SDLK_d); // 15 Window_set_normal_button(209,31,83,14,"Zap unused",0,1,SDLK_DELETE);//16 Window_set_repeatable_button(BUTTON_PLUS_X, BUTTON_PLUS_Y,12,11,"+",0,1,SDLK_KP_PLUS); // 17 Window_set_repeatable_button(BUTTON_MINUS_X,BUTTON_MINUS_Y,12,11,"-",0,1,SDLK_KP_MINUS); // 18 Window_set_normal_button(100,16,35,14,"Neg" ,1,1,SDLK_n); // 19 Window_set_normal_button(7,31,55,14,"Invert" ,1,1,SDLK_i); // 20 Window_set_normal_button(63,31,72,14,"X-Invert" ,5,1,SDLK_v); // 21 // Button without outline Window_set_normal_button(175,66,81,11,"" ,0,1,SDLK_h); // 22 Window_display_frame_mono(175-1,66-1,81+2,11+2,MC_Light); sort_dropdown = Window_set_dropdown_button(136, 16, 54, 14, 80, " Sort", 0, 1, 1, RIGHT_SIDE|LEFT_SIDE, 0); // 23 Window_dropdown_add_item(sort_dropdown, 0, "Hue/Light"); Window_dropdown_add_item(sort_dropdown, 1, "Lightness"); Window_set_normal_button(NUMERIC_BOX_X,NUMERIC_BOX_Y,NUMERIC_BOX_W,NUMERIC_BOX_H,"" ,0,1,KEY_NONE); // 24 // Button without outline Window_display_frame_mono(NUMERIC_BOX_X-1,NUMERIC_BOX_Y-1,NUMERIC_BOX_W+2,NUMERIC_BOX_H+2,MC_Light); button_used = Window_set_normal_button(247,16,45,14,"Histo",0,1,KEY_NONE);// 25 // Dessin des petits effets spciaux pour les boutons [+] et [-] Draw_thingumajig(265, 74,MC_White,-1); Draw_thingumajig(282, 74,MC_White,+1); Draw_thingumajig(265,165,MC_Dark,-1); Draw_thingumajig(282,165,MC_Dark,+1); Display_cursor(); Update_color_count(&used_colors,color_usage); if (show_used_colors) Tag_used_colors(1, color_usage); Update_window_area(0,0,299,188); do { old_mouse_x=Mouse_X; old_mouse_y=Mouse_Y; old_mouse_k=Mouse_K; clicked_button=Window_clicked_button(); switch (clicked_button) { case 0 : // Nulle part break; case -1 : // Hors de la fentre case 1 : // palette if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) ) { Hide_cursor(); temp_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); if (Mouse_K==RIGHT_SIDE) { // Contextual menu T_Dropdown_button dropdown; T_Dropdown_choice *item; dropdown.Pos_X =0; dropdown.Pos_Y =0; dropdown.Height =0; dropdown.Dropdown_width=48; dropdown.First_item =NULL; dropdown.Bottom_up =1; Window_dropdown_add_item(&dropdown, 1, "Copy"); Window_dropdown_add_item(&dropdown, 2, "Paste"); item=Dropdown_activate(&dropdown,Mouse_X,Mouse_Y); if (item && item->Number == 1) { // Copy Set_clipboard_colors(block_end+1-block_start,working_palette + block_start); Display_cursor(); } else if (item && item->Number == 2) { // Paste int nb_colors; // Backup Palette_edit_step(); nb_colors = Get_clipboard_colors(working_palette, block_start); if (nb_colors>0) { memcpy(temp_palette,working_palette,sizeof(T_Palette)); Set_palette(working_palette); need_to_remap=1; Display_cursor(); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); } else { Display_cursor(); } } else if (Back_color!=temp_color) { // Just select back color Back_color=temp_color; // 4 blocks de back_color entourant la fore_color Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); Display_cursor(); } else { Display_cursor(); } Window_dropdown_clear_items(&dropdown); } else { if (!old_mouse_k) { // On vient de clicker sur une couleur (et une seule) if ( (Fore_color!=temp_color) || (block_start!=block_end) ) { // La couleur en question est nouvelle ou elle annule un // ancien bloc. Il faut donc slectionner cette couleur comme // unique couleur choisie. Fore_color=first_color=last_color=block_start=block_end=temp_color; Tag_color_range(block_start,block_end); // Affichage du n de la couleur slectionne Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); Num2str(Fore_color,str,3); Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); Update_window_area(COLOR_X,COLOR_Y,56,7); // Affichage des jauges Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light); Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Palette_edit_select_range(); } } else { // On maintient le click, on va donc tester si le curseur bouge if (temp_color!=last_color) { // On commence par ordonner la 1re et dernire couleur du bloc if (first_colortemp_color) { block_start=temp_color; block_end=first_color; // Affichage du n de la couleur slectionne Num2str(block_start,str ,3); Num2str(block_end ,str+4,3); str[3]=26; // Flche vers la droite Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage des jauges Display_sliders(red_slider,green_slider,blue_slider,1,NULL); // Affichage dans le block de visu du bloc (dgrad) en cours Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); } else { block_start=block_end=first_color; Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light); // Affichage du n de la couleur slectionne Window_rectangle(COLOR_X+24,COLOR_Y,32,7,MC_Light); Update_window_area(COLOR_X+24,COLOR_Y,32,7); Num2str(Fore_color,str,3); Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage des jauges Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); } // On tagge le bloc (ou la couleur) Tag_color_range(block_start,block_end); } last_color=temp_color; } Display_cursor(); } } break; case 2 : // Jauge rouge Hide_cursor(); Palette_edit_alter_channel(); if (block_start==block_end) { if(Palette_view_is_RGB) { Set_red(Fore_color,Reduce_component(Color_max-red_slider->Position),working_palette); Format_component((working_palette[Fore_color].R)*Color_count/256,str); } else { HSL_to_RGB( 255-red_slider->Position, 255-green_slider->Position, 255-blue_slider->Position, &working_palette[Fore_color].R, &working_palette[Fore_color].G, &working_palette[Fore_color].B); Format_component((int)255-red_slider->Position,str); } Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } else { if(Palette_view_is_RGB) { for (i=block_start; i<=block_end; i++) Set_red(i,temp_palette[i].R+Reduce_component(Color_max-red_slider->Position),working_palette); } else { byte greys=0; byte non_greys=0; // Check if the range contains both greys and non-greys for (i=block_start; i<=block_end; i++) if (temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B) non_greys=1; else greys=1; for (i=block_start; i<=block_end; i++) { byte is_grey = temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B; Set_HSL( temp_palette, working_palette, i, is_grey && greys && non_greys ? 0 : Color_max-red_slider->Position, is_grey && greys && non_greys ? 0 : Color_max-green_slider->Position, Color_max-blue_slider->Position ); } } if (red_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-red_slider->Position),str,4); str[0]='-'; } else if (red_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; Display_cursor(); Set_palette(working_palette); break; case 3 : // Jauge verte Hide_cursor(); Palette_edit_alter_channel(); if (block_start==block_end) { if(Palette_view_is_RGB) { Set_green (Fore_color,Reduce_component(Color_max-green_slider->Position),working_palette); Format_component(working_palette[Fore_color].G*Color_count/256,str); } else { HSL_to_RGB( 255-red_slider->Position, 255-green_slider->Position, 255-blue_slider->Position, &working_palette[Fore_color].R, &working_palette[Fore_color].G, &working_palette[Fore_color].B); Format_component((int)255-green_slider->Position,str); } Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } else { if(Palette_view_is_RGB) { for (i=block_start; i<=block_end; i++) Set_green (i,temp_palette[i].G+Reduce_component(Color_max-green_slider->Position),working_palette); } else { byte greys=0; byte non_greys=0; // Check if the range contains both greys and non-greys for (i=block_start; i<=block_end; i++) if (temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B) non_greys=1; else greys=1; for (i=block_start; i<=block_end; i++) { byte is_grey = temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B; Set_HSL( temp_palette, working_palette, i, is_grey && greys && non_greys ? 0 : Color_max-red_slider->Position, is_grey && greys && non_greys ? 0 : Color_max-green_slider->Position, Color_max-blue_slider->Position ); } } if (green_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-green_slider->Position),str,4); str[0]='-'; } else if (green_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; Display_cursor(); Set_palette(working_palette); break; case 4 : // Jauge bleue Hide_cursor(); Palette_edit_alter_channel(); if (block_start==block_end) { if(Palette_view_is_RGB) { Set_blue (Fore_color,Reduce_component(Color_max-blue_slider->Position),working_palette); Format_component(working_palette[Fore_color].B*Color_count/256,str); } else { HSL_to_RGB( 255-red_slider->Position, 255-green_slider->Position, 255-blue_slider->Position, &working_palette[Fore_color].R, &working_palette[Fore_color].G, &working_palette[Fore_color].B); Format_component((int)255-blue_slider->Position,str); } Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } else { if(Palette_view_is_RGB) { for (i=block_start; i<=block_end; i++) Set_blue(i,temp_palette[i].B+Reduce_component(Color_max-blue_slider->Position),working_palette); } else { byte greys=0; byte non_greys=0; // Check if the range contains both greys and non-greys for (i=block_start; i<=block_end; i++) if (temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B) non_greys=1; else greys=1; for (i=block_start; i<=block_end; i++) { byte is_grey = temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B; Set_HSL( temp_palette, working_palette, i, is_grey && greys && non_greys ? 0 : Color_max-red_slider->Position, is_grey && greys && non_greys ? 0 : Color_max-green_slider->Position, Color_max-blue_slider->Position ); } } if (blue_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-blue_slider->Position),str,4); str[0]='-'; } else if (blue_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; Display_cursor(); Set_palette(working_palette); break; case 5 : // Merge if (block_start!=block_end) { dword sum_r=0, sum_g=0, sum_b=0, used=0; Palette_edit_step(); // Compute weighted average for (i=block_start; i<=block_end; i++) { used+=color_usage[i]; sum_r+=working_palette[i].R * color_usage[i]; sum_g+=working_palette[i].G * color_usage[i]; sum_b+=working_palette[i].B * color_usage[i]; } // Do normal average if no pixels used if (used==0) { sum_r=sum_g=sum_b=used=0; for (i=block_start; i<=block_end; i++) { used+=1; sum_r+=working_palette[i].R; sum_g+=working_palette[i].G; sum_b+=working_palette[i].B; } } for (i=block_start; i<=block_end; i++) { Set_red (i,sum_r/used,working_palette); Set_green(i,sum_g/used,working_palette); Set_blue (i,sum_b/used,working_palette); } } else { temp_color=Wait_click_in_palette(Window_palette_button_list); if (temp_color>=0) { dword sum_r=0, sum_g=0, sum_b=0, used; Palette_edit_step(); // Compute weighted average used=color_usage[temp_color]+color_usage[Fore_color]; if (used) { sum_r=(working_palette[temp_color].R * color_usage[temp_color] + working_palette[Fore_color].R * color_usage[Fore_color]) / used; sum_g=(working_palette[temp_color].G * color_usage[temp_color] + working_palette[Fore_color].G * color_usage[Fore_color]) / used; sum_b=(working_palette[temp_color].B * color_usage[temp_color] + working_palette[Fore_color].B * color_usage[Fore_color]) / used; } else // Normal average { sum_r=(working_palette[temp_color].R+working_palette[Fore_color].R)/2; sum_g=(working_palette[temp_color].G+working_palette[Fore_color].G)/2; sum_b=(working_palette[temp_color].B+working_palette[Fore_color].B)/2; } Set_red (temp_color,sum_r,working_palette); Set_green(temp_color,sum_g,working_palette); Set_blue (temp_color,sum_b,working_palette); Set_red (Fore_color,sum_r,working_palette); Set_green(Fore_color,sum_g,working_palette); Set_blue (Fore_color,sum_b,working_palette); Wait_end_of_click(); } } Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); // On prpare la "modifiabilit" des nouvelles couleurs Set_palette(working_palette); memcpy(temp_palette,working_palette,sizeof(T_Palette)); need_to_remap=1; break; case 6 : // Grey scale // Backup Palette_edit_step(); // Grey Scale for (i=block_start;i<=block_end;i++) { temp_color=(dword)( ((dword)working_palette[i].R*30) + ((dword)working_palette[i].G*59) + ((dword)working_palette[i].B*11) )/100; Set_red(i,temp_color,working_palette); Set_green (i,temp_color,working_palette); Set_blue (i,temp_color,working_palette); } Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); // On prpare la "modifiabilit" des nouvelles couleurs Set_palette(working_palette); memcpy(temp_palette,working_palette,sizeof(T_Palette)); need_to_remap=1; break; case 7 : // Swap case 8 : // X-Swap temp_color=Wait_click_in_palette(Window_palette_button_list); if ((temp_color>=0) && (temp_color!=block_start)) { Hide_cursor(); Palette_edit_step(); // On calcule le nombre de couleurs a swapper sans risquer de sortir // de la palette (La var. first_color est utilise pour conomiser 1 var; c'est tout) first_color=(temp_color+block_end-block_start<=255)?block_end+1-block_start:256-temp_color; if (clicked_button==8) // On ne fait de backup de l'image que si on // est en mode X-SWAP. if (!image_is_backed_up) { Backup_layers(-1); image_is_backed_up=1; } Swap(clicked_button==8,block_start,temp_color,first_color,working_palette,color_usage); memcpy(temp_palette,working_palette,sizeof(T_Palette)); // On dplace le bloc vers les modifs: last_color=block_end=temp_color+first_color-1; Fore_color=first_color=block_start=temp_color; // On raffiche le n des bornes du bloc: if (block_start!=block_end) { // Cas d'un bloc multi-couleur Num2str(block_start,str ,3); Num2str(block_end ,str+4,3); str[3]=26; // Flche vers la droite // Affichage dans le block de visu du bloc (dgrad) en cours Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); } else { // Cas d'une seule couleur Num2str(Fore_color,str,3); Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); } Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // On tag le bloc (ou la couleur) Tag_color_range(block_start,block_end); if (show_used_colors) Tag_used_colors(1, color_usage); need_to_remap=1; Set_palette(working_palette); Display_cursor(); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); // En cas de X-Swap, tout l'ecran a pu changer de couleur. if (clicked_button==8) { Palette_edit_step(); // Disable Undo Update_rect(0, 0, Screen_width, Menu_Y_before_window); End_of_modification(); } Wait_end_of_click(); } break; case 9 : // Copy (to other slot) temp_color=Wait_click_in_palette(Window_palette_button_list); if ((temp_color>=0) && (temp_color!=block_start)) { Hide_cursor(); Palette_edit_step(); memcpy(working_palette+temp_color,backup_palette+block_start, ((temp_color+block_end-block_start<=255)?block_end+1-block_start:256-temp_color)*3); memcpy(temp_palette,working_palette,sizeof(T_Palette)); Set_palette(working_palette); // On dplace le bloc vers les modifs: last_color=block_end=((temp_color+block_end-block_start<=255)?(temp_color+block_end-block_start):255); Fore_color=first_color=block_start=temp_color; // On raffiche le n des bornes du bloc: if (block_start!=block_end) { // Cas d'un bloc multi-couleur Num2str(block_start,str ,3); Num2str(block_end ,str+4,3); str[3]=26; // Flche vers la droite // Affichage dans le block de visu du bloc (dgrad) en cours Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); } else { // Cas d'une seule couleur Num2str(Fore_color,str,3); Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); } Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // On tag le bloc (ou la couleur) Tag_color_range(block_start,block_end); need_to_remap=1; Display_cursor(); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Wait_end_of_click(); } break; case 10 : // Spread if (block_start!=block_end) { Palette_edit_step(); Spread_colors(block_start,block_end,working_palette); } else { temp_color=Wait_click_in_palette(Window_palette_button_list); if (temp_color>=0) { Palette_edit_step(); if (temp_color 256) break; // Cancel reduce_colors_number = choice; } else // Each other dropdown item has a number of colors as id. reduce_colors_number = Window_attribute2; if (reduce_colors_number >= 2) { if (!image_is_backed_up) { Backup_layers(-1); image_is_backed_up = 1; } Reduce_palette(&used_colors, reduce_colors_number, working_palette, color_usage); if ((Config.Safety_colors) && (used_colors<4)) { memcpy(temp_palette, Main_palette, sizeof(T_Palette)); memcpy(Main_palette, working_palette, sizeof(T_Palette)); Set_nice_menu_colors(color_usage, 0); memcpy(working_palette, Main_palette, sizeof(T_Palette)); memcpy(Main_palette, temp_palette, sizeof(T_Palette)); } Set_palette(working_palette); // On dfinit la nouvelle palette Draw_all_palette_sliders(red_slider, green_slider, blue_slider, working_palette, block_start, block_end); memcpy(temp_palette, working_palette, sizeof(T_Palette)); Palette_edit_step(); // Disable Undo End_of_modification(); need_to_remap = 1; } break; case 12: // Undo Palette_edit_undo_redo(); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Set_palette(working_palette); need_to_remap=1; break; case 15 : // Used : show usage tags show_used_colors = !show_used_colors; Tag_used_colors(show_used_colors, color_usage); break; case 16 : // Zap unused Palette_edit_step(); if (used_colors==-1) Update_color_count(&used_colors,color_usage); for (i=0; i<256; i++) { if (!color_usage[i]) { temp_color=block_start+(i % (block_end+1-block_start)); working_palette[i].R=backup_palette[temp_color].R; working_palette[i].G=backup_palette[temp_color].G; working_palette[i].B=backup_palette[temp_color].B; } } if ((Config.Safety_colors) && (used_colors<4) && (block_end==block_start)) { memcpy(temp_palette,Main_palette,sizeof(T_Palette)); memcpy(Main_palette,working_palette,sizeof(T_Palette)); Set_nice_menu_colors(color_usage,0); memcpy(working_palette,Main_palette,sizeof(T_Palette)); memcpy(Main_palette,temp_palette,sizeof(T_Palette)); } Set_palette(working_palette); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); need_to_remap=1; break; case 17 : // [+] if (!Palette_view_is_RGB) break; Hide_cursor(); Palette_edit_alter_channel(); if (block_start==block_end) { if (red_slider->Position) { (red_slider->Position)--; Window_draw_slider(red_slider); Set_red(Fore_color,Reduce_component(Color_max-red_slider->Position),working_palette); Format_component(working_palette[Fore_color].R*Color_count/256,str); Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (green_slider->Position) { (green_slider->Position)--; Window_draw_slider(green_slider); Set_green (Fore_color,Reduce_component(Color_max-green_slider->Position),working_palette); Format_component(working_palette[Fore_color].G*Color_count/256,str); Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (blue_slider->Position) { (blue_slider->Position)--; Window_draw_slider(blue_slider); Set_blue (Fore_color,Reduce_component(Color_max-blue_slider->Position),working_palette); Format_component(working_palette[Fore_color].B*Color_count/256,str); Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } } else { if (red_slider->Position) { (red_slider->Position)--; Window_draw_slider(red_slider); } if (green_slider->Position) { (green_slider->Position)--; Window_draw_slider(green_slider); } if (blue_slider->Position) { (blue_slider->Position)--; Window_draw_slider(blue_slider); } for (i=block_start; i<=block_end; i++) { Set_red(i,temp_palette[i].R+Reduce_component(Color_max-red_slider->Position),working_palette); Set_green (i,temp_palette[i].G+Reduce_component(Color_max-green_slider->Position),working_palette); Set_blue (i,temp_palette[i].B+Reduce_component(Color_max-blue_slider->Position),working_palette); } // -- red -- if (red_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-red_slider->Position),str,4); str[0]='-'; } else if (red_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- green -- if (green_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-green_slider->Position),str,4); str[0]='-'; } else if (green_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- blue -- if (blue_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-blue_slider->Position),str,4); str[0]='-'; } else if (blue_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; Display_cursor(); Set_palette(working_palette); break; case 18 : // [-] if (!Palette_view_is_RGB) break; Hide_cursor(); Palette_edit_alter_channel(); if (block_start==block_end) { if (red_slider->PositionPosition)++; Window_draw_slider(red_slider); Set_red(Fore_color,Reduce_component(Color_max-red_slider->Position),working_palette); Format_component(working_palette[Fore_color].R*Color_count/256,str); Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (green_slider->PositionPosition)++; Window_draw_slider(green_slider); Set_green (Fore_color,Reduce_component(Color_max-green_slider->Position),working_palette); Format_component(working_palette[Fore_color].G*Color_count/256,str); Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (blue_slider->PositionPosition)++; Window_draw_slider(blue_slider); Set_blue (Fore_color,Reduce_component(Color_max-blue_slider->Position),working_palette); Format_component(working_palette[Fore_color].B*Color_count/256,str); Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } } else { if (red_slider->Position<(Color_max*2)) { (red_slider->Position)++; Window_draw_slider(red_slider); } if (green_slider->Position<(Color_max*2)) { (green_slider->Position)++; Window_draw_slider(green_slider); } if (blue_slider->Position<(Color_max*2)) { (blue_slider->Position)++; Window_draw_slider(blue_slider); } for (i=block_start; i<=block_end; i++) { Set_red(i,temp_palette[i].R+Reduce_component(Color_max-red_slider->Position),working_palette); Set_green (i,temp_palette[i].G+Reduce_component(Color_max-green_slider->Position),working_palette); Set_blue (i,temp_palette[i].B+Reduce_component(Color_max-blue_slider->Position),working_palette); } // -- red -- if (red_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-red_slider->Position),str,4); str[0]='-'; } else if (red_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- green -- if (green_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-green_slider->Position),str,4); str[0]='-'; } else if (green_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- blue -- if (blue_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-blue_slider->Position),str,4); str[0]='-'; } else if (blue_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; Display_cursor(); Set_palette(working_palette); break; case 19 : // Negative // Backup Palette_edit_step(); // Negative for (i=block_start;i<=block_end;i++) { Set_red(i,255-working_palette[i].R,working_palette); Set_green (i,255-working_palette[i].G,working_palette); Set_blue (i,255-working_palette[i].B,working_palette); } Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Set_palette(working_palette); // On prpare la "modifiabilit" des nouvelles couleurs memcpy(temp_palette,working_palette,sizeof(T_Palette)); need_to_remap=1; break; case 20 : // Inversion case 21 : // X-Inversion // Backup Palette_edit_step(); // Not undoable if X-Invert // On initialise la table de conversion for (i=0; i<=255; i++) conversion_table[i]=i; // Inversion for (i=block_start; i < block_start + (block_end-block_start+1)/2;i++) { temp_color=block_end-(i-block_start); Set_red (i,backup_palette[temp_color].R,working_palette); Set_green (i,backup_palette[temp_color].G,working_palette); Set_blue (i,backup_palette[temp_color].B,working_palette); Set_red (temp_color,backup_palette[i].R,working_palette); Set_green (temp_color,backup_palette[i].G,working_palette); Set_blue (temp_color,backup_palette[i].B,working_palette); if (clicked_button==21) { conversion_table[i]=temp_color; conversion_table[temp_color]=i; temp=color_usage[i]; color_usage[i]=color_usage[temp_color]; color_usage[temp_color]=temp; } } Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); // Si on est en X-Invert, on remap l'image (=> on fait aussi 1 backup) if (clicked_button==21) { if (!image_is_backed_up) { Backup_layers(-1); image_is_backed_up=1; } Hide_cursor(); Remap_image_highlevel(conversion_table); Display_cursor(); End_of_modification(); Palette_edit_step(); // Disable Undo } // On prpare la "modifiabilit" des nouvelles couleurs Set_palette(working_palette); memcpy(temp_palette,working_palette,sizeof(T_Palette)); need_to_remap=1; break; case 22 : // HSL <> RGB // Acte les changements en cours sur une ou plusieurs couleurs Palette_edit_select_range(); Hide_cursor(); Palette_view_is_RGB = !Palette_view_is_RGB; if(! Palette_view_is_RGB) { // On passe en HSL Print_RGB_or_HSL(1); Component_unit(256); // Display the + and - button as disabled Window_draw_normal_bouton(BUTTON_PLUS_X, BUTTON_PLUS_Y,12,11,"+",0,0); Window_draw_normal_bouton(BUTTON_MINUS_X,BUTTON_MINUS_Y,12,11,"-",0,0); } else { // On passe en RGB Print_RGB_or_HSL(0); Component_unit(RGB_scale); // Display the + and - button as enabled Window_draw_normal_bouton(BUTTON_PLUS_X, BUTTON_PLUS_Y,12,11,"+",0,1); Window_draw_normal_bouton(BUTTON_MINUS_X,BUTTON_MINUS_Y,12,11,"-",0,1); } Display_sliders(red_slider,green_slider,blue_slider,(block_start!=block_end),working_palette); Display_cursor(); Update_window_area(BUTTON_PLUS_X-1,BUTTON_PLUS_Y-1,14,14); Update_window_area(BUTTON_MINUS_X-1,BUTTON_MINUS_Y-1,14,14); break; case 23 : // Sort palette { byte h = 0, l = 0, s=0; byte oh=0,ol=0,os=0; // Valeur pour la couleur prcdente int swap=1; byte remap_table[256]; byte inverted_table[256]; byte begin, end; long lightness; long old_lightness; if(block_start==block_end) { begin = 0; end = 255; } else { begin = block_start; end = block_end; } // Init remap table for (i=0;i<256;i++) remap_table[i]=i; // Make a backup because remapping is an undoable modification if (!image_is_backed_up) { Backup_layers(-1); image_is_backed_up=1; } if(Window_attribute2==0) // Sort by Hue (H) and Lightness (L) while(swap==1) { swap=0; h=0;l=255;s=0; for(temp_color=begin;temp_color<=end;temp_color++) { oh=h; ol=l; os=s; RGB_to_HSL(working_palette[temp_color].R, working_palette[temp_color].G, working_palette[temp_color].B,&h,&s,&l); if( ((s==0) && (os>0)) // A grey is before a saturated color || ((s>0 && os > 0) && (hol))) // 2 saturated colors: sort by H, then by L || ((os==0 && s==0) && l>ol)) // Two greys: sort by L only { // Swap color with the previous one SWAP_BYTES(working_palette[temp_color].R, working_palette[temp_color-1].R) SWAP_BYTES(working_palette[temp_color].G, working_palette[temp_color-1].G) SWAP_BYTES(working_palette[temp_color].B, working_palette[temp_color-1].B) SWAP_DWORDS(color_usage[temp_color], color_usage[temp_color-1]) SWAP_BYTES(remap_table[temp_color], remap_table[temp_color-1]) swap=1; } } } else // Sort only on perceived lightness while(swap==1) { swap=0; lightness=Perceptual_lightness(working_palette+begin); for(temp_color=begin+1;temp_color<=end;temp_color++) { old_lightness=lightness; lightness=Perceptual_lightness(working_palette+temp_color); if(lightness>old_lightness) { // Swap color with the previous one SWAP_BYTES(working_palette[temp_color].R, working_palette[temp_color-1].R) SWAP_BYTES(working_palette[temp_color].G, working_palette[temp_color-1].G) SWAP_BYTES(working_palette[temp_color].B, working_palette[temp_color-1].B) SWAP_DWORDS(color_usage[temp_color], color_usage[temp_color-1]) SWAP_BYTES(remap_table[temp_color], remap_table[temp_color-1]) swap=1; } } } for (i=0;i<256;i++) inverted_table[remap_table[i]]=i; Remap_image_highlevel(inverted_table); // Maintenant, tous ces calculs doivent tres pris en compte dans la // palette, l'image et l'cran. Set_palette(working_palette); Palette_edit_step(); // Disable Undo End_of_modification(); need_to_remap=1; } break; case 24: // R G B value: Hex entry { char str[7]; unsigned int new_color; Hide_cursor(); Print_in_window(NUMERIC_BOX_X+2,NUMERIC_BOX_Y+2,"Hex",MC_Black,MC_Light); // Clear out remaining area Window_rectangle(NUMERIC_BOX_X+1+3*8,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-3-3*8, NUMERIC_BOX_H-3,MC_Light); Update_window_area(NUMERIC_BOX_X+1+3*8,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-3-3*8, NUMERIC_BOX_H-3); str[0]='\0'; Display_cursor(); if (Readline(NUMERIC_BOX_X+NUMERIC_BOX_W-2-6*8, NUMERIC_BOX_Y+2, str, 6, INPUT_TYPE_HEXA)) { int length = strlen(str); short new_red, new_blue, new_green; if (length==3 || length==6) { sscanf(str, "%x", &new_color); if (length==3) { new_color = ((new_color&0xF00)*0x1100) | ((new_color&0x0F0)*0x110) | ((new_color&0x00F)*0x11); } new_red=(new_color&0xFF0000) >> 16; new_green=(new_color&0x00FF00) >> 8; new_blue=(new_color&0x0000FF); // Backup Palette_edit_step(); // Assign color for (i=block_start;i<=block_end;i++) { Set_red(i,new_red,working_palette); Set_green (i,new_green,working_palette); Set_blue (i,new_blue,working_palette); } // On prpare la "modifiabilit" des nouvelles couleurs Set_palette(working_palette); memcpy(temp_palette,working_palette,sizeof(T_Palette)); need_to_remap=1; } } // Clear out numeric area Window_rectangle(NUMERIC_BOX_X+1,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-2, NUMERIC_BOX_H-2,MC_Light); Update_window_area(NUMERIC_BOX_X+1,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-2, NUMERIC_BOX_H-2); Display_cursor(); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); } break; case 25: // Number of colors used: Open histogram { int selected_col; selected_col=Window_Histogram(block_start, block_end, color_usage); if (selected_col!=-1) { // Tag selected color Fore_color=first_color=last_color=block_start=block_end=selected_col; Tag_color_range(block_start,block_end); // Affichage du n de la couleur slectionne Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); Num2str(Fore_color,str,3); Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); Update_window_area(COLOR_X,COLOR_Y,56,7); // Affichage des jauges Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light); Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Palette_edit_select_range(); } Display_cursor(); Input_sticky_control=0; Wait_end_of_click(); break; } } if (!Mouse_K) { if (Key) { if (Is_shortcut(Key,SPECIAL_PREVIOUS_FORECOLOR)) // Dcaler Forecolor vers la gauche { if (block_start==block_end) { Fore_color--; first_color--; last_color--; block_start--; block_end--; Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Hide_cursor(); Tag_color_range(block_start,block_end); // Affichage du n de la couleur slectionne Num2str(Fore_color,str,3); Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Display_cursor(); } Key=0; } else if (Is_shortcut(Key,SPECIAL_NEXT_FORECOLOR)) // Dcaler Forecolor vers la droite { if (block_start==block_end) { Fore_color++; first_color++; last_color++; block_start++; block_end++; Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Hide_cursor(); Tag_color_range(block_start,block_end); // Affichage du n de la couleur slectionne Num2str(Fore_color,str,3); Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Display_cursor(); } Key=0; } else if (Is_shortcut(Key,SPECIAL_PREVIOUS_BACKCOLOR)) { Back_color--; Hide_cursor(); Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); Display_cursor(); Key=0; } else if (Is_shortcut(Key,SPECIAL_NEXT_BACKCOLOR)) { Back_color++; Hide_cursor(); Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); Display_cursor(); Key=0; } else if (Key == SDLK_BACKSPACE) // Remise des couleurs du menu l'tat normal en essayant // de ne pas trop modifier l'image. { if (!image_is_backed_up) { Backup_layers(-1); image_is_backed_up=1; } if (used_colors==-1) Update_color_count(&used_colors, color_usage); Palette_edit_step(); memcpy(temp_palette,Main_palette,sizeof(T_Palette)); memcpy(Main_palette,working_palette,sizeof(T_Palette)); Set_nice_menu_colors(color_usage,0); memcpy(working_palette,Main_palette,sizeof(T_Palette)); memcpy(Main_palette,temp_palette,sizeof(T_Palette)); Set_palette(working_palette); memcpy(temp_palette,working_palette,sizeof(T_Palette)); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Update_color_count(&used_colors,color_usage); // End_of_modification(); // Not really needed, the change was in palette entries need_to_remap=1; Key=0; } else if (Is_shortcut(Key,0x100+BUTTON_COLORPICKER)) { // Rcupration d'une couleur derrire le menu Get_color_behind_window(&color,&click); if (click) { Hide_cursor(); if (click==RIGHT_SIDE) { if (Back_color!=color) { Back_color=color; // 4 blocks de back_color entourant la fore_color Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); } } else { Fore_color=first_color=last_color=block_start=block_end=color; Tag_color_range(block_start,block_end); // Affichage du n de la couleur slectionne Window_rectangle(COLOR_X+24,COLOR_Y,32,7,MC_Light); Update_window_area(COLOR_X+24,COLOR_Y,32,7); Num2str(Fore_color,str,3); Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage des jauges Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Palette_edit_select_range(); } Display_cursor(); Wait_end_of_click(); } Key=0; } else if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Key=0; Window_help(BUTTON_PALETTE, NULL); } else if (Is_shortcut(Key,0x100+BUTTON_PALETTE)) { // Close (confirm) clicked_button=14; } else if (Key == (SDLK_c|MOD_CTRL)) // Ctrl-C { Set_clipboard_colors(block_end+1-block_start,working_palette + block_start); } else if (Key == (SDLK_v|MOD_CTRL)) // Ctrl-V { int nb_colors; Hide_cursor(); // Backup Palette_edit_step(); nb_colors = Get_clipboard_colors(working_palette, block_start); if (nb_colors>0) { memcpy(temp_palette,working_palette,sizeof(T_Palette)); Set_palette(working_palette); need_to_remap=1; Display_cursor(); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); } } } if (need_to_remap) { Hide_cursor(); Compute_optimal_menu_colors(working_palette); // On remappe brutalement Remap_screen_after_menu_colors_change(); // Puis on remet les trucs qui ne devaient pas changer Window_draw_palette_bouton(5,79); if (show_used_colors) Tag_used_colors(1, color_usage); Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H,Back_color); Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); Update_window_area(8,82,16*10,5*16); Display_cursor(); need_to_remap=0; } } } while ((clicked_button!=13) && (clicked_button!=14)); if (clicked_button==14) // Sortie par OK { if ( (!image_is_backed_up) && memcmp(Main_palette,working_palette,sizeof(T_Palette)) ) Backup_layers(-1); memcpy(Main_palette,working_palette,sizeof(T_Palette)); End_of_modification(); // Not really needed, the change was in palette entries } Compute_optimal_menu_colors(Main_palette); // La variable employe ici n'a pas vraiment de rapport avec son nom... need_to_remap=(Window_pos_Y+(Window_height*Menu_factor_Y)Position = rgb_scale_slider->Position>128?rgb_scale_slider->Position*2-256:0; Num2str(256-rgb_scale_slider->Position,str,3); Print_in_window(157,78,str,MC_Black,MC_Light); Window_draw_slider(rgb_scale_slider); break; case 10: // /2 RGB scale rgb_scale_slider->Position = rgb_scale_slider->Position>253?254:(rgb_scale_slider->Position)/2+128; Num2str(256-rgb_scale_slider->Position,str,3); Print_in_window(157,78,str,MC_Black,MC_Light); Window_draw_slider(rgb_scale_slider); } } while (clicked_button!=1 && clicked_button!=2 && clicked_button!=3 && clicked_button!=4); // We need to get the sliders positions before closing the window, because they will be freed. palette_cols=256-columns_slider->Position; palette_lines=16-lines_slider->Position; rgb_scale=256-rgb_scale_slider->Position; Close_window(); Unselect_button(BUTTON_PALETTE); Display_cursor(); if (clicked_button==4) // Cancel return; if (palette_vertical != Config.Palette_vertical) { Config.Palette_vertical=palette_vertical; palette_needs_redraw=1; } if (palette_cols!=Config.Palette_cells_X || palette_lines!=Config.Palette_cells_Y) { Config.Palette_cells_X = palette_cols; Config.Palette_cells_Y = palette_lines; palette_needs_redraw=1; } if (rgb_scale!=RGB_scale) { Set_palette_RGB_scale(rgb_scale); Set_palette(Main_palette); Compute_optimal_menu_colors(Main_palette); } if (clicked_button==1) { Menu_tag_colors("Tag colors to exclude",Exclude_color,&dummy,1, NULL, SPECIAL_EXCLUDE_COLORS_MENU); } else if (clicked_button==2) { // Open the menu with Shade settings. Same as the shortcut, except // that this will not activate shade mode on exit. Shade_settings_menu(); } if (palette_needs_redraw) { Change_palette_cells(); Display_menu(); Display_sprite_in_menu(BUTTON_PAL_LEFT,Config.Palette_vertical?MENU_SPRITE_VERTICAL_PALETTE_SCROLL:-1); Draw_menu_button(BUTTON_PAL_LEFT,BUTTON_RELEASED); Draw_menu_button(BUTTON_PAL_RIGHT,BUTTON_RELEASED); } } // ========= Clipboard management ============== int Palette_clipboard_count=0; T_Palette Palette_clipboard; /// Put some colors in the clipboard. /// @param nb_colors Number of colors to push /// @param colors First color of the input array void Set_clipboard_colors(int nb_colors, T_Components *colors) { Palette_clipboard_count=nb_colors; if (nb_colors) { memcpy(Palette_clipboard, colors, nb_colors*sizeof(T_Components)); } } /// Get some RGB colors from clipboard. /// @param palette Target palette /// @param start_color Index of first color to replace /// @return Number of colors retrieved (0-256) int Get_clipboard_colors(T_Palette palette, byte start_color) { int nb_colors = Palette_clipboard_count; if (nb_colors==0) return 0; if (start_color+nb_colors > 256) { nb_colors=256-start_color; } memcpy(palette+start_color, Palette_clipboard, nb_colors*sizeof(T_Components)); return nb_colors; } /// Get the favorite color to use for GUI's black,dark,light or white. const T_Components * Favorite_GUI_color(byte color_index) { static const T_Components cpc_colors[4] = { { 0, 0, 0}, { 0, 0,128}, // Dark blue {128,128,128}, // Grey {255,255,255} }; if (RGB_scale==3) { // Check if ALL GUI colors are compatible with /rgb 3 int i; for (i=0; i<4; i++) { T_Components col; col=Gfx->Default_palette[Gfx->Color[i]]; if ((col.R!=255 && col.R!=128 && col.R!=0) ||(col.G!=255 && col.G!=128 && col.G!=0) ||(col.B!=255 && col.B!=128 && col.B!=0)) // Specialized colors for CPC palette return &cpc_colors[color_index]; } // Skin has suitable colors return &(Gfx->Default_palette[Gfx->Color[color_index]]); } else // Should be Config.Fav_menu_colors[index] if using user colors return &(Gfx->Default_palette[Gfx->Color[color_index]]); } grafx2/src/palette_test.c0000644000076400010400000031317411533245536016102 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ #include #include #include #include "const.h" #include "struct.h" #include "global.h" #include "misc.h" #include "engine.h" #include "readline.h" #include "buttons.h" #include "pages.h" #include "help.h" #include "sdlscreen.h" #include "errors.h" #include "op_c.h" #include "windows.h" #include "input.h" #include "palette.h" #include "shade.h" byte Palette_view_is_RGB = 1; // Indique si on est en HSL ou en RGB // Coordinates of the color count (on histogram button) static const int COUNT_X = 258; static const int COUNT_Y = 49; // Nombre de graduations pour une composante RGB int RGB_scale = 256; // 24bit //int RGB_scale = 64; // VGA //int RGB_scale = 16; // Amiga //int RGB_scale = 4; // MSX2 //int RGB_scale = 3; // Amstrad CPC // Nombre de graduations pour une composante dans le mode actuel int Color_count=256; // Les composantes vont de 0 (Color_count-1) int Color_max=255; // Le demi-pas est une quantit que l'on ajoute une composante // avant de faire un arrondi par division. int Color_halfstep=0; void Set_palette_RGB_scale(int scale) { if (scale>= 2 && scale <= 256) RGB_scale = scale; } int Get_palette_RGB_scale(void) { return RGB_scale; } /// /// Round a 0-255 RGB component according to the RGB_scale. /// The result is also in the 0-255 range. byte Round_palette_component(byte comp) { return ((comp+128/RGB_scale)*(RGB_scale-1)/255*255+(RGB_scale&1?1:0))/(RGB_scale-1); } /// /// Turns a RGB component from 0-255 scale to 0-(RGB_scale-1). /// The passed value should come from Round_palette_component(), /// otherwise the rounding will be "down". int Reduce_component(int comp) { return (comp)*255/Color_max; } /// /// Turns a RGB component from 0-(RGB_scale-1) to 0-255. int Expand_component(int comp) { if (Color_max==255) return comp; return (comp+1)*Color_max/255; // The +1 cancel any rounding down, the above test prevents // the only case where it would be too much. } // Dfinir les units pour les graduations R G B ou H S V void Component_unit(int count) { Color_count = count; Color_max = count-1; Color_halfstep = 256/count/2; } void Set_HSL(T_Palette start_palette, T_Palette end_palette, byte color, short diff_h, short diff_s, short diff_l) { byte h, s, l; RGB_to_HSL(start_palette[color].R,start_palette[color].G,start_palette[color].B,&h,&s,&l); // La teinte (Hue) est cyclique h=(diff_h+256+h); // Pour les autres (Saturation, Lightness), au lieu d'additionner, // on va faire un ratio, cela utilise mieux la plage de valeurs 0-255 if (diff_s<0) s=(255+diff_s)*s/255; else if (diff_s>0) s=255-(255-diff_s)*(255-s)/255; if (diff_l<0) l=(255+diff_l)*l/255; else if (diff_l>0) l=255-(255-diff_l)*(255-l)/255; HSL_to_RGB(h,s,l,&end_palette[color].R,&end_palette[color].G,&end_palette[color].B); } void Set_red(byte color, short new_color, T_Palette palette) { if (new_color< 0) new_color= 0; if (new_color>255) new_color=255; // Arrondi new_color=Round_palette_component(new_color); palette[color].R=new_color; } void Set_green(byte color, short new_color, T_Palette palette) { if (new_color< 0) new_color= 0; if (new_color>255) new_color=255; // Arrondi new_color=Round_palette_component(new_color); palette[color].G=new_color; } void Set_blue(byte color, short new_color, T_Palette palette) { if (new_color< 0) new_color= 0; if (new_color>255) new_color=255; // Arrondi new_color=Round_palette_component(new_color); palette[color].B=new_color; } void Format_component(byte value, char *str) // Formate une chaine de 4 caractres+\0 : "nnn " { Num2str(value,str,3); str[3]=' '; str[4]='\0'; } void Spread_colors(short start,short end,T_Palette palette) // Modifie la palette pour obtenir un dgrad de couleur entre les deux bornes // passes en paramtre { short start_red; short start_green; short start_blue; short end_red; short end_green; short end_blue; short index; // On vrifie qu'il y ait assez de couleurs entre le dbut et la fin pour // pouvoir faire un dgrad: if ( (start!=end) && (start+1!=end) ) { start_red=palette[start].R; start_green =palette[start].G; start_blue =palette[start].B; end_red =palette[end ].R; end_green =palette[end ].G; end_blue =palette[end ].B; for (index=start+1;index=Window_pos_Y) && (y_pos=Window_pos_X) && (x_posPages->Nb_layers; layer++) Remap_general_lowlevel(conversion_table,Main_backups->Pages->Image[layer],Main_backups->Pages->Image[layer],Main_image_width,Main_image_height,Main_image_width); // Remap transparent color Main_backups->Pages->Transparent_color = conversion_table[Main_backups->Pages->Transparent_color]; // On calcule les limites l'cran de l'image if (Main_image_height>=Menu_Y_before_window) end_y=Menu_Y_before_window; else end_y=Main_image_height; if (!Main_magnifier_mode) { if (Main_image_width>=Screen_width) end_x=Screen_width; else end_x=Main_image_width; } else { if (Main_image_width>=Main_separator_position) end_x=Main_separator_position; else end_x=Main_image_width; if ((Main_X_zoom+(Main_image_width*Main_magnifier_factor))>=Screen_width) end_x_mag=Screen_width; else end_x_mag=(Main_X_zoom+(Main_image_width*Main_magnifier_factor)); if (Main_image_height*Main_magnifier_factor>=Menu_Y_before_window) end_y_mag=Menu_Y_before_window; else end_y_mag=Main_image_height*Main_magnifier_factor; } // On doit maintenant faire la traduction l'cran Remap_zone_highlevel(0,0,end_x,end_y,conversion_table); if (Main_magnifier_mode) { Remap_zone_highlevel(Main_separator_position,0,end_x_mag,end_y_mag,conversion_table); // Il peut encore rester le bas de la barre de split remapper si la // partie zoome ne descend pas jusqu'en bas... Remap_zone_highlevel(Main_separator_position,end_y_mag, (Main_separator_position+(SEPARATOR_WIDTH*Menu_factor_X)), Menu_Y_before_window,conversion_table); } // Remappe tous les fonds de fenetre (qui doivent contenir un bout d'cran) Remap_window_backgrounds(conversion_table, 0, Menu_Y_before_window); } void Swap(int with_remap,short block_1_start,short block_2_start,short block_size,T_Palette palette, dword * color_usage) { short pos_1; short pos_2; short end_1; short end_2; byte conversion_table[256]; T_Components temp_palette[256]; dword temp_usage[256]; // On fait une copie de la palette memcpy(temp_palette, palette, sizeof(T_Palette)); // On fait une copie de la table d'used des couleurs memcpy(temp_usage, color_usage, sizeof(dword) * 256); // On commence initialiser la table de conversion un tat o elle ne // fera aucune conversion. for (pos_1=0;pos_1<=255;pos_1++) conversion_table[pos_1]=pos_1; // On calcul les dernires couleurs de chaque bloc. end_1=block_1_start+block_size-1; end_2=block_2_start+block_size-1; if ((block_2_start>=block_1_start) && (block_2_start<=end_1)) { // Le bloc destination commence dans le bloc source. for (pos_1=block_1_start,pos_2=end_1+1;pos_1<=end_2;pos_1++) { // Il faut transformer la couleur pos_1 en pos_2: conversion_table[pos_2]=pos_1; color_usage[pos_1]=temp_usage[pos_2]; palette[pos_1].R=temp_palette[pos_2].R; palette[pos_1].G=temp_palette[pos_2].G; palette[pos_1].B=temp_palette[pos_2].B; // On gre la mise jour de pos_2 if (pos_2==end_2) pos_2=block_1_start; else pos_2++; } } else if ((block_2_start=block_1_start)) { // Le bloc destination dborde dans le bloc source. for (pos_1=block_2_start,pos_2=block_1_start;pos_1<=end_1;pos_1++) { // Il faut transformer la couleur pos_1 en pos_2: conversion_table[pos_2]=pos_1; color_usage[pos_1]=temp_usage[pos_2]; palette[pos_1].R=temp_palette[pos_2].R; palette[pos_1].G=temp_palette[pos_2].G; palette[pos_1].B=temp_palette[pos_2].B; // On gre la mise jour de pos_2 if (pos_2==end_1) pos_2=block_2_start; else pos_2++; } } else { // Le bloc source et le bloc destination sont distincts. for (pos_1=block_1_start,pos_2=block_2_start;pos_1<=end_1;pos_1++,pos_2++) { // Il va falloir permutter la couleur pos_1 avec la couleur pos_2 conversion_table[pos_1]=pos_2; conversion_table[pos_2]=pos_1; // On intervertit le nombre d'used des couleurs pour garder une // cohrence lors d'un ventuel "Zap unused". SWAP_DWORDS(color_usage[pos_1], color_usage[pos_2]) // On fait un changement de teinte: SWAP_BYTES(palette[pos_1].R, palette[pos_2].R) SWAP_BYTES(palette[pos_1].G, palette[pos_2].G) SWAP_BYTES(palette[pos_1].B, palette[pos_2].B) } } if (with_remap) { Remap_image_highlevel(conversion_table); } else { // Restore color usage. Shouldn't have reordered it in the first place. memcpy(color_usage, temp_usage, sizeof(dword) * 256); } } void Set_nice_menu_colors(dword * color_usage,int not_picture) { short index,index2; byte color; byte replace_table[256]; T_Components rgb[4]; short new_colors[4]={255,254,253,252}; // On initialise la table de remplacement for (index=0; index<256; index++) replace_table[index]=index; // On recherche les 4 couleurs les moins utilises dans l'image pour pouvoir // les remplacer par les nouvelles couleurs. for (index2=0; index2<4; index2++) for (index=255; index>=0; index--) { if ((index!=new_colors[0]) && (index!=new_colors[1]) && (index!=new_colors[2]) && (index!=new_colors[3]) && (color_usage[index]new_colors[index+1]) { index2 =new_colors[index]; new_colors[index] =new_colors[index+1]; new_colors[index+1]=index2; color=1; } } } while (color); // On sauvegarde dans rgb les teintes qu'on va remplacer et on met les // couleurs du menu par dfaut for (index=0; index<4; index++) { const T_Components * target_rgb; target_rgb=Favorite_GUI_color(index); color=new_colors[index]; rgb[index].R=Main_palette[color].R; rgb[index].G=Main_palette[color].G; rgb[index].B=Main_palette[color].B; Main_palette[color].R=Round_palette_component(target_rgb->R); Main_palette[color].G=Round_palette_component(target_rgb->G); Main_palette[color].B=Round_palette_component(target_rgb->B); } // Maintenant qu'on a plac notre nouvelle palette, on va chercher quelles // sont les couleurs qui peuvent remplacer les anciennes Hide_cursor(); for (index=0; index<4; index++) replace_table[new_colors[index]]=Best_color_nonexcluded (rgb[index].R,rgb[index].G,rgb[index].B); if (not_picture) { // Remap caused by preview. Only remap screen Remap_zone_highlevel(0,0,Screen_width,Screen_height,replace_table); } else { // On fait un changement des couleurs visibles l'cran et dans l'image Remap_image_highlevel(replace_table); } Display_cursor(); } void Reduce_palette(short * used_colors,int nb_colors_asked,T_Palette palette,dword * color_usage) { char str[5]; // buffer d'affichage du compteur byte conversion_table[256]; // Table de conversion int color_1; // |_ Variables de balayages int color_2; // | de la palette int best_color_1=0; int best_color_2=0; int difference; int best_difference; dword used; dword best_used; // On commence par initialiser la table de conversion dans un tat o // aucune conversion ne sera effectue. for (color_1=0; color_1<=255; color_1++) conversion_table[color_1]=color_1; // Si on ne connait pas encore le nombre de couleurs utilises, on le // calcule! (!!! La fonction appele Efface puis Affiche le curseur !!!) if ((*used_colors)<0) Update_color_count(used_colors,color_usage); Hide_cursor(); // On tasse la palette vers le dbut parce qu'elle doit ressembler // du Gruyre (et comme Papouille il aime pas le fromage...) // Pour cela, on va scruter la couleur color_1 et se servir de l'indice // color_2 comme position de destination. for (color_1=color_2=0;color_1<=255;color_1++) { if (color_usage[color_1]) { // On commence par s'occuper des teintes de la palette palette[color_2].R=palette[color_1].R; palette[color_2].G=palette[color_1].G; palette[color_2].B=palette[color_1].B; // Ensuite, on met jour le tableau d'occupation des couleurs. color_usage[color_2]=color_usage[color_1]; // On va maintenant s'occuper de la table de conversion: conversion_table[color_1]=color_2; // Maintenant, la place dsigne par color_2 est occupe, alors on // doit passer un indice de destination suivant. color_2++; } } // On met toutes les couleurs inutilises en noir for (;color_2<256;color_2++) { palette[color_2].R=0; palette[color_2].G=0; palette[color_2].B=0; color_usage[color_2]=0; } // Maintenant qu'on a une palette clean, on va boucler en rduisant // le nombre de couleurs jusqu' ce qu'on atteigne le nombre dsir. // (The stop condition is further down) while (1) { // Il s'agit de trouver les 2 couleurs qui se ressemblent le plus // parmis celles qui sont utilises (bien sr) et de les remplacer par // une seule couleur qui est la moyenne pondre de ces 2 couleurs // en fonction de leur utilisation dans l'image. best_difference =0x7FFF; best_used=0x7FFFFFFF; for (color_1=0;color_1<(*used_colors);color_1++) for (color_2=color_1+1;color_2<(*used_colors);color_2++) if (color_1!=color_2) { difference =abs((short)palette[color_1].R-palette[color_2].R)+ abs((short)palette[color_1].G-palette[color_2].G)+ abs((short)palette[color_1].B-palette[color_2].B); if (difference<=best_difference) { used=color_usage[color_1]+color_usage[color_2]; if ((differencebest_color_2) { // La color_1 va scroller en arrire. // Donc on transfre son utilisation dans l'utilisation de la // couleur qui la prcde. color_usage[color_1-1]=color_usage[color_1]; // Et on transfre ses teintes dans les teintes de la couleur qui // la prcde. palette[color_1-1].R=palette[color_1].R; palette[color_1-1].G=palette[color_1].G; palette[color_1-1].B=palette[color_1].B; } // Une fois la palette et la table d'utilisation gres, on peut // s'occuper de notre table de conversion. if (conversion_table[color_1]>best_color_2) // La color_1 avait l'intention de se faire remplacer par une // couleur que l'on va (ou que l'on a dj) bouger en arrire. conversion_table[color_1]--; } // On vient d'jecter une couleur, donc on peut mettre jour le nombre // de couleurs utilises. (*used_colors)--; // A la fin, on doit passer (dans la palette) les teintes du dernier // lment de notre ensemble en noir. palette[*used_colors].R=0; palette[*used_colors].G=0; palette[*used_colors].B=0; // Au passage, on va s'assurer que l'on a pas oubli de la mettre une // utilisation nulle. color_usage[*used_colors]=0; // Aprs avoir ject une couleur, on le fait savoir l'utilisateur par // l'intermdiaire du compteur de nombre utilises. Num2str(*used_colors,str,3); Print_in_window(COUNT_X,COUNT_Y,str,MC_Black,MC_Light); } // Maintenant, tous ces calculs doivent tres pris en compte dans la // palette, l'image et l'cran. Remap_image_highlevel(conversion_table); // Et voila pour l'image et l'cran Display_cursor(); } // Position of the numeric values of the R G B sliders static const int NUMERIC_R_X = 176; static const int NUMERIC_G_X = 203; static const int NUMERIC_B_X = 230; static const int NUMERIC_Y = 171; // Position of the whole button static const int NUMERIC_BOX_X = 175; static const int NUMERIC_BOX_Y = 169; static const int NUMERIC_BOX_W = 81; static const int NUMERIC_BOX_H = 12; void Set_palette_slider(T_Scroller_button * slider, word nb_elements, word position, char * value, short x_pos) { slider->Nb_elements=nb_elements; slider->Position=position; Compute_slider_cursor_length(slider); Window_draw_slider(slider); Print_counter(x_pos,NUMERIC_Y,value,MC_Black,MC_Light); } void Display_sliders(T_Scroller_button * red_slider, T_Scroller_button * green_slider, T_Scroller_button * blue_slider, byte block_is_selected, T_Components * palette) { char str[5]; if (block_is_selected) { Set_palette_slider(red_slider,Color_max*2+1,Color_max," 0",NUMERIC_R_X); Set_palette_slider(green_slider,Color_max*2+1,Color_max," 0",NUMERIC_G_X); Set_palette_slider(blue_slider,Color_max*2+1,Color_max," 0",NUMERIC_B_X); } else { byte j1, j2, j3; j1= palette[Fore_color].R; j2= palette[Fore_color].G; j3= palette[Fore_color].B; if (!Palette_view_is_RGB) { RGB_to_HSL(j1,j2,j3,&j1,&j2,&j3); } Format_component(j1*Color_count/256,str); Set_palette_slider(red_slider,Color_count,Color_max-Expand_component(j1),str,NUMERIC_R_X); Format_component(j2*Color_count/256,str); Set_palette_slider(green_slider,Color_count,Color_max-Expand_component(j2),str,NUMERIC_G_X); Format_component(j3*Color_count/256,str); Set_palette_slider(blue_slider,Color_count,Color_max-Expand_component(j3),str,NUMERIC_B_X); } } void Draw_all_palette_sliders(T_Scroller_button * red_slider, T_Scroller_button * green_slider, T_Scroller_button * blue_slider, T_Palette palette,byte start,byte end) { char str[5]; Hide_cursor(); // Raffichage des jauges: if (start!=end) { // Dans le cas d'un bloc, tout 0. red_slider->Position =Color_max; Window_draw_slider(red_slider); Print_counter(NUMERIC_R_X,NUMERIC_Y," 0",MC_Black,MC_Light); green_slider->Position =Color_max; Window_draw_slider(green_slider); Print_counter(NUMERIC_G_X,NUMERIC_Y," 0",MC_Black,MC_Light); blue_slider->Position =Color_max; Window_draw_slider(blue_slider); Print_counter(NUMERIC_B_X,NUMERIC_Y," 0",MC_Black,MC_Light); } else { // Dans le cas d'une seule couleur, composantes. byte j1, j2, j3; j1= palette[start].R; j2= palette[start].G; j3= palette[start].B; if (!Palette_view_is_RGB) { RGB_to_HSL(j1,j2,j3,&j1,&j2,&j3); } DEBUG("j1",j1); Format_component(j1*Color_count/256,str); red_slider->Position=Color_max-Expand_component(j1); Window_draw_slider(red_slider); Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); Format_component(j2*Color_count/256,str); green_slider->Position=Color_max-Expand_component(j2); Window_draw_slider(green_slider); Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); Format_component(j3*Color_count/256,str); blue_slider->Position=Color_max-Expand_component(j3); Window_draw_slider(blue_slider); Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } Display_cursor(); } int Window_Histogram(unsigned char block_start, unsigned char block_end, dword* color_usage) { int i, j; unsigned int max_count = 0; int old_height=0; int hovered_color=-1; int new_hovered_color; int bar_width; T_Special_button *histo; int clicked_button; /* Draws an histogram of the selected range in a separate window */ if (block_start == block_end) { // only one color selected: auto-detect the range for (block_start=0; block_start!=255; block_start++) if (color_usage[block_start]) break; for (block_end=255; block_end!=0; block_end--) if (color_usage[block_end]) break; } // Normalize the histogram towards the most used color // Step 1 : find the most used color in the range for(i=block_start; i<= block_end; i++) { if(color_usage[i] > max_count) max_count = color_usage[i]; } if (max_count == 0) { Warning_message("All these colors are unused!"); Hide_cursor(); return -1; } Open_window(263, 150, "Histogram"); Window_set_normal_button(120, 130, 42, 14, "Close",-1,1,SDLK_RETURN); Print_in_window(6, 17, "Color:", MC_Dark, MC_Light); Print_in_window(110+12*8, 17, "Pixels", MC_Dark, MC_Light); // Step 2 : draw bars bar_width=256/(block_end-block_start+1); j = 0; for(i=block_start; i<= block_end; i++) { int height = 100*color_usage[i]/max_count; // Don't draw anything if the color is unused if (color_usage[i]!=0) { // Draw at least one pixel if the color is used if (height==0) height=1; Window_rectangle( 3+j*bar_width, 127-height, bar_width, height, i); //if (i == MC_Light) { Window_rectangle( 3+j*bar_width, 126-height, bar_width, 1,MC_Black); //} } // vertical outline if (height>old_height) Window_rectangle( 2+j*bar_width, 126-height, 1, height-old_height+1,MC_Black); else if (old_height>height) Window_rectangle( 3+j*bar_width, 126-old_height, 1, old_height-height+1,MC_Black); old_height=height; j++; } // Last vertical outline if (old_height!=0) Window_rectangle( 3+j*(256/(block_end-block_start+1)), 126-old_height, 1, old_height+1,MC_Black); histo = Window_set_special_button(3, 27, j*bar_width, 100); // 2 Update_window_area(0,0,263,150); Display_cursor(); do { // Find hovered area if (Window_click_in_rectangle(histo->Pos_X,histo->Pos_Y,histo->Pos_X+histo->Width-1,histo->Pos_Y+histo->Height-1)) { short x_pos; x_pos=((short)Mouse_X-Window_pos_X)/Menu_factor_X; new_hovered_color=block_start+(x_pos-histo->Pos_X)/bar_width; } else new_hovered_color=-1; // When changing hovered color, update the info area if (new_hovered_color!=hovered_color) { char str[12]; hovered_color=new_hovered_color; Hide_cursor(); if (hovered_color==-1) { Window_rectangle(6+6*8,17,3*8,7,MC_Light); Update_window_area(6+6*8,17,3*8,7); Window_rectangle(86,17,2*8,8,MC_Light); Update_window_area(86,17,2*8,8); Window_rectangle(110,17,11*8,7,MC_Light); Update_window_area(110,17,11*8,7); } else { Num2str(hovered_color,str ,3); Print_in_window(6+6*8,17,str,MC_Black,MC_Light); Window_rectangle(86,17,2*8,8,hovered_color); Update_window_area(86,17,2*8,8); Num2str(color_usage[hovered_color],str ,11); Print_in_window(110,17,str,MC_Black,MC_Light); } Display_cursor(); } clicked_button=Window_clicked_button(); if (Key == KEY_ESC) clicked_button=1; } while( clicked_button < 1); Close_window(); if (clicked_button==2) { // This is a counter-hack. Close_window() sets Mouse_K to zero // on exit, I don't know why (It will become 1 again if you move // the mouse slightly) // Here I force it back to 1, so that the Wait_end_of_click() // will really wait for a release of mouse button. Mouse_K=1; return hovered_color; } return -1; } void Print_RGB_or_HSL(byte mode) { Print_in_window(184,68,mode?"H":"R",MC_Dark,MC_Light); Print_in_window(211,68,mode?"S":"G",MC_Dark,MC_Light); Print_in_window(238,68,mode?"L":"B",MC_Dark,MC_Light); } void Tag_used_colors(byte color, dword color_usage[]) { word index; for (index=0;index<=255;index++) { short x_pos=Window_palette_button_list->Pos_X+6+((index>>4)*10); short y_pos=Window_palette_button_list->Pos_Y+3+((index&15)* 5); byte col; col=(color&&color_usage[index])?MC_White:MC_Light; Window_rectangle(x_pos+5,y_pos+0,1,5,col); } Update_window_area(Window_palette_button_list->Pos_X+3,Window_palette_button_list->Pos_Y+3,12*16,5*16); } void Button_Palette(void) { static const int BUTTON_PLUS_X = 268; static const int BUTTON_PLUS_Y = 74; static const int BUTTON_MINUS_X = 268; static const int BUTTON_MINUS_Y = 165; // Coordinates of the block that displays Backcolor static const int BGCOLOR_DISPLAY_X = 262; static const int BGCOLOR_DISPLAY_Y = 89; static const int BGCOLOR_DISPLAY_W = 24; static const int BGCOLOR_DISPLAY_H = 72; // Coordinates of the block that displays Forecolor static const int FGCOLOR_DISPLAY_X = 266; static const int FGCOLOR_DISPLAY_Y = 93; static const int FGCOLOR_DISPLAY_W = 16; static const int FGCOLOR_DISPLAY_H = 64; // Coordinates of the Color# static const int COLOR_X = 111; static const int COLOR_Y = 69; static short reduce_colors_number = 256; short temp_color; // Variable pouvant reservir pour diffrents calculs intermdiaires dword temp; byte color,click; // Variables pouvant reservir pour diffrents calculs intermdiaires short clicked_button; word old_mouse_x; word old_mouse_y; byte old_mouse_k; byte block_start; byte block_end; byte first_color; byte last_color; char str[10]; word i; T_Normal_button * button_used; T_Scroller_button * red_slider; T_Scroller_button * green_slider; T_Scroller_button * blue_slider; T_Dropdown_button * reduce_dropdown; T_Dropdown_button * sort_dropdown; byte image_is_backed_up = 0; byte need_to_remap = 0; dword color_usage[256]; short used_colors = -1; // -1 <=> Inconnu byte conversion_table[256]; //T_Components * backup_palette; //T_Components * temp_palette; //T_Components * working_palette; static byte show_used_colors=0; backup_palette =(T_Components *)malloc(sizeof(T_Palette)); temp_palette=(T_Components *)malloc(sizeof(T_Palette)); working_palette=(T_Components *)malloc(sizeof(T_Palette)); Component_unit(RGB_scale); Open_window(299, 188,"Palette"); memcpy(working_palette, Main_palette, sizeof(T_Palette)); //memcpy(backup_palette, Main_palette, sizeof(T_Palette)); //memcpy(temp_palette, Main_palette, sizeof(T_Palette)); Palette_edit_step(); Window_set_palette_button(5, 79); // 1 Window_display_frame (172, 63, 122, 121); // Graduation des jauges de couleur Window_rectangle(180,106,17,1,MC_Dark); Window_rectangle(207,106,17,1,MC_Dark); Window_rectangle(234,106,17,1,MC_Dark); Window_rectangle(180,122,17,1,MC_Dark); Window_rectangle(207,122,17,1,MC_Dark); Window_rectangle(234,122,17,1,MC_Dark); Window_rectangle(180,138,17,1,MC_Dark); Window_rectangle(207,138,17,1,MC_Dark); Window_rectangle(234,138,17,1,MC_Dark); // Jauges de couleur red_slider = Window_set_scroller_button(183, 79, 88,Color_count,1,Color_max-Reduce_component(working_palette[Fore_color].R));// 2 green_slider = Window_set_scroller_button(210, 79, 88,Color_count,1,Color_max-Reduce_component(working_palette[Fore_color].G));// 3 blue_slider = Window_set_scroller_button(237, 79, 88,Color_count,1,Color_max-Reduce_component(working_palette[Fore_color].B));// 4 if(Palette_view_is_RGB==1) { Print_RGB_or_HSL(0); Component_unit(RGB_scale); } else { Print_RGB_or_HSL(1); Component_unit(256); } first_color=last_color=block_start=block_end=Fore_color; Tag_color_range(block_start,block_end); // Affichage dans le block de visu de la couleur en cours Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H,Back_color); Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); // Affichage des valeurs de la couleur courante (pour 1 couleur) Display_sliders(red_slider,green_slider,blue_slider,(block_start!=block_end),working_palette); Print_in_window(7, 69, "Color number:", MC_Dark, MC_Light); Num2str(Fore_color, str, 3); Print_in_window(COLOR_X, COLOR_Y, str, MC_Black, MC_Light); Window_set_normal_button( 7,16,55,14,"Merge" ,0,1,SDLK_m); // 5 Window_set_normal_button( 63,16,36,14,"Gray" ,1,1,SDLK_g); // 6 Window_set_normal_button( 7,46,55,14,"Swap" ,0,1,KEY_NONE); // 7 Window_set_normal_button( 63,46,72,14,"X-Swap" ,1,1,SDLK_x); // 8 Window_set_normal_button(136,31,54,14,"Copy" ,1,1,SDLK_c); // 9 Window_set_normal_button(136,46,54,14,"Spread" ,4,1,SDLK_e); // 10 reduce_dropdown = Window_set_dropdown_button(209, 46, 83, 14, 84, "Reduce", 0, 0, 1, RIGHT_SIDE|LEFT_SIDE, 0); // 11 Window_dropdown_add_item(reduce_dropdown, 256, "to uniques"); Window_dropdown_add_item(reduce_dropdown, 128, "to 128"); Window_dropdown_add_item(reduce_dropdown, 64, "to 64"); Window_dropdown_add_item(reduce_dropdown, 32, "to 32"); Window_dropdown_add_item(reduce_dropdown, 16, "to 16"); Window_dropdown_add_item(reduce_dropdown, 8, "to 8"); Window_dropdown_add_item(reduce_dropdown, 4, "to 4"); Window_dropdown_add_item(reduce_dropdown, 2, "to 2"); Window_dropdown_add_item(reduce_dropdown, 0, "Other"); Window_set_normal_button( 6,168,35,14,"Undo" ,1,1,SDLK_u); // 12 Window_set_normal_button( 62,168,51,14,"Cancel",0,1,KEY_ESC); // 13 Window_set_normal_button(117,168,51,14,"OK" ,0,1,SDLK_RETURN); // 14 Window_set_normal_button(209,16,37,14,"Used",0,1,SDLK_d); // 15 Window_set_normal_button(209,31,83,14,"Zap unused",0,1,SDLK_DELETE);//16 Window_set_repeatable_button(BUTTON_PLUS_X, BUTTON_PLUS_Y,12,11,"+",0,1,SDLK_KP_PLUS); // 17 Window_set_repeatable_button(BUTTON_MINUS_X,BUTTON_MINUS_Y,12,11,"-",0,1,SDLK_KP_MINUS); // 18 Window_set_normal_button(100,16,35,14,"Neg" ,1,1,SDLK_n); // 19 Window_set_normal_button(7,31,55,14,"Invert" ,1,1,SDLK_i); // 20 Window_set_normal_button(63,31,72,14,"X-Invert" ,5,1,SDLK_v); // 21 // Button without outline Window_set_normal_button(175,66,81,11,"" ,0,1,SDLK_h); // 22 Window_display_frame_mono(175-1,66-1,81+2,11+2,MC_Light); sort_dropdown = Window_set_dropdown_button(136, 16, 54, 14, 80, " Sort", 0, 1, 1, RIGHT_SIDE|LEFT_SIDE, 0); // 23 Window_dropdown_add_item(sort_dropdown, 0, "Hue/Light"); Window_dropdown_add_item(sort_dropdown, 1, "Lightness"); Window_set_normal_button(NUMERIC_BOX_X,NUMERIC_BOX_Y,NUMERIC_BOX_W,NUMERIC_BOX_H,"" ,0,1,KEY_NONE); // 24 // Button without outline Window_display_frame_mono(NUMERIC_BOX_X-1,NUMERIC_BOX_Y-1,NUMERIC_BOX_W+2,NUMERIC_BOX_H+2,MC_Light); button_used = Window_set_normal_button(247,16,45,14,"Histo",0,1,KEY_NONE);// 25 // Dessin des petits effets spciaux pour les boutons [+] et [-] Draw_thingumajig(265, 74,MC_White,-1); Draw_thingumajig(282, 74,MC_White,+1); Draw_thingumajig(265,165,MC_Dark,-1); Draw_thingumajig(282,165,MC_Dark,+1); Display_cursor(); Update_color_count(&used_colors,color_usage); if (show_used_colors) Tag_used_colors(1, color_usage); Update_window_area(0,0,299,188); do { old_mouse_x=Mouse_X; old_mouse_y=Mouse_Y; old_mouse_k=Mouse_K; clicked_button=Window_clicked_button(); switch (clicked_button) { case 0 : // Nulle part break; case -1 : // Hors de la fentre case 1 : // palette if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) ) { Hide_cursor(); temp_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); if (Mouse_K==RIGHT_SIDE) { // Contextual menu T_Dropdown_button dropdown; T_Dropdown_choice *item; dropdown.Pos_X =0; dropdown.Pos_Y =0; dropdown.Height =0; dropdown.Dropdown_width=48; dropdown.First_item =NULL; dropdown.Bottom_up =1; Window_dropdown_add_item(&dropdown, 1, "Copy"); Window_dropdown_add_item(&dropdown, 2, "Paste"); item=Dropdown_activate(&dropdown,Mouse_X,Mouse_Y); if (item && item->Number == 1) { // Copy Set_clipboard_colors(block_end+1-block_start,working_palette + block_start); Display_cursor(); } else if (item && item->Number == 2) { // Paste int nb_colors; // Backup Palette_edit_step(); nb_colors = Get_clipboard_colors(working_palette, block_start); if (nb_colors>0) { memcpy(temp_palette,working_palette,sizeof(T_Palette)); Set_palette(working_palette); need_to_remap=1; Display_cursor(); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); } else { Display_cursor(); } } else if (Back_color!=temp_color) { // Just select back color Back_color=temp_color; // 4 blocks de back_color entourant la fore_color Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); Display_cursor(); } else { Display_cursor(); } Window_dropdown_clear_items(&dropdown); } else { if (!old_mouse_k) { // On vient de clicker sur une couleur (et une seule) if ( (Fore_color!=temp_color) || (block_start!=block_end) ) { // La couleur en question est nouvelle ou elle annule un // ancien bloc. Il faut donc slectionner cette couleur comme // unique couleur choisie. Fore_color=first_color=last_color=block_start=block_end=temp_color; Tag_color_range(block_start,block_end); // Affichage du n de la couleur slectionne Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); Num2str(Fore_color,str,3); Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); Update_window_area(COLOR_X,COLOR_Y,56,7); // Affichage des jauges Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light); Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Palette_edit_select_range(); } } else { // On maintient le click, on va donc tester si le curseur bouge if (temp_color!=last_color) { // On commence par ordonner la 1re et dernire couleur du bloc if (first_colortemp_color) { block_start=temp_color; block_end=first_color; // Affichage du n de la couleur slectionne Num2str(block_start,str ,3); Num2str(block_end ,str+4,3); str[3]=26; // Flche vers la droite Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage des jauges Display_sliders(red_slider,green_slider,blue_slider,1,NULL); // Affichage dans le block de visu du bloc (dgrad) en cours Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); } else { block_start=block_end=first_color; Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light); // Affichage du n de la couleur slectionne Window_rectangle(COLOR_X+24,COLOR_Y,32,7,MC_Light); Update_window_area(COLOR_X+24,COLOR_Y,32,7); Num2str(Fore_color,str,3); Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage des jauges Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); } // On tagge le bloc (ou la couleur) Tag_color_range(block_start,block_end); } last_color=temp_color; } Display_cursor(); } } break; case 2 : // Jauge rouge Hide_cursor(); Palette_edit_alter_channel(); if (block_start==block_end) { if(Palette_view_is_RGB) { Set_red(Fore_color,Reduce_component(Color_max-red_slider->Position),working_palette); Format_component((working_palette[Fore_color].R)*Color_count/256,str); } else { HSL_to_RGB( 255-red_slider->Position, 255-green_slider->Position, 255-blue_slider->Position, &working_palette[Fore_color].R, &working_palette[Fore_color].G, &working_palette[Fore_color].B); Format_component((int)255-red_slider->Position,str); } Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } else { if(Palette_view_is_RGB) { for (i=block_start; i<=block_end; i++) Set_red(i,temp_palette[i].R+Reduce_component(Color_max-red_slider->Position),working_palette); } else { byte greys=0; byte non_greys=0; // Check if the range contains both greys and non-greys for (i=block_start; i<=block_end; i++) if (temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B) non_greys=1; else greys=1; for (i=block_start; i<=block_end; i++) { byte is_grey = temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B; Set_HSL( temp_palette, working_palette, i, is_grey && greys && non_greys ? 0 : Color_max-red_slider->Position, is_grey && greys && non_greys ? 0 : Color_max-green_slider->Position, Color_max-blue_slider->Position ); } } if (red_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-red_slider->Position),str,4); str[0]='-'; } else if (red_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; Display_cursor(); Set_palette(working_palette); break; case 3 : // Jauge verte Hide_cursor(); Palette_edit_alter_channel(); if (block_start==block_end) { if(Palette_view_is_RGB) { Set_green (Fore_color,Reduce_component(Color_max-green_slider->Position),working_palette); Format_component(working_palette[Fore_color].G*Color_count/256,str); } else { HSL_to_RGB( 255-red_slider->Position, 255-green_slider->Position, 255-blue_slider->Position, &working_palette[Fore_color].R, &working_palette[Fore_color].G, &working_palette[Fore_color].B); Format_component((int)255-green_slider->Position,str); } Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } else { if(Palette_view_is_RGB) { for (i=block_start; i<=block_end; i++) Set_green (i,temp_palette[i].G+Reduce_component(Color_max-green_slider->Position),working_palette); } else { byte greys=0; byte non_greys=0; // Check if the range contains both greys and non-greys for (i=block_start; i<=block_end; i++) if (temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B) non_greys=1; else greys=1; for (i=block_start; i<=block_end; i++) { byte is_grey = temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B; Set_HSL( temp_palette, working_palette, i, is_grey && greys && non_greys ? 0 : Color_max-red_slider->Position, is_grey && greys && non_greys ? 0 : Color_max-green_slider->Position, Color_max-blue_slider->Position ); } } if (green_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-green_slider->Position),str,4); str[0]='-'; } else if (green_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; Display_cursor(); Set_palette(working_palette); break; case 4 : // Jauge bleue Hide_cursor(); Palette_edit_alter_channel(); if (block_start==block_end) { if(Palette_view_is_RGB) { Set_blue (Fore_color,Reduce_component(Color_max-blue_slider->Position),working_palette); Format_component(working_palette[Fore_color].B*Color_count/256,str); } else { HSL_to_RGB( 255-red_slider->Position, 255-green_slider->Position, 255-blue_slider->Position, &working_palette[Fore_color].R, &working_palette[Fore_color].G, &working_palette[Fore_color].B); Format_component((int)255-blue_slider->Position,str); } Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } else { if(Palette_view_is_RGB) { for (i=block_start; i<=block_end; i++) Set_blue(i,temp_palette[i].B+Reduce_component(Color_max-blue_slider->Position),working_palette); } else { byte greys=0; byte non_greys=0; // Check if the range contains both greys and non-greys for (i=block_start; i<=block_end; i++) if (temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B) non_greys=1; else greys=1; for (i=block_start; i<=block_end; i++) { byte is_grey = temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B; Set_HSL( temp_palette, working_palette, i, is_grey && greys && non_greys ? 0 : Color_max-red_slider->Position, is_grey && greys && non_greys ? 0 : Color_max-green_slider->Position, Color_max-blue_slider->Position ); } } if (blue_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-blue_slider->Position),str,4); str[0]='-'; } else if (blue_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; Display_cursor(); Set_palette(working_palette); break; case 5 : // Merge if (block_start!=block_end) { dword sum_r=0, sum_g=0, sum_b=0, used=0; Palette_edit_step(); // Compute weighted average for (i=block_start; i<=block_end; i++) { used+=color_usage[i]; sum_r+=working_palette[i].R * color_usage[i]; sum_g+=working_palette[i].G * color_usage[i]; sum_b+=working_palette[i].B * color_usage[i]; } // Do normal average if no pixels used if (used==0) { sum_r=sum_g=sum_b=used=0; for (i=block_start; i<=block_end; i++) { used+=1; sum_r+=working_palette[i].R; sum_g+=working_palette[i].G; sum_b+=working_palette[i].B; } } for (i=block_start; i<=block_end; i++) { Set_red (i,sum_r/used,working_palette); Set_green(i,sum_g/used,working_palette); Set_blue (i,sum_b/used,working_palette); } } else { temp_color=Wait_click_in_palette(Window_palette_button_list); if (temp_color>=0) { dword sum_r=0, sum_g=0, sum_b=0, used; Palette_edit_step(); // Compute weighted average used=color_usage[temp_color]+color_usage[Fore_color]; if (used) { sum_r=(working_palette[temp_color].R * color_usage[temp_color] + working_palette[Fore_color].R * color_usage[Fore_color]) / used; sum_g=(working_palette[temp_color].G * color_usage[temp_color] + working_palette[Fore_color].G * color_usage[Fore_color]) / used; sum_b=(working_palette[temp_color].B * color_usage[temp_color] + working_palette[Fore_color].B * color_usage[Fore_color]) / used; } else // Normal average { sum_r=(working_palette[temp_color].R+working_palette[Fore_color].R)/2; sum_g=(working_palette[temp_color].G+working_palette[Fore_color].G)/2; sum_b=(working_palette[temp_color].B+working_palette[Fore_color].B)/2; } Set_red (temp_color,sum_r,working_palette); Set_green(temp_color,sum_g,working_palette); Set_blue (temp_color,sum_b,working_palette); Set_red (Fore_color,sum_r,working_palette); Set_green(Fore_color,sum_g,working_palette); Set_blue (Fore_color,sum_b,working_palette); Wait_end_of_click(); } } Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); // On prpare la "modifiabilit" des nouvelles couleurs Set_palette(working_palette); memcpy(temp_palette,working_palette,sizeof(T_Palette)); need_to_remap=1; break; case 6 : // Grey scale // Backup Palette_edit_step(); // Grey Scale for (i=block_start;i<=block_end;i++) { temp_color=(dword)( ((dword)working_palette[i].R*30) + ((dword)working_palette[i].G*59) + ((dword)working_palette[i].B*11) )/100; Set_red(i,temp_color,working_palette); Set_green (i,temp_color,working_palette); Set_blue (i,temp_color,working_palette); } Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); // On prpare la "modifiabilit" des nouvelles couleurs Set_palette(working_palette); memcpy(temp_palette,working_palette,sizeof(T_Palette)); need_to_remap=1; break; case 7 : // Swap case 8 : // X-Swap temp_color=Wait_click_in_palette(Window_palette_button_list); if ((temp_color>=0) && (temp_color!=block_start)) { Hide_cursor(); Palette_edit_step();// Not undoable if X-Swap // On calcule le nombre de couleurs a swapper sans risquer de sortir // de la palette (La var. first_color est utilise pour conomiser 1 var; c'est tout) first_color=(temp_color+block_end-block_start<=255)?block_end+1-block_start:256-temp_color; if (clicked_button==8) // On ne fait de backup de l'image que si on // est en mode X-SWAP. if (!image_is_backed_up) { Backup_layers(-1); image_is_backed_up=1; } Swap(clicked_button==8,block_start,temp_color,first_color,working_palette,color_usage); memcpy(temp_palette,working_palette,sizeof(T_Palette)); // On dplace le bloc vers les modifs: last_color=block_end=temp_color+first_color-1; Fore_color=first_color=block_start=temp_color; // On raffiche le n des bornes du bloc: if (block_start!=block_end) { // Cas d'un bloc multi-couleur Num2str(block_start,str ,3); Num2str(block_end ,str+4,3); str[3]=26; // Flche vers la droite // Affichage dans le block de visu du bloc (dgrad) en cours Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); } else { // Cas d'une seule couleur Num2str(Fore_color,str,3); Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); } Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // On tag le bloc (ou la couleur) Tag_color_range(block_start,block_end); if (show_used_colors) Tag_used_colors(1, color_usage); need_to_remap=1; Set_palette(working_palette); Display_cursor(); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); // En cas de X-Swap, tout l'ecran a pu changer de couleur. if (clicked_button==8) { Update_rect(0, 0, Screen_width, Menu_Y_before_window); End_of_modification(); } Wait_end_of_click(); } break; case 9 : // Copy (to other slot) temp_color=Wait_click_in_palette(Window_palette_button_list); if ((temp_color>=0) && (temp_color!=block_start)) { Hide_cursor(); Palette_edit_step(); memcpy(working_palette+temp_color,backup_palette+block_start, ((temp_color+block_end-block_start<=255)?block_end+1-block_start:256-temp_color)*3); memcpy(temp_palette,working_palette,sizeof(T_Palette)); Set_palette(working_palette); // On dplace le bloc vers les modifs: last_color=block_end=((temp_color+block_end-block_start<=255)?(temp_color+block_end-block_start):255); Fore_color=first_color=block_start=temp_color; // On raffiche le n des bornes du bloc: if (block_start!=block_end) { // Cas d'un bloc multi-couleur Num2str(block_start,str ,3); Num2str(block_end ,str+4,3); str[3]=26; // Flche vers la droite // Affichage dans le block de visu du bloc (dgrad) en cours Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); } else { // Cas d'une seule couleur Num2str(Fore_color,str,3); Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); } Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // On tag le bloc (ou la couleur) Tag_color_range(block_start,block_end); need_to_remap=1; Display_cursor(); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Wait_end_of_click(); } break; case 10 : // Spread if (block_start!=block_end) { Palette_edit_step(); Spread_colors(block_start,block_end,working_palette); } else { temp_color=Wait_click_in_palette(Window_palette_button_list); if (temp_color>=0) { Palette_edit_step(); if (temp_color 256) break; // Cancel reduce_colors_number = choice; } else // Each other dropdown item has a number of colors as id. reduce_colors_number = Window_attribute2; if (reduce_colors_number >= 2) { if (!image_is_backed_up) { Backup_layers(-1); image_is_backed_up = 1; } Reduce_palette(&used_colors, reduce_colors_number, working_palette, color_usage); if ((Config.Safety_colors) && (used_colors<4)) { memcpy(temp_palette, Main_palette, sizeof(T_Palette)); memcpy(Main_palette, working_palette, sizeof(T_Palette)); Set_nice_menu_colors(color_usage, 0); memcpy(working_palette, Main_palette, sizeof(T_Palette)); memcpy(Main_palette, temp_palette, sizeof(T_Palette)); } Set_palette(working_palette); // On dfinit la nouvelle palette Draw_all_palette_sliders(red_slider, green_slider, blue_slider, working_palette, block_start, block_end); memcpy(temp_palette, working_palette, sizeof(T_Palette)); End_of_modification(); need_to_remap = 1; } break; case 12: // Undo Palette_edit_undo_redo(); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Set_palette(working_palette); need_to_remap=1; break; case 15 : // Used : show usage tags show_used_colors = !show_used_colors; Tag_used_colors(show_used_colors, color_usage); break; case 16 : // Zap unused Palette_edit_step(); if (used_colors==-1) Update_color_count(&used_colors,color_usage); for (i=0; i<256; i++) { if (!color_usage[i]) { temp_color=block_start+(i % (block_end+1-block_start)); working_palette[i].R=backup_palette[temp_color].R; working_palette[i].G=backup_palette[temp_color].G; working_palette[i].B=backup_palette[temp_color].B; } } if ((Config.Safety_colors) && (used_colors<4) && (block_end==block_start)) { memcpy(temp_palette,Main_palette,sizeof(T_Palette)); memcpy(Main_palette,working_palette,sizeof(T_Palette)); Set_nice_menu_colors(color_usage,0); memcpy(working_palette,Main_palette,sizeof(T_Palette)); memcpy(Main_palette,temp_palette,sizeof(T_Palette)); } Set_palette(working_palette); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); need_to_remap=1; break; case 17 : // [+] if (!Palette_view_is_RGB) break; Hide_cursor(); Palette_edit_alter_channel(); if (block_start==block_end) { if (red_slider->Position) { (red_slider->Position)--; Window_draw_slider(red_slider); Set_red(Fore_color,Reduce_component(Color_max-red_slider->Position),working_palette); Format_component(working_palette[Fore_color].R*Color_count/256,str); Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (green_slider->Position) { (green_slider->Position)--; Window_draw_slider(green_slider); Set_green (Fore_color,Reduce_component(Color_max-green_slider->Position),working_palette); Format_component(working_palette[Fore_color].G*Color_count/256,str); Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (blue_slider->Position) { (blue_slider->Position)--; Window_draw_slider(blue_slider); Set_blue (Fore_color,Reduce_component(Color_max-blue_slider->Position),working_palette); Format_component(working_palette[Fore_color].B*Color_count/256,str); Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } } else { if (red_slider->Position) { (red_slider->Position)--; Window_draw_slider(red_slider); } if (green_slider->Position) { (green_slider->Position)--; Window_draw_slider(green_slider); } if (blue_slider->Position) { (blue_slider->Position)--; Window_draw_slider(blue_slider); } for (i=block_start; i<=block_end; i++) { Set_red(i,temp_palette[i].R+Reduce_component(Color_max-red_slider->Position),working_palette); Set_green (i,temp_palette[i].G+Reduce_component(Color_max-green_slider->Position),working_palette); Set_blue (i,temp_palette[i].B+Reduce_component(Color_max-blue_slider->Position),working_palette); } // -- red -- if (red_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-red_slider->Position),str,4); str[0]='-'; } else if (red_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- green -- if (green_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-green_slider->Position),str,4); str[0]='-'; } else if (green_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- blue -- if (blue_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-blue_slider->Position),str,4); str[0]='-'; } else if (blue_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; Display_cursor(); Set_palette(working_palette); break; case 18 : // [-] if (!Palette_view_is_RGB) break; Hide_cursor(); Palette_edit_alter_channel(); if (block_start==block_end) { if (red_slider->PositionPosition)++; Window_draw_slider(red_slider); Set_red(Fore_color,Reduce_component(Color_max-red_slider->Position),working_palette); Format_component(working_palette[Fore_color].R*Color_count/256,str); Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (green_slider->PositionPosition)++; Window_draw_slider(green_slider); Set_green (Fore_color,Reduce_component(Color_max-green_slider->Position),working_palette); Format_component(working_palette[Fore_color].G*Color_count/256,str); Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (blue_slider->PositionPosition)++; Window_draw_slider(blue_slider); Set_blue (Fore_color,Reduce_component(Color_max-blue_slider->Position),working_palette); Format_component(working_palette[Fore_color].B*Color_count/256,str); Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } } else { if (red_slider->Position<(Color_max*2)) { (red_slider->Position)++; Window_draw_slider(red_slider); } if (green_slider->Position<(Color_max*2)) { (green_slider->Position)++; Window_draw_slider(green_slider); } if (blue_slider->Position<(Color_max*2)) { (blue_slider->Position)++; Window_draw_slider(blue_slider); } for (i=block_start; i<=block_end; i++) { Set_red(i,temp_palette[i].R+Reduce_component(Color_max-red_slider->Position),working_palette); Set_green (i,temp_palette[i].G+Reduce_component(Color_max-green_slider->Position),working_palette); Set_blue (i,temp_palette[i].B+Reduce_component(Color_max-blue_slider->Position),working_palette); } // -- red -- if (red_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-red_slider->Position),str,4); str[0]='-'; } else if (red_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- green -- if (green_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-green_slider->Position),str,4); str[0]='-'; } else if (green_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- blue -- if (blue_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-blue_slider->Position),str,4); str[0]='-'; } else if (blue_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; Display_cursor(); Set_palette(working_palette); break; case 19 : // Negative // Backup Palette_edit_step(); // Negative for (i=block_start;i<=block_end;i++) { Set_red(i,255-working_palette[i].R,working_palette); Set_green (i,255-working_palette[i].G,working_palette); Set_blue (i,255-working_palette[i].B,working_palette); } Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Set_palette(working_palette); // On prpare la "modifiabilit" des nouvelles couleurs memcpy(temp_palette,working_palette,sizeof(T_Palette)); need_to_remap=1; break; case 20 : // Inversion case 21 : // X-Inversion // Backup Palette_edit_step(); // Not undoable if X-Invert // On initialise la table de conversion for (i=0; i<=255; i++) conversion_table[i]=i; // Inversion for (i=block_start; i < block_start + (block_end-block_start+1)/2;i++) { temp_color=block_end-(i-block_start); Set_red (i,backup_palette[temp_color].R,working_palette); Set_green (i,backup_palette[temp_color].G,working_palette); Set_blue (i,backup_palette[temp_color].B,working_palette); Set_red (temp_color,backup_palette[i].R,working_palette); Set_green (temp_color,backup_palette[i].G,working_palette); Set_blue (temp_color,backup_palette[i].B,working_palette); if (clicked_button==21) { conversion_table[i]=temp_color; conversion_table[temp_color]=i; temp=color_usage[i]; color_usage[i]=color_usage[temp_color]; color_usage[temp_color]=temp; } } Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); // Si on est en X-Invert, on remap l'image (=> on fait aussi 1 backup) if (clicked_button==21) { if (!image_is_backed_up) { Backup_layers(-1); image_is_backed_up=1; } Hide_cursor(); Remap_image_highlevel(conversion_table); Display_cursor(); End_of_modification(); } // On prpare la "modifiabilit" des nouvelles couleurs Set_palette(working_palette); memcpy(temp_palette,working_palette,sizeof(T_Palette)); need_to_remap=1; break; case 22 : // HSL <> RGB // Acte les changements en cours sur une ou plusieurs couleurs Palette_edit_select_range(); Hide_cursor(); Palette_view_is_RGB = !Palette_view_is_RGB; if(! Palette_view_is_RGB) { // On passe en HSL Print_RGB_or_HSL(1); Component_unit(256); // Display the + and - button as disabled Window_draw_normal_bouton(BUTTON_PLUS_X, BUTTON_PLUS_Y,12,11,"+",0,0); Window_draw_normal_bouton(BUTTON_MINUS_X,BUTTON_MINUS_Y,12,11,"-",0,0); } else { // On passe en RGB Print_RGB_or_HSL(0); Component_unit(RGB_scale); // Display the + and - button as enabled Window_draw_normal_bouton(BUTTON_PLUS_X, BUTTON_PLUS_Y,12,11,"+",0,1); Window_draw_normal_bouton(BUTTON_MINUS_X,BUTTON_MINUS_Y,12,11,"-",0,1); } Display_sliders(red_slider,green_slider,blue_slider,(block_start!=block_end),working_palette); Display_cursor(); Update_window_area(BUTTON_PLUS_X-1,BUTTON_PLUS_Y-1,14,14); Update_window_area(BUTTON_MINUS_X-1,BUTTON_MINUS_Y-1,14,14); break; case 23 : // Sort palette { byte h = 0, l = 0, s=0; byte oh=0,ol=0,os=0; // Valeur pour la couleur prcdente int swap=1; byte remap_table[256]; byte inverted_table[256]; byte begin, end; long lightness; long old_lightness; if(block_start==block_end) { begin = 0; end = 255; } else { begin = block_start; end = block_end; } // Init remap table for (i=0;i<256;i++) remap_table[i]=i; // Make a backup because remapping is an undoable modification if (!image_is_backed_up) { Backup_layers(-1); image_is_backed_up=1; } if(Window_attribute2==0) // Sort by Hue (H) and Lightness (L) while(swap==1) { swap=0; h=0;l=255;s=0; for(temp_color=begin;temp_color<=end;temp_color++) { oh=h; ol=l; os=s; RGB_to_HSL(working_palette[temp_color].R, working_palette[temp_color].G, working_palette[temp_color].B,&h,&s,&l); if( ((s==0) && (os>0)) // A grey is before a saturated color || ((s>0 && os > 0) && (hol))) // 2 saturated colors: sort by H, then by L || ((os==0 && s==0) && l>ol)) // Two greys: sort by L only { // Swap color with the previous one SWAP_BYTES(working_palette[temp_color].R, working_palette[temp_color-1].R) SWAP_BYTES(working_palette[temp_color].G, working_palette[temp_color-1].G) SWAP_BYTES(working_palette[temp_color].B, working_palette[temp_color-1].B) SWAP_DWORDS(color_usage[temp_color], color_usage[temp_color-1]) SWAP_BYTES(remap_table[temp_color], remap_table[temp_color-1]) swap=1; } } } else // Sort only on perceived lightness while(swap==1) { swap=0; lightness=Perceptual_lightness(working_palette+begin); for(temp_color=begin+1;temp_color<=end;temp_color++) { old_lightness=lightness; lightness=Perceptual_lightness(working_palette+temp_color); if(lightness>old_lightness) { // Swap color with the previous one SWAP_BYTES(working_palette[temp_color].R, working_palette[temp_color-1].R) SWAP_BYTES(working_palette[temp_color].G, working_palette[temp_color-1].G) SWAP_BYTES(working_palette[temp_color].B, working_palette[temp_color-1].B) SWAP_DWORDS(color_usage[temp_color], color_usage[temp_color-1]) SWAP_BYTES(remap_table[temp_color], remap_table[temp_color-1]) swap=1; } } } for (i=0;i<256;i++) inverted_table[remap_table[i]]=i; Remap_image_highlevel(inverted_table); // Maintenant, tous ces calculs doivent tres pris en compte dans la // palette, l'image et l'cran. Set_palette(working_palette); End_of_modification(); need_to_remap=1; } break; case 24: // R G B value: Hex entry { char str[7]; unsigned int new_color; Hide_cursor(); Print_in_window(NUMERIC_BOX_X+2,NUMERIC_BOX_Y+2,"Hex",MC_Black,MC_Light); // Clear out remaining area Window_rectangle(NUMERIC_BOX_X+1+3*8,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-3-3*8, NUMERIC_BOX_H-3,MC_Light); Update_window_area(NUMERIC_BOX_X+1+3*8,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-3-3*8, NUMERIC_BOX_H-3); str[0]='\0'; Display_cursor(); if (Readline(NUMERIC_BOX_X+NUMERIC_BOX_W-2-6*8, NUMERIC_BOX_Y+2, str, 6, INPUT_TYPE_HEXA)) { int length = strlen(str); short new_red, new_blue, new_green; if (length==3 || length==6) { sscanf(str, "%x", &new_color); if (length==3) { new_color = ((new_color&0xF00)*0x1100) | ((new_color&0x0F0)*0x110) | ((new_color&0x00F)*0x11); } new_red=(new_color&0xFF0000) >> 16; new_green=(new_color&0x00FF00) >> 8; new_blue=(new_color&0x0000FF); // Backup Palette_edit_step(); // Assign color for (i=block_start;i<=block_end;i++) { Set_red(i,new_red,working_palette); Set_green (i,new_green,working_palette); Set_blue (i,new_blue,working_palette); } // On prpare la "modifiabilit" des nouvelles couleurs Set_palette(working_palette); memcpy(temp_palette,working_palette,sizeof(T_Palette)); need_to_remap=1; } } // Clear out numeric area Window_rectangle(NUMERIC_BOX_X+1,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-2, NUMERIC_BOX_H-2,MC_Light); Update_window_area(NUMERIC_BOX_X+1,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-2, NUMERIC_BOX_H-2); Display_cursor(); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); } break; case 25: // Number of colors used: Open histogram { int selected_col; selected_col=Window_Histogram(block_start, block_end, color_usage); if (selected_col!=-1) { // Tag selected color Fore_color=first_color=last_color=block_start=block_end=selected_col; Tag_color_range(block_start,block_end); // Affichage du n de la couleur slectionne Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); Num2str(Fore_color,str,3); Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); Update_window_area(COLOR_X,COLOR_Y,56,7); // Affichage des jauges Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light); Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Palette_edit_select_range(); } Display_cursor(); Input_sticky_control=0; Wait_end_of_click(); break; } } if (!Mouse_K) { if (Key) { if (Is_shortcut(Key,SPECIAL_PREVIOUS_FORECOLOR)) // Dcaler Forecolor vers la gauche { if (block_start==block_end) { Fore_color--; first_color--; last_color--; block_start--; block_end--; Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Hide_cursor(); Tag_color_range(block_start,block_end); // Affichage du n de la couleur slectionne Num2str(Fore_color,str,3); Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Display_cursor(); } Key=0; } else if (Is_shortcut(Key,SPECIAL_NEXT_FORECOLOR)) // Dcaler Forecolor vers la droite { if (block_start==block_end) { Fore_color++; first_color++; last_color++; block_start++; block_end++; Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Hide_cursor(); Tag_color_range(block_start,block_end); // Affichage du n de la couleur slectionne Num2str(Fore_color,str,3); Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Display_cursor(); } Key=0; } else if (Is_shortcut(Key,SPECIAL_PREVIOUS_BACKCOLOR)) { Back_color--; Hide_cursor(); Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); Display_cursor(); Key=0; } else if (Is_shortcut(Key,SPECIAL_NEXT_BACKCOLOR)) { Back_color++; Hide_cursor(); Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); Display_cursor(); Key=0; } else if (Key == SDLK_BACKSPACE) // Remise des couleurs du menu l'tat normal en essayant // de ne pas trop modifier l'image. { if (!image_is_backed_up) { Backup_layers(-1); image_is_backed_up=1; } if (used_colors==-1) Update_color_count(&used_colors, color_usage); Palette_edit_step(); memcpy(temp_palette,Main_palette,sizeof(T_Palette)); memcpy(Main_palette,working_palette,sizeof(T_Palette)); Set_nice_menu_colors(color_usage,0); memcpy(working_palette,Main_palette,sizeof(T_Palette)); memcpy(Main_palette,temp_palette,sizeof(T_Palette)); Set_palette(working_palette); memcpy(temp_palette,working_palette,sizeof(T_Palette)); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Update_color_count(&used_colors,color_usage); // End_of_modification(); // Not really needed, the change was in palette entries need_to_remap=1; Key=0; } else if (Is_shortcut(Key,0x100+BUTTON_COLORPICKER)) { // Rcupration d'une couleur derrire le menu Get_color_behind_window(&color,&click); if (click) { Hide_cursor(); if (click==RIGHT_SIDE) { if (Back_color!=color) { Back_color=color; // 4 blocks de back_color entourant la fore_color Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); } } else { Fore_color=first_color=last_color=block_start=block_end=color; Tag_color_range(block_start,block_end); // Affichage du n de la couleur slectionne Window_rectangle(COLOR_X+24,COLOR_Y,32,7,MC_Light); Update_window_area(COLOR_X+24,COLOR_Y,32,7); Num2str(Fore_color,str,3); Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage des jauges Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Palette_edit_select_range(); } Display_cursor(); Wait_end_of_click(); } Key=0; } else if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Key=0; Window_help(BUTTON_PALETTE, NULL); } else if (Is_shortcut(Key,0x100+BUTTON_PALETTE)) { // Close (confirm) clicked_button=14; } else if (Key == (SDLK_c|MOD_CTRL)) // Ctrl-C { Set_clipboard_colors(block_end+1-block_start,working_palette + block_start); } else if (Key == (SDLK_v|MOD_CTRL)) // Ctrl-V { int nb_colors; Hide_cursor(); // Backup Palette_edit_step(); nb_colors = Get_clipboard_colors(working_palette, block_start); if (nb_colors>0) { memcpy(temp_palette,working_palette,sizeof(T_Palette)); Set_palette(working_palette); need_to_remap=1; Display_cursor(); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); } } } if (need_to_remap) { Hide_cursor(); Compute_optimal_menu_colors(working_palette); // On remappe brutalement Remap_screen_after_menu_colors_change(); // Puis on remet les trucs qui ne devaient pas changer Window_draw_palette_bouton(5,79); if (show_used_colors) Tag_used_colors(1, color_usage); Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H,Back_color); Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); Update_window_area(8,82,16*10,5*16); Display_cursor(); need_to_remap=0; } } } while ((clicked_button!=13) && (clicked_button!=14)); if (clicked_button==14) // Sortie par OK { if ( (!image_is_backed_up) && memcmp(Main_palette,working_palette,sizeof(T_Palette)) ) Backup_layers(-1); memcpy(Main_palette,working_palette,sizeof(T_Palette)); End_of_modification(); // Not really needed, the change was in palette entries } Compute_optimal_menu_colors(Main_palette); // La variable employe ici n'a pas vraiment de rapport avec son nom... need_to_remap=(Window_pos_Y+(Window_height*Menu_factor_Y)Position = rgb_scale_slider->Position>128?rgb_scale_slider->Position*2-256:0; Num2str(256-rgb_scale_slider->Position,str,3); Print_in_window(157,78,str,MC_Black,MC_Light); Window_draw_slider(rgb_scale_slider); break; case 10: // /2 RGB scale rgb_scale_slider->Position = rgb_scale_slider->Position>253?254:(rgb_scale_slider->Position)/2+128; Num2str(256-rgb_scale_slider->Position,str,3); Print_in_window(157,78,str,MC_Black,MC_Light); Window_draw_slider(rgb_scale_slider); } } while (clicked_button!=1 && clicked_button!=2 && clicked_button!=3 && clicked_button!=4); // We need to get the sliders positions before closing the window, because they will be freed. palette_cols=256-columns_slider->Position; palette_lines=16-lines_slider->Position; rgb_scale=256-rgb_scale_slider->Position; Close_window(); Unselect_button(BUTTON_PALETTE); Display_cursor(); if (clicked_button==4) // Cancel return; if (palette_vertical != Config.Palette_vertical) { Config.Palette_vertical=palette_vertical; palette_needs_redraw=1; } if (palette_cols!=Config.Palette_cells_X || palette_lines!=Config.Palette_cells_Y) { Config.Palette_cells_X = palette_cols; Config.Palette_cells_Y = palette_lines; palette_needs_redraw=1; } if (rgb_scale!=RGB_scale) { Set_palette_RGB_scale(rgb_scale); Set_palette(Main_palette); Compute_optimal_menu_colors(Main_palette); } if (clicked_button==1) { Menu_tag_colors("Tag colors to exclude",Exclude_color,&dummy,1, NULL, SPECIAL_EXCLUDE_COLORS_MENU); } else if (clicked_button==2) { // Open the menu with Shade settings. Same as the shortcut, except // that this will not activate shade mode on exit. Shade_settings_menu(); } if (palette_needs_redraw) { Change_palette_cells(); Display_menu(); Display_sprite_in_menu(BUTTON_PAL_LEFT,Config.Palette_vertical?MENU_SPRITE_VERTICAL_PALETTE_SCROLL:-1); Draw_menu_button(BUTTON_PAL_LEFT,BUTTON_RELEASED); Draw_menu_button(BUTTON_PAL_RIGHT,BUTTON_RELEASED); } } // ========= Clipboard management ============== int Palette_clipboard_count=0; T_Palette Palette_clipboard; /// Put some colors in the clipboard. /// @param nb_colors Number of colors to push /// @param colors First color of the input array void Set_clipboard_colors(int nb_colors, T_Components *colors) { Palette_clipboard_count=nb_colors; if (nb_colors) { memcpy(Palette_clipboard, colors, nb_colors*sizeof(T_Components)); } } /// Get some RGB colors from clipboard. /// @param palette Target palette /// @param start_color Index of first color to replace /// @return Number of colors retrieved (0-256) int Get_clipboard_colors(T_Palette palette, byte start_color) { int nb_colors = Palette_clipboard_count; if (nb_colors==0) return 0; if (start_color+nb_colors > 256) { nb_colors=256-start_color; } memcpy(palette+start_color, Palette_clipboard, nb_colors*sizeof(T_Components)); return nb_colors; } /// Get the favorite color to use for GUI's black,dark,light or white. const T_Components * Favorite_GUI_color(byte color_index) { static const T_Components cpc_colors[4] = { { 0, 0, 0}, { 0, 0,128}, // Dark blue {128,128,128}, // Grey {255,255,255} }; if (RGB_scale==3) { // Check if ALL GUI colors are compatible with /rgb 3 int i; for (i=0; i<4; i++) { T_Components col; col=Gfx->Default_palette[Gfx->Color[i]]; if ((col.R!=255 && col.R!=128 && col.R!=0) ||(col.G!=255 && col.G!=128 && col.G!=0) ||(col.B!=255 && col.B!=128 && col.B!=0)) // Specialized colors for CPC palette return &cpc_colors[color_index]; } // Skin has suitable colors return &(Gfx->Default_palette[Gfx->Color[color_index]]); } else // Should be Config.Fav_menu_colors[index] if using user colors return &(Gfx->Default_palette[Gfx->Color[color_index]]); } grafx2/src/pversion.c0000644000076400010400000000003711547421574015244 0ustar vigAdministratorchar Program_version[]="2.3"; grafx2/src/pxdouble.c0000644000076400010400000003467511343525204015225 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ #include #include #include #include "global.h" #include "sdlscreen.h" #include "misc.h" #include "graph.h" #include "pxdouble.h" #include "pxwide.h" // for Display_transparent_line_on_screen_wide() #define ZOOMX 2 #define ZOOMY 2 #ifdef __VBCC__ #define __attribute__(x) #endif void Pixel_double (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; } byte Read_pixel_double (word x,word y) /* On retourne la couleur du pixel aux coords donnes */ { 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 donne */ { 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_double (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 dpart 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 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_double (word x,word y,byte color) /* Affichage d'un pixel dans l'cran, par rapport au dcalage de l'image * dans l'cran, en mode normal (pas en mode loupe) * Note: si on modifie cette procdure, il faudra penser faire galement * la modif dans la procdure Pixel_Preview_Loupe_SDL. */ { // if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) Pixel_double(x-Main_offset_X,y-Main_offset_Y,color); } void Pixel_preview_magnifier_double (word x,word y,byte color) { // Affiche le pixel dans la partie non zoome Pixel_double(x-Main_offset_X,y-Main_offset_Y,color); // Regarde si on doit aussi l'afficher dans la partie zoome 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 = Main_magnifier_factor * (y-Main_magnifier_offset_Y); if (Menu_Y - y_zoom < Main_magnifier_factor) // On ne doit dessiner qu'un morceau du pixel // sinon on dpasse sur le menu height = Menu_Y - y_zoom; else height = Main_magnifier_factor; Block_double( Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, y_zoom, Main_magnifier_factor, height, 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*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; int x; for (x=0;x0;i--) { *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 * 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 vrifie que ce n'est pas la transparence if(*src != transp_color) { *(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_double(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+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_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*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 dpart 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+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_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 * 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 vrifie que ce n'est pas la transparence if(*src != transp_color) { *(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_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 * 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+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_double(word x_pos,word y_pos,word width,byte * line) /* On affiche toute une ligne de pixels telle quelle. */ /* Utilise si le buffer contient dja des pixel doubls. */ { 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) /* 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+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=*line; dest+=ZOOMX; line++; } } void Display_transparent_mono_line_on_screen_double( 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 zoome void Display_brush_color_zoom_double(word x_pos,word y_pos, word x_offset,word y_offset, word width, // width non zoome word end_y_pos,byte transp_color, word brush_width, // width relle 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 zoome for(bx=Main_magnifier_factor;bx>0;bx--) { 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) { return; } } src += brush_width; } // ATTENTION zone jamais atteinte } void Display_brush_mono_zoom_double(word x_pos, word y_pos, word x_offset, word y_offset, word width, // width non zoome word end_y_pos, byte transp_color, byte color, word brush_width, // width relle 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 conscutives) bx = Main_magnifier_factor*ZOOMY; // Pour chaque ligne cran do { // On affiche la ligne zoome Display_transparent_mono_line_on_screen_double( x_pos, y, width * Main_magnifier_factor, buffer, transp_color, color ); // On passe la ligne suivante y++; // On vrifie qu'on est pas la ligne finale if(y == end_y_pos*ZOOMY) { Redraw_grid( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); 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_double(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 zoome dans la partie zoome ! 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{ Display_line_on_screen_fast_double(x_pos,y, width * Main_magnifier_factor,buffer); // Ligne suivante y++; if(y==end_y_pos) { Redraw_grid(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-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; } } grafx2/src/pxquad.c0000644000076400010400000004531711343525204014700 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ #include #include #include #include "global.h" #include "sdlscreen.h" #include "misc.h" #include "graph.h" #include "pxquad.h" #define ZOOMX 4 #define ZOOMY 4 #ifdef __VBCC__ #define __attribute__(x) #endif 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 donnes */ { 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 donne */ { 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 dpart 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 dcalage de l'image * dans l'cran, en mode normal (pas en mode loupe) * Note: si on modifie cette procdure, il faudra penser faire galement * la modif dans la procdure 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 zoome Pixel_quad(x-Main_offset_X,y-Main_offset_Y,color); // Regarde si on doit aussi l'afficher dans la partie zoome 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 = Main_magnifier_factor * (y-Main_magnifier_offset_Y); if (Menu_Y - y_zoom < Main_magnifier_factor) // On ne doit dessiner qu'un morceau du pixel // sinon on dpasse sur le menu height = Menu_Y - y_zoom; else height = Main_magnifier_factor; Block_quad( Main_magnifier_factor * (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 vrifie 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 dpart 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 vrifie 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. */ /* Utilise si le buffer contient dja des pixel doubls. */ { 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 zoome void Display_brush_color_zoom_quad(word x_pos,word y_pos, word x_offset,word y_offset, word width, // width non zoome word end_y_pos,byte transp_color, word brush_width, // width relle 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 zoome 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 zoome word end_y_pos, byte transp_color, byte color, word brush_width, // width relle 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 conscutives) bx = Main_magnifier_factor*ZOOMY; // Pour chaque ligne cran do { // On affiche la ligne zoome 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 vrifie qu'on est pas la ligne finale if(y == end_y_pos*ZOOMY) { Redraw_grid( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); 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 zoome dans la partie zoome ! 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) { Redraw_grid(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-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; } } grafx2/src/pxsimple.c0000644000076400010400000003133311343525206015232 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ #include #include #include #include "global.h" #include "sdlscreen.h" #include "misc.h" #include "graph.h" #include "pxsimple.h" #ifdef __VBCC__ #define __attribute__(x) #endif 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 * VIDEO_LINE_WIDTH)=color; } byte Read_pixel_simple (word x,word y) /* On retourne la couleur du pixel aux coords donnes */ { return *( Screen_pixels + y * VIDEO_LINE_WIDTH + x ); } void Block_simple (word start_x,word start_y,word width,word height,byte color) /* On affiche un rectangle de la couleur donne */ { SDL_Rect rectangle; rectangle.x=start_x; rectangle.y=start_y; rectangle.w=width; rectangle.h=height; SDL_FillRect(Screen_SDL,&rectangle,color); } void Display_part_of_screen_simple (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 dpart ds la source (src) int y; for(y=height;y!=0;y--) // Pour chaque ligne { // On fait une copie de la ligne memcpy(dest,src,width); // On passe la ligne suivante src+=image_width; dest+=VIDEO_LINE_WIDTH; } //Update_rect(0,0,width,height); } void Pixel_preview_normal_simple (word x,word y,byte color) /* Affichage d'un pixel dans l'cran, par rapport au dcalage de l'image * dans l'cran, en mode normal (pas en mode loupe) * Note: si on modifie cette procdure, il faudra penser faire galement * la modif dans la procdure Pixel_Preview_Loupe_SDL. */ { // if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) Pixel_simple(x-Main_offset_X,y-Main_offset_Y,color); } void Pixel_preview_magnifier_simple (word x,word y,byte color) { // Affiche le pixel dans la partie non zoome Pixel_simple(x-Main_offset_X,y-Main_offset_Y,color); // Regarde si on doit aussi l'afficher dans la partie zoome 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 = Main_magnifier_factor * (y-Main_magnifier_offset_Y); if (Menu_Y - y_zoom < Main_magnifier_factor) // On ne doit dessiner qu'un morceau du pixel // sinon on dpasse sur le menu height = Menu_Y - y_zoom; else height = Main_magnifier_factor; Block_simple( Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, y_zoom, Main_magnifier_factor, height, 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*VIDEO_LINE_WIDTH+x_pos+Screen_pixels; int x; for (x=0;x 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *dest = *src; } // Pixel suivant src++; dest++; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH - width; src = src + brush_width - width; } Update_rect(x_pos,y_pos,width,height); } void Display_brush_mono_simple(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*VIDEO_LINE_WIDTH+x_pos+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=color; // On passe au pixel suivant src++; dest++; } // On passe la ligne suivante src+=brush_width-width; dest+=VIDEO_LINE_WIDTH-width; } Update_rect(x_pos,y_pos,width,height); } void Clear_brush_simple(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+y_pos*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 dpart ds la source (src) int y; for(y=height;y!=0;y--) // Pour chaque ligne { // On fait une copie de la ligne memcpy(dest,src,width); // On passe la ligne suivante src+=image_width; dest+=VIDEO_LINE_WIDTH; } Update_rect(x_pos,y_pos,width,height); } // Affiche une brosse (arbitraire) l'cran void Display_brush_simple(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 * VIDEO_LINE_WIDTH + x_pos; // 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 vrifie que ce n'est pas la transparence if(*src != transp_color) { *dest = *src; } // Pixel suivant src++; dest++; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH - width; src = src + brush_width - width; } } void Remap_screen_simple(word x_pos,word y_pos,word width,word height,byte * conversion_table) { // dest = coords a l'cran byte* dest = Screen_pixels + y_pos * VIDEO_LINE_WIDTH + x_pos; int x,y; // Pour chaque ligne for(y=height;y>0;y--) { // Pour chaque pixel for(x=width;x>0;x--) { *dest = conversion_table[*dest]; dest ++; } dest = dest + VIDEO_LINE_WIDTH - width; } Update_rect(x_pos,y_pos,width,height); } void Display_line_on_screen_simple(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*VIDEO_LINE_WIDTH,line,width); } void Display_transparent_mono_line_on_screen_simple( 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; int x; // Pour chaque pixel for(x=0;x 0); src += image_width; } // ATTENTION on n'arrive jamais ici ! } void Display_transparent_line_on_screen_simple(word x_pos,word y_pos,word width,byte* line,byte transp_color) { byte* src = line; byte* dest = Screen_pixels + y_pos * VIDEO_LINE_WIDTH + x_pos; word x; // Pour chaque pixel de la ligne for(x = width;x > 0;x--) { if(*src!=transp_color) *dest = *src; src++; dest++; } } // Affiche une partie de la brosse couleur zoome void Display_brush_color_zoom_simple(word x_pos,word y_pos, word x_offset,word y_offset, word width, // width non zoome word end_y_pos,byte transp_color, word brush_width, // width relle 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 zoome for(bx=Main_magnifier_factor;bx>0;bx--) { Display_transparent_line_on_screen_simple(x_pos,y,width*Main_magnifier_factor,buffer,transp_color); y++; if(y==end_y_pos) { return; } } src += brush_width; } // ATTENTION zone jamais atteinte } void Display_brush_mono_zoom_simple(word x_pos, word y_pos, word x_offset, word y_offset, word width, // width non zoome word end_y_pos, byte transp_color, byte color, word brush_width, // width relle de la brosse byte * buffer ) { byte* src = Brush + y_offset * brush_width + x_offset; int y=y_pos; //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 conscutives) bx = Main_magnifier_factor; // Pour chaque ligne cran do { // On affiche la ligne zoome Display_transparent_mono_line_on_screen_simple( x_pos, y, width * Main_magnifier_factor, buffer, transp_color, color ); // On passe la ligne suivante y++; // On vrifie qu'on est pas la ligne finale if(y == end_y_pos) { Redraw_grid( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); 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_simple(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 zoome dans la partie zoome ! 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,width); bx=Main_magnifier_factor; // Pour chaque ligne do{ Display_line_on_screen_simple(x_pos,y, width * Main_magnifier_factor,buffer); // Ligne suivante y++; if(y==end_y_pos) { Redraw_grid(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-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; } } grafx2/src/pxtall.c0000644000076400010400000003126111343525206014675 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ #include #include #include #include "global.h" #include "sdlscreen.h" #include "misc.h" #include "graph.h" #include "pxtall.h" #include "pxsimple.h" #define ZOOMX 1 #define ZOOMY 2 #ifdef __VBCC__ #define __attribute__(x) #endif void Pixel_tall (word x,word y,byte color) /* Affiche un pixel de la color aux coords x;y l'cran */ { *(Screen_pixels + x + y*ZOOMY*VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x + (y*ZOOMY+1)*VIDEO_LINE_WIDTH)=color; } byte Read_pixel_tall (word x,word y) /* On retourne la couleur du pixel aux coords donnes */ { return *( Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x ); } void Block_tall (word start_x,word start_y,word width,word height,byte color) /* On affiche un rectangle de la couleur donne */ { SDL_Rect rectangle; rectangle.x=start_x; rectangle.y=start_y*ZOOMY; rectangle.w=width; rectangle.h=height*ZOOMY; SDL_FillRect(Screen_SDL,&rectangle,color); } void Display_part_of_screen_tall (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 dpart ds la source (src) int y; for(y=height;y!=0;y--) // Pour chaque ligne { // On fait une copie de la ligne memcpy(dest,src,width); dest+=VIDEO_LINE_WIDTH; memcpy(dest,src,width); // On passe la ligne suivante src+=image_width; dest+=VIDEO_LINE_WIDTH; } //Update_rect(0,0,width,height); } void Pixel_preview_normal_tall (word x,word y,byte color) /* Affichage d'un pixel dans l'cran, par rapport au dcalage de l'image * dans l'cran, en mode normal (pas en mode loupe) * Note: si on modifie cette procdure, il faudra penser faire galement * la modif dans la procdure Pixel_Preview_Loupe_SDL. */ { // if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) Pixel_tall(x-Main_offset_X,y-Main_offset_Y,color); } void Pixel_preview_magnifier_tall (word x,word y,byte color) { // Affiche le pixel dans la partie non zoome Pixel_tall(x-Main_offset_X,y-Main_offset_Y,color); // Regarde si on doit aussi l'afficher dans la partie zoome 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 = Main_magnifier_factor * (y-Main_magnifier_offset_Y); if (Menu_Y - y_zoom < Main_magnifier_factor) // On ne doit dessiner qu'un morceau du pixel // sinon on dpasse sur le menu height = Menu_Y - y_zoom; else height = Main_magnifier_factor; Block_tall( Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, y_zoom, Main_magnifier_factor, height, color ); } } void Horizontal_XOR_line_tall(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+Screen_pixels; int x; for (x=0;x 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *dest = *src; *(dest+VIDEO_LINE_WIDTH) = *src; } // Pixel suivant src++; dest++; } // On passe la ligne suivante dest = dest + ZOOMY*VIDEO_LINE_WIDTH - width; src = src + brush_width - width; } Update_rect(x_pos,y_pos,width,height); } void Display_brush_mono_tall(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+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=color; *(dest+VIDEO_LINE_WIDTH)=color; } // On passe au pixel suivant src++; dest++; } // On passe la ligne suivante src+=brush_width-width; dest+=ZOOMY*VIDEO_LINE_WIDTH-width; } Update_rect(x_pos,y_pos,width,height); } void Clear_brush_tall(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+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 dpart ds la source (src) int y; for(y=height;y!=0;y--) // Pour chaque ligne { // On fait une copie de la ligne memcpy(dest,src,width); dest+=VIDEO_LINE_WIDTH; memcpy(dest,src,width); // On passe la ligne suivante src+=image_width; dest+=VIDEO_LINE_WIDTH; } Update_rect(x_pos,y_pos,width,height); } // Affiche une brosse (arbitraire) l'cran void Display_brush_tall(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; // 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 vrifie que ce n'est pas la transparence if(*src != transp_color) { *dest = *src; *(dest+VIDEO_LINE_WIDTH) = *src; } // Pixel suivant src++; dest++; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width; src = src + brush_width - width; } } void Remap_screen_tall(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; int x,y; // Pour chaque ligne for(y=height*ZOOMY;y>0;y--) { // Pour chaque pixel for(x=width;x>0;x--) { *dest = conversion_table[*dest]; dest ++; } dest = dest + VIDEO_LINE_WIDTH - width; } Update_rect(x_pos,y_pos,width,height); } 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*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,VIDEO_LINE_WIDTH*ZOOMY*y_pos + x_pos + Screen_pixels,width); } void Display_part_of_screen_scaled_tall( word width, // width non zoome word height, // height zoome word image_width,byte * buffer) { byte* src = Main_screen + Main_magnifier_offset_Y * image_width + Main_magnifier_offset_X; int y = 0; // Ligne en cours de traitement // Pour chaque ligne zoomer while(1) { int x; // On clate la ligne Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On l'affiche Facteur fois, sur des lignes conscutives x = Main_magnifier_factor*ZOOMY; // Pour chaque ligne do{ // On affiche la ligne zoome Display_line_on_screen_simple( Main_X_zoom, y, width*Main_magnifier_factor, buffer ); // On passe la suivante y++; if(y==height*ZOOMY) { Redraw_grid(Main_X_zoom,0, width*Main_magnifier_factor,height); Update_rect(Main_X_zoom,0, width*Main_magnifier_factor,height); return; } x--; }while (x > 0); src += image_width; } // ATTENTION on n'arrive jamais ici ! } // Affiche une partie de la brosse couleur zoome void Display_brush_color_zoom_tall(word x_pos,word y_pos, word x_offset,word y_offset, word width, // width non zoome word end_y_pos,byte transp_color, word brush_width, // width relle 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 zoome for(bx=Main_magnifier_factor;bx>0;bx--) { 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) { return; } } src += brush_width; } // ATTENTION zone jamais atteinte } void Display_brush_mono_zoom_tall(word x_pos, word y_pos, word x_offset, word y_offset, word width, // width non zoome word end_y_pos, byte transp_color, byte color, word brush_width, // width relle 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 conscutives) bx = Main_magnifier_factor*ZOOMY; // Pour chaque ligne cran do { // On affiche la ligne zoome Display_transparent_mono_line_on_screen_simple( x_pos, y, width * Main_magnifier_factor, buffer, transp_color, color ); // On passe la ligne suivante y++; // On vrifie qu'on est pas la ligne finale if(y == end_y_pos*ZOOMY) { Redraw_grid( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); 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_tall(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 zoome dans la partie zoome ! 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,width); bx=Main_magnifier_factor; // Pour chaque ligne do{ Display_line_on_screen_tall(x_pos,y, width * Main_magnifier_factor,buffer); // Ligne suivante y++; if(y==end_y_pos) { Redraw_grid(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-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; } } grafx2/src/pxtall2.c0000644000076400010400000004113111343525210014747 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ #include #include #include #include "global.h" #include "sdlscreen.h" #include "misc.h" #include "graph.h" #include "pxtall2.h" #define ZOOMX 2 #define ZOOMY 4 #ifdef __VBCC__ #define __attribute__(x) #endif 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 donnes */ { 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 donne */ { 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 dpart 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 dcalage de l'image * dans l'cran, en mode normal (pas en mode loupe) * Note: si on modifie cette procdure, il faudra penser faire galement * la modif dans la procdure 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 zoome Pixel_tall2(x-Main_offset_X,y-Main_offset_Y,color); // Regarde si on doit aussi l'afficher dans la partie zoome 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 = Main_magnifier_factor * (y-Main_magnifier_offset_Y); if (Menu_Y - y_zoom < Main_magnifier_factor) // On ne doit dessiner qu'un morceau du pixel // sinon on dpasse sur le menu height = Menu_Y - y_zoom; else height = Main_magnifier_factor; Block_tall2( Main_magnifier_factor * (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 vrifie 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 dpart 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 vrifie 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. */ /* Utilise si le buffer contient dja des pixel doubls. */ { 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 zoome void Display_brush_color_zoom_tall2(word x_pos,word y_pos, word x_offset,word y_offset, word width, // width non zoome word end_y_pos,byte transp_color, word brush_width, // width relle 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 zoome 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 zoome word end_y_pos, byte transp_color, byte color, word brush_width, // width relle 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 conscutives) bx = Main_magnifier_factor*ZOOMY; // Pour chaque ligne cran do { // On affiche la ligne zoome 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 vrifie qu'on est pas la ligne finale if(y == end_y_pos*ZOOMY) { Redraw_grid( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); 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 zoome dans la partie zoome ! 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) { Redraw_grid(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-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; } } grafx2/src/pxtriple.c0000644000076400010400000004065311343525210015240 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ #include #include #include #include "global.h" #include "sdlscreen.h" #include "misc.h" #include "graph.h" #include "pxtriple.h" #define ZOOMX 3 #define ZOOMY 3 #ifdef __VBCC__ #define __attribute__(x) #endif 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 donnes */ { 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 donne */ { 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 dpart 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 dcalage de l'image * dans l'cran, en mode normal (pas en mode loupe) * Note: si on modifie cette procdure, il faudra penser faire galement * la modif dans la procdure 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 zoome Pixel_triple(x-Main_offset_X,y-Main_offset_Y,color); // Regarde si on doit aussi l'afficher dans la partie zoome 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 = Main_magnifier_factor * (y-Main_magnifier_offset_Y); if (Menu_Y - y_zoom < Main_magnifier_factor) // On ne doit dessiner qu'un morceau du pixel // sinon on dpasse sur le menu height = Menu_Y - y_zoom; else height = Main_magnifier_factor; Block_triple( Main_magnifier_factor * (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 vrifie 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 dpart 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 vrifie 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. */ /* Utilise si le buffer contient dja des pixel doubls. */ { 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 zoome void Display_brush_color_zoom_triple(word x_pos,word y_pos, word x_offset,word y_offset, word width, // width non zoome word end_y_pos,byte transp_color, word brush_width, // width relle 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 zoome 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 zoome word end_y_pos, byte transp_color, byte color, word brush_width, // width relle 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 conscutives) bx = Main_magnifier_factor*ZOOMY; // Pour chaque ligne cran do { // On affiche la ligne zoome 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 vrifie qu'on est pas la ligne finale if(y == end_y_pos*ZOOMY) { Redraw_grid( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); 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 zoome dans la partie zoome ! 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) { Redraw_grid(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-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; } } grafx2/src/pxwide.c0000644000076400010400000003341011343525212014664 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ #include #include #include #include "global.h" #include "sdlscreen.h" #include "misc.h" #include "graph.h" #include "pxwide.h" #define ZOOMX 2 #define ZOOMY 1 #ifdef __VBCC__ #define __attribute__(x) #endif void Pixel_wide (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; } byte Read_pixel_wide (word x,word y) /* On retourne la couleur du pixel aux coords donnes */ { 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 donne */ { 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_wide (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 dpart 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 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_wide (word x,word y,byte color) /* Affichage d'un pixel dans l'cran, par rapport au dcalage de l'image * dans l'cran, en mode normal (pas en mode loupe) * Note: si on modifie cette procdure, il faudra penser faire galement * la modif dans la procdure Pixel_Preview_Loupe_SDL. */ { // if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) Pixel_wide(x-Main_offset_X,y-Main_offset_Y,color); } void Pixel_preview_magnifier_wide (word x,word y,byte color) { // Affiche le pixel dans la partie non zoome Pixel_wide(x-Main_offset_X,y-Main_offset_Y,color); // Regarde si on doit aussi l'afficher dans la partie zoome 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 = Main_magnifier_factor * (y-Main_magnifier_offset_Y); if (Menu_Y - y_zoom < Main_magnifier_factor) // On ne doit dessiner qu'un morceau du pixel // sinon on dpasse sur le menu height = Menu_Y - y_zoom; else height = Main_magnifier_factor; Block_wide( Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, y_zoom, Main_magnifier_factor, height, 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*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; int x; for (x=0;x0;i--) { *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 * 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 vrifie que ce n'est pas la transparence if(*src != transp_color) { *(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_wide(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+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_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*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 dpart 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+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_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 * 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 vrifie que ce n'est pas la transparence if(*src != transp_color) { *(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_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 * 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+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_wide(word x_pos,word y_pos,word width,byte * line) /* On affiche toute une ligne de pixels telle quelle. */ /* Utilise si le buffer contient dja des pixel doubls. */ { 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) /* 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+1)=*dest=*line; dest+=ZOOMX; line++; } } void Display_transparent_mono_line_on_screen_wide( 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 ! } void Display_transparent_line_on_screen_wide(word x_pos,word y_pos,word width,byte* line,byte transp_color) { byte* src = line; byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; word x; // Pour chaque pixel de la ligne for(x = width;x > 0;x--) { if(*src!=transp_color) { *(dest+1) = *dest = *src; } src++; dest+=ZOOMX; } } // Affiche une partie de la brosse couleur zoome void Display_brush_color_zoom_wide(word x_pos,word y_pos, word x_offset,word y_offset, word width, // width non zoome word end_y_pos,byte transp_color, word brush_width, // width relle 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 zoome for(bx=Main_magnifier_factor;bx>0;bx--) { Display_transparent_line_on_screen_wide(x_pos,y*ZOOMY,width*Main_magnifier_factor,buffer,transp_color); y++; if(y==end_y_pos) { return; } } src += brush_width; } // ATTENTION zone jamais atteinte } void Display_brush_mono_zoom_wide(word x_pos, word y_pos, word x_offset, word y_offset, word width, // width non zoome word end_y_pos, byte transp_color, byte color, word brush_width, // width relle 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 conscutives) bx = Main_magnifier_factor*ZOOMY; // Pour chaque ligne cran do { // On affiche la ligne zoome Display_transparent_mono_line_on_screen_wide( x_pos, y, width * Main_magnifier_factor, buffer, transp_color, color ); // On passe la ligne suivante y++; // On vrifie qu'on est pas la ligne finale if(y == end_y_pos*ZOOMY) { Redraw_grid( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); 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_wide(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 zoome dans la partie zoome ! 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{ Display_line_on_screen_fast_wide(x_pos,y, width * Main_magnifier_factor,buffer); // Ligne suivante y++; if(y==end_y_pos) { Redraw_grid(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-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; } } grafx2/src/pxwide2.c0000644000076400010400000003715511343525212014760 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ #include #include #include #include "global.h" #include "sdlscreen.h" #include "misc.h" #include "graph.h" #include "pxwide2.h" #define ZOOMX 4 #define ZOOMY 2 #ifdef __VBCC__ #define __attribute__(w) #endif 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 donnes */ { 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 donne */ { 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 dpart 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 dcalage de l'image * dans l'cran, en mode normal (pas en mode loupe) * Note: si on modifie cette procdure, il faudra penser faire galement * la modif dans la procdure 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 zoome Pixel_wide2(x-Main_offset_X,y-Main_offset_Y,color); // Regarde si on doit aussi l'afficher dans la partie zoome 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 = Main_magnifier_factor * (y-Main_magnifier_offset_Y); if (Menu_Y - y_zoom < Main_magnifier_factor) // On ne doit dessiner qu'un morceau du pixel // sinon on dpasse sur le menu height = Menu_Y - y_zoom; else height = Main_magnifier_factor; Block_wide2( Main_magnifier_factor * (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 vrifie 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 dpart 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 vrifie 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. */ /* Utilise si le buffer contient dja des pixel doubls. */ { 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 zoome void Display_brush_color_zoom_wide2(word x_pos,word y_pos, word x_offset,word y_offset, word width, // width non zoome word end_y_pos,byte transp_color, word brush_width, // width relle 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 zoome 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 zoome word end_y_pos, byte transp_color, byte color, word brush_width, // width relle 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 conscutives) bx = Main_magnifier_factor*ZOOMY; // Pour chaque ligne cran do { // On affiche la ligne zoome 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 vrifie qu'on est pas la ligne finale if(y == end_y_pos*ZOOMY) { Redraw_grid( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); 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 zoome dans la partie zoome ! 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) { Redraw_grid(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-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; } } grafx2/src/readini.c0000644000076400010400000006522711546416240015017 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2008 Peter Gordon 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 */ #define _XOPEN_SOURCE 500 #include #include #include #include #include "const.h" #include "errors.h" #include "global.h" #include "misc.h" #include "readini.h" #include "setup.h" #include "realpath.h" #include "io.h" void Load_INI_clear_string(char * str, byte keep_comments) { int index; int equal_found=0; for (index=0;str[index]!='\0';) { if ((str[index]=='=')) { equal_found=1; index++; // On enleve les espaces aprs le '=' while (str[index]==' ' || str[index]=='\t') memmove(str+index,str+index+1,strlen(str+index)); } else if ((str[index]==' ' && !equal_found) || (str[index]=='\t')) { // Suppression d'un espace ou d'un tab: memmove(str+index,str+index+1,strlen(str+index)); } else if (!keep_comments && ((str[index]==';') || (str[index]=='#'))) { // Comment str[index]='\0'; } else if ((str[index]=='\r') || (str[index]=='\n')) { // Line break str[index]='\0'; } else { if (!equal_found) { // Passage en majuscule d'un caractre: str[index]=toupper((int)str[index]); } index++; } } // On enlve les espaces avant la fin de chaine while (index>0 && (str[index-1]==' ' || str[index-1]=='\t')) { index--; str[index]='\0'; } } int Load_INI_seek_pattern(char * buffer,char * pattern) { int buffer_index; int pattern_index; // A partir de chaque lettre de la chane buffer for (buffer_index=0;buffer[buffer_index]!='\0';buffer_index++) { // On regarde si la chane pattern est quivalente la position courante // de la chane buffer: for (pattern_index=0;(pattern[pattern_index]!='\0') && (buffer[buffer_index+pattern_index]==pattern[pattern_index]);pattern_index++); // Si on a trouv la chane pattern dans la chane buffer, on renvoie la // position laquelle on l'a trouve (+1 pour que si on la trouve au // dbut a ne renvoie pas la mme chose que si on ne l'avait pas // trouve): if (pattern[pattern_index]=='\0') return (buffer_index+1); } // Si on ne l'a pas trouve, on renvoie 0: return 0; } int Load_INI_reach_group(FILE * file,char * buffer,char * group) { int stop_seek; char * group_upper; char * upper_buffer; // On alloue les zones de mmoire: group_upper=(char *)malloc(1024); upper_buffer=(char *)malloc(1024); // On commence par se faire une version majuscule du groupe rechercher: strcpy(group_upper,group); Load_INI_clear_string(group_upper, 0); stop_seek=0; do { // On lit une ligne dans le fichier: if (fgets(buffer,1024,file)==0) { free(upper_buffer); free(group_upper); return ERROR_INI_CORRUPTED; } Line_number_in_INI_file++; // On s'en fait une version en majuscule: strcpy(upper_buffer,buffer); Load_INI_clear_string(upper_buffer, 0); // On compare la chane avec le groupe recherch: stop_seek=Load_INI_seek_pattern(upper_buffer,group_upper); } while (!stop_seek); free(upper_buffer); free(group_upper); return 0; } /// /// Find the next string in the .INI file. /// @param file INI file currently opened /// @param buffer Current text buffer, preserved from one call to the next /// @param option_name string to search /// @param return_code the found value will be copied there. (must be allocaed) /// @param raw_text Boolean: true to return the raw value (up to end-of-line), false to strip comments. int Load_INI_get_string(FILE * file,char * buffer,char * option_name,char * return_code, byte raw_text) { int stop_seek; char * option_upper; char * upper_buffer; int buffer_index; // On alloue les zones de mmoire: option_upper=(char *)malloc(1024); upper_buffer=(char *)malloc(1024); // On commence par se faire une version majuscule de l'option rechercher: strcpy(option_upper,option_name); Load_INI_clear_string(option_upper, 0); stop_seek=0; do { // On lit une ligne dans le fichier: if (fgets(buffer,1024,file)==NULL) { free(upper_buffer); free(option_upper); return ERROR_INI_CORRUPTED; } Line_number_in_INI_file++; // On s'en fait une version en majuscule: strcpy(upper_buffer,buffer); Load_INI_clear_string(upper_buffer, raw_text); // On compare la chane avec l'option recherche: stop_seek=Load_INI_seek_pattern(upper_buffer,option_upper); // Si on l'a trouve: if (stop_seek) { // On se positionne juste aprs la chane "=" buffer_index=Load_INI_seek_pattern(upper_buffer,"="); strcpy(return_code, upper_buffer + buffer_index); } } while (!stop_seek); free(upper_buffer); free(option_upper); return 0; } int Load_INI_get_value(char * str,int * index,int * value) { int negative = 0; // On teste si la valeur actuelle est YES (ou Y): if (Load_INI_seek_pattern(str+(*index),"yes,")==1) { (*value)=1; (*index)+=4; return 0; } if (strcmp(str+(*index),"yes")==0) { (*value)=1; (*index)+=3; return 0; } if (Load_INI_seek_pattern(str+(*index),"y,")==1) { (*value)=1; (*index)+=2; return 0; } if (strcmp(str+(*index),"y")==0) { (*value)=1; (*index)+=1; return 0; } // On teste si la valeur actuelle est NO (ou N): if (Load_INI_seek_pattern(str+(*index),"no,")==1) { (*value)=0; (*index)+=3; return 0; } if (strcmp(str+(*index),"no")==0) { (*value)=0; (*index)+=2; return 0; } if (Load_INI_seek_pattern(str+(*index),"n,")==1) { (*value)=0; (*index)+=2; return 0; } if (strcmp(str+(*index),"n")==0) { (*value)=0; (*index)+=1; return 0; } if (str[*index]=='$') { (*value)=0; for (;;) { (*index)++; if ((str[*index]>='0') && (str[*index]<='9')) (*value)=((*value)*16)+str[*index]-'0'; else if ((str[*index]>='A') && (str[*index]<='F')) (*value)=((*value)*16)+str[*index]-'A'+10; else if (str[*index]==',') { (*index)++; return 0; } else if (str[*index]=='\0') return 0; else return ERROR_INI_CORRUPTED; } } if (str[*index]=='-') { negative = 1; // next character (*index)++; // Fall thru } if ((str[*index]>='0') && (str[*index]<='9')) { (*value)=0; for (;;) { if ((str[*index]>='0') && (str[*index]<='9')) { (*value)=((*value)*10)+str[*index]-'0'; if (negative) { (*value)*= -1; // This is to do it once per number. negative = 0; } } else if (str[*index]==',') { (*index)++; return 0; } else if (str[*index]=='\0') return 0; else return ERROR_INI_CORRUPTED; (*index)++; } } else return ERROR_INI_CORRUPTED; } int Load_INI_get_values(FILE * file,char * buffer,char * option_name,int nb_expected_values,int * values) { int stop_seek; char * option_upper; char * upper_buffer; int buffer_index; int nb_values; // On alloue les zones de mmoire: option_upper=(char *)malloc(1024); upper_buffer=(char *)malloc(1024); // On commence par se faire une version majuscule de l'option rechercher: strcpy(option_upper,option_name); Load_INI_clear_string(option_upper, 0); stop_seek=0; do { // On lit une ligne dans le fichier: if (fgets(buffer,1024,file)==0) { free(upper_buffer); free(option_upper); return ERROR_INI_CORRUPTED; } Line_number_in_INI_file++; // On s'en fait une version en majuscule: strcpy(upper_buffer,buffer); Load_INI_clear_string(upper_buffer, 0); // On compare la chane avec l'option recherche: stop_seek=Load_INI_seek_pattern(upper_buffer,option_upper); // Si on l'a trouve: if (stop_seek) { nb_values=0; // On se positionne juste aprs la chane "=" buffer_index=Load_INI_seek_pattern(upper_buffer,"="); // Tant qu'on a pas atteint la fin de la ligne while (upper_buffer[buffer_index]!='\0') { if (Load_INI_get_value(upper_buffer,&buffer_index,values+nb_values)) { free(upper_buffer); free(option_upper); return ERROR_INI_CORRUPTED; } if ( ((++nb_values) == nb_expected_values) && (upper_buffer[buffer_index]!='\0') ) { // Too many values ! free(upper_buffer); free(option_upper); return ERROR_INI_CORRUPTED; } } if (nb_valuesStylus_mode = 1; #else conf->Stylus_mode = 0; #endif // On alloue les zones de mmoire: buffer=(char *)malloc(1024); filename=(char *)malloc(256); // On calcule le nom du fichier qu'on manipule: strcpy(filename,Config_directory); strcat(filename,INI_FILENAME); file=fopen(filename,"r"); if (file==0) { // Si le fichier ini est absent on le relit depuis gfx2def.ini strcpy(filename,Data_directory); strcat(filename,INIDEF_FILENAME); file=fopen(filename,"r"); if (file == 0) { free(filename); free(buffer); return ERROR_INI_MISSING; } } if ((return_code=Load_INI_reach_group(file,buffer,"[MOUSE]"))) goto Erreur_Retour; if ((return_code=Load_INI_get_values (file,buffer,"X_sensitivity",1,values))) goto Erreur_Retour; if ((values[0]<1) || (values[0]>4)) conf->Mouse_sensitivity_index_x=1; else conf->Mouse_sensitivity_index_x=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Y_sensitivity",1,values))) goto Erreur_Retour; if ((values[0]<1) || (values[0]>4)) conf->Mouse_sensitivity_index_y=1; else conf->Mouse_sensitivity_index_y=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"X_correction_factor",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>4)) goto Erreur_ERREUR_INI_CORROMPU; // Deprecated setting, unused if ((return_code=Load_INI_get_values (file,buffer,"Y_correction_factor",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>4)) goto Erreur_ERREUR_INI_CORROMPU; // Deprecated setting, unused if ((return_code=Load_INI_get_values (file,buffer,"Cursor_aspect",1,values))) goto Erreur_Retour; if ((values[0]<1) || (values[0]>3)) goto Erreur_ERREUR_INI_CORROMPU; conf->Cursor=values[0]-1; if ((return_code=Load_INI_reach_group(file,buffer,"[MENU]"))) goto Erreur_Retour; conf->Fav_menu_colors[0].R=0; conf->Fav_menu_colors[0].G=0; conf->Fav_menu_colors[0].B=0; conf->Fav_menu_colors[3].R=255; conf->Fav_menu_colors[3].G=255; conf->Fav_menu_colors[3].B=255; if ((return_code=Load_INI_get_values (file,buffer,"Light_color",3,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>63)) goto Erreur_ERREUR_INI_CORROMPU; if ((values[1]<0) || (values[1]>63)) goto Erreur_ERREUR_INI_CORROMPU; if ((values[2]<0) || (values[2]>63)) goto Erreur_ERREUR_INI_CORROMPU; conf->Fav_menu_colors[2].R=(values[0]<<2)|(values[0]>>4); conf->Fav_menu_colors[2].G=(values[1]<<2)|(values[1]>>4); conf->Fav_menu_colors[2].B=(values[2]<<2)|(values[2]>>4); if ((return_code=Load_INI_get_values (file,buffer,"Dark_color",3,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>63)) goto Erreur_ERREUR_INI_CORROMPU; if ((values[1]<0) || (values[1]>63)) goto Erreur_ERREUR_INI_CORROMPU; if ((values[2]<0) || (values[2]>63)) goto Erreur_ERREUR_INI_CORROMPU; conf->Fav_menu_colors[1].R=(values[0]<<2)|(values[0]>>4); conf->Fav_menu_colors[1].G=(values[1]<<2)|(values[1]>>4); conf->Fav_menu_colors[1].B=(values[2]<<2)|(values[2]>>4); if ((return_code=Load_INI_get_values (file,buffer,"Menu_ratio",1,values))) goto Erreur_Retour; if ((values[0]<-4) || (values[0]>2)) goto Erreur_ERREUR_INI_CORROMPU; conf->Ratio=values[0]; if ((return_code=Load_INI_reach_group(file,buffer,"[FILE_SELECTOR]"))) goto Erreur_Retour; if ((return_code=Load_INI_get_values (file,buffer,"Show_hidden_files",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Show_hidden_files=values[0]?1:0; if ((return_code=Load_INI_get_values (file,buffer,"Show_hidden_directories",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Show_hidden_directories=values[0]?1:0; /* if ((return_code=Load_INI_get_values (file,buffer,"Show_system_directories",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Show_system_directories=values[0]?1:0; */ if ((return_code=Load_INI_get_values (file,buffer,"Preview_delay",1,values))) goto Erreur_Retour; if ((values[0]<1) || (values[0]>256)) goto Erreur_ERREUR_INI_CORROMPU; conf->Timer_delay=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Maximize_preview",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Maximize_preview=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Find_file_fast",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>2)) goto Erreur_ERREUR_INI_CORROMPU; conf->Find_file_fast=values[0]; if ((return_code=Load_INI_reach_group(file,buffer,"[LOADING]"))) goto Erreur_Retour; if ((return_code=Load_INI_get_values (file,buffer,"Auto_set_resolution",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Auto_set_res=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Set_resolution_according_to",1,values))) goto Erreur_Retour; if ((values[0]<1) || (values[0]>2)) goto Erreur_ERREUR_INI_CORROMPU; conf->Set_resolution_according_to=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Clear_palette",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Clear_palette=values[0]; if ((return_code=Load_INI_reach_group(file,buffer,"[MISCELLANEOUS]"))) goto Erreur_Retour; if ((return_code=Load_INI_get_values (file,buffer,"Draw_limits",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Display_image_limits=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Adjust_brush_pick",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Adjust_brush_pick=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Coordinates",1,values))) goto Erreur_Retour; if ((values[0]<1) || (values[0]>2)) goto Erreur_ERREUR_INI_CORROMPU; conf->Coords_rel=2-values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Backup",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Backup=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Undo_pages",1,values))) goto Erreur_Retour; if ((values[0]<1) || (values[0]>99)) goto Erreur_ERREUR_INI_CORROMPU; conf->Max_undo_pages=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Gauges_scrolling_speed_Left",1,values))) goto Erreur_Retour; if ((values[0]<1) || (values[0]>255)) goto Erreur_ERREUR_INI_CORROMPU; conf->Delay_left_click_on_slider=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Gauges_scrolling_speed_Right",1,values))) goto Erreur_Retour; if ((values[0]<1) || (values[0]>255)) goto Erreur_ERREUR_INI_CORROMPU; conf->Delay_right_click_on_slider=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Auto_save",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Auto_save=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Vertices_per_polygon",1,values))) goto Erreur_Retour; if ((values[0]<2) || (values[0]>16384)) goto Erreur_ERREUR_INI_CORROMPU; conf->Nb_max_vertices_per_polygon=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Fast_zoom",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Fast_zoom=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Separate_colors",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Separate_colors=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"FX_feedback",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->FX_Feedback=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Safety_colors",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Safety_colors=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Opening_message",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Opening_message=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Clear_with_stencil",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Clear_with_stencil=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Auto_discontinuous",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Auto_discontinuous=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Save_screen_size_in_GIF",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Screen_size_in_GIF=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Auto_nb_colors_used",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Auto_nb_used=values[0]; // Optionnel, le mode video par dfaut ( partir de beta 97.0%) conf->Default_resolution=0; if (!Load_INI_get_string (file,buffer,"Default_video_mode",value_label, 0)) { int mode = Convert_videomode_arg(value_label); if (mode>=0) conf->Default_resolution=mode; } // Optionnel, les dimensions de la fentre ( partir de beta 97.0%) // Do that only if the first mode is actually windowed (not the case on gp2x for example) if(Video_mode[0].Fullscreen==0) { Video_mode[0].Width = 640; Video_mode[0].Height = 480; if (!Load_INI_get_values (file,buffer,"Default_window_size",2,values)) { if ((values[0]>=320)) Video_mode[0].Width = values[0]; if ((values[1]>=200)) Video_mode[0].Height = values[1]; } } conf->Mouse_merge_movement=100; // Optionnel, paramtre pour grouper les mouvements souris (>98.0%) if (!Load_INI_get_values (file,buffer,"Merge_movement",1,values)) { if ((values[0]<0) || (values[0]>1000)) goto Erreur_ERREUR_INI_CORROMPU; conf->Mouse_merge_movement=values[0]; } conf->Palette_cells_X=8; // Optionnel, nombre de colonnes dans la palette (>98.0%) if (!Load_INI_get_values (file,buffer,"Palette_cells_X",1,values)) { if ((values[0]<1) || (values[0]>256)) goto Erreur_ERREUR_INI_CORROMPU; conf->Palette_cells_X=values[0]; } conf->Palette_cells_Y=8; // Optionnel, nombre de lignes dans la palette (>98.0%) if (!Load_INI_get_values (file,buffer,"Palette_cells_Y",1,values)) { if (values[0]<1 || values[0]>16) goto Erreur_ERREUR_INI_CORROMPU; conf->Palette_cells_Y=values[0]; } // Optionnel, bookmarks (>98.0%) for (index=0;indexBookmark_directory[index]=NULL; conf->Bookmark_label[index][0]='\0'; } for (index=0;index8) { value_label[7]=ELLIPSIS_CHARACTER; value_label[8]='\0'; } strcpy(conf->Bookmark_label[index],value_label); } } else break; if (!Load_INI_get_string (file,buffer,"Bookmark_directory",value_label, 1)) { int size=strlen(value_label); if (size!=0) { conf->Bookmark_directory[index]=(char *)malloc(size+1); strcpy(conf->Bookmark_directory[index],value_label); } } else break; } conf->Palette_vertical=0; // Optional, vertical palette option (>98.0%) if (!Load_INI_get_values (file,buffer,"Palette_vertical",1,values)) { if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Palette_vertical=values[0]; } // Optional, the window position (>98.0%) conf->Window_pos_x=9999; conf->Window_pos_y=9999; if (!Load_INI_get_values (file,buffer,"Window_position",2,values)) { conf->Window_pos_x = values[0]; conf->Window_pos_y = values[1]; } conf->Double_click_speed=500; // Optional, speed of double-click (>2.0) if (!Load_INI_get_values (file,buffer,"Double_click_speed",1,values)) { if ((values[0]>0) || (values[0]<=2000)) conf->Double_click_speed=values[0]; } conf->Double_key_speed=500; // Optional, speed of double-keypress (>2.0) if (!Load_INI_get_values (file,buffer,"Double_key_speed",1,values)) { if ((values[0]>0) || (values[0]<=2000)) conf->Double_key_speed=values[0]; } // Optional, name of skin file. (>2.0) if(!Load_INI_get_string(file,buffer,"Skin_file",value_label,1)) { conf->Skin_file = strdup(value_label); } else conf->Skin_file = strdup("skin_DPaint.png"); // Optional, name of font file. (>2.0) if(!Load_INI_get_string(file,buffer,"Font_file",value_label,1)) conf->Font_file = strdup(value_label); else conf->Font_file = strdup("font_Dpaint.png"); conf->Grid_XOR_color=255; // Optional, XOR color for grid overlay (>2.0) if (!Load_INI_get_values (file,buffer,"Grid_XOR_color",1,values)) { if ((values[0]>0) && (values[0]<=255)) conf->Grid_XOR_color=values[0]; } // Optional, "fake hardware zoom" factor (>2.1) if (!Load_INI_get_values (file, buffer,"Pixel_ratio",1,values)) { Pixel_ratio = values[0]; switch(Pixel_ratio) { case PIXEL_WIDE: if(Video_mode[0].Width < 640) Pixel_ratio = PIXEL_SIMPLE; break; case PIXEL_TALL: if(Video_mode[0].Height < 400) Pixel_ratio = PIXEL_SIMPLE; break; case PIXEL_DOUBLE: if(Video_mode[0].Width < 640 || Video_mode[0].Height < 400) Pixel_ratio = PIXEL_SIMPLE; break; case PIXEL_TRIPLE: if(Video_mode[0].Width < 3*320 || Video_mode[0].Height < 3*200) Pixel_ratio = PIXEL_SIMPLE; break; case PIXEL_WIDE2: if(Video_mode[0].Width < 4*320 || Video_mode[0].Height < 2*200) Pixel_ratio = PIXEL_SIMPLE; break; case PIXEL_TALL2: if(Video_mode[0].Width < 2*320 || Video_mode[0].Height < 4*200) Pixel_ratio = PIXEL_SIMPLE; break; case PIXEL_QUAD: if(Video_mode[0].Width < 4*320 || Video_mode[0].Height < 4*200) Pixel_ratio = PIXEL_SIMPLE; break; default: // Convert back unknown values to PIXEL_SIMPLE Pixel_ratio = PIXEL_SIMPLE; break; } } // Optional, Menu bars visibility (> 2.1) if (!Load_INI_get_values (file, buffer,"Menubars_visible",1,values)) { int index; for (index=MENUBAR_STATUS+1; indexRight_click_colorpick=0; // Optional, right mouse button to pick colors (>=2.3) if (!Load_INI_get_values (file,buffer,"Right_click_colorpick",1,values)) { conf->Right_click_colorpick=(values[0]!=0); } conf->Sync_views=1; // Optional, synced view of main and spare (>=2.3) if (!Load_INI_get_values (file,buffer,"Sync_views",1,values)) { conf->Sync_views=(values[0]!=0); } conf->Swap_buttons=0; // Optional, key for swap buttons (>=2.3) if (!Load_INI_get_values (file,buffer,"Swap_buttons",1,values)) { switch(values[0]) { case 1: conf->Swap_buttons=MOD_CTRL; break; case 2: conf->Swap_buttons=MOD_ALT; break; } } // Optional, Location of last directory used for Lua scripts browsing (>=2.3) conf->Scripts_directory[0]='\0'; if (!Load_INI_get_string (file,buffer,"Scripts_directory",value_label, 1)) { strcpy(conf->Scripts_directory,value_label); } if (conf->Scripts_directory[0]=='\0') { // Default when empty: Realpath(Data_directory, conf->Scripts_directory); Append_path(conf->Scripts_directory, "scripts", NULL); } conf->Allow_multi_shortcuts=0; // Optional, allow or disallow multiple shortcuts on same key (>=2.3) if (!Load_INI_get_values (file,buffer,"Allow_multi_shortcuts",1,values)) { conf->Allow_multi_shortcuts=(values[0]!=0); } // Insert new values here fclose(file); free(filename); free(buffer); return 0; // Gestion des erreurs: Erreur_Retour: fclose(file); free(filename); free(buffer); return return_code; Erreur_ERREUR_INI_CORROMPU: fclose(file); free(filename); free(buffer); return ERROR_INI_CORRUPTED; } grafx2/src/readline.c0000644000076400010400000005627511536457152015200 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ /************************************************************************ * * * READLINE (procdure permettant de saisir une chane de caractres) * * * ************************************************************************/ #include #include #include #include "const.h" #include "struct.h" #include "global.h" #include "misc.h" #include "errors.h" #include "const.h" #include "sdlscreen.h" #include "readline.h" #include "windows.h" #include "input.h" #include "engine.h" // Virtual keyboard is mandatory on these platforms: #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) #ifndef VIRT_KEY #define VIRT_KEY 1 #endif #endif #define TEXT_COLOR MC_Black #define BACKGROUND_COLOR MC_Light #define CURSOR_COLOR MC_Black #define CURSOR_BACKGROUND_COLOR MC_Dark // Suppresion d'un caractre une certaine POSITION dans une CHAINE. void Remove_character(char * str, byte position) { for (;str[position]!='\0';position++) str[position]=str[position+1]; } void Insert_character(char * str, char letter, byte position) // Insertion d'une LETTRE une certaine POSITION // dans une CHAINE d'une certaine TAILLE. { char temp_char; for (;letter!='\0';position++) { // On mmorise le caractre qui se trouve en "position" temp_char=str[position]; // On splotch la lettre insrer str[position]=letter; // On place le caractre mmoris dans "letter" comme nouvelle lettre insrer letter=temp_char; } // On termine la chaine str[position]='\0'; } int Valid_character(int c) { // Sous Linux: Seul le / est strictement interdit, mais beaucoup // d'autres poseront des problmes au shell, alors on vite. // Sous Windows : c'est moins grave car le fopen() chouerait de toutes faons. // AmigaOS4: Pas de ':' car utilis pour les volumes. #if defined(__WIN32__) char forbidden_char[] = {'/', '|', '?', '*', '<', '>', ':', '\\'}; #elif defined (__amigaos4__) char forbidden_char[] = {'/', '|', '?', '*', '<', '>', ':'}; #else char forbidden_char[] = {'/', '|', '?', '*', '<', '>'}; #endif int position; if (c < ' ' || c > 255) return 0; for (position=0; position<(long)sizeof(forbidden_char); position++) if (c == forbidden_char[position]) return 0; return 1; } void Display_whole_string(word x_pos,word y_pos,char * str,byte position) { char cursor[2]; Print_general(x_pos,y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); cursor[0]=str[position] ? str[position] : ' '; cursor[1]='\0'; Print_general(x_pos+(position<<3)*Menu_factor_X,y_pos,cursor,CURSOR_COLOR,CURSOR_BACKGROUND_COLOR); } void Init_virtual_keyboard(word y_pos, word keyboard_width, word keyboard_height) { int h_pos; int v_pos; int parent_window_x=Window_pos_X+2; h_pos= Window_pos_X+(keyboard_width-Window_width)*Menu_factor_X/-2; if (h_pos<0) h_pos=0; else if (h_pos+keyboard_width*Menu_factor_X>Screen_width) h_pos=Screen_width-keyboard_width*Menu_factor_X; v_pos=Window_pos_Y+(y_pos+9)*Menu_factor_Y; if (v_pos+(keyboard_height*Menu_factor_Y)>Screen_height) v_pos=Window_pos_Y+(y_pos-keyboard_height-4)*Menu_factor_Y; Hide_cursor(); Open_popup(h_pos,v_pos,keyboard_width,keyboard_height); Window_rectangle(1,0,Window_width-1, Window_height-1, MC_Light); Window_rectangle(0,0,1,Window_height-2, MC_White); // white border on top left angle, when it exceeds border. if (parent_window_x>Window_pos_X) Window_rectangle(0,0,(parent_window_x-Window_pos_X)/Menu_factor_X, 1, MC_White); Window_rectangle(2,Window_height-2,Window_width-2, 2, MC_Black); if(keyboard_width<320) { Window_rectangle(Window_width-2,2,2,Window_height-2, MC_Black); } } /**************************************************************************** * Enhanced super scanf deluxe pro plus giga mieux :-) * ****************************************************************************/ byte Readline(word x_pos,word y_pos,char * str,byte visible_size,byte input_type) // Paramtres: // x_pos, y_pos : Coordonnes de la saisie dans la fentre // str : Chane recevant la saisie (et contenant ventuellement une valeur initiale) // max_size : Nombre de caractres logeant dans la zone de saisie // input_type : 0=Chane, 1=Nombre, 2=Nom de fichier // Sortie: // 0: Sortie par annulation (Esc.) / 1: sortie par acceptation (Return) { byte max_size; // Grosse astuce pour les noms de fichiers: La taille affiche est diffrente // de la taille maximum gre. if (input_type == 2) max_size = 255; else max_size = visible_size; return Readline_ex(x_pos,y_pos,str,visible_size,max_size,input_type,0); } /**************************************************************************** * Enhanced super scanf deluxe pro plus giga mieux :-) * ****************************************************************************/ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_size, byte input_type, byte decimal_places) // Paramtres: // x_pos, y_pos : Coordonnes de la saisie dans la fentre // str : Chane recevant la saisie (et contenant ventuellement une valeur initiale) // max_size : Nombre de caractres logeant dans la zone de saisie // input_type : 0=String, 1=Unsigned int, 2=Filename 3=Signed Double // decimal_places: Number of decimal places for a double // Sortie: // 0: Sortie par annulation (Esc.) / 1: sortie par acceptation (Return) { char initial_string[256]; char display_string[256]; byte position; byte size; word input_key=0; byte is_authorized; word window_x=Window_pos_X; word window_y=Window_pos_Y; byte offset=0; // index du premier caractre affich #ifdef VIRT_KEY // Virtual keyboard byte use_virtual_keyboard=0; static byte caps_lock=0; word keymapping[] = { SDLK_CLEAR,SDLK_BACKSPACE,SDLK_RETURN,KEY_ESC, '0','1','2','3','4','5','6','7','8','9','.',',', 'Q','W','E','R','T','Y','U','I','O','P', 'A','S','D','F','G','H','J','K','L', SDLK_CAPSLOCK,'Z','X','C','V','B','N','M',' ', '-','+','*','/','|','\\', '(',')','{','}','[',']', '_','=','<','>','%','@', ':',';','`','\'','"','~', '!','?','^','&','#','$' }; #endif // Si on a commenc editer par un clic-droit, on vide la chaine. if (Mouse_K==RIGHT_SIDE) str[0]='\0'; else if (input_type==INPUT_TYPE_INTEGER && str[0]!='\0') snprintf(str,10,"%d",atoi(str)); // On tasse la chaine gauche else if (input_type==INPUT_TYPE_DECIMAL) { // Nothing. The caller should have used Sprint_double, with min_positions // at zero, so there's no spaces on the left and no useless 0s on the right. } else if (input_type==INPUT_TYPE_HEXA) { // Nothing. The caller should have initialized a valid hexa number. } // Virtual keyboards #ifdef VIRT_KEY if (input_type == INPUT_TYPE_STRING || input_type == INPUT_TYPE_FILENAME ) { int x,y; Init_virtual_keyboard(y_pos, 320, 87); use_virtual_keyboard=1; // The order is important, see the array Window_set_normal_button( 7,67,43,15,"Clr", 0,1,KEY_NONE); Window_set_normal_button( 51,67,43,15,"Del", 0,1,KEY_NONE); Window_set_normal_button( 95,67,43,15,"OK", 0,1,KEY_NONE); Window_set_normal_button(139,67,43,15,"Esc", 0,1,KEY_NONE); Window_display_frame_in(5,65,179,19); Window_set_normal_button(193,63,17,19,"0", 0,1,KEY_NONE); Window_set_normal_button(193,43,17,19,"1", 0,1,KEY_NONE); Window_set_normal_button(211,43,17,19,"2", 0,1,KEY_NONE); Window_set_normal_button(229,43,17,19,"3", 0,1,KEY_NONE); Window_set_normal_button(193,23,17,19,"4", 0,1,KEY_NONE); Window_set_normal_button(211,23,17,19,"5", 0,1,KEY_NONE); Window_set_normal_button(229,23,17,19,"6", 0,1,KEY_NONE); Window_set_normal_button(193, 3,17,19,"7", 0,1,KEY_NONE); Window_set_normal_button(211, 3,17,19,"8", 0,1,KEY_NONE); Window_set_normal_button(229, 3,17,19,"9", 0,1,KEY_NONE); Window_set_normal_button(211,63,17,19,".", 0,1,KEY_NONE); Window_set_normal_button(229,63,17,19,",", 0,1,KEY_NONE); Window_set_normal_button( 3, 3,18,19,"Q", 0,1,KEY_NONE); Window_set_normal_button( 22, 3,18,19,"W", 0,1,KEY_NONE); Window_set_normal_button( 41, 3,18,19,"E", 0,1,KEY_NONE); Window_set_normal_button( 60, 3,18,19,"R", 0,1,KEY_NONE); Window_set_normal_button( 79, 3,18,19,"T", 0,1,KEY_NONE); Window_set_normal_button( 98, 3,18,19,"Y", 0,1,KEY_NONE); Window_set_normal_button(117, 3,18,19,"U", 0,1,KEY_NONE); Window_set_normal_button(136, 3,18,19,"I", 0,1,KEY_NONE); Window_set_normal_button(155, 3,18,19,"O", 0,1,KEY_NONE); Window_set_normal_button(174, 3,18,19,"P", 0,1,KEY_NONE); Window_set_normal_button( 12,23,18,19,"A", 0,1,KEY_NONE); Window_set_normal_button( 31,23,18,19,"S", 0,1,KEY_NONE); Window_set_normal_button( 50,23,18,19,"D", 0,1,KEY_NONE); Window_set_normal_button( 69,23,18,19,"F", 0,1,KEY_NONE); Window_set_normal_button( 88,23,18,19,"G", 0,1,KEY_NONE); Window_set_normal_button(107,23,18,19,"H", 0,1,KEY_NONE); Window_set_normal_button(126,23,18,19,"J", 0,1,KEY_NONE); Window_set_normal_button(145,23,18,19,"K", 0,1,KEY_NONE); Window_set_normal_button(164,23,18,19,"L", 0,1,KEY_NONE); Window_set_normal_button( 3,43,18,19,caps_lock?"\036":"\037", 0,1,KEY_NONE); Window_set_normal_button( 22,43,18,19,"Z", 0,1,KEY_NONE); Window_set_normal_button( 41,43,18,19,"X", 0,1,KEY_NONE); Window_set_normal_button( 60,43,18,19,"C", 0,1,KEY_NONE); Window_set_normal_button( 79,43,18,19,"V", 0,1,KEY_NONE); Window_set_normal_button( 98,43,18,19,"B", 0,1,KEY_NONE); Window_set_normal_button(117,43,18,19,"N", 0,1,KEY_NONE); Window_set_normal_button(136,43,18,19,"M", 0,1,KEY_NONE); Window_set_normal_button(155,43,18,19," ", 0,1,KEY_NONE); for (y=0; y<5; y++) { for (x=0; x<6; x++) { char label[2]=" "; label[0]=keymapping[x+y*6+44]; Window_set_normal_button(247+x*12, 3+y*16,11,15,label, 0,1,KEY_NONE); } } Update_window_area(0,0,Window_width, Window_height); Display_cursor(); } else if (input_type == INPUT_TYPE_INTEGER || input_type == INPUT_TYPE_DECIMAL ) { Init_virtual_keyboard(y_pos, 215, 47); use_virtual_keyboard=1; // The order is important, see the array Window_set_normal_button( 7,27,43,15,"Clr", 0,1,KEY_NONE); Window_set_normal_button( 51,27,43,15,"Del", 0,1,KEY_NONE); Window_set_normal_button( 95,27,43,15,"OK", 0,1,KEY_NONE); Window_set_normal_button(139,27,43,15,"Esc", 0,1,KEY_NONE); Window_display_frame_in(5,25,179,19); Window_set_normal_button(174, 3,18,19,"0", 0,1,KEY_NONE); Window_set_normal_button( 3, 3,18,19,"1", 0,1,KEY_NONE); Window_set_normal_button( 22, 3,18,19,"2", 0,1,KEY_NONE); Window_set_normal_button( 41, 3,18,19,"3", 0,1,KEY_NONE); Window_set_normal_button( 60, 3,18,19,"4", 0,1,KEY_NONE); Window_set_normal_button( 79, 3,18,19,"5", 0,1,KEY_NONE); Window_set_normal_button( 98, 3,18,19,"6", 0,1,KEY_NONE); Window_set_normal_button(117, 3,18,19,"7", 0,1,KEY_NONE); Window_set_normal_button(136, 3,18,19,"8", 0,1,KEY_NONE); Window_set_normal_button(155, 3,18,19,"9", 0,1,KEY_NONE); Window_set_normal_button(193, 3,18,19,".", 0,1,KEY_NONE); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); } #endif Keyboard_click_allowed = 0; Hide_cursor(); // Effacement de la chane Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); Update_rect(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); // Mise jour des variables se rapportant la chane en fonction de la chane initiale strcpy(initial_string,str); size=strlen(str); position=(size=visible_size) offset=position-visible_size+1; // Formatage d'une partie de la chaine (si trop longue pour tenir) strncpy(display_string, str + offset, visible_size); display_string[visible_size]='\0'; if (offset>0) display_string[0]=LEFT_TRIANGLE_CHARACTER; if (visible_size + offset + 1 < size ) display_string[visible_size-1]=RIGHT_TRIANGLE_CHARACTER; Display_whole_string(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y),display_string,position - offset); Update_rect(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); Flush_update(); if (Mouse_K) { Display_cursor(); Wait_end_of_click(); Hide_cursor(); } while ((input_key!=SDLK_RETURN) && (input_key!=KEY_ESC)) { Display_cursor(); #ifdef VIRT_KEY if (use_virtual_keyboard) { int clicked_button; clicked_button=Window_clicked_button(); input_key=Key_ANSI; if (clicked_button==-1) input_key=SDLK_RETURN; else if (clicked_button>0) { input_key=keymapping[clicked_button-1]; if (input_key==SDLK_CAPSLOCK) { // toggle uppercase caps_lock=!caps_lock; Hide_cursor(); Print_in_window(8, 49,caps_lock?"\036":"\037", MC_Black,MC_Light); Display_cursor(); } else if (input_key==SDLK_BACKSPACE) { // A little hack: the button for backspace will: // - backspace if the cursor is at end of string // - delete otherwise // It's needed for those input boxes that are completely full. if (position='A' && input_key<='Z' && !caps_lock) { input_key+='a'-'A'; } } } else #endif { do { Get_input(20); input_key=Key_ANSI; if (Mouse_K) input_key=SDLK_RETURN; } while(input_key==0); } Hide_cursor(); switch (input_key) { case SDLK_DELETE : // Suppr. if (position0) { // Effacement de la chane if (position==size) Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); position--; if (offset > 0 && (position == 0 || position < (offset + 1))) offset--; goto affichage; } break; case SDLK_RIGHT : // Droite if ((position visible_size + offset - 2) //if (offset + visible_size < max_size && (position == size || (position > visible_size + offset - 2))) if (display_string[position-offset]==RIGHT_TRIANGLE_CHARACTER || position-offset>=visible_size) offset++; goto affichage; } break; case SDLK_HOME : // Home if (position) { // Effacement de la chane if (position==size) Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); position = 0; offset = 0; goto affichage; } break; case SDLK_END : // End if ((position=visible_size) offset=position-visible_size+1; goto affichage; } break; case SDLK_BACKSPACE : // Backspace : combinaison de gauche + suppr if (position) { position--; if (offset > 0 && (position == 0 || position < (offset + 1))) offset--; Remove_character(str,position); size--; // Effacement de la chane Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); goto affichage; } break; case SDLK_CLEAR : // Clear str[0]='\0'; position=offset=0; // Effacement de la chane Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); goto affichage; case SDLK_RETURN : break; case KEY_ESC : // On restaure la chaine initiale strcpy(str,initial_string); size=strlen(str); break; default : if (size=' ' && input_key<= 255)||input_key=='\n') is_authorized=1; break; case INPUT_TYPE_INTEGER : if ( (input_key>='0') && (input_key<='9') ) is_authorized=1; break; case INPUT_TYPE_DECIMAL: if ( (input_key>='0') && (input_key<='9') ) is_authorized=1; else if (input_key=='-' && position==0 && str[0]!='-') is_authorized=1; else if (input_key=='.') is_authorized=1; break; case INPUT_TYPE_FILENAME: // On regarde si la touche est autorise if ( Valid_character(input_key)) is_authorized=1; case INPUT_TYPE_HEXA: if ( (input_key>='0') && (input_key<='9') ) is_authorized=1; else if ( (input_key>='A') && (input_key<='F') ) is_authorized=1; else if ( (input_key>='a') && (input_key<='f') ) is_authorized=1; break; } // End du "switch(input_type)" // Si la touche tait autorise... if (is_authorized) { // ... alors on l'insre ... Insert_character(str,input_key,position/*,size*/); // ce qui augmente la taille de la chaine size++; // et qui risque de dplacer le curseur vers la droite if (size=visible_size) offset++; } // Enfin, on raffiche la chaine goto affichage; } // End du test d'autorisation de touche } // End du test de place libre break; affichage: size=strlen(str); // Formatage d'une partie de la chaine (si trop longue pour tenir) strncpy(display_string, str + offset, visible_size); display_string[visible_size]='\0'; if (offset>0) display_string[0]=LEFT_TRIANGLE_CHARACTER; if (visible_size + offset + 0 < size ) display_string[visible_size-1]=RIGHT_TRIANGLE_CHARACTER; Display_whole_string(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y),display_string,position - offset); Update_rect(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); } // End du "switch(input_key)" Flush_update(); } // End du "while" Keyboard_click_allowed = 1; #ifdef VIRT_KEY if (use_virtual_keyboard) { byte old_mouse_k = Mouse_K; Close_popup(); Mouse_K=old_mouse_k; Input_sticky_control=0; } #endif // Effacement de la chane Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); // On raffiche la chaine correctement if (input_type==INPUT_TYPE_INTEGER) { if (str[0]=='\0') { strcpy(str,"0"); size=1; } Print_in_window(x_pos+((max_size-size)<<3),y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); } else if (input_type==INPUT_TYPE_DECIMAL) { double value; // Discard extra digits value = Fround(atof(str), decimal_places); Sprint_double(str,value,decimal_places,visible_size); // Recompute updated size size = strlen(str); if (size<=visible_size) Print_in_window(x_pos+((visible_size-size)<<3),y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); else Print_in_window_limited(x_pos,y_pos,str,visible_size,TEXT_COLOR,BACKGROUND_COLOR); } else { Print_in_window_limited(x_pos,y_pos,str,visible_size,TEXT_COLOR,BACKGROUND_COLOR); } Update_rect(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); return (input_key==SDLK_RETURN); } void Sprint_double(char *str, double value, byte decimal_places, byte min_positions) { int i; int length; sprintf(str,"%.*f",decimal_places, value); length=strlen(str); for (i=0; i= 0 && decimals[j]=='0'; j--) { decimals[j] = '\0'; } // If all decimals were removed, remove the dot too if (str[i+1]=='\0') str[i]='\0'; // Update string length length=strlen(str); // Ends the parent loop break; } } // Now try add spaces at beginning if (length #include #include #include #include #if defined(__AROS__) #include #endif #if defined(__AROS__) || defined(__BEOS__) || defined(__MORPHOS__) || defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) || defined(__amigaos__) // These platforms don't have realpath(). // We use the following implementation, found in: // http://amiga.sourceforge.net/amigadevhelp/FUNCTIONS/GeekGadgets/realpath/ex02_realpath.c // // When tested on Debian, this piece of code doesn't resolve // symbolic link in the filename itself, only on the directories in // the path. So this implementation is limited, it's really better to // use realpath() if your platform has it. #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) || defined(__amigaos__) // This is a random default value ... #define PATH_MAX 32768 #endif static char *sep(char *path) { char *tmp, c; tmp = strrchr(path, '/'); if(tmp) { c = tmp[1]; tmp[1] = 0; if (chdir(path)) { return NULL; } tmp[1] = c; return tmp + 1; } return path; } char *Realpath(const char *_path, char *resolved_path) { int fd = open(".", O_RDONLY), l; char current_dir_path[PATH_MAX]; char path[PATH_MAX], lnk[PATH_MAX], *tmp = (char *)""; if (fd < 0) { return NULL; } getcwd(current_dir_path,PATH_MAX); strncpy(path, _path, PATH_MAX); if (chdir(path)) { if (errno == ENOTDIR) { #if defined(__WIN32__) || defined(__MORPHOS__) || defined(__amigaos__) // No symbolic links and no readlink() l = -1; #else l = readlink(path, lnk, PATH_MAX); #endif if (!(tmp = sep(path))) { resolved_path = NULL; goto abort; } if (l < 0) { if (errno != EINVAL) { resolved_path = NULL; goto abort; } } else { lnk[l] = 0; if (!(tmp = sep(lnk))) { resolved_path = NULL; goto abort; } } } else { resolved_path = NULL; goto abort; } } if(resolved_path==NULL) // if we called realpath with null as a 2nd arg resolved_path = (char*) malloc( PATH_MAX ); if (!getcwd(resolved_path, PATH_MAX)) { resolved_path = NULL; goto abort; } if(strcmp(resolved_path, "/") && *tmp) { strcat(resolved_path, "/"); } strcat(resolved_path, tmp); abort: chdir(current_dir_path); close(fd); return resolved_path; } #elif defined (__WIN32__) // Mingw has a working equivalent. It only has reversed arguments. char *Realpath(const char *_path, char *resolved_path) { return _fullpath(resolved_path,_path,260); } #else // Use the stdlib function. char *Realpath(const char *_path, char *resolved_path) { return realpath(_path, resolved_path); } #endif grafx2/src/saveini.c0000644000076400010400000005257211546416514015045 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2008 Peter Gordon 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 */ #include #include #include #include "const.h" #include "global.h" #include "readini.h" #include "io.h" #include "errors.h" #include "misc.h" #include "saveini.h" #include "setup.h" int Save_INI_reach_group(FILE * old_file,FILE * new_file,char * buffer,char * group) { int stop_seek; char * group_upper; char * upper_buffer; // On alloue les zones de mmoire: group_upper =(char *)malloc(1024); upper_buffer=(char *)malloc(1024); // On commence par se faire une version majuscule du groupe rechercher: strcpy(group_upper,group); Load_INI_clear_string(group_upper, 0); stop_seek=0; do { // On lit une ligne dans le fichier: if (fgets(buffer,1024,old_file)==0) { free(upper_buffer); free(group_upper); return ERROR_INI_CORRUPTED; } // On s'en fait une version en majuscule: strcpy(upper_buffer,buffer); Load_INI_clear_string(upper_buffer, 0); // On compare la chane avec le groupe recherch: stop_seek=Load_INI_seek_pattern(upper_buffer,group_upper); if (fprintf(new_file,"%s",buffer)<0) { free(upper_buffer); free(group_upper); return ERROR_SAVING_INI; } } while (stop_seek==0); free(upper_buffer); free(group_upper); return 0; } int Save_INI_char_in_value_alphabet(char c) { if ( ( // Digit (c>='0') && (c<='9') ) || ( // Uppercase letter (c>='A') && (c<='Z') ) || ( // Lowerchase letter (c>='a') && (c<='z') ) || (c == '$') || // Hexa prefix (c == '-') || // Minus sign (c== '.') // Dot (in filenames) ) return 1; else return 0; } void Save_INI_set_value(char * dest,char * source,int nb_values_to_set,int * values,int litteral) { int dest_index; int source_index; int value_index; // On commence par recopier tout jusqu'au symbole '=': for (source_index=0;source[source_index]!='=';source_index++) dest[source_index]=source[source_index]; // Puis on recopie le symbole '=': dest[source_index]=source[source_index]; source_index++; // Puis on recopie tous les espaces qui suivent: for (;source[source_index]==' ';source_index++) dest[source_index]=source[source_index]; // Pour l'instant, la source et la destination en sont au mme point: dest_index=source_index; // Puis pour chaque valeur recopier: for (value_index=0;value_index Yes memcpy(dest+dest_index,"yes",3); dest_index+=3; } else { // La valeur <=> No memcpy(dest+dest_index,"no",2); dest_index+=2; } } else { // La valeur doit tre crite sous forme numrique if (source[source_index]=='$') { // On va crire la valeur sous forme hexadcimale: // On commence par inscrire le symbole '$': dest[dest_index]='$'; // Puis on y concatne la valeur: sprintf(dest+dest_index+1,"%x",values[value_index]); dest_index+=strlen(dest+dest_index); } else { // On va crire la valeur sous forme dcimale: sprintf(dest+dest_index,"%d",values[value_index]); dest_index+=strlen(dest+dest_index); } } // Dans la source, on saute la valeur: for (;Save_INI_char_in_value_alphabet(source[source_index]) && (source[source_index]!='\0');source_index++); if (value_index!=(nb_values_to_set-1)) { // Il reste d'autres valeurs crire // On recopie tous les caractres de la source jusqu'au suivant qui // dsigne une valeur: for (;(!Save_INI_char_in_value_alphabet(source[source_index])) && (source[source_index]!='\0');source_index++,dest_index++) dest[dest_index]=source[source_index]; } else { // C'est la dernire valeur initialiser // On recopie toute la fin de la ligne: for (;source[source_index]!='\0';source_index++,dest_index++) dest[dest_index]=source[source_index]; // Et on n'oublie pas d'y mettre l''\0': dest[dest_index]='\0'; } } } void Save_INI_set_string(char * dest,char * source,char * value) { int dest_index; int source_index; // On commence par recopier tout jusqu'au symbole '=': for (source_index=0;source[source_index]!='=';source_index++) dest[source_index]=source[source_index]; // Puis on recopie le symbole '=': dest[source_index]=source[source_index]; source_index++; // Puis on recopie tous les espaces qui suivent: for (;source[source_index]==' ';source_index++) dest[source_index]=source[source_index]; // Pour l'instant, la source et la destination en sont au mme point: dest_index=source_index; // Dans la destination, on crit la valeur: strcpy(dest+dest_index,value); dest_index+=strlen(value); // Dans la source, on saute la valeur: for (;Save_INI_char_in_value_alphabet(source[source_index]) && (source[source_index]!='\0');source_index++); // On recopie toute la fin de la ligne: for (;source[source_index]!='\0';source_index++,dest_index++) dest[dest_index]=source[source_index]; // Et on n'oublie pas d'y mettre l''\0': dest[dest_index]='\0'; } int Save_INI_set_strings(FILE * old_file,FILE * new_file,char * buffer,char * option_name,char * value) { int stop_seek; char * option_upper; char * upper_buffer; char * result_buffer; //int buffer_index; // On alloue les zones de mmoire: option_upper=(char *)malloc(1024); upper_buffer=(char *)malloc(1024); result_buffer=(char *)malloc(1024); // On convertit un eventuel argument NULL en chaine vide. if (value == NULL) value=""; // On commence par se faire une version majuscule de l'option rechercher: strcpy(option_upper,option_name); Load_INI_clear_string(option_upper, 0); stop_seek=0; do { // On lit une ligne dans le fichier: if (fgets(buffer,1024,old_file)==0) { free(result_buffer); free(upper_buffer); free(option_upper); return ERROR_INI_CORRUPTED; } // On s'en fait une version en majuscule: strcpy(upper_buffer,buffer); Load_INI_clear_string(upper_buffer, 0); // On compare la chane avec l'option recherche: stop_seek=Load_INI_seek_pattern(upper_buffer,option_upper); if (stop_seek) { // On l'a trouve: Save_INI_set_string(result_buffer,buffer,value); if (fprintf(new_file,"%s",result_buffer)<0) { free(result_buffer); free(upper_buffer); free(option_upper); return ERROR_SAVING_INI; } } else { // On l'a pas trouve: if (fprintf(new_file,"%s",buffer)<0) { free(result_buffer); free(upper_buffer); free(option_upper); return ERROR_SAVING_INI; } } } while (stop_seek==0); free(result_buffer); free(upper_buffer); free(option_upper); return 0; } int Save_INI_set_values(FILE * old_file,FILE * new_file,char * buffer,char * option_name,int nb_values_to_set,int * values,int litteral) { int stop_seek; char * option_upper; char * upper_buffer; char * result_buffer; //int buffer_index; // On alloue les zones de mmoire: option_upper=(char *)malloc(1024); upper_buffer=(char *)malloc(1024); result_buffer=(char *)malloc(1024); // On commence par se faire une version majuscule de l'option rechercher: strcpy(option_upper,option_name); Load_INI_clear_string(option_upper, 0); stop_seek=0; do { // On lit une ligne dans le fichier: if (fgets(buffer,1024,old_file)==0) { free(result_buffer); free(upper_buffer); free(option_upper); DEBUG("END OF FILE",0); return ERROR_INI_CORRUPTED; } // On s'en fait une version en majuscule: strcpy(upper_buffer,buffer); Load_INI_clear_string(upper_buffer, 0); // On compare la chane avec l'option recherche: stop_seek=Load_INI_seek_pattern(upper_buffer,option_upper); if (stop_seek) { // On l'a trouve: Save_INI_set_value(result_buffer,buffer,nb_values_to_set,values,litteral); if (fprintf(new_file,"%s",result_buffer)<0) { free(result_buffer); free(upper_buffer); free(option_upper); return ERROR_SAVING_INI; } } else { // On l'a pas trouve: if (fprintf(new_file,"%s",buffer)<0) { free(result_buffer); free(upper_buffer); free(option_upper); return ERROR_SAVING_INI; } } } while (stop_seek==0); free(result_buffer); free(upper_buffer); free(option_upper); return 0; } void Save_INI_flush(FILE * old_file,FILE * new_file,char * buffer) { while (fgets(buffer,1024,old_file)!=0) fprintf(new_file,"%s",buffer); } int Save_INI(T_Config * conf) { FILE * old_file; FILE * new_file; char * buffer; int values[3]; char filename[MAX_PATH_CHARACTERS]; char temp_filename[MAX_PATH_CHARACTERS]; int return_code; char ref_ini_file[MAX_PATH_CHARACTERS]; int ini_file_exists; int index; // On alloue les zones de mmoire: buffer=(char *)malloc(1024); // On calcule les noms des fichiers qu'on manipule: strcpy(filename,Config_directory); strcat(filename,INI_FILENAME); // On vrifie si le fichier INI existe if ((ini_file_exists = File_exists(filename))) { strcpy(temp_filename,Config_directory); strcat(temp_filename,INISAVE_FILENAME); // Delete gfx2.$$$ remove(temp_filename); // Rename current config file as gfx2.$$$ if (rename(filename,temp_filename)!=0) { goto Erreur_ERREUR_SAUVEGARDE_INI; } } // On rcupre un fichier INI "propre" partir de gfx2def.ini strcpy(ref_ini_file,Data_directory); strcat(ref_ini_file,INIDEF_FILENAME); old_file=fopen(ref_ini_file,"rb"); if (old_file==0) { fclose(old_file); free(buffer); return ERROR_INI_MISSING; } new_file=fopen(filename,"wb"); if (new_file==0) { free(buffer); return ERROR_SAVING_INI; } if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[MOUSE]"))) goto Erreur_Retour; values[0]=conf->Mouse_sensitivity_index_x; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"X_sensitivity",1,values,0))) goto Erreur_Retour; values[0]=conf->Mouse_sensitivity_index_y; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Y_sensitivity",1,values,0))) goto Erreur_Retour; values[0]=0; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"X_correction_factor",1,values,0))) goto Erreur_Retour; values[0]=0; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Y_correction_factor",1,values,0))) goto Erreur_Retour; values[0]=(conf->Cursor)+1; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Cursor_aspect",1,values,0))) goto Erreur_Retour; if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[MENU]"))) goto Erreur_Retour; values[0]=conf->Fav_menu_colors[2].R>>2; values[1]=conf->Fav_menu_colors[2].G>>2; values[2]=conf->Fav_menu_colors[2].B>>2; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Light_color",3,values,0))) goto Erreur_Retour; values[0]=conf->Fav_menu_colors[1].R>>2; values[1]=conf->Fav_menu_colors[1].G>>2; values[2]=conf->Fav_menu_colors[1].B>>2; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Dark_color",3,values,0))) goto Erreur_Retour; values[0]=conf->Ratio; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Menu_ratio",1,values,0))) goto Erreur_Retour; if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[FILE_SELECTOR]"))) goto Erreur_Retour; values[0]=conf->Show_hidden_files?1:0; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Show_hidden_files",1,values,1))) goto Erreur_Retour; values[0]=conf->Show_hidden_directories?1:0; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Show_hidden_directories",1,values,1))) goto Erreur_Retour; /* values[0]=conf->Show_system_directories?1:0; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Show_system_directories",1,values,1))) goto Erreur_Retour; */ values[0]=conf->Timer_delay; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Preview_delay",1,values,0))) goto Erreur_Retour; values[0]=conf->Maximize_preview; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Maximize_preview",1,values,1))) goto Erreur_Retour; values[0]=conf->Find_file_fast; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Find_file_fast",1,values,0))) goto Erreur_Retour; if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[LOADING]"))) goto Erreur_Retour; values[0]=conf->Auto_set_res; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Auto_set_resolution",1,values,1))) goto Erreur_Retour; values[0]=conf->Set_resolution_according_to; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Set_resolution_according_to",1,values,0))) goto Erreur_Retour; values[0]=conf->Clear_palette; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Clear_palette",1,values,1))) goto Erreur_Retour; if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[MISCELLANEOUS]"))) goto Erreur_Retour; values[0]=conf->Display_image_limits; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Draw_limits",1,values,1))) goto Erreur_Retour; values[0]=conf->Adjust_brush_pick; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Adjust_brush_pick",1,values,1))) goto Erreur_Retour; values[0]=2-conf->Coords_rel; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Coordinates",1,values,0))) goto Erreur_Retour; values[0]=conf->Backup; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Backup",1,values,1))) goto Erreur_Retour; values[0]=conf->Max_undo_pages; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Undo_pages",1,values,0))) goto Erreur_Retour; values[0]=conf->Delay_left_click_on_slider; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Gauges_scrolling_speed_Left",1,values,0))) goto Erreur_Retour; values[0]=conf->Delay_right_click_on_slider; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Gauges_scrolling_speed_Right",1,values,0))) goto Erreur_Retour; values[0]=conf->Auto_save; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Auto_save",1,values,1))) goto Erreur_Retour; values[0]=conf->Nb_max_vertices_per_polygon; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Vertices_per_polygon",1,values,0))) goto Erreur_Retour; values[0]=conf->Fast_zoom; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Fast_zoom",1,values,1))) goto Erreur_Retour; values[0]=conf->Separate_colors; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Separate_colors",1,values,1))) goto Erreur_Retour; values[0]=conf->FX_Feedback; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"FX_feedback",1,values,1))) goto Erreur_Retour; values[0]=conf->Safety_colors; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Safety_colors",1,values,1))) goto Erreur_Retour; values[0]=conf->Opening_message; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Opening_message",1,values,1))) goto Erreur_Retour; values[0]=conf->Clear_with_stencil; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Clear_with_stencil",1,values,1))) goto Erreur_Retour; values[0]=conf->Auto_discontinuous; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Auto_discontinuous",1,values,1))) goto Erreur_Retour; values[0]=conf->Screen_size_in_GIF; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Save_screen_size_in_GIF",1,values,1))) goto Erreur_Retour; values[0]=conf->Auto_nb_used; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Auto_nb_colors_used",1,values,1))) goto Erreur_Retour; if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Default_video_mode",Mode_label(conf->Default_resolution)))) goto Erreur_Retour; values[0]=Video_mode[0].Width; values[1]=Video_mode[0].Height; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Default_window_size",2,values,0))) goto Erreur_Retour; values[0]=(conf->Mouse_merge_movement); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Merge_movement",1,values,0))) goto Erreur_Retour; values[0]=(conf->Palette_cells_X); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Palette_cells_X",1,values,0))) goto Erreur_Retour; values[0]=(conf->Palette_cells_Y); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Palette_cells_Y",1,values,0))) goto Erreur_Retour; for (index=0;indexBookmark_label[index]))) goto Erreur_Retour; if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Bookmark_directory",conf->Bookmark_directory[index]))) goto Erreur_Retour; } values[0]=(conf->Palette_vertical); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Palette_vertical",1,values,1))) goto Erreur_Retour; values[0]=conf->Window_pos_x; values[1]=conf->Window_pos_y; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Window_position",2,values,0))) goto Erreur_Retour; values[0]=(conf->Double_click_speed); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Double_click_speed",1,values,0))) goto Erreur_Retour; values[0]=(conf->Double_key_speed); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Double_key_speed",1,values,0))) goto Erreur_Retour; if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Skin_file",conf->Skin_file))) goto Erreur_Retour; if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Font_file",conf->Font_file))) goto Erreur_Retour; values[0]=(conf->Grid_XOR_color); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Grid_XOR_color",1,values,0))) goto Erreur_Retour; values[0]=(Pixel_ratio); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Pixel_ratio",1,values,0))) { DEBUG("saving pixel ratio",return_code); goto Erreur_Retour; } values[0]=0; for (index=0; indexRight_click_colorpick); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Right_click_colorpick",1,values,1))) goto Erreur_Retour; values[0]=(conf->Sync_views); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Sync_views",1,values,1))) goto Erreur_Retour; switch(conf->Swap_buttons) { case MOD_CTRL: values[0]=1; break; case MOD_ALT: values[0]=2; break; default: values[0]=0; } if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Swap_buttons",1,values,0))) goto Erreur_Retour; if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Scripts_directory",conf->Scripts_directory))) goto Erreur_Retour; values[0]=(conf->Allow_multi_shortcuts); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Allow_multi_shortcuts",1,values,1))) goto Erreur_Retour; // Insert new values here Save_INI_flush(old_file,new_file,buffer); fclose(new_file); fclose(old_file); // On efface le fichier temporaire <=> Ancienne version du .INI if (ini_file_exists) remove(temp_filename); free(buffer); return 0; // Gestion des erreurs: Erreur_Retour: fclose(new_file); fclose(old_file); free(buffer); return return_code; Erreur_ERREUR_SAUVEGARDE_INI: free(buffer); return ERROR_SAVING_INI; } grafx2/src/sdlscreen.c0000644000076400010400000002250011553125630015347 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski 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 */ #include #include #include #include #if defined(__WIN32__) #include #endif // There is no WM on the GP2X... #ifndef __GP2X__ #include #endif #include "global.h" #include "sdlscreen.h" #include "errors.h" #include "misc.h" // 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 // Intermediate update method, does only one update with the smallest // rectangle that includes all modified pixels. #define UPDATE_METHOD_CUMULATED 2 // Total screen update, for platforms that impose a Vsync on each SDL update. #define UPDATE_METHOD_FULL_PAGE 3 // UPDATE_METHOD can be set from makefile, otherwise it's selected here // depending on the platform : #ifndef UPDATE_METHOD #if defined(__macosx__) #define UPDATE_METHOD UPDATE_METHOD_FULL_PAGE #elif defined(__MINT__) #define UPDATE_METHOD UPDATE_METHOD_CUMULATED #else #define UPDATE_METHOD UPDATE_METHOD_CUMULATED #endif #endif volatile int Allow_colorcycling=1; /// Sets the new screen/window dimensions. void Set_mode_SDL(int *width, int *height, int fullscreen) { static SDL_Cursor* cur = NULL; static byte cursorData = 0; Screen_SDL=SDL_SetVideoMode(*width,*height,8,(fullscreen?SDL_FULLSCREEN:0)|SDL_RESIZABLE); if(Screen_SDL != NULL) { // 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); *width = Screen_SDL->w; *height = Screen_SDL->h; } Screen_pixels=Screen_SDL->pixels; } else { DEBUG("Error: Unable to change video mode!",0); } // Trick borrowed to Barrage (http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg737265.html) : // Showing the cursor but setting it to fully transparent allows us to get absolute mouse coordinates, // this means we can use tablet in fullscreen mode. SDL_ShowCursor(1); // Hide the SDL mouse cursor, we use our own SDL_FreeCursor(cur); cur = SDL_CreateCursor(&cursorData, &cursorData, 1,1,0,0); SDL_SetCursor(cur); } #if (UPDATE_METHOD == UPDATE_METHOD_CUMULATED) short Min_X=0; short Min_Y=0; short Max_X=10000; short Max_Y=10000; short Status_line_dirty_begin=0; short Status_line_dirty_end=0; #endif #if (UPDATE_METHOD == UPDATE_METHOD_FULL_PAGE) int update_is_required=0; #endif void Flush_update(void) { #if (UPDATE_METHOD == UPDATE_METHOD_FULL_PAGE) // Do a full screen update if (update_is_required) { SDL_UpdateRect(Screen_SDL, 0, 0, 0, 0); update_is_required=0; } #endif #if (UPDATE_METHOD == UPDATE_METHOD_CUMULATED) if (Min_X>=Max_X || Min_Y>=Max_Y) { ; // Nothing to do } else { if (Min_X<0) Min_X=0; if (Min_Y<0) Min_Y=0; SDL_UpdateRect(Screen_SDL, Min_X*Pixel_width, Min_Y*Pixel_height, Min(Screen_width-Min_X, Max_X-Min_X)*Pixel_width, Min(Screen_height-Min_Y, Max_Y-Min_Y)*Pixel_height); Min_X=Min_Y=10000; Max_X=Max_Y=0; } if (Status_line_dirty_end) { SDL_UpdateRect(Screen_SDL, (18+(Status_line_dirty_begin*8))*Menu_factor_X*Pixel_width,Menu_status_Y*Pixel_height,(Status_line_dirty_end-Status_line_dirty_begin)*8*Menu_factor_X*Pixel_width,8*Menu_factor_Y*Pixel_height); } Status_line_dirty_begin=25; Status_line_dirty_end=0; #endif } void Update_rect(short x, short y, unsigned short width, unsigned short height) { #if (UPDATE_METHOD == UPDATE_METHOD_MULTI_RECTANGLE) SDL_UpdateRect(Screen_SDL, x*Pixel_width, y*Pixel_height, width*Pixel_width, height*Pixel_height); #endif #if (UPDATE_METHOD == UPDATE_METHOD_CUMULATED) if (width==0 || height==0) { Min_X=Min_Y=0; Max_X=Max_Y=10000; } else { if (x < Min_X) Min_X = x; if (y < Min_Y) Min_Y = y; if (x+width>Max_X) Max_X=x+width; if (y+height>Max_Y) Max_Y=y+height; } #endif #if (UPDATE_METHOD == UPDATE_METHOD_FULL_PAGE) update_is_required=1; #endif } void Update_status_line(short char_pos, short width) { #if (UPDATE_METHOD == UPDATE_METHOD_MULTI_RECTANGLE) SDL_UpdateRect(Screen_SDL, (18+char_pos*8)*Menu_factor_X*Pixel_width,Menu_status_Y*Pixel_height,width*8*Menu_factor_X*Pixel_width,8*Menu_factor_Y*Pixel_height); #endif #if (UPDATE_METHOD == UPDATE_METHOD_CUMULATED) // Merge the ranges if (Status_line_dirty_end < char_pos+width) Status_line_dirty_end=char_pos+width; if (Status_line_dirty_begin > char_pos) Status_line_dirty_begin=char_pos; #endif #if (UPDATE_METHOD == UPDATE_METHOD_FULL_PAGE) (void)char_pos; // unused parameter (void)width; // unused parameter update_is_required=1; #endif } /// /// 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; byte *dest_ptr; int y; int remainder; // Support seulement des images 256 couleurs if (source->format->BytesPerPixel != 1) return NULL; if (source->w & 3) remainder=4-(source->w&3); else remainder=0; if (dest==NULL) dest=(byte *)malloc(source->w*source->h); dest_ptr=dest; src=(byte *)(source->pixels); for(y=0; y < source->h; y++) { memcpy(dest_ptr, src,source->w); dest_ptr += source->w; src += source->w + remainder; } return dest; } /// Gets the RGB 24-bit color currently associated with a palette index. SDL_Color Color_to_SDL_color(byte index) { SDL_Color color; color.r = Main_palette[index].R; color.g = Main_palette[index].G; color.b = Main_palette[index].B; color.unused = 255; return color; } /// Reads a pixel in a 8-bit SDL surface. byte Get_SDL_pixel_8(SDL_Surface *bmp, int x, int y) { return ((byte *)(bmp->pixels))[(y*bmp->pitch+x)]; } /// Writes a pixel in a 8-bit SDL surface. void Set_SDL_pixel_8(SDL_Surface *bmp, int x, int y, byte color) { ((byte *)(bmp->pixels))[(y*bmp->pitch+x)]=color; } /// Reads a pixel in a multi-byte SDL surface. dword Get_SDL_pixel_hicolor(SDL_Surface *bmp, int x, int y) { byte * ptr; switch(bmp->format->BytesPerPixel) { case 4: default: return *((dword *)((byte *)bmp->pixels+(y*bmp->pitch+x*4))); case 3: // Reading a 4-byte number starting at an address that isn't a multiple // of 2 (or 4?) is not supported on Caanoo console at least (ARM CPU) // So instead, we will read the 3 individual bytes, and re-construct the // "dword" expected by SDL. ptr = ((byte *)bmp->pixels)+(y*bmp->pitch+x*3); #ifdef SDL_LIL_ENDIAN // Read ABC, output _CBA : Most Significant Byte is zero. return (*ptr) | (*(ptr+1)<<8) | (*(ptr+2)<<16); #else // Read ABC, output ABC_ : Least Significant Byte is zero. return ((*ptr)<<24) | (*(ptr+1)<<16) | (*(ptr+2)<<8); #endif case 2: return *((word *)((byte *)bmp->pixels+(y*bmp->pitch+x*2))); } } /// Convert a SDL Palette to a grafx2 palette void Get_SDL_Palette(const SDL_Palette * sdl_palette, T_Palette palette) { int i; for (i=0; i<256; i++) { palette[i].R=sdl_palette->colors[i].r; palette[i].G=sdl_palette->colors[i].g; palette[i].B=sdl_palette->colors[i].b; } } 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); } } /// Activates or desactivates file drag-dropping in program window. void Allow_drag_and_drop(int flag) { // Inform Windows that we accept drag-n-drop events or not #ifdef __WIN32__ SDL_SysWMinfo wminfo; HWND hwnd; SDL_VERSION(&wminfo.version); SDL_GetWMInfo(&wminfo); hwnd = wminfo.window; DragAcceptFiles(hwnd,flag?TRUE:FALSE); SDL_EventState (SDL_SYSWMEVENT,flag?SDL_ENABLE:SDL_DISABLE ); #endif }grafx2/src/setup.c0000644000076400010400000001733511523551446014544 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2008 Peter Gordon 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 */ #include #include #include #include #include #if defined(__WIN32__) #include #include // Mingw's _mkdir() #elif defined(__macosx__) #import #import #elif defined(__FreeBSD__) #import #elif defined(__MINT__) #include #include #elif defined(__linux__) #include #include #endif #include "struct.h" #include "io.h" #include "setup.h" #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) // This is a random default value ... #define PATH_MAX 32768 #endif int Create_ConfigDirectory(char * config_dir) { #ifdef __WIN32__ // Mingw's mkdir has a weird name and only one argument return _mkdir(config_dir); #else return mkdir(config_dir,S_IRUSR|S_IWUSR|S_IXUSR); #endif } #if defined(__macosx__) || defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) && !defined(__VBCC__) #define ARG_UNUSED __attribute__((unused)) #else #define ARG_UNUSED #endif // Determine which directory contains the executable. // IN: Main's argv[0], some platforms need it, some don't. // OUT: Write into program_dir. Trailing / or \ is kept. // Note : in fact this is only used to check for the datafiles and fonts in // this same directory. void Set_program_directory(ARG_UNUSED const char * argv0,char * program_dir) { #undef ARG_UNUSED // MacOSX #if defined(__macosx__) CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); CFURLGetFileSystemRepresentation(url,true,(UInt8*)program_dir,MAXPATHLEN); CFRelease(url); // Append trailing slash strcat(program_dir ,"/"); // AmigaOS and alike: hard-coded volume name. #elif defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) strcpy(program_dir,"PROGDIR:"); #elif defined(__MINT__) static char path[1024]={0}; char currentDrive='A'; currentDrive=currentDrive+Dgetdrv(); Dgetpath(path,0); sprintf(program_dir,"%c:\%s",currentDrive,path); // Append trailing slash strcat(program_dir,PATH_SEPARATOR); // Linux: argv[0] unreliable #elif defined(__linux__) if (argv0[0]!='/') { char path[PATH_MAX]; readlink("/proc/self/exe", path, sizeof(path)); Extract_path(program_dir, path); return; } Extract_path(program_dir, argv0); // Others: The part of argv[0] before the executable name. // Keep the last \ or /. // On Windows, Mingw32 already provides the full path in all cases. #else Extract_path(program_dir, argv0); #endif } // Determine which directory contains the read-only data. // IN: The directory containing the executable // OUT: Write into data_dir. Trailing / or \ is kept. void Set_data_directory(const char * program_dir, char * data_dir) { // On all platforms, data is relative to the executable's directory strcpy(data_dir,program_dir); // On MacOSX, it is stored in a special folder: #if defined(__macosx__) strcat(data_dir,"Contents/Resources/"); // On GP2X, executable is not in bin/ #elif defined (__GP2X__) || defined (__gp2x__) || defined (__WIZ__) || defined (__CAANOO__) strcat(data_dir,"share/grafx2/"); //on tos the same directory #elif defined (__MINT__) strcpy(data_dir, program_dir); // All other targets, program is in a "bin" subdirectory #elif defined (__AROS__) strcat(data_dir,"/share/grafx2/"); #else strcat(data_dir,"../share/grafx2/"); #endif } // Determine which directory should store the user's configuration. // // For most Unix and Windows platforms: // If a config file already exists in program_dir, it will return it in priority // (Useful for development, and possibly for upgrading from DOS version) // If the standard directory doesn't exist yet, this function will attempt // to create it ($(HOME)/.grafx2, or %APPDATA%\GrafX2) // If it cannot be created, this function will return the executable's // own directory. // IN: The directory containing the executable // OUT: Write into config_dir. Trailing / or \ is kept. void Set_config_directory(const char * program_dir, char * config_dir) { // AmigaOS4 #if defined(__amigaos4__) || defined(__AROS__) strcpy(config_dir,"PROGDIR:"); // GP2X #elif defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) // On the GP2X, the program is installed to the sdcard, and we don't want to mess with the system tree which is // on an internal flash chip. So, keep these settings locals. strcpy(config_dir,program_dir); #elif defined(__MINT__) strcpy(config_dir,program_dir); #else char filename[MAX_PATH_CHARACTERS]; // In priority: check root directory strcpy(config_dir, program_dir); // On all the remaining targets except OSX, the executable is in ./bin #if !defined(__macosx__) strcat(config_dir, "../"); #endif strcpy(filename, config_dir); strcat(filename, CONFIG_FILENAME); if (!File_exists(filename)) { char *config_parent_dir; #if defined(__WIN32__) // "%APPDATA%\GrafX2" const char* Config_SubDir = "GrafX2"; config_parent_dir = getenv("APPDATA"); #elif defined(__BEOS__) || defined(__HAIKU__) // "~/.grafx2", the BeOS way const char* Config_SubDir = ".grafx2"; config_parent_dir = getenv("$HOME"); #elif defined(__macosx__) // "~/Library/Preferences/com.googlecode.grafx2" const char* Config_SubDir = "Library/Preferences/com.googlecode.grafx2"; config_parent_dir = getenv("HOME"); #elif defined(__MINT__) const char* Config_SubDir = ""; printf("GFX2.CFG not found in %s\n",filename); strcpy(config_parent_dir, config_dir); #else // "~/.grafx2" const char* Config_SubDir = ".grafx2"; config_parent_dir = getenv("HOME"); #endif if (config_parent_dir && config_parent_dir[0]!='\0') { int size = strlen(config_parent_dir); strcpy(config_dir, config_parent_dir); if (config_parent_dir[size-1] != '\\' && config_parent_dir[size-1] != '/') { strcat(config_dir,PATH_SEPARATOR); } strcat(config_dir,Config_SubDir); if (Directory_exists(config_dir)) { // Rpertoire trouv, ok strcat(config_dir,PATH_SEPARATOR); } else { // Tentative de cration if (!Create_ConfigDirectory(config_dir)) { // Russi strcat(config_dir,PATH_SEPARATOR); } else { // Echec: on se rabat sur le repertoire de l'executable. strcpy(config_dir,program_dir); #if defined(__macosx__) strcat(config_dir, "../"); #endif } } } } #endif } grafx2/src/shade.c0000644000076400010400000010323511522560062014454 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ #include #include #include "global.h" #include "graph.h" #include "engine.h" #include "errors.h" #include "misc.h" #include "readline.h" #include "help.h" #include "sdlscreen.h" #include "windows.h" #include "input.h" #include "shade.h" void Button_Shade_mode(void) { if (Shade_mode) Effect_function=No_effect; else { Effect_function=Effect_shade; Quick_shade_mode=0; Colorize_mode=0; Smooth_mode=0; Tiling_mode=0; Smear_mode=0; } Shade_mode=!Shade_mode; } void Button_Quick_shade_mode(void) { if (Quick_shade_mode) Effect_function=No_effect; else { Effect_function=Effect_quick_shade; Shade_mode=0; Colorize_mode=0; Smooth_mode=0; Tiling_mode=0; Smear_mode=0; } Quick_shade_mode=!Quick_shade_mode; } void Shade_draw_grad_ranges(void) { word cursor=0; word nb_shades=0; short shade_processed,shade_processed_old; word shade_size=0; word start_shade=0; short x_pos,y_pos; short x_size,y_size; short start_x,start_y,end_x,end_y; // On commence par compter le nombre de shades while (cursor<512) { while ((cursor<512) && (Shade_list[Shade_current].List[cursor]&0xFF00)) cursor++; if (cursor<512) { nb_shades++; while ( (cursor<512) && (!(Shade_list[Shade_current].List[cursor]&0xFF00)) ) cursor++; } } // Maintenant qu'on sait combien il y en a, on les affiche: if (nb_shades) { x_size=Menu_factor_X<<6; y_size=Menu_factor_Y*48; start_x=Window_pos_X+(Menu_factor_X*224); start_y=Window_pos_Y+(Menu_factor_Y*35); end_x=start_x+x_size; end_y=start_y+y_size; cursor=0; shade_processed_old=-1; for (y_pos=start_y;y_posshade_processed_old) { // On commence par sauter tous les vides jusqu'au prochain shade while ((cursor<512) && (Shade_list[Shade_current].List[cursor]&0xFF00)) cursor++; start_shade=cursor; // puis regarde sa taille while ((cursor<512) && (!(Shade_list[Shade_current].List[cursor]&0xFF00))) cursor++; shade_size=cursor-start_shade; shade_processed_old=shade_processed; } for (x_pos=start_x;x_pos=selection_start) && (position<=selection_end)) { Block(x_pos,y_pos,Menu_factor_X<<2,Menu_factor_Y,MC_White); Block(x_pos,y_pos+Menu_factor_Y,Menu_factor_X<<2,Menu_factor_Y,MC_Black); } else Block(x_pos,y_pos,Menu_factor_X<<2,Menu_factor_Y<<1,MC_White); } else // "enable" { if ((position>=selection_start) && (position<=selection_end)) Block(x_pos,y_pos,Menu_factor_X<<2,Menu_factor_Y<<1,MC_Black); else Block(x_pos,y_pos,Menu_factor_X<<2,Menu_factor_Y<<1,MC_Light); } } Update_rect(Window_pos_X+8*Menu_factor_X,Window_pos_Y+131*Menu_factor_Y,Menu_factor_X*64<<2,Menu_factor_Y*8<<3); } void Display_selected_cell_color(word selection_start,word selection_end) { char str[4]; if ((selection_start!=selection_end) || (Shade_list[Shade_current].List[selection_start]&0x0100)) strcpy(str," "); else Num2str(Shade_list[Shade_current].List[selection_start]&0xFF,str,3); Print_in_window(213,115,str,MC_Black,MC_Light); } void Display_selected_color(word selection_start,word selection_end) { char str[4]; if (selection_start!=selection_end) strcpy(str," "); else Num2str(selection_start,str,3); Print_in_window(213,106,str,MC_Black,MC_Light); } void Display_shade_mode(short x,short y,byte mode) { char str[7]; switch (mode) { case SHADE_MODE_NORMAL : strcpy(str,"Normal"); break; case SHADE_MODE_LOOP : strcpy(str," Loop "); break; default : // SHADE_MODE_NOSAT strcpy(str,"No sat"); } Print_in_window(x,y,str,MC_Black,MC_Light); } void Display_all_shade(word selection_start1,word selection_end1, word selection_start2,word selection_end2) { word line, column; word position; for (line=0; line<8; line++) for (column=0; column<64; column++) { position=(line<<6)+column; // On regarde si c'est une couleur ou un bloc vide if (Shade_list[Shade_current].List[position]&0x0100) // Vide { Window_display_frame_out((column<<2)+8,(line*7)+127,4,4); Block(Window_pos_X+(Menu_factor_X*((column<<2)+9)), Window_pos_Y+(Menu_factor_Y*((line*7)+128)), Menu_factor_X<<1,Menu_factor_Y<<1,MC_Light); } else // color Block(Window_pos_X+(Menu_factor_X*((column<<2)+8)), Window_pos_Y+(Menu_factor_Y*((line*7)+127)), Menu_factor_X<<2,Menu_factor_Y<<2, Shade_list[Shade_current].List[position]&0xFF); } Update_rect(Window_pos_X+7*Menu_factor_X,Window_pos_Y+126*Menu_factor_Y,Menu_factor_X*((64<<2)+2),Menu_factor_Y*((8<<2)+2)); Tag_shades(selection_start2,selection_end2); Shade_draw_grad_ranges(); Display_selected_cell_color(selection_start2,selection_end2); Display_selected_color(selection_start1,selection_end1); Display_shade_mode(250,110,Shade_list[Shade_current].Mode); } void Remove_shade(word selection_start,word selection_end) { word temp; if (selection_end=512) temp=512-selection_start; for (cursor=511;cursor>=limit;cursor--) Shade_list[Shade_current].List[cursor]=Shade_list[Shade_current].List[cursor-temp]; for (cursor=selection_start+temp;selection_start=512) return; for (cursor=511;cursor>position;cursor--) Shade_list[Shade_current].List[cursor]=Shade_list[Shade_current].List[cursor-1]; Shade_list[Shade_current].List[position]=0x0100; } short Wait_click_in_shade_table() { short selected_cell=-1; byte old_hide_cursor; Hide_cursor(); old_hide_cursor=Cursor_hidden; Cursor_hidden=0; Cursor_shape=CURSOR_SHAPE_TARGET; Display_cursor(); while (selected_cell<0) { Get_input(20); if ( (Mouse_K==LEFT_SIDE) && ( ( (Window_click_in_rectangle(8,127,263,179)) && (((((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-127)%7)<4) ) || ( (Mouse_X=Window_pos_X+(Window_width*Menu_factor_X)) || (Mouse_Y>=Window_pos_Y+(Window_height*Menu_factor_Y)) ) ) ) selected_cell=(((((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-127)/7)<<6)+ ((((Mouse_X-Window_pos_X)/Menu_factor_X)-8 )>>2); if ((Mouse_K==RIGHT_SIDE) || (Key==KEY_ESC)) selected_cell=512; // valeur indiquant que l'on n'a rien choisi } Hide_cursor(); Cursor_shape=CURSOR_SHAPE_ARROW; Cursor_hidden=old_hide_cursor; Display_cursor(); return selected_cell; } void Swap_shade(short block_1_start,short block_2_start,short block_size) { short pos_1; short pos_2; short end_1; short end_2; word temp; word * temp_shade; // On fait une copie de la liste temp_shade=(word *)malloc(512*sizeof(word)); memcpy(temp_shade,Shade_list[Shade_current].List,512*sizeof(word)); // On calcul les dernires couleurs de chaque bloc. end_1=block_1_start+block_size-1; end_2=block_2_start+block_size-1; if ((block_2_start>=block_1_start) && (block_2_start<=end_1)) { // Le bloc destination commence dans le bloc source. for (pos_1=block_1_start,pos_2=end_1+1;pos_1<=end_2;pos_1++) { // Il faut transformer la case pos_1 en pos_2: Shade_list[Shade_current].List[pos_1]=temp_shade[pos_2]; // On gre la mise jour de pos_2 if (pos_2==end_2) pos_2=block_1_start; else pos_2++; } } else if ((block_2_start=block_1_start)) { // Le bloc destination dborde dans le bloc source. for (pos_1=block_2_start,pos_2=block_1_start;pos_1<=end_1;pos_1++) { // Il faut transformer la couleur pos_1 en pos_2: Shade_list[Shade_current].List[pos_1]=temp_shade[pos_2]; // On gre la mise jour de pos_2 if (pos_2==end_1) pos_2=block_2_start; else pos_2++; } } else { // Le bloc source et le bloc destination sont distincts. for (pos_1=block_1_start,pos_2=block_2_start;pos_1<=end_1;pos_1++,pos_2++) { // On change les cases temp =Shade_list[Shade_current].List[pos_1]; Shade_list[Shade_current].List[pos_1]=Shade_list[Shade_current].List[pos_2]; Shade_list[Shade_current].List[pos_2]=temp; } } free(temp_shade); } int Menu_shade(void) { short clicked_button; // Numro du bouton sur lequel l'utilisateur a click char str[4]; // str d'affichage du n de shade actif et du Pas word old_mouse_x, old_mouse_x2; // Mmo. de l'ancienne pos. du curseur word old_mouse_y, old_mouse_y2; byte old_mouse_k, old_mouse_k2; byte temp_color; // Variables de gestion des clicks dans la palette byte first_color = Fore_color; byte last_color = Fore_color; word selection_start = 0; word selection_end = 0; T_Special_button * input_button; short temp, temp2; word temp_cell; word * buffer; // buffer du Copy/Paste word * undo_buffer; // buffer du Undo word * temp_ptr; byte color; byte click; buffer =(word *)malloc(512*sizeof(word)); undo_buffer =(word *)malloc(512*sizeof(word)); temp_ptr=(word *)malloc(512*sizeof(word)); // Ouverture de la fentre du menu Open_window(310,190,"Shade"); // Dclaration & trac du bouton de palette Window_set_palette_button(5,16); // 1 // Dclaration & trac du scroller de slection du n de dgrad Window_set_scroller_button(192,17,84,8,1,Shade_current); // 2 // Dclaration & trac de la zone de dfinition des dgrads Window_set_special_button(8,127,256,53); // 3 // Dclaration & trac des boutons de sortie Window_set_normal_button(207,17,51,14,"Cancel",0,1,KEY_ESC); // 4 Window_set_normal_button(261,17,43,14,"OK" ,0,1,SDLK_RETURN); // 5 // Dclaration & trac des boutons de copie de shade Window_set_normal_button(206,87,27,14,"Cpy" ,1,1,SDLK_c); // 6 Window_set_normal_button(234,87,43,14,"Paste" ,1,1,SDLK_p); // 7 // On tagge le bloc Tag_color_range(Fore_color,Fore_color); // Trac d'un cadre creux autour du bloc dgrad Window_display_frame_in(171,26,18,66); Block(Window_pos_X+(Menu_factor_X*172),Window_pos_Y+(Menu_factor_Y*27), Menu_factor_X<<4,Menu_factor_Y<<6,MC_Black); // Trac d'un cadre creux autour de tous les dgrads Window_display_frame_in(223,34,66,50); Shade_draw_grad_ranges(); // Trac d'un cadre autour de la zone de dfinition de dgrads Window_display_frame(5,124,262,61); Display_all_shade(first_color,last_color,selection_start,selection_end); // Dclaration & trac des boutons d'dition de shade Window_set_normal_button( 6,107,27,14,"Ins" ,0,1,SDLK_INSERT); // 8 Window_set_normal_button( 38,107,27,14,"Del" ,0,1,SDLK_DELETE); // 9 Window_set_normal_button( 66,107,43,14,"Blank",1,1,SDLK_b); // 10 Window_set_normal_button(110,107,27,14,"Inv" ,1,1,SDLK_i); // 11 Window_set_normal_button(138,107,27,14,"Swp" ,1,1,SDLK_s); // 12 // Dclaration & trac des boutons de taggage Print_in_window(268,123,"Disbl"/*"Dsabl"*/,MC_Dark,MC_Light); Window_set_normal_button(274,133,27,14,"Set" ,0,1,SDLK_F1); // 13 Window_set_normal_button(274,148,27,14,"Clr" ,0,1,SDLK_F2); // 14 // Dclaration & trac de la zone de saisie du pas Print_in_window(272,165,"Step",MC_Dark,MC_Light); input_button = Window_set_input_button(274,174,3); // 15 Num2str(Shade_list[Shade_current].Step,str,3); Window_input_content(input_button,str); // Button Undo Window_set_normal_button(170,107,35,14,"Undo",1,1,SDLK_u); // 16 // Button Clear Window_set_normal_button(278,87,27,14,"Clr",0,1,SDLK_BACKSPACE); // 17 // Button Mode Window_set_normal_button(244,107,60,14,"",0,1,SDLK_TAB); // 18 // Affichage du n de shade actif Num2str(Shade_current+1,str,1); Print_in_window(210,55,str,MC_Black,MC_Light); memcpy(buffer ,Shade_list[Shade_current].List,512*sizeof(word)); memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); Update_rect(Window_pos_X,Window_pos_Y,Menu_factor_X*310,Menu_factor_Y*190); Display_cursor(); do { old_mouse_x=old_mouse_x2=Mouse_X; old_mouse_y=old_mouse_y2=Mouse_Y; old_mouse_k=old_mouse_k2=Mouse_K; clicked_button=Window_clicked_button(); switch (clicked_button) { case 0 : break; case -1 : case 1 : // Gestion de la palette if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) ) { Hide_cursor(); temp_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); if (!old_mouse_k) { // On vient de clicker // On met jour l'intervalle du Shade first_color=last_color=temp_color; // On tagge le bloc Tag_color_range(first_color,last_color); // Trac du bloc dgrad: Display_grad_block_in_window(172,27,first_color,last_color); } else { // On maintient le click, on va donc tester si le curseur bouge if (temp_color!=last_color) { last_color=temp_color; // On tagge le bloc if (first_color<=temp_color) { Tag_color_range(first_color,last_color); Display_grad_block_in_window(172,27,first_color,last_color); } else { Tag_color_range(last_color,first_color); Display_grad_block_in_window(172,27,last_color,first_color); } } } // On affiche le numro de la couleur slectionne Display_selected_color(first_color,last_color); Display_cursor(); } break; case 2 : // Gestion du changement de Shade (scroller) Hide_cursor(); Shade_current=Window_attribute2; // Affichade du n de shade actif Num2str(Shade_current+1,str,1); Print_in_window(210,55,str,MC_Black,MC_Light); // Affichade du Pas Num2str(Shade_list[Shade_current].Step,str,3); Print_in_window(276,176,str,MC_Black,MC_Light); // Trac du bloc dgrad: Display_all_shade(first_color,last_color,selection_start,selection_end); Display_cursor(); // On place le nouveau shade dans le buffer du Undo memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); break; case 3 : // Gestion de la zone de dfinition de shades if (((((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-127)%7)<4) if ( (Mouse_X!=old_mouse_x2) || (Mouse_Y!=old_mouse_y2) || (Mouse_K!=old_mouse_k2) ) { Hide_cursor(); selection_end=(((((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-127)/7)<<6)+ ((((Mouse_X-Window_pos_X)/Menu_factor_X)-8 )>>2); if (!old_mouse_k2) // On vient de clicker selection_start=selection_end; Tag_shades(selection_start,selection_end); Display_selected_cell_color(selection_start,selection_end); Display_cursor(); } break; case 5: // Ok if (selection_start == selection_end && Shade_list[Shade_current].List[selection_start] > 0) Set_fore_color(Shade_list[Shade_current].List[selection_start]); else if (first_color == last_color) Set_fore_color(first_color); break; case 6 : // Copy memcpy(buffer,Shade_list[Shade_current].List,512*sizeof(word)); break; case 7 : // Paste // On place le shade dans le buffer du Undo memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); // Et on le modifie memcpy(Shade_list[Shade_current].List,buffer,512*sizeof(word)); Hide_cursor(); Display_all_shade(first_color,last_color,selection_start,selection_end); Display_cursor(); break; case 8 : // Insert // On place le shade dans le buffer du Undo memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); // Et on le modifie if (first_color<=last_color) temp=last_color-first_color; else temp=first_color-last_color; if (selection_start==selection_end) // Une couleur slectionne { if (Window_attribute1==2) Remove_shade(selection_start,selection_start+temp); } else // Un bloc slectionn { Remove_shade(selection_start,selection_end); if (first_color<=last_color) temp=last_color-first_color; else temp=first_color-last_color; if (selection_start=512) selection_start=511; selection_end=selection_start; Hide_cursor(); Display_all_shade(first_color,last_color,selection_start,selection_end); Display_cursor(); break; case 9 : // Delete // On place le shade dans le buffer du Undo memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); // Et on le modifie Remove_shade(selection_start,selection_end); if (selection_start<=selection_end) selection_end=selection_start; else selection_start=selection_end; Hide_cursor(); Display_all_shade(first_color,last_color,selection_start,selection_end); Display_cursor(); break; case 10 : // Blank // On place le shade dans le buffer du Undo memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); // Et on le modifie if (Window_attribute1==RIGHT_SIDE) // Click droit { if (selection_start!=selection_end) { if (selection_start<=selection_end) { Insert_empty_cell_in_shade(selection_start); Insert_empty_cell_in_shade(selection_end+2); } else { Insert_empty_cell_in_shade(selection_end); Insert_empty_cell_in_shade(selection_start+2); } } else Insert_empty_cell_in_shade(selection_start); if (selection_start<511) selection_start++; if (selection_end<511) selection_end++; } else // Click gauche { if (selection_start<=selection_end) { temp=selection_start; temp2=selection_end; } else { temp=selection_end; temp2=selection_start; } while (temp<=temp2) Shade_list[Shade_current].List[temp++]=0x0100; } Hide_cursor(); Display_all_shade(first_color,last_color,selection_start,selection_end); Display_cursor(); break; case 11 : // Invert // On place le shade dans le buffer du Undo memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); // Et on le modifie if (selection_start<=selection_end) { temp=selection_start; temp2=selection_end; } else { temp=selection_end; temp2=selection_start; } for (;temp255) { temp=255; Num2str(temp,str,3); Window_input_content(input_button,str); } Shade_list[Shade_current].Step=temp; Display_cursor(); break; case 16 : // Undo memcpy(temp_ptr,undo_buffer,512*sizeof(word)); memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); memcpy(Shade_list[Shade_current].List,temp_ptr,512*sizeof(word)); Hide_cursor(); Display_all_shade(first_color,last_color,selection_start,selection_end); Display_cursor(); break; case 17 : // Clear memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); for (temp=0;temp<512;temp++) Shade_list[Shade_current].List[temp]=0x0100; Hide_cursor(); Display_all_shade(first_color,last_color,selection_start,selection_end); Display_cursor(); break; case 18 : // Mode Shade_list[Shade_current].Mode=(Shade_list[Shade_current].Mode+1)%3; Hide_cursor(); Display_shade_mode(250,110,Shade_list[Shade_current].Mode); Display_cursor(); } if (!Mouse_K) switch (Key) { case SDLK_LEFTBRACKET : // Dcaler couleur dans palette vers la gauche case SDLK_RIGHTBRACKET : // Dcaler couleur dans palette vers la droite if (first_color==last_color) { if (Key==SDLK_LEFTBRACKET) { first_color--; last_color--; } else { first_color++; last_color++; } Hide_cursor(); Tag_color_range(first_color,first_color); Block(Window_pos_X+(Menu_factor_X*172), Window_pos_Y+(Menu_factor_Y*27), Menu_factor_X<<4,Menu_factor_Y*64,first_color); // On affiche le numro de la couleur slectionne Display_selected_color(first_color,last_color); Display_cursor(); } Key=0; break; case SDLK_UP : // Select Haut case SDLK_DOWN : // Select Bas case SDLK_LEFT : // Select Gauche case SDLK_RIGHT : // Select Droite if (selection_start==selection_end) { switch (Key) { case SDLK_UP : // Select Haut if (selection_start>=64) { selection_start-=64; selection_end-=64; } else selection_start=selection_end=0; break; case SDLK_DOWN : // Select Bas if (selection_start<448) { selection_start+=64; selection_end+=64; } else selection_start=selection_end=511; break; case SDLK_LEFT : // Select Gauche if (selection_start>0) { selection_start--; selection_end--; } break; default : // Select Droite if (selection_start<511) { selection_start++; selection_end++; } } Hide_cursor(); Tag_shades(selection_start,selection_start); Display_selected_cell_color(selection_start,selection_start); Display_cursor(); } Key=0; break; case SDLK_BACKQUOTE : // Rcupration d'une couleur derrire le menu case SDLK_COMMA : Get_color_behind_window(&color,&click); if (click) { Hide_cursor(); temp_color=color; // On met jour l'intervalle du Shade first_color=last_color=temp_color; // On tagge le bloc Tag_color_range(first_color,last_color); // Trac du bloc dgrad: Display_grad_block_in_window(172,27,first_color,last_color); // On affiche le numro de la couleur slectionne Display_selected_color(first_color,last_color); Display_cursor(); Wait_end_of_click(); } Key=0; break; default: if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Key=0; Window_help(BUTTON_EFFECTS, "SHADE"); } else if (Is_shortcut(Key,SPECIAL_SHADE_MENU)) clicked_button=5; } } while ((clicked_button!=4) && (clicked_button!=5)); Close_window(); free(undo_buffer); free(buffer); free(temp_ptr); return (clicked_button==5); } /// Handles the screen with Shade settings. /// @return true if user clicked ok, false if he cancelled int Shade_settings_menu(void) { T_Shade * initial_shade_list; // Anciennes donnes des shades byte old_shade; // old n de shade actif int return_code; // Backup des anciennes donnes initial_shade_list=(T_Shade *)malloc(sizeof(Shade_list)); memcpy(initial_shade_list,Shade_list,sizeof(Shade_list)); old_shade=Shade_current; return_code = Menu_shade(); if (!return_code) // Cancel { memcpy(Shade_list,initial_shade_list,sizeof(Shade_list)); Shade_current=old_shade; } else // OK { Shade_list_to_lookup_tables(Shade_list[Shade_current].List, Shade_list[Shade_current].Step, Shade_list[Shade_current].Mode, Shade_table_left,Shade_table_right); } free(initial_shade_list); Display_cursor(); return return_code; } void Button_Shade_menu(void) { if (Shade_settings_menu()) { // If user clicked OK while in the menu, activate Shade mode. if (!Shade_mode) Button_Shade_mode(); } } void Button_Quick_shade_menu(void) { short clicked_button; int temp; char str[4]; byte step_backup=Quick_shade_step; // Backup des byte loop_backup=Quick_shade_loop; // anciennes donnes T_Special_button * step_button; Open_window(142,56,"Quick-shade"); Window_set_normal_button(76,36,60,14,"OK",0,1,SDLK_RETURN); // 1 Window_set_normal_button( 6,36,60,14,"Cancel",0,1,KEY_ESC); // 2 Window_set_normal_button(76,18,60,14,"",0,1,SDLK_TAB); // 3 Display_shade_mode(83,21,Quick_shade_loop); // Dclaration & trac de la zone de saisie du pas Print_in_window(5,21,"Step",MC_Dark,MC_Light); step_button = Window_set_input_button(40,19,3); // 4 Num2str(Quick_shade_step,str,3); Window_input_content(step_button,str); Update_rect(Window_pos_X,Window_pos_Y,Menu_factor_X*142,Menu_factor_Y*56); Display_cursor(); do { clicked_button=Window_clicked_button(); switch (clicked_button) { case 3 : // Mode Quick_shade_loop=(Quick_shade_loop+1)%3; Hide_cursor(); Display_shade_mode(83,21,Quick_shade_loop); Display_cursor(); break; case 4 : // Saisie du pas Num2str(Quick_shade_step,str,3); Readline(42,21,str,3,INPUT_TYPE_INTEGER); temp=atoi(str); // On corrige le pas if (!temp) { temp=1; Num2str(temp,str,3); Window_input_content(step_button,str); } else if (temp>255) { temp=255; Num2str(temp,str,3); Window_input_content(step_button,str); } Quick_shade_step=temp; Display_cursor(); } if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_EFFECTS, "QUICK SHADE"); else if (Is_shortcut(Key,SPECIAL_QUICK_SHADE_MENU)) clicked_button=1; } while ((clicked_button!=1) && (clicked_button!=2)); Close_window(); if (clicked_button==2) // Cancel { Quick_shade_step=step_backup; Quick_shade_loop=loop_backup; } else // OK { // Si avant de rentrer dans le menu on n'tait pas en mode Quick-Shade if (!Quick_shade_mode) Button_Quick_shade_mode(); // => On y passe (cool!) } Display_cursor(); } grafx2/src/special.c0000644000076400010400000003201211522560062015002 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ #include #include #include "const.h" #include "struct.h" #include "global.h" #include "graph.h" #include "engine.h" #include "windows.h" #include "special.h" #include "pages.h" #include "misc.h" #include "buttons.h" //---------------------- Modifier le pinceau spcial ------------------------- int Circle_squared_diameter(int diameter) { int result = diameter*diameter; // Trick to make some circles rounder, even though // mathematically incorrect. if (diameter==3 || diameter==9) return result-2; if (diameter==11) return result-6; if (diameter==14) return result-4; return result; } void Set_paintbrush_size(int width, int height) { int x_pos,y_pos; int x,y; int radius2; if (width<1) width=1; if (height<1) height=1; if (width>MAX_PAINTBRUSH_SIZE) width=MAX_PAINTBRUSH_SIZE; if (height>MAX_PAINTBRUSH_SIZE) height=MAX_PAINTBRUSH_SIZE; Paintbrush_width=width; Paintbrush_height=height; Paintbrush_offset_X=Paintbrush_width>>1; Paintbrush_offset_Y=Paintbrush_height>>1; switch (Paintbrush_shape) { case PAINTBRUSH_SHAPE_ROUND : radius2=Circle_squared_diameter(Paintbrush_width); for (y_pos=0, y=1-Paintbrush_height; y_pos>1; for (y_pos=0; y_pos>1; for (y_pos=0; y_pos>1; for (y_pos=0; y_pos>1; for (y_pos=0; y_pos>1; for (y_pos=0; y_pos0) Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)+x_pos-1]=0; if (y_pos>0) Paintbrush_sprite[((y_pos-1)*MAX_PAINTBRUSH_SIZE)+x_pos]=0; } } } } void Smaller_paintbrush(void) { if ( (Paintbrush_shape1) || (Paintbrush_height>1) ) ) { Hide_cursor(); switch (Paintbrush_shape) { case PAINTBRUSH_SHAPE_CROSS: case PAINTBRUSH_SHAPE_PLUS: case PAINTBRUSH_SHAPE_DIAMOND: if (Paintbrush_width&1) Set_paintbrush_size(Paintbrush_width-2,Paintbrush_height-2); else Set_paintbrush_size(Paintbrush_width-1,Paintbrush_height-1); break; case PAINTBRUSH_SHAPE_SQUARE: case PAINTBRUSH_SHAPE_SLASH: case PAINTBRUSH_SHAPE_ANTISLASH: case PAINTBRUSH_SHAPE_SIEVE_SQUARE: case PAINTBRUSH_SHAPE_ROUND: case PAINTBRUSH_SHAPE_SIEVE_ROUND: case PAINTBRUSH_SHAPE_RANDOM: Set_paintbrush_size(Paintbrush_width-1,Paintbrush_height-1); break; case PAINTBRUSH_SHAPE_HORIZONTAL_BAR: Set_paintbrush_size(Paintbrush_width-1,1); break; case PAINTBRUSH_SHAPE_VERTICAL_BAR: Set_paintbrush_size(1,Paintbrush_height-1); } Display_paintbrush_in_menu(); Display_cursor(); } } void Bigger_paintbrush(void) { if ( (Paintbrush_shapeMain_image_width) temp_x_offset=Main_image_width-Screen_width; if (temp_y_offset+Menu_Y>Main_image_height) temp_y_offset=Main_image_height-Menu_Y; if (temp_x_offset<0) temp_x_offset=0; if (temp_y_offset<0) temp_y_offset=0; if ( (Main_offset_X!=temp_x_offset) || (Main_offset_Y!=temp_y_offset) ) { Hide_cursor(); Main_offset_X=temp_x_offset; Main_offset_Y=temp_y_offset; Compute_limits(); Compute_paintbrush_coordinates(); Display_all_screen(); // <=> Display_screen + Display_image_limits Display_cursor(); } } // ---------------------- Scroller la fentre de la loupe -------------------- void Scroll_magnifier(short delta_x,short delta_y) { short temp_x_offset; short temp_y_offset; temp_x_offset=Main_magnifier_offset_X+delta_x; temp_y_offset=Main_magnifier_offset_Y+delta_y; Clip_magnifier_offsets(&temp_x_offset, &temp_y_offset); if ( (Main_magnifier_offset_X!=temp_x_offset) || (Main_magnifier_offset_Y!=temp_y_offset) ) { Hide_cursor(); Main_magnifier_offset_X=temp_x_offset; Main_magnifier_offset_Y=temp_y_offset; Position_screen_according_to_zoom(); Compute_limits(); Compute_paintbrush_coordinates(); Display_all_screen(); Display_cursor(); } } // -------------- Changer le Zoom (grce aux touches [+] et [-]) ------------- void Zoom(short delta) { short index; for (index=0; ZOOM_FACTOR[index]!=Main_magnifier_factor; index++); index+=delta; if ( (index>=0) && (index */ // Pour dsactiver le support TrueType, dfinir NOTTF // To disable TrueType support, define NOTTF #include #include #include // tolower() // TrueType #ifndef NOTTF #if defined(__macosx__) #include #else #include #endif #if defined(__CAANOO__) || defined(__WIZ__) || defined(__GP2X__) // No X11 #elif defined(__linux__) #include #endif #endif #if defined(__macosx__) #include #import #import #endif #include #include "SFont.h" #include "struct.h" #include "global.h" #include "sdlscreen.h" #include "io.h" #include "errors.h" #include "windows.h" #include "misc.h" #include "setup.h" typedef struct T_Font { char * Name; int Is_truetype; int Is_bitmap; char Label[22]; // Liste chaine simple struct T_Font * Next; struct T_Font * Previous; } T_Font; // Liste chaine des polices de texte T_Font * font_list_start; int Nb_fonts; // Inspir par Allegro #define EXTID(a,b,c) ((((a)&255)<<16) | (((b)&255)<<8) | (((c)&255))) #define EXTID4(a,b,c,d) ((((a)&255)<<24) | (((b)&255)<<16) | (((c)&255)<<8) | (((d)&255))) int Compare_fonts(T_Font * font_1, T_Font * font_2) { if (font_1->Is_bitmap && !font_2->Is_bitmap) return -1; if (font_2->Is_bitmap && !font_1->Is_bitmap) return 1; return strcmp(font_1->Label, font_2->Label); } // Ajout d'une fonte la liste. void Add_font(const char *name) { char * font_name; T_Font * font; int size=strlen(name)+1; int index; // Dtermination du type: #if defined(__macosx__) if (size < 6) return; char strFontName[512]; CFStringRef CFSFontName;// = CFSTR(name); CFSFontName = CFStringCreateWithBytes(NULL, (UInt8 *) name, size - 1, kCFStringEncodingASCII, false); // Fix some funny names CFStringGetCString(CFSFontName, strFontName, 512, kCFStringEncodingASCII); // Now we have a printable font name, use it name = strFontName; #else if (size<5 || name[size-5]!='.') return; #endif font = (T_Font *)malloc(sizeof(T_Font)); switch (EXTID(tolower(name[size-4]), tolower(name[size-3]), tolower(name[size-2]))) { case EXTID('t','t','f'): case EXTID('f','o','n'): case EXTID('o','t','f'): case EXTID('p','f','b'): font->Is_truetype = 1; font->Is_bitmap = 0; break; case EXTID('b','m','p'): case EXTID('g','i','f'): case EXTID('j','p','g'): case EXTID('l','b','m'): case EXTID('p','c','x'): case EXTID('p','n','g'): case EXTID('t','g','a'): case EXTID('t','i','f'): case EXTID('x','c','f'): case EXTID('x','p','m'): case EXTID('.','x','v'): font->Is_truetype = 0; font->Is_bitmap = 1; break; default: #if defined(__macosx__) if(strcasecmp(&name[size-6], "dfont") == 0) { font->Is_truetype = 1; font->Is_bitmap = 0; } else { free(font); return; } #else free(font); return; #endif } font->Name = (char *)malloc(size); strcpy(font->Name, name); // Label strcpy(font->Label, " "); if (font->Is_truetype) font->Label[17]=font->Label[18]='T'; // Logo TT font_name=Find_last_slash(font->Name); if (font_name==NULL) font_name=font->Name; else font_name++; for (index=0; index < 17 && font_name[index]!='\0' && font_name[index]!='.'; index++) font->Label[index]=font_name[index]; // Gestion Liste font->Next = NULL; font->Previous = NULL; if (font_list_start==NULL) { // Premiere (liste vide) font_list_start = font; Nb_fonts++; } else { int compare; compare = Compare_fonts(font, font_list_start); if (compare<=0) { if (compare==0 && !strcmp(font->Name, font_list_start->Name)) { // Doublon free(font->Name); free(font); return; } // Avant la premiere font->Next=font_list_start; font_list_start=font; Nb_fonts++; } else { T_Font *searched_font; searched_font=font_list_start; while (searched_font->Next && (compare=Compare_fonts(font, searched_font->Next))>0) searched_font=searched_font->Next; // Aprs searched_font if (compare==0 && strcmp(font->Name, searched_font->Next->Name)==0) { // Doublon free(font->Name); free(font); return; } font->Next=searched_font->Next; searched_font->Next=font; Nb_fonts++; } } } // Trouve le nom d'une fonte par son numro char * Font_name(int index) { T_Font *font = font_list_start; if (index<0 ||index>=Nb_fonts) return ""; while (index--) font = font->Next; return font->Name; } // Trouve le libell d'affichage d'une fonte par son numro // Renvoie un pointeur sur un buffer statique de 20 caracteres. char * Font_label(int index) { T_Font *font; static char label[20]; strcpy(label, " "); // Recherche de la fonte font = font_list_start; if (index<0 ||index>=Nb_fonts) return label; while (index--) font = font->Next; // Libell strcpy(label, font->Label); return label; } // Vrifie si une fonte donne est TrueType int TrueType_font(int index) { T_Font *font = font_list_start; if (index<0 ||index>=Nb_fonts) return 0; while (index--) font = font->Next; return font->Is_truetype; } // Initialisation faire une fois au dbut du programme void Init_text(void) { char directory_name[MAX_PATH_CHARACTERS]; #ifndef NOTTF // Initialisation de TTF TTF_Init(); #endif // Initialisation des fontes font_list_start = NULL; Nb_fonts=0; // Parcours du rpertoire "fonts" strcpy(directory_name, Data_directory); strcat(directory_name, FONTS_SUBDIRECTORY); For_each_file(directory_name, Add_font); #if defined(__WIN32__) // Parcours du rpertoire systeme windows "fonts" #ifndef NOTTF { char * WindowsPath=getenv("windir"); if (WindowsPath) { sprintf(directory_name, "%s\\FONTS", WindowsPath); For_each_file(directory_name, Add_font); } } #endif #elif defined(__macosx__) // Rcupration de la liste des fonts avec fontconfig #ifndef NOTTF int i,number; char home_dir[MAXPATHLEN]; char *font_path_list[3] = { "/System/Library/Fonts", "/Library/Fonts" }; number = 3; // Make sure we also search into the user's fonts directory CFURLRef url = (CFURLRef) CFCopyHomeDirectoryURLForUser(NULL); CFURLGetFileSystemRepresentation(url, true, (UInt8 *) home_dir, MAXPATHLEN); strcat(home_dir, "/Library/Fonts"); font_path_list[2] = home_dir; for(i=0;iformat->palette, palette); if (antialias) { int black_col; // Shaded text: X-Swap the color that is pure black with the BG color number, // so that the brush is immediately 'transparent' // Find black (c) for (black_col=0; black_col<256; black_col++) { if (palette[black_col].R==0 && palette[black_col].G==0 && palette[black_col].B==0) break; } // If not found: c = 256 = 0 (byte) if (black_col != Back_color) { int c; byte colmap[256]; // Swap palette entries SWAP_BYTES(palette[black_col].R, palette[Back_color].R) SWAP_BYTES(palette[black_col].G, palette[Back_color].G) SWAP_BYTES(palette[black_col].B, palette[Back_color].B) // Define a colormap for (c=0; c<256; c++) colmap[c]=c; // The swap colmap[black_col]=Back_color; colmap[Back_color]=black_col; Remap_general_lowlevel(colmap, new_brush, new_brush, text_surface->w,text_surface->h, text_surface->w); // Also, make the BG color in brush palette have same RGB values as // the current BG color : this will help for remaps. palette[Back_color].R=Main_palette[Back_color].R; palette[Back_color].G=Main_palette[Back_color].G; palette[Back_color].B=Main_palette[Back_color].B; } } else { // Solid text: Was rendered as white on black. Now map colors: // White becomes FG color, black becomes BG. 2-color palette. // Exception: if BG==FG, FG will be set to black or white - any different color. long index; byte new_fore=Fore_color; if (Fore_color==Back_color) { new_fore=Best_color_perceptual_except(Main_palette[Back_color].R, Main_palette[Back_color].G, Main_palette[Back_color].B, Back_color); } for (index=0; index < text_surface->w * text_surface->h; index++) { if (palette[*(new_brush+index)].G < 128) *(new_brush+index)=Back_color; else *(new_brush+index)=new_fore; } // Now copy the current palette to brushe's, for consistency // with the indices. memcpy(palette, Main_palette, sizeof(T_Palette)); } *width=text_surface->w; *height=text_surface->h; SDL_FreeSurface(text_surface); TTF_CloseFont(font); return new_brush; } #endif byte *Render_text_SFont(const char *str, int font_number, int *width, int *height, T_Palette palette) { SFont_Font *font; SDL_Surface * text_surface; SDL_Surface *font_surface; byte * new_brush; SDL_Rect rectangle; // Chargement de la fonte font_surface=IMG_Load(Font_name(font_number)); if (!font_surface) { Verbose_message("Warning","Error loading font.\nThe file may be corrupt."); return NULL; } // Font is 24bit: Perform a color reduction if (font_surface->format->BitsPerPixel>8) { SDL_Surface * reduced_surface; int x,y,color; SDL_Color rgb; reduced_surface=SDL_CreateRGBSurface(SDL_SWSURFACE, font_surface->w, font_surface->h, 8, 0, 0, 0, 0); if (!reduced_surface) { SDL_FreeSurface(font_surface); return NULL; } // Set the quick palette for (color=0;color<256;color++) { rgb.r=((color & 0xE0)>>5)<<5; rgb.g=((color & 0x1C)>>2)<<5; rgb.b=((color & 0x03)>>0)<<6; SDL_SetColors(reduced_surface, &rgb, color, 1); } // Perform reduction for (y=0; yh; y++) for (x=0; xw; x++) { SDL_GetRGB(Get_SDL_pixel_hicolor(font_surface, x, y), font_surface->format, &rgb.r, &rgb.g, &rgb.b); color=((rgb.r >> 5) << 5) | ((rgb.g >> 5) << 2) | ((rgb.b >> 6)); Set_SDL_pixel_8(reduced_surface, x, y, color); } SDL_FreeSurface(font_surface); font_surface=reduced_surface; } font=SFont_InitFont(font_surface); if (!font) { DEBUG("Font init failed",1); SDL_FreeSurface(font_surface); return NULL; } // Calcul des dimensions *height=SFont_TextHeight(font, str); *width=SFont_TextWidth(font, str); // Allocation d'une surface SDL text_surface=SDL_CreateRGBSurface(SDL_SWSURFACE, *width, *height, 8, 0, 0, 0, 0); // Copy palette SDL_SetPalette(text_surface, SDL_LOGPAL, font_surface->format->palette->colors, 0, 256); // Fill with transparent color rectangle.x=0; rectangle.y=0; rectangle.w=*width; rectangle.h=*height; SDL_FillRect(text_surface, &rectangle, font->Transparent); // Rendu du texte SFont_Write(text_surface, font, 0, 0, str); if (!text_surface) { DEBUG("Rendering failed",2); SFont_FreeFont(font); return NULL; } new_brush=Surface_to_bytefield(text_surface, NULL); if (!new_brush) { DEBUG("Converting failed",3); SDL_FreeSurface(text_surface); SFont_FreeFont(font); return NULL; } Get_SDL_Palette(font_surface->format->palette, palette); // Swap current BG color with font's transparent color if (font->Transparent != Back_color) { int c; byte colmap[256]; // Swap palette entries SWAP_BYTES(palette[font->Transparent].R, palette[Back_color].R) SWAP_BYTES(palette[font->Transparent].G, palette[Back_color].G) SWAP_BYTES(palette[font->Transparent].B, palette[Back_color].B) // Define a colormap for (c=0; c<256; c++) colmap[c]=c; // The swap colmap[font->Transparent]=Back_color; colmap[Back_color]=font->Transparent; Remap_general_lowlevel(colmap, new_brush, new_brush, text_surface->w,text_surface->h, text_surface->w); } SDL_FreeSurface(text_surface); SFont_FreeFont(font); return new_brush; } #ifdef NOTTF #define TTFONLY __attribute__((unused)) #else #define TTFONLY #endif // Cre une brosse partir des paramtres de texte demands. // Si cela russit, la fonction place les dimensions dans width et height, // et retourne l'adresse du bloc d'octets. byte *Render_text(const char *str, int font_number, TTFONLY int size, int TTFONLY antialias, TTFONLY int bold, TTFONLY int italic, int *width, int *height, T_Palette palette) { T_Font *font = font_list_start; int index=font_number; // Verification type de la fonte if (font_number<0 ||font_number>=Nb_fonts) return NULL; while (index--) font = font->Next; if (font->Is_truetype) { #ifndef NOTTF return Render_text_TTF(str, font_number, size, antialias, bold, italic, width, height, palette); #else return NULL; #endif } else { return Render_text_SFont(str, font_number, width, height, palette); } } grafx2/src/tiles.c0000644000076400010400000000726211427060364014517 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2010 Adrien Destugues 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 */ /// \file Handle tiles. /// Build the tile-area from the current picture void build_tile_area() { word tileAreaWidth = Main_image_width / Snap_width + 1; word tileAreaHeight = Main_image_height / Snap_height + 1; int* tileArea = malloc(tileAreaWidth*tileAreaHeight*sizeof(int)); word tile_x, tile_y, pixel_x, pixel_y; // For each tile, we have to crawl up to the top of the picture and // find the first identical tile for (tile_y = 0; tile_y < tileAreaWidth; tile_y++) for(tile_x = 0; tile_x < tileAreaHeight; tile_x++) { // So, this is the "for each tile" word ctx, cty; // First we compare the tile with the others one in the same line at the left for(ctx = tile_x - 1; ctx >= 0; ctx--) if(compare_tiles(tile_x*Snap_width, tile_y*Snap_height, ctx*Snap_width, tile_y*Snap_height)) { // We found a match ! tileArea[tile_y*tileAreaWidth+tile_x] = tile_y*tileAreaWidth+ctx; goto found; } // Then we look at all the lines above for(cty = tile_y - 1; cty >= 0; cty--) for(ctx = tileAreaWidth - 1; ctx >= 0; ctx--) if(compare_tiles(tile_x*Snap_width, tile_y*Snap_height, ctx*Snap_width, cty*Snap_height)) { // We found a match ! tileArea[tile_y*tileAreaWidth+tile_x] = cty*tileAreaWidth+ctx; goto found; } // Then we look at all the lines below for(cty = tileAreaHeight - 1; cty >= tile_y; cty--) for(ctx = tileAreaWidth - 1; ctx >= 0; ctx--) if(compare_tiles(tile_x*Snap_width, tile_y*Snap_height, ctx*Snap_width, cty*Snap_height)) { // We found a match ! tileArea[tile_y*tileAreaWidth+tile_x] = cty*tileAreaWidth+ctx; goto found; } // Then we look at the tiles at the right of this one // (including the tile itself, so we are sure we match something this time) for(ctx = tileAreaHeight; ctx >= tile_x; ctx--) if(compare_tiles(tile_x*Snap_width, tile_y*Snap_height, ctx*Snap_width, tile_y*Snap_height)) { // We found a match ! tileArea[tile_y*tileAreaWidth+tile_x] = tile_y*tileAreaWidth+ctx; } found: } } // Compare tiles // The parameters are in pixel-space. void compare_tiles(word x1, word y1, word x2, word y2) { word pixel_x, pixel_y; byte c1, c2; for (pixel_y = 0; pixel_y < Snap_width; pixel_y++) for (pixel_x = 0; pixel_x < Snap_height; pixel_x++) { c1 = Main_screen + (y1+pixel_y) * Main_image_width + (x1+pixel_x); c2 = Main_screen + (y2+pixel_y) * Main_image_width + (x2+pixel_x); if (c1 != c2) return 0; } return 1; } /// Copy a tile pixeldata to all the identical ones // Call this after the end of an operation void update_tile(word pixel_x, word pixel_y) { int tileOffset = (pixel_y/Snap_height)*tileAreaHeight + pixel_x/Snap_width; int firstTileOffset = tileOffset + 1; // to make sure they are not equal while(firstTileOffset != tileOffset) { tileOffset = tileArea[tileOffset]; //do the copy of a block starting at (pixel_x, pixel_y) } } grafx2/src/transform.c0000644000076400010400000003516211443175022015406 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ #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,0);// 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 if (Is_shortcut(Key,0x200+BUTTON_ADJUST)) clicked_button=1; 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, INPUT_TYPE_INTEGER)) { // 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_button(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; Upload_infos_page_main(Main_backups->Pages); // Allocate a new page if (Backup_with_new_dimensions(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) { int i; case 2 : // Flip X for (i=0; iPages->Nb_layers; i++) { memcpy(Main_backups->Pages->Image[i],Main_backups->Pages->Next->Image[i],Main_image_width*Main_image_height); Flip_X_lowlevel(Main_backups->Pages->Image[i], Main_image_width, Main_image_height); } break; case 3 : // Flip Y for (i=0; iPages->Nb_layers; i++) { memcpy(Main_backups->Pages->Image[i],Main_backups->Pages->Next->Image[i],Main_image_width*Main_image_height); Flip_Y_lowlevel(Main_backups->Pages->Image[i], Main_image_width, Main_image_height); } break; case 4 : // -90 Rotation for (i=0; iPages->Nb_layers; i++) { Rotate_270_deg_lowlevel(Main_backups->Pages->Next->Image[i], Main_backups->Pages->Image[i], old_width, old_height); } break; case 5 : // +90 Rotation for (i=0; iPages->Nb_layers; i++) { Rotate_90_deg_lowlevel(Main_backups->Pages->Next->Image[i], Main_backups->Pages->Image[i], old_width, old_height); } break; case 6 : // 180 Rotation for (i=0; iPages->Nb_layers; i++) { memcpy(Main_backups->Pages->Image[i],Main_backups->Pages->Next->Image[i],Main_image_width*Main_image_height); Rotate_180_deg_lowlevel(Main_backups->Pages->Image[i], Main_image_width, Main_image_height); } break; case 7 : // Resize for (i=0; iPages->Nb_layers; i++) { Rescale(Main_backups->Pages->Next->Image[i], old_width, old_height, Main_backups->Pages->Image[i], Main_image_width, Main_image_height, 0, 0); } break; } /* for (i=0; iPages->Next->Image[i],0,0,Min(old_width,Main_image_width), Min(old_height,Main_image_height),old_width, Main_backups->Pages->Image[i],0,0,Main_image_width); } */ Redraw_layered_image(); Display_all_screen(); End_of_modification(); } else { Display_cursor(); Message_out_of_memory(); Hide_cursor(); } } Display_cursor(); } grafx2/src/version.c0000644000076400010400000000003411553137524015055 0ustar vigAdministratorchar SVN_revision[]="1781"; grafx2/src/windows.c0000644000076400010400000027657211552354276015114 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Franck Charlet Copyright 2007-2008 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 ******************************************************************************** Graphical interface management functions (windows, menu, cursor) */ #include #include // atoi() #include // strncpy() strlen() #include "windows.h" #include "engine.h" #include "errors.h" #include "global.h" #include "graph.h" #include "input.h" #include "misc.h" #include "op_c.h" #include "readline.h" #include "sdlscreen.h" #include "palette.h" /// Width of one layer button, in pixels before scaling word Layer_button_width = 1; // L'encapsulation tente une perce...ou un dernier combat. // Nombre de cellules rel dans la palette du menu word Menu_cells_X; word Palette_cells_X() { return Menu_cells_X; } word Menu_cells_Y; word Palette_cells_Y() { return Menu_cells_Y; } // Affichage d'un pixel dans le menu (si visible) void Pixel_in_menu(word bar, word x, word y, byte color) { if (Menu_is_visible && Menu_bars[bar].Visible) Block(x*Menu_factor_X,(y+Menu_bars[bar].Top)*Menu_factor_Y+Menu_Y,Menu_factor_X,Menu_factor_Y,color); } // Affichage d'un pixel dans le menu et met a jour la bitmap de skin void Pixel_in_menu_and_skin(word bar, word x, word y, byte color) { Pixel_in_menu(bar, x, y, color); Menu_bars[bar].Skin[2][y*Menu_bars[bar].Skin_width + x] = color; } // Affichage d'un pixel dans la fentre (la fentre doit tre visible) void Pixel_in_window(word x,word y,byte color) { Block((x*Menu_factor_X)+Window_pos_X,(y*Menu_factor_Y)+Window_pos_Y,Menu_factor_X,Menu_factor_Y,color); } // Affichage d'un rectangle dans la fentre (la fentre doit tre visible) void Window_rectangle(word x_pos,word y_pos,word width,word height,byte color) { Block((x_pos*Menu_factor_X)+Window_pos_X,(y_pos*Menu_factor_Y)+Window_pos_Y,width*Menu_factor_X,height*Menu_factor_Y,color); } // -- Affichages de diffrents cadres dans une fentre ----------------------- // -- Frame gnral avec couleurs paramtrables -- void Window_display_frame_generic(word x_pos,word y_pos,word width,word height, byte color_tl,byte color_br,byte color_s,byte color_tlc,byte color_brc) // Paramtres de couleurs: // color_tl =Bords Haut et Gauche // color_br =Bords Bas et Droite // color_s =Coins Haut-Droite et Bas-Gauche // color_tlc=Coin Haut-Gauche // color_brc=Coin Bas-Droite { // Bord haut (sans les extrmits) Block(Window_pos_X+((x_pos+1)*Menu_factor_X), Window_pos_Y+(y_pos*Menu_factor_Y), (width-2)*Menu_factor_X,Menu_factor_Y,color_tl); // Bord bas (sans les extrmits) Block(Window_pos_X+((x_pos+1)*Menu_factor_X), Window_pos_Y+((y_pos+height-1)*Menu_factor_Y), (width-2)*Menu_factor_X,Menu_factor_Y,color_br); // Bord gauche (sans les extrmits) Block(Window_pos_X+(x_pos*Menu_factor_X), Window_pos_Y+((y_pos+1)*Menu_factor_Y), Menu_factor_X,(height-2)*Menu_factor_Y,color_tl); // Bord droite (sans les extrmits) Block(Window_pos_X+((x_pos+width-1)*Menu_factor_X), Window_pos_Y+((y_pos+1)*Menu_factor_Y), Menu_factor_X,(height-2)*Menu_factor_Y,color_br); // Coin haut gauche Pixel_in_window(x_pos,y_pos,color_tlc); // Coin haut droite Pixel_in_window(x_pos+width-1,y_pos,color_s); // Coin bas droite Pixel_in_window(x_pos+width-1,y_pos+height-1,color_brc); // Coin bas gauche Pixel_in_window(x_pos,y_pos+height-1,color_s); } // -- Frame dont tout le contour est d'une seule couleur -- void Window_display_frame_mono(word x_pos,word y_pos,word width,word height,byte color) { Window_display_frame_generic(x_pos,y_pos,width,height,color,color,color,color,color); } // -- Frame creux: fonc en haut-gauche et clair en bas-droite -- void Window_display_frame_in(word x_pos,word y_pos,word width,word height) { Window_display_frame_generic(x_pos,y_pos,width,height,MC_Dark,MC_White,MC_Light,MC_Dark,MC_White); } // -- Frame bomb: clair en haut-gauche et fonc en bas-droite -- void Window_display_frame_out(word x_pos,word y_pos,word width,word height) { Window_display_frame_generic(x_pos,y_pos,width,height,MC_White,MC_Dark,MC_Light,MC_White,MC_Dark); } // -- Frame de sparation: un cadre bomb dans un cadre creux (3D!!!) -- void Window_display_frame(word x_pos,word y_pos,word width,word height) { Window_display_frame_in(x_pos,y_pos,width,height); Window_display_frame_out(x_pos+1,y_pos+1,width-2,height-2); } //-- Affichages relatifs la palette dans le menu --------------------------- // -- Affichage des couleurs courante (fore/back) de pinceau dans le menu -- void Display_foreback(void) { if (Menu_is_visible && Menu_bars[MENUBAR_TOOLS].Visible) { Block((MENU_WIDTH-17)*Menu_factor_X,Menu_Y+Menu_factor_Y,Menu_factor_X<<4,Menu_factor_Y*7,Back_color); Block((MENU_WIDTH-13)*Menu_factor_X,Menu_Y+(Menu_factor_Y<<1),Menu_factor_X<<3,Menu_factor_Y*5,Fore_color); Update_rect((MENU_WIDTH-17)*Menu_factor_X,Menu_Y+Menu_factor_Y,Menu_factor_X<<4,Menu_factor_Y*7); } } /*! Get the top left corner for the palette cell of a color @param index Index of the color, starting at 0 for the top left one. Limited to Menu_cells_X/Menu_cells_Y. */ word Palette_cell_X(byte index) { if (Config.Palette_vertical) { return (MENU_WIDTH+1+((index-First_color_in_palette)%Menu_cells_X)*Menu_palette_cell_width)*Menu_factor_X; } else { return (MENU_WIDTH+1+((index-First_color_in_palette)/Menu_cells_Y)*Menu_palette_cell_width)*Menu_factor_X; } } /*! Get the top left corner for the palette cell of a color @param index Index of the color, starting at 0 for the top left one. Limited to Menu_cells_X/Menu_cells_Y. */ word Palette_cell_Y(byte index) { if (Config.Palette_vertical) { return Menu_Y+((1+(((index-First_color_in_palette)/Menu_cells_X)*(Menu_bars[MENUBAR_TOOLS].Height/Menu_cells_Y)))*Menu_factor_Y); } else { return Menu_Y+((1+(((index-First_color_in_palette)%Menu_cells_Y)*(Menu_bars[MENUBAR_TOOLS].Height/Menu_cells_Y)))*Menu_factor_Y); } } void Set_fore_color(byte color) { byte old_fore_color = Fore_color; Fore_color=color; Reposition_palette(); Display_foreback(); Frame_menu_color(old_fore_color); Frame_menu_color(Fore_color); } void Set_back_color(byte color) { byte old_back_color = Back_color; Back_color=color; Display_foreback(); Frame_menu_color(old_back_color); Frame_menu_color(Back_color); } /// /// Redraw the cell in the menu palette for ::Fore_color. /// This function checks bounds, it won't draw anything if Fore_color is not visible. /// @param id: Color number to frame void Frame_menu_color(byte id) { word start_x,start_y,end_x,end_y; word index; word cell_height=Menu_bars[MENUBAR_TOOLS].Height/Menu_cells_Y; byte color; if (! Menu_bars[MENUBAR_TOOLS].Visible) return; if (id==Fore_color) color = MC_White; else if (id==Back_color) color = MC_Dark; else color = MC_Black; if ((id>=First_color_in_palette) && (id=First_color_in_palette+Menu_cells_X*Menu_cells_Y) First_color_in_palette+=cells; } if (old_color!=First_color_in_palette) Display_menu_palette(); } void Change_palette_cells() { // On initialise avec la configuration de l'utilisateur Menu_cells_X=Config.Palette_cells_X; Menu_cells_Y=Config.Palette_cells_Y; // Mais on sait jamais if (Menu_cells_X<1) Menu_cells_X=1; if (Menu_cells_Y<1) Menu_cells_Y=1; while (1) { Menu_palette_cell_width = ((Screen_width/Menu_factor_X)-(MENU_WIDTH+2)) / Menu_cells_X; // Si a tient, c'est bon. Sinon, on retente avec une colonne de moins if (Menu_palette_cell_width>2) break; Menu_cells_X--; } // Cale First_color_in_palette sur un multiple du nombre de cellules (arrondi infrieur) if (Config.Palette_vertical) First_color_in_palette=First_color_in_palette/Menu_cells_X*Menu_cells_X; else First_color_in_palette=First_color_in_palette/Menu_cells_Y*Menu_cells_Y; // Si le nombre de cellules a beaucoup augment et qu'on tait prs de // la fin, il faut reculer First_color_in_palette pour montrer plein // de couleurs. if ((int)First_color_in_palette+(Menu_cells_Y)*Menu_cells_X*2>=256) First_color_in_palette=255/Menu_cells_Y*Menu_cells_Y-(Menu_cells_X-1)*Menu_cells_Y; // Mise jour de la taille du bouton dans le menu. C'est pour pas que // la bordure noire soit active. Buttons_Pool[BUTTON_CHOOSE_COL].Width=(Menu_palette_cell_width*Menu_cells_X)-1; Buttons_Pool[BUTTON_CHOOSE_COL].Height=(MENU_HEIGHT-9)/Menu_cells_Y*Menu_cells_Y-1; } // Retrouve la couleur sur laquelle pointe le curseur souris. // Cette fonction suppose qu'on a dja vrifi que le curseur est dans // la zone rectangulaire du BUTTON_CHOOSE_COL // La fonction renvoie -1 si on est "trop gauche" (pas possible) // ou aprs la couleur 255 (Ce qui peut arriver si la palette est affiche // avec un nombre de lignes qui n'est pas une puissance de deux.) int Pick_color_in_palette() { int color; int line; int column; line=(((Mouse_Y-Menu_Y)/Menu_factor_Y)-1)/((Menu_bars[MENUBAR_TOOLS].Height)/Menu_cells_Y); column=(((Mouse_X/Menu_factor_X)-(MENU_WIDTH+1))/Menu_palette_cell_width); if (Config.Palette_vertical) { color=First_color_in_palette+line*Menu_cells_X+column; } else { color=First_color_in_palette+line+column*Menu_cells_Y; } if (color<0 || color>255) return -1; return color; } /// Draws a solid textured area, to the right of a toolbar. void Draw_bar_remainder(word current_menu, word x_off) { word y_pos; word x_pos; for (y_pos=0;y_posPages->Nb_layers; word horiz_space; word current_button; word repeats=1; if (! Menu_bars[MENUBAR_LAYERS].Visible) return; // Available space in pixels horiz_space = Screen_width / Menu_factor_X - Menu_bars[MENUBAR_LAYERS].Skin_width; // Don't display all buttons if not enough room if (horiz_space/button_width < button_number) button_number = horiz_space/button_width; // Only 16 icons at the moment if (button_number > 16) // can be different from MAX_NB_LAYERS button_number = 16; // Enlarge the buttons themselves if there's enough room while (button_number*(button_width+2) < horiz_space && repeats < 20) { repeats+=1; button_width+=2; } x_off=Menu_bars[MENUBAR_LAYERS].Skin_width; for (current_button=0; current_button0; i--) { Pixel_in_menu(MENUBAR_LAYERS, x_pos + x_off, y_pos, Gfx->Layer_sprite[sprite_index][current_button][y_pos][source_x]); x_pos++; } } // Next line x_pos=0; } // Next button x_off+=button_width; } // Texture any remaining space to the right. // This overwrites any junk like deleted buttons. Draw_bar_remainder(MENUBAR_LAYERS, x_off); // Update the active area of the layers pseudo-button Buttons_Pool[BUTTON_LAYER_SELECT].Width = button_number * button_width; // Required to determine which layer button is clicked Layer_button_width = button_width; // A screen refresh required by some callers Update_rect( Menu_bars[MENUBAR_LAYERS].Skin_width, Menu_Y+Menu_bars[MENUBAR_LAYERS].Top*Menu_factor_Y, horiz_space*Menu_factor_X, Menu_bars[MENUBAR_LAYERS].Height*Menu_factor_Y); } /// Display the whole menu void Display_menu(void) { word x_pos; word y_pos; int8_t current_menu; char str[4]; if (Menu_is_visible) { // display menu sprite for (current_menu = MENUBAR_COUNT - 1; current_menu >= 0; current_menu --) { if(Menu_bars[current_menu].Visible) { // Skinned area for (y_pos=0;y_pos=Main_X_zoom) )) { // Prepare display of XY coordinates even if in some cases they will be // erased with some other text if ( (Current_operation!=OPERATION_COLORPICK) && (Current_operation!=OPERATION_REPLACE) ) Print_in_menu("X: Y: ",0); else { // The colorpicker display the color id between the parentheses Print_in_menu("X: Y: ( )",0); Num2str(Colorpicker_color,str,3); Print_in_menu(str,20); Print_general(170*Menu_factor_X,Menu_status_Y," ",0,Colorpicker_color); } Print_coordinates(); } Print_filename(); } // Now update the area: menu height and whole screen width (including palette) Update_rect(0,Menu_Y,Screen_width,Menu_height*Menu_factor_Y); } } // -- Affichage de texte ----------------------------------------------------- // -- Afficher une chane n'importe o l'cran -- void Print_general(short x,short y,const char * str,byte text_color,byte background_color) { word index; int x_pos; int y_pos; byte *font_pixel; short real_x; short real_y; byte repeat_menu_x_factor; byte repeat_menu_y_factor; real_y=y; for (y_pos=0;y_pos<8<<3;y_pos+=1<<3) { real_x=0; // Position dans le buffer for (index=0;str[index]!='\0';index++) { // Pointeur sur le premier pixel du caractre font_pixel=Menu_font+(((unsigned char)str[index])<<6); for (x_pos=0;x_pos<8;x_pos+=1) for (repeat_menu_x_factor=0;repeat_menu_x_factor size) { display_string[size-1]=ELLIPSIS_CHARACTER; } Print_in_window(x, y, display_string, text_color, background_color); } /// Draws a string in a window void Print_in_window(short x,short y,const char * str,byte text_color,byte background_color) { Print_general((x*Menu_factor_X)+Window_pos_X, (y*Menu_factor_Y)+Window_pos_Y, str,text_color,background_color); Update_rect(x*Menu_factor_X+Window_pos_X,y*Menu_factor_Y+Window_pos_Y,8*Menu_factor_X*strlen(str),8*Menu_factor_Y); } // Draws a string in the menu's status bar void Print_in_menu(const char * str, short position) { Print_general((18+(position<<3))*Menu_factor_X,Menu_status_Y,str,MC_Black,MC_Light); Update_status_line(position, strlen(str)); } /// Draws the mouse coordinates on the menu /// Only update the digits and doesn't refresh the "X: Y:" labels. This function needs to be fast as it is called each time the mouse moves. void Print_coordinates(void) { char temp[5]; if (Menu_is_visible && !Cursor_in_menu) { if ( (Current_operation==OPERATION_COLORPICK) || (Current_operation==OPERATION_RMB_COLORPICK) || (Current_operation==OPERATION_REPLACE) ) { if ( (Paintbrush_X>=0) && (Paintbrush_Y>=0) && (Paintbrush_XPages->Filename); // Partial copy of the name strncpy(display_string, Main_backups->Pages->Filename, max_size); display_string[max_size]='\0'; if (string_size > max_size) { string_size = max_size; display_string[string_size-1]=ELLIPSIS_CHARACTER; } // Erase whole area Block(Screen_width-max_size*8*Menu_factor_X, Menu_status_Y,Menu_factor_X*max_size*8,Menu_factor_Y<<3,MC_Light); // Print Print_general(Screen_width-(string_size<<3)*Menu_factor_X,Menu_status_Y,display_string,MC_Black,MC_Light); } // Fonction d'affichage d'une chaine numrique avec une fonte trs fine // Spcialise pour les compteurs RGB void Print_counter(short x,short y,const char * str,byte text_color,byte background_color) { // Macros pour crire des litteraux binaires. // Ex: Ob(11110000) == 0xF0 #define Ob(x) ((unsigned)Ob_(0 ## x ## uL)) #define Ob_(x) ((x & 1) | (x >> 2 & 2) | (x >> 4 & 4) | (x >> 6 & 8) | \ (x >> 8 & 16) | (x >> 10 & 32) | (x >> 12 & 64) | (x >> 14 & 128)) byte thin_font[14][8] = { { // 0 Ob(00011100), Ob(00110110), Ob(00110110), Ob(00110110), Ob(00110110), Ob(00110110), Ob(00110110), Ob(00011100) }, { // 1 Ob(00001100), Ob(00011100), Ob(00111100), Ob(00001100), Ob(00001100), Ob(00001100), Ob(00001100), Ob(00001100) }, { // 2 Ob(00011100), Ob(00110110), Ob(00000110), Ob(00000110), Ob(00000110), Ob(00001100), Ob(00011000), Ob(00111110) }, { // 3 Ob(00011100), Ob(00110110), Ob(00000110), Ob(00001100), Ob(00000110), Ob(00000110), Ob(00110110), Ob(00011100) }, { // 4 Ob(00001100), Ob(00001100), Ob(00011000), Ob(00011000), Ob(00110000), Ob(00110100), Ob(00111110), Ob(00000100) }, { // 5 Ob(00111110), Ob(00110000), Ob(00110000), Ob(00111100), Ob(00000110), Ob(00000110), Ob(00110110), Ob(00011100) }, { // 6 Ob(00011100), Ob(00110110), Ob(00110000), Ob(00111100), Ob(00110110), Ob(00110110), Ob(00110110), Ob(00011100) }, { // 7 Ob(00111110), Ob(00000110), Ob(00000110), Ob(00001100), Ob(00011000), Ob(00011000), Ob(00011000), Ob(00011000) }, { // 8 Ob(00011100), Ob(00110110), Ob(00110110), Ob(00011100), Ob(00110110), Ob(00110110), Ob(00110110), Ob(00011100) }, { // 9 Ob(00011100), Ob(00110110), Ob(00110110), Ob(00011110), Ob(00000110), Ob(00000110), Ob(00110110), Ob(00011100) }, { // (espace) Ob(00000000), Ob(00000000), Ob(00000000), Ob(00000000), Ob(00000000), Ob(00000000), Ob(00000000), Ob(00000000) }, { // + Ob(00000000), Ob(00001000), Ob(00001000), Ob(00111110), Ob(00001000), Ob(00001000), Ob(00000000), Ob(00000000) }, { // - Ob(00000000), Ob(00000000), Ob(00000000), Ob(00111110), Ob(00000000), Ob(00000000), Ob(00000000), Ob(00000000) }, { // +- Ob(00001000), Ob(00001000), Ob(00111110), Ob(00001000), Ob(00001000), Ob(00000000), Ob(00111110), Ob(00000000) } }; word index; short x_pos; short y_pos; for (index=0;str[index]!='\0';index++) { int char_number; switch(str[index]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': char_number=str[index]-'0'; break; case ' ': default: char_number=10; break; case '+': char_number=11; break; case '-': char_number=12; break; case '': char_number=13; break; } for (y_pos=0;y_pos<8;y_pos++) { for (x_pos=0;x_pos<6;x_pos++) { byte color = (thin_font[char_number][y_pos] & (1 << (6-x_pos))) ? text_color:background_color; Pixel_in_window(x+(index*6+x_pos),y+y_pos,color); } } } Update_rect(Window_pos_X+x*Menu_factor_X,Window_pos_Y+y*Menu_factor_Y,strlen(str)*Menu_factor_X*6,8*Menu_factor_Y); } /// /// Window asking for confirmation before an action is performed. /// This function is able to display multi-line messages and /// center the lines, but the carriage returns have to be explicit. /// The function will clip the message in case of problem. /// @return 1 if user pressed OK, 0 if CANCEL byte Confirmation_box(char * message) { short clicked_button; word window_width = 120; word nb_lines = 1; const char *c = message; short current_length=0; short current_line; // Count lines, and measure max line length for (c=message; *c != '\0'; c++) { if (*c == '\n') { current_length=0; nb_lines++; } else { current_length++; window_width=Max(window_width, (current_length<<3)+20); } } // Safety if (window_width>310) window_width=310; Open_window(window_width,52+(nb_lines<<3),"Confirmation"); c=message; for (current_line=0; current_line < nb_lines; current_line++) { char * next_eol; char display_string[36+1]; next_eol = strchr(c, '\n'); if (next_eol==NULL) // last line current_length = strlen(c); else current_length = next_eol-c; // Safeguard if (current_length>36) current_length=36; // Copy part of string in null-terminated buffer strncpy(display_string, c, current_length); display_string[current_length]='\0'; Print_in_window((window_width>>1)-(current_length<<2), 20+(current_line<<3), display_string, MC_Black, MC_Light); c += current_length; if (*c == '\n') c++; } Window_set_normal_button((window_width/3)-20 ,29+(nb_lines<<3),40,14,"Yes",1,1,SDLK_y); // 1 Window_set_normal_button(((window_width<<1)/3)-20,29+(nb_lines<<3),40,14,"No" ,1,1,SDLK_n); // 2 Update_rect(Window_pos_X, Window_pos_Y, Window_width*Menu_factor_X, Window_height*Menu_factor_Y); Display_cursor(); do { clicked_button=Window_clicked_button(); if (Key==SDLK_RETURN) clicked_button=1; if (Key==KEY_ESC) clicked_button=2; } while (clicked_button<=0); Key=0; Close_window(); Display_cursor(); return (clicked_button==1)? 1 : 0; } /// Window that allows you to enter a single value int Requester_window(char* message, int initial_value) { short clicked_button = 0; word window_width; char str[10]; window_width=(strlen(message)<<3)+20; if (window_width<120) window_width = 120; Open_window(window_width, 60, "Request"); Print_in_window((window_width>>1)-(strlen(message)<<2), 20, message, MC_Black, MC_Light); sprintf(str, "%d", initial_value); Window_set_input_button(10, 37, 4); // 1 Print_in_window(11, 39, str, MC_Black, MC_Light); Window_set_normal_button(60 ,37,40,14,"OK",1,1,SDLK_y); // 2 Window_set_normal_button(130,37,60,14,"Cancel" ,1,1,SDLK_n); // 3 Update_rect(Window_pos_X, Window_pos_Y, Menu_factor_X * window_width, Menu_factor_Y * 60); Display_cursor(); do { clicked_button = Window_clicked_button(); if (clicked_button == 1) Readline(11, 39, str, 4, INPUT_TYPE_INTEGER); if (Key == SDLK_ESCAPE) clicked_button = 2; } while (clicked_button <= 0); Key = 0; Close_window(); Display_cursor(); return clicked_button==2?-1:atoi(str); } /// Window that show a warning message and wait for a click on the OK button void Warning_message(char * message) { short clicked_button; word window_width; window_width=(strlen(message)<<3)+20; if (window_width<120) window_width=120; Open_window(window_width,60,"Warning!"); Print_in_window((window_width>>1)-(strlen(message)<<2),20,message,MC_Black,MC_Light); Window_set_normal_button((window_width>>1)-20 ,37,40,14,"OK",1,1,SDLK_RETURN); // 1 Update_rect(Window_pos_X,Window_pos_Y,Menu_factor_X*window_width,Menu_factor_Y*60); Display_cursor(); do clicked_button=Window_clicked_button(); while ((clicked_button<=0) && (Key!=KEY_ESC) && (Key!=SDLK_o)); Key=0; Close_window(); Display_cursor(); } /// Window that shows a big message (up to 34x12), and waits for a click on OK. /// On call: Cursor must be displayed /// On exit: Cursor is displayed void Verbose_message(const char *caption, const char * message ) { short clicked_button; int line; int last_space; int nb_char; char buffer[36]; byte original_cursor_shape = Cursor_shape; Open_window(300,160,caption); // Word-wrap the message for (line=0; line < 12 && *message!='\0'; line++) { last_space = -1; for (nb_char=0; nb_char<35 && message[nb_char]!='\0'; nb_char++) { buffer[nb_char]=message[nb_char]; if (message[nb_char] == ' ') { last_space = nb_char; } else if (message[nb_char] == '\n') { last_space = nb_char; break; } } // Close line buffer if (message[nb_char]=='\0' || last_space == -1) last_space = nb_char; buffer[last_space]='\0'; // Print Print_in_window(10,20+line*8,buffer,MC_Black,MC_Light); // Next line message=message+last_space; // Strip at most one carriage return and any leading spaces if (*message == '\n') message++; while (*message == ' ') message++; } Window_set_normal_button(300/2-20,160-23,40,14,"OK",1,1,SDLK_RETURN); // 1 Update_window_area(0,0,Window_width,Window_height); Cursor_shape=CURSOR_SHAPE_ARROW; Display_cursor(); do clicked_button=Window_clicked_button(); while ((clicked_button<=0) && (Key!=KEY_ESC) && (Key!=SDLK_o)); Key=0; Close_window(); Cursor_shape=original_cursor_shape; Display_cursor(); } // -- Redessiner le sprite d'un bouton dans le menu -- void Display_sprite_in_menu(int btn_number,char sprite_number) { Buttons_Pool[btn_number].Icon=sprite_number; if (Buttons_Pool[btn_number].Shape == BUTTON_SHAPE_TRIANGLE_TOP_LEFT) Buttons_Pool[btn_number+1].Icon=sprite_number; else if (Buttons_Pool[btn_number].Shape == BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT) Buttons_Pool[btn_number-1].Icon=sprite_number; } // -- Redessiner la forme du pinceau dans le menu -- void Display_paintbrush_in_menu(void) { switch(Paintbrush_shape) { case PAINTBRUSH_SHAPE_COLOR_BRUSH: Display_sprite_in_menu(BUTTON_PAINTBRUSHES, MENU_SPRITE_COLOR_BRUSH); break; case PAINTBRUSH_SHAPE_MONO_BRUSH: Display_sprite_in_menu(BUTTON_PAINTBRUSHES, MENU_SPRITE_MONO_BRUSH); break; default: Display_sprite_in_menu(BUTTON_PAINTBRUSHES, -1); break; } Draw_menu_button(BUTTON_PAINTBRUSHES,BUTTON_RELEASED); } // -- Dessiner un pinceau prdfini dans la fentre -- void Display_paintbrush_in_window(word x,word y,int number) // Pinceau = 0..NB_PAINTBRUSH_SPRITES-1 : Pinceau prdfini { word x_pos; word y_pos; word window_x_pos; word window_y_pos; int x_size; int y_size; word origin_x; word origin_y; word width; word height; x_size=Menu_factor_X/Pixel_height; if (x_size<1) x_size=1; y_size=Menu_factor_Y/Pixel_width; if (y_size<1) y_size=1; width=Min(Paintbrush[number].Width,PAINTBRUSH_WIDTH); height=Min(Paintbrush[number].Height,PAINTBRUSH_WIDTH); origin_x = (x + 8)*Menu_factor_X - (width/2)*x_size+Window_pos_X; origin_y = (y + 8)*Menu_factor_Y - (height/2)*y_size+Window_pos_Y; for (window_y_pos=0,y_pos=0; y_pos 64 lignes fct(Menu_Facteur) word nb_colors =(block_start<=block_end)?block_end-block_start+1:block_start-block_end+1; word Selected_line_mode=(block_start<=block_end)?0:total_lines-1; word start_x =Window_pos_X+(Menu_factor_X*x_pos); word line_width =Menu_factor_X<<4; // <=> 16 pixels fct(Menu_Facteur) word start_y =Window_pos_Y+(Menu_factor_Y*y_pos); word end_y =start_y+total_lines; word index; if (block_start>block_end) { index=block_start; block_start=block_end; block_end=index; } for (index=start_y;indexIcon_sprite[type][j][i]); Update_rect(ToWinX(x_pos),ToWinY(y_pos),ToWinL(ICON_SPRITE_WIDTH),ToWinH(ICON_SPRITE_HEIGHT)); } void Display_menu_palette_avoiding_window(byte * table) { // On part du principe qu'il n'y a que le bas d'une fentre qui puisse // empiter sur la palette... Et c'est dj pas mal! word color,real_color; word start_x,start_y; word end_x,end_y; word width; word height; word corner_x=Window_pos_X+Window_width*Menu_factor_X; // |_ Coin bas-droit word corner_y=Window_pos_Y+Window_height*Menu_factor_Y; // | de la fentre +1 if (Config.Separate_colors) { width=(Menu_palette_cell_width-1)*Menu_factor_X; height=Menu_factor_Y*((Menu_height-11)/Menu_cells_Y-1); } else { width=Menu_palette_cell_width*Menu_factor_X; height=Menu_factor_Y*((Menu_height-11)/Menu_cells_Y); } for (color=0,real_color=First_color_in_palette;color=corner_y) || (end_x<=Window_pos_X) || (start_x>=corner_x) ) Block(start_x,start_y,width,height,real_color); else { if (start_x>=Window_pos_X) { if ( (end_x>corner_x) || (end_y>corner_y) ) { if ( (end_x>corner_x) && (end_y>corner_y) ) { Block(corner_x,start_y,end_x-corner_x,corner_y-start_y,real_color); Block(start_x,corner_y,width,end_y-corner_y,real_color); } else { if (end_y>corner_y) Block(start_x,corner_y,width,end_y-corner_y,real_color); else Block(corner_x,start_y,end_x-corner_x,height,real_color); } } } else { if (end_xcorner_y) { Block(start_x,start_y,Window_pos_X-start_x,corner_y-start_y,real_color); Block(start_x,corner_y,width,end_y-corner_y,real_color); } else Block(start_x,start_y,Window_pos_X-start_x,height,real_color); } else { if (end_y>corner_y) { Block(start_x,start_y,Window_pos_X-start_x,corner_y-start_y,real_color); Block(corner_x,start_y,end_x-corner_x,corner_y-start_y,real_color); Block(start_x,corner_y,width,end_y-corner_y,real_color); } else { Block(start_x,start_y,Window_pos_X-start_x,height,real_color); Block(corner_x,start_y,end_x-corner_x,height,real_color); } } } } { // Affichage du bloc directement dans le "buffer de fond" de la fenetre. // Cela permet au bloc de couleur d'apparaitre si on dplace la fenetre. short x_pos; short y_pos; short relative_x; // besoin d'une variable signe short relative_y; // besoin d'une variable signe // Attention aux units relative_x = ((short)start_x - (short)Window_pos_X); relative_y = ((short)start_y - (short)Window_pos_Y); for (y_pos=relative_y;y_pos<(relative_y+height)&&y_pos=0&&y_pos>=0) Pixel_background(x_pos,y_pos,real_color); } } } Update_rect(MENU_WIDTH*Menu_factor_X,Menu_Y_before_window,Screen_width-(MENU_WIDTH*Menu_factor_X),(Menu_height-11)*Menu_factor_Y); } // -------- Calcul des bornes de la partie d'image visible l'cran --------- void Compute_limits(void) /* Avant l'appel cette fonction, les donnes de la loupe doivent tre jour. */ { if (Main_magnifier_mode) { // -- Calcul des limites de la partie non zoome de l'image -- Limit_top =Main_offset_Y; Limit_left=Main_offset_X; Limit_visible_bottom =Limit_top+Menu_Y-1; Limit_visible_right=Limit_left+Main_separator_position-1; if (Limit_visible_bottom>=Main_image_height) Limit_bottom=Main_image_height-1; else Limit_bottom=Limit_visible_bottom; if (Limit_visible_right>=Main_image_width) Limit_right=Main_image_width-1; else Limit_right=Limit_visible_right; // -- Calcul des limites de la partie zoome de l'image -- Limit_top_zoom =Main_magnifier_offset_Y; Limit_left_zoom=Main_magnifier_offset_X; Limit_visible_bottom_zoom =Limit_top_zoom+Main_magnifier_height-1; Limit_visible_right_zoom=Limit_left_zoom+Main_magnifier_width-1; if (Limit_visible_bottom_zoom>=Main_image_height) Limit_bottom_zoom=Main_image_height-1; else Limit_bottom_zoom=Limit_visible_bottom_zoom; if (Limit_visible_right_zoom>=Main_image_width) Limit_right_zoom=Main_image_width-1; else Limit_right_zoom=Limit_visible_right_zoom; } else { // -- Calcul des limites de la partie visible de l'image -- Limit_top =Main_offset_Y; Limit_left=Main_offset_X; Limit_visible_bottom =Limit_top+(Menu_is_visible?Menu_Y:Screen_height)-1; // A REVOIR POUR SIMPLIFICATION Limit_visible_right=Limit_left+Screen_width-1; if (Limit_visible_bottom>=Main_image_height) Limit_bottom=Main_image_height-1; else Limit_bottom=Limit_visible_bottom; if (Limit_visible_right>=Main_image_width) Limit_right=Main_image_width-1; else Limit_right=Limit_visible_right; } } // -- Calculer les coordonnes du pinceau en fonction du snap et de la loupe - void Compute_paintbrush_coordinates(void) { if ((Main_magnifier_mode) && (Mouse_X>=Main_X_zoom)) { Paintbrush_X=((Mouse_X-Main_X_zoom)/Main_magnifier_factor)+Main_magnifier_offset_X; Paintbrush_Y=(Mouse_Y/Main_magnifier_factor)+Main_magnifier_offset_Y; } else { Paintbrush_X=Mouse_X+Main_offset_X; Paintbrush_Y=Mouse_Y+Main_offset_Y; } if (Snap_mode) { Paintbrush_X=(((Paintbrush_X+(Snap_width>>1)-Snap_offset_X)/Snap_width)*Snap_width)+Snap_offset_X; Paintbrush_Y=(((Paintbrush_Y+(Snap_height>>1)-Snap_offset_Y)/Snap_height)*Snap_height)+Snap_offset_Y; } // Handling the snap axis mode, when shift is pressed. switch (Current_operation) { // Operations that don't implement it case OPERATION_LINE: case OPERATION_ROTATE_BRUSH: Snap_axis=0; break; // Operations that implement it default: if (Snap_axis==0 && (SDL_GetModState() & KMOD_SHIFT)) { // Start "Snap axis" mode Snap_axis=1; Snap_axis_origin_X=Paintbrush_X; Snap_axis_origin_Y=Paintbrush_Y; } } if (Snap_axis==1) { // Cursor moved if (Paintbrush_X != Snap_axis_origin_X || Paintbrush_Y != Snap_axis_origin_Y) { if ((Paintbrush_X-Snap_axis_origin_X)*(Paintbrush_X-Snap_axis_origin_X) > (Paintbrush_Y-Snap_axis_origin_Y)*(Paintbrush_Y-Snap_axis_origin_Y)) // Displacement was bigger on X axis: lock Y Snap_axis=2; else Snap_axis=3; } } if (Snap_axis==2) { Paintbrush_Y = Snap_axis_origin_Y; } else if (Snap_axis==3) { Paintbrush_X = Snap_axis_origin_X; } } // -- Affichage de la limite de l'image ------------------------------------- void Display_image_limits(void) { short start; short pos; short end; byte right_is_visible; byte bottom_is_visible; short old_zoom_limit; right_is_visible=Main_image_width<((Main_magnifier_mode)?Main_separator_position:Screen_width); bottom_is_visible =Main_image_heightMain_separator_position) { Main_offset_X=Main_magnifier_offset_X+(Main_magnifier_width>>1) -(Main_separator_position>>1); if (Main_offset_X<0) Main_offset_X=0; else if (Main_image_widthMenu_Y) { Main_offset_Y=Main_magnifier_offset_Y+(Main_magnifier_height>>1) -(Menu_Y>>1); if (Main_offset_Y<0) Main_offset_Y=0; else if (Main_image_heightMain_separator_position) { Main_offset_X=target_x-Mouse_X; // Do not allow the zoomed part to show something that the // non-zoomed part doesn't see. All clipping is computed according // to the non-zoomed part. if (Main_magnifier_offset_X Main_offset_X+Main_separator_position) Main_offset_X = Main_magnifier_offset_X+Main_magnifier_width-Main_separator_position; if (Main_offset_X<0) Main_offset_X=0; else if (Main_image_widthMenu_Y) { Main_offset_Y=target_y-Mouse_Y; // Do not allow the zoomed part to show something that the // non-zoomed part doesn't see. All clipping is computed according // to the non-zoomed part. if (Main_magnifier_offset_Y Main_offset_Y) Main_offset_Y = Main_magnifier_offset_Y+Main_magnifier_height; if (Main_offset_Y<0) Main_offset_Y=0; else if (Main_image_height>1)-theoric_X)/Main_magnifier_factor)*Main_magnifier_factor); Main_separator_position=Main_X_zoom-(Menu_factor_X*SEPARATOR_WIDTH); // Correction en cas de dbordement sur la gauche while (Main_separator_position*(Main_magnifier_factor+1)=theoric_X) { Main_separator_position-=Main_magnifier_factor; Main_X_zoom-=Main_magnifier_factor; } } // -------------------- Calcul des information de la loupe ------------------- void Compute_magnifier_data(void) /* Aprs modification des donnes de la loupe, il faut recalculer les limites. */ { Compute_separator_data(); Main_magnifier_width=(Screen_width-Main_X_zoom)/Main_magnifier_factor; Main_magnifier_height=Menu_Y/Main_magnifier_factor; if (Menu_Y%Main_magnifier_factor) Main_magnifier_height++; Clip_magnifier_offsets(&Main_magnifier_offset_X, &Main_magnifier_offset_Y); } void Clip_magnifier_offsets(short *x_offset, short *y_offset) { if (Main_magnifier_mode) { if (*x_offset) { if (Main_image_width<*x_offset+Main_magnifier_width) *x_offset=Main_image_width-Main_magnifier_width; if (*x_offset<0) *x_offset=0; } if (*y_offset) { if (Main_image_height<*y_offset+Main_magnifier_height) *y_offset=Main_image_height-Main_magnifier_height+(Main_magnifier_height*Main_magnifier_factor-Menu_Y>=Main_magnifier_factor/2); if (*y_offset<0) *y_offset=0; } } } /// Changes magnifier factor and updates everything needed void Change_magnifier_factor(byte factor_index, byte point_at_mouse) { int target_x,target_y; // These coordinates are in image space byte magnified_view_leads=1; // Values that need to be computed before switching to the new zoom factor if (!point_at_mouse || Cursor_in_menu || !Main_magnifier_mode) { // Locate the pixel in center of the magnified area target_x = Main_magnifier_offset_X + (Main_magnifier_width >> 1); target_y = Main_magnifier_offset_Y + (Main_magnifier_height >> 1); point_at_mouse=0; } else if (Mouse_X>=Main_X_zoom) { // Locate the pixel under the cursor, in magnified area target_x=((Mouse_X-Main_X_zoom)/Main_magnifier_factor)+Main_magnifier_offset_X; target_y=(Mouse_Y/Main_magnifier_factor)+Main_magnifier_offset_Y; point_at_mouse=1; } else { // Locate the pixel under the cursor, in normal area target_x=Mouse_X+Main_offset_X; target_y=Mouse_Y+Main_offset_Y; magnified_view_leads=0; point_at_mouse=0; } Main_magnifier_factor=ZOOM_FACTOR[factor_index]; Compute_magnifier_data(); if (Main_magnifier_mode) { // Recompute the magnifier offset (center its view) if (point_at_mouse) { // Target pixel must be located under the mouse position. Main_magnifier_offset_X = target_x-((Mouse_X-Main_X_zoom)/Main_magnifier_factor); Main_magnifier_offset_Y = target_y-((Mouse_Y)/Main_magnifier_factor); } else { // Target pixel must be positioned at new center Main_magnifier_offset_X = target_x-(Main_magnifier_width>>1); Main_magnifier_offset_Y = target_y-(Main_magnifier_height>>1); } // Fix cases where the image would overflow on edges Clip_magnifier_offsets(&Main_magnifier_offset_X, &Main_magnifier_offset_Y); if (magnified_view_leads) Position_screen_according_to_zoom(); else Position_screen_according_to_position(target_x, target_y); Pixel_preview=Pixel_preview_magnifier; } else Pixel_preview=Pixel_preview_normal; Compute_limits(); Compute_paintbrush_coordinates(); } void Copy_view_to_spare(void) { // Don't do anything if the pictures have different dimensions if (Main_image_width!=Spare_image_width || Main_image_height!=Spare_image_height) return; // Copie des dcalages de la fentre principale (non zoome) de l'image Spare_offset_X=Main_offset_X; Spare_offset_Y=Main_offset_Y; // Copie du boolen "Mode loupe" de l'image Spare_magnifier_mode=Main_magnifier_mode; // Copie du facteur de zoom du brouillon Spare_magnifier_factor=Main_magnifier_factor; // Copie des dimensions de la fentre de zoom Spare_magnifier_width=Main_magnifier_width; Spare_magnifier_height=Main_magnifier_height; // Copie des dcalages de la fentre de zoom Spare_magnifier_offset_X=Main_magnifier_offset_X; Spare_magnifier_offset_Y=Main_magnifier_offset_Y; // Copie des donnes du split du zoom Spare_separator_position=Main_separator_position; Spare_X_zoom=Main_X_zoom; Spare_separator_proportion=Main_separator_proportion; } // -- Afficher la barre de sparation entre les parties zoomes ou non en // mode Loupe -- void Display_separator(void) { // Partie grise du milieu Block(Main_separator_position+(Menu_factor_X<<1),Menu_factor_Y, (SEPARATOR_WIDTH-4)*Menu_factor_X, Menu_Y-(Menu_factor_Y<<1),MC_Light); // Barre noire de gauche Block(Main_separator_position,0,Menu_factor_X,Menu_Y,MC_Black); // Barre noire de droite Block(Main_X_zoom-Menu_factor_X,0,Menu_factor_X,Menu_Y,MC_Black); // Bord haut (blanc) Block(Main_separator_position+Menu_factor_X,0, (SEPARATOR_WIDTH-3)*Menu_factor_X,Menu_factor_Y,MC_White); // Bord gauche (blanc) Block(Main_separator_position+Menu_factor_X,Menu_factor_Y, Menu_factor_X,(Menu_Y-(Menu_factor_Y<<1)),MC_White); // Bord droite (gris fonc) Block(Main_X_zoom-(Menu_factor_X<<1),Menu_factor_Y, Menu_factor_X,(Menu_Y-(Menu_factor_Y<<1)),MC_Dark); // Bord bas (gris fonc) Block(Main_separator_position+(Menu_factor_X<<1),Menu_Y-Menu_factor_Y, (SEPARATOR_WIDTH-3)*Menu_factor_X,Menu_factor_Y,MC_Dark); // Coin bas gauche Block(Main_separator_position+Menu_factor_X,Menu_Y-Menu_factor_Y, Menu_factor_X,Menu_factor_Y,MC_Light); // Coin haut droite Block(Main_X_zoom-(Menu_factor_X<<1),0, Menu_factor_X,Menu_factor_Y,MC_Light); Update_rect(Main_separator_position,0,SEPARATOR_WIDTH*Menu_factor_X,Menu_Y); // On raffiche toute la partie gauche du split, ce qui permet d'effacer son ancienne position } // -- Fonctions de manipulation du curseur ----------------------------------- // -- Afficher une barre horizontale XOR zoome void Horizontal_XOR_line_zoom(short x_pos, short y_pos, short width) { short real_x_pos=Main_X_zoom+(x_pos-Main_magnifier_offset_X)*Main_magnifier_factor; short real_y_pos=(y_pos-Main_magnifier_offset_Y)*Main_magnifier_factor; short real_width=width*Main_magnifier_factor; short end_y_pos=(real_y_pos+Main_magnifier_factor=Main_X_zoom) ) ) || (Windows_open) || (Cursor_shape==CURSOR_SHAPE_HOURGLASS) ) shape=Cursor_shape; else shape=CURSOR_SHAPE_ARROW; switch(shape) { case CURSOR_SHAPE_TARGET : if (!Paintbrush_hidden) Display_paintbrush(Paintbrush_X,Paintbrush_Y,Fore_color,1); if (!Cursor_hidden) { if (Config.Cursor==1) { start_y=(Mouse_Y<6)?6-Mouse_Y:0; if (start_y<4) Vertical_XOR_line (Mouse_X,Mouse_Y+start_y-6,4-start_y); start_x=(Mouse_X<6)?(short)6-Mouse_X:0; if (start_x<4) Horizontal_XOR_line(Mouse_X+start_x-6,Mouse_Y,4-start_x); end_x=(Mouse_X+7>Screen_width)?Mouse_X+7-Screen_width:0; if (end_x<4) Horizontal_XOR_line(Mouse_X+3,Mouse_Y,4-end_x); end_y=(Mouse_Y+7>Screen_height)?Mouse_Y+7-Screen_height:0; if (end_y<4) Vertical_XOR_line (Mouse_X,Mouse_Y+3,4-end_y); Update_rect(Mouse_X+start_x-6,Mouse_Y+start_y-6,13-end_x,13-end_y); } else { temp=(Config.Cursor)?CURSOR_SHAPE_THIN_TARGET:CURSOR_SHAPE_TARGET; start_x=Mouse_X-Gfx->Cursor_offset_X[temp]; start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; for (y_pos=start_y,counter_y=0; counter_y<15 && y_pos < Screen_height; y_pos++,counter_y++) { if( y_pos < 0 ) continue; for (x_pos=start_x,counter_x=0; counter_x<15 && x_pos < Screen_width; x_pos++,counter_x++) { if( x_pos < 0 ) continue; color=Gfx->Cursor_sprite[temp][counter_y][counter_x]; Cursor_background[counter_y][counter_x]=Read_pixel(x_pos,y_pos); if (color!=MC_Trans) Pixel(x_pos,y_pos,color); } } Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); } } break; case CURSOR_SHAPE_COLORPICKER: if (!Paintbrush_hidden) Display_paintbrush(Paintbrush_X,Paintbrush_Y,Fore_color,1); if (Config.Cursor==1) { // Barres formant la croix principale start_y=(Mouse_Y<5)?5-Mouse_Y:0; if (start_y<3) Vertical_XOR_line (Mouse_X,Mouse_Y+start_y-5,3-start_y); start_x=(Mouse_X<5)?(short)5-Mouse_X:0; if (start_x<3) Horizontal_XOR_line(Mouse_X+start_x-5,Mouse_Y,3-start_x); end_x=(Mouse_X+6>Screen_width)?Mouse_X+6-Screen_width:0; if (end_x<3) Horizontal_XOR_line(Mouse_X+3,Mouse_Y,3-end_x); end_y=(Mouse_Y+6>Menu_Y/*Screen_height*/)?Mouse_Y+6-Menu_Y/*Screen_height*/:0; if (end_y<3) Vertical_XOR_line (Mouse_X,Mouse_Y+3,3-end_y); // Petites barres aux extrmits start_x=(!Mouse_X); start_y=(!Mouse_Y); end_x=(Mouse_X>=Screen_width-1); end_y=(Mouse_Y>=Menu_Y-1); if (Mouse_Y>5) Horizontal_XOR_line(start_x+Mouse_X-1,Mouse_Y-6,3-(start_x+end_x)); if (Mouse_X>5) Vertical_XOR_line (Mouse_X-6,start_y+Mouse_Y-1,3-(start_y+end_y)); if (Mouse_XCursor_offset_X[temp]; start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) { if(y_pos<0) continue; if(y_pos>=Screen_height) break; for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) { if(x_pos<0) continue; if(x_pos>=Screen_width) break; color=Gfx->Cursor_sprite[temp][counter_y][counter_x]; // On sauvegarde dans Cursor_background pour restaurer plus tard Cursor_background[counter_y][counter_x]=Read_pixel(x_pos,y_pos); if (color!=MC_Trans) Pixel(x_pos,y_pos,color); } } Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); } break; case CURSOR_SHAPE_MULTIDIRECTIONAL : case CURSOR_SHAPE_HORIZONTAL : if (Cursor_hidden) break; case CURSOR_SHAPE_ARROW : case CURSOR_SHAPE_HOURGLASS : start_x=Mouse_X-Gfx->Cursor_offset_X[shape]; start_y=Mouse_Y-Gfx->Cursor_offset_Y[shape]; for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) { if(y_pos<0) continue; if(y_pos>=Screen_height) break; for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) { if(x_pos<0) continue; if(x_pos>=Screen_width) break; color=Gfx->Cursor_sprite[shape][counter_y][counter_x]; // On sauvegarde dans Cursor_background pour restaurer plus tard Cursor_background[counter_y][counter_x]=Read_pixel(x_pos,y_pos); if (color!=MC_Trans) Pixel(x_pos,y_pos,color); } } Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); break; case CURSOR_SHAPE_XOR_TARGET : x_pos=Paintbrush_X-Main_offset_X; y_pos=Paintbrush_Y-Main_offset_Y; counter_x=(Main_magnifier_mode)?Main_separator_position:Screen_width; // width de la barre XOR if ((y_pos=Limit_top)) { Horizontal_XOR_line(0,Paintbrush_Y-Main_offset_Y,counter_x); Update_rect(0,Paintbrush_Y-Main_offset_Y,counter_x,1); } if ((x_pos=Limit_left)) { Vertical_XOR_line(Paintbrush_X-Main_offset_X,0,Menu_Y); Update_rect(Paintbrush_X-Main_offset_X,0,1,Menu_Y); } if (Main_magnifier_mode) { // UPDATERECT if ((Paintbrush_Y>=Limit_top_zoom) && (Paintbrush_Y<=Limit_visible_bottom_zoom)) Horizontal_XOR_line_zoom(Limit_left_zoom,Paintbrush_Y,Main_magnifier_width); if ((Paintbrush_X>=Limit_left_zoom) && (Paintbrush_X<=Limit_visible_right_zoom)) Vertical_XOR_line_zoom(Paintbrush_X,Limit_top_zoom,Main_magnifier_height); } break; case CURSOR_SHAPE_XOR_RECTANGLE : // !!! Cette forme ne peut pas tre utilise en mode Loupe !!! // Petite croix au centre start_x=(Mouse_X-3); start_y=(Mouse_Y-3); end_x =(Mouse_X+4); end_y =(Mouse_Y+4); if (start_x<0) start_x=0; if (start_y<0) start_y=0; if (end_x>Screen_width) end_x=Screen_width; if (end_y>Menu_Y) end_y=Menu_Y; Horizontal_XOR_line(start_x,Mouse_Y,end_x-start_x); Vertical_XOR_line (Mouse_X,start_y,end_y-start_y); // Grand rectangle autour start_x=Mouse_X-(Main_magnifier_width>>1); start_y=Mouse_Y-(Main_magnifier_height>>1); if (start_x+Main_magnifier_width>=Limit_right-Main_offset_X) start_x=Limit_right-Main_magnifier_width-Main_offset_X+1; if (start_y+Main_magnifier_height>=Limit_bottom-Main_offset_Y) start_y=Limit_bottom-Main_magnifier_height-Main_offset_Y+1; if (start_x<0) start_x=0; if (start_y<0) start_y=0; end_x=start_x+Main_magnifier_width-1; end_y=start_y+Main_magnifier_height-1; Horizontal_XOR_line(start_x,start_y,Main_magnifier_width); Vertical_XOR_line(start_x,start_y+1,Main_magnifier_height-2); Vertical_XOR_line( end_x,start_y+1,Main_magnifier_height-2); Horizontal_XOR_line(start_x, end_y,Main_magnifier_width); Update_rect(start_x,start_y,end_x+1-start_x,end_y+1-start_y); break; default: //case CURSOR_SHAPE_XOR_ROTATION : start_x=1-(Brush_width>>1); start_y=1-(Brush_height>>1); end_x=start_x+Brush_width-1; end_y=start_y+Brush_height-1; if (Brush_rotation_center_is_defined) { if ( (Brush_rotation_center_X==Paintbrush_X) && (Brush_rotation_center_Y==Paintbrush_Y) ) { cos_a=1.0; sin_a=0.0; } else { x_pos=Paintbrush_X-Brush_rotation_center_X; y_pos=Paintbrush_Y-Brush_rotation_center_Y; cos_a=(float)x_pos/sqrt((x_pos*x_pos)+(y_pos*y_pos)); sin_a=sin(acos(cos_a)); if (y_pos>0) sin_a=-sin_a; } Transform_point(start_x,start_y, cos_a,sin_a, &x1,&y1); Transform_point(end_x ,start_y, cos_a,sin_a, &x2,&y2); Transform_point(start_x,end_y , cos_a,sin_a, &x3,&y3); Transform_point(end_x ,end_y , cos_a,sin_a, &x4,&y4); x1+=Brush_rotation_center_X; y1+=Brush_rotation_center_Y; x2+=Brush_rotation_center_X; y2+=Brush_rotation_center_Y; x3+=Brush_rotation_center_X; y3+=Brush_rotation_center_Y; x4+=Brush_rotation_center_X; y4+=Brush_rotation_center_Y; Pixel_figure_preview_xor(Brush_rotation_center_X,Brush_rotation_center_Y,0); Draw_line_preview_xor(Brush_rotation_center_X,Brush_rotation_center_Y,Paintbrush_X,Paintbrush_Y,0); } else { x1=x3=1-Brush_width; y1=y2=start_y; x2=x4=Paintbrush_X; y3=y4=end_y; x1+=Paintbrush_X; y1+=Paintbrush_Y; y2+=Paintbrush_Y; x3+=Paintbrush_X; y3+=Paintbrush_Y; y4+=Paintbrush_Y; Pixel_figure_preview_xor(Paintbrush_X-end_x,Paintbrush_Y,0); Draw_line_preview_xor(Paintbrush_X-end_x,Paintbrush_Y,Paintbrush_X,Paintbrush_Y,0); } Draw_line_preview_xor(x1,y1,x2,y2,0); Draw_line_preview_xor(x2,y2,x4,y4,0); Draw_line_preview_xor(x4,y4,x3,y3,0); Draw_line_preview_xor(x3,y3,x1,y1,0); } } // -- Effacer le curseur -- void Hide_cursor(void) { byte shape; int start_x; // int car sont parfois ngatifs ! (quand on dessine sur un bord) int start_y; short end_x; short end_y; int x_pos = 0; int y_pos; short counter_x = 0; short counter_y; int temp; float cos_a,sin_a; short x1,y1,x2,y2,x3,y3,x4,y4; if ( ( (Mouse_Y=Main_X_zoom) ) ) || (Windows_open) || (Cursor_shape==CURSOR_SHAPE_HOURGLASS) ) shape=Cursor_shape; else shape=CURSOR_SHAPE_ARROW; switch(shape) { case CURSOR_SHAPE_TARGET : if (!Cursor_hidden) { if (Config.Cursor==1) { start_y=(Mouse_Y<6)?6-Mouse_Y:0; if (start_y<4) Vertical_XOR_line (Mouse_X,Mouse_Y+start_y-6,4-start_y); start_x=(Mouse_X<6)?(short)6-Mouse_X:0; if (start_x<4) Horizontal_XOR_line(Mouse_X+start_x-6,Mouse_Y,4-start_x); end_x=(Mouse_X+7>Screen_width)?Mouse_X+7-Screen_width:0; if (end_x<4) Horizontal_XOR_line(Mouse_X+3,Mouse_Y,4-end_x); end_y=(Mouse_Y+7>Screen_height)?Mouse_Y+7-Screen_height:0; if (end_y<4) Vertical_XOR_line (Mouse_X,Mouse_Y+3,4-end_y); Update_rect(Mouse_X+start_x-6,Mouse_Y+start_y-6,13-end_x,13-end_y); } else { temp=(Config.Cursor)?CURSOR_SHAPE_THIN_TARGET:CURSOR_SHAPE_TARGET; start_x=Mouse_X-Gfx->Cursor_offset_X[temp]; start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) { if(y_pos < 0) continue; if(y_pos>=Screen_height) break; for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) { if(x_pos < 0) continue; else if (x_pos>=Screen_width) break; Pixel(x_pos,y_pos,Cursor_background[counter_y][counter_x]); } } Update_rect(Max(start_x,0),Max(start_y,0),x_pos-start_x,y_pos-start_y); } } if (!Paintbrush_hidden) { Hide_paintbrush(Paintbrush_X,Paintbrush_Y); } break; case CURSOR_SHAPE_COLORPICKER: if (Config.Cursor==1) { // Barres formant la croix principale start_y=(Mouse_Y<5)?5-Mouse_Y:0; if (start_y<3) Vertical_XOR_line (Mouse_X,Mouse_Y+start_y-5,3-start_y); start_x=(Mouse_X<5)?(short)5-Mouse_X:0; if (start_x<3) Horizontal_XOR_line(Mouse_X+start_x-5,Mouse_Y,3-start_x); end_x=(Mouse_X+6>Screen_width)?Mouse_X+6-Screen_width:0; if (end_x<3) Horizontal_XOR_line(Mouse_X+3,Mouse_Y,3-end_x); end_y=(Mouse_Y+6>Screen_height)?Mouse_Y+6-Screen_height:0; if (end_y<3) Vertical_XOR_line (Mouse_X,Mouse_Y+3,3-end_y); start_x=(!Mouse_X); start_y=(!Mouse_Y); end_x=(Mouse_X>=Screen_width-1); end_y=(Mouse_Y>=Menu_Y-1); if (Mouse_Y>5) Horizontal_XOR_line(start_x+Mouse_X-1,Mouse_Y-6,3-(start_x+end_x)); if (Mouse_X>5) Vertical_XOR_line (Mouse_X-6,start_y+Mouse_Y-1,3-(start_y+end_y)); if (Mouse_XCursor_offset_X[temp]; start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) { if(y_pos<0) continue; if(y_pos>=Screen_height) break; for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) { if(x_pos<0) continue; if(x_pos>=Screen_width) break; Pixel(x_pos,y_pos,Cursor_background[counter_y][counter_x]); } } Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); } if (!Paintbrush_hidden) Hide_paintbrush(Paintbrush_X,Paintbrush_Y); break; case CURSOR_SHAPE_MULTIDIRECTIONAL : case CURSOR_SHAPE_HORIZONTAL : if (Cursor_hidden) break; case CURSOR_SHAPE_ARROW : case CURSOR_SHAPE_HOURGLASS : start_x=Mouse_X-Gfx->Cursor_offset_X[shape]; start_y=Mouse_Y-Gfx->Cursor_offset_Y[shape]; for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) { if(y_pos<0) continue; if(y_pos>=Screen_height) break; for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) { if(x_pos<0) continue; if(x_pos>=Screen_width) break; Pixel(x_pos,y_pos,Cursor_background[counter_y][counter_x]); } } Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); break; case CURSOR_SHAPE_XOR_TARGET : x_pos=Paintbrush_X-Main_offset_X; y_pos=Paintbrush_Y-Main_offset_Y; counter_x=(Main_magnifier_mode)?Main_separator_position:Screen_width; // width de la barre XOR if ((y_pos=Limit_top)) { Horizontal_XOR_line(0,Paintbrush_Y-Main_offset_Y,counter_x); Update_rect(0,Paintbrush_Y-Main_offset_Y,counter_x,1); } if ((x_pos=Limit_left)) { Vertical_XOR_line(Paintbrush_X-Main_offset_X,0,Menu_Y); Update_rect(Paintbrush_X-Main_offset_X,0,1,Menu_Y); } if (Main_magnifier_mode) { // UPDATERECT if ((Paintbrush_Y>=Limit_top_zoom) && (Paintbrush_Y<=Limit_visible_bottom_zoom)) Horizontal_XOR_line_zoom(Limit_left_zoom,Paintbrush_Y,Main_magnifier_width); if ((Paintbrush_X>=Limit_left_zoom) && (Paintbrush_X<=Limit_visible_right_zoom)) Vertical_XOR_line_zoom(Paintbrush_X,Limit_top_zoom,Main_magnifier_height); } break; case CURSOR_SHAPE_XOR_RECTANGLE : // !!! Cette forme ne peut pas tre utilise en mode Loupe !!! // Petite croix au centre start_x=(Mouse_X-3); start_y=(Mouse_Y-3); end_x =(Mouse_X+4); end_y =(Mouse_Y+4); if (start_x<0) start_x=0; if (start_y<0) start_y=0; if (end_x>Screen_width) end_x=Screen_width; if (end_y>Menu_Y) end_y=Menu_Y; Horizontal_XOR_line(start_x,Mouse_Y,end_x-start_x); Vertical_XOR_line (Mouse_X,start_y,end_y-start_y); // Grand rectangle autour start_x=Mouse_X-(Main_magnifier_width>>1); start_y=Mouse_Y-(Main_magnifier_height>>1); if (start_x+Main_magnifier_width>=Limit_right-Main_offset_X) start_x=Limit_right-Main_magnifier_width-Main_offset_X+1; if (start_y+Main_magnifier_height>=Limit_bottom-Main_offset_Y) start_y=Limit_bottom-Main_magnifier_height-Main_offset_Y+1; if (start_x<0) start_x=0; if (start_y<0) start_y=0; end_x=start_x+Main_magnifier_width-1; end_y=start_y+Main_magnifier_height-1; Horizontal_XOR_line(start_x,start_y,Main_magnifier_width); Vertical_XOR_line(start_x,start_y+1,Main_magnifier_height-2); Vertical_XOR_line( end_x,start_y+1,Main_magnifier_height-2); Horizontal_XOR_line(start_x, end_y,Main_magnifier_width); Update_rect(start_x,start_y,end_x+1-start_x,end_y+1-start_y); break; default: //case CURSOR_SHAPE_XOR_ROTATION : start_x=1-(Brush_width>>1); start_y=1-(Brush_height>>1); end_x=start_x+Brush_width-1; end_y=start_y+Brush_height-1; if (Brush_rotation_center_is_defined) { if ( (Brush_rotation_center_X==Paintbrush_X) && (Brush_rotation_center_Y==Paintbrush_Y) ) { cos_a=1.0; sin_a=0.0; } else { x_pos=Paintbrush_X-Brush_rotation_center_X; y_pos=Paintbrush_Y-Brush_rotation_center_Y; cos_a=(float)x_pos/sqrt((x_pos*x_pos)+(y_pos*y_pos)); sin_a=sin(acos(cos_a)); if (y_pos>0) sin_a=-sin_a; } Transform_point(start_x,start_y, cos_a,sin_a, &x1,&y1); Transform_point(end_x ,start_y, cos_a,sin_a, &x2,&y2); Transform_point(start_x,end_y , cos_a,sin_a, &x3,&y3); Transform_point(end_x ,end_y , cos_a,sin_a, &x4,&y4); x1+=Brush_rotation_center_X; y1+=Brush_rotation_center_Y; x2+=Brush_rotation_center_X; y2+=Brush_rotation_center_Y; x3+=Brush_rotation_center_X; y3+=Brush_rotation_center_Y; x4+=Brush_rotation_center_X; y4+=Brush_rotation_center_Y; Pixel_figure_preview_xor(Brush_rotation_center_X,Brush_rotation_center_Y,0); Draw_line_preview_xor(Brush_rotation_center_X,Brush_rotation_center_Y,Paintbrush_X,Paintbrush_Y,0); } else { x1=x3=1-Brush_width; y1=y2=start_y; x2=x4=Paintbrush_X; y3=y4=end_y; x1+=Paintbrush_X; y1+=Paintbrush_Y; y2+=Paintbrush_Y; x3+=Paintbrush_X; y3+=Paintbrush_Y; y4+=Paintbrush_Y; Pixel_figure_preview_xor(Paintbrush_X-end_x,Paintbrush_Y,0); Draw_line_preview_xor(Paintbrush_X-end_x,Paintbrush_Y,Paintbrush_X,Paintbrush_Y,0); } Draw_line_preview_xor(x1,y1,x2,y2,0); Draw_line_preview_xor(x2,y2,x4,y4,0); Draw_line_preview_xor(x4,y4,x3,y3,0); Draw_line_preview_xor(x3,y3,x1,y1,0); } } // -- Fonction diverses d'affichage ------------------------------------------ // -- Reafficher toute l'image (en prenant en compte le facteur de zoom) -- void Display_all_screen(void) { word width; word height; // ---/\/\/\ Partie non zoome: /\/\/\--- if (Main_magnifier_mode) { if (Main_image_widthPages->Transparent_color); } else { if (Main_image_widthPages->Transparent_color); } if (Main_image_heightPages->Transparent_color); // ---/\/\/\ Partie zoome: /\/\/\--- if (Main_magnifier_mode) { // Affichage de la barre de split Display_separator(); // Calcul de la largeur visible if (Main_image_widthPages->Transparent_color); if (heightPages->Transparent_color); } // ---/\/\/\ Affichage des limites /\/\/\--- if (Config.Display_image_limits) Display_image_limits(); Update_rect(0,0,Screen_width,Menu_Y); // TODO On peut faire plus fin, en vitant de mettre jour la partie droite du split quand on est en mode loupe. Mais c'est pas vraiment intressant ? } byte Best_color(byte r,byte g,byte b) { int col; int delta_r,delta_g,delta_b; int dist; int best_dist=0x7FFFFFFF; int rmean; byte best_color=0; for (col=0; col<256; col++) { if (!Exclude_color[col]) { delta_r=(int)Main_palette[col].R-r; delta_g=(int)Main_palette[col].G-g; delta_b=(int)Main_palette[col].B-b; rmean = ( Main_palette[col].R + r ) / 2; if (!(dist= ( ( (512+rmean) *delta_r*delta_r) >>8) + 4*delta_g*delta_g + (((767-rmean)*delta_b*delta_b)>>8))) //if (!(dist=(delta_r*delta_r*30)+(delta_g*delta_g*59)+(delta_b*delta_b*11))) return col; if (dist>8) + 4*delta_g*delta_g + (((767-rmean)*delta_b*delta_b)>>8); //dist=(delta_r*delta_r*30)+(delta_g*delta_g*59)+(delta_b*delta_b*11) if (dist=0; i--) { if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[3]].R/tolerence && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[3]].G/tolerence && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[3]].B/tolerence) { MC_White=i; for (i=255; i>=0; i--) { if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[2]].R/tolerence && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[2]].G/tolerence && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[2]].B/tolerence) { MC_Light=i; for (i=255; i>=0; i--) { if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[1]].R/tolerence && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[1]].G/tolerence && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[1]].B/tolerence) { MC_Dark=i; for (i=255; i>=0; i--) { if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[0]].R/tolerence && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[0]].G/tolerence && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[0]].B/tolerence) { MC_Black=i; // On cherche une couleur de transparence diffrente des 4 autres. for (MC_Trans=0; ((MC_Trans==MC_Black) || (MC_Trans==MC_Dark) || (MC_Trans==MC_Light) || (MC_Trans==MC_White)); MC_Trans++); // Easy case MC_OnBlack=MC_Dark; MC_Window=MC_Light; MC_Lighter=MC_White; MC_Darker=MC_Dark; Remap_menu_sprites(); return; } } } } } } } } // Second method: For CPC 27-color modes only // Try to find colors that just work if (Get_palette_RGB_scale()==3) for (i=255; i>=0; i--) { if (Round_palette_component(palette[i].R)/tolerence==cpc_colors[3].R/tolerence && Round_palette_component(palette[i].G)/tolerence==cpc_colors[3].G/tolerence && Round_palette_component(palette[i].B)/tolerence==cpc_colors[3].B/tolerence) { MC_White=i; for (i=255; i>=0; i--) { if (Round_palette_component(palette[i].R)/tolerence==cpc_colors[2].R/tolerence && Round_palette_component(palette[i].G)/tolerence==cpc_colors[2].G/tolerence && Round_palette_component(palette[i].B)/tolerence==cpc_colors[2].B/tolerence) { MC_Light=i; for (i=255; i>=0; i--) { if (Round_palette_component(palette[i].R)/tolerence==cpc_colors[1].R/tolerence && Round_palette_component(palette[i].G)/tolerence==cpc_colors[1].G/tolerence && Round_palette_component(palette[i].B)/tolerence==cpc_colors[1].B/tolerence) { MC_Dark=i; for (i=255; i>=0; i--) { if (Round_palette_component(palette[i].R)/tolerence==cpc_colors[0].R/tolerence && Round_palette_component(palette[i].G)/tolerence==cpc_colors[0].G/tolerence && Round_palette_component(palette[i].B)/tolerence==cpc_colors[0].B/tolerence) { MC_Black=i; // On cherche une couleur de transparence diffrente des 4 autres. for (MC_Trans=0; ((MC_Trans==MC_Black) || (MC_Trans==MC_Dark) || (MC_Trans==MC_Light) || (MC_Trans==MC_White)); MC_Trans++); // Easy case MC_OnBlack=MC_Dark; MC_Window=MC_Light; MC_Lighter=MC_White; MC_Darker=MC_Dark; Remap_menu_sprites(); return; } } } } } } } } // Third method: // Compute luminance for whole palette // Take the darkest as black, the brightest white for(i = 0; i < 256; i++) { RGB_to_HSL(palette[i].R, palette[i].G, palette[i].B, &h, &s[i], &l[i]); // Another formula for lightness, in 0-255 range //l[i]=Perceptual_lightness(&palette[i])/4062/255; if (l[i] > max_l) { max_l = l[i]; MC_White = i; } } for(i = 0; i < 256; i++) { if (l[i] < min_l && i!=MC_White) { min_l = l[i]; MC_Black = i; } } // Alter the S values according to the L range - this is for the future // comparisons, so that highly variable saturation doesn't weigh // too heavily when the the lightness is in a narrow range. for(i = 0; i < 256; i++) { s[i]=s[i]*(max_l-min_l)/255; } for(i = 0; i < 256; i++) { // Adjust (reduce) perceived saturation at both ends of L spectrum if (l[i]>192) s[i]=s[i]*(255-l[i])/64; else if (l[i]<64) s[i]=s[i]*l[i]/64; } // Find color nearest to min+2(max-min)/3 // but at the same time we try to minimize the saturation so that the menu // still looks grey hi_l = min_l + 2*(max_l - min_l)/3; for (i = 0; i < 256; i++) { if ( abs(l[i] - hi_l) + s[i]/2 < delta_high && i!=MC_White && i!=MC_Black) { delta_high = abs(l[i] - hi_l) + s[i]/2; MC_Light = i; } } // Target "Dark color" is 2/3 between Light and Black low_l = ((int)l[MC_Light]*2+l[MC_Black])/3; for (i = 0; i < 256; i++) { if ( abs((int)l[i] - low_l) + s[i]/6 < delta_low && i!=MC_White && i!=MC_Black && i!=MC_Light) { delta_low = abs((int)l[i] - low_l)+ s[i]/6; MC_Dark = i; } } //if (l[MC_Light]Cursor_sprite[k][j][i]); // Main menu bar for (k=0; k<3; k++) for (j=0; jMenu_block[k][j][i]); // Menu sprites for (l=0; l<2; l++) for (k=0; kMenu_sprite[l][k][j][i]); // Effects sprites for (k=0; kEffect_sprite[k][j][i]); // Layers buttons for (l=0; l<3; l++) for (k=0; k<16; k++) for (j=0; jLayer_sprite[l][k][j][i]); // Status bar for (k=0; k<3; k++) for (j=0; jStatusbar_block[k][j][i]); // Layer bar for (k=0; k<3; k++) for (j=0; jLayerbar_block[k][j][i]); // Help fonts for (k=0; k<256; k++) for (j=0; j<8; j++) for (i=0; i<6; i++) Remap_pixel(&Gfx->Help_font_norm[k][i][j]); for (k=0; k<256; k++) for (j=0; j<8; j++) for (i=0; i<6; i++) Remap_pixel(&Gfx->Bold_font[k][i][j]); for (k=0; k<64; k++) for (j=0; j<8; j++) for (i=0; i<6; i++) Remap_pixel(&Gfx->Help_font_t1[k][i][j]); for (k=0; k<64; k++) for (j=0; j<8; j++) for (i=0; i<6; i++) Remap_pixel(&Gfx->Help_font_t2[k][i][j]); for (k=0; k<64; k++) for (j=0; j<8; j++) for (i=0; i<6; i++) Remap_pixel(&Gfx->Help_font_t3[k][i][j]); for (k=0; k<64; k++) for (j=0; j<8; j++) for (i=0; i<6; i++) Remap_pixel(&Gfx->Help_font_t4[k][i][j]); // Drives and other misc. 8x8 icons for (k=0; kIcon_sprite[k][j][i]); // Skin preview for (j = 0; j < 173; j++) for (i = 0; i < 16; i++) Remap_pixel(&Gfx->Preview[i][j]); } Clear_border(MC_Black); } grafx2/src/SDLMain.h0000644000076400010400000000046311343525620014625 0ustar vigAdministrator/* SDLMain.m - main entry point for our Cocoa-ized SDL app Initial Version: Darrell Walisser Non-NIB-Code & other changes: Max Horn Feel free to customize this file to suit your needs */ #import @interface SDLMain : NSObject @end grafx2/src/SFont.h0000644000076400010400000001002511532234750014423 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* SFont: a simple font-library that uses special bitmaps as fonts Copyright (C) 2003 Karl Bartel License: GPL or LGPL (at your choice) WWW: http://www.linux-games.com/sfont/ This program 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; either version 2 of the License, or (at your option) any later version. This program 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 this program; if not, see . Karl Bartel Cecilienstr. 14 12307 Berlin GERMANY karlb@gmx.net */ /************************************************************************ * SFONT - SDL Font Library by Karl Bartel * * * * All functions are explained below. For further information, take a * * look at the example files, the links at the SFont web site, or * * contact me, if you problem isn' addressed anywhere. * * * ************************************************************************/ ////////////////////////////////////////////////////////////////////////////// ///@file SFont.h /// Text rendering system, that uses bitmaps as fonts. /// Not specific to Grafx2, it writes to SDL_Surface. ////////////////////////////////////////////////////////////////////////////// #ifndef _SFONT_H_ #define _SFONT_H_ #include #ifdef __cplusplus extern "C" { #endif /// /// Declare one variable of this type for each font you are using. /// To load the fonts, load the font image into YourFont->Surface /// and call InitFont( YourFont ); typedef struct { SDL_Surface *Surface; int CharBegin[256]; int CharWidth[256]; int Space; unsigned char Transparent; } SFont_Font; /// /// Initializes the font. /// @param Font this contains the suface with the font. /// The Surface must be loaded before calling this function SFont_Font* SFont_InitFont (SDL_Surface *Font); /// /// Frees the font. /// @param Font The font to free /// The font must be loaded before using this function. void SFont_FreeFont(SFont_Font* Font); /// /// Blits a string to a surface. /// @param Surface The surface you want to blit to. /// @param Font The font to use. /// @param text A string containing the text you want to blit. /// @param x Coordinates to start drawing. /// @param y Coordinates to start drawing. void SFont_Write(SDL_Surface *Surface, const SFont_Font *Font, int x, int y, const char *text); /// Returns the width of "text" in pixels int SFont_TextWidth(const SFont_Font* Font, const char *text); /// Returns the height of "text" in pixels (which is always equal to Font->Surface->h) int SFont_TextHeight(const SFont_Font* Font, const char *text); /// Blits a string to Surface with centered x position void SFont_WriteCenter(SDL_Surface *Surface, const SFont_Font* Font, int y, const char *text); #ifdef __cplusplus } #endif #endif /* SFONT_H */ grafx2/src/brush.h0000644000076400010400000001012411521112174014506 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007-2008 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file brush.h /// Actions on the brush. ////////////////////////////////////////////////////////////////////////////// #ifndef __BRUSH_H_ #define __BRUSH_H_ #include "struct.h" /*! Gets the brush from the picture. @param start_x left edge coordinate in the picture @param start_y upper edge coordinate in the picture @param end_x right edge coordinate in the picture @param end_y bottom edge coordinate in the picture @param clear If 1, the area is also cleared from the picture. */ void Capture_brush(short start_x,short start_y,short end_x,short end_y,short clear); /*! Rotates the brush to the right. */ void Rotate_90_deg(void); /*! Stretch the brush to fit the given rectangle. */ void Stretch_brush(short x1, short y1, short x2, short y2); /*! Stretch the brush to fit the given rectangle. Uses fast approximation for the preview while drawing the rectangle on screen. */ void Stretch_brush_preview(short x1, short y1, short x2, short y2); /*! Rotates the brush to the right from the given angle. */ void Rotate_brush(float angle); /*! Stretch the brush to fit the given rectangle. Uses fast approximation for the preview while changing the angle. */ 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); /*! Get color indexes used by the brush. */ void Get_colors_from_brush(void); /*! Outline the brush, add 1 foreground-colored pixel on the edges. Edges are detected considering the backcolor as transparent. */ void Outline_brush(void); /*! Nibble the brush, remove 1 pixel on the edges and make it transparent (ie filled with back color). Edges are detected considering the backcolor as transparent. */ void Nibble_brush(void); /*! Get brush from picture according to a freehand form. @param vertices number of points in the freehand form @param points array of points coordinates @param clear If set to 1, the captured area is also cleared from the picture. */ void Capture_brush_with_lasso(int vertices, short * points,short clear); /// /// Changes the Brush size. /// @return 0 on success, non-zero on failure (memory?). /// @param new_brush: Optionally, you can provide an already allocated new /// brush - otherwise, this function performs the allocation. /// @param old_brush: If the caller passes NULL, this function will free the old /// pixel data. If the caller provides the address of a (free) byte /// pointer, the function will make it point to the original pixel data, /// in this case it will be the caller's responsibility to free() it /// (after transferring pixels to Brush, usually). byte Realloc_brush(word new_brush_width, word new_brush_height, byte *new_brush, byte **old_brush); /// Sets brush's original palette and color mapping. void Brush_set_palette(T_Palette *palette); #endif grafx2/src/buttons.h0000644000076400010400000003440511524036324015076 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ //////////////////////////////////////////////////////////////////////////// ///@file buttons.h /// Almost all the editor actions that are called by the menu are here. //////////////////////////////////////////////////////////////////////////// #ifndef __BOUTONS_H_ #define __BOUTONS_H_ #include "struct.h" void Stencil_update_color(byte color); void Stencil_tag_color(byte color, byte tag_color); /*! Displays an error message when there is no more memory for the requested operation. */ void Message_out_of_memory(void); /*! Displays the splash screen at program startup. */ void Button_Message_initial(void); /*! Changes brush shape. This function saves the current brush shape and swith to the default one (single pixel brush) for the filler and the color picker. These functions don't need (and will not work with) a custom brush. */ void Change_paintbrush_shape(byte shape); // Boutons relatifs aux couleurs /*! Callback for the palette scroller buttons left click. Scrolls the menubar palette one column to the left. */ void Button_Pal_left(void); /*! Callback for the palette scroller buttons right click. Scrolls the menubar palette faster to the left. */ void Button_Pal_left_fast(void); /*! Callback for the palette scroller buttons left click. Scrolls the menubar palette one column to the right. */ void Button_Pal_right(void); /*! Callback for the palette scroller buttons right click. Scrolls the menubar palette faster to the right. */ void Button_Pal_right_fast(void); /*! Callback for the palette color buttons left click. Selects the foreground drawing color when clicking on the menubar palette. */ void Button_Select_forecolor(void); /*! Callback for the palette color buttons right click. Selects the background drawing color when clicking on the menubar palette. */ void Button_Select_backcolor(void); // Boutons relatifs au pinceaux /*! Callback for the brush button left click. Selects the monochrome brush mode when right clicking on the brush button. */ void Button_Brush_monochrome(void); /*! Callback for the brush button right click. Displays the "Paintbrush menu". */ void Button_Paintbrush_menu(void); // Boutons relatifs au mode de dessin main leve /*! Callback for the freehand draw button left click. Selects freehand drawing mode, depending on the current state of the freehand button. */ void Button_Draw(void); /*! Callback for the freehand draw button right click. Cycles the drawing modes for the freehand tool. */ void Button_Draw_switch_mode(void); // Dessin par ligne /*! Callback for the lines button left click. Selects lines drawing mode, depending on the current state of the lines button. */ void Button_Lines(void); /*! Callback for the lines button right click. Cycles the drawing modes for the lines tool. */ void Button_Lines_switch_mode(void); // Button relatif au remplissage /*! Callback for the fill button left click. Start the filling operation. */ void Button_Fill(void); /*! Callback for the fill button right click. Start the color replace operation. */ void Button_Replace(void); /*! Disable and release the fill button. Restores the cursor (custom brushes are disabled for the fill operation). Cleans the status bar if the color replacement tool put a preview color inside it. */ void Button_Unselect_fill(void); // Spray /*! Callback for the spray button left click. Start the spray operation. */ void Button_Airbrush(void); /*! Callback for the spray button right click. Opens the spray's setup menu. */ void Button_Airbrush_menu(void); // Courbes de Bzier /*! Callback for the curves button left click. Start curve operation according to the selected mode. */ void Button_Curves(void); /*! Callback for the curves button right click. Select the curve mode (1-point, 2-point) */ void Button_Curves_switch_mode(void); // Boutons relatifs aux rectangles pleins et vides /*! Callback for the empty rectangle button. Start the rectangle operation. */ void Button_Empty_rectangle(void); /*! Callback for the filled rectangle button. Start the filled rectangle operation. */ void Button_Filled_rectangle(void); // Boutons relatifs au texte /*! Callback for the text button. Opens the text setup window. */ void Button_Text(void); // Boutons relatifs aux dgrads /*! Callback for the gradation button. Opens the "Gradation menu". */ void Button_Gradients(void); /*! Gets the informations from the gradations table and set the global vars for the current gradation. @param index index of the selected gradation */ void Load_gradient_data(int index); // Boutons relatifs aux cercles (ellipses) dgrad(e)s /*! Callback for the gradation circle button left click. Starts drawing a gradation circle. */ void Button_Grad_circle(void); /*! Callback for the gradation circle right click. Starts drawing a gradation ellipsis. */ void Button_Grad_ellipse(void); /*! Callback for the gradation rectangle button. Starts the gradation rectangle drawing operation. */ void Button_Grad_rectangle(void); // Boutons relatifs aux cercles (ellipses) plein(e)s et vides /*! Callback for the circle button left click. Starts drawing an empty circle */ void Button_Empty_circle(void); /*! Callback for the circle button left click. Starts drawing an empty ellipsis */ void Button_Empty_ellipse(void); /*! Callback for the filled circle button ledt click. Starts drawing a filled circle. */ void Button_Filled_circle(void); /*! Callback for the filled circle right click. Starts drawing a filled ellipsis. */ void Button_Filled_ellipse(void); // Boutons relatifs aux polygones vides et pleins /*! Callback for the polyline button left click. Starts drawing a polygon. */ void Button_polygon(void); /*! Callback for the polyline right click. Starts drawing a polyform. */ void Button_Polyform(void); /*! Callback for the polyfill button left click. Starts drawing a filled polygon. */ void Button_Polyfill(void); /*! Callback for the polyfill button right click. Starts drawing a filled polyform. */ void Button_Filled_polyform(void); // Boutons d'ajustement de l'image /*! Callback for the adjust picture button. Start the adjust picture operation. */ void Button_Adjust(void); // Gestion du mode Shade /*! Callback for the shade button (in the FX window). Toogle the shade mode. */ void Button_Shade_mode(void); /*! Callback for the QSHade button (in the FX window). Toogle the Quick Shade effect. */ void Button_Quick_shade_mode(void); /*! Callback for the Shade button (in the FX window) right click. Displays the shade setup menu. */ void Button_Shade_menu(void); // Gestion du Stencil /*! Callback for the Stencil button (in the FX window) left click. Toogle stencil mode. */ void Button_Stencil_mode(void); /*! Callback for the Stencil button (in the FX window) right click. Displays the stencil setup menu. */ void Button_Stencil_menu(void); // Gestion du Masque /*! Callback for the Mask button (in the FX window) left click. Toogles the mask mode/ */ void Button_Mask_mode(void); /*! Callback for the Mask button (in the FX window) right click. Displays the mask setup menu. */ void Button_Mask_menu(void); // Mode grille (Snap) /*! Callback for the Grid button (in the FX window) left click. Toogle the grid. */ void Button_Snap_mode(void); /*! Callback for the Grid button (in the FX window) right click. Displays the grid setup menu. */ void Button_Grid_menu(void); /*! Callback to toggle the grid visible in the magnified view. */ void Button_Show_grid(void); // Mode trame (Sieve) /*! In the sieve window, copy one of the presets patterns to the current one. @param index Index of the pattern to copy */ void Copy_preset_sieve(byte index); /*! In the sieve window, swaps black and white in the current pattern. */ void Invert_trame(void); /*! Callback for the Sieve button (in the FX window) left click. Toogle sieve mode. */ void Button_Sieve_mode(void); /*! Callback for the Sieve button (in the FX window) right click. Displays the sieve setup menu. */ void Button_Sieve_menu(void); // Mode Smooth /*! Callback for the smooth button (in the FX window) left click. Toogles smooth mode. */ void Button_Smooth_mode(void); /*! Callback for the Smooth button (in the FX window) right click. Displays the smooth setup menu. */ void Button_Smooth_mode(void); // Boutons relatifs au mode Colorize /*! Computes the tables used by the transparency/colorize mode. These tables are used to match the drawing color*picture color to the color that is painted on screen. */ void Compute_colorize_table(void); /*! Callback for the Tranparency button (in the FX window) left click. Toogles transparent drawing mode. */ void Button_Colorize_mode(void); /*! Callback for the Transparency button (in the FX window) right click. Displays the tranparency setup menu. */ void Button_Colorize_menu(void); // Boutons relatifs au mode Tiling /*! Callback for the Tiling button (in the FX window) left click. Toogles tiling mode. */ void Button_Tiling_mode(void); /*! Callback for the Tiling button (in the FX window) right click. Displays the tiling setup menu. */ void Button_Tiling_menu(void); /*! Callback for the command that turns off all drawaing effects. */ void Effects_off(void); // Menu des effets /*! Callback for the effects button click. Displays the effect selection menu. */ void Button_Effects(void); // Prise de brosse /*! Callback for the brush button left click. Start the brush picking operation. */ void Button_Brush(void); /*! Callback for the brush button right click. Activates the last captured custom brush. */ void Button_Restore_brush(void); /*! Disables the custom brush and set back a regular one. */ void Button_Unselect_brush(void); // Prise de brosse au lasso /*! Callback for the freehand brush pick button left click. Starts freehand brush picking operation. */ void Button_Lasso(void); /*! Disables the custom freehand brush and set back a regular one. */ void Button_Unselect_lasso(void); // Button relatifs la pipette /*! Starts the color picking operation. */ void Button_Colorpicker(void); /*! Disables the color picker button and get back to the previously selected drawing mode. */ void Button_Unselect_colorpicker(void); /*! Swap fore- and background colors. */ void Button_Invert_foreback(void); // Mode loupe /*! Enters magnify mode. */ void Button_Magnify(void); /*! Displays magnify menu. */ void Button_Magnify_menu(void); /*! Exit magnify mode. */ void Button_Unselect_magnifier(void); // Les diffrents effets sur la brosse /*! Display the Brush effects window. */ void Button_Brush_FX(void); // Boutons relatifs aux diffrentes pages /*! Swap main and spare drawing pages. */ void Button_Page(void); /*! Copy main page to spare page. */ void Button_Copy_page(void); /*! Copy only pixel data from main page to spare page (no palette copy). */ void Copy_image_only(void); /*! Kill (free from memory) the current page. */ void Button_Kill(void); // Boutons relatifs aux changements de rsolution et de taille d'image /*! Display the screenmode menu. */ void Button_Resolution(void); /*! Set the screen to the "safe resolution" (320x200 pixel window). */ void Button_Safety_resolution(void); // Boutons relatifs aux chargements et sauvegardes /*! Opens the load file dialog. */ void Button_Load(void); /*! Reload current picture from disk. */ void Button_Reload(void); /*! Open the save file dialog. */ void Button_Save(void); /*! Saves the current file without asking for a new name. */ void Button_Autosave(void); // Rglage des paramtres de l'utilisateur /*! Display the setting menu. */ void Button_Settings(void); /*! Display the skin selector window. */ void Button_Skins(void); // Annulation de la dernire modification /*! Undo the last modification to the picture. */ void Button_Undo(void); /*! Redo an operation that has been undone. */ void Button_Redo(void); // Boutons relatifs aux effacements d'images /*! Clear the whole screen with black (color index 0). */ void Button_Clear(void); /*! Clear the screen with the selected backcolor. */ void Button_Clear_with_backcolor(void); // Quitter le programme /*! Quits the program. Display a requester to save the changes to the picture before exiting if the pic was modified since last save. */ void Button_Quit(void); // Cacher le menu /*! Hides the menubar. */ void Button_Hide_menu(void); /*! Shows a dropdown panel where you can choose which toolbars are visible */ void Button_Toggle_toolbar(void); /*! Hides all toolbars (except status) or shows them again */ void Button_Toggle_all_toolbars(void); /*! Load picture from file. */ void Load_picture(byte image); /*! Save picture to file. */ void Save_picture(byte image); /*! Generic color tagging menu, for various effects. */ void Menu_tag_colors(char * window_title, byte * table, byte * mode, byte can_cancel, const char *help_section, word close_shortcut ); /*! Display the menu for the smooth effect. */ void Button_Smooth_menu(void); /*! Toogles the smear mode. */ void Button_Smear_mode(void); void Button_Brush_container(void); byte Store_paintbrush(int index); void Select_paintbrush(int index); #endif grafx2/src/const.h0000644000076400010400000004675411522560062014537 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file const.h /// Constants (preprocessor defines) and enumerations used anywhere. ////////////////////////////////////////////////////////////////////////////// #ifndef _CONST_H_ #define _CONST_H_ #ifndef M_2PI #define M_2PI 6.28318530717958647692528676656 ///< Hmm, pie... #endif #define VERSION1 2 ///< Version number for gfx2.cfg (1/4) #define VERSION2 0 ///< Version number for gfx2.cfg (2/4) #define BETA1 98 ///< Version number for gfx2.cfg (3/4) #define BETA2 0 ///< Version number for gfx2.cfg (4/4) #define MAX_VIDEO_MODES 100 ///< Maximum number of video modes Grafx2 can propose. #define NB_ZOOM_FACTORS 15 ///< Number of zoom levels available in the magnifier. #define MENU_WIDTH 254 ///< Width of the menu (not counting the palette) #define MENU_HEIGHT 44 ///< Height of the menu. #define NB_CURSOR_SPRITES 8 ///< Number of available mouse cursor sprites. #define CURSOR_SPRITE_WIDTH 15 ///< Width of a mouse cursor sprite. #define CURSOR_SPRITE_HEIGHT 15 ///< Height of a mouse cursor sprite. #define NB_EFFECTS_SPRITES 9 ///< Number of effect sprites. #define MENU_SPRITE_WIDTH 16 ///< Width of a menu sprite in pixels #define MENU_SPRITE_HEIGHT 16 ///< Height of a menu sprite in pixels #define EFFECT_SPRITE_WIDTH 14 ///< Width of an effect sprite in pixels #define EFFECT_SPRITE_HEIGHT 14 ///< Height of an effect sprite in pixels #define LAYER_SPRITE_WIDTH 14 ///< Width of a layer button in pixels #define LAYER_SPRITE_HEIGHT 10 ///< Height of a layer button in pixels #define PAINTBRUSH_WIDTH 16 ///< Width of a preset paintbrush sprite #define PAINTBRUSH_HEIGHT 16 ///< Height of a preset paintbrush sprite #define MAX_PAINTBRUSH_SIZE 127 ///< Max size for a resizable paintbrush #define ICON_SPRITE_WIDTH 8 ///< Width of an icon in pixels #define ICON_SPRITE_HEIGHT 8 ///< Height of an icon in pixels #define NB_PAINTBRUSH_SPRITES 48 ///< Number of preset paintbrushes #define NB_PRESET_SIEVE 12 ///< Number of preset sieve patterns #define OPERATION_STACK_SIZE 16 ///< Max number of parameters in the operation stack. #define MAX_DISPLAYABLE_PATH 37 ///< Max number of characters to display directory name, in Save/Load screens. #define COMMENT_SIZE 32 ///< Max number of characters for a comment in PKM or PNG file. #define NB_MAX_PAGES_UNDO 99 ///< Max number of undo pages #define DEFAULT_ZOOM_FACTOR 4 ///< Initial zoom factor for the magnifier. #define MAX_PATH_CHARACTERS 260 ///< Number of characters for a file+complete path. Adapt to your OS... #define NB_BOOKMARKS 4 ///< Number of bookmark buttons in Save/Load screen. // Character to show a right arrow, used when editing long strings. It's present in ::Gfx->System_font #define RIGHT_TRIANGLE_CHARACTER 16 // Character to show a left arrow, used when editing long strings. It's present in ::Gfx->System_font #define LEFT_TRIANGLE_CHARACTER 17 /// Character to display in menus for an ellipsis. #define ELLIPSIS_CHARACTER '' #define NB_LAYERS 1 ///< Initial number of layers for a new image #define MAX_NB_LAYERS 16 ///< Maximum number of layers that can be used in grafx2. Note that 32 is upper limit because of a few bit fields. #define BRUSH_CONTAINER_PREVIEW_WIDTH 16 ///< Size for preview of a brush in Brush container #define BRUSH_CONTAINER_PREVIEW_HEIGHT 16 ///< Size for preview of a brush in Brush container #define BRUSH_CONTAINER_COLUMNS 4 ///< Number of columns in the Brush container #define BRUSH_CONTAINER_ROWS 3 ///< Number of rows in the Brush container /// /// We force the dynamic backup page allocation to leave a minimum of /// 256Kb of free memory, to allow the rest of the program to work safely. /// Note: This is a remainder of the DOS version. This system might not work /// so well on other OSes, where the "available memory" changes due to external /// factors. #define MINIMAL_MEMORY_TO_RESERVE (256*1024) #define LEFT_SIDE 1 ///< Indicates a left side or left-click #define RIGHT_SIDE 2 ///< Indicates a right side or right-click #define SEPARATOR_WIDTH 6 ///< Width of the separator between the normal and the zoomed view #define INITIAL_SEPARATOR_PROPORTION 0.3 ///< Proportion of the normal view width, relative to the whole screen width. #define NB_ZOOMED_PIXELS_MIN 4 ///< Minimal number of pixel shown (in width) by the zoomed view. (Note: below 4, you can't scroll!) #if defined(__MORPHOS__) || defined(__amigaos4__) || defined(__amigaos__) #define PARENT_DIR "/" #else /// Filename that means "parent directory" for your operating system. #define PARENT_DIR ".." #endif /// List of file formats recognized by grafx2 enum FILE_FORMATS { FORMAT_ALL_IMAGES=0, ///< This is not really a file format, it's reserverd for a compilation of all file extensions FORMAT_ALL_FILES=1, ///< This is not really a file format, it's reserverd for the "*.*" filter option. FORMAT_PNG, FORMAT_GIF, FORMAT_BMP, FORMAT_PCX, FORMAT_PKM, FORMAT_LBM, FORMAT_IMG, FORMAT_SCx, FORMAT_PI1, FORMAT_PC1, FORMAT_CEL, FORMAT_NEO, FORMAT_C64, FORMAT_KCF, FORMAT_PAL, FORMAT_SCR, FORMAT_XPM, FORMAT_MISC, ///< Must be last of enum: others formats recognized by SDL_image }; /// Default format for 'save as' #define DEFAULT_FILEFORMAT FORMAT_GIF /// Error codes for ::Error() enum ERROR_CODES { ERROR_WARNING=0, ///< Red flash on screen, non-fatal error ERROR_GUI_MISSING, ///< The graphics file is missing ERROR_GUI_CORRUPTED, ///< The graphics file cannot be parsed for GUI elements ERROR_INI_MISSING, ///< File gfx2def.ini is missing ERROR_CFG_MISSING, ///< File gfx2.cfg is missing (non-fatal) ERROR_CFG_CORRUPTED, ///< File gfx2.cfg couldn't be parsed (non-fatal) ERROR_CFG_OLD, ///< Unknown version of gfx2.cfg : either VERY old or wrong file (non-fatal) ERROR_MEMORY, ///< Out of memory ERROR_COMMAND_LINE, ///< Error in command-line arguments (syntax, or couldn't find the file to open) ERROR_FORBIDDEN_MODE, ///< Graphics mode requested is not supported ERROR_SAVING_CFG, ///< Error while writing gfx2.cfg ERROR_MISSING_DIRECTORY, ///< Unable to return to the original "current directory" on program exit ERROR_INI_CORRUPTED, ///< File gfx2.ini couldn't be parsed ERROR_SAVING_INI, ///< Error while writing gfx2.ini ERROR_SORRY_SORRY_SORRY ///< (Page allocation error that shouldn't ever happen, now) }; /// Available pixel scalers enum PIXEL_RATIO { PIXEL_SIMPLE=0, ///< Use real pixels PIXEL_WIDE, ///< Use wide pixels (2x1) like on Amstrad CPC mode 0 PIXEL_TALL, ///< Use tall pixels (1x2) like on Amstrad CPC mode 2 PIXEL_DOUBLE, ///< Use big pixels (2x2) if your LCD screen can't do lowres by itself PIXEL_TRIPLE, ///< Use really big pixels (3x3) PIXEL_WIDE2, ///< Use big wide pixels (4x2) PIXEL_TALL2, ///< Use big tall pixels (2x4) PIXEL_QUAD, ///< Use really giant pixels (4x4). You need to have a screen resolution at least 1280x800 to use this one PIXEL_MAX ///< Number of elements in enum }; /// Different kinds of menu button behavior. enum FAMILY_OF_BUTTONS { FAMILY_TOOL=1, ///< Drawing tools (example : Freehand draw) FAMILY_INTERRUPTION, ///< Temporary operation (example : choosing paintbrush) > Interrupts the current operation to do something, then come back. FAMILY_INSTANT, ///< Single-click action (example : choose a color in palette) > It will be over as soon as we exit the called function. FAMILY_TOOLBAR, ///< Hide/show the menu FAMILY_EFFECTS ///< Effects }; /// The different kinds of buttons in menus or windows. enum BUTTON_SHAPES { BUTTON_SHAPE_NO_FRAME, ///< Ex: the palette BUTTON_SHAPE_RECTANGLE, ///< Ex: Most buttons. BUTTON_SHAPE_TRIANGLE_TOP_LEFT, ///< Ex: Empty rectangles. BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT ///< Ex: Filled rectangles. }; /// The different "mouse cursor" shapes enum CURSOR_SHAPES { CURSOR_SHAPE_ARROW, CURSOR_SHAPE_TARGET, ///< This one uses the paintbrush CURSOR_SHAPE_COLORPICKER, ///< This one uses the paintbrush CURSOR_SHAPE_HOURGLASS, CURSOR_SHAPE_MULTIDIRECTIONAL, CURSOR_SHAPE_HORIZONTAL, CURSOR_SHAPE_THIN_TARGET, ///< This one uses the paintbrush CURSOR_SHAPE_THIN_COLORPICKER, ///< This one uses the paintbrush CURSOR_SHAPE_XOR_TARGET, CURSOR_SHAPE_XOR_RECTANGLE, CURSOR_SHAPE_XOR_ROTATION }; /// The different shapes that can be used as a paintbrush (paintbrush types go in the beginning) enum PAINTBRUSH_SHAPES { PAINTBRUSH_SHAPE_ROUND, PAINTBRUSH_SHAPE_SQUARE, PAINTBRUSH_SHAPE_HORIZONTAL_BAR, PAINTBRUSH_SHAPE_VERTICAL_BAR, PAINTBRUSH_SHAPE_SLASH, PAINTBRUSH_SHAPE_ANTISLASH, PAINTBRUSH_SHAPE_RANDOM, ///< Random pixels in a circle shape, like an airbrush. PAINTBRUSH_SHAPE_CROSS, PAINTBRUSH_SHAPE_PLUS, PAINTBRUSH_SHAPE_DIAMOND, PAINTBRUSH_SHAPE_SIEVE_ROUND, PAINTBRUSH_SHAPE_SIEVE_SQUARE, PAINTBRUSH_SHAPE_RESERVED1, ///< Reserved for future use PAINTBRUSH_SHAPE_RESERVED2, ///< Reserved for future use PAINTBRUSH_SHAPE_RESERVED3, ///< Reserved for future use PAINTBRUSH_SHAPE_RESERVED4, ///< Reserved for future use PAINTBRUSH_SHAPE_RESERVED5, ///< Reserved for future use PAINTBRUSH_SHAPE_RESERVED6, ///< Reserved for future use PAINTBRUSH_SHAPE_RESERVED7, ///< Reserved for future use PAINTBRUSH_SHAPE_RESERVED8, ///< Reserved for future use PAINTBRUSH_SHAPE_MISC, ///< A raw monochrome bitmap, can't be resized. This must be the last of the preset paintbrush types. PAINTBRUSH_SHAPE_POINT, ///< Used to reduce the paintbrush to a single pixel, during operations like floodfill. PAINTBRUSH_SHAPE_NONE, ///< Used to display no cursor at all (colorpicker) PAINTBRUSH_SHAPE_COLOR_BRUSH, ///< User's brush, in color mode PAINTBRUSH_SHAPE_MONO_BRUSH, ///< User's brush, in mono mode PAINTBRUSH_SHAPE_MAX ///< Upper limit. }; /// Normal resting state for a menu button. #define BUTTON_RELEASED 0 /// State of a menu button that is being pressed. #define BUTTON_PRESSED 1 /// State of a button temporarily highligted #define BUTTON_HIGHLIGHTED 2 /// The different modes of the Shade enum SHADE_MODES { SHADE_MODE_NORMAL, SHADE_MODE_LOOP, SHADE_MODE_NOSAT }; /// Identifiers for the chunks (data blocks) of gfx2.cfg enum CHUNKS_CFG { CHUNK_KEYS = 0, ///< Shortcut keys definitions CHUNK_VIDEO_MODES = 1, ///< List of video modes CHUNK_SHADE = 2, ///< Shade settings CHUNK_MASK = 3, ///< Mask settings CHUNK_STENCIL = 4, ///< Stencil settings CHUNK_GRADIENTS = 5, ///< Gradients CHUNK_SMOOTH = 6, ///< Smooth effect settings CHUNK_EXCLUDE_COLORS = 7, ///< List of excluded colors CHUNK_QUICK_SHADE = 8, ///< QShade effect settings CHUNK_GRID = 9, ///< Grid settings CHUNK_BRUSH =10, ///< Paintbrushes CHUNK_SCRIPTS =11, ///< Callable scripts CHUNK_MAX }; /// Identifiers for the 8x8 icons of ::Gfx->Icon_sprite (most are unused now) enum ICON_TYPES { ICON_FLOPPY_3_5=0, ///< 3.5 Floppy disk ICON_FLOPPY_5_25, ///< 5.25 Floppy disk ICON_HDD, ///< Hard disk drive ICON_CDROM, ///< CD-ROM ICON_NETWORK, ///< "Network" drive ICON_STAR, ///< Star (favorite) ICON_DROPDOWN, ///< Dropdown arrow NB_ICON_SPRITES, ///< Number of 8x8 icons ICON_NONE ///< None of the above }; /// Identifiers for the buttons in the menu. enum BUTTON_NUMBERS { // Status bar BUTTON_HIDE = 0, // Layer bar BUTTON_LAYER_MENU, BUTTON_LAYER_COLOR, BUTTON_LAYER_MERGE, BUTTON_LAYER_ADD, BUTTON_LAYER_REMOVE, BUTTON_LAYER_UP, BUTTON_LAYER_DOWN, BUTTON_LAYER_SELECT, // Main menu BUTTON_PAINTBRUSHES, BUTTON_ADJUST, BUTTON_DRAW, BUTTON_CURVES, BUTTON_LINES, BUTTON_AIRBRUSH, BUTTON_FLOODFILL, BUTTON_POLYGONS, BUTTON_POLYFILL, BUTTON_RECTANGLES, BUTTON_FILLRECT, BUTTON_CIRCLES, BUTTON_FILLCIRC, BUTTON_GRADRECT, BUTTON_SPHERES, BUTTON_BRUSH, BUTTON_POLYBRUSH, BUTTON_BRUSH_EFFECTS, BUTTON_EFFECTS, BUTTON_TEXT, BUTTON_MAGNIFIER, BUTTON_COLORPICKER, BUTTON_RESOL, BUTTON_PAGE, BUTTON_SAVE, BUTTON_LOAD, BUTTON_SETTINGS, BUTTON_CLEAR, BUTTON_HELP, BUTTON_UNDO, BUTTON_KILL, BUTTON_QUIT, BUTTON_PALETTE, BUTTON_PAL_LEFT, BUTTON_PAL_RIGHT, BUTTON_CHOOSE_COL, NB_BUTTONS ///< Number of buttons in the menu bar. }; enum MENU_SPRITE { MENU_SPRITE_COLOR_BRUSH=0, MENU_SPRITE_MONO_BRUSH, MENU_SPRITE_DISCONTINUOUS_DRAW, MENU_SPRITE_POINT_DRAW, MENU_SPRITE_CONTOUR_DRAW, MENU_SPRITE_4_POINTS_CURVE, MENU_SPRITE_K_LINE, MENU_SPRITE_CENTERED_LINES, MENU_SPRITE_ELLIPSES, MENU_SPRITE_POLYFORM, MENU_SPRITE_REPLACE, MENU_SPRITE_GRAD_ELLIPSE, MENU_SPRITE_VERTICAL_PALETTE_SCROLL, NB_MENU_SPRITES ///< Number of menu sprites. }; /// /// Identifiers of special actions that can have a keyboard shortcut. /// They are special in the sense that there's no button in the menu for them, /// so it requires a specific handling. enum SPECIAL_ACTIONS { SPECIAL_MOUSE_UP=0, SPECIAL_MOUSE_DOWN, SPECIAL_MOUSE_LEFT, SPECIAL_MOUSE_RIGHT, SPECIAL_CLICK_LEFT, SPECIAL_CLICK_RIGHT, SPECIAL_NEXT_FORECOLOR, SPECIAL_PREVIOUS_FORECOLOR, SPECIAL_NEXT_BACKCOLOR, SPECIAL_PREVIOUS_BACKCOLOR, SPECIAL_SMALLER_PAINTBRUSH, SPECIAL_BIGGER_PAINTBRUSH, SPECIAL_NEXT_USER_FORECOLOR, SPECIAL_PREVIOUS_USER_FORECOLOR, SPECIAL_NEXT_USER_BACKCOLOR, SPECIAL_PREVIOUS_USER_BACKCOLOR, SPECIAL_SCROLL_UP, SPECIAL_SCROLL_DOWN, SPECIAL_SCROLL_LEFT, SPECIAL_SCROLL_RIGHT, SPECIAL_SCROLL_UP_FAST, SPECIAL_SCROLL_DOWN_FAST, SPECIAL_SCROLL_LEFT_FAST, SPECIAL_SCROLL_RIGHT_FAST, SPECIAL_SCROLL_UP_SLOW, SPECIAL_SCROLL_DOWN_SLOW, SPECIAL_SCROLL_LEFT_SLOW, SPECIAL_SCROLL_RIGHT_SLOW, SPECIAL_SHOW_HIDE_CURSOR, SPECIAL_DOT_PAINTBRUSH, SPECIAL_CONTINUOUS_DRAW, SPECIAL_FLIP_X, SPECIAL_FLIP_Y, SPECIAL_ROTATE_90, SPECIAL_ROTATE_180, SPECIAL_STRETCH, SPECIAL_DISTORT, SPECIAL_OUTLINE, SPECIAL_NIBBLE, SPECIAL_GET_BRUSH_COLORS, SPECIAL_RECOLORIZE_BRUSH, SPECIAL_ROTATE_ANY_ANGLE, SPECIAL_BRUSH_DOUBLE, SPECIAL_BRUSH_DOUBLE_WIDTH, SPECIAL_BRUSH_DOUBLE_HEIGHT, SPECIAL_BRUSH_HALVE, SPECIAL_LOAD_BRUSH, SPECIAL_SAVE_BRUSH, SPECIAL_INVERT_SIEVE, SPECIAL_ZOOM_IN, SPECIAL_ZOOM_OUT, SPECIAL_CENTER_ATTACHMENT, SPECIAL_TOP_LEFT_ATTACHMENT, SPECIAL_TOP_RIGHT_ATTACHMENT, SPECIAL_BOTTOM_LEFT_ATTACHMENT, SPECIAL_BOTTOM_RIGHT_ATTACHMENT, SPECIAL_EXCLUDE_COLORS_MENU, SPECIAL_SHADE_MODE, SPECIAL_SHADE_MENU, SPECIAL_QUICK_SHADE_MODE, ///< This must be the first of the "effects" family SPECIAL_QUICK_SHADE_MENU, SPECIAL_STENCIL_MODE, SPECIAL_STENCIL_MENU, SPECIAL_MASK_MODE, SPECIAL_MASK_MENU, SPECIAL_GRID_MODE, SPECIAL_GRID_MENU, SPECIAL_SIEVE_MODE, SPECIAL_SIEVE_MENU, SPECIAL_COLORIZE_MODE, SPECIAL_COLORIZE_MENU, SPECIAL_SMOOTH_MODE, SPECIAL_SMOOTH_MENU, SPECIAL_SMEAR_MODE, SPECIAL_EFFECTS_OFF, SPECIAL_TILING_MODE, SPECIAL_TRANSPARENCY_1, SPECIAL_TRANSPARENCY_2, SPECIAL_TRANSPARENCY_3, SPECIAL_TRANSPARENCY_4, SPECIAL_TRANSPARENCY_5, SPECIAL_TRANSPARENCY_6, SPECIAL_TRANSPARENCY_7, SPECIAL_TRANSPARENCY_8, SPECIAL_TRANSPARENCY_9, SPECIAL_TRANSPARENCY_0, SPECIAL_TILING_MENU, ///< This must be the last of the "effects" family SPECIAL_ZOOM_1, SPECIAL_ZOOM_2, SPECIAL_ZOOM_3, SPECIAL_ZOOM_4, SPECIAL_ZOOM_5, SPECIAL_ZOOM_6, SPECIAL_ZOOM_8, SPECIAL_ZOOM_10, SPECIAL_ZOOM_12, SPECIAL_ZOOM_14, SPECIAL_ZOOM_16, SPECIAL_ZOOM_18, SPECIAL_ZOOM_20, SPECIAL_SHOW_GRID, SPECIAL_LAYER1_SELECT, SPECIAL_LAYER1_TOGGLE, SPECIAL_LAYER2_SELECT, SPECIAL_LAYER2_TOGGLE, SPECIAL_LAYER3_SELECT, SPECIAL_LAYER3_TOGGLE, SPECIAL_LAYER4_SELECT, SPECIAL_LAYER4_TOGGLE, SPECIAL_LAYER5_SELECT, SPECIAL_LAYER5_TOGGLE, SPECIAL_LAYER6_SELECT, SPECIAL_LAYER6_TOGGLE, SPECIAL_LAYER7_SELECT, SPECIAL_LAYER7_TOGGLE, SPECIAL_LAYER8_SELECT, SPECIAL_LAYER8_TOGGLE, SPECIAL_REPEAT_SCRIPT, SPECIAL_RUN_SCRIPT_1, SPECIAL_RUN_SCRIPT_2, SPECIAL_RUN_SCRIPT_3, SPECIAL_RUN_SCRIPT_4, SPECIAL_RUN_SCRIPT_5, SPECIAL_RUN_SCRIPT_6, SPECIAL_RUN_SCRIPT_7, SPECIAL_RUN_SCRIPT_8, SPECIAL_RUN_SCRIPT_9, SPECIAL_RUN_SCRIPT_10, SPECIAL_CYCLE_MODE, NB_SPECIAL_SHORTCUTS ///< Number of special shortcuts }; /// Identifiers of the operations, ie tools you use on the image. enum OPERATIONS { OPERATION_CONTINUOUS_DRAW=0, ///< Freehand continuous draw OPERATION_DISCONTINUOUS_DRAW,///< Freehand discontinuous draw OPERATION_POINT_DRAW, ///< Freehand point-by-point draw OPERATION_FILLED_CONTOUR, ///< Filled contour OPERATION_LINE, ///< Lines OPERATION_K_LINE, ///< Linked lines OPERATION_CENTERED_LINES, ///< Centered lines OPERATION_EMPTY_RECTANGLE, ///< Empty rectangle OPERATION_FILLED_RECTANGLE, ///< Filled rectangle OPERATION_EMPTY_CIRCLE, ///< Empty circle OPERATION_FILLED_CIRCLE, ///< Filled circle OPERATION_EMPTY_ELLIPSE, ///< Empty ellipse OPERATION_FILLED_ELLIPSE, ///< Filled ellipse OPERATION_FILL, ///< Fill OPERATION_REPLACE, ///< Color replacer OPERATION_GRAB_BRUSH, ///< Rectangular brush grabbing OPERATION_POLYBRUSH, ///< Polygonal brush grabbing OPERATION_COLORPICK, ///< Colorpicker OPERATION_MAGNIFY, ///< Position the magnify window OPERATION_3_POINTS_CURVE, ///< Curve with 3 control points OPERATION_4_POINTS_CURVE, ///< Curve with 4 control points OPERATION_AIRBRUSH, ///< Airbrush OPERATION_POLYGON, ///< Polygon OPERATION_POLYFORM, ///< Polyform OPERATION_POLYFILL, ///< Filled polygon OPERATION_FILLED_POLYFORM, ///< Filled polyform OPERATION_SCROLL, ///< Scroll (pan) OPERATION_GRAD_CIRCLE, ///< Gradient-filled circle OPERATION_GRAD_ELLIPSE, ///< Gradient-filled ellipse OPERATION_ROTATE_BRUSH, ///< Rotate brush OPERATION_STRETCH_BRUSH, ///< Stretch brush OPERATION_DISTORT_BRUSH, ///< Distort brush OPERATION_GRAD_RECTANGLE, ///< Gradient-filled rectangle OPERATION_RMB_COLORPICK, ///< Colorpick on right mouse button NB_OPERATIONS ///< Number of operations handled by the engine }; #endif grafx2/src/engine.h0000644000076400010400000001173511545652526014661 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file engine.h /// Utility functions for the menu and all windows. ////////////////////////////////////////////////////////////////////////////// #ifndef __ENGINE_H__ #define __ENGINE_H__ #include "struct.h" void Main_handler (void); void Draw_menu_button (byte btn_number,byte pressed); void Unselect_button (int btn_number); void Select_button (int btn_number,byte click); void Open_window (word width,word height, const char * title); void Close_window (void); void Open_popup (word x_pos, word y_pos, word width, word height); void Close_popup (void); void Window_draw_normal_bouton(word x_pos,word y_pos,word width,word height, const char * title,byte undersc_letter,byte clickable); void Window_select_normal_button(word x_pos,word y_pos,word width,word height); void Window_unselect_normal_button(word x_pos,word y_pos,word width,word height); void Window_draw_palette_bouton(word x_pos,word y_pos); void Compute_slider_cursor_length(T_Scroller_button * button); void Window_draw_slider(T_Scroller_button * button); void Window_draw_scroller_button(T_Scroller_button * button); void Window_input_content(T_Special_button * button, char * content); void Window_clear_input_button(T_Special_button * button); void Window_draw_input_bouton(word x_pos, word y_pos, word width_in_characters); T_Normal_button * Window_set_normal_button(word x_pos, word y_pos, word width, word height, const char * title, byte undersc_letter, byte clickable, word shortcut); T_Normal_button * Window_set_repeatable_button(word x_pos, word y_pos, word width, word height, const char * title, byte undersc_letter, byte clickable, word shortcut); T_Palette_button * Window_set_palette_button(word x_pos, word y_pos); void Window_clear_tags(void); void Tag_color_range(byte start, byte end); T_Scroller_button * Window_set_scroller_button(word x_pos, word y_pos, word height, word nb_elements, word nb_elements_visible, word initial_position); T_Scroller_button * Window_set_horizontal_scroller_button(word x_pos, word y_pos, word height, word nb_elements, word nb_elements_visible, word initial_position); T_Special_button * Window_set_special_button(word x_pos, word y_pos, word width, word height); T_Special_button * Window_set_input_button(word x_pos, word y_pos, word width_in_characters); T_Dropdown_button * Window_set_dropdown_button(word x_pos, word y_pos, word width, word height, word dropdown_width, const char *label, byte display_choice, byte display_centered, byte display_arrow, byte active_button,byte bottom_up); /// Adds an item to a dropdown menu void Window_dropdown_add_item(T_Dropdown_button * dropdown, word btn_number, const char *label); void Window_dropdown_clear_items(T_Dropdown_button * dropdown); /// /// Displays a dropped-down menu and handles the UI logic until the user /// releases a mouse button. /// This function then clears the dropdown and returns the selected item, /// or NULL if the user wasn't highlighting an item when he closed. T_Dropdown_choice * Dropdown_activate(T_Dropdown_button *button, short off_x, short off_y); T_List_button * Window_set_list_button(T_Special_button * entry_button, T_Scroller_button * scroller, Func_draw_list_item draw_list_item, byte color_index); void Window_redraw_list(T_List_button * list); byte Window_click_in_rectangle(short start_x, short start_y, short end_x, short end_y); short Wait_click_in_palette(T_Palette_button * button); short Window_normal_button_onclick(word x_pos, word y_pos, word width, word height, short btn_number); void Get_color_behind_window(byte * color, byte * click); short Window_clicked_button(void); int Button_under_mouse(void); short Window_get_clicked_button(void); void Remap_window_backgrounds(byte * conversion_table, int Min_Y, int Max_Y); void Pixel_background(int x_pos, int y_pos, byte color); /// /// Updates the status bar line with a color number. /// Used when hovering the menu palette. void Status_print_palette_color(byte color); /// Puts the user in wait mode for the specified time ( in 1/100s), /// though the mouse still works. void Delay_with_active_mouse(int delay); #endif grafx2/src/errors.h0000644000076400010400000000440311346252160014707 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Adrien Destugues 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file errors.h /// Functions and macros for tracing and error reporting. ////////////////////////////////////////////////////////////////////////////// #ifdef __VBCC__ #define __func__ "stupid compiler !" #endif /// Prints the source filename, line number, function name, a string and an integer. #define DEBUG(y,z) printf("%s %d %s | %s : %d###\n",__FILE__,__LINE__,__func__,y,(unsigned int)z) /// Same as ::DEBUG but in hexadecimal #define DEBUGX(y,z) printf("%s %d %s | %s : %X###\n",__FILE__,__LINE__,__func__,y,(unsigned int)z) /// Helper function used by the macro ::Error void Error_function(int error_code, const char *filename, int line_number, const char *function_name); /// /// Report a run-time error: It will print to standard output some information /// about the calling function, and then: /// - If the error code is 0, just do a red screen flash and resume. /// - If the error code is non-zero, abort the program. #define Error(n) Error_function(n, __FILE__,__LINE__,__func__) /// Helper function used by the macro ::Warning void Warning_function(const char *message, const char *filename, int line_number, const char *function_name); /// /// Report a run-time abnormal condition : It will print to standard output /// some information about the calling function, and then resume silently. /// This is most useful in debugger so you can put a breakpoint on /// ::Warning_function and examine the stack trace. #define Warning(msg) Warning_function(msg, __FILE__,__LINE__,__func__) grafx2/src/factory.h0000644000076400010400000000046011422614536015045 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ void Button_Brush_Factory(void); void Repeat_script(void); /// Lua scripts bound to shortcut keys. extern char * Bound_script[10]; /// /// Run a lua script linked to a shortcut, 0-9. /// Before: Cursor hidden /// After: Cursor shown void Run_numbered_script(byte index); grafx2/src/filesel.h0000644000076400010400000000410311550336130015010 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file filesel.h /// Fileselector window, used for loading and saving images and brushes. ////////////////////////////////////////////////////////////////////////////// #ifndef __FILESEL_H__ #define __FILESEL_H__ #include "struct.h" #include "loadsave.h" byte Button_Load_or_Save(byte load, T_IO_Context *context); void Add_element_to_list(T_Fileselector *list, const char * full_name, const char *short_name, int type, byte icon); /// /// Formats a display name for a file, directory, or similar name (drive, volume). /// The returned value is a pointer to a single static buffer of maximum 40 characters /// including the '\\0'. char * Format_filename(const char * fname, word max_length, int type); void Free_fileselector_list(T_Fileselector *list); void Sort_list_of_files(T_Fileselector *list); void Recount_files(T_Fileselector *list); T_Fileselector_item * Get_item_by_index(T_Fileselector *list, short index); void Read_list_of_drives(T_Fileselector *list, byte name_length); short Find_file_in_fileselector(T_Fileselector *list, const char * fname); void Locate_list_item(T_List_button * list, short selected_item); int Quicksearch_list(T_List_button * list, T_Fileselector * selector); void Reset_quicksearch(void); #endif grafx2/src/global.h0000644000076400010400000012531711532211712014636 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2009 Franck Charlet Copyright 2009 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file global.h /// This file contains all global variables. /// They are prefixed by ::GFX2_GLOBAL so they are extern when needed. ////////////////////////////////////////////////////////////////////////////// #ifndef _GLOBAL_H_ #define _GLOBAL_H_ #include #include "struct.h" // MAIN declares the variables, // other files only have an extern definition. #ifdef GLOBAL_VARIABLES /// Magic prefix to make all declarations extern, except when included by main.c. #define GFX2_GLOBAL #else #define GFX2_GLOBAL extern #endif // -- CONFIGURATION variables /// Current configuration. GFX2_GLOBAL T_Config Config; /// Array of special keys. GFX2_GLOBAL word Config_Key[NB_SPECIAL_SHORTCUTS][2]; /// A video mode (resolution) usable by Grafx2. typedef struct { short Width; ///< Screen width short Height; ///< Screen height byte Mode; ///< Unused (used to be Mode-X, SVGA, etc) word Fullscreen; ///< 0 for window, 1 for fullscreen byte State; ///< How good is the mode supported. 0:Good (white) 1:OK (light) 2:So-so (dark) 4:User-disabled (black); +128 => System doesn't support it at all. } T_Video_mode; /// Array of all video modes supported by your platform. Actually filled up to ::Nb_video_modes, excluded. GFX2_GLOBAL T_Video_mode Video_mode[MAX_VIDEO_MODES]; /// Actual number of video modes in ::Video_mode. GFX2_GLOBAL int Nb_video_modes; // -- Menu colors GFX2_GLOBAL byte MC_Black; ///< Index of color to use as "black" in the GUI menus. GFX2_GLOBAL byte MC_Dark; ///< Index of color to use as "dark grey" in the GUI menus. GFX2_GLOBAL byte MC_Light; ///< Index of color to use as "light grey" in the GUI menus. GFX2_GLOBAL byte MC_White; ///< Index of color to use as "white" in the GUI menus. GFX2_GLOBAL byte MC_Trans; ///< Index of color to use as "transparent" while loading the GUI file. GFX2_GLOBAL byte MC_OnBlack; ///< Index of color immediately lighter than "black" in the GUI menus. GFX2_GLOBAL byte MC_Window; ///< Index of color to use as window background in the GUI menus. GFX2_GLOBAL byte MC_Lighter; ///< Index of color lighter than window in the GUI menus. GFX2_GLOBAL byte MC_Darker; ///< Index of color darker than window in the GUI menus. // Input state GFX2_GLOBAL word Mouse_X; ///< Current mouse cursor position. GFX2_GLOBAL word Mouse_Y; ///< Current mouse cursor position. GFX2_GLOBAL byte Mouse_K; ///< Current mouse buttons state. Bitfield: 1 for RMB, 2 for LMB. GFX2_GLOBAL byte Keyboard_click_allowed; ///< Set to 0 when you edit a textfield so you can use space without exiting it /// Helper macro to take only one button when both are pressed (LMB has priority) #define Mouse_K_unique (Mouse_K==0?0:(Mouse_K&1?1:(Mouse_K&2?2:0))) /// Last key pressed, 0 if none. Set by the latest call to ::Get_input() GFX2_GLOBAL dword Key; /// /// Last character typed, converted to ANSI character set (Windows-1252). /// This is mostly used when the user enters text (filename, etc). GFX2_GLOBAL dword Key_ANSI; // Keyboard modifiers // (Name conflict with windows.h) #ifdef MOD_SHIFT #undef MOD_SHIFT #endif #ifdef MOD_CTRL #undef MOD_CTRL #endif #ifdef MOD_ALT #undef MOD_ALT #endif /// Key modifier for SHIFT key. Used as mask in ::Key, for example. #define MOD_SHIFT 0x1000 /// Key modifier for CONTROL key. Used as mask in ::Key, for example. #define MOD_CTRL 0x2000 /// Key modifier for ALT key. Used as mask in ::Key, for example. #define MOD_ALT 0x4000 /// Key modifier for META key. Used as mask in ::Key, for example. #define MOD_META 0x8000 /// Boolean set to true when the OS/window manager requests the application to close. ie: [X] button GFX2_GLOBAL byte Quit_is_required; /// /// This boolean is true when the current operation allows changing the /// foreground or background color. GFX2_GLOBAL byte Allow_color_change_during_operation; // -- Mouse cursor data /// Current mouse cursor. Value is in enum ::CURSOR_SHAPES GFX2_GLOBAL byte Cursor_shape; /// Backup of ::Cursor_shape, used while a window is open (and needs a different cursor) GFX2_GLOBAL byte Cursor_shape_before_window; /// Boolean, means the cursor should not be drawn. It's togglable by the user. GFX2_GLOBAL byte Cursor_hidden; /// Boolean, means the cursor is currently hovering over a menu GUI element. GFX2_GLOBAL byte Cursor_in_menu; /// Boolean, means the cursor was hovering over a menu GUI element. GFX2_GLOBAL byte Cursor_in_menu_previous; /// Storage for the graphics under the mouse cursor. Used by ::Hide_cursor and ::Display_cursor GFX2_GLOBAL byte Cursor_background[CURSOR_SPRITE_HEIGHT][CURSOR_SPRITE_WIDTH]; // -- Paintbrush data /// Active paintbrush. It's an index in enum ::PAINTBRUSH_SHAPES GFX2_GLOBAL byte Paintbrush_shape; /// Backup of ::Paintbrush_shape, before fill operation GFX2_GLOBAL byte Paintbrush_shape_before_fill; /// Backup of ::Paintbrush_shape, before color picker operation GFX2_GLOBAL byte Paintbrush_shape_before_colorpicker; /// Backup of ::Paintbrush_shaper, before lasso operation GFX2_GLOBAL byte Paintbrush_shape_before_lasso; /// Boolean, true when the preview paintbrush shouldn't be drawn. GFX2_GLOBAL byte Paintbrush_hidden; /// Cordinate of the preview paintbrush in image space. GFX2_GLOBAL short Paintbrush_X; /// Cordinate of the preview paintbrush in image space. GFX2_GLOBAL short Paintbrush_Y; /// Pixel data of the current brush GFX2_GLOBAL byte * Paintbrush_sprite; /// Current paintbrush's width GFX2_GLOBAL short Paintbrush_width; /// Current paintbrush's height GFX2_GLOBAL short Paintbrush_height; /// Position of current paintbrush's handle GFX2_GLOBAL short Paintbrush_offset_X; /// Position of current paintbrush's handle GFX2_GLOBAL short Paintbrush_offset_Y; // -- Graphic commands /// On the screen, draw a point. GFX2_GLOBAL Func_pixel Pixel; /// Test a pixel color from screen. GFX2_GLOBAL Func_read Read_pixel; /// Redraw all screen, without overwriting the menu. GFX2_GLOBAL Func_display Display_screen; /// Draw a rectangle on screen. GFX2_GLOBAL Func_block Block; /// Draw a point from the image to screen (no zoom). GFX2_GLOBAL Func_pixel Pixel_preview_normal; /// Draw a point from the image to screen (magnified part). GFX2_GLOBAL Func_pixel Pixel_preview_magnifier; /// Draw a point from the image to screen (zoomed if needed). GFX2_GLOBAL Func_pixel Pixel_preview; /// Draw a horizontal XOR line on screen. GFX2_GLOBAL Func_line_XOR Horizontal_XOR_line; /// Draw a vertical XOR line on screen. GFX2_GLOBAL Func_line_XOR Vertical_XOR_line; /// Display part of the brush on screen, color mode. GFX2_GLOBAL Func_display_brush_color Display_brush_color; /// Display part of the brush on screen, monochrome mode. GFX2_GLOBAL Func_display_brush_mono Display_brush_mono; /// Clear the brush currently displayed on screen, redrawing the image instead. GFX2_GLOBAL Func_display_brush_color Clear_brush; /// Remap part of the screen after the menu colors have changed. GFX2_GLOBAL Func_remap Remap_screen; /// Draw a line on screen. GFX2_GLOBAL Func_procsline Display_line; /// Draw a line on screen, without doubling it if using wide pixels. (to be used when the line is already doubled in the input buffer) GFX2_GLOBAL Func_procsline Display_line_fast; /// Read a line of pixels from screen. GFX2_GLOBAL Func_procsline Read_line; /// Redraw all magnified part on screen, without overwriting the menu. GFX2_GLOBAL Func_display_zoom Display_zoomed_screen; /// Display part of the brush on the magnified part of screen, color mode. GFX2_GLOBAL Func_display_brush_color_zoom Display_brush_color_zoom; /// Display part of the brush on the magnified part of screen, monochrome mode. GFX2_GLOBAL Func_display_brush_mono_zoom Display_brush_mono_zoom; /// Clear the brush currently displayed on the magnified part of screen, redrawing the image instead. GFX2_GLOBAL Func_display_brush_color_zoom Clear_brush_scaled; /// Draw an arbitrary brush on screen (not the current brush) GFX2_GLOBAL Func_draw_brush Display_brush; // -- Screen data /// Requested window width. This is set when the user resizes the window. GFX2_GLOBAL int Resize_width; /// Requested window height. This is set when the user resizes the window. GFX2_GLOBAL int Resize_height; /// Current video mode. Index in ::Video_mode GFX2_GLOBAL int Current_resolution; /// After loading an image, this holds the "original screen width", if the file format supported it. GFX2_GLOBAL short Original_screen_X; /// After loading an image, this holds the "original screen height", if the file format supported it. GFX2_GLOBAL short Original_screen_Y; /// /// Current screen (or window) width, in pixels. /// Note that this takes ::Pixel_ratio into account. GFX2_GLOBAL short Screen_width; /// /// Current screen (or window) height, in pixels. /// Note that this takes ::Pixel_ratio into account. GFX2_GLOBAL short Screen_height; /// Coordinate (in image space) of the topmost visible pixel. GFX2_GLOBAL short Limit_top; /// /// Coordinate (in image space) of the lowest visible pixel. /// This can be larger than the image height, if the screen is bigger than image. GFX2_GLOBAL short Limit_bottom; /// Coordinate (in image space) of the leftmost visible pixel. GFX2_GLOBAL short Limit_left; /// /// Coordinate (in image space) of the rightmost visible pixel. /// This can be larger than the image width, if the screen is bigger than image. GFX2_GLOBAL short Limit_right; /// /// Coordinate (in image space) of the lowest visible pixel, limited by the /// image height. Compare with ::Limit_bottom, which is not clipped. GFX2_GLOBAL short Limit_visible_bottom; /// /// Coordinate (in image space) of the rightmost visible pixel, limited by the /// image width. Compare with ::Limit_right, which is not clipped. GFX2_GLOBAL short Limit_visible_right; /// Coordinate (in image space) of the pixel at the top of the magnified view. GFX2_GLOBAL short Limit_top_zoom; /// /// Coordinate (in image space) of the pixel at the bottom of the magnified view. /// This can be larger than the image height, if the screen is bigger than image. GFX2_GLOBAL short Limit_bottom_zoom; /// Coordinate (in image space) of the pixel at the left of the magnified view. GFX2_GLOBAL short Limit_left_zoom; /// /// Coordinate (in image space) of the pixel at the right of the magnified view. /// This can be larger than the image width, if the screen is bigger than image. GFX2_GLOBAL short Limit_right_zoom; /// /// Coordinate (in image space) of the lowest visible pixel, limited by the /// image height. Compare with ::Limit_bottom, which is not clipped. GFX2_GLOBAL short Limit_visible_bottom_zoom; /// Coordinate (in image space) of the rightmost visible pixel. /// This can be larger than the image width, if the screen is bigger than image. GFX2_GLOBAL short Limit_visible_right_zoom; /// Buffer of pixels, used when drawing something to screen. GFX2_GLOBAL byte * Horizontal_line_buffer; /// Current pixel ratio. Index in enum ::PIXEL_RATIO GFX2_GLOBAL int Pixel_ratio; /// Current width of pixels, according to ::Pixel_ratio GFX2_GLOBAL int Pixel_width; /// Current height of pixels, according to ::Pixel_ratio GFX2_GLOBAL int Pixel_height; // -- Current image data /// Pointer to the pixel data of the main image GFX2_GLOBAL byte * Main_screen; /// Palette of the main image GFX2_GLOBAL T_Palette Main_palette; /// Boolean, means the image has been modified since last save. GFX2_GLOBAL byte Main_image_is_modified; /// Width in pixels of the main image. GFX2_GLOBAL short Main_image_width; /// Height in pixels of the main image. GFX2_GLOBAL short Main_image_height; /// X position (in image space) of the pixel to display in the top left corner of screen. GFX2_GLOBAL short Main_offset_X; /// Y position (in image space) of the pixel to display in the top left corner of screen. GFX2_GLOBAL short Main_offset_Y; /// Name of the directory that holds the image currently edited. GFX2_GLOBAL char Main_file_directory[1024]; /// Filename (without directory) of the image currently edited. GFX2_GLOBAL char Main_filename[256]; /// File format of the image currently edited. It's a value of enum ::FILE_FORMATS GFX2_GLOBAL byte Main_fileformat; /// /// Fileselector "filter" format, for the current image. /// (The spare page has its own separate settings) /// It's 0 for "*.*", or a value of enum ::FILE_FORMATS GFX2_GLOBAL byte Main_format; /// Index of the first file/entry to display in the fileselector. GFX2_GLOBAL short Main_fileselector_position; /// /// Position of the "highlight" bar in the fileselector. 10 Files can be visible, /// So it's a number in the [0-9] range. GFX2_GLOBAL short Main_fileselector_offset; /// Current directory for the fileselector. GFX2_GLOBAL char Main_current_directory[1024]; /// Main image's file comment (some image formats support text strings). GFX2_GLOBAL char Main_comment[COMMENT_SIZE+1]; /// X position (in screen coordinates) of the separator between normal and magnified views. GFX2_GLOBAL short Main_separator_position; /// X position (in screen coordinates) of the first pixel of the magnified view. GFX2_GLOBAL short Main_X_zoom; /// Proportion of the non-magnified part of the screen. GFX2_GLOBAL float Main_separator_proportion; /// Boolean, true if the main image has the magnifier active. GFX2_GLOBAL byte Main_magnifier_mode; /// Zoom factor used in the magnifier (main image). GFX2_GLOBAL word Main_magnifier_factor; /// Height of the magnified view for the main image. GFX2_GLOBAL word Main_magnifier_height; /// Width of the magnified view for the main image. GFX2_GLOBAL word Main_magnifier_width; /// X position (in image space) of the pixel to display in the top left corner of the magnified view. GFX2_GLOBAL short Main_magnifier_offset_X; /// Y position (in image space) of the pixel to display in the top left corner of the magnified view. GFX2_GLOBAL short Main_magnifier_offset_Y; /// Index of layer currently being edited GFX2_GLOBAL byte Main_current_layer; /// Bitfield that records which layers are visible. 2^0 for 0, 2^1 for 1, 2^2 for 2, etc. GFX2_GLOBAL dword Main_layers_visible; /// Index to use next time, when creating incremental backups, to make unique filename. GFX2_GLOBAL long Main_safety_number; /// Number of edit actions since the last safety backup GFX2_GLOBAL long Main_edits_since_safety_backup; /// SDL Time of the previous safety backup GFX2_GLOBAL Uint32 Main_time_of_safety_backup; /// Letter prefix for the filenames of safety backups. a or b GFX2_GLOBAL byte Main_safety_backup_prefix; // -- Spare page data /// Palette of the spare page GFX2_GLOBAL T_Palette Spare_palette; /// Boolean, means the spare page has been modified since last save. GFX2_GLOBAL byte Spare_image_is_modified; /// Width in pixels of the spare image. GFX2_GLOBAL short Spare_image_width; /// Height in pixels of the spare image. GFX2_GLOBAL short Spare_image_height; /// X position (in image space) of the pixel to display in the top left corner of screen. GFX2_GLOBAL short Spare_offset_X; /// Y position (in image space) of the pixel to display in the top left corner of screen. GFX2_GLOBAL short Spare_offset_Y; /// Name of the directory that holds the image currently edited as spare page. GFX2_GLOBAL char Spare_file_directory[MAX_PATH_CHARACTERS]; /// Filename (without directory) of the image currently edited as spare page. GFX2_GLOBAL char Spare_filename[MAX_PATH_CHARACTERS]; /// File format of the image currently edited as spare page. It's a value of enum ::FILE_FORMATS GFX2_GLOBAL byte Spare_fileformat; /// /// Fileselector "filter" format, for the spare page. /// (The main image has its own separate settings) /// It's 0 for "*.*", or a value of enum ::FILE_FORMAT GFX2_GLOBAL byte Spare_format; /// Index of the first file/entry to display in the fileselector. GFX2_GLOBAL short Spare_fileselector_position; /// /// Position of the "highlight" bar in the fileselector. 10 Files can be visible, /// So it's a number in the [0-9] range. GFX2_GLOBAL short Spare_fileselector_offset; /// Current directory for the fileselector. GFX2_GLOBAL char Spare_current_directory[MAX_PATH_CHARACTERS]; /// Spare page's file comment (some image formats support text strings). GFX2_GLOBAL char Spare_comment[COMMENT_SIZE+1]; /// X position (in screen coordinates) of the separator between normal and magnified views. GFX2_GLOBAL short Spare_separator_position; /// X position (in screen coordinates) of the first pixel of the magnified view. GFX2_GLOBAL short Spare_X_zoom; /// Proportion of the non-magnified part of the screen. GFX2_GLOBAL float Spare_separator_proportion; /// Boolean, true if the main image has the magnifier active. GFX2_GLOBAL byte Spare_magnifier_mode; /// Zoom factor used in the magnifier (spare page). GFX2_GLOBAL word Spare_magnifier_factor; /// Width of the magnified view for the spare page. GFX2_GLOBAL word Spare_magnifier_height; /// Height of the magnified view for the spare page. GFX2_GLOBAL word Spare_magnifier_width; /// X position (in image space) of the pixel to display in the top left corner of the magnified view. GFX2_GLOBAL short Spare_magnifier_offset_X; /// Y position (in image space) of the pixel to display in the top left corner of the magnified view. GFX2_GLOBAL short Spare_magnifier_offset_Y; /// Index of layer currently being edited GFX2_GLOBAL byte Spare_current_layer; /// Bitfield that records which layers are visible. 2^0 for 0, 2^1 for 1, 2^2 for 2, etc. GFX2_GLOBAL dword Spare_layers_visible; /// Index to use next time, when creating incremental backups, to make unique filename. GFX2_GLOBAL long Spare_safety_number; /// Number of edit actions since the last safety backup GFX2_GLOBAL long Spare_edits_since_safety_backup; /// SDL Time of the previous safety backup GFX2_GLOBAL Uint32 Spare_time_of_safety_backup; /// Letter prefix for the filenames of safety backups. a or b GFX2_GLOBAL byte Spare_safety_backup_prefix; // -- Image backups /// Backup of the current screen, used during drawing when FX feedback is OFF. GFX2_GLOBAL byte * Screen_backup; /// List of backup pages for the main image. GFX2_GLOBAL T_List_of_pages * Main_backups; /// List of backup pages for the spare page. GFX2_GLOBAL T_List_of_pages * Spare_backups; // -- Brush data /// Pixel data of the current brush (remapped). GFX2_GLOBAL byte * Brush; /// Pixel data of the current brush (before remap). GFX2_GLOBAL byte * Brush_original_pixels; /// Palette of the brush, from when it was grabbed. GFX2_GLOBAL T_Palette Brush_original_palette; /// Back_color used when the brush was grabbed GFX2_GLOBAL byte Brush_original_back_color; /// Color mapping from ::Brush_original_pixels to ::Brush GFX2_GLOBAL byte Brush_colormap[256]; /// X coordinate of the brush's "hot spot". It is < ::Brush_width GFX2_GLOBAL word Brush_offset_X; /// Y coordinate of the brush's "hot spot". It is < ::Brush_height GFX2_GLOBAL word Brush_offset_Y; /// Width of the current brush. GFX2_GLOBAL word Brush_width; /// Height of the current brush. GFX2_GLOBAL word Brush_height; /// Name of the directory that holds the brush fil (after loading or saving it). GFX2_GLOBAL char Brush_file_directory[MAX_PATH_CHARACTERS]; /// Filename (without directory) of the brush (after loading or saving it). GFX2_GLOBAL char Brush_filename[MAX_PATH_CHARACTERS]; /// File format of the brush. It's a value of enum ::FILE_FORMATS GFX2_GLOBAL byte Brush_fileformat; /// /// Fileselector "filter" format, for the brush. /// It's 0 for "*.*", or a value of enum ::FILE_FORMATS GFX2_GLOBAL byte Brush_format; /// Index of the first file/entry to display in the brush's fileselector. GFX2_GLOBAL short Brush_fileselector_position; /// /// Position of the "highlight" bar in the brush's fileselector. 10 Files can /// be visible, so it's a number in the [0-9] range. GFX2_GLOBAL short Brush_fileselector_offset; /// Current directory for the brush's fileselector. GFX2_GLOBAL char Brush_current_directory[256]; /// File comment in the brush's fileselector (some image formats support text strings). GFX2_GLOBAL char Brush_comment[COMMENT_SIZE+1]; /// Indicator used for the "Rotate brush" operation. GFX2_GLOBAL byte Brush_rotation_center_is_defined; /// Position of the brush's rotation center, in screen coordinates. GFX2_GLOBAL short Brush_rotation_center_X; /// Position of the brush's rotation center, in screen coordinates. GFX2_GLOBAL short Brush_rotation_center_Y; // -- Menu data (toolbox) /// Boolean, true if the menu has to be displayed. GFX2_GLOBAL byte Menu_is_visible; /// Height of the menu, when it's displayed GFX2_GLOBAL word Menu_height; /// /// Y position (in screen coordinates) where the menu begins. /// This is always either ::Screen_height (when menu is hidden) or (::Screen_height - ::Menu_height) /// As a result, the drawing algoritm always draws the image from 0 to ::Menu_Y-1 GFX2_GLOBAL word Menu_Y; /// Y position of the status bar (in screen coordinates) GFX2_GLOBAL word Menu_status_Y; /// Scaling factor for the menu and all GUI elements GFX2_GLOBAL byte Menu_factor_X; /// Scaling factor for the menu and all GUI elements GFX2_GLOBAL byte Menu_factor_Y; /// Size of a color cell in the menu's palette. GFX2_GLOBAL word Menu_palette_cell_width; GFX2_GLOBAL T_Menu_Bar Menu_bars[MENUBAR_COUNT] #ifdef GLOBAL_VARIABLES = {{MENU_WIDTH, 9, 1, 45, {NULL,NULL,NULL}, 20, BUTTON_HIDE }, // Status {MENU_WIDTH, 10, 1, 35, {NULL,NULL,NULL}, 144, BUTTON_LAYER_SELECT }, // Layers {MENU_WIDTH, 35, 1, 0, {NULL,NULL,NULL}, 254, BUTTON_CHOOSE_COL }} // Main #endif ; // -- Window data /// Number of stacked windows currently displayed. 0 when no window is present. GFX2_GLOBAL byte Windows_open; /// Backup of ::Menu_is_visible, used to store it while a window is open. GFX2_GLOBAL byte Menu_is_visible_before_window; /// Backup of ::Menu_Y, used to store it while a window is open. GFX2_GLOBAL word Menu_Y_before_window; /// Backup of ::Paintbrush_hidden, used to store it while a window is open. GFX2_GLOBAL byte Paintbrush_hidden_before_window; /// The global stack of editor screens. GFX2_GLOBAL T_Window Window_stack[8]; /// Position of the left border of the topmost window (in screen coordinates) #define Window_pos_X Window_stack[Windows_open-1].Pos_X /// Position of the top border of the topmost window (in screen coordinates) #define Window_pos_Y Window_stack[Windows_open-1].Pos_Y /// /// Width of the topmost window, in "window pixels" /// (multiply by ::Menu_factor_X to get screen pixels) #define Window_width Window_stack[Windows_open-1].Width /// /// Height of the topmost window, in "window pixels" /// (multiply by ::Menu_factor_Y to get screen pixels) #define Window_height Window_stack[Windows_open-1].Height /// Total number of buttons/controls in the topmost window. #define Window_nb_buttons Window_stack[Windows_open-1].Nb_buttons /// List of normal buttons in the topmost window. #define Window_normal_button_list Window_stack[Windows_open-1].Normal_button_list /// List of "palette" buttons in the topmost window. #define Window_palette_button_list Window_stack[Windows_open-1].Palette_button_list /// List of sliders (scrollers) in the topmost window. #define Window_scroller_button_list Window_stack[Windows_open-1].Scroller_button_list /// List of special buttons in the topmost window. #define Window_special_button_list Window_stack[Windows_open-1].Special_button_list /// List of dropdown buttons in the topmost window. #define Window_dropdown_button_list Window_stack[Windows_open-1].Dropdown_button_list /// List of list buttons in the topmost window. #define Window_list_button_list Window_stack[Windows_open-1].List_button_list /// /// The function ::Window_clicked_button() set this to ::LEFT_SIDE or ::RIGHT_SIDE /// after a button is activated through left or right mouse click. #define Window_attribute1 Window_stack[Windows_open-1].Attribute1 /// /// The function ::Window_clicked_button() set this to return extra information: /// - When a scroller was clicked: the scroller position (0-n) /// - When a palette was clicked: the color index (0-255) /// - When a dropdown was used: the selected item's number T_Dropdown_choice::Number #define Window_attribute2 Window_stack[Windows_open-1].Attribute2 #define Window_draggable Window_stack[Windows_open-1].Draggable /// Definition of the menu (toolbox) GFX2_GLOBAL struct { // Button aspect word X_offset; ///< Position relative to menu's left word Y_offset; ///< Position relative to menu's top word Width; ///< Button's active width word Height; ///< Button's active heigth byte Pressed; ///< Button is currently pressed byte Shape; ///< Shape, listed in enum ::BUTTON_SHAPES signed char Icon; ///< Which icon to display: Either the one from the toolbar (-1) or one of ::MENU_SPRITE // Triggers on mouse/keyboard Func_action Left_action; ///< Action triggered by a left mouseclick on the button Func_action Right_action; ///< Action triggered by a right mouseclick on the button word Left_shortcut[2]; ///< Keyboard shortcut for a left mouseclick word Right_shortcut[2];///< Keyboard shortcut for a right mouseclick byte Left_instant; ///< Will not wait for mouse release before triggering action byte Right_instant; ///< Will not wait for mouse release before triggering action // Data used when the button is unselected Func_action Unselect_action; ///< Action triggered by unselecting the button byte Family; ///< enum ::FAMILY_OF_BUTTONS. } Buttons_Pool[NB_BUTTONS]; // -- Information about the different drawing modes (effects) /// Current effecting function. When no effect is selected this is ::No_effect() GFX2_GLOBAL Func_effect Effect_function; /// /// Array of booleans, indicates which colors should never be picked by /// ::Best_color() GFX2_GLOBAL byte Exclude_color[256]; // -- Smear mode /// Smear mode is activated GFX2_GLOBAL byte Smear_mode; /// Boolean, indicates that a smear is in progress. GFX2_GLOBAL byte Smear_start; /// Pointer to the sprite to use for smear; it contains pixels from the image. GFX2_GLOBAL byte * Smear_brush; /// Width of the ::Smear_brush GFX2_GLOBAL word Smear_brush_width; /// Height of the ::Smear_brush GFX2_GLOBAL word Smear_brush_height; /// Limits of the smear. GFX2_GLOBAL short Smear_min_X; /// Limits of the smear. GFX2_GLOBAL short Smear_max_X; /// Limits of the smear. GFX2_GLOBAL short Smear_min_Y; /// Limits of the smear. GFX2_GLOBAL short Smear_max_Y; // -- Shade mode /// List of the shade tables GFX2_GLOBAL T_Shade Shade_list[8]; /// Shade currently selected (index in ::Shade_list) GFX2_GLOBAL byte Shade_current; /// Conversion table in use GFX2_GLOBAL byte * Shade_table; /// Conversion table for a left click GFX2_GLOBAL byte Shade_table_left[256]; /// Conversion table for a right click GFX2_GLOBAL byte Shade_table_right[256]; /// Boolean, true when the shade mode is active. GFX2_GLOBAL byte Shade_mode; /// Boolean, true when the quick-shade mode is active. GFX2_GLOBAL byte Quick_shade_mode; /// Size of the step, in Quick-shade mode. It's the number of colors to "jump". GFX2_GLOBAL byte Quick_shade_step; /// Determines how colors should loop in Quick-shade more. Value in enum ::SHADE_MODES GFX2_GLOBAL byte Quick_shade_loop; // -- Stencil mode /// Boolean, true when stencil mode is active. GFX2_GLOBAL byte Stencil_mode; /// Array of the protected colors by Stencil mode. GFX2_GLOBAL byte Stencil[256]; // -- Grid mode /// Boolean, true when the Grid mode is active. GFX2_GLOBAL byte Snap_mode; /// Boolean, true when the Grid is displayed in zoomed view. GFX2_GLOBAL byte Show_grid; /// Width of the grid in Grid mode. GFX2_GLOBAL word Snap_width; /// Height of the grid in Grid mode. GFX2_GLOBAL word Snap_height; /// Position of the starting pixel, in Grid mode. GFX2_GLOBAL word Snap_offset_X; /// Position of the starting pixel, in Grid mode. GFX2_GLOBAL word Snap_offset_Y; // -- Sieve mode /// Boolean, true when the Sieve mode is active GFX2_GLOBAL byte Sieve_mode; /// Sprite of the sieve pattern. It's actually an array of booleans. GFX2_GLOBAL byte Sieve[16][16]; /// Width of the sieve pattern, in Sieve mode. GFX2_GLOBAL short Sieve_width; /// Height of the sieve pattern, in Sieve mode. GFX2_GLOBAL short Sieve_height; // -- Colorize mode /// Boolean, true when the Colorize mode is active. GFX2_GLOBAL byte Colorize_mode; /// % of opacity of Colorize mode (for translucency) GFX2_GLOBAL byte Colorize_opacity; /// Sets the colorization mode: 0 transparency, 1 additive, 2 substractive GFX2_GLOBAL byte Colorize_current_mode; /// /// Table of precomputed factors used by Colorize mode. It hold 0 to 255 when /// opacity is 100%, 0 to 128 when opacity is 50%, etc. // FIXME: This only caches a multiplication and a division. Maybe we should scrap it GFX2_GLOBAL word Factors_table[256]; /// /// Table of precomputed factors used by Colorize mode. It hold 255 to 0 when /// opacity is 100%, 128 to 0 when opacity is 50%, etc. // FIXME: This only caches a multiplication, a division, a substraction. Maybe we should scrap it GFX2_GLOBAL word Factors_inv_table[256]; // -- Smooth mode /// Boolean, true when the Smooth mode is active GFX2_GLOBAL byte Smooth_mode; /// Matrix of "weights" used by the Smooth mode. GFX2_GLOBAL byte Smooth_matrix[3][3]; // -- Tiling mode /// Boolean, true when the Tiling mode is active GFX2_GLOBAL byte Tiling_mode; /// Position of the starting pixel in Tiling mode. GFX2_GLOBAL short Tiling_offset_X; /// Position of the starting pixel in Tiling mode. GFX2_GLOBAL short Tiling_offset_Y; // -- Mask mode /// Boolean, true when the Tiling mode is active GFX2_GLOBAL byte Mask_mode; /// Array of booleans. True if the indexed color is protected by the mask. GFX2_GLOBAL byte Mask_table[256]; // -- Magnifier data #ifdef GLOBAL_VARIABLES word ZOOM_FACTOR[NB_ZOOM_FACTORS]={2,3,4,5,6,8,10,12,14,16,18,20, 24, 28, 32}; #else /// Successive zoom factors, used by the Magnifier. extern word ZOOM_FACTOR[NB_ZOOM_FACTORS]; #endif // -- Data for ellipses and circles // FIXME: move most of these to graph.c GFX2_GLOBAL long Ellipse_cursor_X; GFX2_GLOBAL long Ellipse_cursor_Y; GFX2_GLOBAL long Ellipse_vertical_radius_squared; GFX2_GLOBAL long Ellipse_horizontal_radius_squared; GFX2_GLOBAL qword Ellipse_limit; GFX2_GLOBAL long Circle_cursor_X; GFX2_GLOBAL long Circle_cursor_Y; GFX2_GLOBAL long Circle_limit; // -- Data for gradients /// First color of the gradient. GFX2_GLOBAL short Gradient_lower_bound; /// Last color of the gradient GFX2_GLOBAL short Gradient_upper_bound; /// Boolean, true if the gradient should use colors in descending order GFX2_GLOBAL int Gradient_is_inverted; /// Number of colors in the range ::Gradient_lower_bound to ::Gradient_upper_bound (included) GFX2_GLOBAL long Gradient_bounds_range; /// Maximum value passed to the gradient function. The pixels assigned this value should use last gradient color. GFX2_GLOBAL long Gradient_total_range; /// Amount of randomness to use in gradient (1-256+) GFX2_GLOBAL long Gradient_random_factor; /// Gradient speed of cycling (0-64) GFX2_GLOBAL byte Gradient_speed; /// Pointer to a gradient function, depending on the selected method. GFX2_GLOBAL Func_gradient Gradient_function; /// /// Pointer to the pixel-drawing function that gradients should use: /// either ::Pixel (if the gradient must be drawn on menus only) /// or ::Display_pixel (if the gradient must be drawn on the image) GFX2_GLOBAL Func_pixel Gradient_pixel; /// Index in ::Gradient_array of the currently selected gradient. GFX2_GLOBAL byte Current_gradient; /// Boolean, true when the color cycling is active. GFX2_GLOBAL byte Cycling_mode; // -- Airbrush data /// Mode to use in airbrush: 0 for multicolor, 1 for mono. GFX2_GLOBAL byte Airbrush_mode; /// Diameter of the airbrush, in pixels. GFX2_GLOBAL short Airbrush_size; /// Delay between two airbrush "shots", in 1/100s GFX2_GLOBAL byte Airbrush_delay; /// Number of pixels that are emitted by the airbrush, in mono mode. GFX2_GLOBAL byte Airbrush_mono_flow; /// Number of pixels that are emitted by the airbrush for each color (multi mode) GFX2_GLOBAL byte Airbrush_multi_flow[256]; /// -- Misc data about the program /// Boolean, set to true to exit the program. GFX2_GLOBAL byte Quitting; /// Name of the directory that was current when the program was run. GFX2_GLOBAL char Initial_directory[256]; /// Name of the directory that holds the program's (read-only) data: skins, icon, etc. GFX2_GLOBAL char Data_directory[256]; /// Name of the directory where grafx2 reads and writes configuration (gfx2.ini, gfx2.cfg) GFX2_GLOBAL char Config_directory[256]; /// Current foreground color for drawing. GFX2_GLOBAL byte Fore_color; /// Current background color for drawing. GFX2_GLOBAL byte Back_color; /// For the "Freehand draw" tool, this determines which variant is selected, from ::OPERATION_CONTINUOUS_DRAW to ::OPERATION_FILLED_CONTOUR GFX2_GLOBAL byte Selected_freehand_mode; /// For the Curve tool, this determines which variant is selected, either ::OPERATION_3_POINTS_CURVE or ::OPERATION_4_POINTS_CURVE GFX2_GLOBAL byte Selected_curve_mode; /// For the Line tool, this determines which variant is selected, either ::OPERATION_LINE, ::OPERATION_K_LIGNE or ::OPERATION_CENTERED_LINES GFX2_GLOBAL byte Selected_line_mode; /// Determines which color appears in the first cell of the menu palette. Change this value to "scroll" the palette. GFX2_GLOBAL byte First_color_in_palette; /// Boolean, true if Grafx2 was run with a command-line argument to set a resolution on startup (overrides config) GFX2_GLOBAL byte Resolution_in_command_line; // - Graphic /// Pointer to the font selected for menus. GFX2_GLOBAL byte * Menu_font; /// Pointer to the current active skin. GFX2_GLOBAL T_Gui_skin * Gfx; /// Pointer to the current active skin. GFX2_GLOBAL T_Paintbrush Paintbrush[NB_PAINTBRUSH_SPRITES]; // -- Help data /// Index of the ::Help_section shown by the Help screen. GFX2_GLOBAL byte Current_help_section; /// Line number of the help viewer, in current ::Help_section. 0 for top, increase value to scroll down. GFX2_GLOBAL word Help_position; // -- Operation data /// Index of the operation which was selected (ex: drawing rectangle) before the current interruption (ex: colorpicking). GFX2_GLOBAL word Operation_before_interrupt; /// Index of the current operation. This is the active "tool". GFX2_GLOBAL word Current_operation; /// /// This stack is used to memorize all parameters needed during the course of /// an operation. For example when drawing a rectangle: color, starting /// coordinates, ending coordinates. GFX2_GLOBAL word Operation_stack[OPERATION_STACK_SIZE]; /// Number of parameters stored in ::Operation_stack (0=empty) GFX2_GLOBAL byte Operation_stack_size; /// Boolean, true if the operation (drawing) started in the magnified area. GFX2_GLOBAL byte Operation_in_magnifier; /// Last color hovered by the colorpicker. -1 if it wasn't over the image. GFX2_GLOBAL short Colorpicker_color; /// Position of the colorpicker tool, in image coordinates. GFX2_GLOBAL short Colorpicker_X; /// Position of the colorpicker tool, in image coordinates. GFX2_GLOBAL short Colorpicker_Y; GFX2_GLOBAL short * Polyfill_table_of_points; GFX2_GLOBAL int Polyfill_number_of_points; /// Brush container GFX2_GLOBAL T_Brush_template Brush_container[BRUSH_CONTAINER_COLUMNS*BRUSH_CONTAINER_ROWS]; #ifdef GLOBAL_VARIABLES byte CURSOR_FOR_OPERATION[NB_OPERATIONS]= { CURSOR_SHAPE_TARGET , // Freehand continuous draw CURSOR_SHAPE_TARGET , // Freehand discontinuous draw CURSOR_SHAPE_TARGET , // Freehand point-by-point draw CURSOR_SHAPE_TARGET , // Filled contour CURSOR_SHAPE_TARGET , // Lines CURSOR_SHAPE_TARGET , // Linked lines CURSOR_SHAPE_TARGET , // Centered lines CURSOR_SHAPE_XOR_TARGET , // Empty rectangle CURSOR_SHAPE_XOR_TARGET , // Filled rectangle CURSOR_SHAPE_TARGET , // Empty circle CURSOR_SHAPE_TARGET , // Filled circle CURSOR_SHAPE_TARGET , // Empty ellipse CURSOR_SHAPE_TARGET , // Filled ellipse CURSOR_SHAPE_TARGET , // Fill CURSOR_SHAPE_TARGET , // Color replacer CURSOR_SHAPE_XOR_TARGET , // Rectangular brush grabbing CURSOR_SHAPE_TARGET , // Polygonal brush grabbing CURSOR_SHAPE_COLORPICKER , // Colorpicker CURSOR_SHAPE_XOR_RECTANGLE , // Position the magnify window CURSOR_SHAPE_TARGET , // Curve with 3 control points CURSOR_SHAPE_TARGET , // Curve with 4 control points CURSOR_SHAPE_TARGET , // Airbrush CURSOR_SHAPE_TARGET , // Polygon CURSOR_SHAPE_TARGET , // Polyform CURSOR_SHAPE_TARGET , // Filled polygon CURSOR_SHAPE_TARGET , // Filled polyform CURSOR_SHAPE_MULTIDIRECTIONAL , // Scroll (pan) CURSOR_SHAPE_TARGET , // Gradient-filled circle CURSOR_SHAPE_TARGET , // Gradient-filled ellipse CURSOR_SHAPE_XOR_ROTATION , // Rotate brush CURSOR_SHAPE_XOR_TARGET , // Stretch brush CURSOR_SHAPE_TARGET , // Distort brush CURSOR_SHAPE_XOR_TARGET , // Gradient-filled rectangle CURSOR_SHAPE_COLORPICKER , // Colorpick on right mouse button }; #else /// ::Cursor_shape to use for each operation. extern byte CURSOR_FOR_OPERATION[NB_OPERATIONS]; #endif /// /// Procedures to call for each state (determined by ::Operation_stack_size) of /// each operation, and for each mouse state (no button,left button,right button) GFX2_GLOBAL struct { Func_action Action; ///< Function to call byte Hide_cursor; ///< Boolean: Need to hide/unhide cursor during this step byte Fast_mouse; ///< Operation should take shortcuts with mouse movements } Operation[NB_OPERATIONS][3][OPERATION_STACK_SIZE]; // -- misc /// /// Indicator of error in previous file operations. /// - 0: OK /// - 1: Error when beginning operation. Existing data should be ok. /// - 2: Error while operation was in progress. Data is modified. /// - -1: Interruption of a preview. GFX2_GLOBAL signed char File_error; /// Current line number when reading/writing gfx2.ini GFX2_GLOBAL int Line_number_in_INI_file; // -- Specific to SDL /// Pointer to the program's screen. GFX2_GLOBAL SDL_Surface * Screen_SDL; /// Pointer to the current joystick controller. GFX2_GLOBAL SDL_Joystick* Joystick; /// Indicates "no keyboard shortcut". #define KEY_NONE 0 /// /// This is the "key identifier" for the mouse 3rd button. /// It was chosen to not conflict with any SDL key number. #define KEY_MOUSEMIDDLE (SDLK_LAST+1) /// /// This is the "key identifier" for the mouse wheelup. /// It was chosen to not conflict with any SDL key number. #define KEY_MOUSEWHEELUP (SDLK_LAST+2) /// /// This is the "key identifier" for the mouse wheeldown. /// It was chosen to not conflict with any SDL key number. #define KEY_MOUSEWHEELDOWN (SDLK_LAST+3) /// /// This is the "key identifier" for joystick button number 0. /// All numbers starting with this one are reserved for joystick buttons /// (since their is an unknown number of them, and for example 18 on GP2X) /// It was chosen to not conflict with any SDL key number. #define KEY_JOYBUTTON (SDLK_LAST+4) /// The joystick axis are {X,Y} - on all platforms so far. /// If there is ever a platform where they are reversed, put /// these lines in each platform "case" below. #define JOYSTICK_AXIS_X (0) #define JOYSTICK_AXIS_Y (1) #ifdef __GP2X__ #define JOYSTICK_THRESHOLD (4096) /// Button definitions for the gp2x #define JOY_BUTTON_UP (0) #define JOY_BUTTON_DOWN (4) #define JOY_BUTTON_LEFT (2) #define JOY_BUTTON_RIGHT (6) #define JOY_BUTTON_UPLEFT (1) #define JOY_BUTTON_UPRIGHT (7) #define JOY_BUTTON_DOWNLEFT (3) #define JOY_BUTTON_DOWNRIGHT (5) #define JOY_BUTTON_CLICK (18) #define JOY_BUTTON_A (12) #define JOY_BUTTON_B (13) #define JOY_BUTTON_Y (14) #define JOY_BUTTON_X (15) #define JOY_BUTTON_L (10) #define JOY_BUTTON_R (11) #define JOY_BUTTON_START (8) #define JOY_BUTTON_SELECT (9) #define JOY_BUTTON_VOLUP (16) #define JOY_BUTTON_VOLDOWN (17) #define KEY_ESC (KEY_JOYBUTTON+JOY_BUTTON_X) #elif defined(__WIZ__) /// Button definitions for the Wiz #define JOY_BUTTON_UP (0) #define JOY_BUTTON_DOWN (4) #define JOY_BUTTON_LEFT (2) #define JOY_BUTTON_RIGHT (6) #define JOY_BUTTON_UPLEFT (1) #define JOY_BUTTON_UPRIGHT (7) #define JOY_BUTTON_DOWNLEFT (3) #define JOY_BUTTON_DOWNRIGHT (5) #define JOY_BUTTON_L (10) #define JOY_BUTTON_R (11) #define JOY_BUTTON_A (12) #define JOY_BUTTON_B (13) #define JOY_BUTTON_X (14) #define JOY_BUTTON_Y (15) #define JOY_BUTTON_MENU (8) #define JOY_BUTTON_SELECT (9) #define JOY_BUTTON_VOLUP (16) #define JOY_BUTTON_VOLDOWN (17) #define KEY_ESC (KEY_JOYBUTTON+JOY_BUTTON_X) #elif defined (__CAANOO__) #define JOYSTICK_THRESHOLD (4096) /// Button definitions for the Caanoo #define JOY_BUTTON_A (0) #define JOY_BUTTON_X (1) #define JOY_BUTTON_B (2) #define JOY_BUTTON_Y (3) #define JOY_BUTTON_L (4) #define JOY_BUTTON_R (5) #define JOY_BUTTON_HOME (6) #define JOY_BUTTON_HOLD (7) #define JOY_BUTTON_I (8) #define JOY_BUTTON_II (9) #define JOY_BUTTON_JOY (10) #define KEY_ESC (KEY_JOYBUTTON+JOY_BUTTON_HOME) #else /// /// This is the key identifier for ESC. When hard-coding keyboard shortcuts /// for buttons, etc. we use this instead of SDLK_ESCAPE, /// so the console ports can get a joybutton equivalent of it. #define KEY_ESC SDLK_ESCAPE #endif #endif grafx2/src/graph.h0000644000076400010400000001370311537000540014472 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007-2008 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file graph.h /// Graphic functions that target the screen and/or image. ////////////////////////////////////////////////////////////////////////////// void Shade_list_to_lookup_tables(word * list, short step, byte mode, byte * table_inc, byte * table_dec ); void Transform_point(short x, short y, float cos_a, float sin_a, short * rx, short * ry); int Init_mode_video(int width, int height, int fullscreen,int pixel_ratio); byte No_effect(word x,word y,byte color); byte Effect_shade(word x,word y,byte color); byte Effect_quick_shade(word x,word y,byte color); byte Effect_tiling(word x,word y,byte color); byte Effect_smooth(word x,word y,byte color); void Display_foreback(void); void Display_pixel(word x,word y,byte color); void Display_paintbrush(short x,short y,byte color,byte is_preview); void Hide_paintbrush(short x,short y); void Resize_image(word chosen_width,word chosen_height); void Fill_general(byte fill_color); void Replace(byte New_color); void Pixel_figure_preview (word x_pos,word y_pos,byte color); void Pixel_figure_preview_auto(word x_pos,word y_pos); void Pixel_figure_preview_xor(word x_pos,word y_pos,byte color); void Pixel_figure_preview_xorback(word x_pos,word y_pos,byte color); void Pixel_figure_in_brush(word x_pos,word y_pos,byte color); void Draw_empty_circle_general(short center_x,short center_y,short radius,byte color); void Draw_empty_circle_permanent(short center_x,short center_y,short radius,byte color); void Draw_empty_circle_preview (short center_x,short center_y,short radius,byte color); void Hide_empty_circle_preview (short center_x,short center_y,short radius); void Draw_empty_circle_general(short center_x,short center_y,short radius,byte color); void Draw_filled_circle (short center_x,short center_y,short radius,byte color); void Draw_empty_ellipse_permanent(short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color); void Draw_empty_ellipse_preview (short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color); void Hide_empty_ellipse_preview (short center_x,short center_y,short horizontal_radius,short vertical_radius); void Draw_filled_ellipse (short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color); void Clamp_coordinates_regular_angle(short ax, short ay, short* bx, short* by); void Draw_line_general(short start_x,short start_y,short end_x,short end_y, byte color); void Draw_line_permanent (short start_x,short start_y,short end_x,short end_y,byte color); void Draw_line_preview (short start_x,short start_y,short end_x,short end_y,byte color); void Draw_line_preview_xor(short start_x,short start_y,short end_x,short end_y,byte color); void Draw_line_preview_xorback(short start_x,short start_y,short end_x,short end_y,byte color); void Hide_line_preview (short start_x,short start_y,short end_x,short end_y); void Draw_empty_rectangle(short start_x,short start_y,short end_x,short end_y,byte color); void Draw_filled_rectangle(short start_x,short start_y,short end_x,short end_y,byte color); void Draw_curve_permanent(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, byte color); void Draw_curve_preview (short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, byte color); void Hide_curve_preview (short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, byte color); void Airbrush(short clicked_button); void Gradient_basic (long index,short x_pos,short y_pos); void Gradient_dithered (long index,short x_pos,short y_pos); void Gradient_extra_dithered(long index,short x_pos,short y_pos); void Degrade_aleatoire (long index,short x_pos,short y_pos); void Draw_grad_circle (short center_x,short center_y,short radius,short spot_x,short spot_y); void Draw_grad_ellipse(short center_x,short center_y,short horizontal_radius,short vertical_radius,short spot_x,short spot_y); void Draw_grad_rectangle(short rax,short ray,short rbx,short rby,short vax,short vay, short vbx, short vby); void Polyfill_general(int vertices, short * points, int color); void Polyfill(int vertices, short * points, int color); /// Remap the spare page according to the main page's palette void Remap_spare(void); /// /// 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); void Redraw_grid(short x, short y, unsigned short w, unsigned short h); void Pixel_in_current_screen (word x,word y,byte color,int with_preview); void Pixel_in_current_layer(word x,word y, byte color); byte Read_pixel_from_current_screen (word x,word y); byte Read_pixel_from_current_layer(word x,word y); grafx2/src/haiku.h0000644000076400010400000000015211371336744014502 0ustar vigAdministrator#include "struct.h" #ifndef __HAIKU_H #define __HAIKU_H qword haiku_get_free_space(char* path); #endif grafx2/src/help.h0000644000076400010400000000445311546441764014344 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file help.h /// Functions related to the help browser. The help data is in helpfile.h ////////////////////////////////////////////////////////////////////////////// #ifndef __HELP_H_ #define __HELP_H_ /*! Called to open the help window with the keyboard shortcut. If the mouse is over a button, its contextual help will be displayed. Else, the default helpscreen will be shown. */ void Button_Help(void); /*! Displays and runs the "Statistics" window */ void Button_Stats(void); /*! Displays and runs the "Help / About..." window @param section Number of the help section page to display (equals the button number the mouse was hovering for the contextual help), -1 for the main help page. @param sub_section Help sub-section title (the page will be scrolled so this title is at the top). */ void Window_help(int section, const char * sub_section); /// Opens a window where you can change a shortcut key(s). void Window_set_shortcut(int action_id); /// /// Print a line with the 'help' (6x8) font. short Print_help(short x_pos, short y_pos, const char *line, char line_type, short link_position, short link_size); // Nom de la touche actuallement assignée à un raccourci d'après son numéro // de type 0x100+BOUTON_* ou SPECIAL_* const char * Keyboard_shortcut_value(word shortcut_number); /// /// Browse the complete list of shortcuts and ensure that a key only triggers /// one of them. void Remove_duplicate_shortcuts(void); #endif grafx2/src/helpfile.h0000644000076400010400000036126211553131714015175 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2009 Franck Charlet 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file helpfile.h /// This is all the text that appears in contextual help and credits. /// /// Note: The source code is kept on a public website, so keep this in mind /// if you're thinking of putting an e-mail address in there. At least, use /// "\100" instead of @, to help against the most basic email address harvesters. ////////////////////////////////////////////////////////////////////////////// #include "const.h" // Uses enumerations BUTTON_NUMBERS and SPECIAL_ACTIONS // Some magic formulas: #define HELP_TEXT(x) {'N', x, 0}, // Generates a 'N' line (Normal) #define HELP_LINK(x,y) {'K', x, y}, // Generates a 'K' line (Key) #define HELP_BOLD(x) {'S', x, 0}, // Generates a 'S' line (BOLD) #define HELP_TITLE(x) {'T', x, 0}, {'-', x, 0}, // Generates a 'T' line (Title, upper half) // and a second '-' line (Title, lower half), with the same text. static const T_Help_table helptable_about[] = /* Do not exceed 44 characters for normal lines: HELP_TEXT ("--------------------------------------------") Do not exceed 22 characters for title lines: HELP_TITLE("======================") */ { HELP_TEXT ("") // Leave enough room for a hard-coded logo, eventually. HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE(" GRAFX 2 ") HELP_BOLD (" \"Dragon's Layers\" Edition") HELP_BOLD (" THE ULTIMATE MULTI-RESOLUTION GFX EDITOR") HELP_TEXT (" http://grafx2.googlecode.com") #if defined(__MINT__) HELP_TEXT (" atari build ") #else HELP_TEXT ("") #endif HELP_TEXT ("Copyright 2007-2011, the Grafx2 project team") HELP_TEXT (" Copyright 1996-2001, SUNSET DESIGN") }; static const T_Help_table helptable_licence[] = { HELP_TITLE(" LICENSE") HELP_TEXT ("") HELP_TEXT ("Grafx2 is FREE SOFTWARE, you can") HELP_TEXT ("redistribute it and/or modify it under the") HELP_TEXT ("terms of the GNU General Public License as") HELP_TEXT ("published by the Free Software Foundation;") HELP_TEXT ("version 2 of the License.") HELP_TEXT ("") HELP_TEXT ("Grafx2 is distributed in the hope that it") HELP_TEXT ("will be useful, but WITHOUT ANY WARRANTY;") HELP_TEXT ("without even the implied warranty of") HELP_TEXT ("MERCHANTABILITY or FITNESS FOR A PARTICULAR") HELP_TEXT ("PURPOSE. See the GNU General Public License") HELP_TEXT ("for more details.") HELP_TEXT ("") HELP_TEXT ("You should have received a copy of the GNU") HELP_TEXT ("General Public License along with Grafx2;") HELP_TEXT ("if not, see http://www.gnu.org/licenses/ or") HELP_TEXT ("write to the Free Software Foundation, Inc.") HELP_TEXT (" 59 Temple Place - Suite 330, Boston,") HELP_TEXT (" MA 02111-1307, USA.") }; static const T_Help_table helptable_help[] = { HELP_TITLE(" HELP") HELP_TEXT ("") HELP_TEXT (" Contextual help is available by pressing") HELP_LINK (" the %s key",0x100+BUTTON_HELP) HELP_TEXT (" You can do it while hovering a menu icon,") HELP_TEXT (" or while a window is open.") HELP_TEXT (" When a keyboard shortcut is displayed it's") HELP_TEXT (" your current configuration and you can") HELP_TEXT (" change it by clicking it.") HELP_TEXT ("") HELP_TITLE(" KEYBOARD SHORTCUTS") HELP_TEXT ("") HELP_TEXT ("Scroll visible area") HELP_LINK (" up: %s", SPECIAL_SCROLL_UP) HELP_LINK (" down: %s", SPECIAL_SCROLL_DOWN) HELP_LINK (" left: %s", SPECIAL_SCROLL_LEFT) HELP_LINK (" right: %s", SPECIAL_SCROLL_RIGHT) HELP_LINK (" up faster: %s", SPECIAL_SCROLL_UP_FAST) HELP_LINK (" down faster: %s", SPECIAL_SCROLL_DOWN_FAST) HELP_LINK (" left faster: %s", SPECIAL_SCROLL_LEFT_FAST) HELP_LINK (" right faster: %s", SPECIAL_SCROLL_RIGHT_FAST) HELP_LINK (" up slower: %s", SPECIAL_SCROLL_UP_SLOW) HELP_LINK (" down slower: %s", SPECIAL_SCROLL_DOWN_SLOW) HELP_LINK (" left slower: %s", SPECIAL_SCROLL_LEFT_SLOW) HELP_LINK (" right slower: %s", SPECIAL_SCROLL_RIGHT_SLOW) HELP_TEXT ("Emulate mouse") HELP_LINK (" Up: %s", SPECIAL_MOUSE_UP) HELP_LINK (" Down: %s", SPECIAL_MOUSE_DOWN) HELP_LINK (" Left: %s", SPECIAL_MOUSE_LEFT) HELP_LINK (" Right: %s", SPECIAL_MOUSE_RIGHT) HELP_LINK (" Left click: %s", SPECIAL_CLICK_LEFT) HELP_LINK (" Right click: %s", SPECIAL_CLICK_RIGHT) HELP_LINK ("Show / Hide menu: %s", 0x100+BUTTON_HIDE) HELP_LINK ("Show / Hide cursor: %s", SPECIAL_SHOW_HIDE_CURSOR) HELP_LINK ("Paintbrush = \".\": %s", SPECIAL_DOT_PAINTBRUSH) HELP_LINK ("Paintbrush choice: %s", 0x100+BUTTON_PAINTBRUSHES) HELP_LINK ("Monochrome brush: %s", 0x200+BUTTON_PAINTBRUSHES) HELP_LINK ("Freehand drawing: %s", 0x100+BUTTON_DRAW) HELP_TEXT ("Switch freehand") HELP_LINK (" drawing mode: %s", 0x200+BUTTON_DRAW) HELP_TEXT ("Continuous freehand") HELP_LINK (" drawing: %s", SPECIAL_CONTINUOUS_DRAW) HELP_LINK ("Line: %s", 0x100+BUTTON_LINES) HELP_LINK ("Knotted lines: %s", 0x200+BUTTON_LINES) HELP_LINK ("Spray: %s", 0x100+BUTTON_AIRBRUSH) HELP_LINK ("Spray menu: %s", 0x200+BUTTON_AIRBRUSH) HELP_LINK ("Floodfill: %s", 0x100+BUTTON_FLOODFILL) HELP_LINK ("Replace color: %s", 0x200+BUTTON_FLOODFILL) HELP_LINK ("Bezier's curves: %s", 0x100+BUTTON_CURVES) HELP_TEXT ("Bezier's curve with") HELP_LINK (" 3 or 4 points %s", 0x200+BUTTON_CURVES) HELP_LINK ("Empty rectangle: %s", 0x100+BUTTON_RECTANGLES) HELP_LINK ("Filled rectangle: %s", 0x100+BUTTON_FILLRECT) HELP_LINK ("Empty circle: %s", 0x100+BUTTON_CIRCLES) HELP_LINK ("Empty ellipse: %s", 0x200+BUTTON_CIRCLES) HELP_LINK ("Filled circle: %s", 0x100+BUTTON_FILLCIRC) HELP_LINK ("Filled ellipse: %s", 0x200+BUTTON_FILLCIRC) HELP_LINK ("Empty polygon: %s", 0x100+BUTTON_POLYGONS) HELP_LINK ("Empty polyform: %s", 0x200+BUTTON_POLYGONS) HELP_LINK ("Polyfill: %s", 0x100+BUTTON_POLYFILL) HELP_LINK ("Filled polyform: %s", 0x200+BUTTON_POLYFILL) HELP_LINK ("Gradient rectangle: %s", 0x100+BUTTON_GRADRECT) HELP_LINK ("Gradation menu: %s", 0x200+BUTTON_GRADRECT) HELP_LINK ("Toggle color cycling:%s", SPECIAL_CYCLE_MODE) HELP_LINK ("Spheres: %s", 0x100+BUTTON_SPHERES) HELP_LINK ("Gradient ellipses: %s", 0x200+BUTTON_SPHERES) HELP_LINK ("Adjust picture: %s", 0x100+BUTTON_ADJUST) HELP_LINK ("Flip picture menu: %s", 0x200+BUTTON_ADJUST) HELP_LINK ("Effects menu: %s", 0x100+BUTTON_EFFECTS) HELP_LINK ("Effects all off %s", SPECIAL_EFFECTS_OFF) HELP_LINK ("Shade mode: %s", SPECIAL_SHADE_MODE) HELP_LINK ("Shade menu: %s", SPECIAL_SHADE_MENU) HELP_LINK ("Quick-shade mode: %s", SPECIAL_QUICK_SHADE_MODE) HELP_LINK ("Quick-shade menu: %s", SPECIAL_QUICK_SHADE_MENU) HELP_LINK ("Stencil mode: %s", SPECIAL_STENCIL_MODE) HELP_LINK ("Stencil menu: %s", SPECIAL_STENCIL_MENU) HELP_LINK ("Mask mode: %s", SPECIAL_MASK_MODE) HELP_LINK ("Mask menu: %s", SPECIAL_MASK_MENU) HELP_LINK ("Grid mode: %s", SPECIAL_GRID_MODE) HELP_LINK ("Grid menu: %s", SPECIAL_GRID_MENU) HELP_LINK ("Grid view: %s", SPECIAL_SHOW_GRID) HELP_LINK ("Sieve mode: %s", SPECIAL_SIEVE_MODE) HELP_LINK ("Sieve menu: %s", SPECIAL_SIEVE_MENU) HELP_LINK ("Invert Sieve: %s", SPECIAL_INVERT_SIEVE) HELP_LINK ("Colorize mode: %s", SPECIAL_COLORIZE_MODE) HELP_LINK (" At opacity 10%%: %s", SPECIAL_TRANSPARENCY_1) HELP_LINK (" At opacity 20%%: %s", SPECIAL_TRANSPARENCY_2) HELP_LINK (" At opacity 30%%: %s", SPECIAL_TRANSPARENCY_3) HELP_LINK (" At opacity 40%%: %s", SPECIAL_TRANSPARENCY_4) HELP_LINK (" At opacity 50%%: %s", SPECIAL_TRANSPARENCY_5) HELP_LINK (" At opacity 60%%: %s", SPECIAL_TRANSPARENCY_6) HELP_LINK (" At opacity 70%%: %s", SPECIAL_TRANSPARENCY_7) HELP_LINK (" At opacity 80%%: %s", SPECIAL_TRANSPARENCY_8) HELP_LINK (" At opacity 90%%: %s", SPECIAL_TRANSPARENCY_9) HELP_LINK (" At opacity 100%%: %s", SPECIAL_TRANSPARENCY_0) HELP_LINK ("Colorize menu: %s", SPECIAL_COLORIZE_MENU) HELP_LINK ("Smooth mode: %s", SPECIAL_SMOOTH_MODE) HELP_LINK ("Smooth menu: %s", SPECIAL_SMOOTH_MENU) HELP_LINK ("Smear mode: %s", SPECIAL_SMEAR_MODE) HELP_LINK ("Tiling mode: %s", SPECIAL_TILING_MODE) HELP_LINK ("Tiling menu: %s", SPECIAL_TILING_MENU) HELP_LINK ("Pick brush: %s", 0x100+BUTTON_BRUSH) HELP_LINK ("Pick polyform brush: %s", 0x100+BUTTON_POLYBRUSH) HELP_LINK ("Restore brush: %s", 0x200+BUTTON_BRUSH) HELP_LINK ("Flip brush X: %s", SPECIAL_FLIP_X) HELP_LINK ("Flip brush Y: %s", SPECIAL_FLIP_Y) HELP_LINK ("90 brush rotation: %s", SPECIAL_ROTATE_90) HELP_LINK ("180 brush rotation: %s", SPECIAL_ROTATE_180) HELP_LINK ("Stretch brush: %s", SPECIAL_STRETCH) HELP_LINK ("Distort brush: %s", SPECIAL_DISTORT) HELP_LINK ("Outline brush: %s", SPECIAL_OUTLINE) HELP_LINK ("Nibble brush: %s", SPECIAL_NIBBLE) HELP_LINK ("Double brush size: %s", SPECIAL_BRUSH_DOUBLE) HELP_LINK ("Halve brush size: %s", SPECIAL_BRUSH_HALVE) HELP_LINK ("Double brush width: %s", SPECIAL_BRUSH_DOUBLE_WIDTH) HELP_LINK ("Double brush height: %s", SPECIAL_BRUSH_DOUBLE_HEIGHT) HELP_LINK ("Get brush colors: %s", SPECIAL_GET_BRUSH_COLORS) HELP_LINK ("Recolorize brush: %s", SPECIAL_RECOLORIZE_BRUSH) HELP_LINK ("Rotate brush: %s", SPECIAL_ROTATE_ANY_ANGLE) HELP_LINK ("Pipette: %s", 0x100+BUTTON_COLORPICKER) HELP_LINK ("Swap fore/back color:%s", 0x200+BUTTON_COLORPICKER) HELP_TEXT ("Magnifier mode") HELP_LINK (" Toggle: %s", 0x100+BUTTON_MAGNIFIER) HELP_LINK (" Zoom factor menu: %s", 0x200+BUTTON_MAGNIFIER) HELP_LINK (" Zoom in: %s", SPECIAL_ZOOM_IN) HELP_LINK (" Zoom out: %s", SPECIAL_ZOOM_OUT) HELP_LINK (" 1:1 (off) %s", SPECIAL_ZOOM_1) HELP_LINK (" 2:1 %s", SPECIAL_ZOOM_2) HELP_LINK (" 3:1 %s", SPECIAL_ZOOM_3) HELP_LINK (" 4:1 %s", SPECIAL_ZOOM_4) HELP_LINK (" 5:1 %s", SPECIAL_ZOOM_5) HELP_LINK (" 6:1 %s", SPECIAL_ZOOM_6) HELP_LINK (" 8:1 %s", SPECIAL_ZOOM_8) HELP_LINK (" 10:1 %s", SPECIAL_ZOOM_10) HELP_LINK (" 12:1 %s", SPECIAL_ZOOM_12) HELP_LINK (" 14:1 %s", SPECIAL_ZOOM_14) HELP_LINK (" 16:1 %s", SPECIAL_ZOOM_16) HELP_LINK (" 18:1 %s", SPECIAL_ZOOM_18) HELP_LINK (" 20:1 %s", SPECIAL_ZOOM_20) HELP_LINK ("Brush effects menu: %s", 0x100+BUTTON_BRUSH_EFFECTS) HELP_LINK ("Brush factory: %s", 0x200+BUTTON_BRUSH_EFFECTS) HELP_LINK ("Repeat last script: %s", SPECIAL_REPEAT_SCRIPT) HELP_LINK ("Run script #1: %s", SPECIAL_RUN_SCRIPT_1) HELP_LINK ("Run script #2: %s", SPECIAL_RUN_SCRIPT_2) HELP_LINK ("Run script #3: %s", SPECIAL_RUN_SCRIPT_3) HELP_LINK ("Run script #4: %s", SPECIAL_RUN_SCRIPT_4) HELP_LINK ("Run script #5: %s", SPECIAL_RUN_SCRIPT_5) HELP_LINK ("Run script #6: %s", SPECIAL_RUN_SCRIPT_6) HELP_LINK ("Run script #7: %s", SPECIAL_RUN_SCRIPT_7) HELP_LINK ("Run script #8: %s", SPECIAL_RUN_SCRIPT_8) HELP_LINK ("Run script #9: %s", SPECIAL_RUN_SCRIPT_9) HELP_LINK ("Run script #10: %s", SPECIAL_RUN_SCRIPT_10) HELP_LINK ("Text: %s", 0x100+BUTTON_TEXT) HELP_LINK ("Resolution menu: %s", 0x100+BUTTON_RESOL) HELP_LINK ("Safety resolution: %s", 0x200+BUTTON_RESOL) HELP_LINK ("Help: %s", 0x100+BUTTON_HELP) HELP_LINK ("Statistics: %s", 0x200+BUTTON_HELP) HELP_LINK ("Go to spare page: %s", 0x100+BUTTON_PAGE) HELP_LINK ("Copy to spare page: %s", 0x200+BUTTON_PAGE) HELP_LINK ("Save as: %s", 0x100+BUTTON_SAVE) HELP_LINK ("Save: %s", 0x200+BUTTON_SAVE) HELP_LINK ("Load: %s", 0x100+BUTTON_LOAD) HELP_LINK ("Re-load: %s", 0x200+BUTTON_LOAD) HELP_LINK ("Save brush: %s", SPECIAL_SAVE_BRUSH) HELP_LINK ("Load brush: %s", SPECIAL_LOAD_BRUSH) HELP_LINK ("Larger brush size: %s", SPECIAL_BIGGER_PAINTBRUSH) HELP_LINK ("Smaller brush size: %s", SPECIAL_SMALLER_PAINTBRUSH) HELP_LINK ("Settings: %s", 0x100+BUTTON_SETTINGS) HELP_LINK ("Undo: %s", 0x100+BUTTON_UNDO) HELP_LINK ("Redo: %s", 0x200+BUTTON_UNDO) HELP_LINK ("Kill page: %s", 0x100+BUTTON_KILL) HELP_LINK ("Clear: %s", 0x100+BUTTON_CLEAR) HELP_LINK ("Clear with BG color: %s", 0x200+BUTTON_CLEAR) HELP_LINK ("Quit: %s", 0x100+BUTTON_QUIT) HELP_LINK ("Palette menu: %s", 0x100+BUTTON_PALETTE) HELP_LINK ("2nd Palette menu: %s", 0x200+BUTTON_PALETTE) HELP_LINK ("Exclude colors menu: %s", SPECIAL_EXCLUDE_COLORS_MENU) HELP_TEXT ("") HELP_TEXT ("Scroll palette") HELP_LINK (" Back: %s", 0x100+BUTTON_PAL_LEFT) HELP_LINK (" Forward: %s", 0x100+BUTTON_PAL_RIGHT) HELP_LINK (" Back faster: %s", 0x200+BUTTON_PAL_LEFT) HELP_LINK (" Forward faster: %s", 0x200+BUTTON_PAL_RIGHT) HELP_TEXT ("") HELP_TEXT ("Change brush attachement") HELP_LINK (" Center : %s", SPECIAL_CENTER_ATTACHMENT) HELP_LINK (" Top-left : %s", SPECIAL_TOP_LEFT_ATTACHMENT) HELP_LINK (" Top-right : %s", SPECIAL_TOP_RIGHT_ATTACHMENT) HELP_LINK (" Bottom-left : %s", SPECIAL_BOTTOM_LEFT_ATTACHMENT) HELP_LINK (" Bottom-right: %s", SPECIAL_BOTTOM_RIGHT_ATTACHMENT) HELP_TEXT ("") HELP_TEXT ("Select foreground color") HELP_TEXT ("") HELP_LINK (" Next : %s", SPECIAL_NEXT_FORECOLOR) HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_FORECOLOR) HELP_TEXT ("") HELP_TEXT ("Select background color") HELP_LINK (" Next : %s", SPECIAL_NEXT_BACKCOLOR) HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_BACKCOLOR) HELP_TEXT ("") HELP_TEXT ("Select user-defined foreground color") HELP_TEXT ("") HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_FORECOLOR) HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_FORECOLOR) HELP_TEXT ("") HELP_TEXT ("Select user-defined background color") HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_BACKCOLOR) HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_BACKCOLOR) HELP_TEXT ("") HELP_TEXT ("LAYERS") HELP_TEXT ("") HELP_LINK (" Menu : %s", 0x100+BUTTON_LAYER_MENU) HELP_LINK (" Add new : %s", 0x100+BUTTON_LAYER_ADD) HELP_LINK (" Delete : %s", 0x100+BUTTON_LAYER_REMOVE) HELP_LINK (" Merge : %s", 0x100+BUTTON_LAYER_MERGE) HELP_LINK (" Move up : %s", 0x100+BUTTON_LAYER_UP) HELP_LINK (" Move down : %s", 0x100+BUTTON_LAYER_DOWN) //HELP_LINK (" Set transp: %s", 0x100+BUTTON_LAYER_COLOR) HELP_TEXT (" Select :") HELP_LINK (" 1 : %s", SPECIAL_LAYER1_SELECT) HELP_LINK (" 2 : %s", SPECIAL_LAYER2_SELECT) HELP_LINK (" 3 : %s", SPECIAL_LAYER3_SELECT) HELP_LINK (" 4 : %s", SPECIAL_LAYER4_SELECT) HELP_LINK (" 5 : %s", SPECIAL_LAYER5_SELECT) HELP_LINK (" 6 : %s", SPECIAL_LAYER6_SELECT) HELP_LINK (" 7 : %s", SPECIAL_LAYER7_SELECT) HELP_LINK (" 8 : %s", SPECIAL_LAYER8_SELECT) HELP_TEXT (" Toggle :") HELP_LINK (" 1 : %s", SPECIAL_LAYER1_TOGGLE) HELP_LINK (" 2 : %s", SPECIAL_LAYER2_TOGGLE) HELP_LINK (" 3 : %s", SPECIAL_LAYER3_TOGGLE) HELP_LINK (" 4 : %s", SPECIAL_LAYER4_TOGGLE) HELP_LINK (" 5 : %s", SPECIAL_LAYER5_TOGGLE) HELP_LINK (" 6 : %s", SPECIAL_LAYER6_TOGGLE) HELP_LINK (" 7 : %s", SPECIAL_LAYER7_TOGGLE) HELP_LINK (" 8 : %s", SPECIAL_LAYER8_TOGGLE) }; static const T_Help_table helptable_credits[] = { //HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") HELP_TITLE(" GRAFX2 IS CREATED BY") HELP_TEXT ("") HELP_BOLD (" THE GRAFX2 PROJECT TEAM") HELP_TEXT ("") HELP_TEXT (" Adrien Destugues (pulkomandy)") HELP_TEXT (" Yves Rizoud (yrizoud)") HELP_TEXT ("") HELP_TEXT (" Got the source back to life in 2006") HELP_TEXT ("") HELP_BOLD (" SUNSET DESIGN") HELP_BOLD (" AUTHORS OF GRAFX2.0 BETA 96.5%") HELP_TEXT ("") HELP_TEXT (" Guillaume Dorme alias \"Robinson\" (code)") HELP_TEXT (" Karl Maritaud alias \"X-Man\" (code&gfx)") //HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") HELP_TEXT ("") HELP_TEXT (" Re-licensed GrafX2 under the GPL in 2001") HELP_TEXT (" Huge thanks to them for their work !") HELP_TEXT ("") HELP_BOLD (" OTHER CODE CONTRIBUTORS") HELP_TEXT ("") HELP_TEXT (" Karl Bartel") HELP_TEXT (" SFont: bitmap fonts rendering") HELP_TEXT ("") HELP_TEXT (" Petter Lindquist") HELP_TEXT (" C64 file and image formats") HELP_TEXT ("") HELP_TEXT (" Pasi Kallinen") HELP_TEXT (" Better command-line handling") HELP_TEXT ("") HELP_TEXT (" DawnBringer") HELP_TEXT (" Lua scripts, image effects") HELP_TEXT ("") HELP_TEXT (" Nitrofurano") HELP_TEXT (" Lua scripts") HELP_TEXT ("") HELP_TITLE(" ART") HELP_TEXT ("") HELP_TEXT (" Made (www.m4de.com)") HELP_TEXT (" Logo (classic)") HELP_TEXT ("") HELP_TEXT (" X-Man") HELP_TEXT (" Buttons and fonts (classic)") HELP_TEXT ("") HELP_TEXT (" iLKke (ilkke.blogspot.com)") HELP_TEXT (" Buttons and logo (modern, scenish)") HELP_TEXT (" Several fonts") HELP_TEXT ("") HELP_TEXT (" Jamon") HELP_TEXT (" Buttons, logo and font (DPaint tribute)") HELP_TEXT ("") HELP_TEXT (" Hatch") HELP_TEXT (" Vectorized icon") HELP_TEXT ("") HELP_TEXT (" ...Pixelled all the graphics") HELP_TEXT ("") HELP_TITLE(" OTHER MACHINES PORTS") HELP_TEXT ("") HELP_BOLD (" AMIGA OS 3 PORT") HELP_TEXT ("") HELP_TEXT (" Artur Jarosik") HELP_TEXT ("") HELP_BOLD (" AMIGA OS 4 PORT") HELP_TEXT ("") HELP_TEXT (" Peter Gordon (www.petergordon.org.uk)") HELP_TEXT ("") HELP_BOLD (" AROS PORT") HELP_TEXT ("") HELP_TEXT (" Fernando Mastandrea (masta.uy)") HELP_TEXT (" Markus Weiss") HELP_TEXT ("") HELP_BOLD (" FREEBSD PORT") HELP_TEXT ("") HELP_TEXT (" Jean-Baptiste Berlioz (Tobe)") HELP_TEXT ("") HELP_BOLD (" HAIKU OS AND BEOS PORT") HELP_TEXT ("") HELP_TEXT (" Luc Schrijvers (Begasus)") HELP_TEXT ("") HELP_BOLD (" LINUX BINARIES") HELP_TEXT ("") HELP_TEXT (" Gentoo : Matteo 'Peach' Pescarin") HELP_TEXT (" Debian : Grkan Sengn") HELP_TEXT ("") HELP_BOLD (" MAC OS X PORT") HELP_TEXT ("") HELP_TEXT (" Franck Charlet (hitchhikr)") HELP_TEXT (" Per Olofsson (MagerValp)") HELP_TEXT ("") HELP_BOLD (" MORPHOS PORT") HELP_TEXT ("") HELP_TEXT (" Rusback") HELP_TEXT (" OffseT") HELP_TEXT ("") HELP_BOLD (" NETBSD PORT") HELP_TEXT ("") HELP_TEXT (" Jeff Read") HELP_TEXT ("") HELP_BOLD (" SKYOS PORT") HELP_TEXT ("") HELP_TEXT (" Luc Schrijvers (Begasus)") HELP_TEXT ("") HELP_BOLD (" WIZ & CAANOO PORT") HELP_TEXT ("") HELP_TEXT (" Alexander Filyanov (PheeL)") HELP_TEXT ("") HELP_BOLD (" ATARI PORT") HELP_TEXT ("") HELP_TEXT (" Pawel Goralski (Saulot)") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT (" ... made it work on your favourite toaster") HELP_TEXT ("") HELP_TITLE(" BUGFINDERS") HELP_TEXT ("") //HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") HELP_TEXT (" anibiqme blumunkee BDCIron ") HELP_TEXT (" Ced DarkDefende DawnBringer ") HELP_TEXT (" El Topo falenblood fanickbux ") HELP_TEXT (" fano fogbot121 Frost ") HELP_TEXT (" Grimmy Grkan Sengn Hatch ") HELP_TEXT (" HoraK-FDF iLKke Iw2evk ") HELP_TEXT (" jackfrost128 Jamon keito ") HELP_TEXT (" kusma Lord Graga Lorenzo Gatti ") HELP_TEXT (" MagerValp maymunbeyin mind ") HELP_TEXT (" MooZ Pasi Kallinen the Peach ") HELP_TEXT (" petter PheeL Ravey1138 ") HELP_TEXT (" richienyhus sm4tik spratek ") HELP_TEXT (" Surt tape.yrm TeeEmCee ") HELP_TEXT (" tempest Timo Kurrpa titus^Rab ") HELP_TEXT (" Tob yakumo2975 00ai99") HELP_TEXT ("") HELP_TEXT (" ... posted the annoying bug reports.") HELP_TEXT ("") HELP_TITLE(" FILE FORMATS CREDITS") HELP_TEXT ("") HELP_TEXT (" BMP : Microsoft") HELP_TEXT (" CEL,KCF : K.O.S. (KISekae Set system)") HELP_TEXT (" GIF : Compuserve") HELP_TEXT (" IMG : Bivas (W. Wiedmann?)") HELP_TEXT (" LBM : Electronic Arts") HELP_TEXT (" PAL : ermmh... nobody (?)") HELP_TEXT (" PCX : Z-Soft") HELP_TEXT (" PI1,PC1 : Degas Elite") HELP_TEXT (" PKM : Sunset Design") HELP_TEXT (" PNG : W3C") HELP_TEXT (" SCx : Colorix (?)") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE(" OUR HOMEPAGE") HELP_TEXT ("") HELP_BOLD (" http://grafx2.googlecode.com") HELP_TEXT ("") HELP_TEXT (" Please report any bug you may find there") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE(" GREETINGS") HELP_TEXT ("") HELP_BOLD ("Pulkomandy:") HELP_TEXT ("") HELP_TEXT (" To the Pouet.net BBS posters, the #CPC") HELP_TEXT (" trolls and the bitfellas") HELP_TEXT (" To every people who makes the scene alive!") HELP_TEXT (" To all guys making nice pixelled pictures") HELP_TEXT (" (with or without GrafX2)") HELP_TEXT ("") HELP_BOLD ("Sunset Designs:") HELP_TEXT ("") HELP_TEXT (" We send our best regards to...") HELP_TEXT ("") HELP_TEXT (" Access Filter Pink") HELP_TEXT (" Ace Fiver Pixel") HELP_TEXT (" AcidJam Flan Profil") HELP_TEXT (" Acryl Fred Prowler") HELP_TEXT (" Alexel FreddyV Puznik") HELP_TEXT (" Alias Frost Quick") HELP_TEXT (" Amiral Gal(GDC) Ra") HELP_TEXT (" Arrakis GainX Raster") HELP_TEXT (" Avocado Gandalf Ravian") HELP_TEXT (" Baloo Goblin RedBug") HELP_TEXT (" Barti Greenpix7 Rem") HELP_TEXT (" Bat Grid Rez") HELP_TEXT (" Biro GrosQuick Roudoudou") HELP_TEXT (" Bisounours HackerCroll Sacrilege") HELP_TEXT (" BlackAxe Haplo Sam") HELP_TEXT (" Bonnie Hof SandMan") HELP_TEXT (" Boo Hornet Scape") HELP_TEXT (" Boz Hulud Sbastien") HELP_TEXT (" Carine Java Shodan") HELP_TEXT (" Chandra JBT Skal") HELP_TEXT (" Cheetah Jrme Skyfire") HELP_TEXT (" Chill Julien(JCA) Sphair") HELP_TEXT (" Cougar KalMinDo Sprocket") HELP_TEXT (" Cremax KaneWood Stef") HELP_TEXT (" Cyclone Karma Stony") HELP_TEXT (" Dake Keith303 Sumaleth") HELP_TEXT (" Danny Lazur Sunday") HELP_TEXT (" Danube LightShow Suny") HELP_TEXT (" Darjul Lluvia Sybaris") HELP_TEXT (" Darwin Louie TBF") HELP_TEXT (" DarkAngel Luk Tempest") HELP_TEXT (" Das Made Thor") HELP_TEXT (" Decker Mamos TMK") HELP_TEXT (" DerPiipo Mandrixx TwoFace") HELP_TEXT (" Destop Mangue Underking") HELP_TEXT (" Diabolo Mars Unreal") HELP_TEXT (" DineS Mephisto VaeVictis") HELP_TEXT (" Drac Mercure Vastator") HELP_TEXT (" DrYes Mirec Vatin") HELP_TEXT (" Edyx Moa Veckman") HELP_TEXT (" Eller Moxica Wain") HELP_TEXT (" Ellyn MRK Wally") HELP_TEXT (" EOF Nitch WillBe") HELP_TEXT (" Fall Noal Xoomie") HELP_TEXT (" Fame Nytrik Xtrm") HELP_TEXT (" Fantom Optic YannSulu") HELP_TEXT (" Fear Orome Z") HELP_TEXT (" Feather Pahladin Zeb") HELP_TEXT (" Fennec Phar Zebig") HELP_TEXT ("") HELP_TEXT (" and all #pixel, #demofr and #coders.") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT (" Some information taken from several docs") HELP_TEXT (" (PCGPE, Intervue, PC Interdit...)") HELP_TEXT (" gave us an invaluable help.") HELP_TEXT ("") HELP_TEXT (" Thanks to Shawn Hargreaves for his filled") HELP_TEXT (" polygon routine from Allegro v2.2.") HELP_TEXT ("") HELP_TEXT (" Thanks to Carlos \"Made\" Pardo for his") HELP_TEXT (" great GrafX2 logo.") HELP_TEXT ("") HELP_TEXT (" This is our very first program compiled") HELP_TEXT (" with the Gnu C Compiler.") HELP_TEXT (" A thousand thanks to the authors of") HELP_TEXT (" this compiler.") HELP_TEXT ("") HELP_TEXT (" We also would like to thank all the") HELP_TEXT (" people who gave us ideas to improve") HELP_TEXT (" GrafX2.") HELP_TEXT ("") HELP_TITLE (" SNAIL MAIL") HELP_TEXT ("") //HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") HELP_TEXT (" ADRIEN DESTUGUES (PulkoMandy)") HELP_TEXT (" 3, rue Lapouble") HELP_TEXT (" 64000 PAU") HELP_TEXT (" (Send emails! Welcome in 21th century!)") HELP_TEXT ("") HELP_TEXT (" GUILLAUME DORME (Robinson)") HELP_TEXT (" 15, rue de l'observatoire") HELP_TEXT (" 87000 LIMOGES (FRANCE)") HELP_TEXT (" (May take some years to get an answer)") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT (" KARL MARITAUD (X-Man)") HELP_TEXT (" 10, rue de la Brasserie") HELP_TEXT (" 87000 LIMOGES (FRANCE)") HELP_TEXT (" (From 2001, current status: unknown)") HELP_TEXT ("") HELP_TEXT ("") }; static const T_Help_table helptable_paintbrush[] = { HELP_TITLE("PAINTBRUSHES") HELP_TEXT ("") HELP_BOLD (" LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_PAINTBRUSHES) HELP_TEXT ("") HELP_TEXT ("Displays a menu where you can choose the") HELP_TEXT ("shape of your paintbrush.") HELP_TEXT ("") HELP_TEXT ("Paintbrushes are sorted by family. You can") HELP_TEXT ("see some paintbrushes of the same family but") HELP_TEXT ("with different sizes. There is at least one") HELP_TEXT ("paint-brush from each family displayed in") HELP_TEXT ("this menu.") HELP_TEXT ("Here is the list of all the different") HELP_TEXT ("paintbrush families:") HELP_TEXT ("") HELP_TEXT ("******* *** * * * * * * ") HELP_TEXT ("******* ***** * * * * * * ") HELP_TEXT ("******* ******* * * * * * * * * ") HELP_TEXT ("******* ******* * * * * * * ") HELP_TEXT ("******* ******* * * * * * * * * ") HELP_TEXT ("******* ***** * * * * * * ") HELP_TEXT ("******* *** * * * * * * ") HELP_TEXT ("") HELP_TEXT ("Square Disc Sieve Sieve ") HELP_TEXT (" square disc ") HELP_TEXT (" ") HELP_TEXT (" * * * ") HELP_TEXT (" *** * * * ") HELP_TEXT (" ***** * * ") HELP_TEXT ("******* ******* * ") HELP_TEXT (" ***** * * * * ") HELP_TEXT (" *** * ") HELP_TEXT (" * * * * ") HELP_TEXT (" ") HELP_TEXT ("Diamond Random Horiz. Vertical") HELP_TEXT (" bar bar ") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT (" * * * * *") HELP_TEXT (" * * * * *") HELP_TEXT (" * * * * *") HELP_TEXT (" * * * *******") HELP_TEXT (" * * * * *") HELP_TEXT (" * * * * *") HELP_TEXT ("* * * * *") HELP_TEXT ("") HELP_TEXT (" Slash Back- Cross X Cross +") HELP_TEXT (" slash") HELP_TEXT ("") HELP_TEXT ("When using one of these, you can change the") HELP_TEXT ("brush size by using the keys:") HELP_LINK ("Reduce : %s", SPECIAL_SMALLER_PAINTBRUSH) HELP_LINK ("Increase : %s", SPECIAL_BIGGER_PAINTBRUSH) HELP_TEXT ("") HELP_TEXT ("Other brushes are bitmaps, their size can't") HELP_TEXT ("be adjusted.") HELP_TEXT ("") HELP_TEXT ("Click with left mouse button to choose a ") HELP_TEXT ("paintbrush, and right mouse button to store") HELP_TEXT ("your current brush in the slot. If your") HELP_TEXT ("current brush is a grabbed brush, it will") HELP_TEXT ("store a monochrome version of it, maximum") HELP_TEXT ("15x15. (See below 'Brush container' to store") HELP_TEXT ("backups of a big brush)") HELP_TEXT ("The stored brushes are saved when you exit") HELP_TEXT ("the program.") HELP_TEXT ("") HELP_TEXT ("The 'Preset' button allows you to pick a") HELP_TEXT ("brush from any family. It's useful if you've") HELP_TEXT ("overwritten all normal slots with brushes") HELP_TEXT ("that you use more often.") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD ("BRUSH CONTAINER") HELP_TEXT ("") HELP_TEXT ("The bottom row, initially showing empty") HELP_TEXT ("buttons, is the brush container. You can") HELP_TEXT ("right-click a button to store the current") HELP_TEXT ("brush in it, and then whenever you need the") HELP_TEXT ("brush back, open this menu again and") HELP_TEXT ("left-click the button.") HELP_TEXT ("The container can memorize resizable brushes") HELP_TEXT ("as well as brushes grabbed from the image.") HELP_TEXT ("Brushes are lost when you exit the program.") HELP_TEXT ("") HELP_BOLD (" RIGHT CLICK ") HELP_LINK ("(Key:%s)",0x200+BUTTON_PAINTBRUSHES) HELP_TEXT ("") HELP_TEXT ("Transforms your current user-defined brush") HELP_TEXT ("into a paintbrush. This is actually a") HELP_TEXT ("\"monochromisation\" of your user-defined") HELP_TEXT ("brush. This means that every color of the") HELP_TEXT ("brush that aren't the Back-color will be") HELP_TEXT ("set to the Fore-color. But this option") HELP_TEXT ("doesn't alter the brush: you'll just have") HELP_TEXT ("to right-click on the \"Get brush\" buttons") HELP_TEXT ("to get your brush back.") HELP_TEXT ("") HELP_TEXT ("Note: When you press (not in the menu) the") HELP_LINK ("key %s, the current",SPECIAL_DOT_PAINTBRUSH) HELP_TEXT ("paintbrush becomes the smallest member of") HELP_TEXT ("the \"Disc\" family: i.e one pixel.") }; static const T_Help_table helptable_adjust[] = { HELP_TITLE("ADJUST OR TRANSFORM") HELP_TITLE(" PICTURE") HELP_TEXT ("") HELP_BOLD (" LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_ADJUST) HELP_TEXT ("") HELP_TEXT ("Allows you to scroll the picture to") HELP_TEXT ("re-center your graph for example.") HELP_TEXT ("") HELP_TEXT ("Any part of the picture that goes out of") HELP_TEXT ("the image by a side comes back by the") HELP_TEXT ("opposite one.") HELP_TEXT ("") HELP_TEXT ("Left clicking the picture will scroll only") HELP_TEXT ("the active layer. Right-clicking will scroll") HELP_TEXT ("all of them.") HELP_TEXT ("") HELP_TEXT ("It is assimilated to the drawing tools") HELP_TEXT ("family.") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD (" RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_ADJUST) HELP_TEXT ("") HELP_TEXT ("Opens the Picture Transform menu.") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("PICTURE TRANSFORM") HELP_TEXT ("") HELP_BOLD ("RESCALE") HELP_TEXT ("") HELP_TEXT ("Allows you to change the image's size,") HELP_TEXT ("rescaling it accordingly. Enter new size") HELP_TEXT ("and press RESIZE to confirm.") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("When 'Lock proportions' is checked and you") HELP_TEXT ("change one dimension, the other one is") HELP_TEXT ("automatically adjusted to preserve the") HELP_TEXT ("proportions of the original image.") HELP_TEXT ("") HELP_TEXT ("You can use the dropdown button to choose") HELP_TEXT ("between three ways to enter the dimensions:") HELP_TEXT ("") HELP_TEXT ("In 'Pixels' mode, the column 'old' shows") HELP_TEXT ("the original dimensions, and you can set") HELP_TEXT ("the new size in pixels.") HELP_TEXT ("") HELP_TEXT ("In 'Percent' mode, you set a percentage") HELP_TEXT ("compared to the original image.") HELP_TEXT ("") HELP_TEXT ("In 'Ratio' mode, you can set 2 numbers for") HELP_TEXT ("each dimension, and the resizing factor will") HELP_TEXT ("be of 'new''old'. For example you can use") HELP_TEXT ("1:3 to divide the image by three, 2:1 to") HELP_TEXT ("double it, and any fraction like 15:16.") HELP_TEXT ("") HELP_TEXT ("Be careful that moving from one mode to the") HELP_TEXT ("next can lose precision, if the selected") HELP_TEXT ("dimensions cannot be represented exactly in") HELP_TEXT ("the new mode.") HELP_TEXT ("") HELP_BOLD ("MIRROR") HELP_TEXT ("") HELP_TEXT ("- X: Flip the picture horizontally.") HELP_TEXT ("") HELP_TEXT ("- Y: Flip the picture vertically.") HELP_TEXT ("") HELP_BOLD ("ROTATE") HELP_TEXT ("") HELP_TEXT ("-90: Rotates the image by 90") HELP_TEXT (" clockwise.") HELP_TEXT ("") HELP_TEXT ("+90: Rotates the image by 90") HELP_TEXT (" counter-clockwise.") HELP_TEXT ("180: Rotates the image by 180") HELP_TEXT ("") HELP_TEXT ("") }; static const T_Help_table helptable_draw[] = { HELP_TITLE("HAND-DRAWING") HELP_TEXT ("") HELP_BOLD (" LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_DRAW) HELP_TEXT ("") HELP_TEXT ("Selects the current hand-drawing mode as the") HELP_TEXT ("active drawing tool. There are 4") HELP_TEXT ("hand-drawing modes:") HELP_TEXT ("") HELP_TEXT ("Continuous hand-drawing: as you move the") HELP_TEXT ("mouse, the paintbrush is regularily pasted") HELP_TEXT ("on the picture. This drawing tool allows to") HELP_TEXT ("change the fore and back colors when being") HELP_TEXT ("in use.") HELP_TEXT ("") HELP_TEXT ("Discontinuous hand-drawing: as you move the") HELP_TEXT ("mouse, the paintbrush is pasted on the") HELP_TEXT ("picture every time a delay is passed") HELP_TEXT ("(actually, the delay is 1 VBL") HELP_TEXT ("(vertical blanking)). This drawing tool") HELP_TEXT ("allows to change the fore and back colors") HELP_TEXT ("when being in use.") HELP_TEXT ("") HELP_TEXT ("Dot by dot hand-drawing: the paintbrush is") HELP_TEXT ("only pasted at the position where you first") HELP_TEXT ("clicked.") HELP_TEXT ("") HELP_TEXT ("Contour fill: Draws pixels like continuous") HELP_TEXT ("mode, but when you release the button Grafx2") HELP_TEXT ("draws a line back to your starting position,") HELP_TEXT ("and fills the area. This tool doesn't use") HELP_TEXT ("the current brush, but single pixels.") HELP_TEXT ("") HELP_BOLD (" RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_DRAW) HELP_TEXT ("") HELP_TEXT ("Toggles the different hand-drawing modes") HELP_TEXT ("and activates, at the same time, the") HELP_TEXT ("hand-drawing tool.") }; static const T_Help_table helptable_curves[] = { HELP_TITLE("SPLINES") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_CURVES) HELP_TEXT ("") HELP_TEXT ("Selects the current curve-drawing mode as") HELP_TEXT ("the active drawing tool. There are 2") HELP_TEXT ("different curve-drawing modes:") HELP_TEXT ("") HELP_TEXT ("* 4 control points curves: define the basic") HELP_TEXT ("line like a classical line, then move, with") HELP_TEXT ("the left mouse button, the inner control") HELP_TEXT ("points to choose the shape of your curve.") HELP_TEXT ("When the curve has the shape you want, click") HELP_TEXT ("with the right mouse button to draw it") HELP_TEXT ("definitively.") HELP_TEXT ("") HELP_TEXT ("* 3 control points curves: the same as") HELP_TEXT ("above, but you'll have only one inner") HELP_TEXT ("control point to place. Moreover, the spline") HELP_TEXT ("will be traced just after placing this") HELP_TEXT ("point.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_CURVES) HELP_TEXT ("") HELP_TEXT ("Toggles the different curve-drawing modes") HELP_TEXT ("and activates, at the same time, the") HELP_TEXT ("curve-drawing tool.") }; static const T_Help_table helptable_lines[] = { HELP_TITLE("LINES") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_LINES) HELP_TEXT ("") HELP_TEXT ("Selects the current line-drawing mode as the") HELP_TEXT ("active drawing tool. There are 3") HELP_TEXT ("line-drawing modes:") HELP_TEXT ("") HELP_TEXT ("* Classical lines: when first clicking on") HELP_TEXT ("the picture, you'll define the start of the") HELP_TEXT ("line. Maintain your click to choose the end") HELP_TEXT ("of the line and release the mouse button to") HELP_TEXT ("set it.") HELP_TEXT ("If you hold SHIFT when drawing, the line") HELP_TEXT ("will be constrained to horizonal, vertical") HELP_TEXT ("or diagonal.") HELP_TEXT ("") HELP_TEXT ("* Knotted lines: works like classical lines,") HELP_TEXT ("but the end of your line will automatically") HELP_TEXT ("become the start of the next one. When you") HELP_TEXT ("want to stop chaining lines, use the") HELP_TEXT ("opposite mouse button. \"The opposite button\"") HELP_TEXT ("means that if you started to draw lignes") HELP_TEXT ("with the left button (Fore-color), you'll") HELP_TEXT ("have to stop the procedure with the right") HELP_TEXT ("button; and conversely.") HELP_TEXT ("") HELP_TEXT ("* Concentric lines: when first clicking on") HELP_TEXT ("the picture, you'll define center of the") HELP_TEXT ("lines. In fact, the center is defined by the") HELP_TEXT ("the position of the mouse when you release") HELP_TEXT ("the mouse button. Then you can draw lines") HELP_TEXT ("from the center to the current mouse") HELP_TEXT ("position by clicking. To stop drawing") HELP_TEXT ("concentric lines, use the opposite mouse") HELP_TEXT ("button. This drawing tool allows to change") HELP_TEXT ("the fore and back colors when being in use.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_LINES) HELP_TEXT ("") HELP_TEXT ("Toggles the different line-drawing modes and") HELP_TEXT ("activates, at the same time, the") HELP_TEXT ("line-drawing tool.") }; static const T_Help_table helptable_airbrush[] = { HELP_TITLE("SPRAY") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_AIRBRUSH) HELP_TEXT ("") HELP_TEXT ("Selects the spray as the active drawing") HELP_TEXT ("tool. This drawing tool allows to change the") HELP_TEXT ("fore and back colors when being in use.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_AIRBRUSH) HELP_TEXT ("") HELP_TEXT ("Displays a menu where you can configure the") HELP_TEXT ("spray:") HELP_TEXT ("") HELP_TEXT ("- Size: Defines the diameter of the circle") HELP_TEXT ("in which will effectively fit the spray.") HELP_TEXT ("") HELP_TEXT ("- Delay: Defines the number of VBLs that") HELP_TEXT ("will be waited for between two flows of") HELP_TEXT ("spray.") HELP_TEXT ("") HELP_TEXT ("- Mode: Defines whether you want to use a") HELP_TEXT ("monochrome spray or a multi- colored one.") HELP_TEXT ("") HELP_TEXT ("- Mono-flow: Defines the number of") HELP_TEXT ("paintbrushes that will be pasted in the") HELP_TEXT ("circle of the spray at each cycle.") HELP_TEXT ("") HELP_TEXT ("- Palette: Left-click on a color of the") HELP_TEXT ("palette to see how much it will be used in") HELP_TEXT ("the multicolored flow, and modify it by") HELP_TEXT ("using the gauge on the right. If the flow of") HELP_TEXT ("this color was equal to 0, then the \"Init\"") HELP_TEXT ("value will be applied. Or set the flow of a") HELP_TEXT ("color to 0 by clicking on it with the right") HELP_TEXT ("mouse button.") HELP_TEXT ("") HELP_TEXT ("- Clear: Removes all the colors from the") HELP_TEXT ("multicolored flow. Actually, this puts a 0") HELP_TEXT ("value in the use of each color.") HELP_TEXT ("") HELP_TEXT ("- Init: Allows you to define a value that") HELP_TEXT ("will be set to the color you click on in the") HELP_TEXT ("palette if its value is equal to 0. This") HELP_TEXT ("permits to tag a set of colors more quickly.") HELP_TEXT ("") HELP_TEXT ("- +1,-1,x2,/2: Modify the values of all the") HELP_TEXT ("tagged colors (and only them).") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("Tip: If you often use the Shade mode, and") HELP_TEXT ("are bored to click many times on a color to") HELP_TEXT ("reach the color you want, you can define a") HELP_TEXT ("spray with \"Size\"=1, \"Mono-flow\"=1, and") HELP_TEXT ("\"Delay\"=2 (or more, according to your") HELP_TEXT ("reflexes). And then, you'll just have to") HELP_TEXT ("click a few hundredths of second to modify a") HELP_TEXT ("color.") }; static const T_Help_table helptable_floodfill[] = { HELP_TITLE("FLOODFILL") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_FLOODFILL) HELP_TEXT ("") HELP_TEXT ("Selects the filler as the active drawing") HELP_TEXT ("tool. The filler, as any drawing tool, will") HELP_TEXT ("be affected by all the effects!") HELP_TEXT ("") HELP_TEXT ("Note that only the visible part of the") HELP_TEXT ("picture will be filled (as every other") HELP_TEXT ("drawing tools, the floodfill only alters the") HELP_TEXT ("visible part of the picture; this avoids") HELP_TEXT ("unwanted effects that wouldn't be controlled") HELP_TEXT ("by the user).") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_FLOODFILL) HELP_TEXT ("") HELP_TEXT ("Selects the color replacement as the active") HELP_TEXT ("drawing tool.") HELP_TEXT ("") HELP_TEXT ("Any rule has its exceptions and this one") HELP_TEXT ("doesn't depart from that. Indeed, this tool") HELP_TEXT ("is the only one to be affected by no effect") HELP_TEXT ("(except Stencil) and to be able to modify") HELP_TEXT ("non visible parts of the picture.") HELP_TEXT ("The function of this tool being replacing") HELP_TEXT ("all the occurences of a color in the picture") HELP_TEXT ("by another, if would have been a shame to") HELP_TEXT ("limit modifications only to the visible part") HELP_TEXT ("of the picture.") }; static const T_Help_table helptable_polygons[] = { HELP_TITLE("POLYGONS") HELP_TITLE("POLYFORMS") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_POLYGONS) HELP_TEXT ("") HELP_TEXT ("Selects the polygons as the active drawing") HELP_TEXT ("tool.") HELP_TEXT ("") HELP_TEXT ("This works just like knotted-lines but loops") HELP_TEXT ("the extremities when you're finished.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_POLYGONS) HELP_TEXT ("") HELP_TEXT ("Selects the polyforms as the active drawing") HELP_TEXT ("tool.") HELP_TEXT ("") HELP_TEXT ("This works like a combination of free-hand") HELP_TEXT ("drawing and knotted-lines. If you keep the") HELP_TEXT ("mouse button pressed, you'll draw as if you") HELP_TEXT ("were in free-hand drawing mode. And, if you") HELP_TEXT ("release the mouse button, it will work like") HELP_TEXT ("knotted lines.") HELP_TEXT ("") HELP_TEXT ("Click on the opposite mouse button (i.e.:") HELP_TEXT ("click right if you started to draw with the") HELP_TEXT ("left mouse button, and vice versa) to") HELP_TEXT ("terminate the operation. The two extremities") HELP_TEXT ("will be linked automatically.") }; static const T_Help_table helptable_polyfill[] = { HELP_TITLE("FILLED POLY") HELP_LINK ("(Key:%s)",0x100+BUTTON_POLYFILL) HELP_LINK ("(Key:%s)",0x200+BUTTON_POLYFILL) HELP_TEXT (" Work exactly the same way as the polygons") HELP_TEXT ("et polyforms above, but fill in the interior") HELP_TEXT ("of the drawn shapes.") }; static const T_Help_table helptable_rectangles[] = { HELP_TITLE("RECTANGLES") HELP_LINK ("(Key:%s)",0x100+BUTTON_RECTANGLES) HELP_TEXT ("") HELP_TEXT ("Selects the empty rectangles as the active") HELP_TEXT ("drawing tool.") HELP_TEXT ("") HELP_TEXT ("Set a corner of a rectangle. Maintain the") HELP_TEXT ("click to move the opposite corner and") HELP_TEXT ("release the mouse button to set it") HELP_TEXT ("definitively.") }; static const T_Help_table helptable_filled_rectangles[] = { HELP_TITLE("FILLED RECT") HELP_LINK ("(Key:%s)",0x100+BUTTON_FILLRECT) HELP_TEXT ("") HELP_TEXT ("Selects the filled rectangles as the active") HELP_TEXT ("drawing tool.") HELP_TEXT ("") HELP_TEXT ("Works like an empty rectangle.") }; static const T_Help_table helptable_circles[] = { HELP_TITLE("CIRCLES") HELP_TITLE("ELLIPSES") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_CIRCLES) HELP_TEXT ("") HELP_TEXT ("Selects the empty circles as the active") HELP_TEXT ("drawing tool.") HELP_TEXT ("") HELP_TEXT ("Position the center of the cercle and") HELP_TEXT ("maintain the mouse button to select its") HELP_TEXT ("radius.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_CIRCLES) HELP_TEXT ("") HELP_TEXT ("Selects the empty ellipses as the active") HELP_TEXT ("drawing tool.") HELP_TEXT ("") HELP_TEXT ("Position the center of the cercle and") HELP_TEXT ("maintain the mouse button to select its") HELP_TEXT ("dimensions.") }; static const T_Help_table helptable_filled_circles[] = { HELP_TITLE("FILLED CIRCLES") HELP_TITLE(" AND ELLIPSES") HELP_TEXT ("") HELP_BOLD ("FILLED CIRCLES") HELP_LINK ("(Key:%s)",0x100+BUTTON_FILLCIRC) HELP_TEXT ("") HELP_TEXT ("Works like empty circles.") HELP_TEXT ("") HELP_BOLD ("FILLED ELLIPSES") HELP_LINK ("(Key:%s)",0x200+BUTTON_FILLCIRC) HELP_TEXT ("") HELP_TEXT ("Works like empty ellipses.") }; static const T_Help_table helptable_grad_rect[] = { HELP_TITLE("GRAD RECTANGLE") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_GRADRECT) HELP_TEXT ("") HELP_TEXT ("Selects the rectangle with gradations as") HELP_TEXT ("the active drawing tool.") HELP_TEXT ("") HELP_TEXT ("Set a corner of a rectangle. Maintain the") HELP_TEXT ("click to move the opposite corner and") HELP_TEXT ("release the mouse button to set it") HELP_TEXT ("definitively.") HELP_TEXT ("") HELP_TEXT ("If you don't like what you have done and") HELP_TEXT ("want to restart, you can use the right") HELP_TEXT ("click to cancel everything at this point.") HELP_TEXT (" If you think it's nice, then click and hold") HELP_TEXT ("the mouse in a point you want to have the") HELP_TEXT ("starting color, drag to a point where you") HELP_TEXT ("want the ending color, and release the") HELP_TEXT ("button. You can press SHIFT to enforce your") HELP_TEXT ("line to be vertical, horizontal, or") HELP_TEXT ("diagonal.") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_GRADRECT) HELP_TEXT ("") HELP_TEXT ("Opens a window where you can define the way") HELP_TEXT ("gradations are processed. The different") HELP_TEXT ("sections of this menu are:") HELP_TEXT ("") HELP_TEXT ("- Direction (arrow): Switches the direction") HELP_TEXT ("of the gradation.") HELP_TEXT ("") HELP_TEXT ("- Dithering method: Toggles the 3 following") HELP_TEXT ("methods:") HELP_TEXT (" - No dithering") HELP_TEXT (" - Basical dithering") HELP_TEXT (" - Enhanced dithering") HELP_TEXT ("") HELP_TEXT ("- Mix: Mixes the gradation with a more or") HELP_TEXT ("less random factor.") HELP_TEXT ("") HELP_TEXT ("- Palette: Select a color range to build a") HELP_TEXT ("gradation.") HELP_TEXT ("") HELP_TEXT ("- Index scroller: Defines the current") HELP_TEXT ("gradation among a set of 16 that will be") HELP_TEXT ("memorised.") HELP_TEXT ("") HELP_BOLD ("COLOR CYCLING") HELP_TEXT ("") HELP_TEXT ("These options allow you to use animation of") HELP_TEXT ("colors: Grafx2 will shift palette entries") HELP_TEXT ("at real-time. Note that only the LBM file") HELP_TEXT ("format can record these settings, and very") HELP_TEXT ("few image viewers will play it back.") HELP_TEXT ("") HELP_TEXT ("- Cycling: Activates or desactivates the") HELP_TEXT ("cycling of colors when you're in the editor.") HELP_LINK ("Key: %s", SPECIAL_CYCLE_MODE) HELP_TEXT ("") HELP_TEXT ("- Speed: Sets the speed for the cycling of") HELP_TEXT ("this range. Zero means this range doesn't") HELP_TEXT ("cycle. With 1, the range shifts 0.2856 times") HELP_TEXT ("per second; at speed 64 it's 18.28 times") HELP_TEXT ("per second. The program activates cycling") HELP_TEXT ("while you hold the speed slider, so you can") HELP_TEXT ("preview the speed.") HELP_TEXT ("") }; static const T_Help_table helptable_spheres[] = { HELP_TITLE("GRAD SPHERE") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_SPHERES) HELP_TEXT ("") HELP_TEXT ("Selects the spheres as the active drawing") HELP_TEXT ("tool.") HELP_TEXT ("") HELP_TEXT ("Position the center of the sphere and") HELP_TEXT ("maintain the mouse button to select its") HELP_TEXT ("radius. Then place the spot-light.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_SPHERES) HELP_TEXT ("") HELP_TEXT ("Selects the ellipses with gradation as the") HELP_TEXT ("active drawing tool.") HELP_TEXT ("") HELP_TEXT ("Draw the shape like a normal ellipse, and") HELP_TEXT ("then position the spot-light and click the") HELP_TEXT ("left mouse button to finish the shape.") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("If you trace a sphere or an ellipse with") HELP_TEXT ("gradation with the right mouse button, the") HELP_TEXT ("result will be the same figure filled with") HELP_TEXT ("the Back-color.") }; static const T_Help_table helptable_brush[] = { HELP_TITLE("GRAB BRUSH") HELP_BOLD (" OR RESTORE BRUSH") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_BRUSH) HELP_TEXT ("") HELP_TEXT ("Engages a brush grabbing.") HELP_TEXT ("") HELP_TEXT ("Click on a corner of the rectangle") HELP_TEXT ("containing the brush then maintain the click") HELP_TEXT ("to define the opposite corner of the") HELP_TEXT ("rectangle. Release the mouse button to grab") HELP_TEXT ("the brush. Performing this operation with") HELP_TEXT ("the right mouse button will erase the area") HELP_TEXT ("where the brush was grabbed with the") HELP_TEXT ("Back-color.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_BRUSH) HELP_TEXT ("") HELP_TEXT ("Restores the old brush.") }; static const T_Help_table helptable_polybrush[] = { HELP_TITLE("POLY GRAB") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_POLYBRUSH) HELP_TEXT ("") HELP_TEXT ("Grabs a brush of any shape by defining a") HELP_TEXT ("polyform (please refer to section 8 for more") HELP_TEXT ("explanations).") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_BRUSH) HELP_TEXT ("") HELP_TEXT ("Restores the old brush (same as above).") }; static const T_Help_table helptable_brush_fx[] = { HELP_TITLE("BRUSH FX") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_BRUSH_EFFECTS) HELP_TEXT ("") HELP_TEXT ("Displays a menu where the following options") HELP_TEXT ("are available:") HELP_TEXT ("") HELP_LINK ("- X: (Key:%s)",SPECIAL_FLIP_X) HELP_TEXT ("Flip horizontally.") HELP_TEXT ("") HELP_LINK ("- Y: (Key:%s)",SPECIAL_FLIP_Y) HELP_TEXT ("Flip vertically.") HELP_TEXT ("") HELP_LINK ("- Rotate by 90: (Key:%s)",SPECIAL_ROTATE_90) HELP_TEXT ("Rotates the brush by an angle of 90 degrees.") HELP_TEXT ("") HELP_LINK ("- Rotate by 180: (Key:%s)",SPECIAL_ROTATE_180) HELP_TEXT ("Rotates the brush by an angle of 180") HELP_TEXT ("degrees.") HELP_TEXT ("") HELP_TEXT ("- Rotate by any angle:") HELP_LINK ("(Key:%s)",SPECIAL_ROTATE_ANY_ANGLE) HELP_TEXT ("Triggers an interactive operation that") HELP_TEXT ("allows you to rotate the brush. For this,") HELP_TEXT ("start by placing the center or rotation with") HELP_TEXT ("the left mouse button (if, at this moment,") HELP_TEXT ("you press the right button, the operation") HELP_TEXT ("with be cancelled). After that, you can") HELP_TEXT ("define the angle of rotation as many times") HELP_TEXT ("as you want by moving the mouse and") HELP_TEXT ("left-clicking. Then validate with the right") HELP_TEXT ("button when you are satisfied. Meanwhile,") HELP_TEXT ("you can press on the 8 outer digits of the") HELP_TEXT ("numeric pad for defining angles multiple of") HELP_TEXT ("45 degrees:") HELP_TEXT ("") HELP_TEXT (" 135 90 45") HELP_TEXT (" \\ | /") HELP_TEXT (" '7' '8' '9'") HELP_TEXT (" 180 -'4' '6'- 0") HELP_TEXT (" '1' '2' '3'") HELP_TEXT (" / | \\") HELP_TEXT (" 225 270 315") HELP_TEXT ("") HELP_LINK ("- Stretch: (Key:%s)",SPECIAL_STRETCH) HELP_TEXT ("Triggers an interactive operation") HELP_TEXT ("that enables you to stretch the brush. For") HELP_TEXT ("this, start by placing the upper-left") HELP_TEXT ("cornerof the brush with the left mouse") HELP_TEXT ("button (if, at this moment, you press the") HELP_TEXT ("right button, the operation will be") HELP_TEXT ("cancelled). after that, you can place the") HELP_TEXT ("opposite corner as many times as you need,") HELP_TEXT ("then validate with the right mouse button") HELP_TEXT ("when you are satisfied. If you place this") HELP_TEXT ("point at coordinates inferior to the ones of") HELP_TEXT ("the first point, the brush will be inverted.") HELP_TEXT ("Meanwhile, you can press the following keys") HELP_TEXT ("whose effects are:") HELP_TEXT (" 'D' : Double the brush") HELP_TEXT (" 'H' : Reduce the brush by half") HELP_TEXT (" 'X' : Double the brush in X") HELP_TEXT (" 'Shift+X': Reduce the brush by half in X") HELP_TEXT (" 'Y' : Double the brush in Y") HELP_TEXT (" 'Shift+Y': Reduce the brush by half in Y") HELP_TEXT (" 'N' : Restore the normal size of the") HELP_TEXT (" brush (can be useful because") HELP_TEXT (" it's the only way for") HELP_TEXT (" cancelling)") HELP_TEXT ("") HELP_LINK ("- Distort: (Key:%s)",SPECIAL_DISTORT) 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") HELP_TEXT ("outlines of the brush with the Fore- color.") HELP_TEXT ("") HELP_LINK ("- Nibble: (Key:%s)",SPECIAL_NIBBLE) HELP_TEXT ("This option \"nibbles\" the outlines") HELP_TEXT ("of the brush. It's in some way the opposite") HELP_TEXT ("effect of the Outline option.") HELP_TEXT ("") HELP_LINK ("- Recolorize: (Key:%s)",SPECIAL_RECOLORIZE_BRUSH) HELP_TEXT ("Remaps the brush so that it") HELP_TEXT ("looks like it would in the spare page, using") HELP_TEXT ("the current palette.") HELP_TEXT ("") HELP_LINK ("- Get brush colors: (Key:%s)",SPECIAL_GET_BRUSH_COLORS) HELP_TEXT ("Transfers the spare") HELP_TEXT ("page's colors used by the brush to the") HELP_TEXT ("current palette.") HELP_TEXT ("") HELP_TEXT ("- Brush handle:") HELP_TEXT ("Allows you to choose where to place the") HELP_TEXT ("handle of the brush. Shortcuts are :") HELP_LINK (" Center : %s", SPECIAL_CENTER_ATTACHMENT) HELP_LINK (" Top-left : %s", SPECIAL_TOP_LEFT_ATTACHMENT) HELP_LINK (" Top-right : %s", SPECIAL_TOP_RIGHT_ATTACHMENT) HELP_LINK (" Bottom-left : %s", SPECIAL_BOTTOM_LEFT_ATTACHMENT) HELP_LINK (" Bottom-right: %s", SPECIAL_BOTTOM_RIGHT_ATTACHMENT) HELP_TEXT ("") HELP_LINK ("- Load : (Key:%s)",SPECIAL_LOAD_BRUSH) HELP_TEXT ("Load a brush from disk.") HELP_TEXT ("") HELP_LINK ("- Save : (Key:%s)",SPECIAL_SAVE_BRUSH) HELP_TEXT ("Save a brush to disk.") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("BRUSH FACTORY") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x200+BUTTON_BRUSH_EFFECTS) HELP_TEXT ("") HELP_TEXT ("This menu allows you to run scripts. Scripts") HELP_TEXT ("are written in the Lua language, and allow") HELP_TEXT ("you to modify the brush (hence the name") HELP_TEXT ("'Brush factory'), or even modify the image") HELP_TEXT ("or palette, like a Photoshop filter. See") HELP_TEXT ("the online documentation for more help") HELP_TEXT ("on scripting.") HELP_TEXT ("") HELP_TEXT ("You can select a script with the selector,") HELP_TEXT ("the bottom panel shows a short description") HELP_TEXT ("of what it does, and you can click Run to") HELP_TEXT ("launch it.") HELP_TEXT ("") HELP_TEXT ("The scripts are located in the application's") HELP_TEXT ("data folder, under the '/scripts'") HELP_TEXT ("subdirectory. The list is refreshed each") HELP_TEXT ("time you open the window. Scripts are loaded") HELP_TEXT ("from disk when you run them.") HELP_TEXT ("") HELP_LINK ("- Repeat last script: %s", SPECIAL_REPEAT_SCRIPT) HELP_TEXT ("") }; static const T_Help_table helptable_effects[] = { HELP_TITLE("DRAW MODES") HELP_LINK ("(Key:%s)",0x100+BUTTON_EFFECTS) HELP_TEXT ("") HELP_TEXT (" This button opens a menu where you can") HELP_TEXT ("switch on or off the different drawing") HELP_TEXT ("modes.") HELP_TEXT (" In this menu, the \"All off\" button switches") HELP_TEXT ("all the drawing modes off. The [Del] key") HELP_TEXT ("is the keyboard shortcut for this button.") HELP_TEXT (" The \"Feedback\" button is only used in") HELP_TEXT ("\"Shade\", \"Quick-shade, \"Transparency\"") HELP_TEXT ("and \"Smooth\" modes. When it is set, it means") HELP_TEXT ("that the _current_ state of the picture") HELP_TEXT ("has to be taken into account for the effect") HELP_TEXT ("instead of the state in which the image") HELP_TEXT ("was when you started to click for drawing.") HELP_TEXT ("The best, as often, is that you try by") HELP_TEXT ("yourself with and without Feedback to see") HELP_TEXT ("the difference.") HELP_TEXT (" The other buttons are the following:") HELP_TEXT ("") HELP_TITLE("SHADE") HELP_TEXT (" It consists in increasing or decreasing the") HELP_TEXT ("color number within a user-defined range.") HELP_TEXT ("This shows its real dimension when used with") HELP_TEXT ("a range of colors that shade off. Then,") HELP_TEXT ("you can work on a part of your picture where") HELP_TEXT ("colors belong to the same range without") HELP_TEXT ("having to change your brush color all the") HELP_TEXT ("time. You can choose the incrementation or") HELP_TEXT ("decrementation of the color by pressing") HELP_TEXT ("the left or right mouse button while") HELP_TEXT ("drawing. If you click on a color that does") HELP_TEXT ("not belong to the range, it will remain") HELP_TEXT ("unchanged.") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key : %s)", SPECIAL_SHADE_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Shade mode.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_SHADE_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can define one table") HELP_TEXT ("of shades within a range of 8 memorised by") HELP_TEXT ("the program. The different sections of this") HELP_TEXT ("menu are:") HELP_TEXT ("") HELP_TEXT ("- Palette: You can define in it the color") HELP_TEXT ("blocks that will be inserted") HELP_TEXT ("into the table of shades.") HELP_TEXT ("") HELP_TEXT ("- Scroller: Used to change flick through the") HELP_TEXT ("tables of shades.") HELP_TEXT ("") HELP_TEXT ("- Table of shades definition area: The 512") HELP_TEXT ("squares should be widely") HELP_TEXT ("sufficient to define the different shades") HELP_TEXT ("since every 256 colors of") HELP_TEXT ("the palette cannot be present more than once") HELP_TEXT ("in each table.") HELP_TEXT ("") HELP_TEXT ("- A window (on the top-right side) permits") HELP_TEXT ("to visualize the different") HELP_TEXT ("shades defined in he current table.") HELP_TEXT ("") HELP_TEXT ("- Copy: Copy the contents of the table in a") HELP_TEXT ("buffer.") HELP_TEXT ("(Each time you open this menu, the current") HELP_TEXT ("table is automatically") HELP_TEXT ("transfered into this buffer).") HELP_TEXT ("") HELP_TEXT ("- Paste: Copy the contents of the buffer") HELP_TEXT ("above in the current table.") HELP_TEXT ("") HELP_TEXT ("- Clear: Reset the \"shades\" table.") HELP_TEXT ("") HELP_TEXT ("- Insert: Used to insert the block selected") HELP_TEXT ("in the palette at the") HELP_TEXT ("cursor's position in the table of shades.") HELP_TEXT ("IF you click with the left mouse button on") HELP_TEXT ("this button THEN IF a block of more than one") HELP_TEXT ("color is selected in the table THEN It is") HELP_TEXT ("deleted and the block defined in the palette") HELP_TEXT ("is inserted. ELSE The block defined in the") HELP_TEXT ("palette is inserted at the postion just") HELP_TEXT ("before the selected square. END IF") HELP_TEXT ("ELSE The block defined in the palette is") HELP_TEXT ("inserted by erasing the colors following the") HELP_TEXT ("beginning of the bloc selected in the table.") HELP_TEXT ("END IF") HELP_TEXT ("") HELP_TEXT ("- Delete: Delete the block selected in the") HELP_TEXT ("table.") HELP_TEXT ("") HELP_TEXT ("- Blank: Follows this algorithm:") HELP_TEXT ("IF you click with the left mouse button on") HELP_TEXT ("this button THEN Replace the block selected") HELP_TEXT ("in the table by blank squares.") HELP_TEXT ("ELSE IF a block of more than one color is") HELP_TEXT ("selected in the table THEN Insert blank") HELP_TEXT ("squares to the left and to the right of the") HELP_TEXT ("block. (this is useful for isolating a") HELP_TEXT ("shade quickly) ELSE Insert blank squares") HELP_TEXT ("to the left of the selected square. END IF") HELP_TEXT ("END IF") HELP_TEXT ("") HELP_TEXT ("- Invert: Invert the order of the block") HELP_TEXT ("selected in the table.") HELP_TEXT ("") HELP_TEXT ("- Swap: Allows you you move a block (this") HELP_TEXT ("exchanges it with what is") HELP_TEXT ("where you want to move it).") HELP_TEXT ("") HELP_TEXT ("- Undo: Cancel the last modification of the") HELP_TEXT ("table.") HELP_TEXT ("") HELP_TEXT ("- The 2 numbers displayed on the right of") HELP_TEXT ("these buttons are: (above) - the number of") HELP_TEXT ("the color selected in the palette if only") HELP_TEXT ("one color is selected. (below) - the number") HELP_TEXT ("of the color contained in a square in the") HELP_TEXT ("shades table if this square is the only one") HELP_TEXT ("selected.") HELP_TEXT ("") HELP_TEXT ("- The \"mode\" button displays 3 different") HELP_TEXT ("modes:") HELP_TEXT ("\"Normal\": Shades in the range and saturates") HELP_TEXT ("to its boundaries.") HELP_TEXT ("\"Loop\": Shades in the range and loops if") HELP_TEXT ("boundaries are passed.") HELP_TEXT ("\"No saturation\": Shades in the range and") HELP_TEXT ("doesn't saturate if boundaries are passed.") HELP_TEXT ("If the Step (see below) is set to 1, this") HELP_TEXT ("option does exactly the same as the Normal") HELP_TEXT ("mode.") HELP_TEXT ("") HELP_TEXT ("- Set/Disable: If you want to define several") HELP_TEXT ("shades in the same table") HELP_TEXT ("but you'd like these shades not to be") HELP_TEXT ("effective at the same time, you") HELP_TEXT ("can mask (disable) some parts of the table") HELP_TEXT ("so that they will be") HELP_TEXT ("interpreted a blank squares.") HELP_TEXT ("To do that, select a block in the table of") HELP_TEXT ("shades and click on \"Set\".") HELP_TEXT ("The block will be underlined with a white") HELP_TEXT ("line; this means that it is") HELP_TEXT ("disabled.") HELP_TEXT ("") HELP_TEXT ("- Clear/Enable: This does exactly the") HELP_TEXT ("opposite as the button above.") HELP_TEXT ("") HELP_TEXT ("- Step: Defines the step of incrementation") HELP_TEXT ("of the shade. The bigger,") HELP_TEXT ("the faster you run through the colors of the") HELP_TEXT ("shade.") HELP_TEXT ("For example: if the step is 2 and that you") HELP_TEXT ("have defined a shade with") HELP_TEXT ("the colors 0,1,4,5,9 and that you click on a") HELP_TEXT ("pixel of color 1, it will") HELP_TEXT ("take the value 5 which is 2 positions next") HELP_TEXT ("in the la table.") HELP_TEXT ("") HELP_TEXT ("(We are sorry for these technical") HELP_TEXT ("considerations quite far from a purely") HELP_TEXT ("artistic point of view; but know that this") HELP_TEXT ("effect is really very useful and it is") HELP_TEXT ("preferable that you understand its whole") HELP_TEXT ("functionment if you want to fully take") HELP_TEXT ("advantage of it).") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("QUICK SHADE") HELP_TEXT (" This drawing mode has about the same effect") HELP_TEXT ("as Shade mode's except that it is faster") HELP_TEXT ("to configurate but a little bit less") HELP_TEXT ("powerful. When you draw on a color of the") HELP_TEXT ("image which is between the fore- and the") HELP_TEXT ("back-color in the palette, the color tends") HELP_TEXT ("towards the fore-color (according to the") HELP_TEXT ("step defined) if you draw with the left") HELP_TEXT ("mouse button, or it tends towards the") HELP_TEXT ("back-color if you are using the right mouse") HELP_TEXT ("button.") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_QUICK_SHADE_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Quick-shade mode.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_QUICK_SHADE_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu with a few parameters that mean") HELP_TEXT ("exactly the same as in the menu of Shade") HELP_TEXT ("mode. These parameters are the step and the") HELP_TEXT ("loop/satu- ration mode (normal, loop, no") HELP_TEXT ("saturation).") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("STENCIL") HELP_TEXT (" It is used to prevent some colors from") HELP_TEXT ("being modified if you draw on them. The") HELP_TEXT ("main application of the stencil is when you") HELP_TEXT ("want to change one color or more into") HELP_TEXT ("another.") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_STENCIL_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Stencil mode.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_STENCIL_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can define a stencil.") HELP_TEXT ("The different sections of this menu are:") HELP_TEXT ("") HELP_TEXT ("- Clear: No color is protected.") HELP_TEXT ("") HELP_TEXT ("- Invert: Colors that were protected are") HELP_TEXT ("unprotected and vice versa.") HELP_TEXT ("") HELP_TEXT ("- Palette: Select colors that should be") HELP_TEXT ("protected with the left mouse button or") HELP_TEXT ("unprotect colors with the right mouse") HELP_TEXT ("button.") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("MASK") HELP_TEXT (" This effect could have been called \"True") HELP_TEXT ("stencil\" because it protects some parts of") HELP_TEXT ("the picture instead of some colors. The") HELP_TEXT ("colors you tag represent the pixels in the") HELP_TEXT ("spare page, corresponding to the pixels in") HELP_TEXT ("the current page, that you don't want to") HELP_TEXT ("alter. For example, draw a simple white") HELP_TEXT ("figure on a black background in the spare") HELP_TEXT ("page. Then, tag the black color in the menu") HELP_TEXT ("of the Mask mode. When you'll draw in the") HELP_TEXT ("current page, only the pixels corresponding") HELP_TEXT ("to the white (non-black) ones in the spare") HELP_TEXT ("page will be modified.") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_MASK_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Mask mode.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_MASK_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can set the colors of") HELP_TEXT ("the Mask.") HELP_TEXT ("This menu works the same way as the one of") HELP_TEXT ("the Stencil, so please refer to the Stencil") HELP_TEXT ("paragraph to know how to use it.") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("GRID") HELP_TEXT (" This is useful to snap the cursor to the") HELP_TEXT ("cross-points of a grid. It's generally") HELP_TEXT ("used to draw a grid before drawing sprites") HELP_TEXT ("of the same size such as a font or tiles,") HELP_TEXT ("or for drawing figures or grabbing brushes") HELP_TEXT ("with their dimensions multiple of the step") HELP_TEXT ("of the grid.") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_GRID_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Snap-to-grid mode.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_GRID_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can define the grid") HELP_TEXT ("parameters. These parameters are:") HELP_TEXT ("") HELP_TEXT ("- X,Y: Steps of the grid.") HELP_TEXT ("") HELP_TEXT ("- dX,dY: Offsets of the grid.") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("The following shortcut hides or shows the") HELP_TEXT ("grid in the magnified view:") HELP_LINK ("%s", SPECIAL_SHOW_GRID) HELP_TEXT ("The grid size will be according to your") HELP_TEXT ("snap-to-grid settings.") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("SIEVE") HELP_TEXT (" This effect allows you, by defining a") HELP_TEXT ("pattern, to draw only on particular points") HELP_TEXT ("of the picture. If you are a Manga drawer,") HELP_TEXT ("you might find this useful to make patterned") HELP_TEXT ("shades or color transitions.") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_SIEVE_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Sieve mode.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_SIEVE_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can define the Sieve") HELP_TEXT ("parameters. This menu consists in:") HELP_TEXT ("") HELP_TEXT ("- 16x16 drawing area: You can define a") HELP_TEXT ("pattern in it (left click => white pixel /") HELP_TEXT ("right click => black pixel). All the white") HELP_TEXT ("pixels indicate that, when you'll draw,") HELP_TEXT ("pixels will be applied on the picture at the") HELP_TEXT ("corresponding positions whereas black pixels") HELP_TEXT ("won't modify the picture: whites pixels are") HELP_TEXT ("the \"holes of the sieve\".") HELP_TEXT ("") HELP_TEXT ("- 12 default patterns: They can be copied to") HELP_TEXT ("the drawing area.") HELP_TEXT ("") HELP_TEXT ("- \"Transfer to brush\": Copies the pattern to") HELP_TEXT ("the brush (white pixels => Fore-color /") HELP_TEXT ("black pixels => Back-color).") HELP_TEXT ("") HELP_TEXT ("- \"Get from brush\": Puts the brush into the") HELP_TEXT ("drawing area (back-color => black pixels /") HELP_TEXT ("others => white pixels).") HELP_TEXT ("") HELP_TEXT ("- Scrolling 4-arrows pad: Scrolls the") HELP_TEXT ("pattern in the drawing area.") HELP_TEXT ("") HELP_TEXT ("- Resizing 4-arrows pad: Defines the") HELP_TEXT ("dimensions of the pattern.") HELP_TEXT ("") HELP_TEXT ("- Default-value (black or white square):") HELP_TEXT ("Indicates which value must be inserted when") HELP_TEXT ("you increase the dimensions of the pattern.") HELP_TEXT ("") HELP_TEXT ("- \"Clear\": Sets the whole pattern with the") HELP_TEXT ("default value (see above).") HELP_TEXT ("") HELP_TEXT ("- \"Invert\": It... inverts :) ... black and") HELP_TEXT ("white pixels.") HELP_LINK ("(Key: %s)", SPECIAL_INVERT_SIEVE) HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("TRANSPARENCY") HELP_TEXT (" This allows to mix the color(s) of the") HELP_TEXT ("paintbrush with the colors of the picture.") HELP_TEXT ("It's used to make transparency effects like") HELP_TEXT ("with watercolors.") HELP_TEXT ("") HELP_TEXT ("You can also use the following shortcuts to") HELP_TEXT ("activate transparency mode and assign an") HELP_TEXT ("amount of opacity:") HELP_LINK (" 10%% : %s", SPECIAL_TRANSPARENCY_1) HELP_LINK (" 20%% : %s", SPECIAL_TRANSPARENCY_2) HELP_LINK (" 30%% : %s", SPECIAL_TRANSPARENCY_3) HELP_LINK (" 40%% : %s", SPECIAL_TRANSPARENCY_4) HELP_LINK (" 50%% : %s", SPECIAL_TRANSPARENCY_5) HELP_LINK (" 60%% : %s", SPECIAL_TRANSPARENCY_6) HELP_LINK (" 70%% : %s", SPECIAL_TRANSPARENCY_7) HELP_LINK (" 80%% : %s", SPECIAL_TRANSPARENCY_8) HELP_LINK (" 90%% : %s", SPECIAL_TRANSPARENCY_9) HELP_LINK (" 100%% : %s", SPECIAL_TRANSPARENCY_0) HELP_TEXT ("If you use two of these shortcuts quickly,") HELP_TEXT ("the second will set the units for finer") HELP_TEXT ("control. Ie: 4 5 makes 45%, 0 9 makes 9%.") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_COLORIZE_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Transparency mode.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_COLORIZE_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can define the") HELP_TEXT ("Transparency parameters. These parameters") HELP_TEXT ("are:") HELP_TEXT ("") HELP_TEXT ("- Interpolation rate: Indicates the") HELP_TEXT ("percentage of the applied color that will be") HELP_TEXT ("considered upon the replaced color.") HELP_TEXT ("") HELP_TEXT ("- Interpolation method: Uses an") HELP_TEXT ("interpolation algorithm to compute the") HELP_TEXT ("color, according to the interpolation rate.") HELP_TEXT ("") HELP_TEXT ("- Additive method: Uses the lightest colors") HELP_TEXT ("to choose the color to apply. For example:") HELP_TEXT ("if you want to apply a color RGB:30,20,40 on") HELP_TEXT ("a color RGB:10,50,20, the color applied will") HELP_TEXT ("be the one, in the palette, that is the") HELP_TEXT ("closest to the theoretic color RGB:30,50,40.") HELP_TEXT ("") HELP_TEXT ("- Subtractive method: uses the darkest") HELP_TEXT ("colors to choose the color to apply. For") HELP_TEXT ("example: if you want to apply a color") HELP_TEXT ("RGB:30,20,40 on a color RGB:10,50,20, the") HELP_TEXT ("color applied will be the one, in the") HELP_TEXT ("palette, that is the closest to the") HELP_TEXT ("theoretic color RGB:10,20,20.") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("SMOOTH") HELP_TEXT (" It provides an easy but not as efficient") HELP_TEXT ("anti-aliasing as any artist's touch.") HELP_TEXT ("Anyway this effect finds a better use in") HELP_TEXT ("making a blurry aspect.") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_SMOOTH_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Smooth mode.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_SMOOTH_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can define the Smooth") HELP_TEXT ("matrix or choose one among the 4 ones") HELP_TEXT ("predefined.") HELP_TEXT ("The middle square represents the pixel on") HELP_TEXT ("which you draw and the 8 others represent") HELP_TEXT ("the neighbour pixels. Then, the point on") HELP_TEXT ("which one draw will be replaced by the") HELP_TEXT ("weighted average (according to values of") HELP_TEXT ("each squares) of the 9 defined points.") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("SMEAR") HELP_TEXT (" It smears pixels in the direction you are") HELP_TEXT ("moving your paintbrush, just as if you") HELP_TEXT ("wanted to spread fresh paint with your") HELP_TEXT ("fingers. You can combine this effect with") HELP_TEXT ("the transparency effect.") HELP_TEXT ("") HELP_LINK ("(Key: %s)", SPECIAL_SMEAR_MODE) HELP_TEXT ("Switches the Smear mode.") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("TILING") HELP_TEXT (" It consists in displaying parts of the") HELP_TEXT ("brush that are adjusted on a tiling when") HELP_TEXT ("you are drawing. It's mainly used for") HELP_TEXT ("quickly drawing a background with a") HELP_TEXT ("pattern, but there is a great number of") HELP_TEXT ("other possibilities.") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_TILING_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Tiling mode.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_TILING_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can define the Tiling") HELP_TEXT ("parameters. These parameters are the offsets") HELP_TEXT ("of the tiling.") }; static const T_Help_table helptable_text[] = { HELP_TITLE("TEXT") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_TEXT) HELP_TEXT ("") HELP_TEXT ("The text menu allows you to enter some text") HELP_TEXT ("and render it as a brush.") HELP_TEXT ("The current background and foreground colors") HELP_TEXT ("are very important, they determine the text") HELP_TEXT ("color, the transparent color, and also the") HELP_TEXT ("color range to use for antialiasing.") HELP_TEXT ("GrafX2 can use 'bitmap' fonts as long as") HELP_TEXT ("they are in the special layout supported ") HELP_TEXT ("by SFont.") HELP_TEXT ("TrueType fonts can also be used if this") HELP_TEXT ("version of GrafX2 was compiled with") HELP_TEXT ("TrueType support.") HELP_TEXT ("") HELP_TEXT ("- Txt: Click and enter your text here, a") HELP_TEXT ("line of up to 250 characters.") HELP_TEXT ("") HELP_TEXT ("- Clear txt: Empties the current text.") HELP_TEXT ("When the text is empty, a standard string") HELP_TEXT ("is shown instead in the preview area.") HELP_TEXT ("") HELP_TEXT ("- Antialias: Click to enable or disable") HELP_TEXT ("Antialiasing. Only affects TrueType fonts.") HELP_TEXT ("") HELP_TEXT ("- Size: Determine the font height. Only") HELP_TEXT ("affects TrueType fonts.") HELP_TEXT ("") HELP_TEXT ("- Font selector: Choose a font. You can") HELP_TEXT ("use the arrow keys (up and down) to quickly") HELP_TEXT ("browse your fonts.") HELP_TEXT ("TrueType fonts are indicated by 'TT'.") HELP_TEXT ("") HELP_TEXT ("- Preview area: Shows what the brush will") HELP_TEXT ("look like.") }; static const T_Help_table helptable_magnifier[] = { HELP_TITLE("MAGNIFIER") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_MAGNIFIER) HELP_TEXT ("") HELP_TEXT ("Engages/Disengages the choice of the zoomed") HELP_TEXT ("window. If you're already in magnifier mode,") HELP_TEXT ("you'll return to normal mode.") HELP_LINK ("Zoom in : %s",SPECIAL_ZOOM_IN) HELP_LINK ("Zoom out: %s",SPECIAL_ZOOM_OUT) HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_MAGNIFIER) HELP_TEXT ("") HELP_TEXT ("Displays a menu where you can choose the") HELP_TEXT ("magnifying factor.") HELP_TEXT ("") HELP_TEXT (" Note: When you are in Zoom mode, you can") HELP_TEXT ("move the \"split\" bar by clicking on it and") HELP_TEXT ("moving your mouse left or right while") HELP_TEXT ("holding the mouse button down.") }; static const T_Help_table helptable_colorpicker[] = { HELP_TITLE("PIPETTE") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_COLORPICKER) HELP_TEXT ("") HELP_TEXT ("Engages a color grabbing.") HELP_TEXT ("") HELP_TEXT ("Click on the picture to get the color of the") HELP_TEXT ("pixel you're on. You can either get a new") HELP_TEXT ("Fore-color or Back-color with respectively") HELP_TEXT ("left or right mouse button.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_COLORPICKER) HELP_TEXT ("") HELP_TEXT ("Swap Fore-color and Back-color.") HELP_TEXT ("") HELP_TEXT (" The color currently pointed will be") HELP_TEXT ("displayed in the tool-bar right after the") HELP_TEXT ("coordinates. If you click outside the") HELP_TEXT ("picture, the color 0 will be returned.") }; static const T_Help_table helptable_resolution[] = { HELP_TITLE("RESOLUTION AND") HELP_TITLE(" IMAGE SIZE") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_RESOL) HELP_TEXT ("") HELP_TEXT ("Displays a menu where you can define the") HELP_TEXT ("size of your picture and choose the") HELP_TEXT ("screen resolution.") HELP_TEXT ("") HELP_TEXT ("- Image size") HELP_TEXT ("Click in the boxes named \"Width\" and") HELP_TEXT ("\"Height\" to change the size of the image") HELP_TEXT ("you're editing, up to 9999x9999.") HELP_TEXT ("You can also right-click a video mode to") HELP_TEXT ("copy its dimensions to the image's.") HELP_TEXT ("") HELP_TEXT ("- Pixel size") HELP_TEXT ("If you choose any Pixel size other than") HELP_TEXT ("Normal, Grafx2 will emulate a lower") HELP_TEXT ("resolution by scaling up everything it") HELP_TEXT ("displays, including the menus and mouse") HELP_TEXT ("cursor. In Double, Triple and Quadruple") HELP_TEXT ("mode, the image will appear zoomed x2, x3 or") HELP_TEXT ("x4, keeping the original proportions. The") HELP_TEXT ("scaling is done in software, with no linear") HELP_TEXT ("interpolation, so it can't cause blur. This") HELP_TEXT ("setting is especially useful if your") HELP_TEXT ("hardware or drivers don't support the low") HELP_TEXT ("resolutions you need, but it also allows you") HELP_TEXT ("to draw in low-resolution while staying in") HELP_TEXT ("window mode.") HELP_TEXT ("If you choose one of the scalers called") HELP_TEXT ("Wide, Tall, Wide2 and Tall2, this will") HELP_TEXT ("emulate a video mode which has rectangular") HELP_TEXT ("pixels (longer horizontally or vertically),") HELP_TEXT ("like some video modes of the C64, Amstrad") HELP_TEXT ("CPC, and Commodore Amiga.") HELP_TEXT ("") HELP_TEXT ("- Video mode") HELP_TEXT ("Click on a video mode to select it.") HELP_TEXT ("Grafx2 only lists modes that are detected") HELP_TEXT ("as available on your computer. Depending on") HELP_TEXT ("your video card and drivers, there can be") HELP_TEXT ("a huge difference in the number of modes") HELP_TEXT ("it can propose.") HELP_TEXT ("The small buttons on the left-hand side of") HELP_TEXT ("the lines in the list of modes have been") HELP_TEXT ("designed to allow you to disable some modes") HELP_TEXT ("that are not supported by your card. So, the") HELP_TEXT ("modes that you will disable won't be used") HELP_TEXT ("when loading pictures with \"Auto-set") HELP_TEXT ("resolution\" ON.") HELP_TEXT ("") HELP_TEXT ("When you click on one of these buttons, its") HELP_TEXT ("color changes to one of the 4 following. The") HELP_TEXT ("signification for each color of these") HELP_TEXT ("buttons is:") HELP_TEXT ("") HELP_TEXT ("- Light gray: The video mode is OK. It can") HELP_TEXT ("be used by the auto-set resolution option") HELP_TEXT ("when you load picture, and you can select it") HELP_TEXT ("in the menu of resolutions.") HELP_TEXT ("") HELP_TEXT ("- White: It works exactly the same as above.") HELP_TEXT ("Moreover, it allows you to tag your") HELP_TEXT ("favourite modes. Indeed, the huge number of") HELP_TEXT ("video modes makes it more difficult to find") HELP_TEXT ("the mode your want in the list; so you can") HELP_TEXT ("tag your favoutite ones in white, so that it") HELP_TEXT ("will be easier to locate them. (Note: you") HELP_TEXT ("cannot disable the standard windowed mode)") HELP_TEXT ("") HELP_TEXT ("- Dark gray: It allows you to indicate which") HELP_TEXT ("modes are not really perfect (flickering,") HELP_TEXT ("not centered, etc...) but which can be used") HELP_TEXT ("even so. The difference with the light grey") HELP_TEXT ("button is that these modes won't be used by") HELP_TEXT ("the auto-set resolution option.") HELP_TEXT ("") HELP_TEXT ("- Black: Use it for totally unsupported") HELP_TEXT ("modes. Thus, these modes won't be selected") HELP_TEXT ("the \"auto-set res.\" and the program will") HELP_TEXT ("not let you select them from the list of") HELP_TEXT ("resolutions.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_RESOL) HELP_TEXT ("") HELP_TEXT (" Automatically switches to the 640x400 window") HELP_TEXT ("mode.") }; static const T_Help_table helptable_page[] = { HELP_TITLE("SPARE") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_PAGE) HELP_TEXT ("") HELP_TEXT ("Jumps to spare page. The current page is") HELP_TEXT ("then considered as the new spare page, and") HELP_TEXT ("the spare page considered as the new current") HELP_TEXT ("page.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_PAGE) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can choose whether") HELP_TEXT ("you want to copy the whole picture (keyboard") HELP_TEXT ("short-cut in this menu is [Return]), only") HELP_TEXT ("the pixels, only the palette, or only some") HELP_TEXT ("colors.") HELP_TEXT ("In this last case, a second menu") HELP_TEXT ("(stencil-like) will propose you to tag the") HELP_TEXT ("colors you want to copy (they are all") HELP_TEXT ("selected by default).") HELP_TEXT ("Please refer to section \"Stencil\" to know") HELP_TEXT ("how to use this last menu.") HELP_TEXT ("The last option the menu (\"Copy palette and") HELP_TEXT ("remap\"), remaps the spare page with the") HELP_TEXT ("current palette and replicates this palette") HELP_TEXT ("to the spare page. This option is useful to") HELP_TEXT ("quickly remap a picture with the palette of") HELP_TEXT ("another.") }; static const T_Help_table helptable_save[] = { HELP_TITLE("SAVE") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_SAVE) HELP_TEXT ("") HELP_TEXT ("Displays a fileselector where the following") HELP_TEXT ("options are available:") HELP_TEXT ("") HELP_TEXT ("- Select drive: Allow you to change the") HELP_TEXT ("current drive.or volume (depending on your") HELP_TEXT ("operating system") HELP_TEXT ("") HELP_TEXT ("- Format: Allows you to choose the file") HELP_TEXT ("format you want. (PAL and KCF file formats") HELP_TEXT ("are \"palette\" files).") HELP_TEXT ("") HELP_TEXT ("- Filename: Allows you to give a new name to") HELP_TEXT ("the picture. If no extension is given, the") HELP_TEXT ("default (according to the format) will be") HELP_TEXT ("used.") HELP_TEXT ("") HELP_TEXT ("- Bookmarks: The four dropdown buttons allow") HELP_TEXT ("you to bookmark frequently used directories.") HELP_TEXT ("Use right-click to open a contextual menu") HELP_TEXT ("to Set it (memorize current directory),") HELP_TEXT ("Rename it to change its label, and Clear it") HELP_TEXT ("if you no longer need it. Use left-click to") HELP_TEXT ("change to the memorized directory.") HELP_TEXT ("") HELP_TEXT ("- File-list: Allows you to flick through the") HELP_TEXT ("disk tree or to overwrite an existing file.") HELP_TEXT ("") HELP_TEXT ("- Delete: Allows you to delete the item") HELP_TEXT ("under the selection bar. If the item is a") HELP_TEXT ("directory, it must be empty to be removed.") HELP_TEXT ("") HELP_TEXT ("- Save: Saves the picture with the current") HELP_TEXT ("filename, with the chosen format. If the ") HELP_TEXT ("current filename represents a directory,") HELP_TEXT ("you'll enter it.") HELP_TEXT ("") HELP_TEXT ("- Comment (Txt): If you're using the PKM") HELP_TEXT ("or PNG format, you can type in a comment on") HELP_TEXT ("your picture. It will be memorized in the") HELP_TEXT ("image.") HELP_TEXT ("") HELP_TEXT ("Note: The Backspace key brings you directly") HELP_TEXT ("to the parent directory. You can also type") HELP_TEXT ("the first letters of a filename you are") HELP_TEXT ("looking for, to access it faster.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_SAVE) HELP_TEXT ("") HELP_TEXT ("Save the current picture with its current") HELP_TEXT ("filename, format and comment.") HELP_TEXT ("") HELP_TEXT ("If the file already exists, a confirmation") HELP_TEXT ("box will appear.") }; static const T_Help_table helptable_load[] = { HELP_TITLE("LOAD") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_LOAD) HELP_TEXT ("") HELP_TEXT ("This works the same way as Save.") HELP_TEXT ("") HELP_TEXT ("You'll have access in the format selector to") HELP_TEXT ("a \"*.*\" filter. And of course, you won't be") HELP_TEXT ("able to type in any comment.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_LOAD) HELP_TEXT ("") HELP_TEXT ("Reloads the picture.") HELP_TEXT ("") HELP_TEXT ("If you want to load a picture and that you") HELP_TEXT ("haven't saved the last modifications of the") HELP_TEXT ("current picture, a confirmation box will") HELP_TEXT ("appear.") }; static const T_Help_table helptable_settings[] = { HELP_TITLE("SETTINGS") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_SETTINGS) HELP_TEXT ("") HELP_TEXT ("Displays a menu where you can configure some") HELP_TEXT ("miscellaneous elements of the program.") HELP_TEXT ("Detailed description of each setting is") HELP_TEXT ("available when this screen is open (Use the") HELP_LINK ("%s key.",0x100+BUTTON_HELP) HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("SKINS") HELP_TEXT ("") HELP_TEXT ("This window allow you to change the look and") HELP_TEXT ("feel of the program.") HELP_TEXT ("") HELP_TEXT ("- Font: determines whether you want to use") HELP_TEXT ("GrafX2 with a classical font, or another one") HELP_TEXT ("a bit funnier.") HELP_TEXT ("") HELP_TEXT ("- Cursor: Allows you to choose the graphic") HELP_TEXT ("mouse cursor: Solid and Thin are solid black") HELP_TEXT ("and white cursors defined by the skin file,") HELP_TEXT (" Transparent is a 1-pixel wide XOR cross.") HELP_TEXT ("") HELP_TEXT ("- Graphic file: you can change the whole") HELP_TEXT ("interface by selecting where the sprites for") HELP_TEXT ("all buttons are. Look at the files in the") HELP_TEXT ("\"skin\" directory if you want to create your") HELP_TEXT ("own. There are two skins available, the") HELP_TEXT ("default for 2.1 is called modern. Classic is") HELP_TEXT ("for nostalgics who wish to remember the old") HELP_TEXT ("days of Sunset Design. If you create a good") HELP_TEXT ("skin, feel free to share it with us! We may") HELP_TEXT ("include it in a future release...") HELP_TEXT ("") HELP_TEXT ("- Separate colors: Draws a squaring around") HELP_TEXT ("the colors of the tool-bar.") HELP_TEXT ("") HELP_TEXT ("- Show/Hide picture limits: Indicates if the") HELP_TEXT ("picture boundaries must be displayed when") HELP_TEXT ("you are in a resolution bigger than the") HELP_TEXT ("picture.") HELP_TEXT ("") }; static const T_Help_table helptable_settings_details[] = { HELP_TITLE("DETAILED SETTINGS") HELP_TEXT ("") HELP_TITLE("FILE SELECTOR") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD (" Show hidden files") HELP_TEXT ("Hidden files appear.") HELP_TEXT ("") HELP_BOLD (" Show hidden directories") HELP_TEXT ("Hidden directories appear.") HELP_TEXT ("") HELP_BOLD (" Preview delay") HELP_TEXT ("Delay before displaying a preview in file-") HELP_TEXT ("selectors (in 18.2th of second). Possible") HELP_TEXT ("values range from 1 to 256.") HELP_TEXT ("") HELP_BOLD (" Maximize preview") HELP_TEXT ("Maximize the preview of the pictures so that") HELP_TEXT ("it is as big as possible. If you're not in") HELP_TEXT ("the same resolution as the picture's one, it") HELP_TEXT ("can try to correct the aspect ratio, but if") HELP_TEXT ("the picture does not fill the whole screen,") HELP_TEXT ("it can be worse.") HELP_TEXT ("") HELP_BOLD (" Find file fast") HELP_TEXT ("This option is used to place the selection") HELP_TEXT ("bar on a filename by typing its first") HELP_TEXT ("letters. For example, if you want to find") HELP_TEXT ("the 'PICTURE.PKM' in a directory that also") HELP_TEXT ("contains 'PALETTE.PAL', you'll just have to") HELP_TEXT ("type P and I. The different values of 'FFF'") HELP_TEXT ("indicate if you want to find the name in") HELP_TEXT ("both files and directories or just in only") HELP_TEXT ("one of these:") HELP_TEXT ("0: files and directories") HELP_TEXT ("1: files only") HELP_TEXT ("2: directories only") HELP_TEXT ("") HELP_BOLD (" Auto set resolution") HELP_TEXT ("Automatically set the resolution when") HELP_TEXT ("loading a picture. You should set this value") HELP_TEXT ("to 'yes' after disabling the video modes") HELP_TEXT ("that are notsupported by your video card or") HELP_TEXT ("monitor.") HELP_TEXT ("") HELP_BOLD (" Set resolution according to") HELP_TEXT ("If the variable above is set to 'yes', this") HELP_TEXT ("one tells if you want to set the resolution") HELP_TEXT ("according to:") HELP_TEXT ("1: the internal 'original screen' dimensions") HELP_TEXT (" of the picture") HELP_TEXT ("2: the actual dimensions of the picture") HELP_TEXT (" ") HELP_BOLD (" Backup") HELP_TEXT ("Create a backup file when saving.") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("FILE FORMAT OPTIONS") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD (" Save screen size in GIF") HELP_TEXT ("Save the screen dimensions in GIF files. If") HELP_TEXT ("you want to read these files with Photoshop") HELP_TEXT ("or Alchemy, and maybe some other programs,") HELP_TEXT ("you must set this option to 'no'.") HELP_TEXT ("") HELP_BOLD (" Clear palette") HELP_TEXT ("If you load a picture with a palette of less") HELP_TEXT ("than 256 colors, this option defines if you") HELP_TEXT ("want to clear the palette or to keep the") HELP_TEXT ("colors of the previous picture that are over") HELP_TEXT ("the number of colors of the new picture.") HELP_TEXT ("For example, if you load a 32-color picture,") HELP_TEXT ("the colors 32 to 255 will be set to black if") HELP_TEXT ("this option is set to 'yes', or they will be") HELP_TEXT ("kept unchanged if this option is set to 'no'") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("GUI") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD (" Opening message") HELP_TEXT ("Display a message at startup telling the") HELP_TEXT ("version number of the program.") HELP_TEXT ("") HELP_BOLD (" Menu ratio") HELP_TEXT ("Aspect ratio and size of the menus and the") HELP_TEXT ("tool-bar.") HELP_TEXT ("Possible values:") HELP_TEXT ("0: Do not adapt (pixels are not stretched)") HELP_TEXT ("1: Adapt the menus and the tool-bar") HELP_TEXT (" according to the resolution") HELP_TEXT ("2: Slightly adapt the ratio of the menus and") HELP_TEXT (" tool-bar") HELP_TEXT ("-1:Do not adapt (like 0)") HELP_TEXT ("-2:Stretch by x2 maximum") HELP_TEXT ("-3:Stretch by x3 maximum") HELP_TEXT ("-4:Stretch by x4 maximum") HELP_TEXT ("") HELP_BOLD (" Draw limits") HELP_TEXT ("Draw the limits of the picture.") HELP_TEXT ("") HELP_BOLD (" Coordinates") HELP_TEXT ("Coordinates:") HELP_TEXT ("1: Relative") HELP_TEXT ("2: Absolute") HELP_TEXT ("") HELP_BOLD (" Separate colors") HELP_TEXT ("Separate the colors in the tool-bar by a") HELP_TEXT ("black squaring.") HELP_TEXT ("") HELP_BOLD (" Safety colors") HELP_TEXT ("When you reduce the palette or 'zap' some") HELP_TEXT ("colors out of it, it is possible that there") HELP_TEXT ("are not enough colors left to draw the") HELP_TEXT ("menus. Switching the following variable on") HELP_TEXT ("will bring back the colors of the menu if") HELP_TEXT ("there are less than 4 colors left after") HELP_TEXT ("'reducing' or 'zapping'.") HELP_TEXT ("") HELP_BOLD (" Grid XOR color") HELP_TEXT ("This determines the color value for the") HELP_TEXT ("grid. Each pixel of the grid will be") HELP_TEXT ("displayed by XOR-ing the original color with") HELP_TEXT ("the value of this setting.") HELP_TEXT ("For example, if you always paint 16-color") HELP_TEXT ("images, you can set it to 16 so the color of") HELP_TEXT ("the grid are 16 for 0, 17 for 1, etc. Then") HELP_TEXT ("you can set colors 16-31 as lighter/darker") HELP_TEXT ("variants of your original palette, resulting") HELP_TEXT ("in a pretty grid !") HELP_TEXT ("") HELP_BOLD (" Sync views") HELP_TEXT ("When this mode is active, scrolling the view") HELP_TEXT ("(and the magnifier view) affects both the") HELP_TEXT ("main image and the spare page - as long as") HELP_TEXT ("they have the same dimensions.") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("INPUT") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD (" Gauges scrolling speed Left") HELP_TEXT ("Speed of the scroll-bars (in VBLs waited)") HELP_TEXT ("while clicking with the left or right button") HELP_TEXT ("of the mouse.") HELP_TEXT ("Values can be between 1 and 255. The bigger") HELP_TEXT ("values, the slower.") HELP_TEXT ("") HELP_BOLD (" Gauges scrolling speed Right") HELP_TEXT ("Speed of the scroll-bars (in VBLs waited)") HELP_TEXT ("while clicking with the left or right button") HELP_TEXT ("of the mouse.") HELP_TEXT ("Values can be between 1 and 255. The bigger") HELP_TEXT ("values, the slower.") HELP_TEXT ("") HELP_BOLD (" Merge movement") HELP_TEXT ("This setting allows you merge successive") HELP_TEXT ("mouse movements into a single mouse") HELP_TEXT ("movement. You should only use it if you are") HELP_TEXT ("using a mouse which reports at 200Hz or") HELP_TEXT ("more, and you experience lag when using") HELP_TEXT ("discontinuous hand-drawing with large") HELP_TEXT ("brushes (this tool tries to paste the brush") HELP_TEXT ("and update the screen on each new mouse") HELP_TEXT ("position) In this case, set this to 2 or") HELP_TEXT ("more, to ignore some intermediate mouse") HELP_TEXT ("reports when a more recent one is present.") HELP_TEXT ("Note that with a value superior to 1, you") HELP_TEXT ("lose precision with continuous hand-drawing,") HELP_TEXT ("as intermediate mouse positions are skipped.") HELP_TEXT ("") HELP_BOLD (" Double click speed") HELP_TEXT ("This is the time (in milliseconds) between") HELP_TEXT ("two clicks for Grafx2 to recognize a") HELP_TEXT ("double-click. Double-click is used mostly in") HELP_TEXT ("the palette area of the menu: double-click a") HELP_TEXT ("color to open the palette.") HELP_TEXT ("") HELP_BOLD (" Double key speed") HELP_TEXT ("When you press two digit keys in rapid") HELP_TEXT ("succession (ex: 3 8), Grafx2 sets") HELP_TEXT ("transparency to 38% (instead of 30% then") HELP_TEXT ("80%). This setting allows you to set the") HELP_TEXT ("maximum delay between two keypresses for") HELP_TEXT ("GrafX2 to recognize them as a combo.") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD (" Swap buttons") HELP_TEXT ("This setting determines which key inverts") HELP_TEXT ("the mouse buttons when it's held : A left") HELP_TEXT ("click is then interpreted as a right-click.") HELP_TEXT ("It's especially useful for one-button") HELP_TEXT ("controllers, such as touchscreens and") HELP_TEXT ("tablets.") HELP_TEXT ("") HELP_TITLE("EDITING") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD (" Adjust brush pick") HELP_TEXT ("Adjust the brush grabbing in 'grid' mode.") HELP_TEXT ("") HELP_BOLD (" Undo pages") HELP_TEXT ("Number of pages stored in memory for") HELP_TEXT ("'undoing'.") HELP_TEXT ("Values are between 1 and 99.") HELP_TEXT ("") HELP_BOLD (" Vertices per polygon") HELP_TEXT ("Maximum number of vertices used in filled") HELP_TEXT ("polygons and polyforms, and lasso. Possible") HELP_TEXT ("values range from 2 to 16384.") HELP_TEXT ("") HELP_BOLD (" Fast zoom") HELP_TEXT ("Automatically zoom into the pointed area") HELP_TEXT ("when you press the short-key of the") HELP_TEXT ("Magnifier button while being above the") HELP_TEXT ("picture.") HELP_TEXT ("") HELP_BOLD (" Clear with stencil") HELP_TEXT ("Take the Stencil into account when clearing") HELP_TEXT ("the image.") HELP_TEXT ("") HELP_BOLD (" Auto discontinuous") HELP_TEXT ("Directly set the discontinuous freehand") HELP_TEXT ("drawing mode after brush grabbing.") HELP_TEXT ("") HELP_BOLD (" Auto nb colors used") HELP_TEXT ("Automaticaly count the number of different") HELP_TEXT ("colors used when opening the palette editor") HELP_TEXT ("window. (Set it to 'no' if you have a slow") HELP_TEXT ("computer or if you edit huge pictures)") HELP_TEXT ("") HELP_BOLD (" Right click colorpick") HELP_TEXT ("This enables a mode where the right mouse") HELP_TEXT ("buttons acts as a color picker until") HELP_TEXT ("it's released, and selects Foreground color.") HELP_TEXT ("This mode prevents you from painting with") HELP_TEXT ("Background color.") HELP_TEXT ("This option is ignored when the Shade,") HELP_TEXT ("Quick-shade, or Tiling mode is used.") HELP_TEXT ("") HELP_TEXT (" Multi shortcuts") HELP_TEXT ("When this setting is disabled, and you") HELP_TEXT ("create a shortcut with a key that is already") HELP_TEXT ("associated to another shortcut, Grafx2 will") HELP_TEXT ("unset the latter. If you enable this mode,") HELP_TEXT ("Grafx2 will not make such check, so you can") HELP_TEXT ("design shortcuts that trigger several") HELP_TEXT ("actions at once.") HELP_TEXT ("") }; static const T_Help_table helptable_clear[] = { HELP_TITLE("CLEAR") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_CLEAR) HELP_TEXT ("") HELP_TEXT ("Clears the picture with the color number 0,") HELP_TEXT ("or the transparent color of the picture.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_CLEAR) HELP_TEXT ("") HELP_TEXT ("Clears the picture with the Back-color.") }; static const T_Help_table helptable_general[] = { HELP_TITLE("HELP STATS") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_HELP) HELP_TEXT ("") HELP_TEXT ("Displays an info window where you'll find") HELP_TEXT ("some credits, help about the credits,") HELP_TEXT ("different effects, greetings, registering...") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_HELP) HELP_TEXT ("") HELP_TEXT ("Displays a window where you'll find") HELP_TEXT ("miscellaneous information about the system.") HELP_TEXT (" Note: you should take care to keep more") HELP_TEXT ("than 128 Kb in order to let the program") HELP_TEXT ("run in a proper way.") }; static const T_Help_table helptable_undo[] = { HELP_TITLE("OOPS") HELP_TEXT ("(UNDO/REDO)") HELP_TEXT ("LEFT CLICK Allows you to undo the last") HELP_TEXT ("modification on the picture.") HELP_LINK ("(Key:%s)",0x100+BUTTON_UNDO) HELP_TEXT ("") HELP_TEXT ("RIGHT CLICK Allows you to redo the last") HELP_TEXT ("modification undone on the picture.") HELP_TEXT ("The maximum number of UNDO that you can") HELP_TEXT ("perform can be defined in the settings") HELP_TEXT ("menu.") HELP_TEXT ("Undo/Redo aren't effective after page") HELP_TEXT ("switching, picture loading and picture") HELP_TEXT ("size modifications.") HELP_LINK ("(Key:%s)",0x200+BUTTON_UNDO) }; static const T_Help_table helptable_kill[] = { HELP_TITLE("KILL") HELP_TEXT ("KILL CURRENT PAGE") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_KILL) HELP_TEXT ("") HELP_TEXT ("Removes the current page from the list of") HELP_TEXT ("\"Undo\" pages. This allows you to free some") HELP_TEXT ("memory if you need it. For instance, this") HELP_TEXT ("will allow you to delete the start-up page") HELP_TEXT ("after having loaded an image. A message will") HELP_TEXT ("appear if you've already erased all the") HELP_TEXT ("pages except the last one.") HELP_TEXT (" Note: Another way to free some memory is to") HELP_TEXT ("decrease the number of \"Undo\" pages. Or") HELP_TEXT ("else, if you have recentlt grabbed a very") HELP_TEXT ("big brush that you don't use any more, you") HELP_TEXT ("can grab a new smaller one. The memory") HELP_TEXT ("allocated by the big brush will be thus") HELP_TEXT ("freed.") }; static const T_Help_table helptable_quit[] = { HELP_TITLE("QUIT") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_QUIT) HELP_TEXT ("") HELP_TEXT ("Allows you to leave GrafX2. If there are") HELP_TEXT ("unsaved modifications in the current or") HELP_TEXT ("spare page, a confirmation box will ask you") HELP_TEXT ("if you really want to quit GrafX2, if you") HELP_TEXT ("want to save (Auto-save, no fileselector) or") HELP_TEXT ("if you want to stay in GrafX2.") }; static const T_Help_table helptable_palette[] = { HELP_TITLE("PAL MENU") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_PALETTE) HELP_TEXT ("") HELP_TEXT ("Displays a menu where the following options") HELP_TEXT ("are available:") HELP_TEXT ("") HELP_TEXT ("- Palette: Allows you to choose a") HELP_TEXT ("color-block to edit. If you click with the") HELP_TEXT ("right mouse button, you'll choose a new") HELP_TEXT ("Back-color.") HELP_TEXT ("") HELP_TEXT ("- Gauges: Allow you to modify the") HELP_TEXT ("current selection.") HELP_TEXT ("") HELP_TEXT ("- RGB or HSL above the gauges: Switches") HELP_TEXT ("between RGB and HSL color spaces. In HSL") HELP_TEXT ("mode, the three sliders allow you to set the") HELP_TEXT ("Hue (tint), Saturation (from grayscale to") HELP_TEXT ("pure color) and Lightness (from black to") HELP_TEXT ("white).") HELP_TEXT ("") HELP_TEXT ("- numbers below the gauges: Allows you to") HELP_TEXT ("type in a new color in hexadecimal RRGGBB") HELP_TEXT ("or RGB: ie. to get blue, you can type either") HELP_TEXT ("0000ff or 00f.") HELP_TEXT ("") HELP_TEXT ("- \"+\" and \"-\": Allow you to lighten or") HELP_TEXT ("darken the current selection.") HELP_TEXT ("") HELP_TEXT ("- Preset: Restores the predefined GrafX2") HELP_TEXT ("palette.") HELP_TEXT ("") HELP_TEXT ("- Gray: Transforms the current selection") HELP_TEXT ("into its gray-scaled equivalent.") HELP_TEXT ("") HELP_TEXT ("- Neg: Transforms the current selection") HELP_TEXT ("into its reverse video equivalent.") HELP_TEXT ("") HELP_TEXT ("- Invert: Swaps the colors of the current") HELP_TEXT ("selection so that the first colors become") HELP_TEXT ("the last ones.") HELP_TEXT ("") HELP_TEXT ("- X-Invert: Works as above but modifies the") HELP_TEXT ("picture so that it looks the same.") HELP_TEXT ("") HELP_TEXT ("- Swap: Swaps the current selection with") HELP_TEXT ("another color-block. Click on the beginning") HELP_TEXT ("of the new color-block.") HELP_TEXT ("") HELP_TEXT ("- X-Swap: Works as above but modifies the") HELP_TEXT ("picture so that it looks the same. This may") HELP_TEXT ("be useful if you want to sort your palette.") HELP_TEXT ("") HELP_TEXT ("- Copy: Copies the current selection to") HELP_TEXT ("another color-block. Click on the beginning") HELP_TEXT ("of the new color-block.") HELP_TEXT ("") HELP_TEXT ("- Spread: Computes a gradation between two") HELP_TEXT ("colors. If your selection is only made up of") HELP_TEXT ("one color, select the second color in the") HELP_TEXT ("palette. Otherwise, the two colors used will") HELP_TEXT ("be its extremities.") HELP_TEXT ("") HELP_TEXT ("- Sort: sorts the palette by color ranges.") HELP_TEXT ("If you click with the left mouse button, it") HELP_TEXT ("will sort by H S L; and if you click with") HELP_TEXT ("the right mouse button, it will sort by L") HELP_TEXT ("only. Note that you can choose a range of") HELP_TEXT ("colors before sorting, and instead of the") HELP_TEXT ("whole palette it will sort this range.") HELP_TEXT ("") HELP_TEXT ("- Used: Indicates the number of colors used") HELP_TEXT ("in the picture and opens a histogram screen.") HELP_TEXT ("") HELP_TEXT ("- Zap unused: Erases the unused colors with") HELP_TEXT ("copies of the current selection. (The") HELP_TEXT ("keyboard shortcut for this button is ).") HELP_TEXT ("") HELP_TEXT ("- Reduce: Allows you to reduce the palette") HELP_TEXT ("to the number of colors you want (and") HELP_TEXT ("modifies the picture).") HELP_TEXT ("") HELP_TEXT ("- Undo: Allows you to recover the last") HELP_TEXT ("modifications made on the palette. Note that") HELP_TEXT ("it can't undo the changes that affect the") HELP_TEXT ("pixels (remapping), you'll need to Cancel") HELP_TEXT ("them.") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("If you press , the program will") HELP_TEXT ("replace, as well as possible, some unused") HELP_TEXT ("colors by the four default colors of the") HELP_TEXT ("menu. The image won't look altered because") HELP_TEXT ("the modified colors (in the case they were") HELP_TEXT ("used on a few points) will be replaced by") HELP_TEXT ("the closest colors in the rest of the") HELP_TEXT ("palette. This option is really useful when") HELP_TEXT ("you modify the palette so that there are no") HELP_TEXT ("colors that fit for the menu (eg: \"Zap") HELP_TEXT ("unused\" while very little colors are used in") HELP_TEXT ("the picture; or \"Reduce\" with a very small") HELP_TEXT ("number of colors).") HELP_TEXT ("") HELP_TEXT ("If you press the key below or <,>") HELP_TEXT ("(QWERTY), the menu will disappear and you") HELP_TEXT ("will be able to pick up a color from the") HELP_TEXT ("picture easily. Press to cancel.") HELP_TEXT ("") HELP_TEXT ("If only one color is selected (not a block),") HELP_TEXT ("the <[> and <]> keys can be used to select") HELP_TEXT ("the previous or next Forecolor (Backcolor if") HELP_TEXT ("you press at the same time).") HELP_TEXT ("") HELP_TEXT ("Warning! If you press Undo after an action") HELP_TEXT ("that modifies the picture (X-Swap, X-Invert") HELP_TEXT ("and Reduce colors), the picture won't be") HELP_TEXT ("remapped as it was just before this action.") HELP_TEXT ("Only Cancel will.") HELP_TEXT ("") HELP_TITLE("PALETTE OPTIONS") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_PALETTE) HELP_TEXT ("") HELP_TEXT ("Opens a menu from where you have the") HELP_TEXT ("following options:") HELP_TEXT ("") HELP_TEXT ("- Colors for best match:") HELP_TEXT ("A menu in which you can select the colors") HELP_TEXT ("that have not to be used for smoothing, for") HELP_TEXT ("the transparency mode, and for remapping.") HELP_TEXT ("") HELP_TEXT ("- User's color series:") HELP_TEXT ("A menu in which you can define color series") HELP_TEXT ("for next/previous user color shortcuts.") HELP_TEXT ("It's the same settings than the shade mode.") HELP_TEXT ("After you have some color ranges defined in") HELP_TEXT ("this screen, you can use those shortcuts to") HELP_TEXT ("move to the next or previous color according") HELP_TEXT ("to your ranges:") HELP_TEXT ("") HELP_TEXT ("Foreground color") HELP_TEXT ("") HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_FORECOLOR) HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_FORECOLOR) HELP_TEXT ("") HELP_TEXT ("Background color") HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_BACKCOLOR) HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_BACKCOLOR) HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("- Palette layout:") HELP_TEXT ("Lets you customize the palette that appears") HELP_TEXT ("on the right of the menu. You can choose the") HELP_TEXT ("number of lines and columns.") HELP_TEXT ("If you want the colors to run top to bottom,") HELP_TEXT ("check the 'Vertical' button, otherwise the") HELP_TEXT ("colors runs left to right.") HELP_TEXT ("") HELP_TEXT ("- RGB Scale:") HELP_TEXT ("Lets you set the scale of the R G B sliders") HELP_TEXT ("in the palette screen. You should normally") HELP_TEXT ("leave it at 256 to get the full 0-255 range,") HELP_TEXT ("but if you want to constrain the palette") HELP_TEXT ("to the capabilities of some specific") HELP_TEXT ("computers and consoles, you can choose eg:") HELP_TEXT (" 64 : VGA") HELP_TEXT (" 16 : Amiga") HELP_TEXT (" 4 : MSX2") HELP_TEXT (" 2 : Amstrad CPC") }; static const T_Help_table helptable_pal_scroll[] = { HELP_TITLE("SCROLL PAL") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_TEXT ("") HELP_TEXT ("Scrolls the palette window in the right of") HELP_TEXT ("the menu.") HELP_LINK ("Key for back: %s", 0x100+BUTTON_PAL_LEFT) HELP_LINK ("Key for forward: %s", 0x100+BUTTON_PAL_RIGHT) HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_TEXT ("") HELP_TEXT ("Same as above, but faster.") HELP_LINK ("Key for back: %s", 0x200+BUTTON_PAL_LEFT) HELP_LINK ("Key for forward: %s", 0x200+BUTTON_PAL_RIGHT) HELP_TEXT ("") }; static const T_Help_table helptable_color_select[] = { HELP_TITLE("PALETTE") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_TEXT ("") HELP_TEXT ("Defines the Fore-color.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_TEXT ("") HELP_TEXT ("Defines the Back-color.") }; static const T_Help_table helptable_hide[] = { HELP_TITLE("HIDE MENU") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_HIDE) HELP_TEXT ("") HELP_TEXT ("Allows you to hide all toolbars, leaving") HELP_TEXT ("only the status bar.") HELP_TEXT ("Click again to show them again.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_TEXT ("") HELP_TEXT ("Opens a drop-down menu where you can choose") HELP_TEXT ("Which toolbars are going to be visible in") HELP_TEXT ("the menu.") }; static const T_Help_table helptable_layermenu[] = { HELP_TITLE("LAYERS MENU") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_LAYER_MENU) HELP_TEXT ("") HELP_TEXT ("In this menu you can set the following") HELP_TEXT ("options:") HELP_TEXT ("") HELP_TEXT ("* Transparent color : This determines which") HELP_TEXT ("color index is considered transparent when") HELP_TEXT ("using layers. Click the button and then") HELP_TEXT ("click on the image to pick the right color,") HELP_TEXT ("or use ESC to cancel.") HELP_TEXT ("") HELP_TEXT ("* Transparent background : When this option") HELP_TEXT ("is checked, all pixels of the transparent") HELP_TEXT ("color on layer 1 (background layer) will") HELP_TEXT ("be tagged as transparent in the final image.") HELP_TEXT ("Check this option if you want to make a") HELP_TEXT ("transparent GIF or PNG. These are the only") HELP_TEXT ("file formats that support this option.") }; static const T_Help_table helptable_layertrans[] = { HELP_TITLE("LAYERS TRANSPARENCY") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_TEXT ("") HELP_TEXT ("Sets the transparent color as background pen") HELP_TEXT ("color.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_TEXT ("") HELP_TEXT ("The current Background color becomes the") HELP_TEXT ("color considered transparent for the layers.") }; static const T_Help_table helptable_layermerge[] = { HELP_TITLE("LAYERS MERGE") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_LAYER_MERGE) HELP_TEXT ("") HELP_TEXT ("Merges the current layer with the one below") HELP_TEXT ("it, and sets the resulting layer as current") HELP_TEXT ("one for editing.") HELP_TEXT ("This function has no effect if you're") HELP_TEXT ("editing the lowest layer.") }; static const T_Help_table helptable_layeradd[] = { HELP_TITLE("ADD LAYER") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_LAYER_ADD) HELP_TEXT ("") HELP_TEXT ("Add a new layer above the current one,") HELP_TEXT ("and selects this new (empty) layer for") HELP_TEXT ("editing.") }; static const T_Help_table helptable_layerdel[] = { HELP_TITLE("DROP LAYER") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_LAYER_REMOVE) HELP_TEXT ("") HELP_TEXT ("Deletes the current layer.") }; static const T_Help_table helptable_layerup[] = { HELP_TITLE("MOVE LAYER UP") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_LAYER_UP) HELP_TEXT ("") HELP_TEXT ("Swaps the current layer with the one") HELP_TEXT ("above it. This has no effect if this") HELP_TEXT ("layer is already on top.") }; static const T_Help_table helptable_layerdown[] = { HELP_TITLE("MOVE LAYER DOWN") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_LAYER_DOWN) HELP_TEXT ("") HELP_TEXT ("Swaps the current layer with the one") HELP_TEXT ("below it. This has no effect if this") HELP_TEXT ("layer is already on the bottom.") }; static const T_Help_table helptable_layerselect[] = { HELP_TITLE("LAYER SELECTION") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_TEXT ("") HELP_TEXT ("Choose a layer as the current one for") HELP_TEXT ("drawing.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_TEXT ("") HELP_TEXT ("Makes a layer visible or invisible.") HELP_TEXT ("If you click the current layer, this toggles") HELP_TEXT ("the visibility of all other layers instead.") }; #define HELP_TABLE_DECLARATION(x) {x, sizeof(x)/sizeof(const T_Help_table)}, T_Help_section Help_section[] = { HELP_TABLE_DECLARATION(helptable_about) HELP_TABLE_DECLARATION(helptable_licence) HELP_TABLE_DECLARATION(helptable_help) HELP_TABLE_DECLARATION(helptable_credits) // Attention, keep the same order as BUTTON_NUMBERS: HELP_TABLE_DECLARATION(helptable_hide) HELP_TABLE_DECLARATION(helptable_layermenu) HELP_TABLE_DECLARATION(helptable_layertrans) HELP_TABLE_DECLARATION(helptable_layermerge) HELP_TABLE_DECLARATION(helptable_layeradd) HELP_TABLE_DECLARATION(helptable_layerdel) HELP_TABLE_DECLARATION(helptable_layerup) HELP_TABLE_DECLARATION(helptable_layerdown) HELP_TABLE_DECLARATION(helptable_layerselect) HELP_TABLE_DECLARATION(helptable_paintbrush) HELP_TABLE_DECLARATION(helptable_adjust) HELP_TABLE_DECLARATION(helptable_draw) HELP_TABLE_DECLARATION(helptable_curves) HELP_TABLE_DECLARATION(helptable_lines) HELP_TABLE_DECLARATION(helptable_airbrush) HELP_TABLE_DECLARATION(helptable_floodfill) HELP_TABLE_DECLARATION(helptable_polygons) HELP_TABLE_DECLARATION(helptable_polyfill) HELP_TABLE_DECLARATION(helptable_rectangles) HELP_TABLE_DECLARATION(helptable_filled_rectangles) HELP_TABLE_DECLARATION(helptable_circles) HELP_TABLE_DECLARATION(helptable_filled_circles) HELP_TABLE_DECLARATION(helptable_grad_rect) HELP_TABLE_DECLARATION(helptable_spheres) HELP_TABLE_DECLARATION(helptable_brush) HELP_TABLE_DECLARATION(helptable_polybrush) HELP_TABLE_DECLARATION(helptable_brush_fx) HELP_TABLE_DECLARATION(helptable_effects) HELP_TABLE_DECLARATION(helptable_text) HELP_TABLE_DECLARATION(helptable_magnifier) HELP_TABLE_DECLARATION(helptable_colorpicker) HELP_TABLE_DECLARATION(helptable_resolution) HELP_TABLE_DECLARATION(helptable_page) HELP_TABLE_DECLARATION(helptable_save) HELP_TABLE_DECLARATION(helptable_load) HELP_TABLE_DECLARATION(helptable_settings) HELP_TABLE_DECLARATION(helptable_clear) HELP_TABLE_DECLARATION(helptable_general) HELP_TABLE_DECLARATION(helptable_undo) HELP_TABLE_DECLARATION(helptable_kill) HELP_TABLE_DECLARATION(helptable_quit) HELP_TABLE_DECLARATION(helptable_palette) HELP_TABLE_DECLARATION(helptable_pal_scroll) HELP_TABLE_DECLARATION(helptable_pal_scroll) HELP_TABLE_DECLARATION(helptable_color_select) // End of buttons list // NB_BUTTONS+0 HELP_TABLE_DECLARATION(helptable_settings_details) // NB_BUTTONS+1 // HELP_TABLE_DECLARATION() // NB_BUTTONS+2 // HELP_TABLE_DECLARATION() // ... }; grafx2/src/hotkeys.h0000644000076400010400000000503011436521504015057 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2008 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file hotkeys.h /// Definition of the tables used by the keyboard shortcuts. /// The actual data is in hotkeys.c ////////////////////////////////////////////////////////////////////////////// #if !defined(__VBCC__) #include #else #define bool char #endif #include #define NB_SHORTCUTS 198 ///< Number of actions that can have a key combination associated to it. /*** Types definitions and structs ***/ typedef struct { word Number; ///< Identifier for shortcut. This is a number starting from 0, which matches ::T_Config_shortcut_info.Number char Label[36]; ///< Text to show in the screen where you can edit the shortcut. char Explanation1[37]; ///< Explanation text (1/3) to show in the screen where you can edit the shortcut. char Explanation2[37]; ///< Explanation text (2/3) to show in the screen where you can edit the shortcut. char Explanation3[37]; ///< Explanation text (3/3) to show in the screen where you can edit the shortcut. bool Suppr; ///< Boolean, true if the shortcut can be removed. word Key; ///< Primary shortcut. Value is a keycode, see keyboard.h word Key2; ///< Secondary shortcut. Value is a keycode, see keyboard.h } T_Key_config; /// Table with all the configurable shortcuts, whether they are for a menu button or a special action. extern T_Key_config ConfigKey[NB_SHORTCUTS]; /// /// Translation table from a shortcut index to a shortcut identifier. /// The value is either: /// - 0x000 + special shortcut number /// - 0x100 + button number (left click) /// - 0x200 + button number (right click) extern word Ordering[NB_SHORTCUTS]; grafx2/src/init.h0000644000076400010400000000373511524345740014352 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file init.h /// Initialization (and some de-initialization) functions. ////////////////////////////////////////////////////////////////////////////// T_Gui_skin *Load_graphics(const char * skin_file, T_Gradient_array *gradients); void Set_current_skin(const char *skinfile, T_Gui_skin *gfx); void Init_buttons(void); void Init_operations(void); void Init_brush_container(void); int Load_CFG(int reload_all); int Save_CFG(void); void Set_all_video_modes(void); void Set_config_defaults(void); void Init_sighandler(void); void Init_paintbrushes(void); /// Set application icon(s) void Define_icon(void); extern char Gui_loading_error_message[512]; /// /// Loads a 8x8 monochrome font, the kind used in all menus and screens. /// This function allocates the memory, and returns a pointer to it when /// successful. /// If an error is encountered, it frees what needs it, prints an error message /// in ::Gui_loading_error_message, and returns NULL. byte * Load_font(const char * font_name); /// /// Based on which toolbars are visible, updates their offsets and /// computes ::Menu_height and ::Menu_Y void Compute_menu_offsets(void); grafx2/src/input.h0000644000076400010400000000521111464642104014532 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file input.h /// Functions for mouse, keyboard and joystick input. /// Joystick input is used to emulate mouse on platforms that don't have a /// pointing device, ie: the GP2X. ////////////////////////////////////////////////////////////////////////////// /// /// This is the keyboard/mouse/joystick input polling function. /// Returns 1 if a significant changed occurred, such as a mouse button pressed /// or depressed, or a new keypress was in the keyboard buffer. /// The latest input variables are held in ::Key, ::Key_ANSI, ::Mouse_X, ::Mouse_Y, ::Mouse_K. /// Note that ::Key and ::Key_ANSI are not persistent, they will be reset to 0 /// on subsequent calls to ::Get_input(). int Get_input(int sleep_time); /// Returns true if the keycode has been set as a keyboard shortcut for the function. int Is_shortcut(word key, word function); /// Returns true if the function has any shortcut key. int Has_shortcut(word function); /// Adjust mouse sensitivity (and actual mouse input mode) void Adjust_mouse_sensitivity(word fullscreen); void Set_mouse_position(void); /// /// This holds the ID of the GUI control that the mouse /// is manipulating. The input system will reset it to zero /// when mouse button is released, but it's the engine /// that will record and retrieve a real control ID. extern int Input_sticky_control; /// Allows locking movement to X or Y axis: 0=normal, 1=lock on next move, 2=locked horizontally, 3=locked vertically. extern int Snap_axis; /// For the :Snap_axis mode, sets the origin's point (in image coordinates) extern int Snap_axis_origin_X; /// For the :Snap_axis mode, sets the origin's point (in image coordinates) extern int Snap_axis_origin_Y; /// /// This malloced string is set when a drag-and-drop event /// brings a file to Grafx2's window. extern char * Drop_file_name; grafx2/src/io.h0000644000076400010400000001304711545663754014026 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2008 Yves Rizoud 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file io.h /// Low-level endian-neutral file operations, and also some filesystem operations. /// Many of these may seem trivial, but the wrappers eliminate the need for a /// forest of preprocessor defines in each file. /// You MUST use the functions in this file instead of: /// - fread() and fwrite() /// - stat() /// - fstat() /// - opendir() /// - readdir() /// - Also, don't assume "/" or "\\", use PATH_SEPARATOR /// If you don't, you break another platform. ////////////////////////////////////////////////////////////////////////////// /// Reads a single byte from an open file. Returns true if OK, false if a file i/o error occurred. int Read_byte(FILE *file, byte *dest); /// Writes a single byte to an open file. Returns true if OK, false if a file i/o error occurred. int Write_byte(FILE *file, byte b); /// Reads several bytes from an open file. Returns true if OK, false if a file i/o error occurred. int Read_bytes(FILE *file, void *dest, size_t size); /// Writes several bytes to an open file. Returns true if OK, false if a file i/o error occurred. int Write_bytes(FILE *file, void *dest, size_t size); /// Reads a 16-bit Low-Endian word from an open file. Returns true if OK, false if a file i/o error occurred. int Read_word_le(FILE *file, word *dest); /// Writes a 16-bit Low-Endian word to an open file. Returns true if OK, false if a file i/o error occurred. int Write_word_le(FILE *file, word w); /// Reads a 32-bit Low-Endian dword from an open file. Returns true if OK, false if a file i/o error occurred. int Read_dword_le(FILE *file, dword *dest); /// Writes a 32-bit Low-Endian dword to an open file. Returns true if OK, false if a file i/o error occurred. int Write_dword_le(FILE *file, dword dw); /// Reads a 16-bit Big-Endian word from an open file. Returns true if OK, false if a file i/o error occurred. int Read_word_be(FILE *file, word *dest); /// Writes a 16-bit Big-Endian word to an open file. Returns true if OK, false if a file i/o error occurred. int Write_word_be(FILE *file, word w); /// Reads a 32-bit Big-Endian dword from an open file. Returns true if OK, false if a file i/o error occurred. int Read_dword_be(FILE *file, dword *dest); /// Writes a 32-bit Big-Endian dword to an open file. Returns true if OK, false if a file i/o error occurred. int Write_dword_be(FILE *file, dword dw); /// Extracts the filename part from a full file name. void Extract_filename(char *dest, const char *source); /// Extracts the directory from a full file name. void Extract_path(char *dest, const char *source); /// Finds the rightmost path separator in a full filename. Used to separate directory from file. char * Find_last_slash(const char * str); #if defined(__WIN32__) #define PATH_SEPARATOR "\\" #elif defined(__MINT__) #define PATH_SEPARATOR "\\" #else #define PATH_SEPARATOR "/" #endif /// Size of a file, in bytes. Returns 0 in case of error. int File_length(const char *fname); /// Size of a file, in bytes. Takes an open file as argument, returns 0 in case of error. int File_length_file(FILE * file); /// Returns true if a file passed as a parameter exists in the current directory. int File_exists(char * fname); /// Returns true if a directory passed as a parameter exists in the current directory. int Directory_exists(char * directory); /// Check if a file or directory is hidden. Full name (with directories) is optional. int File_is_hidden(const char *fname, const char *full_name); /// Scans a directory, calls Callback for each file in it, void For_each_file(const char * directory_name, void Callback(const char *)); /// Scans a directory, calls Callback for each file or directory in it, void For_each_directory_entry(const char * directory_name, void Callback(const char *, byte is_file, byte is_directory, byte is_hidden)); /// /// Creates a fully qualified name from a directory and filename. /// The point is simply to insert a PATH_SEPARATOR when needed. void Get_full_filename(char * output_name, char * file_name, char * directory_name); /// /// Appends a file or directory name to an existing directory name. /// As a special case, when the new item is equal to PARENT_DIR, this /// will remove the rightmost directory name. /// reverse_path is optional, if it's non-null, the function will /// write there : /// - if filename is ".." : The name of eliminated directory/file /// - else: ".." void Append_path(char *path, const char *filename, char *reverse_path); /// /// Creates a lock file, to check if an other instance of Grafx2 is running. /// @return 0 on success (first instance), -1 on failure (others are running) byte Create_lock_file(const char *file_directory); /// /// Release a lock file created by ::Create_Lock_file void Release_lock_file(const char *file_directory); grafx2/src/keyboard.h0000644000076400010400000000633311353475056015210 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file keyboard.h /// Functions to convert bewteen the SDL key formats and the keycode we use /// in grafx2. /// The keycode we're using is generalized to handle mouse and joystick shortcuts /// as well. The format can be broken down as: /// - 0x0000 + a number between 0 and SDLK_LAST (about 324) : the SDL "sym" key number. /// - 0x0000 + SDLK_LAST+1: Mouse middle button. /// - 0x0000 + SDLK_LAST+2: Mouse wheel up. /// - 0x0000 + SDLK_LAST+3: Mouse wheel down. /// - 0x0000 + SDLK_LAST+4+B : Joystick button number "B", starting at B=0. /// - 0x0800 + a number between 0 and 0x7FF: The scancode key number, for keys which have no "sym", such as keys from multimedia keyboards, and "fn" and "Thinkpad" key for a laptop. /// Add 0x1000 for the Shift modifier MOD_SHIFT /// Add 0x2000 for the Control modifier ::MOD_CONTROL /// Add 0x4000 for the Alt modifier ::MOD_ALT /// Add 0x8000 for the "Meta" modifier ::MOD_META (On MacOS X it's the CMD key) ////////////////////////////////////////////////////////////////////////////// /*! Convert an SDL keysym to an ANSI/ASCII character. This is used to type text and numeric values in input boxes. @param keysym SDL symbol to convert */ word Keysym_to_ANSI(SDL_keysym keysym); /*! Convert an SDL keysym to an internal keycode number. This is needed because SDL tends to split the information across the unicode sym, the regular sym, and the raw keycode. We also need to differenciate 1 (keypad) and 1 (regular keyboard), and some other things. See the notice at the beginning of keyboard.h for the format of a keycode. @param keysym SDL symbol to convert */ word Keysym_to_keycode(SDL_keysym keysym); /*! Helper function to convert between SDL system and the old coding for PC keycodes. This is only used to convert configuration files from the DOS version of Grafx2, where keyboard codes are in in the IBM PC AT form. @param scancode Scancode to convert */ word Key_for_scancode(word scancode); /*! Returns key name in a string. Used to display them in the helpscreens and in the keymapper window. @param Key keycode of the key to translate, including modifiers */ const char * Key_name(word key); /*! Gets the modifiers in our format from the SDL_Mod information. Returns a combination of ::MOD_SHIFT, ::MOD_ALT, ::MOD_CONTROL @param mod SDL modifiers state */ word Key_modifiers(SDLMod mod); grafx2/src/layers.h0000644000076400010400000000231311343525572014677 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2009 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 */ void Button_Layer_add(void); void Button_Layer_remove(void); void Button_Layer_menu(void); void Button_Layer_set_transparent(void); void Button_Layer_get_transparent(void); void Button_Layer_merge(void); void Button_Layer_up(void); void Button_Layer_down(void); void Button_Layer_select(void); void Button_Layer_toggle(void); void Layer_activate(byte layer, short side); grafx2/src/libraw2crtc.h0000644000076400010400000000061011343525574015616 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* GFX2CRTC - libraw2crtc.h * CloudStrife - 20080921 * Diffus sous licence libre CeCILL v2 * Voire LICENCE */ #ifndef LIBRAW2CRTC_H #define LIBRAW2CRTC_H 1 unsigned char * raw2crtc(unsigned short width, unsigned short height, unsigned char mode, unsigned char r9, unsigned long *outSize, unsigned char *r1, unsigned char r12, unsigned char r13); #endif grafx2/src/loadsave.h0000644000076400010400000002116311524346304015175 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file loadsave.h /// Saving and loading different picture formats. /// Also handles showing the preview in fileselectors. ////////////////////////////////////////////////////////////////////////////// #ifndef __LOADSAVE_H__ #define __LOADSAVE_H__ #include #include enum CONTEXT_TYPE { CONTEXT_MAIN_IMAGE, CONTEXT_BRUSH, CONTEXT_PREVIEW, CONTEXT_SURFACE, }; /// Data for a cycling color series. Heavily cloned from T_Gradient_array. typedef struct { byte Start; ///< First color byte End; ///< Last color byte Inverse; ///< Boolean, true if the gradient goes in descending order byte Speed; ///< Frequency of cycling, from 1 (slow) to 64 (fast) } T_Color_cycle; typedef struct { /// Kind of context. Internally used to differentiate the "sub-classes" enum CONTEXT_TYPE Type; // File properties char * File_name; char * File_directory; byte Format; // Image properties T_Palette Palette; short Width; short Height; byte Nb_layers; char Comment[COMMENT_SIZE+1]; byte Background_transparent; byte Transparent_color; /// Pixel ratio of the image enum PIXEL_RATIO Ratio; /// Load/save address of first pixel byte *Target_address; /// Pitch: Difference of addresses between one pixel and the one just "below" it long Pitch; /// Original file name, stored in GIF file char * Original_file_name; /// Original file directory, stored in GIF file char * Original_file_directory; byte Color_cycles; T_Color_cycle Cycle_range[16]; /// Internal: during load, marks which layer is being loaded. short Current_layer; /// Internal: Used to mark truecolor images on loading. Only used by preview. //byte Is_truecolor; /// Internal: Temporary RGB buffer when loading 24bit images T_Components *Buffer_image_24b; /// Internal: Temporary buffer when saving the flattened copy of something byte *Buffer_image; // Internal: working data for preview case short Preview_factor_X; short Preview_factor_Y; short Preview_pos_X; short Preview_pos_Y; byte *Preview_bitmap; byte Preview_usage[256]; // Internal: returned surface for SDL_Surface case SDL_Surface * Surface; } T_IO_Context; #define PREVIEW_WIDTH 120 #define PREVIEW_HEIGHT 80 /// Type of a function that can be called for a T_IO_Context. Kind of a method. typedef void (* Func_IO) (T_IO_Context *); /* void Pixel_load_in_current_screen (word x_pos, word y_pos, byte color); void Pixel_load_in_preview (word x_pos, word y_pos, byte color); void Pixel_load_in_brush (word x_pos, word y_pos, byte color); */ // Setup for loading a preview in fileselector void Init_context_preview(T_IO_Context * context, char *file_name, char *file_directory); // Setup for loading/saving the current main image void Init_context_layered_image(T_IO_Context * context, char *file_name, char *file_directory); // Setup for loading/saving an intermediate backup void Init_context_backup_image(T_IO_Context * context, char *file_name, char *file_directory); // Setup for loading/saving the flattened version of current main image void Init_context_flat_image(T_IO_Context * context, char *file_name, char *file_directory); // Setup for loading/saving the user's brush void Init_context_brush(T_IO_Context * context, char *file_name, char *file_directory); // Setup for saving an arbitrary undo/redo step, from either the main or spare page. void Init_context_history_step(T_IO_Context * context, T_Page *page); // Setup for loading an image into a new SDL surface. void Init_context_surface(T_IO_Context * context, char *file_name, char *file_directory); // Cleans up resources (currently: the 24bit buffer) void Destroy_context(T_IO_Context *context); /// /// High-level picture loading function. void Load_image(T_IO_Context *context); /// /// High-level picture saving function. void Save_image(T_IO_Context *context); /// /// Checks if there are any pending safety backups, and then opens them. /// Returns 0 if there were none /// Returns non-zero if some backups were loaded. int Check_recovery(void); /// Makes a safety backup periodically. void Rotate_safety_backups(void); /// Remove safety backups. Need to call on normal program exit. void Delete_safety_backups(void); /// Data for an image file format. typedef struct { byte Identifier; ///< Identifier for this format in enum :FILE_FORMATS char *Label; ///< Five-letter label Func_IO Test; ///< Function which tests if the file is of this format Func_IO Load; ///< Function which loads an image of this format Func_IO Save; ///< Function which saves an image of this format byte Palette_only; ///< Boolean, true if this format saves/loads only the palette. byte Comment; ///< This file format allows a text comment byte Supports_layers; ///< Boolean, true if this format preserves layers on saving char *Default_extension; ///< Default file extension char *Extensions; ///< List of semicolon-separated file extensions } T_Format; /// Array of the known file formats extern T_Format File_formats[]; /// /// Function which attempts to save backups of the images (main and spare), /// called in case of SIGSEGV. /// It will save an image only if it has just one layer... otherwise, /// the risk of flattening a layered image (or saving just one detail layer) /// is too high. void Image_emergency_backup(void); /// /// Load an arbitrary SDL_Surface. /// @param gradients Pass the address of a target T_Gradient_array if you want the gradients, NULL otherwise SDL_Surface * Load_surface(char *full_name, T_Gradient_array *gradients); /* /// Pixel ratio of last loaded image: one of :PIXEL_SIMPLE, :PIXEL_WIDE or :PIXEL_TALL extern enum PIXEL_RATIO Ratio_of_loaded_image; */ T_Format * Get_fileformat(byte format); // -- File formats /// Total number of known file formats unsigned int Nb_known_formats(void); // Internal use /// Generic allocation and similar stuff, done at beginning of image load, as soon as size is known. void Pre_load(T_IO_Context *context, short width, short height, long file_size, int format, enum PIXEL_RATIO ratio, byte truecolor); /// Remaps the window. To call after palette (last) changes. void Palette_loaded(T_IO_Context *context); /// Generic cleanup done on end of loading (ex: color-conversion from the temporary 24b buffer) //void Post_load(T_IO_Context *context); /// Query the color of a pixel (to save) byte Get_pixel(T_IO_Context *context, short x, short y); /// Set the color of a pixel (on load) void Set_pixel(T_IO_Context *context, short x, short y, byte c); /// Set the color of a 24bit pixel (on load) void Set_pixel_24b(T_IO_Context *context, short x, short y, byte r, byte g, byte b); /// Function to call when need to switch layers. void Set_layer(T_IO_Context *context, byte layer); // ================================================================= // What follows here are the definitions of functions and data // useful for fileformats.c, miscfileformats.c etc. // ================================================================= // This is here and not in fileformats.c because the emergency save uses it... typedef struct { byte Filler1[6]; word Width; word Height; byte Filler2[118]; T_Palette Palette; } T_IMG_Header; // Data for 24bit loading /* typedef void (* Func_24b_display) (short,short,byte,byte,byte); extern int Image_24b; extern T_Components * Buffer_image_24b; extern Func_24b_display Pixel_load_24b; void Init_preview_24b(short width,short height,long size,int format); void Pixel_load_in_24b_preview(short x_pos,short y_pos,byte r,byte g,byte b); */ // void Set_file_error(int value); /* void Init_preview(short width,short height,long size,int format,enum PIXEL_RATIO ratio); */ void Init_write_buffer(void); void Write_one_byte(FILE *file, byte b); void End_write(FILE *file); #endif grafx2/src/misc.h0000644000076400010400000001611711520364016014331 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file misc.h /// Miscellanous unsorted functions. ////////////////////////////////////////////////////////////////////////////// #include "struct.h" #define SWAP_BYTES(a,b) { byte c=a; a=b; b=c;} #define SWAP_WORDS(a,b) { word c=a; a=b; b=c;} #define SWAP_DWORDS(a,b) { dword c=a; a=b; b=c;} #define SWAP_SHORTS(a,b) { short c=a; a=b; b=c;} #define SWAP_FLOATS(a,b) { float c=a; a=b; b=c;} #define SWAP_PBYTES(a,b) { byte * c=a; a=b; b=c;} void Copy_image_to_brush(short start_x,short start_y,short Brush_width,short Brush_height,word image_width); void Remap_general_lowlevel(byte * conversion_table,byte * in_buffer, byte *out_buffer,short width,short height,short buffer_width); void Scroll_picture(byte * main_src, byte * main_dest, short x_offset,short y_offset); void Wait_end_of_click(void); void Set_color(byte color, byte red, byte green, byte blue); void Set_palette(T_Palette palette); void Palette_256_to_64(T_Palette palette); void Palette_64_to_256(T_Palette palette); void Clear_current_image(byte color); void Clear_current_image_with_stencil(byte color, byte * stencil); dword Round_div(dword numerator,dword divisor); word Count_used_colors(dword * usage); word Count_used_colors_area(dword* usage, word start_x, word start_y, word width, word height); word Count_used_colors_screen_area(dword* usage, word start_x, word start_y, word width, word height); void Pixel_in_brush (word x,word y,byte color); byte Read_pixel_from_spare_screen(word x,word y); byte Read_pixel_from_backup_screen (word x,word y); byte Read_pixel_from_feedback_screen (word x,word y); byte Read_pixel_from_brush (word x,word y); void Ellipse_compute_limites(short horizontal_radius,short vertical_radius); // Calcule les valeurs suivantes en fonction des deux paramtres: // // Ellipse_vertical_radius_squared // Ellipse_horizontal_radius_squared // Ellipse_Limit_High // Ellipse_Limit_Low byte Pixel_in_ellipse(void); // Indique si le pixel se trouvant Ellipse_cursor_X pixels // (Ellipse_cursor_X>0 = droite, Ellipse_cursor_X<0 = gauche) et // Ellipse_cursor_Y pixels (Ellipse_cursor_Y>0 = en bas, // Ellipse_cursor_Y<0 = en haut) du centre se trouve dans l'ellipse en // cours. byte Pixel_in_circle(void); // Indique si le pixel se trouvant Circle_cursor_X pixels // (Circle_cursor_X>0 = droite, Circle_cursor_X<0 = gauche) et // Circle_cursor_Y pixels (Circle_cursor_Y>0 = en bas, // Circle_cursor_Y<0 = en haut) du centre se trouve dans le cercle en // cours. // Gestion du chrono dans les fileselects void Init_chrono(dword delay); void Check_timer(void); void Replace_a_color(byte old_color, byte New_color); void Replace_colors_within_limits(byte * replace_table); byte Effect_interpolated_colorize (word x,word y,byte color); byte Effect_additive_colorize (word x,word y,byte color); byte Effect_substractive_colorize(word x,word y,byte color); byte Effect_alpha_colorize(word x,word y,byte color); byte Effect_sieve(word x,word y); /// /// 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); // -- Gestion du chrono -- byte Timer_state; // State du chrono: 0=Attente d'un Xme de seconde // 1=Il faut afficher la preview // 2=Plus de chrono gerer pour l'instant dword Timer_delay; // Nombre de 18.2me de secondes demands dword Timer_start; // Heure de dpart du chrono byte New_preview_is_needed; // Boolen "Il faut relancer le chrono de preview" unsigned long Memory_free(void); #define Num2str(a,b,c) sprintf(b,"%*lu",c,(long)(a)) #define Dec2str(a,b,c) sprintf(b,"%.*f",c,(double)(a)) short Round(float value); short Round_div_max(short numerator,short divisor); /* round number n to d decimal points */ double Fround(double n, unsigned d); int Min(int a,int b); int Max(int a,int b); char* Mode_label(int mode); int Convert_videomode_arg(const char *argument); grafx2/src/mountlist.h0000644000076400010400000000356311343525576015452 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* mountlist.h -- declarations for list of mounted file systems Copyright (C) 1991, 1992, 1998, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This program 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; either version 2, or (at your option) any later version. This program 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 this program; if not, see . */ ////////////////////////////////////////////////////////////////////////////// ///@file mountlist.h /// A function to enumerate the mounting points in the filesystem. /// Used to display them in fileselectors. ////////////////////////////////////////////////////////////////////////////// #ifndef MOUNTLIST_H_ # define MOUNTLIST_H_ #if !defined(__VBCC__) # include #else #define bool char #endif #include /* A mount table entry. */ struct mount_entry { char *me_devname; /* Device node name, including "/dev/". */ char *me_mountdir; /* Mount point directory name. */ char *me_type; /* "nfs", "4.2", etc. */ dev_t me_dev; /* Device number of me_mountdir. */ unsigned int me_dummy : 1; /* Nonzero for dummy file systems. */ unsigned int me_remote : 1; /* Nonzero for remote fileystems. */ unsigned int me_type_malloced : 1; /* Nonzero if me_type was malloced. */ struct mount_entry *me_next; }; struct mount_entry *read_file_system_list (bool need_fs_type); #endif grafx2/src/op_c.h0000644000076400010400000001674411522560062014325 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file op_c.h /// Color reduction and color conversion (24b->8b, RGB<->HSL). /// This is called op_c because half of the process was originally /// coded in op_asm, in assembler. ////////////////////////////////////////////////////////////////////////////// #ifndef _OP_C_H_ #define _OP_C_H_ #include "struct.h" //////////////////////////////////////////////// Dfinition des types de base typedef T_Components * T_Bitmap24B; typedef byte * T_Bitmap256; //////////////////////////////////////// Dfinition d'une table de conversion typedef struct { int nbb_r; // Nb de bits de prcision sur les rouges int nbb_g; // Nb de bits de prcision sur les verts int nbb_b; // Nb de bits de prcision sur les bleu int rng_r; // Nb de valeurs sur les rouges (= 1< */ ////////////////////////////////////////////////////////////////////////////// ///@file operatio.h /// Code for the drawing tools operations. ////////////////////////////////////////////////////////////////////////////// #include "struct.h" // General operation handling functions. These may be moved to ops_handler.h when operatio.c grows over 5000 lines again... /// Do some housekeeping before starting work on a operation. void Start_operation_stack(word new_operation); /// Put a value on ::Operation_stack void Operation_push(short value); /// Take a value off ::Operation_stack void Operation_pop(short * value); void Init_start_operation(void); short Distance(short x1, short y1, short x2, short y2); //////////////////////////////////////////////////// OPERATION_CONTINUOUS_DRAW void Freehand_mode1_1_0(void); void Freehand_mode1_1_2(void); void Freehand_mode12_0_2(void); void Freehand_mode1_2_0(void); void Freehand_mode1_2_2(void); ///////////////////////////////////////////////// OPERATION_DISCONTINUOUS_DRAW void Freehand_mode2_1_0(void); void Freehand_mode2_1_2(void); void Freehand_mode2_2_0(void); void Freehand_mode2_2_2(void); ////////////////////////////////////////////////////// OPERATION_POINT_DRAW void Freehand_mode3_1_0(void); void Freehand_Mode3_2_0(void); void Freehand_mode3_0_1(void); ///////////////////////////////////////////////////////////// OPERATION_LINE void Line_12_0(void); void Line_12_5(void); void Line_0_5(void); ///////////////////////////////////////////////////////////// OPERATION_MAGNIFY void Magnifier_12_0(void); /////////////////////////////////////////////////// OPERATION_RECTANGLE_????? void Rectangle_12_0(void); void Rectangle_12_5(void); void Empty_rectangle_0_5(void); void Filled_rectangle_0_5(void); ////////////////////////////////////////////////////// OPERATION_CERCLE_????? void Circle_12_0(void); void Circle_12_5(void); void Empty_circle_0_5(void); void Filled_circle_0_5(void); ///////////////////////////////////////////////////// OPERATION_ELLIPSE_????? void Ellipse_12_0(void); void Ellipse_12_5(void); void Empty_ellipse_0_5(void); void Filled_ellipse_0_5(void); ////////////////////////////////////////////////////// OPERATION_GRAB_BRUSH void Brush_12_0(void); void Brush_12_5(void); void Brush_0_5(void); ///////////////////////////////////////////////////// OPERATION_STRETCH_BRUSH void Stretch_brush_12_0(void); void Stretch_brush_1_7(void); void Stretch_brush_0_7(void); void Stretch_brush_2_7(void); //////////////////////////////////////////////////// OPERATION_ROTATE_BRUSH void Rotate_brush_12_0(void); 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); ////////////////////////////////////////////////////////////// OPERATION_FILL void Fill_1_0(void); void Fill_2_0(void); ///////////////////////////////////////////////////////// OPERATION_REPLACE void Replace_1_0(void); void Replace_2_0(void); /////////////////////////////////////////////////////////// OPERATION_COLORPICK void Pipette_0_0(void); void Colorpicker_12_0(void); void Colorpicker_1_1(void); void Colorpicker_2_1(void); void Colorpicker_0_1(void); /////////////////////////////////////////////////////////// OPERATION_K_LIGNE void K_line_12_0(void); void K_line_12_6(void); void K_line_0_6(void); void K_line_12_7(void); /////////////////////////////////////////////////// OPERATION_COURBE_?_POINTS void Curve_34_points_1_0(void); void Curve_34_points_2_0(void); void Curve_34_points_1_5(void); void Curve_34_points_2_5(void); void Curve_4_points_0_5(void); void Curve_4_points_1_9(void); void Curve_4_points_2_9(void); void Curve_3_points_0_5(void); void Curve_3_points_0_11(void); void Curve_3_points_12_11(void); ///////////////////////////////////////////////////////////// OPERATION_AIRBRUSH void Airbrush_1_0(void); void Airbrush_2_0(void); void Airbrush_12_2(void); void Airbrush_0_2(void); //////////////////////////////////////////////////////////// OPERATION_*POLY* void Polygon_12_0(void); void Polygon_12_9(void); void Polyfill_12_0(void); void Polyfill_0_8(void); void Polyfill_12_8(void); void Polyfill_12_9(void); void Polyform_12_0(void); void Polyform_12_8(void); void Polyform_0_8(void); void Filled_polyform_12_0(void); void Filled_polyform_12_8(void); void Filled_polyform_0_8(void); void Filled_contour_0_8(void); //////////////////////////////////////////////////////////// OPERATION_SCROLL void Scroll_12_0(void); void Scroll_12_5(void); void Scroll_0_5(void); //////////////////////////////////////////////////// OPERATION_GRAD_CIRCLE void Grad_circle_12_0(void); void Grad_circle_12_6(void); void Grad_circle_0_6(void); void Grad_circle_12_8(void); void Grad_circle_or_ellipse_0_8(void); ////////////////////////////////////////////////// OPERATION_GRAD_ELLIPSE void Grad_ellipse_12_0(void); void Grad_ellipse_12_6(void); void Grad_ellipse_0_6(void); void Grad_ellipse_12_8(void); ///////////////////////////////////////////////// OPERATION_GRAD_RECTANGLE void Grad_rectangle_12_0(void); void Grad_rectangle_12_5(void); void Grad_rectangle_0_5(void); void Grad_rectangle_0_7(void); void Grad_rectangle_12_7(void); void Grad_rectangle_12_9(void); void Grad_rectangle_0_9(void); /////////////////////////////////////////////////// OPERATION_CENTERED_LINES void Centered_lines_12_0(void); void Centered_lines_12_3(void); void Centered_lines_0_3(void); void Centered_lines_12_7(void); void Centered_lines_0_7(void); /////////////////////////////////////////////////// OPERATION_RMB_COLORPICK byte Rightclick_colorpick(byte cursor_visible); void Rightclick_colorpick_2_1(void); void Rightclick_colorpick_0_1(void); grafx2/src/pages.h0000644000076400010400000001141011523551230014463 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file pages.h /// Handler for the Undo/Redo system. ////////////////////////////////////////////////////////////////////////////// #ifndef _PAGES_H_ #define _PAGES_H_ /// /// Pointer to the image to read, while drawing. It's either the last history /// layer page when FX feedback is on, or the history page before it /// when FX feedback is off. extern byte * FX_feedback_screen; ////////////////////////////////////////////////////////////////////////// /////////////////////////// BACKUP /////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// #ifndef NOLAYERS /// The pixels of visible layers, flattened copy. extern T_Bitmap Main_visible_image; /// The pixels of visible layers, flattened copy, used for no-feedback effects. extern T_Bitmap Main_visible_image_backup; /// The index of visible pixels from ::Visible image. Points to the right layer. extern T_Bitmap Main_visible_image_depth_buffer; #endif /// The pixels of visible layers for the spare page, flattened copy. extern T_Bitmap Spare_visible_image; /// /// INDIVIDUAL PAGES /// void Download_infos_page_main(T_Page * page); void Upload_infos_page_main(T_Page * page); /// Add a new layer to latest page of a list. Returns 0 on success. byte Add_layer(T_List_of_pages *list, byte layer); /// Delete a layer from the latest page of a list. Returns 0 on success. byte Delete_layer(T_List_of_pages *list, byte layer); /// Merges the current layer onto the one below it. byte Merge_layer(); // private T_Page * New_page(byte nb_layers); void Download_infos_page_spare(T_Page * page); void Upload_infos_page_spare(T_Page * page); void Clear_page(T_Page * page); void Copy_S_page(T_Page * dest,T_Page * source); /// /// LISTS OF PAGES /// void Init_list_of_pages(T_List_of_pages * list); // private int Allocate_list_of_pages(T_List_of_pages * list); void Backward_in_list_of_pages(T_List_of_pages * list); void Advance_in_list_of_pages(T_List_of_pages * list); void Free_last_page_of_list(T_List_of_pages * list); int Create_new_page(T_Page * new_page,T_List_of_pages * current_list, dword layer_mask); void Change_page_number_of_list(T_List_of_pages * list,int number); void Free_page_of_a_list(T_List_of_pages * list); /// /// BACKUP HIGH-LEVEL FUNCTIONS /// int Init_all_backup_lists(int width,int height); void Set_number_of_backups(int nb_backups); int Backup_new_image(byte layers,int width,int height); int Backup_with_new_dimensions(int width,int height); /// /// Resizes a backup step in-place (doesn't add a Undo/Redo step). /// Should only be called after an actual backup, because it loses the current. /// pixels. This function is meant to be used from within Lua scripts. int Backup_in_place(int width,int height); /// Backup the spare image, the one you don't see. void Backup_the_spare(dword layer_mask); int Backup_and_resize_the_spare(int width,int height); /// Backup with a new copy for the working layer, and references for all others. void Backup(void); /// Backup with a new copy of some layers (the others are references). void Backup_layers(dword layer_mask); void Undo(void); void Redo(void); void Free_current_page(void); // 'Kill' button void Exchange_main_and_spare(void); void End_of_modification(void); void Update_depth_buffer(void); void Redraw_layered_image(void); void Redraw_current_layer(void); void Update_screen_targets(void); /// Update all the special image buffers, if necessary. int Update_buffers(int width, int height); int Update_spare_buffers(int width, int height); void Redraw_spare_image(void); /// /// Must be called after changing the head of Main_backups list, or /// Main_current_layer void Update_FX_feedback(byte with_feedback); /// /// STATISTICS /// /// Total number of unique bitmaps (layers, animation frames, backups) extern long Stats_pages_number; /// Total memory used by bitmaps (layers, animation frames, backups) extern long long Stats_pages_memory; #endif grafx2/src/palette.h0000644000076400010400000000453611522560062015037 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file palette.h /// Palette screen, and some palette-related high-level functions. ////////////////////////////////////////////////////////////////////////////// /// Open the palette menu and handles everything inside it. void Button_Palette(void); /// Open the secondary palette menu and handles it. void Button_Secondary_palette(void); /// Choose the number of graduations for RGB components, from 2 to 256. void Set_palette_RGB_scale(int); int Get_palette_RGB_scale(void); /// /// Scale a component (R, G or B) according to the current RGB graduations. /// Returns the resulting value, in the [0-255] range. byte Round_palette_component(byte comp); /*! Adds 4 menu colors in the current palette. @param color_usage An up-to-date color usage table (byte[256]) (read only) @param not_picture 0 if the caller is the palette screen, 1 if it's a preview in the file selector. */ void Set_nice_menu_colors(dword * color_usage,int not_picture); /// Put some colors in the clipboard. /// @param nb_colors Number of colors to push /// @param colors First color of the input array void Set_clipboard_colors(int nb_colors, T_Components *colors); /// Get some RGB colors from clipboard. /// @param palette Target palette /// @param start_color Index of first color to replace /// @return Number of colors retrieved (0-256) int Get_clipboard_colors(T_Palette palette, byte start_color); /// Get the favorite color to use for GUI's black,dark,light or white. const T_Components * Favorite_GUI_color(byte color_index); grafx2/src/pxdouble.h0000644000076400010400000000633411343525604015225 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file pxdouble.h /// Renderer for double pixels (2x2). ////////////////////////////////////////////////////////////////////////////// #include "struct.h" void Pixel_double (word x,word y,byte color); byte Read_pixel_double (word x,word y); void Block_double (word start_x,word start_y,word width,word height,byte color); void Pixel_preview_normal_double (word x,word y,byte color); void Pixel_preview_magnifier_double (word x,word y,byte color); void Horizontal_XOR_line_double (word x_pos,word y_pos,word width); void Vertical_XOR_line_double (word x_pos,word y_pos,word height); 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); void Display_brush_mono_double (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_double (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_double (word x_pos,word y_pos,word width,word height,byte * conversion_table); void Display_part_of_screen_double (word width,word height,word image_width); void Display_line_on_screen_double (word x_pos,word y_pos,word width,byte * line); void Read_line_screen_double (word x_pos,word y_pos,word width,byte * line); void Display_part_of_screen_scaled_double(word width,word height,word image_width,byte * buffer); void Display_brush_color_zoom_double (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_double (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_double (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_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); void Display_line_on_screen_fast_double (word x_pos,word y_pos,word width,byte * line); grafx2/src/pxquad.h0000644000076400010400000000626511343525604014710 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ ////////////////////////////////////////////////////////////////////////////// ///@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); grafx2/src/pxsimple.h0000644000076400010400000000663511343525606015252 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file pxsimple.h /// Renderer for simple pixels (1x1). This is the normal one. ////////////////////////////////////////////////////////////////////////////// #include "struct.h" void Pixel_simple (word x,word y,byte color); byte Read_pixel_simple (word x,word y); void Block_simple (word start_x,word start_y,word width,word height,byte color); void Pixel_preview_normal_simple (word x,word y,byte color); void Pixel_preview_magnifier_simple (word x,word y,byte color); void Horizontal_XOR_line_simple (word x_pos,word y_pos,word width); void Vertical_XOR_line_simple (word x_pos,word y_pos,word height); void Display_brush_color_simple (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_simple (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_simple (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_simple (word x_pos,word y_pos,word width,word height,byte * conversion_table); void Display_part_of_screen_simple (word width,word height,word image_width); void Display_line_on_screen_simple (word x_pos,word y_pos,word width,byte * line); void Read_line_screen_simple (word x_pos,word y_pos,word width,byte * line); void Display_part_of_screen_scaled_simple(word width,word height,word image_width,byte * buffer); void Display_brush_color_zoom_simple (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_simple (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_simple (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_simple (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_transparent_mono_line_on_screen_simple( word x_pos, word y_pos, word width, byte* line, byte transp_color, byte color); void Display_transparent_line_on_screen_simple(word x_pos,word y_pos,word width,byte* line,byte transp_color); grafx2/src/pxtall.h0000644000076400010400000000617111343525606014710 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file pxtall.h /// Renderer for tall pixels (1x2). ////////////////////////////////////////////////////////////////////////////// #include "struct.h" void Pixel_tall (word x,word y,byte color); byte Read_pixel_tall (word x,word y); void Block_tall (word start_x,word start_y,word width,word height,byte color); void Pixel_preview_normal_tall (word x,word y,byte color); void Pixel_preview_magnifier_tall (word x,word y,byte color); void Horizontal_XOR_line_tall (word x_pos,word y_pos,word width); void Vertical_XOR_line_tall (word x_pos,word y_pos,word height); void Display_brush_color_tall (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_tall (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_tall (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_tall (word x_pos,word y_pos,word width,word height,byte * conversion_table); void Display_part_of_screen_tall (word width,word height,word image_width); void Display_line_on_screen_tall (word x_pos,word y_pos,word width,byte * line); void Read_line_screen_tall (word x_pos,word y_pos,word width,byte * line); void Display_part_of_screen_scaled_tall(word width,word height,word image_width,byte * buffer); void Display_brush_color_zoom_tall (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_tall (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_tall (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_tall (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); grafx2/src/pxtall2.h0000644000076400010400000000631411343525610014764 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ ////////////////////////////////////////////////////////////////////////////// ///@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); grafx2/src/pxtriple.h0000644000076400010400000000633411343525610015247 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ ////////////////////////////////////////////////////////////////////////////// ///@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); grafx2/src/pxwide.h0000644000076400010400000000643711343525612014706 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file pxwide.h /// Renderer for wide pixels (2x1). ////////////////////////////////////////////////////////////////////////////// #include "struct.h" void Pixel_wide (word x,word y,byte color); byte Read_pixel_wide (word x,word y); void Block_wide (word start_x,word start_y,word width,word height,byte color); void Pixel_preview_normal_wide (word x,word y,byte color); void Pixel_preview_magnifier_wide (word x,word y,byte color); void Horizontal_XOR_line_wide (word x_pos,word y_pos,word width); void Vertical_XOR_line_wide (word x_pos,word y_pos,word height); 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); void Display_brush_mono_wide (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_wide (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_wide (word x_pos,word y_pos,word width,word height,byte * conversion_table); void Display_part_of_screen_wide (word width,word height,word image_width); void Display_line_on_screen_wide (word x_pos,word y_pos,word width,byte * line); void Read_line_screen_wide (word x_pos,word y_pos,word width,byte * line); void Display_part_of_screen_scaled_wide(word width,word height,word image_width,byte * buffer); void Display_brush_color_zoom_wide (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_wide (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_wide (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_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); void Display_line_on_screen_fast_wide (word x_pos,word y_pos,word width,byte * line); void Display_transparent_line_on_screen_wide(word x_pos,word y_pos,word width,byte* line,byte transp_color); grafx2/src/pxwide2.h0000644000076400010400000000631411343525612014762 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ ////////////////////////////////////////////////////////////////////////////// ///@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); grafx2/src/readini.h0000644000076400010400000000217311522560062015007 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file readini.h /// Reading settings in gfx2.ini ////////////////////////////////////////////////////////////////////////////// int Load_INI(T_Config * conf); int Load_INI_seek_pattern(char * buffer,char * pattern); void Load_INI_clear_string(char * str, byte keep_comments); grafx2/src/readline.h0000644000076400010400000000575611522560062015171 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file readline.h /// Text input functions. ////////////////////////////////////////////////////////////////////////////// enum INPUT_TYPE { INPUT_TYPE_STRING=0, ///< Any string INPUT_TYPE_INTEGER=1, ///< Decimal integer INPUT_TYPE_FILENAME=2,///< Filename INPUT_TYPE_DECIMAL=3, ///< Decimal value INPUT_TYPE_HEXA=4, ///< Hexadecimal integer }; /// /// Lets the user input a line of text, exit by Esc or Return. /// @param x_pos Coordinates of input, in window coordinates before scaling. /// @param y_pos Coordinates of input, in window coordinates before scaling. /// @param str The original string value (will be modified, unless user cancels. /// @param visible_size Number of characters visible and editable. /// @param input_type one of enum ::INPUT_TYPE /// @return 0 if user cancelled (esc), 1 if accepted (return) byte Readline(word x_pos,word y_pos,char * str,byte visible_size,byte input_type); /// /// Lets the user input a line of text, exit by Esc or Return. /// @param x_pos Coordinates of input, in window coordinates before scaling. /// @param y_pos Coordinates of input, in window coordinates before scaling. /// @param str The original string value (will be modified, unless user cancels. /// @param visible_size Number of characters visible. /// @param max_size Number of characters editable. /// @param input_type one of enum ::INPUT_TYPE /// @param decimal_places Number of decimal places (used only with decimal type) /// @return 0 if user cancelled (esc), 1 if accepted (return) byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_size, byte input_type, byte decimal_places); /// /// Converts a double to string. /// @param str Target string, should be pre-allocated and at least 40 characters, to be safe. /// @param value The number to convert /// @param decimal_places Number of decimal places to keep. 15 seems the maximum. /// @param min_positions Minimum number of characters: Will pad spaces on the left to meet this minimum. void Sprint_double(char *str, double value, byte decimal_places, byte min_positions); grafx2/src/realpath.h0000644000076400010400000000240311343525616015177 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Adrien Destugues 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file realpath.h /// Implementation of realpath() that is portable on all our platforms. ////////////////////////////////////////////////////////////////////////////// #ifndef _REALPATH_H #define _REALPATH_H /// /// Makes an absolute filename, resolving symbolic links etc. /// @param _path Input path /// @param resolved_path Output path, allocated by caller /// @return (points to resolved_path) char *Realpath(const char *_path, char *resolved_path); #endif grafx2/src/saveini.h0000644000076400010400000000200511522560062015024 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file saveini.h /// Saving settings in gfx2.ini ////////////////////////////////////////////////////////////////////////////// int Save_INI(T_Config * conf); grafx2/src/sdlscreen.h0000644000076400010400000000555111552354252015366 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file sdlscreen.h /// Screen update (refresh) system, and some SDL-specific graphic functions. ////////////////////////////////////////////////////////////////////////////// #ifndef SDLSCREEN_H_INCLUDED #define SDLSCREEN_H_INCLUDED #include #include "struct.h" /// /// 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) void Set_mode_SDL(int *,int *,int); 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); void Update_status_line(short char_pos, short width); /// /// 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); /// Gets the RGB 24-bit color currently associated with a palette index. SDL_Color Color_to_SDL_color(byte); /// Reads a pixel in a 8-bit SDL surface. byte Get_SDL_pixel_8(SDL_Surface *bmp, int x, int y); /// Reads a pixel in a multi-byte SDL surface. dword Get_SDL_pixel_hicolor(SDL_Surface *bmp, int x, int y); /// Writes a pixel in a 8-bit SDL surface. void Set_SDL_pixel_8(SDL_Surface *bmp, int x, int y, byte color); /// Convert a SDL Palette to a grafx2 palette void Get_SDL_Palette(const SDL_Palette * sdl_palette, T_Palette palette); /// /// 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); extern volatile int Allow_colorcycling; /// Activates or desactivates file drag-dropping in program window. void Allow_drag_and_drop(int flag); #endif // SDLSCREEN_H_INCLUDED grafx2/src/setup.h0000644000076400010400000001141211524035602014527 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2008 Peter Gordon 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file setup.h /// Functions that determine where grafx2 is running, finds its data, and /// reads and writes configuration files. ////////////////////////////////////////////////////////////////////////////// /// /// Determine which directory contains the executable. /// - IN: Main's argv[0], some platforms need it, some don't. /// - OUT: Write into program_dir. Trailing / or \ is kept. /// Note : in fact this is only used to check for the datafiles and fonts in this same directory. void Set_program_directory(const char * argv0,char * program_dir); /// /// Determine which directory contains the read-only data. /// IN: The directory containing the executable /// OUT: Write into data_dir. Trailing / or \ is kept. void Set_data_directory(const char * program_dir, char * data_dir); /// /// Determine which directory should store the user's configuration. /// For most Unix and Windows platforms: /// If a config file already exists in program_dir, it will return it in priority /// (Useful for development, and possibly for upgrading from DOS version) /// If the standard directory doesn't exist yet, this function will attempt /// to create it ($(HOME)/.grafx2, or %APPDATA%\\GrafX2) /// If it cannot be created, this function will return the executable's /// own directory. /// IN: The directory containing the executable /// OUT: Write into config_dir. Trailing / or \ is kept. void Set_config_directory(const char * program_dir, char * config_dir); /// Name of the subdirectory containing fonts, under the data directory (::Set_data_directory()) #if defined (__MINT__) #define FONTS_SUBDIRECTORY "FONTS" #else #define FONTS_SUBDIRECTORY "fonts" #endif /// Name of the subdirectory containing fonts, under the data directory (::Set_data_directory()) #if defined (__MINT__) #define SKINS_SUBDIRECTORY "SKINS" #else #define SKINS_SUBDIRECTORY "skins" #endif /// Name of the binary file containing some configuration settings. #if defined (__MINT__) #define CONFIG_FILENAME "GFX2.CFG" #else #define CONFIG_FILENAME "gfx2.cfg" #endif /// Name of the text file containing some settings in INI format. #if defined (__MINT__) #define INI_FILENAME "GFX2.INI" #else #define INI_FILENAME "gfx2.ini" #endif /// Name of the backup of the INI file. #if defined (__MINT__) #define INISAVE_FILENAME "GFX2.$$$" #else #define INISAVE_FILENAME "gfx2.$$$" #endif /// Name of the default .INI file (read-only: gives .INI format and defaults) #if defined (__MINT__) #define INIDEF_FILENAME "GFX2DEF.INI" #else #define INIDEF_FILENAME "gfx2def.ini" #endif /// Prefix for filenames of safety backups (main) #if defined (__MINT__) #define SAFETYBACKUP_PREFIX_A "A" #else #define SAFETYBACKUP_PREFIX_A "a" #endif /// Prefix for filenames of safety backups (spare) #if defined (__MINT__) #define SAFETYBACKUP_PREFIX_B "B" #else #define SAFETYBACKUP_PREFIX_B "b" #endif /// Name of the image file that serves as an application icon. #if defined (__MINT__) #define GFX2_ICON_FILENAME "GFX2.GIF" #else #define GFX2_ICON_FILENAME "gfx2.gif" #endif /// Name of the image file for the default (and fallback) GUI skin. #if defined (__MINT__) #define DEFAULT_SKIN_FILENAME "SDPAINT.PNG" #else #define DEFAULT_SKIN_FILENAME "skin_DPaint.png" #endif /// Name of the image file for the default (and fallback) 8x8 font. #if defined (__MINT__) #define DEFAULT_FONT_FILENAME "FDPAINT.PNG" #else #define DEFAULT_FONT_FILENAME "font_DPaint.png" #endif /// File extension for safety backups #if defined (__MINT__) #define BACKUP_FILE_EXTENSION ".BKP" #else #define BACKUP_FILE_EXTENSION ".bkp" #endif /// File prefix for fonts #if defined (__MINT__) #define FONT_PREFIX "F" #else #define FONT_PREFIX "font_" #endif /// File prefix for skins #if defined (__MINT__) #define SKIN_PREFIX "S" #else #define SKIN_PREFIX "skin_" #endif grafx2/src/shade.h0000644000076400010400000000220711522560062014456 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file shade.h /// Screens for Shade and Quick-shade settings. ////////////////////////////////////////////////////////////////////////////// #ifndef SHADE_H_INCLUDED #define SHADE_H_INCLUDED void Button_Quick_shade_menu(void); int Shade_settings_menu(void); #endif // SHADE_H_INCLUDED grafx2/src/special.h0000644000076400010400000000355411522560062015020 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program 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 */ #include "struct.h" ////////////////////////////////////////////////////////////////////////////// ///@file special.h /// Editor functions that can be hooked to a keyboard shortcut, but don't have /// a menu button associated to them. ////////////////////////////////////////////////////////////////////////////// void Set_paintbrush_size(int width, int height); void Smaller_paintbrush(void); void Bigger_paintbrush(void); void Special_next_forecolor(void); void Special_previous_forecolor(void); void Special_next_backcolor(void); void Special_previous_backcolor(void); void Special_next_user_forecolor(void); void Special_previous_user_forecolor(void); void Special_next_user_backcolor(void); void Special_previous_user_backcolor(void); void Scroll_screen(short delta_x,short delta_y); void Scroll_magnifier(short delta_x,short delta_y); void Zoom(short delta); void Zoom_set(int index); void Display_stored_brush_in_window(word x,word y,int number); void Store_brush(int index); byte Restore_brush(int index); /*! Command that sets the transparency level. */ void Transparency_set(byte amount); grafx2/src/struct.h0000644000076400010400000006516311546416000014726 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file struct.h /// Structures that can be used in the whole program. ////////////////////////////////////////////////////////////////////////////// #ifndef _STRUCT_H_ #define _STRUCT_H_ #if defined(__BEOS__) || defined(__TRU64__) #include #else #include #endif #include "const.h" // POSIX calls it strcasecmp, Windows uses stricmp... no ANSI standard. #ifdef WIN32 #define strcasecmp stricmp #endif // Definition of the base data types /// 8bit unsigned integer #define byte uint8_t /// 16bit unsigned integer #define word uint16_t /// 32bit unsigned integer #define dword uint32_t /// 64bit unsigned integer #define qword uint64_t // Named function prototypes // GrafX2 use a lot of function pointer to do the drawing depending in the "fake hardware zoom" and the magnifier status. typedef void (* Func_action) (void); ///< An action. Used when you click a menu button or trigger a keyboard shortcut. typedef void (* Func_pixel) (word,word,byte); ///< Set pixel at position (x,y) to color c. Used in load screen to write the data to brush, picture, or preview area. typedef byte (* Func_read) (word,word); ///< Read a pixel at position (x,y) on something. Used for example in save to tell if the data is a brush or a picture typedef void (* Func_clear) (byte); typedef void (* Func_display) (word,word,word); typedef byte (* Func_effect) (word,word,byte); ///< Called by all drawing tools to draw with a special effect (smooth, transparency, shade, ...) typedef void (* Func_block) (word,word,word,word,byte); typedef void (* Func_line_XOR) (word,word,word); ///< Draw an XOR line on the picture view of the screen. Use a different function when in magnify mode. typedef void (* Func_display_brush_color) (word,word,word,word,word,word,byte,word); typedef void (* Func_display_brush_mono) (word,word,word,word,word,word,byte,byte,word); typedef void (* Func_gradient) (long,short,short); typedef void (* Func_remap) (word,word,word,word,byte *); typedef void (* Func_procsline) (word,word,word,byte *); typedef void (* Func_display_zoom) (word,word,word,byte *); typedef void (* Func_display_brush_color_zoom) (word,word,word,word,word,word,byte,word,byte *); typedef void (* Func_display_brush_mono_zoom) (word,word,word,word,word,word,byte,byte,word,byte *); typedef void (* Func_draw_brush) (byte *,word,word,word,word,word,word,byte,word); typedef void (* Func_draw_list_item) (word,word,word,byte); ///< Draw an item inside a list button. This is done with a callback so it is possible to draw anything, as the list itself doesn't handle the content /// A set of RGB values. #ifdef __GNUC__ typedef struct { byte R; ///< Red byte G; ///< Green byte B; ///< Blue } __attribute__((__packed__)) T_Components, T_Palette[256] ; ///< A complete 256-entry RGB palette (768 bytes). #else #pragma pack(1) typedef struct { byte R; ///< Red byte G; ///< Green byte B; ///< Blue } T_Components, T_Palette[256] ; ///< A complete 256-entry RGB palette (768 bytes). #pragma pack() #endif /// A normal rectangular button in windows and menus. typedef struct T_Normal_button { short Number; ///< Unique identifier for all controls word Pos_X; ///< Coordinate for top of button, relative to the window, before scaling. word Pos_Y; ///< Coordinate for left of button, relative to the window, before scaling. word Width; ///< Width before scaling word Height; ///< Height before scaling byte Clickable; ///< Boolean, unused. byte Repeatable; ///< Boolean, true if the button activates repeatedly until you release the mouse button. Used for "+" buttons, for example. word Shortcut; ///< Keyboard shortcut that will emulate a click on this button. struct T_Normal_button * Next;///< Pointer to the next normal button of current window. } T_Normal_button; /// A window control that shows a complete 256-color palette typedef struct T_Palette_button { short Number; ///< Unique identifier for all controls word Pos_X; ///< Coordinate for top of button, relative to the window, before scaling. word Pos_Y; ///< Coordinate for left of button, relative to the window, before scaling. struct T_Palette_button * Next;///< Pointer to the next palette of current window. } T_Palette_button; /// A window control that represents a scrollbar, with a slider, and two arrow buttons. typedef struct T_Scroller_button { short Number; ///< Unique identifier for all controls byte Is_horizontal; ///< Boolean: True if slider is horizontal instead of vertical. word Pos_X; ///< Coordinate for top of button, relative to the window, before scaling. word Pos_Y; ///< Coordinate for left of button, relative to the window, before scaling. word Length; ///< Length before scaling. word Nb_elements; ///< Number of distinct values it can take. word Nb_visibles; ///< If this slider is meant to show several elements of a collection, this is their number (otherwise, it's 1). word Position; ///< Current position of the slider: which item it's pointing. word Cursor_length; ///< Dimension of the slider, in pixels before scaling. struct T_Scroller_button * Next;///< Pointer to the next scroller of current window. } T_Scroller_button; /// Special invisible button /// A window control that only has a rectangular "active" area which catches mouse clicks, // but no visible shape. It's used for custom controls where the drawing is done on // a case by case basis. typedef struct T_Special_button { short Number; ///< Unique identifier for all controls word Pos_X; ///< Coordinate for top of button, relative to the window, before scaling. word Pos_Y; ///< Coordinate for left of button, relative to the window, before scaling. word Width; ///< Width before scaling word Height; ///< Height before scaling struct T_Special_button * Next;///< Pointer to the next special button of current window. } T_Special_button; /// Data for a dropdown item, ie. one proposed choice. typedef struct T_Dropdown_choice { short Number; ///< Value that identifies the choice (for this dropdown only) const char * Label; ///< String to display in the dropdown panel struct T_Dropdown_choice * Next;///< Pointer to the next choice for this dropdown. } T_Dropdown_choice; /// A window control that behaves like a dropdown button. typedef struct T_Dropdown_button { short Number; ///< Unique identifier for all controls word Pos_X; ///< Coordinate for top of button, relative to the window, before scaling. word Pos_Y; ///< Coordinate for left of button, relative to the window, before scaling. word Width; ///< Width before scaling word Height; ///< Height before scaling byte Display_choice; ///< Boolean, true if the engine should print the selected item's label in the dropdown area when the user chooses it. byte Display_centered; ///< Boolean, true to center the labels (otherwise, align left) byte Display_arrow; ///< Boolean, true to display a "down" arrow box in top right byte Bottom_up; ///< Boolean, true to make the dropdown panel go above its button instead of below it byte Active_button; ///< Determines which mouse button(s) cause the dropdown panel to open: LEFT_SIDE || RIGHT_SIDE || (LEFT_SIDE|RIGHT_SIDE) word Dropdown_width; ///< Width of the dropdown panel when it's open. Use 0 for "same as the dropdown button" T_Dropdown_choice * First_item; ///< Linked list with the choices available for this dropdown. struct T_Dropdown_button * Next;///< Pointer to the next dropdown button of current window. } T_Dropdown_button; /// Data for one item (file, directory) in a fileselector. typedef struct T_Fileselector_item { char Full_name[256]; ///< Filesystem value. byte Type; ///< Type of item: 0 = File, 1 = Directory, 2 = Drive byte Icon; ///< One of ::ICON_TYPES, ICON_NONE for none. struct T_Fileselector_item * Next; ///< Pointer to next item of the current fileselector. struct T_Fileselector_item * Previous;///< Pointer to previous item of the current fileselector. word Length_short_name; ///< Number of bytes allocated for :Short_name #if __GNUC__ < 3 char Short_name[0]; ///< Name to display. #else char Short_name[]; ///< Name to display. #endif // No field after Short_name[] ! Dynamic allocation according to name length. } T_Fileselector_item; /// Data for a fileselector typedef struct T_Fileselector { /// Number of elements in the current fileselector's ::Filelist short Nb_elements; /// Number of files in the current fileselector's ::Filelist short Nb_files; /// Number of directories in the current fileselector's ::Filelist short Nb_directories; /// Head of the linked list for the fileselector. T_Fileselector_item * First; /// Index for direct access to element number N T_Fileselector_item ** Index; } T_Fileselector; /// "List" button as used in the font selection, skin selection, and brush factory screens. It's like a limited filelist. /// The screenmode selection and load/save screen were written before this existed so they use their own code. It would be nice if they were updated to use this one. typedef struct T_List_button { short Number; ///< Unique identifier for all controls short List_start; ///< Index of the font to appear as first line short Cursor_position; ///< Index of the selected line (0=top) T_Special_button * Entry_button; ///< Pointer to the associated selection control. T_Scroller_button * Scroller; ///< Pointer to the associated scroller Func_draw_list_item Draw_list_item; ///< Function to call for each item to draw its line byte Color_index; ///< Background color: From 0->MC_Black to 3->MC_White struct T_List_button * Next; ///< Pointer to the next list button of current window. } T_List_button; /// A stackable window (editor screen) typedef struct { word Pos_X; word Pos_Y; word Width; word Height; word Nb_buttons; T_Normal_button *Normal_button_list; T_Palette_button *Palette_button_list; T_Scroller_button *Scroller_button_list; T_Special_button *Special_button_list; T_Dropdown_button *Dropdown_button_list; T_List_button *List_button_list; int Attribute1; int Attribute2; byte Draggable; } T_Window; /// Data for one line of the "Help" screens. typedef struct { char Line_type; ///< Kind of line: 'N' for normal line, 'S' for a bold line, 'K' for a line with keyboard shortcut, 'T' and '-' for upper and lower titles. char * Text; ///< Displayed string. int Line_parameter; ///< Generic parameter depending on line type. For 'K' lines: a shortcut identifier. For others: unused. } T_Help_table; /// Data for one section of the "Help" screens, ie a page. typedef struct { const T_Help_table* Help_table; ///< Pointer to the array of ::T_Help_table that contains the lines word Length; ///< Size of the array of lines } T_Help_section; /// Data for one setting of gradients. Warning, this one is saved/loaded as binary. typedef struct { byte Start; ///< First color byte End; ///< Last color dword Inverse; ///< Boolean, true if the gradient goes in descending order dword Mix; ///< Amount of randomness to add to the mix (0-255) dword Technique;///< Gradient technique: 0 (no pattern) 1 (dithering), or 2 (big dithering) byte Speed; ///< Speed of cycling. 0 for disabled, 1-64 otherwise. } T_Gradient_range; /// Data for a full set of gradients. typedef struct { int Used; ///< Reference count T_Gradient_range Range[16]; } T_Gradient_array; /// Data for one setting of shade. Warning, this one is saved/loaded as binary. typedef struct { word List[512]; ///< List of entries, each one is either a color (0-255) or -1 for empty. byte Step; ///< Step to increment/decrement on left-clicks. byte Mode; ///< Shade mode: Normal, Loop, or No-saturation see ::SHADE_MODES } T_Shade; /// Data for one fullscreen video mode in configuration file. Warning, this one is saved/loaded as binary. typedef struct { byte State; ///< How good is the mode supported. 0:Good (white) 1:OK (light) 2:So-so (dark) 4:User-disabled (black); +128 => System doesn't support it at all. word Width; ///< Videomode width in pixels. word Height;///< Videomode height in pixels. } T_Config_video_mode; /// Header for gfx2.cfg typedef struct { char Signature[3]; ///< Signature for the file format. "CFG". byte Version1; ///< Major version number (ex: 2) byte Version2; ///< Minor version number (ex: 0) byte Beta1; ///< Major beta version number (ex: 96) byte Beta2; ///< Major beta version number (ex: 5) } T_Config_header; /// Header for a config chunk in for gfx2.cfg typedef struct { byte Number; ///< Section identfier. Possible values are in enum ::CHUNKS_CFG word Size; ///< Size of the configuration block that follows, in bytes. } T_Config_chunk; /// Configuration for one keyboard shortcut in gfx2.cfg typedef struct { word Number; ///< Indicates the shortcut action. This is a number starting from 0, which matches ::T_Key_config.Number word Key; ///< Keyboard shortcut: SDLK_something, or -1 for none word Key2; ///< Alternate keyboard shortcut: SDLK_something, or -1 for none } T_Config_shortcut_info; /// This structure holds all the settings saved and loaded as gfx2.ini. typedef struct { char *Font_file; ///< Name of the font used in the menus. Matches file skins/font_*.png (Case-sensitive on some filesystems) char *Skin_file; ///< String, name of the file where all the graphic data is stored int Show_hidden_files; ///< Boolean, true to show hidden files in fileselectors. int Show_hidden_directories; ///< Boolean, true to show hidden directories in fileselectors. // int Show_system_directories; ///< (removed when converted from DOS) byte Display_image_limits; ///< Boolean, true to display a dotted line at the borders of the image if it's smaller than screen. byte Cursor; ///< Mouse cursor aspect: 1 Solid, 2 Transparent, 3 Thin byte Maximize_preview; ///< Boolean, true to make previews in fileselector fit the whole rectangle. byte Auto_set_res; ///< Boolean, true to make grafx2 switch to a new resolution whenever you load an image. byte Coords_rel; ///< Boolean, true to display coordinates as relative (instead of absolute) byte Backup; ///< Boolean, true to backup the original file whenever you save an image. byte Adjust_brush_pick; ///< Boolean, true to omit the right and bottom edges when grabbing a brush in Grid mode. byte Auto_save; ///< Boolean, true to save configuration when exiting program. byte Max_undo_pages; ///< Number of steps to memorize for Undo/Redo. byte Mouse_sensitivity_index_x; ///< Mouse sensitivity in X axis byte Mouse_sensitivity_index_y; ///< Mouse sensitivity in Y axis byte Mouse_merge_movement; ///< Number of SDL mouse events that are merged into a single change of mouse coordinates. byte Delay_left_click_on_slider; ///< Delay (in 1/100s) between two activations of a repeatable button when you hold left-click. byte Delay_right_click_on_slider; ///< Delay (in 1/100s) between two activations of a repeatable button when you hold left-click. long Timer_delay; ///< Delay (in 1/55s) before showing a preview in a fileselector. T_Components Fav_menu_colors[4]; ///< Favorite colors to use for the menu. int Nb_max_vertices_per_polygon; ///< Limit for the number of vertices in polygon tools. byte Clear_palette; ///< Boolean, true to reset the palette (to black) before loading an image. byte Set_resolution_according_to; ///< When Auto_set_res is on, this determines if the mode should be chosen according to the "original screen" information in the file (1) or the picture dimensons (2) int8_t Ratio; ///< Determines the scaling of menu and windows: 0 no scaling, 1 scaling, 2 slight scaling, negative= opposite of max scaling byte Fast_zoom; ///< Boolean, true if the magnifier shortcut should automatically view the mouse area. byte Find_file_fast; ///< In fileselectors, this determines which entries should be sought when typing letters: 0 all, 1 files only, 2 directories only. byte Separate_colors; ///< Boolean, true if the menu palette should separate color cells with a black outline. word Palette_cells_X; ///< Number of colors to show in a row of the menu palette. word Palette_cells_Y; ///< Number of colors to show in a column of the menu palette. byte Palette_vertical; ///< Boolean, true if the menu palette should go top to bottom instead of left to right byte FX_Feedback; ///< Boolean, true if drawing effects should read the image being modified (instead of the image before clicking) byte Safety_colors; ///< Boolean, true to make the palette automatically re-create menu colors if needed after a "Zap" or color reduction. byte Opening_message; ///< Boolean, true to display the splash screen on strtup. byte Clear_with_stencil; ///< Boolean, true to take the stencil into effect (if active) when using the Clear function. byte Auto_discontinuous; ///< Boolean, true to automatically switch to the discontinuous freehand draw after grabbing a brush. byte Screen_size_in_GIF; ///< Boolean, true to store current resolution in GIF files. byte Auto_nb_used; ///< Boolean, true to count colors in Palette screen. byte Default_resolution; ///< Default video mode to use on startup. Index in ::Video_mode. char *Bookmark_directory[NB_BOOKMARKS];///< Bookmarked directories in fileselectors: This is the full directory name. char Bookmark_label[NB_BOOKMARKS][8+1];///< Bookmarked directories in fileselectors: This is the displayed name. int Window_pos_x; ///< Last window x position (9999 if unsupportd/irrelevant for the platform) int Window_pos_y; ///< Last window y position (9999 if unsupportd/irrelevant for the platform) word Double_click_speed; ///< Maximum delay for double-click, in ms. word Double_key_speed; ///< Maximum delay for double-keypress, in ms. byte Grid_XOR_color; ///< XOR value to apply for grid color. byte Right_click_colorpick; ///< Boolean, true to enable a "tablet" mode, where RMB acts as instant colorpicker byte Sync_views; ///< Boolean, true when the Main and Spare should share their viewport settings. byte Stylus_mode; ///< Boolean, true to tweak some tools (eg:Curve) for single-button stylus. word Swap_buttons; ///< Sets which key swaps mouse buttons : 0=none, or MOD_CTRL, or MOD_ALT. char Scripts_directory[MAX_PATH_CHARACTERS];///< Full pathname of directory for Lua scripts byte Allow_multi_shortcuts; ///< Boolean, true if the same key combination can trigger multiple shortcuts. } T_Config; // Structures utilisées pour les descriptions de pages et de liste de pages. // Lorsqu'on gérera les animations, il faudra aussi des listes de listes de // pages. // Ces structures sont manipulées à travers des fonctions de gestion du // backup dans "graph.c". /// This is the data for one step of Undo/Redo, for one image. /// This structure is resized dynamically to hold pointers to all of the layers in the picture. /// The pointed layers are just byte* holding the raw pixel data. But at Image[0]-1 you will find a short that is used as a reference counter for each layer. /// This way we can use the same pixel data in many undo pages when the user edit only one of the layers (which is what they usually do). typedef struct T_Page { int Width; ///< Image width in pixels. int Height; ///< Image height in pixels. T_Palette Palette; ///< Image palette. char Comment[COMMENT_SIZE+1]; ///< Comment to store in the image file. char File_directory[MAX_PATH_CHARACTERS];///< Directory that contains the file. char Filename[MAX_PATH_CHARACTERS]; ///< Filename without directory. byte File_format; ///< File format, in enum ::FILE_FORMATS struct T_Page *Next; ///< Pointer to the next backup struct T_Page *Prev; ///< Pointer to the previous backup T_Gradient_array *Gradients; ///< Pointer to the gradients used by the image. byte Background_transparent; ///< Boolean, true if Layer 0 should have transparent pixels byte Transparent_color; ///< Index of transparent color. 0 to 255. byte Nb_layers; ///< Number of layers #if __GNUC__ < 3 byte * Image[0]; #else byte * Image[]; ///< Pixel data for the (first layer of) image. #endif // Define as Image[0] if you have an old gcc which is not C99. // No field after Image[] ! Dynamic layer allocation for Image[1], [2] etc. } T_Page; /// Collection of undo/redo steps. typedef struct { int List_size; ///< Number of ::T_Page in the vector "Pages". T_Page * Pages; ///< Head of a linked list of pages, each one being a undo/redo step. } T_List_of_pages; /// A single image bitmap /// This struct is used to store a flattened view of the current picture. typedef struct { int Width; ///< Image width in pixels. int Height; ///< Image height in pixels. byte * Image; ///< Pixel data for the image. } T_Bitmap; /// A single memorized brush from the Brush Container typedef struct { byte Paintbrush_shape; ///< Kind of brush byte Thumbnail[BRUSH_CONTAINER_PREVIEW_WIDTH][BRUSH_CONTAINER_PREVIEW_HEIGHT]; // Data for color brush word Width; word Height; byte * Brush; /// < Color brush (if any) T_Palette Palette; byte Colormap[256]; byte Transp_color; } T_Brush_template; /// GUI skin data typedef struct { // Mouse /// X coordinate of the mouse cursor's "hot spot". It is < ::CURSOR_SPRITE_WIDTH word Cursor_offset_X[NB_CURSOR_SPRITES]; /// Y coordinate of the mouse cursor's "hot spot". It is < ::CURSOR_SPRITE_HEIGHT word Cursor_offset_Y[NB_CURSOR_SPRITES]; /// Graphic resources for the mouse cursor. byte Cursor_sprite[NB_CURSOR_SPRITES][CURSOR_SPRITE_HEIGHT][CURSOR_SPRITE_WIDTH]; // Sieve patterns /// Preset sieve patterns, stored as binary (one word per line) word Sieve_pattern[12][16]; // Menu and other graphics /// Bitmap data for the menu, a single rectangle. byte Menu_block[3][35][MENU_WIDTH]; byte Layerbar_block[3][10][144]; byte Statusbar_block[3][9][20]; /// Bitmap data for the icons that are displayed over the menu. byte Menu_sprite[2][NB_MENU_SPRITES][MENU_SPRITE_HEIGHT][MENU_SPRITE_WIDTH]; /// Bitmap data for the different "effects" icons. byte Effect_sprite[NB_EFFECTS_SPRITES][EFFECT_SPRITE_HEIGHT][EFFECT_SPRITE_WIDTH]; /// Bitmap data for the different Layer icons. byte Layer_sprite[3][16][LAYER_SPRITE_HEIGHT][LAYER_SPRITE_WIDTH]; /// Bitmap data for the Grafx2 logo that appears on splash screen. All 256 colors allowed. byte Logo_grafx2[231*56]; /// Bitmap data for the 6x8 font used in help screens. byte Help_font_norm [256][6][8]; /// Bitmap data for the 6x8 font used in help screens ("bold" verstion). byte Bold_font [256][6][8]; // 12 // 34 /// Bitmap data for the title font used in help screens. Top-left quarter. byte Help_font_t1 [64][6][8]; /// Bitmap data for the title font used in help screens. Top-right quarter. byte Help_font_t2 [64][6][8]; /// Bitmap data for the title font used in help screens. Bottom-left quarter. byte Help_font_t3 [64][6][8]; /// Bitmap data for the title font used in help screens. Bottom-right quarter. byte Help_font_t4 [64][6][8]; /// Bitmap data for the small 8x8 icons. byte Icon_sprite[NB_ICON_SPRITES][ICON_SPRITE_HEIGHT][ICON_SPRITE_WIDTH]; /// A default 256-color palette. T_Palette Default_palette; /// Preview for displaying in the skin dialog byte Preview[16][173]; /// GUI color indices in skin palette: black, dark, light, white. byte Color[4]; /// Transparent GUI color index in skin file byte Color_trans; } T_Gui_skin; typedef struct { // Preset paintbrushes /// Graphic resources for the preset paintbrushes. byte Sprite[PAINTBRUSH_HEIGHT][PAINTBRUSH_WIDTH]; /// Width of the preset paintbrushes. word Width; /// Height of the preset paintbrushes. word Height; /// Type of the preset paintbrush: index in enum PAINTBRUSH_SHAPES byte Shape; /// Brush handle for the preset brushes. Generally ::Width[]/2 word Offset_X; /// Brush handle for the preset brushes. Generally ::Height[]/2 word Offset_Y; } T_Paintbrush; // A menubar. typedef struct { word Width; word Height; byte Visible; word Top; ///< Relative to the top line of the menu, hidden bars don't count. byte* Skin[3]; ///< [0] has normal buttons, [1] has selected buttons, [2] is current. word Skin_width; byte Last_button_index; } T_Menu_Bar; typedef enum { MENUBAR_STATUS = 0, // MUST be 0 MENUBAR_LAYERS, MENUBAR_TOOLS, MENUBAR_COUNT } T_Menubars; #endif grafx2/src/text.h0000644000076400010400000000523111523100334014347 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2008 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file text.h /// Functions related to rendering text as a brush, using TrueType or SFont. ////////////////////////////////////////////////////////////////////////////// /// Initialization of text settings, needs to be called once on program startup. void Init_text(void); /// Returns true if text.c was compiled with TrueType support. int TrueType_is_supported(void); /// Add a new font to the list to propose to the user. void Add_font(const char *name); /// /// Creates a brush, from the parameters given: /// @param str The text to render /// @param font_number The index of the font to use. Pass 0 for the first font you declared with ::Add_font(), 1 for the second etc. /// @param size The size in points (unused for bitmap fonts) /// @param antialias Boolean, true to use antialiasing in TrueType /// @param bold Boolean, true to use bold rendering in TrueType /// @param italic Boolean, true to use italic rendering in TrueType /// @param width Returns the width of the created brush, in pixels. /// @param height Returns the height of the created brush, in pixels. /// @param palette Returns the custom palette for the brush. /// Returns true on success. byte *Render_text(const char *str, int font_number, int size, int antialias, int bold, int italic, int *width, int *height, T_Palette palette); /// Finds a label to display for a font declared with ::Add_font(). char * Font_label(int index); /// Finds the filename of a font declared with ::Add_font(). char * Font_name(int index); /// Returns true if the font of this number is TrueType, false if it's a SFont bitmap. int TrueType_font(int index); /// /// Number of fonts declared with a series of ::Add_font(). This is public for /// convenience, but functionaly it is read-only. extern int Nb_fonts; grafx2/src/transform.h0000644000076400010400000000215511343525632015414 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file transform.h /// Screen and functions for picture transform. ////////////////////////////////////////////////////////////////////////////// /// Opens and handles the Picture transform screen. void Button_Transform_menu(void); grafx2/src/windows.h0000644000076400010400000001141111525510174015063 0ustar vigAdministrator/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007-2008 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 */ ////////////////////////////////////////////////////////////////////////////// ///@file windows.h /// Graphical interface management functions (windows, menu, cursor) ////////////////////////////////////////////////////////////////////////////// #ifndef __WINDOWS_H_ #define __WINDOWS_H_ #include "struct.h" #define ToWinX(x) (((x)*Menu_factor_X)+Window_pos_X) #define ToWinY(y) (((y)*Menu_factor_Y)+Window_pos_Y) #define ToWinL(l) ((l)*Menu_factor_X) #define ToWinH(h) ((h)*Menu_factor_Y) #define Update_window_area(x,y,w,h) Update_rect(Window_pos_X+(x)*Menu_factor_X,Window_pos_Y+(y)*Menu_factor_Y,(w)*Menu_factor_X,(h)*Menu_factor_Y); void Display_cursor(void); void Hide_cursor(void); void Remap_screen_after_menu_colors_change(void); void Compute_optimal_menu_colors(T_Components * palette); void Remap_menu_sprites(); void Position_screen_according_to_zoom(void); void Compute_separator_data(void); void Compute_magnifier_data(void); void Clip_magnifier_offsets(short *x_offset, short *y_offset); void Compute_limits(void); void Compute_paintbrush_coordinates(void); void Pixel_in_menu(word bar, word x, word y, byte color); void Pixel_in_menu_and_skin(word bar, word x, word y, byte color); void Pixel_in_window(word x,word y,byte color); void Set_fore_color(byte color); void Set_back_color(byte color); void Frame_menu_color(byte id); void Display_menu_palette(void); void Display_menu(void); void Display_layerbar(void); void Reposition_palette(void); void Change_palette_cells(void); int Pick_color_in_palette(void); word Palette_cells_X(void); word Palette_cells_Y(void); void Print_general(short x,short y,const char * str,byte text_color,byte background_color); void Print_in_window(short x,short y,const char * str,byte text_color,byte background_color); void Print_in_window_limited(short x,short y,const char * str,byte size,byte text_color,byte background_color); void Print_char_in_window(short x_pos,short y_pos,const unsigned char c,byte text_color,byte background_color); void Print_in_menu(const char * str, short position); void Print_coordinates(void); void Print_filename(void); void Print_counter(short x,short y,const char * str,byte text_color,byte background_color); byte Confirmation_box(char * message); void Warning_message(char * message); void Verbose_message(const char * caption, const char * message); int Requester_window(char* message, int initial_value); void Display_image_limits(void); void Display_all_screen(void); void Window_rectangle(word x_pos,word y_pos,word width,word height,byte color); void Window_display_frame_generic(word x_pos,word y_pos,word width,word height, byte color_tl,byte color_br,byte color_s,byte color_tlc,byte color_brc); void Window_display_frame_mono(word x_pos,word y_pos,word width,word height,byte color); void Window_display_frame_in(word x_pos,word y_pos,word width,word height); void Window_display_frame_out(word x_pos,word y_pos,word width,word height); void Window_display_frame(word x_pos,word y_pos,word width,word height); void Display_sprite_in_menu(int btn_number,char sprite_number); void Display_paintbrush_in_menu(void); void Display_paintbrush_in_window(word x,word y,int number); void Draw_thingumajig(word x,word y, byte color, short direction); void Display_grad_block_in_window(word x_pos,word y_pos,word block_start,word block_end); void Window_display_icon_sprite(word x_pos,word y_pos,byte type); byte Best_color(byte red,byte green,byte blue); byte Best_color_nonexcluded(byte red,byte green,byte blue); byte Best_color_perceptual(byte r,byte g,byte b); byte Best_color_perceptual_except(byte r,byte g,byte b, byte except); void Horizontal_XOR_line_zoom(short x_pos, short y_pos, short width); void Vertical_XOR_line_zoom(short x_pos, short y_pos, short height); void Change_magnifier_factor(byte factor_index, byte point_at_mouse); /// Width of one layer button, in pixels before scaling extern word Layer_button_width; /// Copy viewport settings and offsets from the Main to the Spare. void Copy_view_to_spare(void); #endif grafx2/src/Makefile0000644000076400010400000006235311546444456014707 0ustar vigAdministrator# Grafx2 - The Ultimate 256-color bitmap paint program # # Copyright 2011 Franck Charlet # Copyright 2011 Pawel Gralski # Copyright 2009 Per Olofsson # Copyright 2008 Peter Gordon # Copyright 2008-2010 Yves Rizoud # Copyright 2007-2010 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 # Overridable defaults prefix = /usr/local exec_prefix = $(prefix) bindir = $(exec_prefix)/bin datarootdir = $(prefix)/share datadir = $(datarootdir) pixmapdir = $(datarootdir)/icons # Compile with OPTIM=0 to disable gcc optimizations, to enable debug. STRIP = strip ### Specific to build MAC OS X universal binaries on Tiger ### ### (may need to be changed or removed depedning on the OSX version) ### MACOSX_SYSROOT = /Developer/SDKs/MacOSX10.4u.sdk MACOSX_ARCH = -arch ppc -arch i386 ### PLATFORM DETECTION AND CONFIGURATION ### PLATFORMOBJ = # There is no uname under windows, but we can guess we are there with the COMSPEC env.var # Windows specific ifdef COMSPEC DELCOMMAND = rm -f MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp BIN = ../bin/grafx2.exe COPT = -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -g -ggdb `sdl-config --cflags` $(TTFCOPT) $(JOYCOPT) $(VKEYCOPT) $(LUACOPT) $(LAYERCOPT) LOPT = `sdl-config --libs` -lSDL_image $(TTFLOPT) -lpng14 $(LUALOPT) LUALOPT = -llua CC = gcc OBJDIR = ../obj/win32 # Resources (icon) WINDRES = windres.exe PLATFORMOBJ = $(OBJDIR)/winres.o PLATFORM = win32 #some misc files we have to add to the release archive under windows. PLATFORMFILES = bin/SDL.dll bin/SDL_image.dll bin/libpng14-14.dll bin/zlib1.dll $(TTFLIBS) ZIP = zip else #For all other platforms, we can rely on uname PLATFORM = $(shell uname) ifeq ($(PLATFORM),AmigaOS) # 1 #AmigaOS (3 or 4) specific DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp BIN = ../bin/grafx2 COPT = -Wall -c -gstabs `sdl-config --cflags` $(TTFCOPT) LOPT = `sdl-config --libs` -lSDL_image -lpng -ljpeg -lz $(TTFLOPT) -lft2 CC = gcc OBJDIR = ../obj/amiga ZIP = lha ZIPOPT = a NOTTF = 1 else ifeq ($(PLATFORM),Darwin) # 2 #Mac OS X specific DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty # Force it OPTIM = 3 CP = cp ZIP = zip PLATFORMFILES = gfx2.png # Where the SDL frameworks are located FWDIR = /Library/Frameworks BIN = ../bin/grafx2 SVN_REVISION = $(shell svnversion | cut -f2 -d ":" - | tr -d "M") SDLCOPT = $(MACOSX_ARCH) -I$(FWDIR)/SDL.framework/Headers -I$(FWDIR)/SDL_image.framework/Headers -I$(FWDIR)/SDL_ttf.framework/Headers -D_THREAD_SAFE #-framework SDL_ttf SDLLOPT = -isysroot $(MACOSX_SYSROOT) $(MACOSX_ARCH) -L/usr/lib -framework SDL -framework SDL_image -framework Cocoa -framework Carbon -framework OpenGL COPT = -D_DARWIN_C_SOURCE -D__macosx__ -D__linux__ -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -std=c99 -c -g $(LUACOPT) $(SDLCOPT) $(TTFCOPT) -I/usr/X11/include LOPT = $(SDLLOPT) -llua -lpng -lz # Use gcc for compiling. Use ncc to build a callgraph and analyze the code. CC = gcc #CC = nccgen -ncgcc -ncld -ncfabs OBJDIR = ../obj/macosx PLATFORMOBJ = $(OBJDIR)/SDLMain.o X11LOPT = MACAPPEXE = Grafx2.app/Contents/MacOS/Grafx2 NOTTF = 1 else ifeq ($(PLATFORM),AROS) # 3 #AROS specific DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp BIN = ../bin/grafx2 COPT = -Wall -g `sdl-config --cflags` $(TTFCOPT) LOPT = -lSDL_image `sdl-config --libs` -lpng -ljpeg -lz $(TTFLOPT) -lfreetype2shared CC = gcc OBJDIR = ../obj/aros STRIP = strip --strip-unneeded --remove-section .comment ZIP = lha ZIPOPT = a else ifeq ($(PLATFORM),MorphOS) # 4 #MorphOS specific DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp BIN = ../bin/grafx2 COPT = -Wall -gstabs -c `sdl-config --cflags` $(TTFCOPT) LOPT = -lSDL_image `sdl-config --libs` -lpng -ljpeg -lz $(TTFLOPT) CC = gcc OBJDIR = ../obj/morphos ZIP = lha ZIPOPT = a PLATFORMFILES = ../misc/grafx2.info else ifeq ($(PLATFORM),BeOS) # 6 #BeOS specific DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp BIN = ../bin/grafx2 COPT = -W -Wall -c -g `sdl-config --cflags` $(TTFCOPT) -I/boot/home/config/include LOPT = `sdl-config --libs` -lSDL_image -lpng -ljpeg -lz $(TTFLOPT) CC = gcc OBJDIR = ../obj/beos ZIP = zip else ifeq ($(PLATFORM),Haiku) # 7 #Haiku specific DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp BIN = ../bin/grafx2 PLATFORMOBJ = $(OBJDIR)/haiku.o ifeq ($(NOLUA),1) LUACOPT = LUALOPT = else LUACOPT = -D__ENABLE_LUA__ LUALOPT = -llua endif COPT = -W -Wall -c -g `sdl-config --cflags` $(TTFCOPT) -I/boot/common/include $(LUACOPT) LOPT = `sdl-config --libs` -lSDL_image -lpng -ljpeg -lz $(TTFLOPT) -lfreetype -lbe $(LUALOPT) CC = gcc OBJDIR = ../obj/haiku ZIP = zip else ifeq ($(PLATFORM),skyos) # 8 #SkyOS specific DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp BIN = ../bin/grafx2 COPT = -W -Wall -Wdeclaration-after-statement -c -g `sdl-config --cflags` $(TTFCOPT) LOPT = `sdl-config --libs` -lSDL_image -lpng -ljpeg -lz $(TTFLOPT) CC = gcc OBJDIR = ../obj/skyos ZIP = zip else ifeq ($(PLATFORM),OSF1) #9 #OSF1 / tru64 alpha DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp ZIP = zip PLATFORMFILES = gfx2.png BIN = ../bin/grafx2 COPT = -W -Wall -std=c99 -c -g -gstabs -D__TRU64__ `sdl-config --cflags` $(TTFCOPT) $(LUACOPT) LOPT = `sdl-config --libs` -lSDL_image $(TTFLOPT) -lpng $(LUALOPT) -lm OBJDIR = ../obj/unix X11LOPT = -lX11 CC = gcc else # Finally, the default rules that work fine for most unix/gcc systems, linux and freebsd are tested. # Linux and FreeBSD specific (default rules) DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp ZIP = zip PLATFORMFILES = gfx2.png ifneq ($(ATARICROSS),1) ifeq ($(NOLUA),1) LUACOPT = LUALOPT = else LUACOPT = `pkg-config lua --cflags --silence-errors ||pkg-config lua5.1 --cflags --silence-errors ||pkg-config lua-5.1 --cflags` LUALOPT = `pkg-config lua --libs --silence-errors ||pkg-config lua5.1 --libs --silence-errors ||pkg-config lua-5.1 --libs` endif endif # These can only be used under linux and maybe freebsd. They allow to compile for the gp2x or to create a windows binary ifdef WIN32CROSS #cross compile a Win32 executable CC = i586-mingw32msvc-gcc BIN = ../bin/grafx2.exe COPT = -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -g -ggdb -Dmain=SDL_main `/usr/local/cross-tools/i386-mingw32/bin/sdl-config --cflags` $(TTFCOPT) LOPT = -mwindows -lmingw32 -lSDLmain -lSDL -lshlwapi `/usr/local/cross-tools/i386-mingw32/bin/sdl-config --libs` -lSDL_image $(TTFLOPT) OBJDIR = ../obj/win32 PLATFORM = win32 else ifdef GP2XCROSS #cross compile an exec for the gp2x CC = /opt/open2x/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/bin/arm-open2x-linux-gcc BIN = ../bin/grafx2.gpe COPT = -W -Wall -Wdeclaration-after-statement -pedantic -std=c99 -static -g -O$(OPTIM) -I/opt/open2x/gcc-4.1.1-glibc-2.3.6/include `/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin/sdl-config --cflags` $(TTFCOPT) -D__GP2X__ $(TTFCOPT) $(JOYCOPT) $(VKEYCOPT) $(LUACOPT) $(LAYERCOPT) LOPT = -static -lSDL_image `/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin/sdl-config --static-libs` -ljpeg -lpng -lz -lm $(TTFLOPT) $(LUALOPT) OBJDIR = ../obj/gp2x NOTTF = 1 PLATFORM = gp2x STRIP = /opt/open2x/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/bin/arm-open2x-linux-strip JOYCOPT = -DUSE_JOYSTICK else ifdef AROS32CROSS #cross compile an Aros 32 bit executable BIN = ../bin/grafx2 COPT = -Wall -g `i386-linux-aros-sdl-config --cflags` $(TTFCOPT) LOPT = -lSDL_image `i386-linux-aros-sdl-config --libs` -lpng -ljpeg -lz $(TTFLOPT) -lfreetype2shared CC = i386-aros-gcc OBJDIR = ../obj/aros STRIP = strip --strip-unneeded --remove-section .comment PLATFORM = AROS ZIP = lha ZIPOPT = a else ifdef ATARICROSS #cross compile an exec for atari TOS/MiNT machine CC = m68k-atari-mint-gcc BIN = ../bin/grafx2.ttp LUALOPT = -llua OBJDIR = ../obj/m68k-atari-mint PLATFORM = m68k-atari-mint STRIP = m68k-atari-mint-strip -s X11LOPT = COPT = -W -Wall -m68020-60 -fomit-frame-pointer -pedantic -std=c99 -Wdeclaration-after-statement -D__MINT__ -DNO_INLINE_MATH -O$(OPTIM) -c -I$(prefix)/include `$(prefix)/bin/libpng12-config --cflags` `$(prefix)/bin/sdl-config --cflags` $() $(JOYCOPT) $(LAYERCOPT) $(LUACOPT) LOPT = -static -m68020-60 -lSDL_image `$(prefix)/bin/sdl-config --libs` -L$(prefix)/lib -ltiff -ljpeg `$(prefix)/bin/libpng12-config --libs` -lz -lm $(TTFLOPT) -lfreetype $(LUALOPT) $(LAYERLOPT) else # Compiles a regular linux executable for the native platform BIN = ../bin/grafx2 COPT = -W -Wall -Wdeclaration-after-statement -std=c99 -c -g `sdl-config --cflags` $(TTFCOPT) $(LUACOPT) $(JOYCOPT) $(VKEYCOPT) -O$(OPTIM) LOPT = `sdl-config --libs` -lSDL_image $(TTFLOPT) -lpng $(LUALOPT) -lm # Use gcc for compiling. Use ncc to build a callgraph and analyze the code. CC = gcc #CC = nccgen -ncgcc -ncld -ncfabs OBJDIR = ../obj/unix X11LOPT = -lX11 endif endif endif endif endif endif endif endif endif endif endif endif endif ### BUILD SETTINGS are set according to vars set in the platform selection, ### the "overridable defaults", and environment variables set before launching make #TrueType is optional: make NOTTF=1 to disable support and dependencies. ifndef ($(ATARICROSS,1)) ifeq ($(NOTTF),1) TTFCOPT = -DNOTTF=1 TTFLOPT = TTFLIBS = TTFLABEL = -nottf else TTFCOPT = TTFLOPT = -L$(prefix)/lib -lSDL_ttf $(X11LOPT) TTFLIBS = bin/libfreetype-6.dll bin/SDL_ttf.dll TTFLABEL = endif else ifeq ($(NOTTF),1) TTFCOPT = -DNOTTF=1 TTFLOPT = TTFLIBS = TTFLABEL = -nottf else TTFCOPT = TTFLOPT = -L$(prefix)/lib -lSDL_ttf $(X11LOPT) TTFLIBS = TTFLABEL = endif endif #Lua scripting is optional too ifeq ($(NOLUA),1) LUACOPT = LUALOPT = LUALABEL = -nolua else LUACOPT += -D__ENABLE_LUA__ LUALABEL = endif #To enable Joystick emulation of cursor, make USE_JOYSTICK=1 (for input.o) #This can be necessary to test cursor code on a PC, but by default for all #non-console platforms the joystick is disabled, to avoid reporting #'restless' movements when an analog joystick or a poorly-calibrated joypad #is plugged in. ifeq ($(USE_JOYSTICK),1) JOYCOPT = -DUSE_JOYSTICK endif #To enable virtual keyboard input (mouse-driven), make VIRT_KEY=1 #This is automatically enabled on some platforms, but this #switch allows you to test the virtual keyboard on any other platform. ifeq ($(VIRT_KEY),1) VKEYCOPT = -DVIRT_KEY endif #To speed up rendering, can disable the layered editing # with NOLAYERS=1 ifeq ($(NOLAYERS),1) LAYERCOPT = -DNOLAYERS else LAYERCOPT = endif ### And now for the real build rules ### .PHONY : all debug release clean depend zip version force install uninstall # 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)/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 $(OBJDIR)/pversion.o $(OBJDIR)/factory.o $(PLATFORMOBJ) $(OBJDIR)/fileformats.o $(OBJDIR)/miscfileformats.o $(OBJDIR)/libraw2crtc.o $(OBJDIR)/brush_ops.o $(OBJDIR)/buttons_effects.o $(OBJDIR)/layers.o SKIN_FILES = ../share/grafx2/skins/skin_classic.png ../share/grafx2/skins/skin_modern.png ../share/grafx2/skins/skin_DPaint.png ../share/grafx2/skins/font_Classic.png ../share/grafx2/skins/font_Fun.png ../share/grafx2/skins/font_Fairlight.png ../share/grafx2/skins/font_Melon.png ../share/grafx2/skins/font_DPaint.png ../share/grafx2/skins/skin_scenish.png ../share/grafx2/skins/font_Seen.png ../share/grafx2/skins/skin_Aurora.png SCRIPT_FILES = ../share/grafx2/scripts/samples_2.3/brush/ApplyColor.lua ../share/grafx2/scripts/samples_2.3/brush/Fisheye.lua ../share/grafx2/scripts/samples_2.3/brush/GrayscaleAvg.lua ../share/grafx2/scripts/samples_2.3/brush/GrayscaleDesat.lua ../share/grafx2/scripts/samples_2.3/brush/Halfsmooth.lua ../share/grafx2/scripts/samples_2.3/brush/Waves.lua ../share/grafx2/scripts/samples_2.3/demo/3DPalette.lua ../share/grafx2/scripts/samples_2.3/demo/Ellipse.lua ../share/grafx2/scripts/samples_2.3/demo/FlipPicture.lua \ ../share/grafx2/scripts/samples_2.3/demo/SierpinskyCarpet.lua ../share/grafx2/scripts/samples_2.3/demo/SierpinskyTriangle.lua ../share/grafx2/scripts/samples_2.3/demo/Spritesheet.lua ../share/grafx2/scripts/samples_2.3/demo/brush/Amigaball.lua ../share/grafx2/scripts/samples_2.3/demo/brush/ColorSphere.lua ../share/grafx2/scripts/samples_2.3/demo/brush/FindAA.lua ../share/grafx2/scripts/samples_2.3/demo/brush/Mandelbrot.lua ../share/grafx2/scripts/samples_2.3/libs/dawnbringer_lib.lua ../share/grafx2/scripts/samples_2.3/libs/memory.lua \ ../share/grafx2/scripts/samples_2.3/palette/Desaturate.lua ../share/grafx2/scripts/samples_2.3/palette/ExpandColors.lua ../share/grafx2/scripts/samples_2.3/palette/FillColorCube.lua ../share/grafx2/scripts/samples_2.3/palette/InvertedRGB.lua ../share/grafx2/scripts/samples_2.3/palette/Set3bit.lua ../share/grafx2/scripts/samples_2.3/palette/Set6bit.lua ../share/grafx2/scripts/samples_2.3/palette/SetC64Palette.lua ../share/grafx2/scripts/samples_2.3/palette/ShiftHue.lua ../share/grafx2/scripts/samples_2.3/picture/CellColourReducer.lua \ ../share/grafx2/scripts/samples_2.3/picture/DrawGridIsometric.lua ../share/grafx2/scripts/samples_2.3/picture/DrawgridOrthogonal_Index.lua ../share/grafx2/scripts/samples_2.3/picture/DrawGridOrthogonal_RGB.lua ../share/grafx2/scripts/samples_2.3/picture/GlassGridFilter.lua ../share/grafx2/scripts/samples_2.3/picture/PaletteToPicture.lua ../share/grafx2/scripts/samples_2.3/picture/Pic2isometric.lua ../share/grafx2/scripts/samples_2.3/picture/Rainbow-Dark2Bright.lua ../share/grafx2/scripts/samples_2.3/picture/RemapImage2RGB.lua \ ../share/grafx2/scripts/samples_2.3/picture/RemapImage2RGB_ed.lua ../share/grafx2/scripts/samples_2.3/picture/RemapImageTo3bitPal.lua ../share/grafx2/scripts/samples_2.3/picture/XBitColourXpaceFromPalette.lua FONT_FILES = ../share/grafx2/fonts/8pxfont.png ../share/grafx2/fonts/Tuffy.ttf ../share/grafx2/fonts/PF_Arma_5__.png ../share/grafx2/fonts/PF_Easta_7_.png ../share/grafx2/fonts/PF_Easta_7__.png ../share/grafx2/fonts/PF_Ronda_7__.png ../share/grafx2/fonts/PF_Tempesta_5.png ../share/grafx2/fonts/PF_Tempesta_5_.png ../share/grafx2/fonts/PF_Tempesta_5__.png ../share/grafx2/fonts/PF_Tempesta_5___.png ../share/grafx2/fonts/PF_Tempesta_7.png ../share/grafx2/fonts/PF_Tempesta_7_.png ../share/grafx2/fonts/PF_Tempesta_7__.png ../share/grafx2/fonts/PF_Tempesta_7___.png ../share/grafx2/fonts/PF_Westa_7_.png ../share/grafx2/fonts/PF_Westa_7__.png ifeq ($(PLATFORM),Darwin) all : $(MACAPPEXE) $(MACAPPEXE) : $(BIN) rm -rf Grafx2.app mkdir -p Grafx2.app Grafx2.app/Contents Grafx2.app/Contents/Frameworks Grafx2.app/Contents/MacOS Grafx2.app/Contents/Resources Grafx2.app/Contents/Resources/scripts echo 'APPL????' > Grafx2.app/Contents/PkgInfo cp ../Info.plist Grafx2.app/Contents cp -r Grafx2.icns Grafx2.app/Contents/Resources cp -r English.lproj Grafx2.app/Contents/Resources cp -r ../share/grafx2/fonts Grafx2.app/Contents/Resources cp -r ../share/grafx2/skins Grafx2.app/Contents/Resources cp -r ../share/grafx2/gfx2def.ini Grafx2.app/Contents/Resources cp -r $(SCRIPT_FILES) Grafx2.app/Contents/Resources/scripts mkdir -p Grafx2.app/Contents/Frameworks/SDL.framework/Versions mkdir -p Grafx2.app/Contents/Frameworks/SDL_image.framework/Versions # mkdir -p Grafx2.app/Contents/Frameworks/SDL_ttf.framework/Versions cp -Rp $(FWDIR)/SDL.framework/Versions/A Grafx2.app/Contents/Frameworks/SDL.framework/Versions cp -Rp $(FWDIR)/SDL_image.framework/Versions/A Grafx2.app/Contents/Frameworks/SDL_image.framework/Versions # cp -Rp $(FWDIR)/SDL_ttf.framework/Versions/A Grafx2.app/Contents/Frameworks/SDL_ttf.framework/Versions rm -fr Grafx2.app/Contents/Frameworks/SDL.framework/Versions/A/Headers rm -fr Grafx2.app/Contents/Frameworks/SDL.framework/Versions/A/Resources rm -fr Grafx2.app/Contents/Frameworks/SDL_image.framework/Versions/A/Headers rm -fr Grafx2.app/Contents/Frameworks/SDL_image.framework/Versions/A/Resources # rm -fr Grafx2.app/Contents/Frameworks/SDL_ttf.framework/Versions cp $(BIN) $(MACAPPEXE) $(STRIP) -x -X -S $(MACAPPEXE) chmod +x $(MACAPPEXE) tar cvzf grafx2-svn$(SVN_REVISION)-macosx.tgz --exclude '*svn*' --exclude '*DS_Store*' Grafx2.app/* else all : $(BIN) endif debug : $(BIN) # Make release will strip the executable to make it smaller but non-debugable release : version $(BIN) $(STRIP) $(BIN) # Create a zip archive ready for upload to the website, including binaries and sourcecode ziprelease: version $(BIN) release echo `sed "s/.*=\"\(.*\)\";/\1/" pversion.c`.`svnversion` | tr " :" "_-" | sed -e "s/\(wip\)\\./\1/I" > $(OBJDIR)/versiontag tar cvzf "../src-`cat $(OBJDIR)/versiontag`.tgz" --strip=1 ../src/*.c ../src/*.h ../src/Makefile ../src/Makefile.dep ../src/gfx2.ico cd .. && $(ZIP) $(ZIPOPT) "grafx2-`cat $(OBJDIR:../%=%)/versiontag`$(TTFLABEL)-$(PLATFORM).$(ZIP)" $(BIN:../%=%) share/grafx2/gfx2def.ini $(SCRIPT_FILES:../%=%) $(SKIN_FILES:../%=%) share/grafx2/gfx2.gif share/icons/grafx2.svg doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt doc/PF_fonts.txt $(FONT_FILES:../%=%) doc/README-zlib1.txt doc/README-SDL.txt doc/README-SDL_image.txt doc/README-SDL_ttf.txt doc/README-lua.txt src-`cat $(OBJDIR:../%=%)/versiontag`.tgz $(PLATFORMFILES:../%=%) $(DELCOMMAND) "../src-`cat $(OBJDIR)/versiontag`.tgz" tar cvzf "../grafx2-`cat $(OBJDIR)/versiontag`$(TTFLABEL)-src.tgz" --strip=1 --transform 's,^,grafx2/,g' ../src/*.c ../src/*.h ../src/Makefile ../src/Makefile.dep ../share/grafx2/gfx2def.ini $(SCRIPT_FILES) $(SKIN_FILES) ../src/gfx2.ico ../share/grafx2/gfx2.gif ../share/icons/grafx2.svg ../doc/README.txt ../doc/COMPILING.txt ../doc/gpl-2.0.txt ../doc/PF_fonts.txt ../misc/unix/grafx2.1 ../misc/unix/grafx2.xpm ../misc/unix/grafx2.desktop $(FONT_FILES) $(DELCOMMAND) "$(OBJDIR)/versiontag" $(BIN) : $(OBJ) test -d ../bin || $(MKDIR) ../bin $(CC) $(OBJ) -o $(BIN) $(LOPT) $(LFLAGS) # SVN revision number version.c : echo "char SVN_revision[]=\"`svnversion .`\";" > version.c ifeq ($(LABEL),) else echo "char Program_version[]=\"$(LABEL)\";" > pversion.c endif version : delversion delpversion version.c pversion.c $(OBJDIR)/version.o $(OBJDIR)/pversion.o all delversion : $(DELCOMMAND) version.c delpversion : ifeq ($(LABEL),) else $(DELCOMMAND) pversion.c endif $(OBJDIR)/%.o : %.c $(if $(wildcard $(OBJDIR)),,$(MKDIR) $(OBJDIR)) $(CC) $(COPT) $(CFLAGS) -c $*.c -o $(OBJDIR)/$*.o $(OBJDIR)/%.o : %.m $(if $(wildcard $(OBJDIR)),,$(MKDIR) $(OBJDIR)) $(CC) $(COPT) -c $*.m -o $(OBJDIR)/$*.o depend : $(CC) -MM *.c | sed 's:^[^ ]:$$(OBJDIR)/&:' > Makefile.dep # Link the icons to the program under windows $(OBJDIR)/winres.o : gfx2.ico echo "1 ICON \"gfx2.ico\"" | $(WINDRES) -o $(OBJDIR)/winres.o # Compile the C++ file needed in Haiku to use the API $(OBJDIR)/haiku.o : haiku.cpp g++ -c haiku.cpp -o $(OBJDIR)/haiku.o clean : $(DELCOMMAND) $(OBJ) $(DELCOMMAND) $(BIN) ifneq ($(PLATFORM),amiga-vbcc) # Linux installation of the program install : $(BIN) # Create dirs test -d $(DESTDIR)$(bindir) || $(MKDIR) $(DESTDIR)$(bindir) test -d $(DESTDIR)$(datadir)/grafx2 || $(MKDIR) $(DESTDIR)$(datadir)/grafx2 test -d $(DESTDIR)$(datadir)/grafx2/fonts || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/fonts test -d $(DESTDIR)$(datadir)/grafx2/skins || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/skins test -d $(DESTDIR)$(datadir)/grafx2/scripts || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts test -d $(DESTDIR)$(datadir)/grafx2/scripts/libs || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts/libs test -d $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3 || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3 test -d $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/brush || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/brush test -d $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/demo || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/demo test -d $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/demo/brush || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/demo/brush test -d $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/libs || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/libs test -d $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/palette || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/palette test -d $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/picture || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/picture test -d $(DESTDIR)$(datadir)/applications || $(MKDIR) $(DESTDIR)$(datadir)/applications test -d $(DESTDIR)$(pixmapdir) || $(MKDIR) $(DESTDIR)$(pixmapdir) # Copy files $(CP) $(BIN) $(DESTDIR)$(bindir) $(CP) ../share/grafx2/gfx2def.ini $(DESTDIR)$(datadir)/grafx2/ $(CP) ../share/grafx2/gfx2.gif $(DESTDIR)$(datadir)/grafx2/ $(CP) ../share/grafx2/fonts/* $(DESTDIR)$(datadir)/grafx2/fonts/ $(CP) $(SKIN_FILES) $(DESTDIR)$(datadir)/grafx2/skins/ for f in $(SCRIPT_FILES); do cp "$$f" "$(DESTDIR)$(bindir)/$$f" ; done # Icon and desktop file for debian $(CP) ../misc/unix/grafx2.desktop $(DESTDIR)$(datadir)/applications/ $(CP) ../misc/unix/grafx2.xpm $(DESTDIR)$(pixmapdir) $(CP) ../share/icons/grafx2.svg $(DESTDIR)$(pixmapdir) @echo Install complete # Linux uninstallation of the program uninstall : $(DELCOMMAND) $(DESTDIR)$(bindir)/grafx2 $(DELCOMMAND) $(DESTDIR)$(datadir)/grafx2/gfx2def.ini $(DELCOMMAND) $(DESTDIR)$(datadir)/grafx2/gfx2.gif $(DELCOMMAND) $(DESTDIR)$(datadir)/grafx2/fonts/* $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/fonts),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/fonts,) $(DELCOMMAND) $(SKIN_FILES:../share%=$(DESTDIR)$(datadir)%) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/skins),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/skins,) $(DELCOMMAND) $(SCRIPT_FILES:../share%=$(DESTDIR)$(datadir)%) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/picture),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/picture,) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/palette),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/palette,) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/libs),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/libs,) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/demo/brush),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/demo/brush,) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/demo),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/demo,) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/brush),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3/brush,) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.3,) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts/libs),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts/libs,) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts,) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2),$(RMDIR) $(DESTDIR)$(datadir)/grafx2,) # Icon and desktop file for debian $(DELCOMMAND) $(DESTDIR)$(datadir)/applications/grafx2.desktop $(DELCOMMAND) $(DESTDIR)$(pixmapdir)/grafx2.xpm $(DELCOMMAND) $(DESTDIR)$(pixmapdir)/grafx2.svg @echo Uninstall complete endif -include Makefile.dep grafx2/src/Makefile.dep0000644000076400010400000001412011550334774015437 0ustar vigAdministrator$(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 brush.h $(OBJDIR)/brush_ops.o: brush_ops.c brush.h struct.h const.h buttons.h engine.h \ global.h graph.h misc.h operatio.h pages.h sdlscreen.h windows.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 \ palette.h errors.h readini.h saveini.h shade.h io.h help.h text.h \ sdlscreen.h windows.h brush.h input.h special.h setup.h $(OBJDIR)/buttons_effects.o: buttons_effects.c buttons.h struct.h const.h engine.h \ global.h graph.h help.h input.h misc.h readline.h sdlscreen.h windows.h \ brush.h $(OBJDIR)/engine.o: engine.c const.h struct.h global.h graph.h misc.h special.h \ buttons.h operatio.h shade.h errors.h sdlscreen.h windows.h brush.h \ input.h engine.h pages.h layers.h factory.h loadsave.h io.h $(OBJDIR)/factory.o: factory.c brush.h struct.h const.h buttons.h engine.h errors.h \ filesel.h loadsave.h global.h graph.h io.h misc.h pages.h readline.h \ sdlscreen.h windows.h palette.h input.h help.h realpath.h $(OBJDIR)/fileformats.o: fileformats.c errors.h global.h struct.h const.h \ loadsave.h misc.h io.h windows.h pages.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 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 pxtriple.h pxwide2.h pxtall2.h pxquad.h windows.h input.h \ brush.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 pages.h $(OBJDIR)/hotkeys.o: hotkeys.c struct.h const.h global.h hotkeys.h $(OBJDIR)/init.o: init.c buttons.h struct.h const.h errors.h global.h graph.h \ init.h io.h factory.h help.h hotkeys.h keyboard.h loadsave.h misc.h \ mountlist.h operatio.h palette.h sdlscreen.h setup.h transform.h \ windows.h layers.h special.h $(OBJDIR)/input.o: input.c global.h struct.h const.h keyboard.h sdlscreen.h \ windows.h errors.h misc.h buttons.h input.h loadsave.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 keyboard.h $(OBJDIR)/layers.o: layers.c const.h struct.h global.h windows.h engine.h pages.h \ sdlscreen.h input.h help.h misc.h $(OBJDIR)/libraw2crtc.o: libraw2crtc.c const.h global.h struct.h loadsave.h $(OBJDIR)/loadsave.o: loadsave.c buttons.h struct.h const.h errors.h global.h io.h \ loadsave.h misc.h graph.h op_c.h pages.h palette.h sdlscreen.h windows.h \ engine.h brush.h setup.h $(OBJDIR)/main.o: main.c const.h struct.h global.h graph.h misc.h init.h buttons.h \ engine.h pages.h loadsave.h sdlscreen.h errors.h readini.h saveini.h \ io.h text.h setup.h windows.h brush.h palette.h realpath.h input.h \ help.h $(OBJDIR)/misc.o: misc.c struct.h const.h sdlscreen.h global.h errors.h buttons.h \ engine.h misc.h keyboard.h windows.h palette.h input.h graph.h pages.h $(OBJDIR)/miscfileformats.o: miscfileformats.c engine.h struct.h const.h errors.h \ global.h io.h libraw2crtc.h loadsave.h misc.h sdlscreen.h windows.h $(OBJDIR)/mountlist.o: mountlist.c $(OBJDIR)/op_c.o: op_c.c op_c.h struct.h const.h errors.h global.h engine.h \ windows.h $(OBJDIR)/operatio.o: operatio.c const.h struct.h global.h misc.h engine.h graph.h \ operatio.h buttons.h pages.h errors.h sdlscreen.h brush.h windows.h \ input.h $(OBJDIR)/pages.o: pages.c global.h struct.h const.h pages.h errors.h loadsave.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 \ palette.h shade.h $(OBJDIR)/palette_test.o: palette_test.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 palette.h shade.h $(OBJDIR)/pversion.o: pversion.c $(OBJDIR)/pxdouble.o: pxdouble.c global.h struct.h const.h sdlscreen.h misc.h \ graph.h pxdouble.h pxwide.h $(OBJDIR)/pxquad.o: pxquad.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ pxquad.h $(OBJDIR)/pxsimple.o: pxsimple.c global.h struct.h const.h sdlscreen.h misc.h \ graph.h pxsimple.h $(OBJDIR)/pxtall.o: pxtall.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ pxtall.h pxsimple.h $(OBJDIR)/pxtall2.o: pxtall2.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ pxtall2.h $(OBJDIR)/pxtriple.o: pxtriple.c global.h struct.h const.h sdlscreen.h misc.h \ graph.h pxtriple.h $(OBJDIR)/pxwide.o: pxwide.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ pxwide.h $(OBJDIR)/pxwide2.o: pxwide2.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ pxwide2.h $(OBJDIR)/readini.o: readini.c const.h errors.h global.h struct.h misc.h readini.h \ setup.h realpath.h io.h $(OBJDIR)/readline.o: readline.c const.h struct.h global.h misc.h errors.h \ sdlscreen.h readline.h windows.h input.h engine.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 saveini.h setup.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 setup.h $(OBJDIR)/shade.o: shade.c global.h struct.h const.h graph.h engine.h errors.h \ misc.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 pages.h misc.h buttons.h $(OBJDIR)/text.o: text.c SFont.h struct.h const.h global.h sdlscreen.h io.h \ errors.h windows.h misc.h setup.h $(OBJDIR)/tiles.o: tiles.c $(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 engine.h errors.h \ global.h graph.h input.h misc.h op_c.h readline.h sdlscreen.h palette.h grafx2/share/grafx2/gfx2def.ini0000644000076400010400000004644311546417262016776 0ustar vigAdministrator###### GrafX2 initialization file ###### Fichier d'initialisation de GrafX2 ## # # # # # You may modify this file with any # Vous pouvez modifier ce fichier avec # # standard ASCII text editor. # n'importe quel diteur de texte # # # ASCII standard. # # # # # Comments are preceded by ';' or # Les commentaires sont prcds par # # '#'. # ';' ou '#'. # # # # # Options are not case sensitive and # Les options ne sont pas sensibles # # spaces are ignored. # la casse et les espaces sont ignors.# # # # # You must not change the order of # Vous ne devez pas changer l'ordre # # the sections and their options. # des sections et de leurs options. # # You must not delete or put into # Vous ne devez pas effacer ou mettre # # comment any section nor option. # en commentaire une section ou option.# # # # # Each option is preceded by a # Chaque option est prcde par un # # comment which explains its meaning. # commentaire qui explique sa fonction.# # # # ############################################################################## [MOUSE] # [SOURIS] ; The sensitivity of the mouse can | La sensibilit de la souris peut ; take values from 1 to 4. The | prendre des valeurs de 1 4. Plus ; smaller values, the faster. | les valeurs sont petites, plus c'est ; This only takes effect in | rapide. Ce paramtrage n'est utilis ; fullscreen modes. | que dans les modes "plein cran". ; | X_sensitivity = 1 ; (default 1) Y_sensitivity = 1 ; (default 1) ; Unused setting, only kept for compatibility. X_correction_factor = 0 ; (default 0) Y_correction_factor = 0 ; (default 0) ; Aspect of the main cursor (cross) | Aspect du curseur principal (croix) ; 1: Solid | 1: Solide ; 2: Transparent | 2: Transparent ; 3: Thin (solid) | 3: Fin (solide) Cursor_aspect = 1 ; (default 1) [MENU] # [MENU] ; Colors of the menus (the black | Couleurs des menus (la couleur noire ; and the white colors cannot be | et la couleur blanche ne peuvent pas ; modified). | tre modifies). ; Values are in {Red,Green,Blue} | Les valeurs sont dans l'ordre {Rouge, ; order and are between 0 and 63. | Vert,Bleu} et vont de 0 63. Light_color = 42,42,42 ; (default 42,42,42) Dark_color = 27,27,27 ; (default 27,27,27) ; ; Light_color = 24,25,30 ; \_ Nightmare ; Dark_color = 13,14,19 ; / ; ; Light_color = 10,45,28 ; \_ Forest ; Dark_color = 5,27,12 ; / ; ; Light_color = 48,41,26 ; \_ Gold ; Dark_color = 26,22,15 ; / ; ; Light_color = 10,40,55 ; \_ Oceanic ; Dark_color = 10,20,32 ; / ; Aspect ratio and size of the | Proportion des menus et de la barre ; menus and the tool-bar. | d'outils. ; Possible values: | Valeurs possibles: ; 0: Do not adapt (pixels are not | 0: Ne pas adapter (les pixels ne sont ; stretched) | pas tirs) ; 1: Adapt the menus and the tool- | 1: Adapter les menus et la barre ; bar according to the resolution| d'outils suivant la rsolution ; 2: Slightly adapt the ratio of | 2: Adapter lgrement les proportions ; the menus and tool-bar | des menus et de la barre d'outils ; -1:Do not adapt (like 0) | -1:Ne pas adapter (comme 0) ; -2:Stretch by x2 maximum | -2:Etire au double de taille si possible ; -3:Stretch by x3 maximum | -3:Etire au triple de taille si possible ; -4:Stretch by x4 maximum | -3:Etire au quadruple de taille si ; | possible. Menu_ratio = -2 ; (default -2) [FILE_SELECTOR] # [SELECTEUR_DE_FICHIERS] ; Show hidden files and | Afficher les fichiers et rpertoires ; directories (values are 'yes' or | cachs (les valeurs sont 'yes' ou ; 'no'). | 'no'). Show_hidden_files = no ; (default 'no') Show_hidden_directories = no ; (default 'no') ; Delay before displaying a preview | Dlai avant d'afficher une preview ; in file-selectors (in 18.2th of | dans les slecteurs de fichiers (en ; second). Possible values range | 18.2mes de seconde) Les valeurs ; from 1 to 256. | possibles vont de 1 256. Preview_delay = 8 ; (default 8) ; Maximize the preview of the | Maximiser la preview des images pour ; pictures so that it is as big as | qu'elle soit aussi grande que ; possible. If you're not in the | possible. ; same resolution as the picture's | Si vous n'tes pas dans la mme rso- ; one, it can try to correct the | lution que celle de l'image, cela peut ; aspect ratio, but if the picture | essayer de corriger les proportions, ; does not fill the whole screen, | mais si l'image ne prend pas tout ; it can be worse. | l'cran, cela peut tre pire. Maximize_preview = no ; (default 'no') ; This option is used to place the | Cette option est utilise pour placer ; selection bar on a filename by | la barre de slection sur un nom de ; typing its first letters. | fichier en tapant ses 1res lettres. ; For example, if you want to find | Par exemple, si vous voulez trouver le ; the "PICTURE.PKM" in a directory | fichier "PICTURE.PKM" dans un rper- ; that also contains "PALETTE.PAL", | toire contenant galement le fichier ; you'll just have to type P and I. | "PALETTE.PAL", vous n'aurez qu' taper ; The different values of "FFF" | P puis I. ; indicate if you want to find the | Les different valeurs de "FFF" ; name in both files and directories| indiquent si vous voulez trouvez le nom ; or just in only one of these: | dans les fichiers ET les rpertoires ou ; 0: files and directories | simplement dans l'un OU l'autre. ; 1: files only | 0: fichiers et rpertoires ; 2: directories only | 1: fichiers seulement ; | 2: rpertoires seulement Find_file_fast = 0 ; (default 0) [LOADING] # [CHARGEMENT] ; Automatically set the resolution | Passer automatiquement dans la bonne ; when loading a picture. | rsolution lors du chargement d'une ; You should set this value to | image. ; 'yes' after disabling the video | Vous devriez dfinir cette option ; modes that are not supported by | 'yes' aprs avoir inhib les modes ; your video card or monitor. | vido qui ne sont pas supports par ; | votre matriel. Auto_set_resolution = no ; (default 'no') ; If the variable above is set to | Si la variable ci-dessus est 'yes', ; 'yes', this one tells if you want | celle-ci indique si vous voulez ; to set the resolution according | dfinir la rsolution suivant: ; to: | 1: les dimensions de "l'cran ; 1: the internal "original screen" | d'origine" internes l'image ; dimensions of the picture | 2: les vritables dimensions de ; 2: the actual dimensions of the | l'image ; picture | Set_resolution_according_to = 1 ; (default 1) ; If you load a picture with a | Si vous chargez une image ayant une ; palette of less than 256 colors, | palette de moins de 256 couleurs, ; this option defines if you want | cette option indique si vous souhaitez ; to clear the palette or to keep | effacer la palette ou bien conserver ; the colors of the previous | les couleurs de l'image prcdente qui ; picture that are over the number | se situent au-del du nombre de la ; of colors of the new picture. | nouvelle image. ; For example, if you load a | Par exemple, si vous chargez une image ; 32-color picture, the colors 32 | de 32 couleurs, les couleurs 32 255 ; to 255 will be set to black if | seront passes en noir si cette option ; this option is set to 'yes', or | est 'yes', ou bien elles resteront ; they will be kept unchanged if | inchanges si elle est 'no'. ; this option is set to 'no'. | Clear_palette = yes ; (default 'yes') [MISCELLANEOUS] # [DIVERS] ; Draw the limits of the picture. | Afficher les limites de l'image Draw_limits = yes ; (default 'yes') ; Adjust the brush grabbing in | Ajuster la capture de brosse en mode ; "grid" mode. | "grille". Adjust_brush_pick = yes ; (default 'yes') ; Coordinates: | Coordonnes: ; 1: Relative | 1: Relatives ; 2: Absolute | 2: Absolues Coordinates = 1 ; (default 1) ; Create a backup file when saving. | Crer un fichier backup lors des ; | sauvegardes. Backup = no ; (default 'no') ; Number of pages stored in memory | Nombre de pages stockes en mmoire ; for "undoing". | destines annuler les dernires ; Values are between 1 and 99. | modifications. Valeurs entre 1 et 99. Undo_pages = 10 ; (default 10) ; Speed of the scroll-bars (in VBLs | Vitesse des barre de dfilement (en ; waited) while clicking with the | VBLs attendus) lorsque l'un des ; left or right button of the mouse.| boutons de la souris est enfonc. ; Values can be between 1 and 255. | Les valeurs sont comprises entre 1 et ; The bigger values, the slower. | 255. Plus elles sont grandes, plus ; | c'est lent. Gauges_scrolling_speed_Left = 10 ; (default 10) Gauges_scrolling_speed_Right = 3 ; (default 3) ; Automatically save the configu- | Enregistre automatiquement la configu- ; ration when exiting the program. | ration lorsqu'on quitte le programme. Auto_save = yes ; (default 'yes') ; Maximum number of vertices used | Nombre maximum de vertex utiliss dans ; in filled polygons and polyforms, | les polygnes et polyformes pleins, et ; and lasso. Possible values range | le lasso. Les valeurs possibles vont ; from 2 to 16384. | de 2 16384. ; Each vertex takes 4 bytes. | Chaque vertex prend 4 octets. Vertices_per_polygon = 1024 ; (default 1024) ; Automatically zoom into the | Zoomer automatiquement la zone pointe ; pointed area when you press the | par la souris lorsque vous appuyez sur ; short-key of the Magnifier button | la touche de raccourci de la loupe. ; while being above the picture. | Fast_zoom = yes ; (default 'yes') ; Separate the colors in the tool- | Sparer les couleurs dans la barre ; bar by a black squaring. | d'outils par un quadrillage noir. Separate_colors = no ; (default 'no') ; Initial value of the feedback for | Valeur initiale du "feedback" pour les ; the drawing modes (cf. docs). | modes de dessin (cf. docs). FX_feedback = yes ; (default 'yes') ; When you reduce the palette or | Si vous rduisez la palette ou "zappez" ; "zap" some colors out of it, it is| quelques couleurs, il est possible ; possible that there are not enough| qu'il ne reste pas assez de couleurs ; colors left to draw the menus. | pour afficher les menus. Mettre cette ; Switching the following variable | variable 'yes' ramnera automatiquent ; on will bring back the colors of | les couleurs du menu s'il reste moins ; the menu if there are less than 4 | de 4 couleurs aprs une "rduction" ou ; colors left after "reducing" or | un "zapping". ; "zapping". | Safety_colors = yes ; (default 'yes') ; Display a message at startup | Afficher un message au dmarrage ; telling the version number of the | indiquant le numro de version du ; program. | programme. Opening_message = yes ; (default 'yes') ; Take the Stencil into account when| Prendre le Stencil en compte lorsqu'on ; clearing the image. | efface l'image. Clear_with_stencil = yes ; (default 'yes') ; Directly set the discontinuous | Passer automatiquement en mode de ; freehand drawing mode after brush | dessin discontinu aprs la prise d'une ; grabbing. | brosse. Auto_discontinuous = no ; (default 'no') ; Save the screen dimensions in GIF | Sauver les dimensions de l'cran dans ; files. If you want to read these | les fichiers GIF. Si vous voulez lire ; files with Photoshop or Alchemy, | ces fichiers avec Photoshop ou Alchemy, ; and maybe some other programs, you| et peut-tre d'autres programmes, vous ; must set this option to 'no'. | devez mettre cette option 'no'. Save_screen_size_in_GIF = no ; (default 'no') ; Automaticaly count the number of | Compter automatiquement le nombre de ; different colors used when opening| couleurs diffrentes utilises lors de ; the palette editor window. (Set it| d'ouverture de la fentre d'dition de ; to 'no' if you have a slow PC or | la palette. (Mettez-le 'no' si vous ; if you edit huge pictures) | avez un PC lent ou bien si vous ditez ; | d'normes images). Auto_nb_colors_used = yes ; (default 'yes') ; Default video mode at startup | Mode vido par dfaut au ; (see the list by running the | dmarrage (voir la liste en lanant ; program with argument "/?". | le programme avec l'option "/?". Default_video_mode = window ; (default 'window') ; Window dimensions. The program | Dimensions de la fentre en mode ; remembers the last window size. | fentr. Default_window_size = 640,480 ; (default '640,480') ; This setting allows you merge successive mouse movements into a single ; mouse movement. You should only use it if you are using a mouse which ; reports at 200Hz or more, and you experience lag when using discontinuous ; hand-drawing with large brushes (this tool tries to paste the brush and ; update the screen on each new mouse position) In this case, set this to 2 ; or more, to ignore some intermediate mouse reports when a more recent one ; is present. ; Note that with a value superior to 1, you lose precision with continuous ; hand-drawing, as intermediate mouse positions are skipped. Merge_movement = 0 ; (default 0) ; Number of columns in the palette of the menu bar. Can be any number from ; 1 to 256. If there is not enough room, the program will display less ; columns. But your preference will be kept, and as soon as there is more ; space in the screen, more columns will be shown. ; Palette_Cells_X = 8; (Default 8) ; Number of lines in the palette of the menu. Can be any number from ; 1 to 16. The menu can always display the number of lines you request. ; Palette_Cells_Y = 8; (Default 8) ; Bookmarked directories. Leave the directory blank for unused ones. ; Bookmark_label = Bookmark_directory = Bookmark_label = Bookmark_directory = Bookmark_label = Bookmark_directory = Bookmark_label = Bookmark_directory = ; In the classic layout, the palette in the menu has colors from left to ; right. If you prefer the colors ordered top to bottom, set this option ; to YES. ; Palette_vertical = NO; (Default NO) ; The program remembers the last window position, if the ; OS isn't able to do it by itself. (ie: Windows) Window_position = 9999,9999; (Default 9999,9999 which means: NA) ; This is the time (in milliseconds) between two clicks for Grafx2 to ; recognize a double-click. Double-click is used mostly in the palette ; area of the menu: double-click a color to open the palette. Double_click_speed = 500; (Default 500) ; When you press two digit keys in rapid succession (ex: 3 8), Grafx2 ; sets transparency to 38% (instead of 30% then 80%). This setting ; allows you to set the maximum delay between two keypresses for ; GrafX2 to recognize them as a combo. Double_key_speed = 500; (Default 500) ; Name of the skinfile you want to | Nom du fichier skin que vous voulez ; use. | utiliser. ; Default : (empty to let the program choose) Skin_file = ; Name of the font file (8x8) you | Nom du fichier police de caractre ; want to use. | 8x8 utilise dans les menus. ; Default : (empty to let the program choose) Font_file = ; This determines the color value for the grid. Each pixel of ; the grid will be displayed by XOR-ing the original color with ; the value of this setting. ; For example, if you always paint 16-color images, you can set it ; to 16 so the color of the grid are 16 for 0, 17 for 1, etc. ; Then you can set colors 16-31 as lighter/darker variants ; of your original palette, resulting in a pretty grid ! ; ; Valid values are 1 to 255. Grid_XOR_color = 255; (Default 255) ; This records the last pixel ratio used, to restore it on start. ; Valid values are from 0 to 7 for: Simple, Wide, Tall, Double, ; Triple, Wide2, Tall2, Quadruple. ; Pixel_ratio = 0; (Default 0) ; This records the visibility of toolbars, to restore them on start. ; It's a bitfield, where 1=Status, 2=Layers, 4=Tools ; Menubars_visible = 255; (Default 255) ; This enables a mode where right mouse buttons acts as ; a color picker, with most tools. ; Right_click_colorpick = NO; (Default NO) ; When this mode is active, scrolling the view (and the magnifier view) ; affects both the main image and the spare page - as long as they have ; the same dimensions. ; Sync_views = YES; (Default YES) ; This setting determines which key inverts the mouse buttons ; when it's held : A left click is then interpreted as a right-click. ; It's especially useful for one-button controllers, ; such as touchscreens and tablets. ; Possible values are 0 (none), 1 (control), 2 (alt) ; Swap_buttons = 1; (Default 1) ; Last directory browsed with the script selector. ; Leave blank to initially start in (data directory)/scripts ; Scripts_directory = ; When this setting is disabled, and you create a shortcut with a key that ; is already associated to another shortcut, Grafx2 will unset the latter. ; If you enable this mode, Grafx2 will not make such check, so you can design ; shortcuts that trigger several actions at once. ; Allow_multi_shortcuts = no; (Default no) ; end of configuration grafx2/share/grafx2/scripts/samples_2.3/brush/ApplyColor.lua0000644000076400010400000000701011546116166024361 0ustar vigAdministrator--BRUSH Remap: Apply PenColor --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program 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. See dofile("../libs/dawnbringer_lib.lua") OK,tin,clz,fade,amt,brikeep,falloff,nobg,briweight = inputbox("Apply PenColor 2 Brush", "1. Tint", 1, 0,1,-1, "2. Colorize", 0, 0,1,-1, "BG->FG color Fade", 0, 0,1,0, "AMOUNT % (0-100)", 100, 0,100,0, "Preserve Brightness", 1, 0,1,0, "Bri/Dark FallOff", 1, 0,1,0, "Exclude Background", 1,0,1,0, "ColMatch Bri-Weight %", 25, 0,100,0 ); if OK == true then function cap(v) return math.min(255,math.max(v,0)); end w, h = getbrushsize() fg = getforecolor() bg = getbackcolor() fR,fG,fB = getcolor(fg) bR,bG,bB = getcolor(bg) pal = db.fixPalette(db.makePalList(256)) if nobg == 1 then pal = db.stripIndexFromPalList(pal,bg) -- Remove background color from pallist end amtA = amt / 100 amtR = 1 - amtA -- Normalize Pen Color lev = (fR+fG+fB)/3 fR = fR - lev fG = fG - lev fB = fB - lev --------------------------------------------------- -- Colorize (Colourant) (just apply colorbalance) -- Tint (make grayscale and apply colorbalance) -- -- I think it should be the other way around since colorize is the process of adding color to B&W film... -- But this is the what Brilliance and others call it -- if clz == 1 or tin == 1 then cols = {} for n = 0, 255, 1 do r,g,b = getcolor(n) a = db.getBrightness(r,g,b) mR,mG,mB = fR,fG,fB -- Fade between bg & fg pencolor across dark-bright if fade == 1 then lf = a / 255 lr = 1 - lf mR = bR*lr + fR*lf mG = bG*lr + fG*lf mB = bB*lr + fB*lf lev = (mR+mG+mB)/3 mR = mR - lev mG = mG - lev mB = mB - lev end fr,fg,fb = mR,mG,mB if brikeep == 1 then -- Loose Brightness preservation (ex: applying full red to dark colors) brin = db.getBrightness(cap(r+mR),cap(g+mG),cap(b+mB)) itot = brin - a fr = mR - itot fg = mG - itot fb = mB - itot end -- Falloff (Effect weakens at dark and bright colors) if falloff == 1 then fo = 1 - math.abs((a - 127.5)/127.5)^2 fr = fr * fo fg = fg * fo fb = fb * fo end if tin == 1 then --cols[n+1] = matchcolor((a+fr)*amtA + r*amtR, (a+fg)*amtA + g*amtR, (a+fb)*amtA + b*amtR) cols[n+1] = db.getBestPalMatchHYBRID({(a+fr)*amtA+r*amtR, (a+fg)*amtA + g*amtR, (a+fb)*amtA + b*amtR},pal,briweight / 100,true) end if clz == 1 then --cols[n+1] = matchcolor((r+fr)*amtA + r*amtR, (g+fg)*amtA + g*amtR, (b+fb)*amtA + b*amtR) cols[n+1] = db.getBestPalMatchHYBRID({(r+fr)*amtA+r*amtR, (g+fg)*amtA + g*amtR, (b+fb)*amtA + b*amtR},pal,briweight / 100,true) end end if nobg == 1 then cols[getbackcolor()+1] = getbackcolor(); end for x = 0, w - 1, 1 do for y = 0, h - 1, 1 do putbrushpixel(x, y, cols[getbrushpixel(x,y) + 1]); end end end; -- eof Colorize & Tint -------------------------------------------------------- end -- OK grafx2/share/grafx2/scripts/samples_2.3/brush/Fisheye.lua0000644000076400010400000000162511546116042023670 0ustar vigAdministrator--BRUSH Distortion: FishEye --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program 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. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project --http://goto.glocalnet.net/richard_fhager/evalion/evalion.html w, h = getbrushsize() for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do ox = x / w; oy = y / h; v = (math.cos((ox-0.5)*math.pi)*math.cos((oy-0.5)*math.pi))*0.85; ox = (1 + ox - (ox-0.5)*v) % 1; oy = (1 + oy - (oy-0.5)*v) % 1; c = getbrushbackuppixel(math.floor(ox*w),math.floor(oy*h)); putbrushpixel(x, y, c); end end grafx2/share/grafx2/scripts/samples_2.3/brush/GrayscaleAvg.lua0000644000076400010400000000106311546116042024640 0ustar vigAdministrator--BRUSH Remap: Grayscale (average) --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program 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. See w, h = getbrushsize() for x = 0, w - 1, 1 do for y = 0, h - 1, 1 do r, g, b = getcolor(getbrushpixel(x,y)) a = (r+g+b)/3 putbrushpixel(x, y, matchcolor(a,a,a)); end end grafx2/share/grafx2/scripts/samples_2.3/brush/GrayscaleDesat.lua0000644000076400010400000000166611546116042025174 0ustar vigAdministrator--BRUSH Remap: Grayscale (desaturate) --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program 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. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project --http://goto.glocalnet.net/richard_fhager/evalion/evalion.html percent = 100 -- function desaturate(percent,r,g,b) -- V1.0 by Richard Fhager p = percent / 100 a = (math.min(math.max(r,g,b),255) + math.max(math.min(r,g,b),0)) * 0.5 * p r = r + (a-r*p) g = g + (a-g*p) b = b + (a-b*p) return r,g,b end -- w, h = getbrushsize() for x = 0, w - 1, 1 do for y = 0, h - 1, 1 do putbrushpixel(x, y, matchcolor(desaturate(percent,getcolor(getbrushpixel(x,y))))); end end grafx2/share/grafx2/scripts/samples_2.3/brush/Halfsmooth.lua0000644000076400010400000000156011546116042024376 0ustar vigAdministrator--BRUSH: Halfsize with smoothscaling --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program 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. See w, h = getbrushsize() setbrushsize(math.floor(w/2),math.floor(h/2)) for x = 0, w - 1, 2 do for y = 0, h - 1, 2 do r1,g1,b1 = getcolor(getbrushbackuppixel(x,y)); r2,g2,b2 = getcolor(getbrushbackuppixel(x+1,y)); r3,g3,b3 = getcolor(getbrushbackuppixel(x,y+1)); r4,g4,b4 = getcolor(getbrushbackuppixel(x+1,y+1)); r = (r1 + r2 + r3 + r4 ) / 4; g = (g1 + g2 + g3 + g4 ) / 4; b = (b1 + b2 + b3 + b4 ) / 4; c = matchcolor(r,g,b); putbrushpixel(x/2, y/2, c); end end grafx2/share/grafx2/scripts/samples_2.3/brush/Waves.lua0000644000076400010400000000200411546116042023351 0ustar vigAdministrator--BRUSH Distortion: Waves v1.0 --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program 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. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project -- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html --frq = 2 --amp = 0.3 -- Adjust power of frequency & amplitude frq_adj = 2 amp_adj = 0.02 ok,frq,amp = inputbox("Settings", "Frequency 1-10", 3, 1,10,0, "Amplitude 1-10", 3, 1,10,0 ); w, h = getbrushsize() for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do ox = x / w; oy = y / h; ox = (1 + ox + math.sin(oy*math.pi*frq*frq_adj)*amp*amp_adj) % 1; c = getbrushbackuppixel(math.floor(ox*w),y); putbrushpixel(x, y, c); end end grafx2/share/grafx2/scripts/samples_2.3/demo/3DPalette.lua0000644000076400010400000002543411546116156023674 0ustar vigAdministrator--3D-Palette viwer V0.7 (HSL-models added, 3D-World added, Pen-color only cycles thru unique colors, InputBox) --by Richard 'Dawnbringer' Fhager -- Mouse: Rotate Cube (Stops animation) -- Arrow-keys: Move Cube (in 3D world) -- F1: Start/Stop animation -- F2: Reset -- F3: Increase Color-Size -- F4: Decrease Color-Size -- F5: (Wip) Cycle thru selected PenColor (Note that only unique colors are displayed) -- F9: RGB-space model --F10: HSL-space model --F11: HSLcubic-space model -- "+" (Num): Zoom In -- "-" (Num): Zoom Out -- Esc: Exit script dofile("../libs/dawnbringer_lib.lua") BRIDIAG_SHOW = 1 -- Show brightness/Grayscale diagonal (1 = on, 0 = off) ANIM = 1 -- Animation (1 = on, 0 = off) BOX_DRK = 8 -- Darkest color used for box (0-255) BOX_BRI = 112 -- Brightest color used for box (0-255) COLSIZE_BASE = 26 -- Colors base size (value to adjusted by palette-size, with 2 cols maxsize is v / 1.23) -- OK,RGB,HSL,HSLC,BOX_BRI,COLSIZE_BASE,SET800x600 = inputbox("3D-Palette Viever Settings", "1. RGB space [F9]", 1, 0,1,-1, "2. HSL space [F10]", 0, 0,1,-1, "3. HSL-cubic space [F11]",0, 0,1,-1, "Box Brightness (16-255)", BOX_BRI, 16,255,0, "Col Size (1-100) [F3/F4]", COLSIZE_BASE, 1,100,0, "Set Screen to 800x600", 1,0,1,0 ); -- if OK then if SET800x600 == 1 then setpicturesize(800,600); end SPACE = "rgb" FORM = "cube" if HSL == 1 then SPACE = "hsl" FORM = "cylinder" end if HSLC == 1 then SPACE = "hsl_cubic" FORM = "cube" end pal = db.fixPalette(db.makePalList(256)) FG = getforecolor() BG = getbackcolor() palcol = FG -- function initColors(space) for n = 1, #pal, 1 do c = pal[n]; if space == "rgb" then cols[n] = {c[1]/128-1,c[2]/128-1,c[3]/128-1,c[4]}; end if space == "hsl_cubic" then cols[n] = {} cols[n][1] = (db.getHUE(c[1],c[2],c[3],0) / 6.0 * 255) / 128 - 1 cols[n][2] = (db.getSaturation(c[1],c[2],c[3])) / 128 - 1 cols[n][3] = (db.getLightness(c[1],c[2],c[3])) / 128 - 1 cols[n][4] = c[4] end if space == "hsl" then cols[n] = {} hue = db.getHUE(c[1],c[2],c[3],0) / 6.0 * math.pi*2 rad = db.getSaturation(c[1],c[2],c[3]) / 256 cols[n][1] = math.cos(hue) * rad cols[n][2] = math.sin(hue) * rad cols[n][3] = (db.getLightness(c[1],c[2],c[3])) / 128 - 1 cols[n][4] = c[4] end end end -- cols = {} -- Make points of palette colors colz = {} -- To hold calculated points initColors(SPACE) function initPointsAndLines(form,bridiag) if form == "cube" then pts = {{-1,1,-1},{1,1,-1},{1,-1,-1},{-1,-1,-1}, -- The box {-1,1, 1},{1,1, 1},{1,-1, 1},{-1,-1, 1}} lin = {{1,2},{2,3},{3,4},{4,1},{5,6},{6,7},{7,8},{8,5},{1,5},{2,6},{3,7},{4,8}} -- Box Lines if bridiag == 1 then lin[13] = {4,6}; end end if form == "cylinder" then p = 28 pts = {} lin = {} for n = 1, p, 1 do x = math.cos(math.pi*2 / p * (n-1)) y = math.sin(math.pi*2 / p * (n-1)) pts[n] = {x,y,-1} lin[n] = {n,1 + (n%p)} pts[n + p] = {x,y,1} lin[n + p] = {n+p,p + 1 + (n%p)} end lin[p*2+1] = {1,p+1} -- Red (0 degrees) lin[p*2+2] = {p+1,p+1+math.ceil(p/2)} -- Lightness end (needs an even # of points to work) end end boxp = {} -- To hold the calculated points initPointsAndLines(FORM,BRIDIAG_SHOW) w,h = getpicturesize() CX,CY = w/2, h/2 function initAndReset() XANG, YANG, ZANG, ZOOM, COLSIZE_ADJ, XD, YD, WORLD_X, WORLD_Y = 0,0,0,0,0,0,0,0,0 end initAndReset() SIZE = math.min(w,h)/4 DIST = 5 -- Distance perspective modifier, ~5 is nominal, more means "less 3D" CMAXSIZE = math.floor(COLSIZE_BASE / ((#pal)^0.3)) --CMAXSIZE = 8 CMINSIZE = 1 -- Negative values are ok. Color are never smaller than 1 pix BOX_LINE_DIV = 20 -- Number of colors/segments that a box-line can be divided into (depth) BOX_DIV_MULT = BOX_LINE_DIV / (math.sqrt(3)*2) -- Box depth colors box_div = {} for n = 0, BOX_LINE_DIV-1, 1 do c = BOX_DRK + (BOX_BRI / (BOX_LINE_DIV - 1)) * n --box_div[BOX_LINE_DIV - n] = matchcolor(c,c,c) box_div[BOX_LINE_DIV - n] = db.getBestPalMatchHYBRID({c,c,c},pal,0.5,true) end --BOX_COL = matchcolor(80,80,80) BKG_COL = matchcolor(0,0,0) --CUR_COL = matchcolor(112,112,112) function rotate3D(x,y,z,Xsin,Ysin,Zsin,Xcos,Ycos,Zcos) -- PrecCalced cos&sin for speed local x1,x2,x3,y1,y2,y3,f,xp,yp x1 = x y1 = y * Xcos + z * Xsin z1 = z * Xcos - y * Xsin x2 = x1 * Ycos - z1 * Ysin y2 = y1 z2 = x1 * Ysin + z1 * Ycos x3 = x2 * Zcos - y2 * Zsin y3 = x2 * Zsin + y2 * Zcos z3 = z2 return x3,y3,z3 end function do3D(x,y,z,zoom,dist,Xsin,Ysin,Zsin,Xcos,Ycos,Zcos) -- PrecCalced cos&sin for speed local x1,x2,x3,y1,y2,y3,f,xp,yp x1 = x y1 = y * Xcos + z * Xsin z1 = z * Xcos - y * Xsin x2 = x1 * Ycos - z1 * Ysin y2 = y1 z2 = x1 * Ysin + z1 * Ycos x3 = x2 * Zcos - y2 * Zsin y3 = x2 * Zsin + y2 * Zcos z3 = z2 f = dist/(z3 + dist + zoom) xp = x3 * f yp = y3 * f return xp,yp,z3 end function draw3Dline(x1,y1,z1,x2,y2,z2,div,mult,depthlist) local s,xt,yt,xd,yd,zd,xf,yf xd = (x2 - x1) / div yd = (y2 - y1) / div zd = (z2 - z1) / div xf,yf = x1,y1 for s = 1, div, 1 do -- Depth assumes a 1-Box (z ranges from -sq(3) to sq(3)) depth = math.floor(1 + (z1+zd*s + 1.732) * mult) xt = x1 + xd*s -- + math.random()*8 yt = y1 + yd*s -- + math.random()*8 c = depthlist[depth] if c == null then c = 1; end -- Something isn't perfect, error is super rare but this controls it drawline(xf,yf,xt,yt,c) xf = xt yf = yt end end function killinertia() XD = 0 YD = 0 end -- If using 1-box, z is -sq(3) to sq(3) minz = math.sqrt(3) totz = minz * 2 maxrad = CMAXSIZE - CMINSIZE q = 0 delay = 4 move = 0.03 while 1 < 2 do -- Time-for-space-wiggle...or somekindof attempt --WORLD_X = -move --q = (q + 1) % delay --if q < delay/2 then WORLD_X = move; end clearpicture(BKG_COL) Xsin = math.sin(XANG); Xcos = math.cos(XANG) Ysin = math.sin(YANG); Ycos = math.cos(YANG) Zsin = math.sin(ZANG); Zcos = math.cos(ZANG) -- Rotate Box points for n = 1, #pts, 1 do p = pts[n] x,y,z = p[1],p[2],p[3] XP,YP,zp = rotate3D(x,y,z,Xsin,Ysin,Zsin,Xcos,Ycos,Zcos) boxp[n] = {XP,YP,zp} end -- Rotate Colors in palette for n = 1, #cols, 1 do p = cols[n] x,y,z,c = p[1],p[2],p[3],p[4] XP,YP,zp = rotate3D(x,y,z,Xsin,Ysin,Zsin,Xcos,Ycos,Zcos) colz[n] = {XP,YP,zp,c} end ------------------------------------ -- Control world ------------------------------------ -- Calculate points anew -- Worldize Box points for n = 1, #boxp, 1 do s = SIZE v = boxp[n] x = v[1] + WORLD_X y = v[2] + WORLD_Y z = v[3] f = DIST/(z + DIST + ZOOM) XP = CX + x * f * s YP = CY + y * f * s boxp[n] = {XP,YP,z} end -- Worldize Colors in palette for n = 1, #colz, 1 do s = SIZE v = colz[n] x = v[1] + WORLD_X y = v[2] + WORLD_Y z = v[3] c = v[4] f = DIST/(z + DIST + ZOOM) XP = CX + x * f * s YP = CY + y * f * s colz[n] = {XP,YP,z,c} end ------------------------------------- ------------------------------------- -- Brightness Diagonal --if BRIDIAG_SHOW == 1 then -- p1 = boxp[4] -- p2 = boxp[6] -- x1,y1,z1 = p1[1],p1[2],p1[3] -- x2,y2,z2 = p2[1],p2[2],p2[3] -- draw3Dline(x1,y1,z1,x2,y2,z2,BOX_LINE_DIV,BOX_DIV_MULT,box_div) --end -- sort on z db.sorti(colz,3) -- Draw colors for n = #colz, 1, -1 do p = colz[n] XP,YP,zp,c = p[1],p[2],p[3],p[4] radius = CMINSIZE + maxrad - (zp+minz) / totz * maxrad dorad = math.floor(radius - ZOOM*2 + COLSIZE_ADJ) if dorad >= 1 then drawdisk(XP,YP,dorad,c) --db.drawRectangle(XP,YP,dorad,dorad,c) else putpicturepixel(XP,YP,c) end if c == FG or c == BG then sz = math.max(3,dorad + 3) if c == BKG_COL then v = (c+128) % 255; c = matchcolor(v,v,v); end db.drawRectangleLine(XP-sz,YP-sz,sz*2,sz*2,c) end end -- colz -- Draw box for n = 1, #lin, 1 do l = lin[n] p1 = boxp[l[1]] p2 = boxp[l[2]] x1,y1,z1 = p1[1],p1[2],p1[3] x2,y2,z2 = p2[1],p2[2],p2[3] draw3Dline(x1,y1,z1,x2,y2,z2,BOX_LINE_DIV,BOX_DIV_MULT,box_div) end -- eof box --updatescreen(); if (waitbreak(0.00)==1) then return; end repeat old_key = key; old_mouse_x = mouse_x; old_mouse_y = mouse_y; old_mouse_b = mouse_b; updatescreen() moved, key, mouse_x, mouse_y, mouse_b = waitinput(0) if mouse_b == 1 then ANIM = 0; end if (key==27) then return; end if (key==282) then ANIM = (ANIM+1) % 2; end -- F1: Stop/Start Animation if (key==283) then initAndReset(); end -- F2: Reset all values if (key==284) then COLSIZE_ADJ = COLSIZE_ADJ + 0.5; end -- F3 if (key==285) then COLSIZE_ADJ = COLSIZE_ADJ - 0.5; end -- F4 if (key==286) then --FG = (FG + 1) % 255; palcol = (palcol + 1) % #pal FG = pal[palcol+1][4] setforecolor(FG); setcolor(0,getcolor(0)) -- Force update of palette until setforecolor() is fixed end -- F5 if (key==290) then -- F9 initColors("rgb") initPointsAndLines("cube",BRIDIAG_SHOW) end if (key==291) then -- F10 initColors("hsl") initPointsAndLines("cylinder", 0) -- Bridiag won't show even if turned on, it's only for cube end if (key==292) then -- F11 initColors("hsl_cubic") initPointsAndLines("cube",BRIDIAG_SHOW) end if (key==269) then ZOOM = ZOOM + 0.1; end if (key==270) then ZOOM = ZOOM - 0.1; end SPEED = math.pi / 100 if (key==273) then WORLD_Y = WORLD_Y - 0.05; killinertia(); end if (key==274) then WORLD_Y = WORLD_Y + 0.05; killinertia(); end if (key==276) then WORLD_X = WORLD_X - 0.05; killinertia(); end if (key==275) then WORLD_X = WORLD_X + 0.05; killinertia(); end until ((mouse_b == 1 and (old_mouse_x~=mouse_x or old_mouse_y~=mouse_y)) or key~=0 or ANIM==1 or math.abs(XD)>0.01 or math.abs(YD)>0.01); if ANIM == 0 then if (mouse_b==1 and (old_mouse_x~=mouse_x or old_mouse_y~=mouse_y)) then -- Inertia XD = (mouse_y - old_mouse_y)*0.005 YD = (mouse_x - old_mouse_x)*0.005 else XD = XD*0.92 YD = YD*0.92 end XANG = ((XANG - XD) % (math.pi*2)); YANG = ((YANG + YD) % (math.pi*2)); ZANG = 0 end if ANIM == 1 then XANG = (XANG + math.pi/300) % (math.pi*2) YANG = (YANG + math.pi/500) % (math.pi*2) ZANG = (ZANG + math.pi/1000) % (math.pi*2) end --XANG = ((CY-mouse_y) / 200 % (math.pi*2)); --YANG = ((mouse_x - CX) / 200 % (math.pi*2)); --ZANG = 0 statusmessage("X: "..math.floor(XANG*57.3)..", Y: "..math.floor(YANG*57.3)..", Z: "..math.floor(ZANG*57.3)..", Zoom: "..math.floor(-ZOOM*10).." ") end end -- OK grafx2/share/grafx2/scripts/samples_2.3/demo/Ellipse.lua0000644000076400010400000000267011546122070023471 0ustar vigAdministrator--PICTURE scene: Ellipse update-demo (anim) --Demonstrates 'interactive' features. --by Richard Fhager -- Copyright 2011 Richard Fhager -- -- This program 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. See -- -- rot: Rotation in degrees -- stp: Step is # of line segments (more is "better") -- a & b are axis-radius function ellipse2(x,y,a,b,stp,rot,col) local n,m=math,rad,al,sa,ca,sb,cb,ox,oy,x1,y1,ast m = math; rad = m.pi/180; ast = rad * 360/stp; sb = m.sin(-rot * rad); cb = m.cos(-rot * rad) for n = 0, stp, 1 do ox = x1; oy = y1; sa = m.sin(ast*n) * b; ca = m.cos(ast*n) * a x1 = x + ca * cb - sa * sb y1 = y + ca * sb + sa * cb if (n > 0) then drawline(ox,oy,x1,y1,col); end end end -- setpicturesize(300,300) setcolor(0,96,96,96) setcolor(1,255,255,128) r1 = 100 r2 = 50 rt = 0 frames = 100 while (1 < 2) do r1t = 10 + math.random() * 140 r2t = 10 + math.random() * 140 rtt = math.random() * 360 for n = 0, frames-1, 1 do clearpicture(0) f2 = n / frames f1 = 1 - f2 r1a = r1*f1 + r1t*f2 r2a = r2*f1 + r2t*f2 rta = rt*f1 + rtt*f2 -- x, y, r1, r2, stp, rot, col ellipse2(150, 150, r1a, r2a, 50, rta, 1) statusmessage('press ESC to stop') updatescreen();if (waitbreak(0)==1) then return end end r1,r2,rt = r1a,r2a,rta end grafx2/share/grafx2/scripts/samples_2.3/demo/FlipPicture.lua0000644000076400010400000000143411546110272024320 0ustar vigAdministrator-- flip picture - Copyright 2010 Paulo Silva -- This program 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. See w,h=getpicturesize(); ok,flipx,flipy=inputbox("flip picture","flip x",1,0,1,-1,"flip y",0,0,1,-1); if ok==true then if flipx==1 then for y=0,h-1,1 do for x=0,w/2,1 do c1=getpicturepixel(x,y);c2=getpicturepixel(w-x-1,y) putpicturepixel(x,y,c2);putpicturepixel(w-x-1,y,c1) end;end else for y=0,h/2,1 do for x=0,w-1,1 do c1=getpicturepixel(x,y);c2=getpicturepixel(x,h-y-1) putpicturepixel(x,y,c2);putpicturepixel(x,h-y-1,c1) end;end;end;end grafx2/share/grafx2/scripts/samples_2.3/demo/SierpinskyCarpet.lua0000644000076400010400000000241311546106310025365 0ustar vigAdministrator--PICTURE: Pattern - Sierpinsky carpet v1.0 --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Email: dawnbringer@hem.utfors.se -- MSN: annassar@hotmail.com -- -- Copyright 2010 Richard Fhager -- -- This program 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. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project -- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html -- frac = {{1,1,1},{1,0,1},{1,1,1}} iter = 6 -- function pattern(x,y,p,n,i) -- Fractal Pattern V1.0 by Richard Fhager (mod allows for wrapping) py = #p px = #p[1] while ((p[1+math.abs(math.floor(y*py))%py][1+math.abs(math.floor(x*px))%px]) == 1 and n -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project -- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html -- frac = {{1,1},{1,0}} iter = 15 -- function pattern(x,y,p,n,i) -- Fractal Pattern V1.0 by Richard Fhager (mod allows for wrapping) py = #p px = #p[1] while ((p[1+math.abs(math.floor(y*py))%py][1+math.abs(math.floor(x*px))%px]) == 1 and n -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project --http://goto.glocalnet.net/richard_fhager/evalion/evalion.html w, h = getbrushsize() if (w<64 or h<64) then setbrushsize(64,64) w=64 h=64 end for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do -- Fractionalize image dimensions ox = x / w; oy = y / h; -- Ball Xr = ox-0.5; Yr = oy-0.5; W = (1 - 2*math.sqrt(Xr*Xr + Yr*Yr)); -- 'FishEye' distortion / Fake 3D F = (math.cos((ox-0.5)*math.pi)*math.cos((oy-0.5)*math.pi))*0.65; ox = ox - (ox-0.5)*F; oy = oy - (oy-0.5)*F; -- Checkers V = ((math.floor(0.25+ox*10)+math.floor(1+oy*10)) % 2) * 255 * W; -- Specularities SPEC1 = math.max(0,(1-5*math.sqrt((ox-0.45)*(ox-0.45)+(oy-0.45)*(oy-0.45)))*112); SPEC2 = math.max(0,(1-15*math.sqrt((ox-0.49)*(ox-0.49)+(oy-0.48)*(oy-0.48)))*255); r = W * 255 + SPEC1 + SPEC2 g = V + SPEC1 + SPEC2 b = V + SPEC1 + SPEC2 putbrushpixel(x, y, matchcolor(r,g,b)); end end grafx2/share/grafx2/scripts/samples_2.3/demo/brush/ColorSphere.lua0000644000076400010400000000164511546122470025451 0ustar vigAdministrator--BRUSH Scene: Sphere of pencolor v1.0 --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program 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. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project --http://goto.glocalnet.net/richard_fhager/evalion/evalion.html w, h = getbrushsize() rp,gp,bp = getcolor(getforecolor()) for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do -- Fractionalize image dimensions ox = x / w; oy = y / h; -- Sphere X = 0.5; Y = 0.5; Rd = 0.5 a = math.sqrt(math.max(0,Rd*Rd - ((X-ox)*(X-ox)+(Y-oy)*(Y-oy)))) * 1/Rd r = rp * a g = gp * a b = bp * a putbrushpixel(x, y, matchcolor(r,g,b)); end end grafx2/share/grafx2/scripts/samples_2.3/demo/brush/FindAA.lua0000644000076400010400000000350311546122660024302 0ustar vigAdministrator--BRUSH: Find AA-colors from pencolors --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program 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. See cellw = 8 cellh = 4 colors = 256 setbrushsize(cellw * 3, cellh * 3) -- function makePalList(cols) pal = {} for n = 0, cols-1, 1 do r,g,b = getcolor(n) pal[n+1] = {r,g,b} end return pal end -- -- function getBestPalMatchHYBRID(rgb,pal,briweight) local diff,diffC,diffB,best,bestcol,cols,n,c,r,g,b,p,obri,pbri cols = #pal bestcol = 0 best = 9e99 r = rgb[1] g = rgb[2] b = rgb[3] obri = math.pow(r*9,2)+math.pow(g*16,2)+math.pow(b*8,2) for n=0, cols-1, 1 do p = pal[n+1] pbri = math.pow(p[1]*9,2)+math.pow(p[2]*16,2)+math.pow(p[3]*8,2) diffB = math.abs(obri - pbri) diffC = (math.pow(r-p[1],2)+math.pow(g-p[2],2)+math.pow(b-p[3],2)) * 400 --diff = diffB + diffC diff = briweight * (diffB - diffC) + diffC if diff <= best then bestcol = n; best = diff; end end return bestcol end -- -- function drawRectangle(x1,y1,w,h,c) for y = y1, y1+h, 1 do for x = x1, x1+w, 1 do putbrushpixel(x,y,c); end end end -- palList = makePalList(colors) cf = getforecolor() cb = getbackcolor() rf,gf,bf = getcolor(cf) rb,gb,bb = getcolor(cb) ra = (rf + rb) / 2 ga = (gf + gb) / 2 ba = (bf + bb) / 2 rgb1 = {ra,ga,ba} c1 = getBestPalMatchHYBRID(rgb1,palList,0.0) c2 = getBestPalMatchHYBRID(rgb1,palList,0.75) c3 = getBestPalMatchHYBRID(rgb1,palList,0.99) q = {{cf,c1,cb}, {cf,c2,cb}, {cf,c3,cb}} for y = 0, #q-1, 1 do for x = 0, #q[1]-1, 1 do drawRectangle(x*cellw,y*cellh,cellw,cellh,q[y+1][x+1]) end end grafx2/share/grafx2/scripts/samples_2.3/demo/brush/Mandelbrot.lua0000644000076400010400000000246511546121436025315 0ustar vigAdministrator--BRUSH Scene: Mandelbrot fractal v0.5 -- --Draws a Mandelbrot fractal in the current brush. -- --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program 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. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project --http://goto.glocalnet.net/richard_fhager/evalion/evalion.html colors = 64 x0 = -1.7 x1 = 0.7 ym = 0 iter = 64 ok, x0, x1, ym, iter = inputbox("Fractal data", "X0", x0, -2, 2,4, "X1", x1, -2, 2,4, "midY", ym, -2, 2,4, "Iter", iter, 1, 2048,0 ); -- -0.831116819,-0.831116815,0.2292112435,192 function mandel(x,y,l,r,o,i) -- pos. as fraction of 1, left coord, right coord, y coord, iterations local w,s,a,p,q,n,v,w s=math.abs(r-l); a = l + s*x; p = a; b = o - s*(y-0.5); q = b; n = 1; v = 0; w = 0; while (v+w<4 and n 0 then s = 1; end if v < 0 then s = -1; end return s end -- -- function db.rotation (rot_ang,hub_x,hub_y,x,y) -- Rotate coordinates x & y relative hub local new_ang,dist,m,xd,yd,v; m = math xd=hub_x-x; yd=hub_y-y; if (not(xd==0 and yd==0)) then v = -90; if xd < 0 then v = 90; end new_ang = m.atan(yd/xd) - (v+rot_ang) * m.pi/180; dist = m.sqrt(xd*xd+yd*yd); x = hub_x - m.sin(new_ang)*dist; y = hub_y + m.cos(new_ang)*dist; end return math.floor(x),math.floor(y) -- For drawing purposes end -- -- -- ... eof Custom Math Functions ... -- -- ************************************* -- *** Fractional Scenery *** -- ************************************* -- function db.setSceneryPalette() db.colorCigarr(10,28,true) -- 250 colors setcolor(250, 208,48,48) setcolor(251, 48,208,48) setcolor(252, 48,48,208) setcolor(253, 224,224,64) setcolor(254, 224,64,224) setcolor(255, 64,224,224) end -- -- function db.star(xf,yf,sx,sy,rgb,haz,out,lum) local n,c,dist; c={} dist = haz + out * math.sqrt((xf-sx)^2+(yf-sy)^2); for n = 1, 3, 1 do c[n] = (rgb[n] * lum) / dist; end return c; end -- -- function db.zoom(xf,yf,zoom,panx,pany) -- Zoom and Pan in a fractional coord-system xf = (xf-0.5)/zoom + 0.5 + panx; yf = (yf-0.5)/zoom + 0.5 + pany; return xf,yf end -- -- function db.rotationFrac(rot_ang,hub_x,hub_y,x,y) -- Rotate coordinates x & y relative hub local new_ang,dist,m,xd,yd,v; m = math xd=hub_x-x; yd=hub_y-y; if (not(xd==0 and yd==0)) then v = -90; if xd < 0 then v = 90; end new_ang = m.atan(yd/xd) - (v+rot_ang) * m.pi/180; dist = m.sqrt(xd*xd+yd*yd); x = hub_x - m.sin(new_ang)*dist; y = hub_y + m.cos(new_ang)*dist; end return x,y end -- -- function db.twirl(x,y,arms,trot,tpow,tang) local b,ang,vx,vy,vr,m,deg,tw m=math; deg=math.pi/180; tw=.5; if (not(x==.5 and y==.5)) then ang = m.atan((.5-y)/(.5-x)); b = 0; if (x>.5) then b = m.pi; end vx = .5-x; vy = .5-y; vr = m.pow(m.sqrt(vx*vx+vy*vy),tpow); tw = .5+m.sin(-tang*deg+vr*trot+(ang + b)*arms)*.5; end return tw; end -- --- Alpha filters -- function db.alpha1(x,y,amp) -- Coord, Amplify: 0..n local p,a,xh,yh,m xh=0.5-x; yh=0.5-y; m = math p = m.pow(xh*xh+yh*yh,0.7); a = m.cos(32*m.pi*p)*m.sin(8*m.pi*(xh+yh)); return 1 + (a * amp) end -- -- -- ... eof Fractional Scenery ... -- -- ************************************* -- *** Custom Array Functions *** -- ************************************* -- -- Ok, I don't know Lua that well (still unsure about some scopes & refs etc.) -- And some features may not be active in Grafx2. So, some of the follwing functions -- may exist in Lua/Grafx2...but since I'm not sure if and how they work - I'll prefer -- to add a set of my own of known performance. -- function db.newArrayInit2Dim(xs,ys,val) local x,y,ary; ary = {} for y = 1, ys, 1 do ary[y] = {} for x = 1, xs, 1 do ary[y][x] = val end end return ary end -- -- -- Merge two arrays into a NEW one: array_c = db.newArrayMerge(array_b,array_b) -- function db.newArrayMerge(a,b) local n,ary; ary = {} for n = 1, #a, 1 do ary[n] = a[n] end for n = 1, #b, 1 do ary[n+#a] = b[n] end return ary end -- -- -- Generate a copy of an array with a new value added Last -- function db.newArrayInsertLast(a,val) local n,ary; ary = {} for n = 1, #a, 1 do ary[n] = a[n] end ary[#a+1] = val return ary end -- -- -- Generate a copy of an array with a new value added First -- function db.newArrayInsertFirst(a,val) local n,ary; ary = {} ary[1] = val for n = 2, #a+1, 1 do ary[n] = a[n-1] end return ary end -- -- function db.ary2txt(ary) -- One & two dimensions supported [a,b] -> "a,b". [[a,b],[c,d]] -> "a-b, c-d" local t,n,m,v t = "" for n = 1, #ary, 1 do if type(ary[n]) == "table" then t = t..ary[n][1] for m = 2, #ary[n], 1 do t = t.."-"..ary[n][m] end else t = t..ary[n]; end t = t..", " end return t end -- -- -- ... eof Custom Array Functions ... -- -- ************************************* -- *** Misc. Logical Operations *** -- ************************************* -- -- palList [r,g,b,palindex] is expected only to contain unique colors -- index = -1 --> index of list -- function db.makeIndexList(list,index) local n,ilist ilist = {} for n = 1, #list, 1 do if (index > 0) then ilist[n] = list[n][index]; end if (index == -1) then ilist[n] = n; end end return ilist end -- -- -- Return a list of all possible (non-same) pairs from the entries in a list -- [a,b,c] --> [[a,b],[a,c],[b,c]] -- (All entries are treated as unique. i.e it's only the INDEX that counts) -- mode = 0: Only unique pairs (m = (n^2 - n)/2), [a,b] --> [[a,b]] -- mode = 1: All pairs, i.e mirror versions as well. (m = n^2 - n), [a,b] --> [[a,b], [b,a]] -- function db.pairsFromList(list,mode) local a,b,l,n,pairs pairs = {} l = #list n = 1 for a = 1, l, 1 do for b = a+1, l, 1 do pairs[n] = {list[a],list[b]}; n = n + 1 if mode == 1 then pairs[n] = {list[b],list[a]}; n = n + 1; end end end return pairs end -- function db.valueInArray(ary,val) local n,res res = false for n = 1, #ary, 1 do if ary[n] == val then res = true; break; end end return res end -- RAMP specific -- Remove initial pair (palList) colors from pallist function db.initiateRamp(pair,pallist,pal_index) local n,found,plist plist = {} found = 1 for n = 1, #pallist, 1 do if db.valueInArray(pair,pallist[n]) == false then plist[found] = pallist[n]; found = found + 1; end end pair[pal_index] = plist -- ex: ["pal"] return pair -- Is now a 2 color RAMP end -- -- Remove new col entry from ramp's pallist and add it to the ramp, returns an updated ramp -- RampList = [1,2] ["pal"] = palList = [3,4,5], addindex = 3 -- --> [1,2,3] palList = [4,5] function db.updateRamp(ramp,addindex,pal_index) local n,found,pallist,plist,newramp plist = {} pallist = ramp[pal_index] -- New palList without added color to IndexList found = 1 for n = 1, #pallist, 1 do if pallist[n] ~= addindex then plist[found] = pallist[n]; found = found + 1; end end newramp = db.newArrayInsertLast(ramplist,addindex) newramp[pal_index] = plist return rlist end -- -- Returns a list of all inital ramps from color pairs -- -- Weeds out bad pairs, attaches remaining palette colors and the first rgb-vector -- -- function db.initiateRampList(pairs,pallist,pal_index,vec_index,min,maxmult,rw,gw,bw) local n,ramplist,newpairs,accept,dist,c1,c2,max,rD,gD,bD ramplist = {} max = min + (142 / math.sqrt(#pallist)) * maxmult -- min ex: 8-12 accept = 0 for n = 1, #pairs, 1 do c1 = pallist[pairs[n][1]] c2 = pallist[pairs[n][2]] rD = c2[1] - c1[1] gD = c2[2] - c1[2] bD = c2[3] - c1[3] dist = math.sqrt( (rw*rD)^2 + (gw*gD)^2 + (bw*bD)^2 ) if dist >= min and dist <= max then accept = accept + 1; ramplist[accept] = db.initiateRamp(pairs[n],pallist,pal_index); ramplist[accept][vec_index] = {rD, gD, bD, dist}; -- Add first color vector, ONLY KEEP DISTANCE? end end return ramplist end function db.findRampExpansionColors(ramp) local clist clist = {} -- Calculate vectors here? return clist end function db.findRAMPS(min_len, max_len) local i,n,c,pallist,ramp,ramplist,pairs,spairs,palindex,vecindex,found,donelist,newlist,dones local colorlist palindex = "pal" vecindex = "vector" pallist = db.fixPalette(db.makePalList(256), 0) pairs = db.pairsFromList(db.makeIndexList(pallist,-1), 0) ramplist = db.initiateRampList(pairs,pallist,palindex,vecindex, 8,0.75, 0.26,0.55,0.19) -- MIN_LEN = 5 -- MAX_LEN = 10 -- Split Ramp-build into two parts: -- 1. Build ramps >= MIN_LEN, NONE added to 'Done' -- 2. Run til no more ramps can be expanded or reaches MAX_LEN, ALL ramps added to 'Done' for i = 1, (min_len - 2), 1 do -- Assuming 2 for inital pairs (2 color ramps) newlist = {} found = 0 for n = 1, #ramplist, 1 do ramp = ramplist[n] colorlist = db.findRampExpansionColors(ramp) -- Colors that can split the current ramp into new expanded ramps for c = 1, #colorlist, 1 do found = found + 1; newlist[found] = db.updateRamp(ramp,colorlist[c],palindex); -- Ramp is expanded by 1 color end end ramplist = newlist end donelist = {}; dones = 0 repeat newlist = {} found = 0 for n = 1, #ramplist, 1 do ramp = ramplist[n] if true == false then found = found + 1; newlist[found] = db.updateRamp(ramp,color,palindex); else dones = dones + 1; donelist[dones] = ramp; end end --ramplist = newlist until found == 0 return #pairs.." - "..#ramplist end -- -- ... eof Misc. Logical Operations ... -- -- *************************************** -- *** General RGB-Color Modifications *** -- *************************************** -- function db.makeComplimentaryColor(r,g,b,brikeeplev) -- Lev: 0 = Normal, 1 = Loose, 2 = Strict local bri_o,bri_n,bdiff function cap(v) return math.max(0,math.min(v,255)); end bri_o = db.getBrightness(r,g,b) r,g,b = db.shiftHUE(r,g,b,180) if brikeeplev > 0 then for n = 0, brikeeplev*3-1, 1 do -- Must iterate to reduce brightness error bri_n = db.getBrightness(r,g,b) bdiff = (bri_o - bri_n) / 2 * brikeeplev r = cap(r + bdiff) g = cap(g + bdiff) b = cap(b + bdiff) end end return r,g,b end -- -- *** Color balance *** -- -- bri_flag: Preserve brightness -- loose_flag: Loose preservation restrictions for brightness and balance -- -- Jeez, was this a tricky sucker; color-balance is just adding and capping... -- but trying color-balance with preserved perceptual brightness is a different monster... -- ...so bad I could only solve it by iterative error correction. -- function db.ColorBalance(r,g,b,rd,gd,bd,bri_flag,loose_flag) -- preserve brightness local rw,gw,bw,ri,gi,bi,itot,rni,gni,bni,ro,go,bo,ovscale,lev,count,rt,gt,bt,rf,gf,bf,bri -- Dawn 3.0, [0.26,0.55,0.19], 0-255 bri-colorscale adjust = 1.56905 rw,gw,bw = 0.26, 0.55, 0.19 function cap(v) return math.min(255,math.max(v,0)); end bri = db.getBrightness(r,g,b) -- Loose brightness & balance preservation, a good compromise. if bri_flag == true and loose_flag == true then lev = (rd + gd + bd) / 3 rd = rd - lev gd = gd - lev bd = bd - lev brin = db.getBrightness(cap(r+rd),cap(g+gd),cap(b+bd)) itot = brin - bri rd = rd - itot gd = gd - itot bd = bd - itot end if bri_flag == true and loose_flag == false then itot = 255 count = 0 -- Normalize (Yup, it's right only to normalize once first..cont.norm. will have some counter-effect) lev = (rd + gd + bd) / 3 rd = rd - lev gd = gd - lev bd = bd - lev repeat --messagebox("Norm:"..rd..", "..gd..", "..bd) -- Calculate total brightness change -- Note: Perceptual Brightness is exponential, and can't be delta-adjusted for anything other than greyscales. -- Although the formula for the new brightness corrected normalization level can can be derived... -- ...it doesn't do much good since the bigger problem is overflow outside the 0-255 boundary. -- As for now, I see no other means to solve this issue than with iterative error-correction. rt = r+rd gt = g+gd bt = b+bd itot = 9e99 rni = rd gni = gd bni = bd -- We can get brightness of negative values etc. So bri-correction is put on hold until values are scaled down if (rt>=0 and gt>=0 and bt>=0) and (rt<256 and gt<256 and bt<256) then brin = db.getBrightness(rt,gt,bt) itot = brin - bri --messagebox("Bri Diff: "..itot) -- Brightness adjusted balance rni = rd - itot gni = gd - itot bni = bd - itot end --messagebox("Bri Adj Bal:"..rni..", "..gni..", "..bni) -- Apply balance to find overflow (as fraction of the channel change) ro = math.max( math.max((r + rni)-255,0), math.abs(math.min((r + rni),0)) ) / math.max(math.abs(rni),1) go = math.max( math.max((g + gni)-255,0), math.abs(math.min((g + gni),0)) ) / math.max(math.abs(gni),1) bo = math.max( math.max((b + bni)-255,0), math.abs(math.min((b + bni),0)) ) / math.max(math.abs(bni),1) ovscale = 1 - math.max(ro,go,bo) -- Scaling balances might be logically incorrect (as they can be seen as constant differences) -- But scaling DOWN is quite harmless and I don't see how it could be done otherwise... -- ex: +10 red, +5 blue: Scale x2 = +20 red, +10 blue -> More red over blue than ordered, a contrast behaviour. -- +10 red, +5 blue: Scale x0.5 = +5 red, +2.5 blue -> Less of everything, but a part of the order. Harmless? -- rd = rni * ovscale gd = gni * ovscale bd = bni * ovscale count = count + 1 --messagebox("Final bal:"..rd..", "..gd..", "..bd) until math.abs(itot) < 1 or count > 5 end rf = r + rd gf = g + gd bf = b + bd --messagebox("Result color:"..rf..", "..gf..", "..bf) return rf,gf,bf end -- -- -- bri_flag: Preserve brightness -- cap_flag: Cap new color at 0-255, has a desaturating effect for large values. -- function db.ColorBalanceXXX(r,g,b,rd,gd,bd,bri_flag,cap_flag) -- preserve brightness local rf,gf,bf if cap_flag == true then rd = math.min(255,math.max(0, r+rd)) - r gd = math.min(255,math.max(0, g+gd)) - g bd = math.min(255,math.max(0, b+bd)) - b end local rw,gw,bw,ri,gi,bi,itot,rni,gni,bni,ro,go,bo,ovscale -- Dawn 3.0, [0.26,0.55,0.19], 0-255 bri-colorscale adjust = 1.56905 rw,gw,bw = 0.26, 0.55, 0.19 if bri_flag == true then -- Calculate total brightness change --ri = rd * rw --gi = gd * gw --bi = bd * bw --itot = math.sqrt(ri^2 + gi^2 + bi^2) bri = db.getBrightness(r,g,b) brin = db.getBrightness(r+rd,g+gd,b+bd) itot = brin - bri -- Normalized and Brightness adjusted balance rni = rd - itot gni = gd - itot bni = bd - itot -- Apply balance to find overflow (as fraction of the channel change) ro = math.max( math.max((r + rni)-255,0), math.abs(math.min((r + rni),0)) ) / math.max(math.abs(rni),1) go = math.max( math.max((g + gni)-255,0), math.abs(math.min((g + gni),0)) ) / math.max(math.abs(gni),1) bo = math.max( math.max((b + bni)-255,0), math.abs(math.min((b + bni),0)) ) / math.max(math.abs(bni),1) ovscale = 1 - math.max(ro,go,bo) rd = rni * ovscale gd = gni * ovscale bd = bni * ovscale end rf = r + rd gf = g + gd bf = b + bd return rf,gf,bf end -- -- function db.getContrast(ch) -- Channel, returns fraction -1..0..1, negative for ch < 127.5 --return math.abs((ch / 127.5) - 1) return (ch / 127.5) - 1 end -- -- function db.getAvgContrast(r,g,b) return (math.abs(db.getContrast(r)) + math.abs(db.getContrast(g)) + math.abs(db.getContrast(b))) / 3 end -- -- -- Mode = 0: Proportional - all colors reach max contrast at 100% -- -- Mode = 1: Linear - percentage simply added -- function db.changeContrastOLD(r,g,b,prc,mode) local m,rd,gd,bd,rv,gv,bv,rc,gc,bc,base,sign base = 1; sign = 1 if prc < 0 then base = 0; sign = -1; end -- decontrast m = prc / 100 * sign -- mode 0 rc = db.getContrast(r) rd = (base - math.abs(rc)) * m * db.sign(rc) rv = (rc+rd+1) * 127.5 gc = db.getContrast(g) gd = (base - math.abs(gc)) * m * db.sign(gc) gv = (gc+gd+1) * 127.5 bc = db.getContrast(b) bd = (base - math.abs(bc)) * m * db.sign(bc) bv = (bc+bd+1) * 127.5 return rv,gv,bv end -- function db.changeContrast(r,g,b,prc) -- Photoshop style local m,rd,gd,bd,rv,gv,bv,rc,gc,bc m = 1 + math.pow((255 / 100 * prc),3) / (255*255) -- decontrast if prc < 0 then m = 1 - math.abs(prc)/100 end rc = db.getContrast(r) rd = rc * m rv = (rd+1) * 127.5 gc = db.getContrast(g) gd = gc * m gv = (gd+1) * 127.5 bc = db.getContrast(b) bd = bc * m bv = (bd+1) * 127.5 return rv,gv,bv end -- function db.getBrightness(r,g,b) -- 0-255 local bri --bri = (r+g+b)/3 --bri = r*0.3 + g*0.59 + b*0.11 -- Luma Y'601 --bri = math.sqrt((r*0.3)^2 + (g*0.59)^2 + (b*0.11)^2) -- Luma Y'601 --bri = r*0.245 + g*0.575 + b*0.18 -- Dawn 2.0 bri = math.sqrt((r*0.26)^2 + (g*0.55)^2 + (b*0.19)^2) * 1.56905 -- Dawn 3.0 return bri end -- -- -- Note on desaturation: These functions are all junk, the only way to desaturate -- is to fade a color into it's corresponding greyscale. -- -- function db.desaturate(percent,r,g,b) -- V1.0 by Richard Fhager local a,p p = percent / 100 a = (math.min(math.max(r,g,b),255) + math.max(math.min(r,g,b),0)) * 0.5 * p r = r + (a-r*p) -- a+r*(1-p) g = g + (a-g*p) b = b + (a-b*p) return r,g,b end -- -- function db.desaturateA(percent,c) -- array version local r,g,b,a r = c[1] g = c[2] b = c[3] p = percent / 100 a = (math.min(math.max(r,g,b),255) + math.max(math.min(r,g,b),0)) * 0.5 * p r = r + (a-r*p) g = g + (a-g*p) b = b + (a-b*p) return {r,g,b} end -- -- function db.desatAVG(desat,c) -- Desaturation, simpe average r = c[1] g = c[2] b = c[3] p = desat / 100 a = (r+g+b)/3 r = r + p*(a-r) g = g + p*(a-g) b = b + p*(a-b) return {r,g,b} end -- -- function db.getSaturation(r,g,b) -- HSL local M,m,c,s,l M = math.max(r,g,b) m = math.min(r,g,b) c = (M - m)/255 s = 0 if c ~= 0 then --l = (0.3*r + 0.59*g + 0.11*b)/255 -- HSLuma: Y'601 l = (M+m)/510 -- This produces a quite "correct looking" divison of saturation if l <= 0.5 then s = c / (2*l); end if l > 0.5 then s = c / (2-2*l); end end return math.min(255,s * 255) end -- -- function db.getTrueSaturationX(r,g,b) -- Distance from grayscale axis. Not HSV/HSL local sat,bri bri = (r+g+b) / 3 sat = math.min(255, math.sqrt((r-bri)^2 + (g-bri)^2 + (b-bri)^2) * 1.224744875) return sat end -- -- WIP. Trying to find a more natural model for estimating Saturation -- Current: (HSL + True) / 2 function db.getAppSaturation(r,g,b) return math.min(255, (db.getSaturation(r,g,b) + db.getTrueSaturationX(r,g,b)) / 2) end -- -- function db.saturate(percent,r,g,b) local a,m,p,mc a = (math.min(math.max(r,g,b),255) + math.max(math.min(r,g,b),0)) * 0.5 m = math.min(255-math.max(r,g,b), math.min(r,g,b)) p = percent * (m / 100) mc = math.max((r-a),(g-a),(b-a)) -- Can this be derived elsewhere? if mc ~= 0 then r = r + (r-a) * p / mc g = g + (g-a) * p / mc b = b + (b-a) * p / mc end return r,g,b end -- -- -- Super Saturate: Better than Photoshop etc. -- -- Higher than 100% power is ok -- function db.saturateAdv(percent,r,g,b,brikeeplev,greydamp) -- brikeep = 0 - 2 local a,m,p,mc,bri_o,bri_n,bdiff,mx,mi,adj,q,n function cap(v) return math.max(0,math.min(v,255)); end mx = math.max(r,g,b) mi = math.min(r,g,b) bri_o = db.getBrightness(r,g,b) a = (math.min(mx,255) + math.max(mi,0)) * 0.5 m = math.min(255-mx, mi) p = percent * (m / 100) mc = math.max((r-a),(g-a),(b-a)) -- Can this be derived elsewhere? if mc ~= 0 and m ~= 0 then adj = math.min(1,(mx - mi) / m) -- Reduce effect on low saturation if greydamp == false then adj = 1; end q = p / mc * adj r = cap( r + (r-a) * q ) g = cap( g + (g-a) * q ) b = cap( b + (b-a) * q ) end for n = 0, brikeeplev*2, 1 do -- Must iterate to reduce brightness error bri_n = db.getBrightness(r,g,b) bdiff = (bri_o - bri_n) / 2 * brikeeplev r = cap(r + bdiff) g = cap(g + bdiff) b = cap(b + bdiff) end return r,g,b end -- -- -- Lightness: Darken / Brighten color (Argument and returnvalue is a rgb-list) -- Rate of change is inversely proportional to the distance of the max/min. -- i.e. all colors/channels will reach max/min at the same time (at 0 or 100 %) -- (As opposed to 'Brightness' where all channels are changed by a constant value) -- function db.lightness(percent,c) local v,r,g,b,p r = c[1] g = c[2] b = c[3] p = math.abs(percent/100) v = 255 if percent < 0 then v = 0; end r = r + (v - r)*p g = g + (v - g)*p b = b + (v - b)*p return {r,g,b} end -- -- function db.changeLightness(r,g,b,percent) local v v = db.lightness(percent,{r,g,b}) return v[1],v[2],v[3] end -- -- function db.getLightness(r,g,b) -- HSL bi-hexcone return (math.max(r,g,b) + math.min(r,g,b)) / 2 end -- -- function db.shiftHUE(r,g,b,deg) -- V1.3 R.Fhager 2007, (Heavily derived code, hehe...) local c,h,mi,mx,d,s,p,i,f,q,t c = {g,b,r} mi = math.min(r,g,b) mx = math.max(r,g,b); v = mx; d = mx - mi; s = 0; if mx ~= 0 then s = d/mx; end p = 1; if g ~= mx then p = 2; if b ~= mx then p = 0; end; end if s~=0 then h=(deg/60+(6+p*2+(c[1+p]-c[1+(p+1)%3])/d))%6; i=math.floor(h); f=h-i; p=v*(1-s); q=v*(1-s*f); t=v*(1-s*(1-f)); c={v,q,p,p,t,v} r = c[1+i] g = c[1+(i+4)%6] b = c[1+(i+2)%6] end return r,g,b end -- -- function db.getHUE(r,g,b,greytol) -- 0-6 (6.5 = Greyscale), mult. with 60 for degrees -- 1 Color diff is roughly detected by Tolerance = 0.0078125 (Tol. incr. with lightness etc.) local c,h,mi,mx,d,s,p,i,f,q,t c = {g,b,r} mi = math.min(r,g,b) mx = math.max(r,g,b); v = mx; d = mx - mi; s = 0; if mx ~= 0 then s = d/mx; end p = 1; if g ~= mx then p = 2; if b ~= mx then p = 0; end; end h = 6.5 -- for custom graphical purposes if s>greytol then -- can't use >= h=(6+p*2+(c[1+p]-c[1+(p+1)%3])/d)%6; end return h end -- -- -- ... eof RGB color modifications ... -- -- **************************************** -- *** Custom Color / Palette functions *** -- **************************************** -- function db.rgbcap(r,g,b,mx,mi) local m = math return m.max(mi,m.min(r,mx)), m.max(mi,m.min(g,mx)), m.max(mi,m.min(b,mx)) end -- -- function db.makePalList(cols) local pal,n,r,g,b pal = {} for n = 0, cols-1, 1 do r,g,b = getcolor(n) pal[n+1] = {r,g,b,n} end return pal end -- -- function db.makeSparePalList(cols) local pal,n,r,g,b pal = {} for n = 0, cols-1, 1 do r,g,b = getsparecolor(n) pal[n+1] = {r,g,b,n} end return pal end -- -- -- Use to remove the black colors (marks unused colors) from palette-list -- if it's known that no black color exists in the image. function db.stripBlackFromPalList(pallist) local i,u,c,dummy; i = 257 -- Do 'nothing' If using a full 256 col palette with no blacks for u = 1, #pallist, 1 do c = pallist[u] if (c[1]+c[2]+c[3]) == 0 then i = u; end end dummy = table.remove(pallist,i) return pallist end -- -- function db.stripIndexFromPalList(pallist,colindex) local i,u,c,dummy for u = 1, #pallist, 1 do c = pallist[u] if c[4] == colindex then i = u; end end dummy = table.remove(pallist,i) return pallist end -- -- function db.addHSBtoPalette(pallist) local n,hue,sat,rgb for n=1, #pallist, 1 do rgb = pallist[n] pallist[n][5] = db.getHUE(rgb[1],rgb[2],rgb[3],0) pallist[n][6] = db.getSaturation(rgb[1],rgb[2],rgb[3]) pallist[n][7] = db.getBrightness(rgb[1],rgb[2],rgb[3]) end return pallist -- {r,g,b,n,bri,hue,sat} end -- -- function db.makePalListRange(start,ends) local pal,n,r,g,b,a pal = {} a = 1 for n = start, ends, 1 do r,g,b = getcolor(n) pal[a] = {r,g,b,n}; a = a + 1; end return pal end -- -- function db.makePalListShade(cols,sha) -- Convert colors to less bits, colorcube operations etc. local pal,n,r,g,b,mf,div mf = math.floor div = 256 / sha pal = {} for n = 0, cols-1, 1 do r,g,b = getcolor(n) pal[n+1] = {mf(r/div),mf(g/div),mf(b/div),n} end return pal end -- -- function db.makePalListShadeSPARE(cols,sha) -- Convert colors to less bits, colorcube operations etc. local pal,n,r,g,b,mf,div mf = math.floor div = 256 / sha pal = {} for n = 0, cols-1, 1 do r,g,b = getsparecolor(n) pal[n+1] = {mf(r/div),mf(g/div),mf(b/div),n} end return pal end -- -- function db.getColorDistance_weight(r1,g1,b1,r2,g2,b2,rw,gw,bw) return math.sqrt( (rw*(r1-r2))^2 + (gw*(g1-g2))^2 + (bw*(b1-b2))^2 ) end -- -- function db.getBestPalMatch(r,g,b,pal,index_flag) -- pal = [r,g,b,palindex], index_flag -> return palindex if pal is sorted or reduced local diff,best,bestcol,cols,n,c,p cols = #pal bestcol = -1 best = 9e99 for n=1, cols, 1 do p = pal[n] diff = db.getColorDistance_weight(r,g,b,p[1],p[2],p[3],0.26,0.55,0.19) * 1.569 if diff < best then bestcol = n; best = diff; end end if index_flag == true then bestcol = pal[bestcol][4] + 1 end return bestcol-1 -- palList index start at 1, image-palette at 0 end -- -- Normally this function will return the (image)palette index of best color -- ...but if the palette has been sorted with 'fixPalette' it will return the index -- of the custom palList, setting index_flag will convert this value to image-palette index -- -- HYBRID means the colormatch is a combo of color and (perceptual)brightness -- -- function db.getBestPalMatchHYBRID(rgb,pal,briweight,index_flag) -- Now correctly balanced local diff,diffC,diffB,best,bestcol,cols,n,c,r,g,b,p,obri,pbri cols = #pal bestcol = -1 best = 9e99 --messagebox(briweight) -- Note: Not secured against negative values (this algorithm is SLOW, we cannot afford it) r = rgb[1] g = rgb[2] b = rgb[3] obri = db.getBrightness(r,g,b) -- 0-255 for n=1, cols, 1 do p = pal[n] pbri = db.getBrightness(p[1],p[2],p[3]) diffB = math.abs(obri - pbri) -- we need to normalize the distance by the weights diffC = db.getColorDistance_weight(r,g,b,p[1],p[2],p[3],0.26,0.55,0.19) * 1.569 diff = briweight * (diffB - diffC) + diffC if diff < best then bestcol = n; best = diff; end end if index_flag == true then bestcol = pal[bestcol][4] + 1 -- Since we detract 1 on return, God Lua is stupid end return bestcol-1 -- palList index start at 1, image-palette at 0 end -- -- -- Special version of Hybrid-remapping for mixPalette list -- -- mixpal: {score,col#1,col#2,dist,rm,gm,bm, c1_r,c1_g,c1_b, c2_r,c2_g,c2_b} -- -- returns: {col#1,col#2} (index of palette) -- function db.getBestPalMatchHybridMIX(rgb,mixpal,briweight,mixreduction) local diff,diffC,diffB,best,bestcol,cols,n,c,r,g,b,p,obri,pbri, distmult cols = #mixpal bestcol = -1 best = 9e99 -- We will simply add the the distance to the mix with the distance between the mixcolors and -- employ a user tolerance to much the latter will matter. --distmult = 255 / 9.56 / 100 * mixreduction -- 16 shades distmult = 1.56902 / 100 * mixreduction -- 24-bit, Dawn3.0 colormodel -- Note: Not secured against negative values (this algorithm is SLOW, we cannot afford it) r = rgb[1] g = rgb[2] b = rgb[3] obri = db.getBrightness(r,g,b) -- 0-255 for n=1, cols, 1 do p = mixpal[n] --pbri = db.getBrightness(p[5],p[6],p[7]) -- *** DawnBringer's exponetial color brightness dither resolution phenomena theorem *** -- Bri = color value ^ 2 -- Two adjacent pixels displayed with "normal high resolution" will NOT have the perceptual -- brightness of the resulting mixcolor. The brightness lies closer to that of the brightest pixel. -- Bri[(C1+C2)/2] = SQRT( (C1bri^2 + C2bri^2) / 2 ) -- (Brightness according to Dawn-model: bri = SQRT( (r*.26)^2 + (g*.55)^2 + (b*.19)^2 ) ) pbri = math.sqrt((db.getBrightness(p[8],p[9],p[10])^2 + db.getBrightness(p[11],p[12],p[13])^2) / 2) diffB = math.abs(obri - pbri) -- we need to normalize the distance by the weights diffC = db.getColorDistance_weight(r,g,b,p[5],p[6],p[7],0.26,0.55,0.19) * 1.569 + p[4]*distmult diff = briweight * (diffB - diffC) + diffC if diff <= best then bestcol = n; best = diff; end end return {mixpal[bestcol][2], mixpal[bestcol][3]} --return {mixpal[bestcol][2], 0} end -- -- function db.matchcolorHSB(h,s,b,pallist,index_flag) -- -- why don't we just convert HSB-diagram to RGB and do normal colormatching? -- Not the same... -- local n,c,best,bestcol,pb,ph,ps,diff,huediff,huecorr,hue_adj,sat_adj,bri_adj bestcol = -1 best = 9e99 -- higher adjust means more impact (higher hue gives more interpolation ) hue_adj = 4 sat_adj = 0.075 bri_adj = 2 huecorr = 255 / 6 -- Our Hue goes from 0.0 - 5.999 for n=1, #pallist, 1 do c = pallist[n] ph = c[5] ps = c[6] pb = c[7] huediff = math.abs(h-ph*huecorr) if huediff > 127 then huediff = huediff - (huediff % 127) * 2; end --if ph == 6.5 then huediff = 0; end -- With less saturation, exact hue becomes less important and brightness more usefull -- This allows for greyscales and low saturation colors to work smoothly. huediff = huediff * (ps /255) diff = hue_adj*huediff^2 + (s-ps)^2 * sat_adj + (b-pb)^2 * bri_adj if diff <= best then bestcol = n; best = diff; end end if index_flag == true then bestcol = palList[bestcol][4] + 1 -- Since we detract 1 on return, God Lua is stupid end return bestcol-1 end -- -- -- Used by PaletteAnalysis.lua, FindRamps(), MixColors() -- function db.fixPalette(pal,sortflag) -- Arrange palette & only keep unique colors local n,l,rgb,i,unique,bri,hue,sat,ulist,indexpal,newpal,dtot ulist = {} indexpal = {} newpal = {} local doubles; doubles = {} l = #pal unique = 1 -- ok, see how stupid lua is dtot = 0 for n=1, l, 1 do rgb = pal[n]; -- actually rgbn i = 1 + rgb[1] * 65536 + rgb[2] * 256 + rgb[3]; bri = db.getBrightness(rgb[1],rgb[2],rgb[3]) if indexpal[i] == nil then indexpal[i] = rgb; ulist[unique] = {i,bri}; unique = unique+1; else doubles[rgb[4]] = true; -- Mark as double dtot = dtot + 1 end end -- sort ulist if sortflag == 1 then db.sorti(ulist,2); end -- sort by brightness l = #ulist for n=1, l, 1 do newpal[n] = indexpal[ulist[n][1]] end newpal["doubles"] = doubles newpal.double_total = dtot --messagebox("unique colors", unique-1) return newpal end -- -- -- InsertionSort Array, this is chaos...I'm confused and stomped...don't understand how Lua works... -- ...sorting seem be to ok but this code is ugly... -- Sort LO-HI -- -- Screwed up or confused thing here I think, perhaps lo-hi/hi-lo. This is working lo-hi but the code -- looks like hi-lo...edit this some day -- function db.sorti(d,idx) local a,j,tmp,l,e l = #d for a=2, l, 1 do tmp = d[a]; e = a for j=a, 2, -1 do e = j if d[j-1][idx] > tmp[idx] then d[j] = d[j-1]; e = j-1; else break; end; end; d[e] = tmp; -- WHY THE F**K CAN'T YOU READ j HERE!?! STUPID ASSUCKING LANGUAGE end; --return d end -- -- function db.drawColorspace12bit(x,y,cols,size) local r,g,b,c,rows,row,col,s16,rx,ry,xx,yy s16 = size*16 rows = math.floor(16/cols) for g = 0, 15, 1 do col = g % cols row = math.floor(g / cols) for r = 0, 15, 1 do for b = 0, 15, 1 do c = matchcolor(r*17,g*17,b*17) xx = x+col*s16+r*size yy = y+row*s16+b*size for ry = 0, size-1, 1 do for rx = 0, size-1, 1 do putpicturepixel(xx+rx,yy+ry,c) end;end end end end end -- -- function db.drawHSBdiagram(pallist,posx,posy,width,height,size,sat) --db.addHSBtoPalette(palList) local x,y,c for y = 0, height-1, 1 do for x = 0, width-1, 1 do hue = 255/width * x bri = 255/height * y c = db.matchcolorHSB(hue,sat,bri,pallist,true) db.drawRectangle(posx + x*size, posy + y*size,size,size, c) end end end -- -- -- Histograms, remapping etc. -- -- function db.makeHistogram() local n,y,x,c,w,h,list; list = {} w, h = getpicturesize() for n = 1, 256, 1 do list[n] = 0; end for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do c = getpicturepixel(x,y) list[c+1] = list[c+1] + 1 end end return list end -- -- function db.makeSpareHistogram() local n,y,x,c,w,h,list; list = {} w, h = getsparepicturesize() --w,h = 512,360 for n = 1, 256, 1 do list[n] = 0; end for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do c = getsparepicturepixel(x,y) list[c+1] = list[c+1] + 1 end end return list end -- -- -- Makes a palette-list from only the colors (histogram) that occurs in the image -- Assumes image/palette has not changed since histogram was created function db.makePalListFromHistogram(hist) local n,r,g,b,list,count list = {} count = 1 for n = 1, #hist, 1 do if hist[n] > 0 then r,g,b = getcolor(n-1) list[count] = {r,g,b,n-1} count = count + 1 end end return list end -- function db.makePalListFromSpareHistogram(hist) local n,r,g,b,list,count list = {} count = 1 for n = 1, #hist, 1 do if hist[n] > 0 then r,g,b = getsparecolor(n-1) list[count] = {r,g,b,n-1} count = count + 1 end end return list end -- -- function db.remap(org) -- Working with a remap-list there's no need of reading backuppixel --messagebox("Remapping") local x,y,c,i,w,h,s,f,col f = getpicturepixel s = false w, h = getpicturesize() for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do c = f(x,y) i = org[c+1] if i == null then i = matchcolor(getbackupcolor(getbackuppixel(x,y))); s = true; col = c; end -- Find color for a removed double putpicturepixel(x,y,i) end end if s then messagebox("Remapping: Not all image colors were found in remap-list (re-assign), probably due to duplicate removal. Matchcolor was used, ex: col# "..col); end end -- -- -- Palette DeCluster: Color-reduction by fusing similar colors into new ones, using a desired tolerance. -- This is a method similar to Median-Cut, but more surgical. -- -- pallist: Palette list {r,g,b,palette_index} -- hist: Histogram {color 0 pixels, color 1 pixels...etc} always a full 256 color list -- crad: Cluster radius treshold in % of distance between black & white -- A value of 0 will only remove identical colors -- A value of 3-4 will usally fuse redundant colors without causing notice -- prot_pow: (0..10) Protect common colors in histogram. Distances are increased by ocurrence. -- Also gives protection to fused colors even if not using histogram (combined nominal weights) -- pixels: Pixels in image (so protection can be calculated) -- rw,gw,bw: Color weights (rw+gw+bw = 1, 0.33,0.33,0.33 is nominal) -- -- Returns: -- a new (c)palette list {r,g,b,{original palette_indices},fused flag, histogram_weight} -- a remap list (org) [image color + 1] = remap color (in the new palette) function db.deCluster(pallist, hist, crad, prot_pow, pixels, rw,gw,bw) --messagebox(pixels) local u,c,a,i,o,j,n,c1,c2,r,g,b,r1,g1,b1,r2,g2,b2,wt,rt,gt,bt,tot,pd local worst,wtot,maxdist,maxDist,distfrac,clusterExists,clustVal,count,crad1 local cList,cPalList,clusterList,fuseCol,orgcols,newPalList,org maxdist = math.sqrt(rw*rw*65025 + gw*gw*65025 + bw*bw*65025) distfrac = 100 / maxdist -- Let's just make a slightly more suitable format of the pallist (List for original color(s)) cPalList = {} for u = 1, #pallist, 1 do c = pallist[u] cPalList[u] = {c[1],c[2],c[3],{c[4]},false,hist[c[4]+1]} -- r,g,b,{original colors},fuse_marker,histogram_weight end --table.insert(cPalList,{255,255,0,{257},false,1}) clusterExists = true while clusterExists do clusterExists = false clusterList = {} crad1 = crad + 1 -- avoid divison by zero worst = 9999 for a = 1, #cPalList, 1 do c1 = cPalList[a] r1,g1,b1 = c1[1],c1[2],c1[3] wtot = c1[6] cList = {a} maxDist = 0 for b = 1, #cPalList, 1 do if (b ~= a) then c2 = cPalList[b] r2,g2,b2 = c2[1],c2[2],c2[3] wt = c2[6] pd = math.pow((1 + wt / pixels), prot_pow) -- Protection, increase distance dist = db.getColorDistance_weight(r1,g1,b1,r2,g2,b2,rw,gw,bw) * distfrac * pd if dist <= crad then wtot = wtot + wt table.insert(cList,b) maxDist = math.max(dist,maxDist) end end end -- b if #cList > 1 then clustVal = maxDist / (crad1 * #cList) * (wtot / #cList) if clustVal < worst then worst = clustVal clusterList = cList end end end -- a --t = db.ary2txt(clusterList) --messagebox("Worst cluster is "..t) -- Fuse if #clusterList > 1 then clusterExists = true -- Run another iteration and look for more clusters fuseCol = {0,0,0,{}} rt,gt,bt,tot = 0,0,0,0 for n = 1, #clusterList, 1 do i = clusterList[n] c = cPalList[i] --o = c[4][1] -- Original color (always #1 in list since fused colors can't re-fuse) o = c[4] -- Original color list --if c[5] == true then messagebox("Re-Fusing..."); end r,g,b = c[1],c[2],c[3] --wt = hist[o+1] -- Org. colors are 0-255 wt = c[6] rt = rt + r * wt gt = gt + g * wt bt = bt + b * wt tot = tot + wt cPalList[i] = -1 -- Erase color --table.insert(fuseCol[4],o) orgcols = fuseCol[4] for j = 1, #o, 1 do table.insert(orgcols,o[j]) end fuseCol[4] = orgcols end rt = rt / tot gt = gt / tot bt = bt / tot fuseCol[1] = rt fuseCol[2] = gt fuseCol[3] = bt fuseCol[5] = true -- fusecol marker fuseCol[6] = tot table.insert(cPalList,fuseCol) --messagebox(#clusterList.." Colors was fused, resulting in "..rt..", "..gt..", "..bt) newPalList = {} for n = 1, #cPalList, 1 do if cPalList[n] ~= -1 then table.insert(newPalList,cPalList[n]) --newPalList = db.newArrayInsertLast(newPalList,cPalList[n]) end end cPalList = newPalList --messagebox("Pal length: "..#cPalList) statusmessage("DeCluster - Image colors:"..#cPalList.." "); waitbreak(0) end -- fuse end -- while -- Create remap-list org = {} count = 0 for u = 1, #cPalList, 1 do c = cPalList[u] for n = 1, #c[4], 1 do i = c[4][n] org[i+1] = count -- quick way to remap without matchcolor end count = count + 1 end return org,cPalList end; -- decluster -- -- ... eof Custom Color / Palette functions ... -- -- ***************************** -- *** Custom Draw functions *** -- ***************************** -- function db.lineTransp(x1,y1,x2,y2,c,amt) -- amt: 0-1, 1 = Full color local n,st,m,x,y,r,g,b,r1,g1,b1,c2,org; m = math org = 1 - amt st = m.max(1,m.abs(x2-x1),m.abs(y2-y1)); for n = 0, st, 1 do x = m.floor(x1+n*(x2-x1)/st) y = m.floor(y1+n*(y2-y1)/st) r,g,b = getcolor(getpicturepixel(x,y)) r1,g1,b1 = getcolor(c) c2 = matchcolor(r1*amt+r*org, g1*amt+g*org, b1*amt+b*org) putpicturepixel(x, y, c2 ); end end -- -- function db.drawBrushRectangle(x1,y1,w,h,c) local x,y for y = y1, y1+h-1, 1 do for x = x1, x1+w-1, 1 do putbrushpixel(x,y,c); end end end -- -- function db.drawRectangle(x1,y1,w,h,c) drawfilledrect(x1, y1, x1+w, y1+w, c); end -- -- function db.drawRectangleNeg(x1,y1,w,h,c) local x,y,xs,ys xs = db.sign(w) ys = db.sign(h) if xs == 0 then xs = 1; end if ys == 0 then ys = 1; end for y = y1, y1+h-1, ys do for x = x1, x1+w-1, xs do putpicturepixel(x,y,c); end end end -- -- function db.drawRectangleLine(x,y,w,h,c) w = w-1 h = h-1 drawline(x,y,x+w,y,c) drawline(x,y,x,y+h,c) drawline(x,y+h,x+w,y+h,c) drawline(x+w,y,x+w,y+h,c) end -- -- function db.drawRectangleMix(x1,y1,w,h,c1,c2) local x,y,c,n c = {c1,c2} n = 0 for y = y1, y1+h-1, 1 do n = n + 1 for x = x1, x1+w-1, 1 do n = n + 1 putpicturepixel(x,y,c[n%2+1]); end end end -- -- function db.drawBrushCircle(x1,y1,r,c) -- ok, lottsa weird adjustments here, can probably be optimized... local x,y,d for y = 0, r*2, 1 do for x = 0, r*2, 1 do d = math.sqrt((x-r-0.5)^2 + (y-r-0.5)^2) if d < r-0.25 then putbrushpixel(x1+x-r-0.5,y1+y-r-0.5,c); end end end end -- -- -- Rotation in degrees -- Step is # of line segments (more is "better") -- a & b are axis-radius function db.ellipse2(x,y,a,b,stp,rot,col) local n,m=math,rad,al,sa,ca,sb,cb,ox,oy,x1,y1,ast m = math; rad = m.pi/180; ast = rad * 360/stp; sb = m.sin(-rot * rad); cb = m.cos(-rot * rad) for n = 0, stp, 1 do ox = x1; oy = y1; sa = m.sin(ast*n) * b; ca = m.cos(ast*n) * a x1 = x + ca * cb - sa * sb y1 = y + ca * sb + sa * cb if (n > 0) then drawline(ox,oy,x1,y1,col); end end end -- --[[ var ER = 0.3 var DR = 0.15 ellipse(0.5*xx,0.5*yy,DR*xx,6,Math.PI*0) function ellipse(x,y,r,stp,rot){ var n,deg=360,m=Math,rad=Math.PI/180,rn var ox,oy,x1,y1,x2,y2,d1,r1 = ER * xx for (n=0; n<=deg; n+=stp){ ox = x2; oy = y2, rn = rad * n d1 = rn - rot x1 = x + m.sin(d1) * r y1 = y + m.cos(d1) * r x2 = x1 + m.sin(-rn) * r1 y2 = y1 + m.cos(-rn) * r1 if (n > 0){ line_rgb(MX,[0,0,0],0,ox,oy,x2,y2) } } } } ellipse2(0.5*xx,0.5*yy,15,8,200,22,[0,0,0],0.5) function ellipse2(x,y,a,b,stp,rot,rgb,transp){ var n,m=Math,rad=m.PI/180,al,sa,ca,sb,cb,ox,oy,x1,y1 sb = m.sin(-rot * rad); cb = m.cos(-rot * rad) for (n=0; n<=stp; n++){ ox = x1; oy = y1; al = rad * 360/stp * n sa = m.sin(al) * b; ca = m.cos(al) * a x1 = x + ca * cb - sa * sb y1 = y + ca * sb + sa * cb if (n > 0){ line_rgb(MX,rgb,transp,ox,oy,x1,y1) } } } ]] function db.obliqueCube(side,x,y,r,g,b,bri) local n,c,depth,x1,y1,x2,y2,f f = matchcolor c = f(r,g,b) cP50 = f(r+bri*0.5,g+bri*0.5,b+bri*0.5) cP75 = f(r+bri*0.75,g+bri*0.75,b+bri*0.75) cM50 = f(r-bri*0.5,g-bri*0.5,b-bri*0.5) cM100 = f(r-bri,g-bri,b-bri) depth = math.floor(side / 2) for n = 0, depth-1, 1 do drawline(x+side+n,y-1-n,x+side+n,y+side-n-1,cM50) end for n = 0, depth-1, 1 do drawline(x+n,y-1-n,x+side+n-1,y-1-n,cP50) end -- / -- --drawline(x+side,y-1,x+side+depth-1,y-depth,c) -- Smoothing & Shade -- -- / --drawline(x+side,y+side-1,x+side+depth-1,y+side-depth,cM100) --drawline(x,y,x+side-2,y,cP75) --drawline(x,y,x,y+side-2,cP75) db.drawRectangle(x,y,side,side,c) end function db.obliqueCubeBRI(side,x,y,r,g,b,bri,pallist,briweight,index_flag) local n,c,depth,x1,y1,x2,y2 --f = db.getBestPalMatchHYBRID c = db.getBestPalMatchHYBRID({r,g,b}, pallist, briweight, index_flag) cP50 = db.getBestPalMatchHYBRID({r+bri*0.5,g+bri*0.5,b+bri*0.5}, pallist, briweight, index_flag) cP75 = db.getBestPalMatchHYBRID({r+bri*0.75,g+bri*0.75,b+bri*0.75}, pallist, briweight, index_flag) cM50 = db.getBestPalMatchHYBRID({r-bri*0.5,g-bri*0.5,b-bri*0.5}, pallist, briweight, index_flag) cM100 = db.getBestPalMatchHYBRID({r-bri,g-bri,b-bri}, pallist, briweight, index_flag) depth = math.floor(side / 2) db.drawRectangle(x,y,side,side,c) for n = 0, depth-1, 1 do drawline(x+side+n,y-1-n,x+side+n,y+side-n-1,cM50) end for n = 0, depth-1, 1 do drawline(x+n,y-1-n,x+side+n-1,y-1-n,cP50) end -- / -- drawline(x+side,y-1,x+side+depth-1,y-depth,c) -- Smoothing & Shade -- -- / --drawline(x+side,y+side-1,x+side+depth-1,y+side-depth,cM100) --drawline(x,y,x+side-2,y,cP75) --drawline(x,y,x,y+side-2,cP75) end -- -- ... eof Custom Draw functions ... -- -- ****************************** -- *** Filters & Convolutions *** -- ****************************** function db.applyConvolution2Pic(convmx,divisor,bias,neg,amt) local r,g,b,mx,my,cx,cy,mxh,myh,mp,rb,gb,bb,xx,yy,x,y,w,h,div,n1,n2,amtr,ro,go,bo n1 = 1 n2 = bias if neg == 1 then n1 = -1 n2 = 255 + bias end amtr = 1 - amt w, h = getpicturesize() cy = #convmx cx = #convmx[1] mxh = math.floor(cx / 2) + 1 myh = math.floor(cy / 2) + 1 for y = 0, h-1, 1 do for x = 0, w-1, 1 do r,g,b = 0,0,0 ro,go,bo = getcolor(getbackuppixel(x,y)) div = divisor for my = 1, cy, 1 do for mx = 1, cx, 1 do xp = mx-mxh yp = my-myh mp = convmx[my][mx] xx = x + xp yy = y + yp if yy>=0 and yy=0 and xx 0 and n 0 and n0) then x = x*px - fx y = y*py - fy nfrac = nfrac + spfrac end n = n+1 end --return 1 - n/i; return 1 - nfrac/i end -- -- function db.mandel(x,y,l,r,o,i) -- pos. as fraction of 1, left coord, right coord, y coord, iterations local w,s,a,p,q,n,v,w s=math.abs(r-l); a = l + s*x; p = a; b = o - s*(y-0.5); q = b; n = 1; v = 0; w = 0; while (v+w<4 and n weakest then weakest = w; weak_i = {z,y,x}; end end end;end;end return weak_i[1],weak_i[2],weak_i[3] end -- -- -- -- Nearest color version: void is selected by the point that has the greatest distance -- to the nearest color. Higher value means greater void. -- function db.addColor2Cube(cube,sha,r,g,b,rw,gw,bw) local star,x,y,z,d,rd,gd,bd,cu1,cu2 star = 0 cube[r+1][g+1][b+1] = {false, star} for z = 0, sha-1, 1 do rd = (rw*(z-r))^2 cu2 = cube[z+1] for y = 0, sha-1, 1 do gd = (gw*(y-g))^2 cu1 = cu2[y+1] for x = 0, sha-1, 1 do d = rd + gd + (bw*(x-b))^2 --cube[z+1][y+1][x+1][2] = math.min(d, cube[z+1][y+1][x+1][2]) -- Don't add, use nearest color cu1[x+1][2] = math.min(d, cu1[x+1][2]) end;end;end end -- -- Should be same as original, but not 100% verified. Using a rgb+1 trick to speed up handling -- function db.addColor2Cube_test(cube,sha,r,g,b,rw,gw,bw) local star,x,y,z,d,rd,gd,bd,cu1,cu2 star = 0 r = r+1; g = g+1; b = b+1 cube[r][g][b] = {false, star} for z = 1, sha, 1 do rd = (rw*(z-r))^2 cu2 = cube[z] for y = 1, sha, 1 do gd = (gw*(y-g))^2 cu1 = cu2[y] for x = 1, sha, 1 do cu1[x][2] = math.min(rd+gd+(bw*(x-b))^2, cu1[x][2]) end;end;end end -- -- Create new allowed colorlines in colorspace (ramps from which colors can be picked) function db.enableRangeColorsInCube(cube,sha,r1,g1,b1,r2,g2,b2) local div,r,g,b,n,rs,gs,bs div = 256 / sha rs = (r2 - r1) / sha / div gs = (g2 - g1) / sha / div bs = (b2 - b1) / sha / div for n = 0, sha-1, 1 do r = math.floor(r1/div + rs * n) g = math.floor(g1/div + gs * n) b = math.floor(b1/div + bs * n) cube[r+1][g+1][b+1][1] = true end end -- function db.colorCigarr(shades,radius,fill_flag) local s,rad,radsq,step,shalf,bas,cols,found,x,y,z,bri,con,d,n radius = radius / 100 step = math.floor(255 / (shades-1)) shalf = math.floor(shades / 2) s = shades - 1 rad = math.floor(shades / 2 * radius) radsq = rad^2 bas = 0 cols = {} found = 0 for z = 0, s, 1 do for y = 0, s, 1 do for x = 0, s, 1 do --0.26,0.55,0.19 bri = (x + y + z ) / 3 --bri = math.sqrt(((x*0.26)^2 + (y*0.55)^2 + (z*0.19)^2)) * 1.5609 con = math.floor((shades - math.abs(bri - shalf)*2) * radius) d = math.floor(math.sqrt((bri-x)^2 + (bri-y)^2 + (bri-z)^2)) --d = math.floor(math.sqrt(((bri-x)*0.26)^2 + ((bri-y)*0.55)^2 + ((bri-z)*0.19)^2)) * 1.5609 -- Filled cigarr: Less or Equal, cigarr shell: Equal if d == con or (d < con and fill_flag) then found = found + 1 r = bas + x * step g = bas + y * step b = bas + z * step cols[found] = {r,g,b} end end; end; end --messagebox("Colors found: "..found.."\n\n".."Run AnalyzePalette to examine") for n = 0, 255, 1 do if n < found then c = cols[n+1] setcolor(n,c[1],c[2],c[3]) else setcolor(n,0,0,0) end end end -- eof colorcigarr -- -- ... eof Color Cube ... -- -- COLORMIX -- -- -- Returns a list of mixcolors palette entries, that are ranked by by quality & usefulness -- -- This whole junk my partly locked on 16 shades (4096 colors/ 12bit palette precision) so don't use anything else... -- -- function db.colormixAnalysis(sha,spare_flag,cust_dist) -- Interface local shades,pallist,ilist,custom_max_distance shades = sha -- 16 is good --messagebox(shades) custom_max_distance = -1 if cust_dist ~= null then custom_max_distance = cust_dist -- in % end if spare_flag == true then -- No shades here for now --pallist = db.makePalListShadeSPARE(256,shades) -- 16 shades so Colorcube processes is possible pallist = db.makeSparePalList(256) pallist = db.fixPalette(pallist,0) -- Remove doubles, No need to sort? ilist = db.makeIndexList(pallist, -1) -- -1, use list order as index else pallist = db.makePalListShade(256,shades) -- 16 shades so Colorcube processes is possible pallist = db.fixPalette(pallist,0) -- Remove doubles, No need to sort? ilist = db.makeIndexList(pallist, -1) -- -1, use list order as index end if shades > 0 then return db.colormixAnalysisEXT(shades,pallist,ilist,custom_max_distance) -- max distance in % end if shades == -1 then return db.colormixAnalysisEXTnoshade(pallist,ilist,custom_max_distance) -- max distance in % end end -- -- function db.colormixAnalysisEXT(SHADES,pallist,ilist,custom_max_distance) -- Shades, most number of mixes returned local n,m,c1,c2,pairs,cube,rm,gm,bm local mix,total,found,dist,void,ideal,mini,maxi,bestmix,bestscore --messagebox("will now make pairs") pairs = db.pairsFromList(ilist,0) -- 0 for unique pairs only, pairs are entries in pallist --messagebox(#pairs.." will now add colors to cube") cube = db.initColorCube(SHADES,{true,9999}) for n = 1, #pallist, 1 do c1 = pallist[n] db.addColor2Cube_test(cube,SHADES,c1[1],c1[2],c1[3],0.26,0.55,0.19) end -- these values are adjusted for a 12bit palette (0-15) and perceptual weight where r+g+b = 1.0 -- Ideal distance = 2.5 Green steps = 1.375 -- Minimum distance = 1 Green step = 0.55 --messagebox("colorcube done") VACT = 1 DACT = 1 total = 9.56 -- Max distance possible with 16 shades ideal = 0.45 -- 1 step = 0.637 mini = 0.35 maxi = ideal + (total - ideal) / math.max(1, #pallist / 16) if custom_max_distance ~= -1 then maxi = total * (custom_max_distance / 100) end mix = {} --mix[1] = {9e99,0,0,9e99,0,0,0} bestmix = -1 bestscore = 9e99 found = 0 for n = 1, #pairs, 1 do c1 = pallist[pairs[n][1]] c2 = pallist[pairs[n][2]] --0.26,0.55,0.19 dist = db.getColorDistance_weight(c1[1],c1[2],c1[3],c2[1],c2[2],c2[3],0.26,0.55,0.19) -- Not normalized rm = math.floor((c1[1]+c2[1])/2) gm = math.floor((c1[2]+c2[2])/2) bm = math.floor((c1[3]+c2[3])/2) -- Mix color adjustment (perhaps less than perfect, but probably good enough) mixbri = db.getBrightness(rm,gm,bm) truebri = math.sqrt((db.getBrightness(c1[1],c1[2],c1[3])^2 + db.getBrightness(c2[1],c2[2],c2[3])^2) / 2) diff = truebri - mixbri rm = math.max(0,math.min(15,math.floor(rm + diff))) gm = math.max(0,math.min(15,math.floor(gm + diff))) bm = math.max(0,math.min(15,math.floor(bm + diff))) newbri = db.getBrightness(rm,gm,bm) delta = math.abs(newbri - truebri) --if delta > 0.9 then -- messagebox(pallist[pairs[n][1]][4]..", "..pallist[pairs[n][2]][4].." delta = "..delta) --end -- --rm = math.floor(math.sqrt((c1[1]^2 + c2[1]^2) / 2)) --gm = math.floor(math.sqrt((c1[2]^2 + c2[2]^2) / 2)) --bm = math.floor(math.sqrt((c1[3]^2 + c2[3]^2) / 2)) void = cube[rm+1][gm+1][bm+1][2] if dist >= mini and dist <= maxi then found = found + 1 score = ((1+DACT*(dist - ideal)^2) / (1+void*VACT)) -- Lowest is best mix[found] = {score,pallist[pairs[n][1]][4],pallist[pairs[n][2]][4],dist,rm*SHADES,gm*SHADES,bm*SHADES,c1[1]*SHADES,c1[2]*SHADES,c1[3]*SHADES,c2[1]*SHADES,c2[2]*SHADES,c2[3]*SHADES} -- mix holds palette entry if score < bestscore then bestscore = score; bestmix = found; end end end if true == false then -- 2nd pass, add bestmix to colorspace. This reduces many similar mixes. m = mix[bestmix] db.addColor2Cube(cube,SHADES,m[5],m[6],m[7],0.26,0.55,0.19) for n = 1, #mix, 1 do if n ~= bestmix then m = mix[n] dist = m[4] void = cube[m[5]+1][m[6]+1][m[7]+1][2] score = ((1+DACT*(dist - ideal)^2) / (1+void*VACT)) m[1] = score end end end c1,c2 = -1,-1 if found > 0 then db.sorti(mix,1) best = mix[1] c1 = best[2] c2 = best[3] end --return found,c1,c2 return mix,found,c1,c2 end -- -- -- Mixcolor without colorcube - no scoring or sorting, 24bit colors, faster... -- function db.colormixAnalysisEXTnoshade(pallist,ilist,custom_max_distance) local n,m,c1,c2,pairs,cube,rm,gm,bm local mix,total,found,dist,void,ideal,mini,maxi,bestmix,bestscore pairs = db.pairsFromList(ilist,0) -- 0 for unique pairs only, pairs are entries in pallist total = 162.53 -- Max distance possible with 24-bit palette ad Dawn3.0 color weights 162.53 ideal = 0 mini = 0 maxi = ideal + (total - ideal) / math.max(1, #pallist / 16) if custom_max_distance ~= -1 then maxi = total * (custom_max_distance / 100) end mix = {} found = 0 for n = 1, #pairs, 1 do c1 = pallist[pairs[n][1]] c2 = pallist[pairs[n][2]] --0.26,0.55,0.19 dist = db.getColorDistance_weight(c1[1],c1[2],c1[3],c2[1],c2[2],c2[3],0.26,0.55,0.19) -- Not normalized rm = math.floor((c1[1]+c2[1])/2) gm = math.floor((c1[2]+c2[2])/2) bm = math.floor((c1[3]+c2[3])/2) -- Mix color adjustment mixbri = db.getBrightness(rm,gm,bm) truebri = math.sqrt((db.getBrightness(c1[1],c1[2],c1[3])^2 + db.getBrightness(c2[1],c2[2],c2[3])^2) / 2) diff = truebri - mixbri rm = math.max(0,math.min(255,math.floor(rm + diff))) gm = math.max(0,math.min(255,math.floor(gm + diff))) bm = math.max(0,math.min(255,math.floor(bm + diff))) newbri = db.getBrightness(rm,gm,bm) delta = math.abs(newbri - truebri) --if delta > 0.9 then -- messagebox(pallist[pairs[n][1]][4]..", "..pallist[pairs[n][2]][4].." delta = "..delta) --end -- if dist >= mini and dist <= maxi then found = found + 1 score = 1 mix[found] = {score,pallist[pairs[n][1]][4],pallist[pairs[n][2]][4],dist,rm,gm,bm,c1[1],c1[2],c1[3],c2[1],c2[2],c2[3]} -- mix holds palette entry end end --messagebox(#mix) return mix,found,-1,-1 end -- -- Fuse a palettelist into an extended mix-anlysis list function db.fusePALandMIX(pal,mix,max_score,max_dist) local n,c,mixlist,tot,score,dist,c1,c2,rm,gm,bm mixlist = {} tot = 0 -- {r,g,b,n} for n = 1, #pal, 1 do tot = tot + 1 c = pal[n] mixlist[tot] = {0,c[4],c[4],0,c[1],c[2],c[3],c[1],c[2],c[3],c[1],c[2],c[3]} end -- {score,col#1,col#2,dist,rm,gm,bm} low score is best for n = 1, #mix, 1 do score = mix[n][1] dist = mix[n][4] if score <= max_score and dist <= max_dist then tot = tot + 1 mixlist[tot] = mix[n] end end return mixlist end -- -- ******************************************** -- *** L-system (fractal curves & "plants") *** -- ******************************************** -- -- function db.Lsys_makeData(a) local n,i; i = {} for n = 1, #a, 1 do i[a[n][2]] = a[n]; end return i end -- -- function db.Lsys_makeSet(seed,iter,data) local s,n,i,nset,set set = seed for n = 1, iter, 1 do nset = '' for i = 1, #set, 1 do s = string.sub(set,i,i) nset = nset..data[s][3] end set = nset end return set end -- function db.Lsys_draw(set,data,cx,cy,size,rot,rgb,rng,transp, speed) local p,M,DEG,l,n,d,i,v,q,c,tx,ty,posx,posy,dval,col,w,h,s,cl,count if speed == nil then speed = 50; end -- speed is drawing operations per update function ang(d) return (d % 360 + 360) * DEG; end w,h = getpicturesize() p = 0 M = math DEG = math.pi/180 l = #set posx={}; posy={}; dval={} if (rgb == null) then rgb = {0,0,0}; end if (transp == null) then transp = 0; end col = db.newArrayMerge(rgb,{}) q = 255 / l count = 0 for n = 1, l, 1 do s = string.sub(set,n,n) d = data[s] i = d[1] v = d[4] --messagebox(i) if (i == 'Left') then rot = rot - v; end if (i == 'Right') then rot = rot + v; end if (i == 'Save') then p=p+1; posx[p] = cx; posy[p] = cy; dval[p] = rot; end if (i == 'Load') then cx = posx[p]; cy = posy[p]; rot = dval[p]; p=p-1; end if (i == 'Draw') then tx = cx + M.sin(ang(rot)) * size ty = cy + -M.cos(ang(rot)) * size for c = 1, 3, 1 do if (rng[c] > 0) then col[c] = rgb[c] + (n * q) * rng[c]; end if (rng[c] < 0) then col[c] = rgb[c] + (n * q) * rng[c]; end end cl = matchcolor(col[1],col[2],col[3]) --putpicturepixel(cx*w,cy*h,cl); --drawline(cx*w,cy*h,tx*w,ty*h,cl) db.lineTransp(cx*w,cy*h,tx*w,ty*h,cl,transp) cx = tx; cy = ty end count = count + 1 if count == speed then count = 0; updatescreen(); if (waitbreak(0)==1) then return end; end end return {cx,cy,rot} end -- draw -- -- eof L-system -- grafx2/share/grafx2/scripts/samples_2.3/libs/memory.lua0000644000076400010400000000664311546120602023414 0ustar vigAdministrator-- Persistence library: -- Memorize data for current function -- memory.save(tab) and tab=memory.load() -- -- The data will be stored in file called -- .dat -- in the lua directory -- -- Example 1: -- -- -- Load initial values or set defaults -- arg = memory.load({picX=320,picY=200,scale=0}) -- -- Run an inputbox -- OK,arg.picX,arg.picY,arg.scale = inputbox("Image Size")", -- "Width", arg.picX, 1,2048,0, -- "Height", arg.picY, 1,2048,0, -- "Scale", arg.scale, 0,1,0); -- if OK == true then -- -- Save the selected values -- memory.save(arg) -- end -- Example 2: -- -- -- Load initial values or set defaults -- arg = memory.load({x=320,y=200,scale=0}) -- picX=arg.x -- picY=arg.y -- scale=arg.scale -- -- Run an inputbox -- OK,picX,picY,scale = inputbox("Image Size")", -- "Width", picX, 1,2048,0, -- "Height", picY, 1,2048,0, -- "Scale", scale, 0,1,0); -- if OK == true then -- -- Save the selected values -- memory.save({x=picX,y=picY,scale=scale}) -- end memory = { serialize = function(o) if type(o) == "number" then return tostring(o) elseif type(o) == "string" then return string.format("%q", o) --elseif type(o) == "table" then -- io.write("{\n") -- for k,v in pairs(o) do -- io.write(" ", k, " = ") -- memory.serialize(v) -- io.write(",\n") -- end -- io.write("}\n") else error("cannot serialize a " .. type(o)) end end; -- Return a string identifying the calling function. -- Pass 1 for parent, 2 for grandparent etc. callername = function(level) local w local last_slash local info = debug.getinfo(level+1,"Sn") local caller=tostring(info.name) -- Function name if possible if (caller~="nil") then return caller end -- Otherwise, get file name, without extension -- Get part after directory name last_slash=0 while true do local pos = string.find(info.source, "/", last_slash+1) if (pos==nil) then break end last_slash=pos end while true do local pos = string.find(info.source, "\\", last_slash+1) if (pos==nil) then break end last_slash=pos end caller=string.sub(info.source, last_slash+1) -- Remove file extension if (string.sub(caller,-4, -1)==".lua") then caller=string.sub(caller, 1, -5) end return caller end; -- Memorize some parameters. save = function(o) local caller=memory.callername(2) --for k, v in pairs(o) do -- messagebox(tostring(k)) -- messagebox(tostring(v)) --end local f, e = io.open(caller..".dat", "w"); if (f ~= nil) then f:write("Entry {\n") for k, v in pairs(o) do if (type(v)=="number") then f:write(" "..k.."="..memory["serialize"](v)..",\n") end end f:write("}\n") f:close() end end; -- Recover some saved parameters. load = function(o) local caller=memory.callername(2) local i function Entry (b) -- Adds (or replaces) values in arg with those from b for k, v in pairs(b) do o[k]=v end end local f = (loadfile(caller..".dat")) if (f ~= nil) then f() end return o end; } return memory grafx2/share/grafx2/scripts/samples_2.3/palette/Desaturate.lua0000644000076400010400000000205311546106106024704 0ustar vigAdministrator--PALETTE Adjust: Desaturate v1.1 --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program 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. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project -- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html -- Note: Negative values will work as INCREASED saturation, but I'm not sure if this function is 100% correct --percent = 25 OK,percent = inputbox("Desaturate Palette","Percent %", 25, 0,100,0); -- function desaturate(percent,r,g,b) -- V1.0 by Richard Fhager p = percent / 100 a = (math.min(math.max(r,g,b),255) + math.max(math.min(r,g,b),0)) * 0.5 * p r = r + (a-r*p) g = g + (a-g*p) b = b + (a-b*p) return r,g,b end -- if OK == true then for c = 0, 255, 1 do setcolor(c, desaturate(percent,getcolor(c))) end endgrafx2/share/grafx2/scripts/samples_2.3/palette/ExpandColors.lua0000644000076400010400000001131411546106114025203 0ustar vigAdministrator--PALETTE: Expand Colors v1.0 --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Email: dawnbringer@hem.utfors.se -- MSN: annassar@hotmail.com -- -- Copyright 2010 Richard Fhager -- -- This program 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. See -- Continously fill the greatest void in the area of the color-cube enclosed by (or along ramps of) initial colors -- This algorithm will create lines of allowed colors (all ranges) in 3d colorspace and the pick -- new colors from the most void areas (on any line). Almost like a Median-cut in reverse. -- -- Rather than filling the colorcube symmetrically it adds intermediate colors to the existing ones. -- -- Running this script on the C64 16-color palette might be educational -- -- -- Source cols#, Expand to #, -- Ex: 15-31 means that palette colors 0-15 is expanded to 16 new colors placed at slots 16-31 -- -- Spread mode: OFF - New colors will conform to the contrast & saturation of original colors -- (new colors will stay on the ramps possible from the original colors) -- -- ON - New colors will expand their variance by each new addition (mostly notable when adding many new colors) -- Will add range lines/ramps to all new colors from old ones, but keep within max/min values of the -- original colors. 15-bit mode will dampen the spread towards extreme colors (if starting with low contrast) -- -- 15-bit colors: Higher color-resolution, 32768 possible colors rather than the 4096 of 12bit. Slower but perhaps better. -- SHADES = 16 -- Going 24bit will probably be too slow and steal too much memory, so start with 12bit (4096 colors) for now ini = 0 exp = 255 OK,ini,exp,linemode,fbit = inputbox("Expand Colors (0-255):", "Source Cols #: 1-254", 15, 1,254,0, "Expand to #: 2-255", 31, 2,255,0, "Spread mode", 0, 0,1,0, "15-bit colors (slow)", 0, 0,1,0 ); if (fbit == 1) then SHADES = 32; end function initColorCube(sha) ary = {} for z = 0, sha-1, 1 do ary[z+1] = {} for y = 0, sha-1, 1 do ary[z+1][y+1] = {} for x = 0, sha-1, 1 do ary[z+1][y+1][x+1] = {false,0} end end end return ary end -- Gravity model (think of colors as stars of equal mass/brightness in a 3d space) function addColor2Cube(cube,sha,r,g,b) star = 1000000 fade = 1000 cube[r+1][g+1][b+1] = {false,star} for z = 0, sha-1, 1 do for y = 0, sha-1, 1 do for x = 0, sha-1, 1 do d = fade / ( (x-b)^2 + (y-g)^2 + (z-r)^2 ) cube[z+1][y+1][x+1][2] = cube[z+1][y+1][x+1][2] + d end;end;end end -- Create new allowed colorlines in colorspace (ramps from which colors can be picked) function enableRangeColorsInCube(cube,sha,r1,g1,b1,r2,g2,b2) local div,r,g,b div = 256 / sha rs = (r2 - r1) / sha / div gs = (g2 - g1) / sha / div bs = (b2 - b1) / sha / div for n = 0, sha-1, 1 do r = math.floor(r1/div + rs * n) g = math.floor(g1/div + gs * n) b = math.floor(b1/div + bs * n) cube[r+1][g+1][b+1][1] = true end end function findVoid(cube,sha) weakest = 999999999999 weak_i = {-1,-1,-1} for z = 0, sha-1, 1 do for y = 0, sha-1, 1 do for x = 0, sha-1, 1 do c = cube[z+1][y+1][x+1] if c[1] == true then w = c[2] if w <= weakest then weakest = w; weak_i = {z,y,x}; end end end;end;end return weak_i[1],weak_i[2],weak_i[3] end -- if OK == true then cube = initColorCube(SHADES) -- Define allowed colorspace for y = 0, ini-1, 1 do r1,g1,b1 = getcolor(y) for x = y+1, ini, 1 do r2,g2,b2 = getcolor(x) enableRangeColorsInCube(cube,SHADES,r1,g1,b1,r2,g2,b2) end end div = 256 / SHADES -- Fill cube with initial colors for n = 0, ini, 1 do r,g,b = getcolor(n) addColor2Cube(cube,SHADES,math.floor(r/div),math.floor(g/div),math.floor(b/div)) end for n = ini+1, exp, 1 do r,g,b = findVoid(cube,SHADES) if (r == -1) then messagebox("Report:","No more colors can be found, exit at "..n); break; end mult = 255 / (SHADES - 1) setcolor(n, r*mult,g*mult,b*mult) if linemode == 1 then -- Add lines from new color to all old for x = 0, n-1, 1 do r2,g2,b2 = getcolor(x) enableRangeColorsInCube(cube,SHADES,r*mult,g*mult,b*mult,r2,g2,b2) -- uses 24bit values rgb end end addColor2Cube(cube,SHADES,r,g,b) -- rgb is in 'shade' format here end end grafx2/share/grafx2/scripts/samples_2.3/palette/FillColorCube.lua0000644000076400010400000000446011546106122025271 0ustar vigAdministrator--PALETTE: Fill ColorCube voids v1.0 --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Email: dawnbringer@hem.utfors.se -- MSN: annassar@hotmail.com -- -- Copyright 2010 Richard Fhager -- -- This program 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. See -- -- Create a palette by continously filling the greatest void in the RGB color-cube -- SHADES = 16 -- Going 24bit will probably be too slow and steal too much memory, so we're 12bit (4096 colors) for now ini = 0 exp = 255 OK,ini,exp = inputbox("Fill Palette Color voids", "From/Keep #: 0-254", 0, 0,254,0, "Replace to #: 1-255", 31, 1,255,0 ); function initColorCube(sha) ary = {} for z = 0, sha-1, 1 do ary[z+1] = {} for y = 0, sha-1, 1 do ary[z+1][y+1] = {} end end return ary end function addColor2Cube(cube,sha,r,g,b) -- Gravity model star = 1000000 fade = 1000 cube[r+1][g+1][b+1] = star for z = 0, sha-1, 1 do for y = 0, sha-1, 1 do for x = 0, sha-1, 1 do d = fade / ( (x-b)^2 + (y-g)^2 + (z-r)^2 ) if cube[z+1][y+1][x+1] ~= nil then cube[z+1][y+1][x+1] = cube[z+1][y+1][x+1] + d else cube[z+1][y+1][x+1] = d end end;end;end end function findVoid(cube,sha) weakest = 999999999999 weak_i = {-1,-1,-1} for z = 0, sha-1, 1 do for y = 0, sha-1, 1 do for x = 0, sha-1, 1 do w = cube[z+1][y+1][x+1] if w <= weakest then weakest = w; weak_i = {z,y,x}; end end;end;end return weak_i[1],weak_i[2],weak_i[3] end -- if OK == true then cube = initColorCube(SHADES) -- Fill cube with initial colors for n = 0, ini-1, 1 do r,g,b = getcolor(n) div = SHADES addColor2Cube(cube,SHADES,math.floor(r/div),math.floor(g/div),math.floor(b/div)) end if ini == 0 then -- With no inital color, some inital data must be added to the colorcube. addColor2Cube(cube,SHADES,0,0,0) setcolor(0, 0,0,0) ini = ini + 1 end for n = ini, exp, 1 do r,g,b = findVoid(cube,SHADES) mult = 255 / (SHADES - 1) setcolor(n, r*mult,g*mult,b*mult) addColor2Cube(cube,SHADES,r,g,b) end end grafx2/share/grafx2/scripts/samples_2.3/palette/InvertedRGB.lua0000644000076400010400000000121611546106130024713 0ustar vigAdministrator--PALETTE Modify: Inverted RGB --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program 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. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project -- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html for c = 0, 255, 1 do r,g,b = getcolor(c) r2 = (g+b)/2 g2 = (r+b)/2 b2 = (r+g)/2 setcolor(c, r2,g2,b2) end grafx2/share/grafx2/scripts/samples_2.3/palette/Set3bit.lua0000644000076400010400000000171311546106134024123 0ustar vigAdministrator--PALETTE Set: 3 Bit (8 Primaries) --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program 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. See -- Generate palette of all colors possible with a given number of shades for each channel -- 2 shades = 1 bit / channel = 3 bit palette = 2^3 colors = 8 colors -- 4 shades = 2 bit / channel = 6 bit palette = 2^6 colors = 64 colors -- Channel shades (shades = 2 ^ bit-depth) shades = 2 mult = 255 / (shades-1) colors = {} col = 0 for r = 0, shades-1, 1 do for g = 0, shades-1, 1 do for b = 0, shades-1, 1 do col = col + 1 colors[col] = { r*mult, g*mult, b*mult } end end end for c = 1, #colors, 1 do setcolor(c-1,colors[c][1],colors[c][2],colors[c][3]) end grafx2/share/grafx2/scripts/samples_2.3/palette/Set6bit.lua0000644000076400010400000000171611546106140024126 0ustar vigAdministrator--PALETTE Set: Full 6 Bit (64 colors) --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program 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. See -- Generate palette of all colors possible with a given number of shades for each channel -- 2 shades = 1 bit / channel = 3 bit palette = 2^3 colors = 8 colors -- 4 shades = 2 bit / channel = 6 bit palette = 2^6 colors = 64 colors -- Channel shades (shades = 2 ^ bit-depth) shades = 4 mult = 255 / (shades-1) colors = {} col = 0 for r = 0, shades-1, 1 do for g = 0, shades-1, 1 do for b = 0, shades-1, 1 do col = col + 1 colors[col] = { r*mult, g*mult, b*mult } end end end for c = 1, #colors, 1 do setcolor(c-1,colors[c][1],colors[c][2],colors[c][3]) end grafx2/share/grafx2/scripts/samples_2.3/palette/SetC64Palette.lua0000644000076400010400000000243511546106144025140 0ustar vigAdministrator--PALETTE Set: C64 Palette (16 colors) --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program 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. See OK,clean = inputbox("C64 Palette:", "Remove old palette", 0, 0,1,0 ); colors = {{0, 0, 0}, -- 0 Black {62, 49,162}, -- 1 D.Blue {87, 66, 0}, -- 2 Brown {140, 62, 52}, -- 3 D.Red {84, 84, 84}, -- 4 D.Grey {141, 72,179}, -- 5 Purple {144, 95, 37}, -- 6 Orange {124,112,218}, -- 7 B.Blue {128,128,128}, -- 8 Grey {104,169, 65}, -- 9 Green {187,119,109}, -- 10 B.Red {122,191,199}, -- 11 Cyan {171,171,171}, -- 12 B.Grey {208,220,113}, -- 13 Yellow {172,234,136}, -- 14 B.Green {255,255,255} -- 15 White } if OK == true then for c = 1, #colors, 1 do setcolor(c-1,colors[c][1],colors[c][2],colors[c][3]) end if clean == 1 then for c = #colors+1, 256, 1 do setcolor(c-1,0,0,0) end end endgrafx2/share/grafx2/scripts/samples_2.3/palette/ShiftHue.lua0000644000076400010400000000237311546106152024330 0ustar vigAdministrator--PALETTE Adjust: Shift Hue v0.9 --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program 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. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project -- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html --Shift_degrees = 45 OK,Shift_degrees = inputbox("Shift Hue v0.9","Degrees", 45, 0,360,3); -- function shiftHUE(r,g,b,deg) -- V1.3 R.Fhager 2007, adopted from Evalion local c,h,mi,mx,d,s,p,i,f,q,t c = {g,b,r} mi = math.min(r,g,b) mx = math.max(r,g,b); v = mx; d = mx - mi; s = 0; if mx ~= 0 then s = d/mx; end p = 1; if g ~= mx then p = 2; if b ~= mx then p = 0; end; end if s~=0 then h=(deg/60+(6+p*2+(c[1+p]-c[1+(p+1)%3])/d))%6; i=math.floor(h); f=h-i; p=v*(1-s); q=v*(1-s*f); t=v*(1-s*(1-f)); c={v,q,p,p,t,v} r = c[1+i] g = c[1+(i+4)%6] b = c[1+(i+2)%6] end return r,g,b end -- if OK == true then for c = 0, 255, 1 do r,g,b = getcolor(c) setcolor(c, shiftHUE(r,g,b,Shift_degrees)) end endgrafx2/share/grafx2/scripts/samples_2.3/picture/CellColourReducer.lua0000644000076400010400000000343011546110440026171 0ustar vigAdministrator-- cell colour reducer - jan'11, from Paulo Silva, with help from people from GrafX2 google group (DawnBringer, Adrien Destugues (PulkoMandy), and Yves Rizoud) -- This program 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. See w,h=getpicturesize() ok,xcell,ycell=inputbox("Modify cell pixel size","xcell",8,1,16,4,"ycell",8,1,16,4); if ok==true then function grayscaleindexed(c) r,g,b=getcolor(c);return math.floor((b*11+r*30+g*59)/100);end celcnt={};for n=0,255,1 do celcnt[n+1]=0;end -- Arraycounter must have initial value for y1=0,h-1,ycell do for x1=0,w-1,xcell do for i=0,255,1 do celcnt[i+1]=0;end for y2=0,ycell-1,1 do for x2=0,xcell-1,1 do x=x1+x2;y=y1+y2;u=getpicturepixel(x,y) celcnt[u+1]=celcnt[u+1]+(1000*xcell*ycell)+math.random(0,950);end;end ikattr=0;paattr=0;ikcnt=0;pacnt=0 for i=0,255,1 do if ikcntgrayscaleindexed(paattr) then tmpr=ikattr;ikattr=paattr;paattr=tmpr;end wmid=math.floor((grayscaleindexed(paattr)+grayscaleindexed(ikattr))/2) for y2=0,ycell-1,1 do for x2=0,xcell-1,1 do x=x1+x2;y=y1+y2;u=getpicturepixel(x,y) if u==ikattr then idou=ikattr elseif u==paattr then idou=paattr else idou=ikattr if grayscaleindexed(u)>wmid then idou=paattr;end end putpicturepixel(x,y,idou) end;end;end;end;end grafx2/share/grafx2/scripts/samples_2.3/picture/DrawGridIsometric.lua0000644000076400010400000000116611546110610026201 0ustar vigAdministrator-- Draw isometric grid - Copyright 2010 Paulo Silva -- This program 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. See w,h=getpicturesize(); ok,gsiz,ik=inputbox("draw isometric grid","size",16,0,128,5,"colour",1,0,255,6); if ok==true then for y=0,h-1,gsiz do for x=0,w-1,1 do putpicturepixel(x,y+(x/2)%gsiz,ik); end;end for y=0,h-1,gsiz do for x=0,w-1,1 do putpicturepixel(x+((gsiz/2)-1),y+(gsiz-1)-((x/2)%gsiz),ik); end;end;end grafx2/share/grafx2/scripts/samples_2.3/picture/DrawgridOrthogonal_Index.lua0000644000076400010400000000114311546110630027543 0ustar vigAdministrator-- draw grid - indexed colour - Copyright 2010 Paulo Silva -- This program 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. See w,h=getpicturesize(); ok,xsiz,ysiz,c=inputbox("draw grid - indexed colour)","x size",8,1,64,5,"y size",8,1,64,6,"colour id",0,0,255,6); if ok==true then for y=0,h-1,1 do for x=0,w-1,xsiz do putpicturepixel(x,y,c);end;end for y=0,h-1,ysiz do for x=0,w-1,1 do putpicturepixel(x,y,c);end;end;end grafx2/share/grafx2/scripts/samples_2.3/picture/DrawGridOrthogonal_RGB.lua0000644000076400010400000000125411546110650027053 0ustar vigAdministrator-- draw grid - rgb (matchcolor) - Copyright 2010 Paulo Silva -- This program 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. See w,h=getpicturesize() ok,xsiz,ysiz,r,g,b=inputbox("draw grid - rgb (matchcolor)","x size",8,1,64,5,"y size",8,1,64,6,"r",128,0,255,6,"g",128,0,255,6,"b",128,0,255,6); if ok==true then c=matchcolor(r,g,b) for y=0,h-1,1 do for x=0,w-1,xsiz do putpicturepixel(x,y,c); end;end for y=0,h-1,ysiz do for x=0,w-1,1 do putpicturepixel(x,y,c); end;end;end grafx2/share/grafx2/scripts/samples_2.3/picture/GlassGridFilter.lua0000644000076400010400000000130711546106440025647 0ustar vigAdministrator-- Glass grid filter - Copyright 2010 Paulo Silva -- This program 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. See w,h=getpicturesize(); ok,xsiz,ysiz=inputbox("message","xsize",8,0,64,5,"ysize",8,0,64,6); if ok==true then for y1=0,h-1,xsiz do for x1=0,w-1,ysiz do for y2=0,(ysiz/2)-1,1 do for x2=0,xsiz-1,1 do c1=getpicturepixel(x1+x2,y1+y2);c2=getpicturepixel(x1+(xsiz-1)-x2,y1+(ysiz-1)-y2) putpicturepixel(x1+x2,y1+y2,c2);putpicturepixel(x1+(xsiz-1)-x2,y1+(ysiz-1)-y2,c1) end;end;end;end;end grafx2/share/grafx2/scripts/samples_2.3/picture/PaletteToPicture.lua0000644000076400010400000000111711546110416026054 0ustar vigAdministrator-- palette to picture - Copyright 2010 Paulo Silva -- This program 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. See w,h=getpicturesize(); ok,xsiz,ysiz=inputbox("palette to picture","x size",8,1,16,5,"y size",8,1,16,6); if ok==true then for y1=0,7,1 do for x1=0,31,1 do for y2=0,ysiz-1,1 do for x2=0,xsiz-1,1 do putpicturepixel(x1*xsiz+x2,y1*ysiz+y2,y1+x1*8) end;end;end;end;end grafx2/share/grafx2/scripts/samples_2.3/picture/Pic2isometric.lua0000644000076400010400000000316411546106400025335 0ustar vigAdministrator--PICTURE (part of): 2 Isometric v0.1b --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Email: dawnbringer@hem.utfors.se -- MSN: annassar@hotmail.com -- -- Copyright 2010 Richard Fhager -- -- This program 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. See -- Color 0 is assumed to be the background -- iso = {{0, 0, 1, 1, 1, 1, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1}, {2, 2, 1, 1, 1, 1, 3, 3}, {2, 2, 2, 2, 3, 3, 3, 3}, {2, 2, 2, 2, 3, 3, 3, 3}, {2, 2, 2, 2, 3, 3, 3, 3}, {0, 0, 2, 2, 3, 3, 0, 0}} isowidth = 8 isoheight = 7 xoff = 0.5 yoff = 0 xstep = 4 ystep = 2 zstep = 4 -- Part of screen from top-left (4 = 1/4) xsize = 5 ysize = 4 w, h = getpicturesize() xo = math.floor(w * xoff) -- just don't render more than can be fittted right now w = math.floor(w / xsize) h = math.floor(h / ysize) for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do isox = x * xstep - y * xstep isoy = y * ystep + x * ystep cb = getbackuppixel(x,y) -- if cb ~= 0 then r,g,b = getbackupcolor(cb); c1 = matchcolor(r,g,b); c2 = matchcolor(r+64, g+64, b+64); c3 = matchcolor(r-64, g-64, b-64); cols = {0,c1,c2,c3} for iy = 1, isoheight, 1 do for ix = 1, isowidth, 1 do i = iso[iy][ix] c = cols[i+1] if i ~= 0 then putpicturepixel(xo + isox+ix-1, isoy+iy-1, c); end end end end -- end end grafx2/share/grafx2/scripts/samples_2.3/picture/Rainbow-Dark2Bright.lua0000644000076400010400000000301011546106410026312 0ustar vigAdministrator--PICTURE: Rainbow - Dark to Bright --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Email: dawnbringer@hem.utfors.se -- MSN: annassar@hotmail.com -- -- Copyright 2010 Richard Fhager -- -- This program 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. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project -- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html -- -- function shiftHUE(r,g,b,deg) -- V1.3 R.Fhager 2007, adopted from Evalion local c,h,mi,mx,d,s,p,i,f,q,t c = {g,b,r} mi = math.min(r,g,b) mx = math.max(r,g,b); v = mx; d = mx - mi; s = 0; if mx ~= 0 then s = d/mx; end p = 1; if g ~= mx then p = 2; if b ~= mx then p = 0; end; end if s~=0 then h=(deg/60+(6+p*2+(c[1+p]-c[1+(p+1)%3])/d))%6; i=math.floor(h); f=h-i; p=v*(1-s); q=v*(1-s*f); t=v*(1-s*(1-f)); c={v,q,p,p,t,v} r = c[1+i] g = c[1+(i+4)%6] b = c[1+(i+2)%6] end return r,g,b end -- w, h = getpicturesize() for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do -- Fractionalize image dimensions ox = x / w; oy = y / h; r = 255 * math.sin(oy * 2) g = (oy-0.5)*512 * oy b = (oy-0.5)*512 * oy r, g, b = shiftHUE(r,g,b,ox * 360); c = matchcolor(math.max(0,math.min(255,r)),math.max(0,math.min(255,g)),math.max(0,math.min(255,b))) putpicturepixel(x, y, c); end end grafx2/share/grafx2/scripts/samples_2.3/picture/RemapImage2RGB.lua0000644000076400010400000000173211546106452025253 0ustar vigAdministrator--SCENE: Remap pic to RGB, diag.dith --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program 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. See -- Set Palette (to a predefined one) colors = {{ 0, 0, 0}, {255, 0, 0}, { 0,255, 0}, { 0, 0,255} } chm = {1,0,0} for c = 1, #colors, 1 do setcolor(c-1,colors[c][1],colors[c][2],colors[c][3]) end for c = #colors, 255, 1 do setcolor(c,0,0,0) end w, h = getpicturesize() for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do r,g,b = getbackupcolor(getbackuppixel(x,y)); rn = r * chm[1+(y+0+x)%3] gn = g * chm[1+(y+1+x)%3] bn = b * chm[1+(y+2+x)%3] n = matchcolor(rn,gn,bn); putpicturepixel(x, y, n); end end grafx2/share/grafx2/scripts/samples_2.3/picture/RemapImage2RGB_ed.lua0000644000076400010400000000253011546106456025724 0ustar vigAdministrator--SCENE: Remap pic 2 RGB, 1lineED-dith. (Same line simple error-diffusion dither) --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program 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. See power = 0.615 c1 = 0.8 -- Error weight (white is green) c2 = 0.2 -- RGB weight (white is r+g+b) -- Set Palette (to a predefined one) colors = {{ 0, 0, 0}, {255, 0, 0}, { 0,255, 0}, { 0, 0,255} } chm = {1,0,0} for c = 1, #colors, 1 do setcolor(c-1,colors[c][1],colors[c][2],colors[c][3]) end for c = #colors, 255, 1 do setcolor(c,0,0,0) end w, h = getpicturesize() for y = 0, h - 1, 1 do re = 0 ge = 0 be = 0 for x = (y%2), w - 1, 1 do r,g,b = getbackupcolor(getbackuppixel(x,y)); rn = re * c1 + r * chm[1+(y+0+x)%3] * c2 gn = ge * c1 + g * chm[1+(y+1+x)%3] * c2 bn = be * c1 + b * chm[1+(y+2+x)%3] * c2 n = matchcolor(rn,gn,bn); putpicturepixel(x, y, n); rn,gn,bn = getcolor(getpicturepixel(x,y)); re = (re + (r - rn)) * power ge = (ge + (g - gn)) * power be = (be + (b - bn)) * power end end grafx2/share/grafx2/scripts/samples_2.3/picture/RemapImageTo3bitPal.lua0000644000076400010400000000247211546106462026363 0ustar vigAdministrator--SCENE: Remap pic to 3bit, LineEDdith. (Same line simple error-diffusion dither) --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program 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. See -- -- Just a demonstration. -- power = 0.6 -- Channel shades (shades = 2 ^ bit-depth) shades = 2 mult = 255 / (shades-1) colors = {} col = 0 for r = 0, shades-1, 1 do for g = 0, shades-1, 1 do for b = 0, shades-1, 1 do col = col + 1 colors[col] = { r*mult, g*mult, b*mult } end end end for c = 1, #colors, 1 do setcolor(c-1,colors[c][1],colors[c][2],colors[c][3]) end for c = #colors, 255, 1 do setcolor(c,0,0,0) end w, h = getpicturesize() for y = 0, h - 1, 1 do re = 0 ge = 0 be = 0 for x = (y%2), w - 1, 1 do r,g,b = getbackupcolor(getbackuppixel(x,y)); rn = re + r gn = ge + g bn = be + b n = matchcolor(rn,gn,bn); putpicturepixel(x, y, n); rn,gn,bn = getcolor(getpicturepixel(x,y)); re = (re + (r - rn)) * power ge = (ge + (g - gn)) * power be = (be + (b - bn)) * power end end grafx2/share/grafx2/scripts/samples_2.3/picture/XBitColourXpaceFromPalette.lua0000644000076400010400000000133411546110700027772 0ustar vigAdministrator-- Copyright 2010 Paulo Silva -- This program 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. See w,h=getpicturesize(); ok,bitd=inputbox("colourspace from palette","bitdepth:",4,1,8,5); if ok==true then bitd3=(2^bitd);bitd8=(2^(math.floor(bitd/2)));bitd9=(2^((math.floor((bitd-1)/2))+1)) for y1=0,(bitd8-1),1 do for x1=0,(bitd9-1),1 do for y2=0,(bitd3-1),1 do for x2=0,(bitd3-1),1 do putpicturepixel(x1*bitd3+x2,y1*bitd3+y2,matchcolor((y2*255)/(bitd3-1),((y1*8+x1)*255)/(bitd3-1),(x2*255)/(bitd3-1))) end;end;end;end;end grafx2/share/grafx2/skins/skin_classic.png0000644000076400010400000004001311551414020021216 0ustar vigAdministratorPNG  IHDRXDPLTETTTTTTTTTTTTT̼|||lll\\\LLL<<<,,, |l\L<, ||ll\\LL<<,, |l\L<, ||ll\\LL<<,, |l\L<, ̼||ll\\LL<<,,  00@@TTddttxhTD4$ 00@@TTddttxhTD4$ 00@@TTddttxhTD4$<\|`@ <\|`@ <\|`@ 褈|Ԍp̀dtXhL\@P4D(|8p,`P@ ||(||@||X||p||||||||||||||||mmmtEXtSoftwareGrafx2SjZcrNg /0?@OP_`op}* IDATx^8#]Է3R%̅0^.G絴eI~@wZ&1QA ZAe*_*_*_L *    ,lu bSys or{kˊCOq1>3pזßͭt8Y=>~V5rx'>1 {+tr&*6x=-fl\߬w$}d\|(f>{r&זOg>l71p Bք"A<9叆#ICϠ~:i{4Kц >lG_7x P;O?.=\ZBG0b3vx6q4<ӕ b?y6^_~RO#n6Cq$SρхTOH|1pr!cxnR>?|6NSI/P!T BDsUJ3PA8p8"|:hSB^6v.A{9+=O]ϗ㰩ӌ#9xER[,rzG]$>SZEu:1Ek5Piq_VVʸA1^8T}`ڧFŰ8|tRBvh\32ǐ=a4S{hOv? Iy1;ׄycxDQ6G=(3J#(cΙ6= )};[0R:;m0qEk!{ȸ8)}~OWv Ү1:UȈ5=z?k3tsD.7seǷWhA;*m:܍4nEKD/L]>f2ucp_VdԵi;?p.u bN{E g%2G[A(a@;?I/+4xjf 7 1X3ҤW9T~&WŤU— WB9 UP-;QadA sC |c^i=,|kl.|9Bp>ץ*mYw4<ӻtT%Bē( Ovٛ\  G^dT=F^=(pUx>od~TKQ e֎sȟ6YۙɎ.e$2N1UpPKo$7:wbNQg rDZ_ 5"q FT>ǫ:q3bJ?.U&(m|Æ?:M3*c'b?6Hb"^iץiU._j yкv[J34;$|;0|Z+~d#+X{A.uSLiDhgpybt$|!yņT&|ѹJ1z]`pGb,8| ;USHKvbߙ֩U8'0ǥUN~/FriImˬվ/71jƞF8,?sZeYJ2c Ρx%FvPz'pUu~^#W5cu)3#§U*tW~a6Y`+Lwxg{9lٺ QZ~䶺^; u枽ҷqʤMӪ iYRVq+IG Qs2Rl^zzR_?W( _)|BKMW9~{/~K KcJx NHqmz~F9;8`Z>1X6$kt =Wsf}KՃ JWg K?FERV{ szV|OWB~ 6~{bK$ި j| i(yl~?߷AV\q>vW/|*U&|,qzb}pPȞ^ONbgs,>d -ЗHq*|;w>́z)|[ôڍ +ҖzZgخ0LX mLHlLQỄ=Hf,'Vwxutݣԓ]`*[ vZ3 |Q$,|l5C^mș:ߤ&\,#U PIy1)-|S6x~6fmə l2Z#E" {nԦ^+U=,;%ӷq Rc92HOq5=w#t"Vj _QhA;Jaˀu")uneQ=N k;"W㏭백u~Ko"KI[tS}Nꩦ/S4WyB?l/E=UCk'Ջszh .||^ \Ջ ޹?zbWoQas3'h9-''գbSRϧ<>yNGGvnSoiT..sj\2^~{~d\=f9>S5(}\=O`zFN~\a\$_Vq*|W5:=^>|{Ws4]zz> +^C+UC2Ӿ/7}ziò;:(e6Ye$6Y@gAL8N8=`GVuxp\e#k=W/ S9~n\PAjg/]Bd3|SΏws +u=PɠzyKv,U/jlد?/iF{~+Mk?sw}*wT3l1*w菥Yr_~ e*' AjyNam A`:W/EGm    ,v^z?| o,[\z;,Qݩmey!0Ç >ayaY"P῿ەG:/#xO<րgV% `\O ߺZb_'qj7|v~m|^k_V >Q5Waun;]؇^2SbyzNW@.|'گݻUYU/XU/XU/XU/XU/X&}|[*m)$-p,0V g%rɒ:ls6 mXmu0Y&iVʠ}K6-]JlK0!6\ /1nIJxb%ˈ4B)|Le* z aN w* K mx>ZkklUݖU6`oSS`k:n]igfͼmkdS5ڟ:j;fmOK]ݻP]ᛔ2{CڷmT1s՛DZ%'x*QΏyQDZ%󛠜kV52uͺowB)0Zp1m_;/o9޷/m9)}ซZnU/XU/XU/XU/XMKjfA=r!Zq|iI}Oy4o'Mg; i|dZ捦z.q6dYkO3ex)^8oL+ɼ}5/A94}U 8U-] 8[Ty n3|{JtNEA%%eOiR;6 -;x>xc.e{@2)|n} gbQs QGF.y; =2oyd(z޾:Hy>nbs(Wu3ɼ}=G}#$%ۧ8]W3{NO}:wIo~i;OR`:}o?~k"V>Kz!t\')0 E?G֞7nwH3z?^]S$\NVL_ΓKחT#7;>Q1FL/_zhi;ORh`ȋ Ђo/췅;no7eWHwzV_DO,mIsPM 4Z>68.KybjF_nMO+ f^o) C[{.1OO}3kD(>ip}q|C7cnev}b/Ϻ{пITj*CFhLB˗k%>6w][`ku=!,OVcS3SΓTbB] ߺ>쳎Kx-jy~>=}1IC Y=z!¿YऎD٪)ɯbo/4bwuc0:mWsD`w\@X*ԛe9]1n*ǏĬ#Z"op٩ =>z}qqݔt:UΓTN/C;-sޜ`ncA̫s PYbnczg7;m~VAy#$+"@_(w7 zycГ$,h2U(ܵW7hl+,(S  4EDd'运3R'NŰfh5 /Bqrvj9i(\?ì|hx23F7~/o..0vEgv!Eoerr&f6D߿Ӂ?s)M.W߾I/!ā:|vJi;OR=#~]=K8~r?!|,Hudop@^3gR_|y=os jII۷?O3:X$6S/R;' ^F~V)Nf"Tw/׊f})<<ܿ|UCàqP" ?Z \ϙx o1OOOX?]ڿyi~~7-Siۭ.x_]u=c"x8+/mIj$%] ._ ɇG,7}^o>Q `P'?gk$k\1faM=P|=1vo$ p{, ~7Qw)ʡ|bGL'jBrz}Kw!fJy~34-н!Jߛ]$c1Lr^H&wЛWJyVY*_*_*_*OkgŧOͫ{5>u-8Kx-~4}_ږiAFOEZ+Z1~ P뭎cGB]AtgDvt|] ] YSږt|n? `ͪO PM^:5:Sm[ӭk;U_ok;(n_Gt|[֬[MίNX*_*_*_*n^Ay/;y\Їyxk4;98uÒlv|% 8g)d>h]d[x&o=6^|dh?N3+^k36>GkP8vm/{h3V"RO4x6tJXY2Qx[ڀsV:ׯ'z"xZE>> !nu՞O=2c 8g1|,$gG|=%ا}9=T+χ 2.=WiYLB|:ҳ{Ub_ɩkNHAUhy))س7(~Jpع.FqO6F%v-WaF3[IIXڀsVjޒBy>x Q.S :_^9e-SڀsV _yg?wi$m{d<ߧeK5ډI6/Ǽ@rNxN;Y*x2JX|촅ZR{>+MBU3|U$ 1!*T%H|$!s[/}xi};ȥuiYYMo}PiYGu|6^ zCu0=q+ 5u@ lQ#I#C:JGu_e?m?uѺxd Ri{? (S$1pD]<Afq=yO=t p(9$xU`tS!጑bGF%Cņ#.Mrd' $~nbx괁> T:>wOUFWOwUo J@TXf= EI'sjz Du_}Ҁϵ 0 FiY .k婾xO]z"x,hnzi1S3<;G"vH:ͤ+i.hB4AuWwh_գvc'Qt 8gIn;񽖗 gJ9ڄG|uv_$*8Uvrwޞ)uxݻ:K竺֤ߖQ|>5|_.]2zǒ%2xHhځ5['p{>6i,4fJpBzJ 8gnq;}55z-m9V_Є}u3EiYJ;X 8gΑkKpα@iYGBģ9I,sָ9j 8gmsɫbT 8DQ 8gfwJpΙ{WiY;MrĿaf')p|6Ym欷0ޣɛ"3gb6yZc:#pSmqG6t{ZnxG۝u2.1:ʙ Ç ^UiYv^zS!o^cnCM873<GD1?@fY,oca`,F{OcѭQ+|WdgiYLB|=[WZ*M,#&?S9CNW$ѾRRgoo6P 6sM=\:*m9KbYcu2Gzm|p+Ѿ|T"iBxXz*_u=f=x@tTWNYgA~ 6Wh]) i<%K|x&&'~C/Ǭ@rN+xT9p;|'K _ڀsV_ KK?tV6 V!Uz~PiYT'6T%H|$Az1ƒ{ i|A|:v&ad}|Z>#:Jp΢u{,}+`zX03P3NӫBLҾ42j`d|1)|J|']1UFu4ca"Ǒ~=_bUDju4o8!7?)/%#>e*s:bMDg\G^}V'u7tjC,|^~^ot uk{9D:DZۃ>Qe!?^;@ѓ!L~Ὓr-6m#]&z Mݴكg:+|/B ?hctWYSy]cu~w|/.Mw]L#s~oE^|C?#=Or|#;3!Zr>(I.~.Jpx~lnKCWim^?=JMT%:&]5Is9i;IrK},_2V^?~7VtOTv@ `Pm.2)S]R7ѸfEy}k;χU`M~nL;ΫuWn-t"u2P#Z/Mw͏^>GC錀FyΜ9?d`C/5z# ِ4{ c2߷^~|5P7"K}]SofǤ#mòcy~:>Y_%w#2[5PltiƶloͻwF8|a[Ŭ >X٧~XXs 햅^ׁ3~¸Nߗozqg oÑ5lE|.)~GzB>Qbtz]Kn&:nvڤO޹nڻ/cpƥõegd[䭞h_y;T ԡ)\I3|-Vm`L1Nc2ڶkn/u;Vu1=TS?m_Oq3sQ7vI.\ 11Kyo/{ƌל|h2?&*('*                 R2dIENDB`grafx2/share/grafx2/skins/skin_modern.png0000644000076400010400000004711011524351352021076 0ustar vigAdministratorPNG  IHDRXDPLTEa(U߂i,E$ig&LW FJ478'6ԩœzempZ_^ORLDD990++% }m]M<, }}mm]]MM<<,, }m]M<, }}mm]]MM<<,, }m]M<, Ͼ}}mm]]MM<<,,  00AAUUeeuuyiUE4$ 00AAUUeeuuyiUE4$ 00AAUUeeuuyiUE4$<]}aA <]}aA <]}aA 릊}׎qςeuYiM]AQ4E(}8q,aQA }}}}.}}E}}\}}s}}}}}}}}}}}}}}mmmќ'tEXtSoftwareGrafx2Sj`crNg /0?@OP_`op 98 IDATx]v,Nby?a`jBB8Zt'FkSEU1GKCGa*E%¨O ?aT' TJQɟ0*F%¨O ?ai-Û7x>…G,ZX= OnpƷ{} O?/: WiWz|l>]>F<"!:RK;ڠy5=Y:-oy\ C㉴ݏh>6!{:D)7{ V:ʣ v, '޺u/&/K_8o,V&Aw\y&GGZoت*2d6=oeϾ0[Bg!sdxHFAo?KG$֥^z0vC~_V4eKGM~"O(zߤ9G+n0U`Ƀ>$eE!đwN8ɡNЩت}^aǥE~!|r.㏟7>>7%RPX rCLL }qwo lY1w̷o?:{ؚi77D a&$ Fqx_xEJA;a|Ngۚ/BTIC֐ M $)C~OlՍ-Gvk_FPl涇[w&oN&rb7w!V֩ 9**+̗em;0דB=63<+$mK"(<$E1kݠGT8tHQQ,@i1wܬH`n)I#A_)f^Bht5VgRaJMjo50> <憟'@_6O {}~-fBR8bg,]W =fRIQL4P|N)s7J4}J:zЬo S&>Зi;o6Í-~v;֐.Vviܪ9sw J𱢦0_Jr50oWf#=ƹ4Hwv*SxJ0~f$|\L:)?VV'YX'JJLz qQđ!؆D(¾@qdӸ5t5iIKJ6W|ﭣ$8#OhS\ {9!\r-"iܪ0>o%2&&|_{r}_.!bE\EjTϩBAIv&bo|M~2E1~,uݔ/яRc^M N\;5wCMLH0fOܣFN<=X Ky#gN$7o "-M{ɗ.+0t{c"'nܞAxNsAjh7  5e#OeVn#eV?MM&fK~(Ser3M4Io0o"CSsn_*#qeEk|v/'4#G~d4(M].ewrC]F[0ȗ4hXGɯoq76>'8¦-L>ς$9ދSi; ٨ OYيhKKg#ߴȗ| 7<|EҏD>~!eguG|)QeXE+[!j~++t; 9&}M5LOXTи1lAPi7}~3i x>A7JkP|3ԿG`2e/,Ï~7eg"} 7MZ4?֯= c3hh_nϭFaZ# X}d ߵѕo^?q",sgG|@djB3Hnh)Oȷ?O~Z̘J fY1Ff_'Mƅ[I@P_HT|شLG,$Ç}8n׿4kϛE>Yj̾x֡[ 娌sr|䞦As)6?Z?OZll8>W!J9#eH|hi e} һ?Z??\ƀ]5h,h2Xl AW<#tO@77s&+w}:*!Yߞo'G渖Oo^ 8gGxj~Qwvź J0[}v>%<ۧQަG +uA>b ?a A>^GۘoVku#.|ϒ{G?iT8Bk~vi,0|+1UO`jǚO hE!9w_$1H~e򝴲n~ ҀBO^ȷ|dNGD~Ҹ(3#ֈyM~"wOSqr= L̵5$38 rzE^){|4?7U8}|o|O=}̾|wb}>&hh yODآO ;.-ϧOgMfk{iO G{\"?LE]kܷ5_ZQ \94mֆ |\I>vOb\[Z4^ヒpK#fqͺbo$_FDNd O3 Ice{@Y''?ztT SR" qbM#i"7οkOƫE}JX+_ J {_]P}4|Щl'd[(h9^ՙ2zRFEw1 c+q:W};ź0_ޱp%]W =fRo_QL4P\N~o7>54MuqJYLγs747[F`4lZ&15ipoe< *9NJ]z>W{ !*Ilg9pME;n̿R;ɩSt?ŽI''܊*$ \D+2ɛXFFMGr0i86ľ::(Q!1|c|6M,)_1>[TwEA|G2j(sֹH~C眎Ksf%i>hmLJ"?*V$'J|4&q/Aj/d/ۛkg"-'SZSop\}~tShFIJQ{5%;q 5##2;##oh>5.{[:UWxC[y#̽ 1JŜdffW|1ۧL^_4B2Êt'Iq"lh4NZ5͏"_λb`l%AMp/(꼽5_Gm0WՔ5wX}_ _IP!{'y^6D|69|[UGf{dgo}Ea櫣$Ou| h)zv)wdh~F>U3{***A~pk$pJq :͕<8߼Ѿ/354 w/Cl_ hN*M] wp5+ypV[x +d67{n}q]G|cNb_?{EȔ&;QeXE+U楪׿ƤE_5\d/64#3~oRD+w7l&[ SB;q)Κ1Y*~L˫*~D>0Y& U*h%A&:_ɏ{W{tM^rۯBi|A%eE>he E!M$[|+O`c0B>?TU |6JjG4ߥeWbTD> d|S"N*\s:|X@>u 5?]0E߇NKsyŴ}兽>Yɿ5X*|my)?) 6.(ET*-!( zItNۈ:nB98MU`}*R2 D]̘_V] _Ւil:QoE/̚] ߘ.n7ߪoBiPo,`o$Q3aT'JQɟ0*F%EZ2r. l_*bɹXvFis%91s:Q&BkmKyM䨐hs)UtTeԷ_mĵ:c-9-75ѷٿ1ݭ:λA~0M]>*-!vS{}~vBξ(YM {){b#^i}{Pk>YU8JӠ(ZkxW &M浩%{w@un;Q! TDwcoEB|4Ej~4I>(; _L"<~>R-i>w_WǓ)]/J件ٗW# {8( /sW \9P5(o @|fjwQ"?zeQD~F_"I>dٓ(Hhwv+>:r"k`ފt >;aT'J.=cwzkʷ} tLx"9'm `ٴc%X/e٫j 7Zed៼q؜\ϥ^X'7xu&o<J,Ó̽?$ߡ$k2;#r@ Ux&dҦXvkh27Y>K-1p&(ό|mRT\|f5eeܓ;!1<3Vd:&֬"ԫX ;a%u &XoePW;6^jfcɁ Qclo -)cY㽷:& &yjv2Y'o&'W~2-o(o㰡IJVw{ךdM&PľG\JۄL˞cq)~5-^Ç} tL0"\I.3#Gr$qI>Ϛ볲grz:D1U?}侒WkV|OU, l0cƒu_T(\ xW1IqE6)6y7>|Hdf>emْ\8Z$r_jVV'n;[@G8WO\x{nPxaiJ#2aTV $FWS;3ty}>a[XE>qo+.o̷6yYq[wS3p볘O&vVmvTXZ IDAT..{)o|36_OBlL~wb*v/ \F{yhwH:h \4$>3-16H,Ma{vLFX_煨DKqYђD_G57w蘠 U } tL9&JQɟ0*F%¨O ?a\X9œ}_ I/+t"ÁXxm`-@>c8W<I/YRw|^+,0oHߑ|X' 4h >U|fz7z(K8ps"^tP|Y`sdxaD%3g`tGC=: I ?aT'JQɟ0*F%¨Of"[΃Dߤ| a]-9o9*>{}q^.Y}y&OC?%0\ٷfNbofm<{l&|:Ozs?C[[΃DU ̴OA~!>n:?/$"W~>]~4?m#t m>1uzWrQɿ@ɂop9Onl.b;lb"{{7 o|FlvC/#RJ ~1@shaP)\t?vBG>4N"? wCQ/@<? WN 9p@>6{=VWVd~7@e>\t 4WHn)p,cxW  9zs6vwgЍ;n >gG`/vcIy}:Vrwv9O+ p#Eۻ' ACWxLv4G t̯"߈b3uY`:ԿW `ƒ.Z:4{y D7| lffDLi%H>$Hf*H#>jĞ4Pr<,)9B7g. h?~=XJ?󞸇W;P=`ZQ3Xu؊9?bKk>|=e"#}\?z~*XWP j}nz gS7%@::4Pp4ل@(pna!b<Bp#;n`,B(Ѕ.~9v.s8YNbK~v&f{8S'j{`1( i9SyY% M{> 0A׫=+U{hwC~~1l@Cl@|:5\-m {7Q DtVs8¶ 0e L~% MbA=>xqt@b`ʁP.xik ;yv!.Î_Cs]R< v6h/8 >VG^oא{4`3.'h*KPbH^N;HN2Ȋ{ >3(.`W`׻iM}iDYt+e0qTp؅X{PCO+-c-;pݗۥ1;K-}9"p( Ϟ2yYÙh<1pnl`8s 7-8}:s 0s_CP9:|G!mWep8[LlpกO hɳ|חDh#! VV~H-oNՇE;ss*]\Ӈd(|Xhp!48;HރGLp,p^1OKt֎# }hri@xq!qϡnR^CG{h{J~Gs^^Rv!p3 8I> y|2ajsyxċ[/p<9h\Ze1xBӓ 0y7l8S0r.Q7 gg"~0=8JD s6{dH,pbaZ4P 2* /w!##\m ˆď0g`}2;>x~rQ- !0&*e`/=9=YLJ}8EKzb>Ta2[˥ BRȇ &Tr p06 ?rqv4`c3>䗀0|ooq#?Df(PVRٟk/Cf=R0Nc6p.Y ^̾zw:U¯`>Bc;AaZ s8% v>_0/}ӷ |>B>-4]@]jbAOo0249 +VNZcOBy<%q~i36-t9_`!5guCyXrTX q&#dMA߳n2%>~rA[ߝ` BT2'+ٔLƀkES;| ;b;`HBX0w:@?4jGS.p*w pt.! ~p9h~\K䑠-qOτA>'Ԗiu {ĹH?M9>DsD>{F~0ӆdm9=+< 1/aFcK/3Jgo/ҷ ?{a=VqdYʫSs1Ƃtۚ"3eO[ /:rN YZ:ħuh]L>lr${zdOx#a gz6ƜH> = ܑ}XdCEg6% ͌׊!fyyN^zxp(ŧ{5e#;?~CN$iˉR9d&V͇+O}zpQ@YOQM Dc{Zo92V3\R~J$Jx`Өi"P0S.C/f7e!4O !b a~jU+b.g^ η7z}F!v|q:>Y)R4{D ~~=Y_ c~Oo_ .2C6XcLjw9@IT"9(%Z{~wY.|oDMOs[~FC4J| t9S0lA@|^wɟ<}y ,+}T2WLh1&y /0ߜ+$(ӏmqVv4-Ũ4^{[0he*\Z++?6LH:ٜ`9 Uicn{ޠ{!m[p|b_ +OcT}~Wp|Hm8n_cT}~8%n_c}q1>?59d ?aT'JQɟ0*F%¨Ox> A 4O;\pS]\.I3eCR#}fH<[_Ԗl9!7ߎFW[cFaG?J]EHaQHY;42ٗc5=]b _o % loo>*\UFUjotJS0;,Eapչ8f<,RǥX&-quqM+7%7o%UƳN-o/3!k2Xn#ӷnj|>=1EHwYǓȵTx׬,8fOyK,@j99]bUG#t9/:jRy7[cFA_I[jOf˹ɀ+0|euj8BL%$J ;' ]VEj$>䒥l}F:3:5;#ob^8fdf֧T:t݈'Ϩjfŗ&44SY\yd_R1;8 KGL Ru14@>uM+OGԓ9) Ȍ9omLgBQ!F3Hrn3|1Y3&hzO 综jd4BxU IMn $UIBՓjp39Nıc~ul~W% 9喙H#ͤ95C^ƕ;|U/i-1oF3N5sy*&psNQGq͘ҥ&j* oJԇlH_؈y߾V!D3Xj}d[ck_|T[cq\ߦeXɭ?=78f[cF=8f} px-3& 缪 -1E(ќT߷ hܼ8fRoQ5kE-1oF3samѷnj9߷njKs ]q >U/X.]QSCx^J+TYdw 8=?py;3[)yڧoya~% TM ?aT'JQɟ0*F%\6 kA 4K;R7! G%x|;[co5guBÏEBΜ=6HC8kC-85p7|W} p4hgCE dIDAT7m1u>ځ*5d[M/f$!ः`C#68fD-}$s|'b6uM:/_i>ݐqbȾ8fD&|J+ݠ%4Jn>_82tort`Ew6Yٷq8f<,RǥX&-qbuqwwj-~t dz2=* ;8v\G&I+S]<>5&?1} pWhS1y{5hHmn ]Yr=Y?I]1Rq|H-' :i dG } pxDC +O o¨O ?aT'JQɟ0*F+iRxoo6Grzs6yLq{Z?r#ߪ[isQnmg=@3TyRxiYS:/g({7^EBm/h|L݈~&ߣ6>J>M$wQ3 bt+'Uc}~_T BJZ{MHvOwz|:(jo~@ܷ/jSxZIYu%{I zm]u.6wK˿v`P0$Q 1@O,8v E{d5!W|_VrOOSIYF{nK_1|A?>?j6-a60 |qL$1W.*p/ifmZ /Rө){>;h/{wĈkA~>;{xmJg/}`0? # 4PwҐhoLxzbh:Fo||5Pwj-wɿvO%ZF<"m%e ˕IE?4?LU5N]&mܺm~|NjDz'_}ن>Fi=VuBoJG~qA|)4 .F=zi{vǼ|ڞjs'NM:&W>յz:u m.6O]{'i _4z _VK>!5mE%4:Ɨkcغ.;oCܞM uY |•m3a|xke=c&5 >`G0g̚O+E%¨O ?aT'JQɟ0*F%¨O ?aT'JQɟ0*F%¨O ?aT'JQɟ0*F%¨O ?aT'JQɟ0·L6IENDB`grafx2/share/grafx2/skins/skin_DPaint.png0000644000076400010400000003574011532771322021001 0ustar vigAdministratorPNG  IHDRXDPLTE}y}˚E<aς<QeyA<A(MyA 000EEEUUUeeeuuuMYq44QQmmM$U(m4<IYeq}4QmϢ߾MIYQqi4QmMay84UQqmAAYYqqYu A,Y8qEQ]iu4QmMey$4'w: ыv.u:y/^~&'_VSei uUU@NeCEs2bx3QOp3@Z$S be Ş_V г~zgX r{9w0ok!aGUOܜQc{B8٠eS^ ުͷqKd`]v;? i8so)L~ ގ3cg:jȗmMW}?NT~3=|"5ԗM{ a/SY5>Ww &Z~=OЁpiQ)jߚ e=ei :{ ?>SHC~cba.i,t;T.;>eG4j 3~tB>l烷AH~ [w }>aLHuy eoJ.Jm"/Xo~r?ʃ%s?Lft||2!#Fʠ0m"aȜ7;|X8 rU(_?R "g :c6QU:C!hޕD$8za4(||$|C۰vS07 ɣڣx>L4QhJUͼ 6v>q[I)Id[b;iO<>ÇA*WCKZSu4\YA|o~I+(4"эo9^AAʄϧ^TwJu|gld`廢旻Jv ~"[[A'e: bGz K*;Mw=߃L)S:󃯪 z}$gwv8Y໸ RTW|MݼNy~6_)͖Sѷ^XA*銁Wj96|DGsKD=U6?((/eUh;a[M*4#y=_zr G#||ĽWa _I ?h6_íYe>Yw|w<:t6^*c[f[fճKx~  ߢ{a'[r4qv*`oDSXB}z1[k+UۿkO﷣iOX 5)Dq)U!BgI?*qZj!xm:X iRz^: h 㩢Sn^:ϫyҨr?jn9Gvt}'q 趘˫)?gc;||m4ڍ,0.L ?hn2(L`ۆH72gfij| 05ٓ*3lK`)2As?L! H}m3wGPDc|w%H|׃G46^%ỳjǛC)`Ha* \f5 j_Z?~!3$JZOLUWy*ۋ1a[Eת(_{Uj]E*Ğ< =_gm;9^PN6u0ÇѝfDz+okrtlZv[aKіÃ?#׳Ny#hNVfzƒ?O6X}٣7:-d2tSy]׆z.ځ;F=2vXw|w'?ux7Xm1G++:vlOms4jn9Nҹ4m.ϫ;=559^'ӓϧ^0*wJ$;C|ޖd#?|tYj [uU N+$b* -]3S v~࿦_jߩճY;(l}o^Ny~6_)-|555Uαk,+Xk;_V6^17l ~A"9aUE, /XT,_ Re,_~",_~",w& |r`= K=EJdDOIAvgXa5+C'my۵zƂNK]KPpy/aj<./0 ocy|]dr,1^ ]\x_WqnFPXp.#,SGc@J7װNT.| WOiSA63UJo+X "k|}Qb:F]4: _7TI`7~~C_:xjrڏ—As>aW 6?,WOK7ѼAa_ >T|Q~U7tQw5e)F ϱ6q|k;w} (D;t /X`E /X`E /Xnrx"KWj5Oo5jՍ=f7cfKۖuc61[Dty6"htYm1>6w=, >٢z[ c{$ guN=GIVgl U5ڟ8W%YZB N?ϴ|;JULN}=o-G}GIVg!ƞ3\rnn;|\9᳔o(P( bms{T:c_.NUGkS&u5qnC{'"O݌嬞Ŗ8wR#3kv;6hœۏJGm{=*Sfwc_uOɽq7h\?{o٦zQ ~K~"R? Q:|h6?ؾd[twQUt%YGXV E%A$ǨͶ! o~[Ad7}>Xd@-f-IXPpjg᥯!}?Mp9&,J Xޫ)j~9<}C&SO([2nm"vvpZV6Ð|`/A2_{Xk瀮:Oy WS(wFI{~y>x~?نB|{~[~m˴U^w6n{3=~o3!}(wVbbO>:+3ꔲD~Om),ZQ~",_~",19}T :% `߰fn :%9\cy(bQCGstJrl[l38AFϤ >Mk_}mm}?:AL֬%I􃵝I׫bWm) <cܪ$iz,gSYx?w WSu`5uwkIozu{!;uv>$|3w#m)I{~y>x~? ͘6i3 )ϯ=g緵1'{\߻| ]O1P 0ޫ_{n*=7ǽhfBH75( Z^k ) :%lR8m));3'=D9 /X`E /X`cWOEo8&'Q~bVO@C2??iVq5<fuO S_>U9u#'33<OYav~-p(j^{|x^ɇOZj5  1승y}Y틧) <ʅ\<7"_qFǜ5* 3̓,}؝E<,_~",_~bPn;RDcWR˽߇~_fvᯛvn| ~.|Ihjh&ۉ?*_w B`t}/9{_4{Aw6g#HoM=K_}`si(7d-$wI$ןY ?{M__Z_KWkC_ngyA}Z#)?p~[/\susM)y`+%VQ9t|>@/eHnin\FW/;zF\`v/ַUo 9{Hpgo9zX;~{=#q >w{ y4|pǿJW%{~+jCӋt/a~B?5?W=]R7?y{+a7זJTZG[zz9<goEqP/^<?!Y˞ݷoW4}{w_~"-!s6t;Qw G-z~=7-y|Y֯Yl'Q$xV0wxԕlW><|7b9Unek}4,`zg"+gIIuJkqi5K ~,ZvDgCGOjF_\A0Ў/je_J]:'鍮9%3,Y]> Q_aVmZkj}~aTbB;T;MNOl, z;#oR{>} 'Z.Z߰G ( yTH *_A `+k^<>y~R!zsk`u_=t}΅/d/ᯠ6[/L~ ;,epS㫢"* K-K‡x^k.}Ejg(]_&ث/A9 ;[U?.BW8f7A$1aWuj2wwno-4{9n}[ASW!{~uhUCy] _s__[@~T>xz2VLLr+wQgWa^x>@]>+z ~F@E/$-^B] \_,<%K;M띠?/}{wCx/ x5fw{-y~B9ZːW~Am+I2$ {><<ȷ{ Aa_j6堦zŁ?tY0c -bPGqW;Xv- 4mJW-{k+;yZ^SWA :l$ًO /;ܘ zE: %# ߿_vmE9PHwJzڃ!^~BifϠS__e8oED-K۵/R%|^yūE_( r?v%Ȋ8 ~TJzRs5\/-ʩ!aXZ K8gKxQ=* |ǿǟO=u_ ISQ|/,ZX{ s#Q t|WσЇt8ߊZzzzOuˆ#?o[J?zkүhri%ORV_ o~6WKCn%@;?^]@C Y_y1>/wu hV/!1#Fhd` ; k3%{IW _Ⱥ`EhIF_+X%FeCcr|~J^ ⱛ IDATKuׇ//O%Mʻot2Bt[/B/~q@fvYPiG?% D&{ʿp|A?Y?{e s+1/y,-_uo4`D}<}o* -R7|?J.~!ޏ9Wtz^x0#>գ{zX ޾ yczg =~O~ K_W/Oҗ/0lg) ^RWz|H8ZՃ9o>eL]eY񾥆oֿAWoF_պEvnboPWJ?ǿHGQ0q b ƗOq^O bWT비?_~Sӟ[?'tPLL%R{ְQ&_>`6!JOJr,xYrF>HEސ+ѣ`^8 ;rn?J>o?@%I=OI ﴮ~AWo*= (bny0&s`7~8/"N_~־YF>ep<ȝo/9ȳ({Shܖ_3U`xX-Vb%3$rZZܛ+DFr}^otig!?*/}f%gt/U@/BBWWw~.AYu5< XUv )==OH‡&OQME`~uã޿ߚDK=xp88p|GpFnG%[ߘ>Qã_]k#_=\}9+^SXxG;K7&8/34|o߰F/oIWfp)~%n~vFppF@4t|EZ|EZ`U,X`E /X`E ޹?vS{v7e^ qjxx~~}gܶXmX<N]y Puc8SIr⁽?LdJW;pov=m99;Ǟ֤|'C56{DKm56/Ͽ&S?ox|_\m+_Zj^ͧ~E9 /X`E /X`Ŕ1jQfԵ:^6"Wl P/*#ts^qAHnNYR㸳5*"*‡ALQm.t5ůo>-{r͙@6m+ lEDž:;nF jUcc}z;S[1qMlh:vz 63b8x匢G0Ŋ%xv?r#&Csp Jwx?ϣb{!]:g>"þ4* |gGq΃٤0Piȶy>*[<XZ^KH !8K+Zfj68k̨>7; p"yݧ# ۏ2rpʊyNtp: \O扯]kz4χixf>ۉ jNZ6{0 k@5_Xo{}V[8|]Q<x7b'gc_ۀ9)칱ݜ P'Ŧ+( 8e&8X 8e1܈z5*>M:p<;>m"om)tgŘ5V'Ox ŵ <1Qw_c^j[8;-\d{m~ߐ =mM6;̘ݙP"&xܑNp4i:k/>0V}J)@Ʃ kY! u7kzm)@Spa5,<<)rr.O­FnNY%tΥ@nNYBdfs.}nNYqvsp:XWnNYň2D^Q 8ef7X 8es}{rpcgzy =j ?>ϣEݗԾrpg'#{?D7w}RzRWm)uOXߢh_)2 ~ے2,Iv!'b#NZd Rgjewp.~$;ǯv->Y"CmlJd蔹 8e!X5@|dreNjyyl#k΄:>n_]a(g|/`,>.t6qWUPrßk6ر46ekbGGk,Sam+gT >L,Vp/A^іwY4:ۀSVU{ q|eܛHv lMU*/ق=2ZD_PUŁ]Z 8e2S6YeF ݙm P#|>My5'X~ۀSV8s Pz*7O|7'^+_y>L3S8/VOܟNdpTvrE", ߫Y^sƈ[~//Ƭ­:,  לN~E{A~~~K]n7ؠ-M\][64ҴV_ā=Nn&kdnoaa<΄X'UtIYSQv"?VJ 8e2N6LTu5lUnNYʄ5=6Š-9q5. 6e'eT?BۀSVnvۀSVnvۀS\m)dιTm)BHlem)]Eի^U#erpnrpeۀSV;<#C̣dOuQku-->vۀSV?K=>v!^'S/'֓OJnNYM*xEHۖ 8eNb 9sfp"智JnNY̹O12zۨA*}nNYG%:s?j/H~9@̽|[Oy'3*m6DۀSVftÕۀS`E /X`E /XI5G5>vm~ޙD{:g }DTX$3|rd>C+|5w;{^T{΃C)|z̭@mU_| sf.DЈ77{̺ 餚 KY&|D?˷j㙵/w{`puiMځ16?[ثȼҍʾszs~G׈}w?ZbhTZINv1tӀ2YUms*ܤUǼߏ ;J=C5ƺ$%)yi_kTܱol{mV}Am|4C˨7_;;q*Ȅ~/ےy>uE xpWjH^ g'j]3xo[Ṅ7mtN|Om 9!c~.h3XaF{Z}F?CGs ^14x1hUN>}/UYWӲsts2D:G ?Y~&j5vhus?5t;|G_֫fd`sm/<[ޟazYIREvVN;KüKpu˧gl$_u7C{!@ 4zxeulo&Kh'.gnҧ۶ 11o6MKSF4M,Jo<ZL~YZG+|P˄ c4h>z6MxP2WϘ q<sh3_`e⤼",_~",_~",_~",_~",_~",_~",_~",_?|)4IENDB`grafx2/share/grafx2/skins/font_Classic.png0000644000076400010400000000511411532235266021177 0ustar vigAdministratorPNG  IHDR@ƒYPLTEmmm:tEXtSoftwareGrafx2SjIDATxY 0 v6" vD-Aٌ/}?wx]u1ي1-ur3q^s3dY!Yg$&`M~%q_ҕ7C$F\Q0"̑ šS7g153^Z`A޶@ `t2 L~5OAhh8Ex.` *PJ3MˈU=u UGvj(gD 3Ee|'3oFyQt̙(1Po[Ate= &:mYlBʐf 2g0m uJ@I;Pͮ1MZ5שQ"=0 P$vMh]:>D?<ũDADYͺ`+9V, O=е$_:s_FPfi%B`()|𧪧{l9h%/wﯣ2jCQ;PCΪr EW[̠." uf)|Q N, **8+^Sjˬl|Ɣ-HhEn|v8[| R.(X7ޚhp/> C N}gX^\ ~W4fڰ A1݊h`aB{`P.$8R.,*P_䘑="~  az7y+҅wIt3 ӠUGd08 ^* g`iVUF}XjVk^/.WedBٶYЏ7>H $:L`p $ x ilW0u5p>ae&b=]Bj3Ta 8@ H @ ?@`-3^gϾrz-q8iƼQ) X!zhN QլU.~i$ey><^V^l p*$l (1~f-V}!lEN}KVnƻ+`l+r蒥ޕxF`fWufj?2DbS2iKl?o9. ,A M3CH:#2a 9x\z<⇙8b-H(L2$ߌJjP2+) |VGlp% x 򍠚8ɗ(˯͈N M (D%* S CޗЂ"\S2U_/UQFzq/H9A)QދשA_ {>AoGF>)j?K`υ^Y!#$ 14AQZ@`^+^DmW! ,B nX#e$#p Erv8PiK|߅, T{8\%p{I XW'>/D$$ڵ$N]60*  @pr4 p>zpDlk Aq6k21r<]NAT([ LhѡǞ4c}g`IqT¨j9%E`QbiɾMeM@Z;Q20_<枼I Y?hG-53Ӡ#yw"Hv㊱#r(@8fT0O)[(\(p@`p|2Yq) Tߍ ftx3wB߾CP*X_c~f޴a'6z5;?X1jJ"^ao)nhP , Cl$dž+n2zO"ySg~YYN_꾚2~}Γkwm(g|s:/1nֲ=Łq\XnW@-s˾ & MuhxIENDB`grafx2/share/grafx2/skins/font_Fairlight.png0000644000076400010400000000517011532236060021522 0ustar vigAdministratorPNG  IHDR@ƒYPLTEmmm#tEXtSoftwareGrafx2SjIDATxY* ӷے,\ lgת?qF=5jq a8U [sZIe#?_@YmCƳi4ƿa43%Ur4>!Vyր87Bh1rx-upLTLV )0uo S_2j J s"zˀYjԀcYc@3 U`0+Ę;=u~ȄE(h wHІ' Q:r0LQ?&sSJ85)h18<YUFT;E$}DV&OC$G!oOM ٶ[$@<"L`A f\LP )T~]C[د@ƱP׊5o~Ϊȍ܁QYę#n @%ר8\Ɂ ‚6}da^OptH>e[ű=`$# ǣWʽgC?#r/^~pŷv&?\nݤIENDB`grafx2/share/grafx2/skins/font_Melon.png0000644000076400010400000000523211532236102020657 0ustar vigAdministratorPNG  IHDR@ƒYPLTE~9tEXtSoftwareGrafx2Sj:IDATxYr0i.Ȗk:NB<9Ywqw=Wd|})MJ^Y滑Zo`L59tKh; 5|Kwz/9"ay6fN2ԑ‡C,Wws8=&^J`N^8>@Wat1 L~9HOA% g).jSd+ڏpwY])f(Q xPwo`@ς0zv R"yUM*aNb7Z\+\R'I^! $jJUjpun%;2$#6ž`>>L2"選n*E+S{v*>}>=w;-IXx~D,+TFOI)3er2j~߇GaގY&+2n&!_:FZ \CJ=/!>+؏_0yd@D\m<;_.(ͰѢ[wq{2C@f6쭦' gRy]Z݋ꑢ]n|1lpFPP(E@|k[ 4tS< 6j Gnb`bFQYrQM0#S'wjb6% Ҩ\>`- C#Tq_ucђa2g3puTX(`' -3CSC@2Wsc0A9[♖0^߿qֻlnҀI'&{ KX;]P c{QSz\2wsb+3; fԼ4dFjq[g$϶lC&`!pxd F4g& 6LѝZiNJQ97%2sT 68RYy A> Co鎔:$_>,|FETFǫ}gzP֥DpROG`(|sܷDnOk_iH5(옭VkOz٫jP͓ݏ`r`z4MRL"RG*M1@!~`)%PEc? kk $g y ;vt Zµ<`no7@ @`}m#gW]z5>vbNG7TCW$ÚZvCFQ`$,Ž׵z<{KZQ*6(ȷgg6\<8+;8]:l2a7|h@tJ P=#Rp7!H;nXq~IENDB`grafx2/share/grafx2/skins/font_DPaint.png0000644000076400010400000000513011532236024020764 0ustar vigAdministratorPNG  IHDR@ƒYPLTEmmm:tEXtSoftwareGrafx2SjIDATxYv) DӛThqoLQ*9"\ܑk]ϥp2\JQ nHw_% 9frRQxf`V_#}Vxm5G?dv5 P> )S5o9g h 5jf';̟ Hꡩ'|tI'eD{H픬*&Tky&WvnaZ FZ[3E=6}}'6>}a[n3[wVm=ƛ~[v>+oFtB?B37ɫQB>/MРZ^& |vݝ-vf4[nU ;j@̝m<8CH@9Qt A 3Dm]◼P[Z;02uJ06 bEQ)ld.d7xOTz}^wΕU݁/dY;Lm|Clq W4net&ud} Ag}+lg64vf!SHqiDPi~uΛ^{@ek웕:D=a*6}Lk~Kiʀ^+qW+!3%^>c kEP9kKM?v G/5i\rI7IuwD1G4#=J"&|5VW[u-ʦ&6Q@ⷴ&( ֬"?v~ HfԨenL aI+u{B#=Rg.Hn7 aN= dal(c@q:0 !-`:ɿտ1!rV;2rA;IHEߎx`TXO lKݠ0{9Z}8/^ u\ 0xbJk<3o?jk+S;ǎTS 9zM5tN]\jef#n2|z$if%\sXЊRW @~yw}fȃ˹X|3ġ@)V6AAGz{u`;y֗zg@< _?LsqIENDB`grafx2/share/grafx2/skins/skin_scenish.png0000644000076400010400000004554711524351604021262 0ustar vigAdministratorPNG  IHDRXDPLTENQY޳}}<\#:3#jhA&_I8B<\o1?<]}aA }m]M<, }}mm]]MM<<,, }m]M<, }}mm]]MM<<,, }m]M<, Ͼ}}mm]]MM<<,,  00AAUUeeuuyiUE4$ 00AAUUeeuuyiUE4$ 00AAUUeeuuyiUE4$<]}aA 릊}׎qςeuYiM]AQ4E(}8q,aQA a(U߂i,E$ig&LW FJ478'6ԩœzempZ_^ORLDD990++% }}(}}A}}Y}}q}}}}}}}}}}}}}}@[iu^rf?.tEXtSoftwareGrafx2SjZcrNgP_ /0?@O`opT^ IDATxgz:<5ĉ{rF&{Dı%@ƠXGI#JSW*K?bG,4C_@T# RX*K?bG,3|cn\-Ukab+l݂bY 7w|ϊ˴ϰO۾ 6k\w^:Sϝp[Ok, \q-|&_8ƥxB2b4c}Yfa Z5U{WSY* 2Z9QRi|&>rUV8X[@o 1x 4FS jAö=:B>HaN=*QՆFRrJ(E_?+/GM;Tcܬ0ZTah7rkAK}fb=畆ZƿY #||>\q`}x-ggT~;ȠiƲIk+8sCiVms#R󰭽LsҸ!jJjҌ|٧zG=h=68 xM+^ZrGȺL}(䌕_JUҩ0\XGAI}nWX|9'ŭ4!Y0 @M⎴ mWkyO5?wB=*Bt=3__HLާ1|v7E~/|I8TH)Գ4:,\\| a/[,!sGOpFg5߰+Uj3Գ44.ϱGMZU?bw;`rF+TjYOi~]0~f|/ZVG'^{ƨ$_0_k>yrִgX:|Kmց[c'M ?4Cf =t *5J0j~F Wlm҆7|2y遯s/Uc^JB(gm ~Ob^Jha^;Zuj}ٝN?cϭh%9C: nsҤjS5D=[ɤvQG]L/mXkEt7j _2֊ΠM1οWOzl0-n{N-+nC )_W&&:XgŲX{.4uF}VHp>w Kꓶ_Fݎ3}0S_v+$ lltc_ 0Xo)Ӈ]Åv+ıGa2?1mĜk `i%Q̉|bHܫ;qF Jq^ӕ|c|4( ~_~VoxfRpL\A6T>*Vxmm9 qOZayn(IoOpݥ!g?lB^`ؿ|?sک{JFgSYS#H1M<ΥD4_&P>CC˕w+</ksV ߧZqy55_|ob/ȇ[xvn?Mx|8qǟ1q.ٴ/!u9 NɣoRϯ6XO?r}ZV'U0%!s.q*\8cm_M#L}[B|#=[U=gǬ'F$z* ަ>u$رkg§ /ɠgdGVH# 5?D?ZSNjv$X SoG~6S<Xmy2\ ($\e;^HOF]V4neO=S/>Q[A72h8*\a^X {)Gˬ /rإ3KF K*K LO=?OZ++c>>tpA1ο _q"v _|‹'q>ǒsYq#SqE#渇Uu |؈xEߝ /]8ex0&W!EO?"QIĺ!l!:wכލ4Ա.h~>qFxz5%y&}s'sd /pў+n߾vm{]qg˪3iL;MöW-s| p6,=ܣWMSu"=ki/ac|uE |?,,H?=G)UX_/+o0)D’*'>}~GJejn .ۣ>d֙LKx-i9ȃ޸p\;<̴M5m)gҬ]X\tmH<\k/T xf/$|iF_3r%|E?PX+f:1ר&Ͽs]x4fӓ[?#_ ~w\>/k~TF!Q K'B ByɎ)1os;YkזGE'oP3%f}k8`OXKP_ߟsz+Es:|B(g] ~I8U€ s6|;_3y*\4)ٙdO5TgDu2mdAby@ٜg?_PYCWҴNyŊ\W&&:VR a&sS0mv9:)95ga*ͧ?/tVO>}~/L`uOvm:t+ ߜNӛ9]ש|M}A)dA%UAa/W rzP=#@/pjnc Zw>_rԔI`u¤5DS~!M§0QI x#38モpfQ^ٛ? ]!.?8.AСXi τ' ͸"1-]ddH(cmAD]9Y$'価:kKHW>t+Ibjjk^t*S.r>7_͓H5~I}R3t+POQʣʎ&sH 5|j\> >|[/\Kgsw9|50mCWBϯ1S5IH("s7 9K}=~KKcs՟4.x𝸑^;<6X>_̾S1`ubs%rw0z>j}(̜Ù_B2n>աOIc.+RÏYCI38['9}6j glXRYb`*rb/D 2292^1ݮe8FH/oًWKeōrVRO;N++|Ib#~ghӣK&'xCO@mUHQ5_%yV_VVO]oz7 ҈S" DWS\;Wq2G;HN [\>{=.:\kobjoJ'wٲoZR3|#ZC_Vߐ&ː.T#_~\F2T#a%q'|;WX*K?bG,T# RX*K'w?>,`?W=q`E0 ':*]wdHo1PD~qg1qCWǸQebW?>{JxH _>s|-|h6NU*Md9>+5['F_M/K×qN{|8ߚobmWke2|_!qqW>{?> ?M|G; |- ү}'Nނ\;o2=}~ߟk٧XU~r.jE鬩a%9|k~G'rNdbU^{{ߓ:;bG,T# RX*K?bG,U- ],+9>Uוy%nKKRlfۜ*K]M޼Ūm>+?/M|_k[_Y[O۸RZKCW=K^*26LP?煷)]*襡+gvw;|UJ?hi g)o뮌]5ɵ>6)s gYU{KCW=˧ߢ(2t߳T# RX*K.]g+4\G&UF\.gҒ3m6th.Gx1m3q[w6YៗL_k[lK/vYYYũBOM[|RK?b#T# RX*K?bi;'*I*K?bG,R?Q[$xCw[Z%/7t3~N¿ jz ;70kJ^*m`+~KGk?it@V5m"^U$-ic/ɼ6x9[ i]?ptۉ q" [$i×Z͏\@SEaHG[5S;)COo]?S~<ؘ?;X|5L5zVEV mrjvg%Y)HPHhJ ~zezw %IuUC=Y;Uӻd ߗ>ϺS_Z%I9ow +[$G,ޥ;bG,%{"{Gip6EBe{ːX<|x7t>48cte/Vխoórcyqg\.BIo3ڨ22ٲuVϰEvly࿑bcB-oG0-,*߶ - 3O5`ghny0SGi[U.Y y4͖MdO MAX3ryߺ|u }$iMO6v[ <=Z6Fket7`ib6_dKR4ľ¿E.Ԙ4_g_x a&u1-}}4m{v`˹GHtM 'n@-d6l38&9VEDBo#l8 ?`{ cTIU;p8?MOfPmxH&qx ?5& FipH+G@;۴lm)TNO cScaG&͒&e(3rd)z94{^&#–$kSo+xfmkw8zӿٔ11<;t;X" V쟁e/_8޵BIW[tjٴV ]$u2LjT# RX*K?bG,W^~ }$ipT%`4_d<|A;W^XNe\9eg\.i`+1./,-awF\$~#+MD>c,jy >?t>4&v[˞vħ9azʣ9GHcCW#I3|/ֲ`p{\&Tw.[=5&4ΛX^:#G]G+߷da5TiRQay oȖ19/mѲ- o&#K!:|-:mv陽Of]LK|f_"x'rᇰ;i ޓ('Io<}uq_sǟrO'b)z_(M`|"h2[ӲPy|8N2h»XXi+IpI{Y2=ʌ[ć+Y^vV͞}Gpq@+z ^,Yn4/h6f| 0O]V7Ⱦ¿U5gqٛG&{Ȋ7?̲oBIdK?bG,T# RX2eOwJ-|GM ્sx*Ǒ ߐsE7 |M_<' 4Rӗ*, OP}>loW[|25zKaօ/WD/>>lZrlu\Ƒ>ԣ}/HMX*K?bG,T# tڲz ௧a"=П}q^"y}#9$P*g oWqX6C/vAϦ=}?C ˠXt١ 8IN'IhQ/7;G;zó=7A}>Z`+ѫD+Y)|w} IAW[p&#G _0 ]w) 9E=_k V6wGbX'Wlszv دWo輽S=7 |s~ކvJZPPŀ `5{&#u,}ρ};t&jV=?Pi@)C7g{mHhD; " t{8|1yłrz,Z}N/U|$ qd~,v@KUbbnz gCW%p |P fCX܀<"8 {h6&H?KXȟX ;e8OHszKAo?TKbaz6'G|]@X"hg/AG} %@ ё8:f(?vf\臏|ARZ#'mv0<0t=ߥPoR(zTk=: B\[tz/b1]y_Ы~Whr`˃?!{zm΃=͂A)f'?# c@YGg/CN4yQ4ك9A{cZ.=WoAgn|sM{Gqgp:C+܈Zω~XRV[+^LNX|VU@B kn9Xກz9 ]j}7Sfl=u$'`bֻ#qBY/;AaL[?]yJ 3 ʇ0|&?rEuj nϯ1}AvnwaKO^b\0h<FH?*`GXBüS_a)_I]P02G/npA`D?bM{Vs&x/¿ ~ǂ_9ߐZ{~u AMU-NG֯<kgdG3O&f:*Oo۳O(η``旛aM}iDIt+4>v#|?ۂ>=8#ʏI:pהnuo8fF-O{Pî0<{8x, 6D5)@z!mf c:pXӈgЫ;0s_]P):|G!|pɃ 6 Q/+د``'hy|yAD6b͓5!|:z $Gail,r Ŕ|WɅO.χ@?yb98`84_A2b64 `f圞Fw a| .;`LvDl|h>t,0臧 YlCB p. /SFY]w)M0BL8~ƑwB \Ocl>¤fub20 0";(>P9o@} !xO5rǟ5ݛs p-k,O3 \ W?t=ߥ4I/4~r ׀^AwެCH ͢w鰜8jl`{]"x0B!mcc!Y#{H띰ƻ&/4Ӵ/J܂ ɇ0F>5,%ȘogtNscnZ!}cOP&"]Gf_qQ'Nn}k0û ՊEhhgЀ\ 8Xob O{.zCx~!PssE`Jy 9G} ВK}_i;y{IUCzgAp|$ʰy;Y׋Վ/Z(=$ yr6 c 7 $$a;;v+N-an~!nXq a@ҭ`؅A'~Q e%?9-=83@5=1h>!@d7!##l7_ˆ0g`yxaۑ@jM 0lRᗥxn/9=YLJ}8Esb:Ta2k\^!jm.an C1 _=@-g@ FFrVS+4 =MafNl eu` 5~_|I K8l]鸜̾rs8YG0x㎠0-1 f=Yxz ?H& ]w)̈́Û9!䣪 _, ڛ-(C=ܷd˴ؓļAwǽvqJ9lx&*_C1Czк3V nhN $MhR8cu(;ާ {B`7 0W9z+< 1t@h&6"C^N!T?yL!C] ljq /uc0ⶑɲWnc%E!FeO[ /:ro{5A>Igu:4UtI7tH=;t=ߥcYa*;TقH}S>NMpƊ B-:`;2=DbHYp0@7'~f, ݲD#nŻp$|+O7Н X4._>O_^y (O#ߪ(y`.ӳ>绔vw"Q'R~J$JaӨi"?DStlg˧À7 9D?= ޗ[ݜz:>MOssd?f*vB+8 I:j~(|BhgL]6dh1*ng eו2jC*7!4M~|gA绔 +>a"\(bW)juWt:(ᔞ 'SZ;N-I݀[U@\^J_M5N߭V~x'y6T~>Z+/_@u/6=:VM==~\ ]'uh,}|U>_k=}w8~|RgPب.ivkhdNpixҧc#|jz҈Ȓi>ag&w\gSC6yj5#6+%g#L<i>6̾4.\CW#KK]E+]Tpǝ*~>_e޾i+/Icno]Q/ RY ],?nOkK8s\fuwQt|VQҒ8t>$c/PN-o/W4@+LtqKM0~}GF枘%6k q|9 څ%3?t>'ͷQǜJ%: ZNKLH]H&wq+ I[jOf˱ɀ)m_}μSEz5I$ON -M mVDj$.䒥l}V:u |d9y6j~QZ>rso2t>4̺j7Z'PJ7j32.dI&/f' T_FՎG)i?i_68ZGh*3~?i6}꜂ wH8\c ~6()?O 4=d#^Yfb[+gL24:O ۼjd4vEwIt+7` yI%XM-rz"x;8t>4z&XKf^&O35cQIY&|R_L(O>${ YUg;~)գvsǨ>mDڎmҽؤA:_G&t{8*૳ K"l\U8_{^0:×c\ӻFUJrW}5Qqη9 }>1KMF>PO*] dGrC3z =W ],53b}YtQG&q1?Mg}}],UG,oCW#KG,p1t>8|[/KGq],jPX*- ^GۻYnu+/ qk=R5rS_Kn .}Yn# ],M֕_dMQΟ{U=gY)l \IWKϹ"+Y[z0O8盌-T_F|x'LL7nc۷9\kBj=Ҥ(s&\QSCx^JO h}pUΛ}]f "^1|g |d)ο04C_@T# RX*K?bG,ϳ}>ӆs߰Kҡ{ʳ$_JG&!yfV0ZJ߹^@`5GXjsF\ ],:I]VOd5NV"-'jn3x6hyklDt]"|jzgGL ;k5~ןyj;U5dǭ2|z1#+"l ],G08'g|5et}9qtAƊ=Ggvw|J/ݠ%G7Y~X2toq[޾RD;6H _'Y~5+%ז8渌+5V''o?}wLR\Ha (%* ;8wj a}{IXKh.>cɺ ƯȒW裞S@f $Z|?i\O_6W_gRqA2 #wTG'X8պy͗ciS22֛ ],O5 -M mV461fK>B_4ϯIʙPO!W#IGK5vl]˥F5T=ԙ_锑CF&/M50i|13>>q532oS*?({+z#XD6z{i=gBx4:uxhc{J EOSCP9L-xcguf[Dv:~4-G^FS16/h<*o&Vn}1 ۂo1ɫTvT]Fg={IDAT*oOSnbģKDˁsj\}ָr϶ k5+ ],Nsy*&psaw&CW#Khkѱ<7-E(ݧ L2$_odiq'ߛ :mOq>zpNC-Y-ڢ*8KŤ@V$C-K.8*૳ K"l\U8_{^0:×c|ӻFfT)5_մ&[F:%/tt|ҥ&?'ׅzR=h >R|5YQ:3ꓡ+&yF, 1G+%Ke |di$b i:ks |d?bY?bG,?{+@_G|ߞx]2t>4?'jPX*- ^G+ ],LG8_Lc5?bϯ߿%7zg ],~BG&ʯxIiս ],M#_6t׽~Yo߷_t+rϡ+~c|r?'MF}k*J#>&Kﱍ[sȵrN!K5i9o!| 3t>a_A/pRX*K?bG,T#N|=swI׷-|gD_1z?\^rt{r>~Q(Cwާt\|EO9_]Ν |6K#m#c }'ʹV7>>h~iWY+q/]{RdRz3}]wp)ǥc7${$Nb\jcQSEW[.)1=^}s_K}_]w`Ϣ&* `J$[.?ɟ2}]ޥ8dt6|]u%5TҶCVuhm+]>?jV-a>Ia@&q}k>W]G,4i3pOId\jF֧]ˣ}7|O03J#Εs|7̹:;j__?#w 8;1\O5z# وOkid/Ox}}/W5z62|km,;ןH[l8\~:Y_ O#g{5PmJeƥlo[uuF2ױc>r>wY} gߤMoe|I o=אggۏg\?;gaxWjB>y|Ε쟝Zw;L1Y?}ݲo>8K~4rn oɥѾ/Q+;kڥkYvBJ13i>zs_>䥟yݿ{ q}6)ʽ'93`cVSi._<9w@隱z5 x_]c֖ 2(!O^eXG,T# RX*K?bG,T# RX*K?bG,T# RX*K?bG,T# RX*@>IENDB`grafx2/share/grafx2/skins/font_Seen.png0000644000076400010400000000505611532236116020510 0ustar vigAdministratorPNG  IHDR@ƒYPLTEmmm#tEXtSoftwareGrafx2SjIDATxY9k@I_ۮ{nA,kqw=r7cx+{xFZe_kcCH^v ۿ!Gtǿŋ#achsaPd  i|gzK ,% *KdK_A}TD@F (H8*ڏwMY])`f(1 xHw^*@ς(9zw R E_rxXj5ׯB$&6]:1x-#[d&^r|2BCmcLZ&Ģ=5dT{I`$@3XڹP0 e"`Hu)uK΄lTo@K蔡L֦ty3.0 ].%f[sȝo!K+GFw&.Iڭ$x(ɪ9S:%xM,5<&AнɡJn݌$ZG[%@˝ch͑M 05C"@?JY):%o3yA9=kd30^74)Br Sjo#q+%P*X HC_KTm uT,Mm0=apϽqUll`"c5 j.Γ?I-lݪL7Z؅Hc)La@wQ<0'TD<4?5fDTzpDh5$l[.pmS5&Q7X'$:zj4JʘIsWcOu^ؙX@8c`|"KOD(M ɿU]DJ>tK֞ҿeg^w5L4G ^vcwŷT>~^O C /L\Z#4ֱm>us8Ar|FP2#P7;W;PdP;sIWWssdǏآʫŇP}_iF-##AF;ssdǫ㨹܏WWs;Ws-;;;WIIsWWsnvvʏǫǏWsWW;s<# j$ З+&:):i"H>n}BC̬ DOËq".B|7o3<5rpwʗ6lcgi \Xg!`n!}i&:)tig00&m6Re S^zc7oNn87Z#!oiê .53v&b0 %Xxd%ܞ`pKd|C ߽G?v[CJی04ppwNuyD$j -MU#},uH=p09ҪJ!C8|H]șQ[Cbc7ko#Ŝ4S*?k^%SKaê >14wnnlY5Фo7 ia/]>ãcy !tHb:hʡ,|Vx<%ϲAit JܐޣY{T >_͂{7 L9R(*Ҡo;DV;ř  .aQb8E;rS`NhCT1/ ۴e\V'{c7+{ѨRfhެ09 :gP' #||XLf 2 !3tޣYƞSpHu,ulߜ6if'Si)Bx; +t8c`M,X>6{(t+eXOojХR*ÛVWzov ϛ4>c#?b:A!\4\GU Y_~w,_4F+zZ05hN3[?H] b:BzbHkU١Y $H:#}EO;㚹SĜ@,&c5&sdYZSNs uMEjwWMNͦ(̡bU< \"^oh2Gf-pd˥4U=; oڣJ?8s%ljI7*SF1?F&8dxASvG{ԛ|JrOj f8+8HvV3`:Ŏ[8 ;TawW#}(c>JYm.L2jRli9 @8AɳNHhf'Pj /Ҍg5cf.:UpWLeA%@ ^h|mf3]3|Ie/˗ 4& .Y>KABx&ŐKkNo|*.]:˧d+*}%\1P027XFY ~`AHT8m%PzZzP÷QY>2OqPU} mn|#FQF=Ze>~CRxG> /"G]tя}c-/K,K-K/2|_ve[n΁YĢ6kx" I4S^IT9&8Q>ֶ#6`:7CiS 4̲D09l<}}=(LmG +iǧpC˗ Ȭgc F0hǤ=na/'>VXaW\iV^yO~ԧ>O3YeU>Ϯꪫꫯ}n5?kZk1cƎ7nܸO0aĉ&Mc9c=?N8O<餓N>SN9SO3gܹsvi~g3O:_ S-(v_@ǩJ:>s=;Ͽ ~_x]t__K./y饗^veկ~_7o/+ʫꫯ5\{?^wu=V,Fz~-sM U|ŧkJ\:\d!rL4NJ .)7o".u+ ZQJҔ^D̓RR+AE5mHڗf,]RE!ϛ7믿?x7tӟ/7|-r뭷vm~wqwu]w}=sv}<>C=|G}oպE5|Pe;!%W$-3ap[I"5t]._!_vmu{mԒ2f|兩ЎH3Z2H %z <@ƀtWhWjJˏ) _R̈1rErZ `y_2w ˂oB%ΦN3j}L3 8 ᳒/{Sރ}%KfTP;fO9"Jx'`{=O>SO=O?3>s=Ͽ /K//+k~7|ͷz?o;{w6`P.m9<˧ +/o+Q%-dgD skKv?"W ?TAaeG߯훗IY\` Lx7 A^@{R=zu7PcOM 9{WaP:-9|(;\o Ùt{Q'[r6Sއ+ <&Z!eA }I\Sh§U:3e&"kq!QKG§Vqπsg|iZ+ SZ>\M[172\?K /L^=i5Gv(,t0U?_|_ks` Zy1_vg K{ޯ!A:trEY4J|e xLjGP` m k_K>_?n=y䑏GtGͻY6ԧXO>nj`K/?/߿ڃv"-W6߫gZ5WO?> Q}β_j4[,_R? t+H_ 3?,,8PU%ICX4|8@3X>/ zi:VOi_n9+Dwji6z7|VAM~TJYPϠnge`2YEh666ܩ@!Ez\^__?Ls9*W^Wrwuף/c)K(￿ OSZ=|iZ6˴#dެ XX]2jxS߾wJYe2L8_^ze++k"rm.Nk5e]V0%J5? JlA}nT 7j_/ $ R[M{ `Ȍ:^,+n_zGSc~dD6nsL\J>Դo看gi.W&zOG:YO)K`g8_ /Wi]~gŲl/nӜj ߟAI6^l"gX ѵLHȗʀ'Ȭݗa̕p ~"n,phJ4LD6e)7?K ݄t౯ U |0S'xK!|PCq fRzeӨܬx7~/&sP.xxA* y2c3U{peq?k1W_]⭷<6%̓g!7wñ̂$Iy.gWZi n'^?< {ٗ<_a_F-btjvW?+/q\U'g^FBU=C |{itgOZ>SnO2sQ=U^pi]~*8W wzMgY ~zrf:XQ;Vz5<˷5HV5T7` ÿӟY{uĹ{_tHl\᧶ٵ9Vv&mf|Oy|shW9WʈMȠŬ_gS3"k!Z洌&𚪇W U W?|i*?zJO}j?p $:wZMQd^j}LUO~RDrZ y//K  z~P@S O]} 0_j*S*(󖤔({{𦍳y]m4o 7ܠJ+O)o*|]9mo14ë9\]&iP#3/n7^x{X/~  ֢.ZKVult͇a璀d20kYJemk'AKXY+;-*/y |K ԥj [MUҨ<H{.7g|}|NmRGZÛ_{ j~n|e /2Y>:_晧_xw50UMS*9xbGM g!7=K ?y3ϼ KWT'hVkS/֥l^i#a^t5-Ti#Y~K.o W1^ziFUlܽ/ *i,:g룴{$;Q{-BZF\e׀UV>R'<5pOR>[Wn??CjEǫyk[% w*ylVKdU'Jfk o;~]ρ3uTs%&h_-% j ?W/5J[a5݇`5?nUWM{H I jjk%|# oRo`o;l/S 7|r\*Nן2ee9 0/Yo:/U; QR)punj~!]҃91z ~67p.G7؀+^{g͋6!F^iJ&otKߟV cl6O0>4p.V /H~4~|>?Sݿrͅ3ooIX6N4+0^q/%/-V21Qws*~lW?|# 1p1V9?0JƼ5p.WM<<9AY$w'7^O5Ætzr@ȭ[}@}k$ 'q$9{\b6Na4p.W-jXtGnQS=Dr jc˕$sdoZص/\HZpЯe?$?zv2$Y7I.N_7lipЛP'}R{ Mװ}nzpS7Oq_9хֳ[~aZM+c۟[ =~_߂WYkhV<,Ö/77K$4u%—3="xe7e!`$(:/\L;3&/ޡavK6,lxeovK7j߼X"[% ie7mؙ;0Z,tOс埗J7nVK.i%i^N"4(uK@ *$|>s,f'. |e O*w~V7vK]Ofm{S3C5:r ߯C`ŭV IDAT>-ۜvH%񵀭H7KQ *`u ?E.SOqlͻM|fX@M*`m6Z#^JoE,?I^_ze!py'H{Z =0UruWZC= |x |Sj/bV<tk州eJ9s ߵqc\~m>ߺvp7R y [_2y ep?lZ\yٷv_%h2ֳ[/ɉ:nxe \nֽW!cl?lt[?e>v %kuKʙ3gw$eeNJ?<1]q{%N}|S5|sÖϦrY6`;S32֏i6-ֳ[I2uj_iGԾ~B`rR?I:ۚM‡>=zatS|cm j H$kٕF46scgڗJ=~'Oˀ>v̕)~ۥkR9o[ [Sr`ؼSwa =.8 T$ ϾՆPkwMX~fh߾)",ȾO6mڅ2*bFuQ!B >Q'PfzD^EQ:;aS w*طeX j=j%?-] ھxoJmhV[{]$Yvi/||Yf9O>QZǸL:֑*|$c(g$:>XNh4e˷Rgcb?uG(G&Ƚch )V 5~`zxq62"cugπ4p.-=sϏ:9ITR%39Ciy<-It*3l[$937lO=3+$kQ?[xePN%S#q}Iү66!\}mY?Л)@WrmEoSRs t沎їH++g RArP|ǂ1<|юڴ`^ɏ=:>s^Kp wݱOcf𕾄hvz'د4 s>GM'p { hͼ1#g^}$ϳ{7e{ ոP0u-@%?+@.ۇ͇-;/9|J> ym(>|okXp{x56u8C-g9b8}@g~pA#-ࢌ><fyU+,g`/]Kz^xݍ~ПJro '_C]lULnEr=c 9FoYVdlz뭷' !џ^jzT<>djh |_D59tLrw?a4Ǖ ^c'N\Z 6lc:IL+l|s~--l{3Wca4Wc7pM7䦛~Mivm7'2B}}}f`>絰ks~?@ն7N5~c˕$6UEN0:̮Ww$a;7T [m}uW6m.Z?0:`;m2U`^vG")DÏO[~8w#s^K/N쿲a|Kc-][sn 6n]6zJg~uGpUX(n?%ł7o1̈́|SY*O1]m_"K$摻KjE_/~oSxR"Nw{f)C3w,B zM.]wLc=I~Lxa6{Þ֯VlcWs5 K*ER!=<ώ=; w;{p5,?̦,1槱0qf~> } oC:nۃqxpEB;F `Yh o, %\чCaW>2 (<{ oZdEr=c 9FoBYw>)0չkj ,됦0]8zNc!XLsXc o|; s?/i3pF>vVO(J$dW]6hV[{]j>[\3tv'h40^?|Gh64|iE5p.}V3lvFm~mfް^+hd =JpQKݫӼˋ"4ǾCc#ƫ]耣2~굊‡ 6ސQn?O>̒^_yYxl]މ<B^:@%#{+*잔-v1)DwLl!|yEc7GY438VO]vُ\?LN? 读2XX ߓ>|aݓIhCY5ߤK3nKiiamgS}>=sgǷ+Xib)l\o|6*8?}o,m\ n&MZQL>ik|FyN޿`Yr}`<пرc 5i7t?eJ~4y6cIO>iӐ+@5<߆niP5¸8.1Ox~6!Yim 7"O8_) rAJPSO9gk޹w>FaN jcC;y|?qlA_q\0套"˒@ jc˕$#@Q$KB,M;/f#(__oV[{]( /*oUBui&h_2{7g>}x_[9IV*J,߽1$y'8x|5_"G7V?)&/}IӿK/'@?WW诼+R EJx|W|"3o?zȿ,k_sl(lw2o{J7}dMKT|G?ff~!J|^qGYwIKεouw G3yGea~̷OkxսTϪ7h߄J0= CZIMzrNx85{𯾺 }o}[5?-|ZF˼%oCQSpu6?x׳-?^eޗɞؒJ2kf[_EZzP`O^FAy_憾)YOo%Vg>=` vmͫ6VYec,?ee $˾|]*Ks~Q[I?T#|xpjk}飣f?7_d^U [\3^GQR(;Jin/ ^G61ZCUyF޲jamqx78/S!у{"p;7?ҵ&IJncY$iZfçܱKϛ\w]73s4_7ԋ3x4Wi_FІ2~5Iƅ?9/[f?CIMÇ6W!BD|񶡶?4dM=ЬYG~c{M7b~ Kίr4Z`_C-orXA&lUo_Gmp'|/L$a+s y~HѱZhP5=rJ*m|Z~Qvmow{I$&?`j;{'eg6 |-bn|)Dr^q;+Va~a;pgϞpk w_xaM }d.G?J[_/l c\6N?y3gkc>~,?K$-(7'Cc {fצbnfnWo9@K;`3GQEOpo诶kJy-ס9Z||KwT~KB0\'k)vm1q~Uzm̖n;5SoMsm!hSIjxd4{'_SF;ɮQ4OY$k$y3էB&wwEk:_c5k饾 L_Z~PH[m}uBN+ޖ>|ݕz5C?l<u7N"jV[{]b5[>!z4װv?m;|p~͕ѳ۷wEoZPqKG G8 j回|k8-O;Y6MUy$~U?AA<8C k|;+S=>ۗB@ Y8Y,l_DwX/c/h[o |O}_\Loﻯb[@E: J[8[2yOk=2,@¬t@BbKN#ZIjR0i !Ko)]c=Y?>2-<5!1R}CF:~{8.2%2<_Z j9뱸7C3lσ0:׿4'psS13τ{3׳k-|o| S\SGc3҉=y5<*vlX*{X;UßxsO&SOY>}[ou`M%7}f2!O3^ ..:osᇓ?a?c4?CI>[9F):n"!f0gXSv }^a- V4+f2*zM=7א4w[Z7Ӈ9ҲgלIb^/ML`P*5-hz7_{5W_'Ij1[el?| 0a҂3}lھ* `:\|٬|'ƽxqO/P?sF ]=ߦc/s/sF ~?+j i~e~>ikӏط/9-hlOfX>@+$G'ɒ/,ە^:O7r?gB Gyd@~rG/1/,Rɱ/*J/{~ Ԫl?goj7couqDզ#kASz뭷:ۋ?>thV[{]jg'0~mzf2=6||`LJ^˼+M6MX\ om;d'O A6p.W0vO{f2'Bk{ކiM'G~b5|sΜ}/SI'g[m}u}􇞅λUo®wJ9GůwUQ jcUsțSq!W}ꪚG7pm\ [S-?aN{?"IttmGS@A/SA4859v/R .gaE>cY/ГaDZR 0e HoƢZT]E*+Z^J+';w޶b}GA6C.u|C˒ZI?qHOD !7`&@B23J ъS+<NX40aE"{LT<<8IT7lz)]J0M+䳷Iʬ!lb>>e');\kS*$dR_$MJ>|jCI/Y$ oJ#{$~Kߣ;MTJPW1?dO|ZOٸugrrgYCÊt>j-F6 #ySobG}gbV2Cf:k>M_ݦni},BiH΋‡_SKs[\_A|j)6$mSҐN-|h'_S]d,Z~.'pl|c[c m,zԖL]j >v;_h9|qV<; Z)=KuR6[4z_ Nh{>e:ßA./mڥnҾQ[|-ߥj>{jmz$׶舝Ƙz>jCxYf{ n)0){Hc7!pݤr2Gk5pp갾SO68?g nm%y IDAT:;?s̙C.!V ꛮMU 0܆pL:'kai~R:Ga"qm8G߰s,@(bvөFc؀yШJ LU6>(t=gܩ``j>{ƀ $ Es30/6~+5ɼ*vu65nt}OSn–E3.i}3 pNc2G C߰>e}s)]Syg3PGP uRതOUɮ+|GuSg (۟1M3UWفrdt"aqiѻȆVӽeJk?z%%Ng3<zD?4ھ+/մZFmP?+L ꅑ̆I J+sAGG}SI5G_mB -|8/ |c|X.uW;@^:$Yi̩٪Lke_>|je @#̙:]L< ~MހOm >QǞ AlࡑeqM,pC['e :f սt]xЗٹn=xs ݰÎ=u@@ ~TlCb͆k1$ڀlaa%|.ӑ'L^}Mj/o*@7 ݹ}RǞ?]y6>lCJx3ΨJSRV#OUT7Яh.<ۗ~}pF\f}Π럦.؈zUvNБׯk}چ.<3~fϙ0xڹdԱ7 T9Y ~PJi TLœU=Ԡ~Z|ds_Kԧ@ ɩ&j+*tC3Bn\w'TCu{ g /NA8AO33ߦ\k>u}w}oڜj0ӛ{L &o3J /y*^}w蛃}w U~ fph:|f)Exu Λ }w*+70.M$M)KTԙQˢƻ@MCD( ?01(}cQoaxP] 2U5c[y*}w, ^f9 9DSJ8c?]G W5o@xVc7ؿ.c~}kn%)+5ka5|7c;~)ɧ\=Eia5;źxB~6@ ;z4j |1aВkwq=H,_=ޏ=%/gWg/~o: |~ c:/ǔ UAUz=ϳK1% EV 7OױŻ?d} ?"(p1]F2+B4.ʮF} t(갽'=*>]K|=pxӯFR#hQٯZ>Uٿ~ /!|"E~Lb?*{?U|/Zqa_)!kbzbo3y$-:b>CH7ZPyfoo<\70pŚ=ؗcJƊU<;XcS'9tl 9R<4U?vXt2;%I5Wk*w9yjxׇև/ǔjS-uNM ;KwY}NYe? ٗcbo+6l؞>WYyfH>fzރ/`_Ie5J 4{OkbX>fG!5B~D57+e}9/ {I/F/-?Zb}_?s࿓fI'~1~L5Ggof7ϵ{ٟlkO" K1%Rz(ʝ6E}:d#TN;m-@#銠j6hqpg_(8~c͒|~|ws쏊÷Cٗc_;|ww>c/G>|H9b!KQs~ >cÿӇa?G7ZL;rpIS2J?ZFQ+/x[Z 7(1{b18;}>1O:<#N^h)'M^hʔ&m0ye;?&U?G?ϳg {cϱ?ዑ2{߲K;vZ(L1^IW>||=?kc4w=|U~?euLb,Kˏ ,bo௳6_ |o]]@ #{ ϝ! ^>c;xf < G묳O^#2PhqG4ag<_ ԖJ;̭A`֦ ={!qbMlF=r?BHIy;!A u(U2cLm?i]Z~LW aeU5¿ |do4vxe?WMSOId ?&/ ߱U;hU#&3iIJ̏, _X>c_;ϳg|~p3=Ggcu_ÿ& W*7uӊ "!OJ4z{IN8bt ?"^i[[v1ne~ ?&yUvQy=¿[WJӟ#M7rt ?&^'Uvb!TWpf?n'90aJƈKm ikM͕4h= owΞYJ.Hv 4;H?I@M^$C1{t}p%ޮعs ¿[N1nOQ o”M1Qe>cƈY"?+?²#fcA5qN^)/ _^=q8#ƍ7?aI; em?>cÿ(y- 3 eIe_dme+}Uÿ(9R,?S'V6Q@ݐ=#ux=.8_N7UB?l?&Ǟ8%R 3( 1G^ރ(?҄e߸~*~DϞ8%79yy߰oQH#GM7og_p4WBQ[Oo =?/?{g ,=>3,4/ǔ] %jSԗQ %J@GؖuL<o.F; Hc3፦?':G+h=D8mTk4K B'!‡OCw~~6<cbٗcJ_(|}ß)|h‡_>P>cV%]FQ|އwcÿCcr߮}>g,o_O;_~q1{~Qc-ۿHZÿ\lb"&Z^f>,˿;>EښcN!cYEU|͞9|Ú9Mx~%^x}ilScZ%jo3{X;{{¯Ȟ?ϖ{e}3f=GcR/د%6>og@ o!+- aeאC%Fj:`_8s+E/ _;ꗵb%a\/%ʗ*z~{X%V Ua{X%V L9 &G(+A !{p&;ӆw qG0joΤ,_oV5X~S5Ch) KM!sjɃ[G.Rs|^ޣ/siw\v:L ؗVW~_oV[s7h22fjun_\]U֪s|ne;HԹe~runVWe;2l=~*J=~*\"MSYQfp@Z|k/ʓSe' vG`7+qRCBn* ;6a\BL/t? - r$O?/'^f̜B!iΧ4$p)EYͪijwvͦ]U]P~\$y@ ,p/z)7SWF8 S3g ݶ=l$& %`hkb:N{)t Yw]BHdDIO"YU$O3e|ʄN?|0zL H2;Zw%)qgaBzY ~q!H>|IĶ]%(i d2Oy\T$rzW%.'_ 9uqSF#AnV»¾<&p~ſOݬѸ*3O'36c/VzH0W<'2erپm[RH pduŤ2Ww|CsGֽ?~#،5lKg{sl H_Ξ 2M9ΧХ-M0~=-7%9[Vk3s#8s9fwu4?T-?--~x~̇S}\vB?e?TG|ޡԺ[?o{K Vݬe54jwvtQnVbqKg};Y(ݬ*n֐'^n4x*;YзŐf_f{X%V=#k_nVeG;YLD%&TG;֨V]e~Y[TWS,vG`7Ma(f%^Q^Kk/6NUUJ#xܦ-Ϳ6f^vG`7dQv]==k_@erM"~JoK[9_r-ާ񽲝%n\*.k.!4T _r+Z%xQg.rV (PIQGС>nV]lP (>{X%V Ua{X%V Erm훣22bF"$$vG`7Lo``, Y7~8y̟Y>\vG`7+Z22]b]xe>"I2xiRSRݏhk2s9 qvG`7(6vG`79sx2,kX^>gf?72Ww۩=˓kBl5| cw]g]JPҖ1s%Ttֿ!$h7O#g֘Y;~M1K 6Ж/,?檞h7|gXƺ| R+ʼg,sxl>rowv">In.ۯlt3w 2y e2Qjwv -zL=LCܠ) eDY=cN=}+4+|2iVzڄk^UAmfޮ 97m ܅`\|A6ha,CFk_ 7j d/7 0Ad•vpGxu~IznoJ3L$mMo`?e D'XNo)+|P#,puН3—B;e8ڧrzWf#!ly;Y]ԃbvG`7+ea_Oۯף:K6Sɜ:-~x~̇S228z 2HU[S"EΥ>ݬ{XUOnVYa{XCKvG`7k3[vG`7k~Y~Nlݬd(P;Oe5~V UW#U|Y}Nf3ٗP|?_[{XueoR]Mݬz7bP#xEy-̽3ǮHPWU+nV(g=$-ڤU[x>,G 0u&fI6RdxӲȥ߬gD2x>/iIYUz df(q (72pYmh@ ~Un[/`J֫>b J\ H Df9p5ޙ8B ?5]g˔YgޟQo MfL9g*e-)ϋoe~|v&&˼U5sMMFCw\86] ;G)`[)K-$/{_`woM˲|\/ҲjV}vG=Md9}s %zՑA|g-D: ~'7SW++:wn"M% +d1Jui^: ~'d-)F,S{:X ~4/5Uauؘv~<e3\Qk~Q#*Na@ ?C6dia+^C-LhzbG/݋g5 Ϣm(JTDBR+ҖqX6r +^g+)ֲh{gl;(Ӥjys]Wi*jDlf;4f*W!lYppm}i݈ײvh#Y±5%[mӷvoYh?-ȏ)/qԢka3^˯m(gpkW-µZ}*^mg|yU¯vm~&k+j}Mkג(*kJhծAB&]5M uK;Yu2ݦEHKi.m2ZZ? ݛ*#ZVT1lmGÃql`{M~dpLF̅_Ow(ru6Hi+bG%V[KW%V Ua{X%V Ua{X%V Ua{X%V Ua{X%V Ua{X%V Ua{X%V Ua{X%V Ua?\ {IENDB`grafx2/src/gfx2.ico0000644000076400010400000006117611343525634014604 0ustar vigAdministrator 00h ( 00 h^"00 %'  nM h^(0`fUUUUUUUPf̏UUUUUUPl̏PUUUU\UUPlU\UU\UPPU\UP̏ \\PPUŏ\P̌ \U_UUUPUUPlX\PlUPlXUP\P̈\Pl\UP̏UUl̏\PlU\Pl̏̏̏P̏lP̏̏lPfPlflfPfflllflf̌PfffflόPflffl̏fl̏̌lfflffffoffffl̆ȏolflfl|lllflf|ffffff`ffflfff|`fflff`̏`ffoolffff????( @UUUUUUUUP\\PPxu\\\\P\PP|\\|\PP P|||P̌Pl||l|wx|`xl|`x||`L||lǏ@F||f@Flll|w f@lllwww|@fƆ@fllll`lwww|@hff@ffll`l@nhff@f`f@????(  UUP|\UP\\PUP PlPflfffflo(0`   8++5888rRTTT3n9K'S+\4a2g8m9v=z?\|@wNʄRn|**   * $**$ * $******$ * $*****$ ***$** ***$**$** *******$** $*********$**$**$************$*** $*$*$**$*$*$$*** ****$$*$$*$$*** $*$**$****$*** **$********* **$***$$**$****** **$*************** ** **$$*$$*******$* **$*$**$$*********$****$$***$***$*$*********$**** *$**$$**$**$* ***$**$*** $****$**$** **$***$** ********$ $*******$  ******$**$  $**$**$   ****$* &   **$$*** &   **$$**$&    $*$*$*   **$$***   **$$*$**     **$**$****   **$********$* **    %**$$$****$$* **      '!***********     )!**$*****     )!$*$***    )!*$* **  )"$** ***  ("$** ****** ** * &** ****** ***** **&*** *  ***************&**************????( @ +999eeIrRb3n9\|@                      ????( \|@(0` %  |@`2|@8rR\\\\\\\\\\\\\\|@|@||8rR\\\\\\\\\\\\\\|@||\8rR\\\\\\\\\\\\\|@||\8rR\\\\\\\\\\\\\|\8rR\\\\\\\||\88\\\\|\858\\\\|\\\\||\\\\\|\\\\\\\\|\\\\\\|@||||||\|\\\|@|||||\\|\\|@|||\|\\\\|@|\\\\|@||||\\\ |@|\\\\rR+|@|||||\\\rRz?|@||||\\rRw>||||\\\rRn;||\rRg8|rR8g8|||||\8S+||\85|@|||\5+n9||\8+n9|\8+n9||\8888n9|@||\8888n9|@|||\8888n9|@|@|@|@|\8888|@|@|@|@|@|@|@||\8888|@|@|@|@|@|@|@|@|@|||\TTT|@|@|@|@|@|@|@|@|@|||\888|@|@|@|@|@|@|@|@|@|||@|@|@|@|@|@||||@|@|@|@|@|@|@|@|@|||@|@|@|@|@|@|@|@|@|@|@|||@|@|@|@|@|@|@|@|@|@|@|@|@\4||||||@|@|@|@|@|@|@|@|@5wN|@|@|@|@|@|@+5wN||@|@|@|@|@|@|@|@n9+wN|||@|@|@|@|@|@|@|@|@|@|@|@n9+wN||@|@|@|@|@|@|@|@|@|@|@|@|@n9888ʄR3|v=|@|@|@|@|@|@|@|@|@|@|@n9888ʄRK'|3|@|@|@|@|@|@|@|@888c3|@l8|@|@|@|@|@888`2|@|@|@|@|@|@888 888 ????( @ 5\\\\\\\rR55eI\\\\\\\\\\eI55eI\\\\\\eI55eI\\\\\eI55eI\\eI5eI\\\eI\\\\|@5|@b35|@b355|@b355|@b355b355n955+55ee55e|@e55e|@e55e|@|@e55e|@|@|@|@e5|@|@|@e|@|@|@|@|@|@|@|@|@|@|@|@|@|@|@|@b3|@|@|@|@|@|@|@|@b355|@|@|@|@|@|@|@|@b355|@|@|@|@|@|@|@b355|@|@|@|@|@b355|@|@555(  @\\\\\\\\\\\\\\\\\\\|@\|@\|@|@|@|@|@|@|@|@|@|@|@|@|@|@|@grafx2/share/grafx2/gfx2.gif0000644000076400010400000000220211400503416016250 0ustar vigAdministratorGIF89a b~1 !, HA*\pÃ8`` Ѣ%(@%^4P `I'SdȘiּiʠ.G\ SLCْI0yԠ^icǯO][K^j6U9Zo[G[-Q%G\-Vy Pc%S^{sd7zof3|hHl7nD vjm],߲RioٹԮ6n/a d<@Ng_ns@N>ߧ>]ЉiWwx]ng`D`w6m *h`jfS(bJ8"h 9P*~bA;grafx2/share/icons/grafx2.svg0000644000076400010400000005426111350224564016573 0ustar vigAdministrator image/svg+xml grafx2/doc/README.txt0000644000076400010400000001203611547422130014676 0ustar vigAdministrator __/_/_/ __/_/ _/ _/ __/_/ _/ _/ __/_/ __/_/_/ _/ _/ _/ _/ _/ _/ _/_/ _/_/ _/ _/ _/_/_/_/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/_/_/ _/ _/_/_/ _/ _/ _/ _/_/_/_/ GrafX2 - The Ultimate 256-color bitmap paint program Copyright (C)1996-2001 Sunset Design (G.Dorme & K.Maritaud) Copyright (C)2007-2010 the Grafx2 Project Team (A.Destugues & Y.Rizoud) ------------------------------------- === ABOUT === GrafX2 is a drawing program dedicated to pixelart and low-color graphics. This program is dedicated to everybody who knows what a single pixel is. Its layout is not very different from the famous Deluxe Paint or Brilliance, so it will be quite easy to handle it if you know at least one of these programs. If you aren't used to the art of drawing with up to 256 colors, it will be a little more difficult for you, but you should give it a try (or more, because most of the power of this program won't show up on the first try). Then, you might eventually like to draw the oldskool way ! Grafx2 was originally written for the MS-DOS operating system. The authors then released the sourcecode and we've modified it to run on your favorite platform (if we missed it, please tell us !). Check the homepage at http://code.google.com/p/grafx2 for latest news and bugfixed versions. === HELP === Remember that right-clicking and left-clicking often have different functions, even on menu buttons. If you are in trouble when using the program, press to get contextual help. You can also check the wiki at http://code.google.com/p/grafx2/wiki for some more information. If you've hidden the menu and you're stuck, press to show it again. === LICENSE === 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. See doc/gpl-v2.txt for details. GrafX2 uses the following libraries that are distributed according to their own licenses: - SDL: see doc/README-SDL.txt - SDL_image: see doc/README-SDL_image.txt - SDL_ttf: see doc/README-SDL_ttf.txt - zlib: (on Windows) see doc/README-zlib1.txt - Lua: see doc/README-lua.txt The font Tuffy.ttf included as a sample in the fonts directory is public domain. The source code of Grafx2 should always be distributed along with the executable; You can normally find it in a packed archive whose name begins by "src". The source code is also available on the web site, either by accessing the Subversion repository: http://grafx2.googlecode.com/svn/trunk/ or you can find the latest versions as packed archives: http://code.google.com/p/grafx2/wiki/Downloads === COMPILING === See the file COMPILING.txt for compiling instructions. There's also a page on the wiki: http://code.google.com/p/grafx2/wiki/Compiling === AUTHORS AND SUPPORT === To watch the full credits list, in the program, click '?' then 'Credits'. Please report bugs and request features on the bugtracker: http://code.google.com/p/grafx2/issues/list E-mail: grafx2@googlegroups.com It's a public mailing-list, so be aware that your message will be visible at: http://groups.google.com/group/grafx2 Sends greetings and glops to pouet.net : http://pouet.net/prod.php?which=51865 === HISTORY === Short revision history : * 04/2011 2.3 Further improvements * 03/2010 2.2 Layers, Lua scripting * 09/2009 2.1 GUI improvements and some new features. * 06/2009 2.0 Completed the features planned by Sunset Design. * 04/2009 2.0b99.0% Many new features and critical fixes. * 01/2009 2.0b98.0% Now running Linux, Windows, Mac OS X, BeOS, Haiku, AmigaOS 3.x and 4, MorphOS, SkyOS and gp2x. * 10/2008 2.0b97.0% Our first public beta release. * 07/2008 Our first public alpha release, Windows and Linux only * 04/2007 Start of this project and port to SDL. * 2001 Sunset Design releases the source under the GNU GPL. * 12/1999 2.0b96.5% Last release from Sunset Design. * 11/1996 2.0b90% First public release, at the Wired'96. * 09/1995 Project starts. Check http://code.google.com/p/grafx2/source/list for (very) detailed changelog. Check http://code.google.com/p/grafx2/wiki/History for an overview of the new features and bugfixes in each numbered version. === FINAL WORDS === We enjoy programming GrafX2, we hope you will enjoy drawing with it. If you like the program, here is a list of things you can do: * Register as an user at www.ohloh.net/p/grafx2 to improve our Karma * Port GrafX2 to your favourite platform * Report bugs or ask for features you miss (you'll get credited in the helpscreen !) * Make all your friends use GrafX2 * Send us your nice drawings, we'll put them in our online gallery Enjoy Pixelling with GrafX2, PulkoMandy & Yves, the great GrafX2 Project Team.- grafx2/doc/COMPILING.txt0000644000076400010400000001423711436573006015275 0ustar vigAdministratorGrafx2 compilation and installation =================================== === Requirements === * gcc C compiler (other compilers may work, but are not officially supported) * GNU make (other similar "make" tools may work, but are not supported) * SDL library v1.2 * SDL_image library * libpng (not on MacOSX) * FreeType library (optional, for truetype fonts) * SDL_ttf library (optional, for truetype fonts) * Lua library v5.1 (optional, for Lua scripting) Extra requirements for Windows: * a POSIX environment: MSYS is fine, maybe Cygwin would work as well. * use Mingw C compiler instead of gcc Extra requirements for UNIX/X11 (Linux, FreeBSD, ...): * pkg-config (optional, for Lua scripting) * X11 headers (optional, for truetype fonts) On Debian-based distributions you should be able to get all these files by simply running the following command from a terminal : sudo aptitude install gcc make libsdl1.2-dev libsdl-image1.2-dev libsdl-ttf2.0-dev libfreetype6-dev liblua5.1-0-dev lua5.1 === Instructions === Open a shell/Terminal, enter the directory where you have the project tree, and type: cd src make If all goes well, it should build grafx2 (the main program) in the "bin" directory. Voil. If you don't have FreeType and SDL_ttf, type make NOTTF=1 instead. It will build a version without TrueType support : the Text tool will be limited to bitmap fonts, proportional fonts with .ttf extension won't be available. If you don't have lua available, type `make NOLUA=1`. You will not be able to use lua scripts to generate and alter brush and pictures. These options can be combined, for example for a build without ttf nor lua type make NOTTF=1 NOLUA=1 === Build variants === The default compilation is optimized ( -O ), with debugging symbols for GDB. Compile with OPTIM=0 to disable optimizations, if you have some real debugging to do. Compile with OPTIM=3 to use maximum optimizations. Type "make release" if you don't want the debugging symbols. Compile with USE_JOYSTICK=1 to enable joystick input : Only useful for developers, to check the input code for platforms that don't have a mouse. Compile with NOLAYERS=1 to make a version of Grafx2 that can't display several layers at a time: You will still be able to edit layered images, but you will only see one layer at a time. This option is designed for slow platforms, as it makes the program faster. === Other compilation targets === make clean Erases all generated files (intermediate objects, and executable) make depend Re-compute the dependencies (makefile.dep). Other compilation targets (make version, make ziprelease) require Subversion and are only useful to contributors to the svn repository of Grafx2. === System specifics === == Unix/Linux == sudo make install This copies the executable and data files in your system, in the /usr/local/bin and /usr/local/share directories. You then no longer need the compilation directory. sudo make uninstall Removes the copied files from your system, keeps your configuration. For both options, you can specify prefix=something to choose the target directory root: For example prefix=/usr or prefix=./test-install == gp2x == The gp2x build is very similar to the Linux one. TTF is always disabled because there is no X11 support on the gp2x. To compile a gp2x executable, type make GP2XCROSS=1 This will only work on an UNIXsystem (Linux or FreeBSD). == Windows == It is also possible to compile from linux, with this command : make WIN32CROSS=1 You will need the mingw cross-compiler, and all the librairies listed above. Here is a list of the resources used to build the Windows version: 4DOS with an alias make=mingw32-make MSYS installed in C:\MSYS Mingw installed in C:\MSYS\mingw SDL: SDL-devel-1.2.13-mingw32.tar.gz Uncompress in temporary directory make make install (no effect?) Headers are in /usr/mingw/include/SDL, copy them to /usr/include/SDL Zlib: http://gnuwin32.sourceforge.net/downlinks/zlib.php zlib-1.2.3.exe Install in c:\msys\mingw Libpng Requires: Zlib http://www.mirrorservice.org/sites/download.sourceforge.net/pub/sourceforge/l/li/libpng/ libpng-1.4.2.tar.gz (Before June 2010, we were using libpng-1.0.23.tar.gz) Uncompress in temporary directory ./configure make make install (long) Files created in /usr/local/include and /usr/local/lib .... libjpeg (optional - improves SDL_image with JPEG reading) http://www.mirrorservice.org/sites/download.sourceforge.net/pub/sourceforge/l/project/li/libjpeg/libjpeg/ jpegsr6.zip Uncompress in temporary directory ./configure --enable-shared make (make install doesn't work. Copy jpeglib.h, jmorecfg.h, jconfig.h in include, and libjpeg.a in lib) libtiff (optional - improves SDL_image with TIFF reading) ftp://ftp.sgi.com/graphics/tiff/ tiff-v3.4-tar.gz Uncompress in temporary directory ./configure i686-pc-mingw32 make Don't use 'make install', copy tiff.h libtiff.a manually instead. SDL_image: Requires: Libpng Requires optionally: libtiff Requires optionally: libjpeg http://www.mirrorservice.org/sites/download.sourceforge.net/pub/sourceforge/l/li/libsdl/ SDL_image-1.2.8.zip Uncompress in temporary directory ./configure Check in the messages that png worked Optionally check if jpeg worked too Optionally check if tiff worked too make make install prefix=/usr/mingw FreeType: http://www.mirrorservice.org/sites/download.sourceforge.net/pub/sourceforge/m/mi/mingw-cross/ mingw-freetype-2.3.7-2 Uncompress in c:/mwsys/mingw SDL_ttf: No mingw package http://www.mirrorservice.org/sites/download.sourceforge.net/pub/sourceforge/l/li/libsdl/ SDL_ttf-2.0.9-win32.zip for DLLs: libfreetype-6.dll, SDL_ttf.dll, zlib1.dll SDL_ttf-2.0.9.tar.gz Lua: (optional) http://www.lua.org/ftp/lua-5.1.4.tar.gz Uncompress in temporary directory Use sh shell make mingw (make install doesn't work, even with prefix) Copy luaconf.h, lualib.h, lua.h, lauxlib.h to c:\msys\mingw\include Copy liblua.a to c:\msys\mingw\lib Copy lua51.dll to c:\msys\mingw\bin grafx2/doc/gpl-2.0.txt0000644000076400010400000004362611436573010015032 0ustar vigAdministrator GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program 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; either version 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. grafx2/doc/PF_fonts.txt0000644000076400010400000000062111436573010015455 0ustar vigAdministratorFonts by Yusuke Kamiyamane http://p.yusukekamiyamane.com/fonts/ License: "The fonts can be used free for any personal or commercial projects." - Arma Five - Ronda Seven - Easta Seven - Westa Seven - Tempesta Seven - Tempesta Five Converted to Sfont format by yrizoud Changed filenames for better sorting: for Compressed _ for Condensed __ for Normal ___ for Extended grafx2/misc/unix/grafx2.10000644000076400010400000000470711551631130015627 0ustar vigAdministrator.TH GRAFX2 1 "April 14, 2011" .SH NAME grafx2 \- Ultimate 256-color bitmap paint program .SH SYNOPSIS .B grafx2 .RI [ options ] " files" ... .br .SH DESCRIPTION This manual page documents briefly the .B grafx2 command. .PP \fBgrafx2\fP is a bitmap paint program that allows you to draw in more than 60 video resolutions, including most of the standard Amiga resolutions : 320x200, 320x256, 320x512, 640x256, 640x512, etc... provided your videocard knows how to handle them. This program is dedicated to everybody who knows what a single pixel is. Its layout is not very different from the famous Deluxe Paint or Brilliance, so it will be quite easy to handle it if you know at least one of these programs. If you aren't used to the art of drawing with up to 256 colors, it will be a little more difficult for you, but you should give it a try (or more, because most of the power of this program won't show up on the first try). .SH OPTIONS A summary of options is included below. They can be prefixed by either / - or -- .TP .B -?, -h, -help Show summary of options. .TP .B -wide To emulate a video mode with wide pixels (2 x 1). .TP .B -tall To emulate a video mode with tall pixels (1 x 2). .TP .B -double To emulate a video mode with double pixels (2 x 2). .TP .B -wide2 To emulate a video mode with double wide pixels (4 x 2). .TP .B -tall2 To emulate a video mode with double tall pixels (2 x 4). .TP .B -triple To emulate a video mode with triple pixels (3 x 3). .TP .B -quadruple To emulate a video mode with quadruple pixels (4 x 4). .TP .B -rgb To reduce RGB precision from 256 to n levels. .TP .B -skin Use an alternate file for the menu graphics. .TP .B -mode To set a video mode listed with the -help parameter. .SH FILES User settings are stored in ~/.grafx2/gfx2.ini. This file is really meant to be edited by the user and allows to tweak many aspects of the program. .SH ENVIRONMENT Since grafx2 uses the SDL library for graphics and user input you can use control some of that parts using the SDL environment variables described at http://www.libsdl.org/cgi/docwiki.cgi/Environment_variables .SH SEE ALSO .BR gimp (1), .BR imagemagick (1). .br .SH AUTHOR grafx2 was written by Adrien Destugues, Yves Rizoud, Peter Gordon, Markus Weiss, Rusback, Franck Charlet, Luc Schrijvers, Karl Maritaud, Guillaume Dorme, and Karl Bartel. .PP This manual page was written by G\[:u]rkan Seng\[:u]n , for the Debian project (and may be used by others). grafx2/misc/unix/grafx2.xpm0000644000076400010400000000270111300630706016263 0ustar vigAdministrator/* XPM */ static char *grafx_[] = { /* columns rows colors chars-per-pixel */ "32 32 16 1", " c blue", ". c #FEFFFF", "X c black", "o c #808080", "O c #008080", "+ c #800080", "@ c cyan", "# c #C0C0C0", "$ c navy", "% c None", "& c black", "* c black", "= c black", "- c black", "; c black", ": c black", /* pixels */ "XXXXXXXXXX%%%%%%%%%%%%XXXXXXXXXX", "X...@.@@@#X%%%%%%%%%%X..@@@@@# X", "X.@@#O#OOOOX%%%%%%%%X.OO $X", "X.O@O#OO OOOX%%%%%%X@O o.o $X", "X@@OOOOOO O OX%%%%X@O o.o $X", "X.O#OOOO O O OX%%X@O o.o $X", "X@OOO O O O OXX@O oooo.oooo $X", "X@OO O O O O#O o......... $X", "X#O O O o.oooo.oooo $X", "X OO O o.o o.o $X", "%X$OO O O o.o oo o.o $X%", "%%X$OO o.o.o o.o $X%%", "%%%X$O oo o.o $X%%%", "%%%%X$O o#.#o o.o $X%%%%", "%%%%%X$ #o o.o o. $X%%%%%", "%%%%%%X$ o. o.o.o#o $X%%%%%%", "%%%%%%X# o#o.o o.o OX%%%%%%", "%%%%%X@ o.o OX%%%%%", "%%%%X@O o.#o o.o OX%%%%", "%%%X@O o.oo# o. OX%%%", "%%X.O o.o o.ooo#o o..o OX%%", "%X.O o.o o.....o .oo. OX%", "X.O o.o o.o . . X", "X. o.o o.o # . o. +X", "X@ .o o.o o. .o.o ++X", "X. . .o.o +XX ..o +X", "X@ #o o. + +X%%X+ + .o + +X", "X@ o.o o.o+ +X%%%%X+ +X", "X@ o#..o+ +X%%%%%%X+ + + + +X", "X# + + +X%%%%%%%%X+ + + + ++X", "Xo++++++++X%%%%%%%%%%X+++++++++X", "XXXXXXXXXX%%%%%%%%%%%%XXXXXXXXXX" }; grafx2/misc/unix/grafx2.desktop0000644000076400010400000000022011344063046017127 0ustar vigAdministrator[Desktop Entry] Name=GrafX2 Comment=Deluxe Paint Clone Exec=grafx2 Terminal=false Type=Application Icon=grafx2 Categories=Application;Graphics; grafx2/share/grafx2/fonts/8pxfont.png0000644000076400010400000000336011343530046020173 0ustar vigAdministratorPNG  IHDRA loZPLTETTTTTTTTTTTTT̼|||lll\\\LLL<<<,,, |l\L<, ||ll\\LL<<,, |l\L<, ||ll\\LL<<,, |l\L<, ̼||ll\\LL<<,,  00@@TTddttxhTD4$ 00@@TTddttxhTD4$ 00@@TTddttxhTD4$<\|`@ <\|`@ <\|`@ 褈|Ԍp̀dtXhL\@P4D(|8p,`P@ ||(||@||X||p||||||||||||||||l0(pGLk pHYs  ~IDAThXْ0Td|$y<4Ml51-<| n^ց"ʋ%ܪ٫?wO'!}'k_ƍ<{vlaxoy^-ϯC^\ \/XCPen @pfqDXR9syy@|c%U;0^-č.v& 2]EWO>Y8V} ;]a|CzkqmH烰[[o ,o$\zH*z,`W *Εy4m5 E'V78 8v<]Wq+*;E/t~3o~YΣ' ]/ 6wmTym'UpsՌ E1>FFSFr ⇮w_AZ)L~qWPwqplR"l{/3}2n^_|iy(yCerXJ\:#JH&pUq?Z'9(|7 ÒtC{\ɏ;_xUcdǣ:h1N8o⌻OŲ 73F}*7)VW~E*2 oI*}I4Xm0_gGwƙlEW$b츢JA ׍2ؐ:(lbWp[}h96% oAbD36IgVs_ѡ<2~@)ya}:ޟpD.Nʇ*@v8d|b+`;||Ԙ@ȕ&v@3woUjs_pbmg;gxYWxǵ gٵ{@wh=IENDB`grafx2/share/grafx2/fonts/Tuffy.ttf0000644000076400010400000004401411343530046017674 0ustar vigAdministratorFFTMEQ\GGDEF)FPGPOSF^GSUBltFp OS/2kVcmap+Bcvt !y8gaspFHglyfҺ4headB 6hhea ΎD$hmtxwJlocaR<maxph name/d=posteHDh 4_< //??]bT@_P0 PfEd ==hg5zhd~$)Z!~Ngbmg(pdppmfqpXpppophpqqKTBX\9X)HydyvyzySdytqyQyyy5\KyZ\My7-XyP(TJL-dr+~X`TLIb}I((fI`f(xR^D5(xZZp}?5(P`TX?VJ1Z+L)h;m^?V1&a~yub R R R R R RlSxzzzz 1f1f1f1f1fAl p`V1\ ^ ^ ^ ^ ^ ^TVllllxsR$p&p&p&p$pwV(((((? S_cjQaq[A<        !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a}~pcdhtnjriqfsxblkwy|u{zov!y0pdZrbDV$8L <*n^  ` t   0 @ R d p @ v $ L n  : p Jf*"Vp(2@ $LXdp|(4Bfr~6BNZfr~ ,8DP\$jgB #.546324632#"&'&#");'(=@,':?,':"!'77%-?1$,?0% ;&46;2#"&'4&%46;2#"&'&+'"+)"Dv$(v$( 5{!#!#!5!!5!3!3!!!\\Vii#RaaR{{e*3:3.'#5.'7.5467>54&ŁВ}#wK:oeL-ӴQ~fL- ;5O-S|k9ԝ]t7.54>32+'n_c[eaw|!Jg[ZL6RY(Ro_t3LLgiv4su]:Hy^P]; #u`lc46;2#"&'&+)"Dv$( ) &5473n{suTIUZ #654'3 tjyTJ]!y9#"'&54?"&5463'&547632763272#'#"&'q!& 0*" (*om*( "*0 &! (#)!)' (( ')!)#( NB !3!!#!N34̍7Ɏ7g#>%'65"&'&54632>%8H':@,':^,XM/gK/% -?1$m3!!m[g>74632#"&'&g@,':?,':^-?1$,?0% T3#3͞d&4>32#"'&732>54'.#"dByo.mܓ."mPI&!kPL(ך|ڈ ڄxpms#73#F\Pm/'6$32!!4>7>54&#"'AxlP/*@:M3C *b`?u4PypG ?"=#-kdV7 GeY3bOO8>#,\ny/^\2*0%96F%q /?32654.+532654&+"'>32#"&q&S9_s=Nba_Py 5{euBN'&TM3}/RhIwK(}pdUI@i^mRM @]GX 3##!;!`^ }ts#V&"'!!632#"&'732654'.\!;1%$^B[# kч.T߄ ' KT7¤?>݉Ţ,'r)4'.#"326632#"&'&54>73oqiEI@! Bse /";N%gu!f~ɛ+3N~N͓*-:snDd Ho7 #!57նPh/@%2654'.#"32654'.#"2#"$'&54>7&'&546Fs`oewU# 3SQ) q" n&oVbqQa -n'l((w͠4,NY9V'0*32654'.#"#"&'&54>32#%qiI@! )PmQ 1A#fv"fɛ2->~pW3Γ,+:rr>mqH'  q#H&  T% 3 PdXBfbb!!!!B  \%# 3#eZ9-=#54>7> 54&#"'>324632#"&'&=6(E  |RHV~KJ>I21@,':?,':-P6="9 $}Z|92`aa?7'4G9-?1$,?0% )FV%# &54$32#"&'#"&'&5463232654'.#"32632654'.#"M^7`Ј6Tb-7x(,OzȎv R38f osc.[]uKZmqBTfWRP_]wC@K^89+54'.#32>54'.#"&'!2#2#!?FqK4S}F+ %HU˱vo? WHvK- *KcZ#!7KR,#^ud'!0C9#<9!4Ye:*#u5X^3$$"BWKL5!d)#".54>32.+"3267Lp_wȋa-.awLbN1hhi87#!!2*JcUi0ODOAs[4jTχpzy !!!!!!y0gy !!!!#y0\d0".54>32.#"32>5!5!#*P-bwI:jgi99igFvP53#"&'&q o\Fͥ&45}ggGy 33 ##yxϼsy3!!yeݍy 33 3##yϙTT!P\Ly 333#y䝑wPZ\34'.#"32>%4>32#".'&H=^V]\==^U]\>&Z{yƆV'Z{xƆVvmStAPVokRq@MzUeΞc\ltmdʚ`Zkjy 3 4'.+';2+# ,SbΞ BՊΞ#)E?#-(WsB\94'.#"3267'764>32'#".'&PAaVde5=a[6{"Xg ([yb|b=U?ZLnd}b=rjVuAi{mdRvC)"teΞc?hVokRyu54&+ ##;2^R2Sמ3Ʀ"5LF(|wx- <732654.'.54632.#"#"&-s,G=Z7S%5H26!)ps2-G4S(@T?B*ۋGWr)L:9'* ))=CZ3êHq|^$>.+!! 13HNf8TX!!#!XD7##y3#"$'&5332>5-#zKe9g+rV?~ЇP3#3GBPT 333# #T+P3J 3 3 # #Jjc;˾^)'JLd3 3#LddBX<d!!!!Pliݍ#!!#3u`Z\!31 53#5!`@}5#'#35}VX5!XB獍`w!&'&547632#"c  "$  TbB +"32654&'254&#"'632#=#"&546ol`{h uEz"Nۋ+Dh6Fcgcfm1`+"hm{=>,Χ">32#".'#&"320Fd>e\..\f>dF-蠠ts-GA#]poŤ`#@E-LlF!.#"32>7#"&54>32xF+O6! z@Um;u(PmTr6)2c#60M)HA&Vj=zaI#3#5#".54>3232654&".Ed?RZ>.\e>dF0stR-E@#@lXpš]#AG-pbF"!.#"3267#".>32 pLw<[e I }##5354>32.#"3;X`':M+m((9V325332654&"FsM[e<\h-Fd>RZ>.\e>dF0Lstck;Agt8Wu!-E@#@lXpš]#AG-p!#3>32#4."rRd732>32#4.#"V+K3ژ/1L.tm+A+#HnrK/a1&/@$ihs;^dH<gN!#3>32#4."rRd732#".732>54.#"f9kia_Ɍa BoJIoB 7ab7wʗUZyDDyZyuuTN">32#".'#&"320Fd>e\..\f>dF-蠠ts1-GA#]poŤ`#@E-"I? N'3"&=".54>325332654&"4B5Ȝ[..\e>dF0Lst=5u͸y\anpš]#AG-pN&#"#3>32P1>Y{5qR*xw1Yy`HJ6.54672&#" #"&'732654.+ȔQR0 6Pu-52 ?"?%6!&ؗ&h\et&G? :Ab;-JG%zOG$<$  " .0="pCH`U(@-fP+#53533#;#"&5􎎗uFFx-uox13#5#".532>5rRd7=#".532>53L{MՖjg1^R2rRd7&67>7&#"327.'&'&'&Z@T! ,9F'+Z <.<"Y,'F:, (f}w"  P-M+>   " '@W} 33}R=532676=4>7&'&=4'&'.#"5@T! ,:F',Y <.?"Z+'F9, 'i|"  T+Q-9  " %R?3\>3232>7#".#"?1H$800: D7!!5D" ?403$B1+!-,+,--+^PN!.'&54>753&#"327#}k 8]`4cdZPkU~pPRZ< w,9L|M. W_Pz[!&S]jZ`4T'(#5332.#"!!!>7!>7j^I: g ^.P  &&(; TBTktFdQ}N! s *?w-w132654'.#""'#53&'&547#536253#3# cAKi bALidPP+;yPPy&B>QjK>Qj779F$gQ{77{4B%hWJu!5!3 33!!!#!5!DX1Ϙ7D6ׇLZ#53鏏{z+h,;632#"&'7;26754"#"&'&54>32.+"4'.#";2& ];S Ga - " N[avFF^!Q% Ö0,Wd #pX 7:nxH\S{QL4632#"&'&%4632#"&'&#8&!48&!4)8&!48&!4F&8+  '8+! &8+  '8+!)7(8#"&'&54632&"327%32654'.#"432#"&'&uCSJqyV[;N"L84!.sssu bC\GUy;R8& ,D%o&nŖ2)Ŗ+;^ 3# 3#ч^"#"!}#5!5!!͏mm^X,:M32>54'.#"4>32#".'&%32>54&5.+'32#'# Qlv;DtH Vpu5EtGu?gE& kʡ 3"/0]KRRq -dAR2,JuG$5aZ.(KzH&1^_ftR&߰96}U{8q "N:> ,?j!!?]j1=32654'.#"4632#"&'& N4=S N4=Svm^m^3AW?3BXBktY ltY'HPa+632#"'&'&54i$:!  ufh%#332>53#5#".) $.N5%.u:,E*(J+6L8'@QQ&b9D$yu,23"3"&#.'&54>;0GM*$)A/%=^^A0 s  !!6O2!5!   ,7O1*)b`3neE'{uqJ>54'.'7u'@8*J  "  .8>H 81,b;^ #!#^"#"#}"{R}'C'\$ R'rX$ Rq'A$ RJ'a$ R'i/$ R'pf1$ Sg!#!!!!!!53OFF{JxX'v&'C^( 'r`^( Z'A( 'i1( A'Cjs, 'rX, If'A, 9'iZ!, #53!2+324'.+!F}82⛝(,bhE^S5'a+1 f'CP2 f'r 2 fs'A2 fJ'a32 f'iB2 lJ7,-c,`,9%#7&'&54>3273#"'32>54'&' &#"J|/6[xczaE55\wc5VoYZ=#OIXYZ<)FokRvD2EmtRsB;LzTtod`&O}Txd'C=s8 'rs8 w'A8 'iB8 Vn'r^<  2>54'&!3 ##/WlC.E7gc&;b@&(SX>!\]G>32!"'732>54'.+"5;2>54'&#" #67,DXQ'+^eNPj[ ( ?d_?&$*Y)JsO3!  *-8cF:" ,GnA'h5{ $;`@o;xJ'%#CP7bzY ^l#'CD ^l'r;D ^l&AD ^l'ayLD ^l^'i^D ^lV'pD T`FWa"32654'.>32!32>7#".'#"&'&546326&74'&#"'>32!&'&#"i_"\mf:zd!aV8m'@5$,,5U8 ȘWR$ "AP'N55Q3^t /:X/Zl1$h(Ob4_Y^} - IG]~ 7nk 9 %71&7035,6+&'f(YsG9BmuV]vF'v F l+'C H l5'r9 H l&A5H l`'iH -/3#&'&547632#"!  "1$   #3#632#"'&'&54$1:!  s# 3##'#31^VR#3#4632#"&'&%4632#"&'&8&!48&!4)8&!48&!41&8+  '8+! &8+  '8+!R@32654'.#"#"&'&54324'.''7&#"'6327 Iqg;h9C ݠ)G/30 h8cGY)J7`.2u׆%sjMo$!8BҸHP$. )^1dFm'aXQ p''CR p1'rhR p&A3R p'a/R pZ'ioR w[& VJ 1 32>54'&'&#"7&'&54>3273#"'ATEj< ZASAh>! s7__1q9_c0DNNVD2?L{LWG+%YwZVKOZuQ\NN'CX 'rGX &A1/X b'iuX ?'rK\ +!#3>32#"./4'.#"326/DU4":[^8d6fD5hU5Jr)54ȢXeZkA.7]Rp6c4:jDAQDr'Ha>'Jq2[>| 0#53>32.#"!!!!3267#"&'#53&54'}q}M`2XQ<_,"i0E\>`<9[7&:K`3+ZJ MW+Da/!!zs) +[x    D   g y R   9  l ~ & & & k "-SCreated by Thatcher Ulrich (http://tulrich.com) with FontForge 1.0 (http://fontforge.sf.net) This font, including hint instructions, has been donated to the Public Domain. Do whatever you want with it. Created by Thatcher Ulrich (http://tulrich.com) with FontForge 1.0 (http://fontforge.sf.net) This font, including hint instructions, has been donated to the Public Domain. Do whatever you want with it. TuffyTuffyRegularRegularFontForge 1.0 : Tuffy Regular : 11-2-2007FontForge 1.0 : Tuffy Regular : 11-2-2007Tuffy RegularTuffy RegularVersion 001.100 Version 001.100 TuffyTuffyThatcher UlrichThatcher Ulrichhttp://tulrich.com http://tulrich.com http://tulrich.com http://tulrich.com Public Domain Public Domain MagerKursivNormalCursiva1KG=K9C@A82VanligKursivNormaleCursivoNormlDQltStandardKursivNormalItaliqueRegelmatigCursief2  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghjikmlnoqprsutvwxzy{}|~ softhyphen figuredash quotereverseduni201FEuro  latn ,latnkern6<BX^djtzq&79+Y\Z5)72$7$w$Xy$ (H$H$BD?qYWDQRWX\MuMP[MHMu$(*.2379:<?DHIJMRTU\?.grafx2/share/grafx2/fonts/PF_Arma_5__.png0000644000076400010400000000247311406505434020563 0ustar vigAdministratorPNG  IHDR aPLTEMM"""fff>!tEXtSoftwareGrafx2SjIDATXXr oέ rB޵e uY[[Kk`?ңΫ%:S yDkՊrverVoK񔷒 vXԔ7^یhKasft@V(q]Gl)tBV־lcb}zq!!nuۅ+;zAW2\Bve*g`>?g/J$ӬKmz6&d* 8p mT-6)2rwv9zezb(SVB;;Dl&!Uf6چ\ZT$Ź-wEnGӨCD鶙?gb=\م.h5e2ZzHzIWp?9 DHC@IENDB`grafx2/share/grafx2/fonts/PF_Easta_7_.png0000644000076400010400000000321711374561770020611 0ustar vigAdministratorPNG  IHDRjPLTEMM"""fff>!tEXtSoftwareGrafx2Sj/IDAThYn0 ,~gF}N[G?Jp>_BuYgFmpH72WS溲6Рs6s@3n.'v+rrߞ4|%"0M2q'K|1 Gk2mݛp79PL'ea&!v7>ꍪeaEt9pWᦅ`B)GwUs)=O1b8c:'LGDI$`0~ iPl?0d-kqNu0W %(&S2&B#]V{`i&,t-y Vvf4$W}PS Ðxf=X֮lDy $|F澅jo&X1M,Anp .|D d<0qu _'x3_oK2Md8}-zo"FLVOme~!Q=Kq9p% Iʼ>,{̉@)z5'02csM@lp۩2VhdB[jw RNێ O~tȞ{t x9wpFc1Aա\|(N=!!D :OyrکQ)A/gUC=Xw& 8sN1[x1 lP`%͢vŢ1kLa5tEX8fVs~#vc30=P4='2sи5v_<9.5t?dc?/5McXPXIENDB`grafx2/share/grafx2/fonts/PF_Easta_7__.png0000644000076400010400000000350011374557460020744 0ustar vigAdministratorGIF89aMM"""fff!,௠ "Dh† *@ '^ԘbD<#E%7zH/CsD4e3%˘:R *cNDw&,T)ϡHJi)ԜRz#ז%jڳkKMUZ-:,IN㢕ѳYڽ[,F~ <È+^̸ǐ#KL˘3k̹ϛMӨS^ͺװc˞M6cѶs4ѿ=q?μ#.ێ+>⢗kPzC߃<vuuo?H '\ a "xh${Y}!vq'ތ'!{.GQ &:PH*& ;grafx2/share/grafx2/fonts/PF_Ronda_7__.png0000644000076400010400000000314411374561674020760 0ustar vigAdministratorPNG  IHDRdC8PLTEMM"""fff>!tEXtSoftwareGrafx2SjIDAThZn mmږ0-k6Ԁm{[e]??0WT x9cnzo3eoԜ?j ŨwQc2YJ|JZ 0}hSRp7(fZf MnB CI'~:Q_(2HH0b5Xa=BrM(JQԇ>H,T(ՔsM$j4uIy@<@!$a/J}PxtN_ m *K? c,nmzJ-k}IE( hm>ζ/fbW9&M٤ឣITY"h*Zn{B30Af;6b9OQI +&AH>s/ ?xt*@9 cY5cTfokAEf9m93fIENDB`grafx2/share/grafx2/fonts/PF_Tempesta_5_.png0000644000076400010400000000247411374561510021330 0ustar vigAdministratorPNG  IHDR Qc[JPLTEIH"""fffBftEXtSoftwareGrafx2SjIDATXXr04j.uz6'?%kMsk:39Wfd#>GS|V y-_<_ sуM n}zl`_bp@aF\D]zzJ fڿynBiOpK^um+ϛe"`Oh=,':ws *A 4мn&gf x_1*E&s)v~DK_oInYPBLQ0'oK[DDxmS2wq%&z<|1_4_w=Mb8ⷲFt6\4yrB .@]6r&߱Qf*@U٨;bF$ЙBQoKލq,Q~ㄲꃩ3 YCL*_q0orA6lV=/Йa@ tn\Mk;-vIENDB`grafx2/share/grafx2/fonts/PF_Tempesta_5__.png0000644000076400010400000000252711374561616021475 0ustar vigAdministratorPNG  IHDRn 0^.!PLTEIH"""fffBftEXtSoftwareGrafx2SjIDAThYr ommdivYCqlz;f}FY>:yEL |R.gwWs߮&&^5`64Q_M%S=}z,kh|>ʶ>HRDìl8VFzz +,^Du1JYIў`M6bʪjہ:32+¡SVI"m+\rÕv,] &`ܺ91\2~+w͎@Miǜ2Iʓ:?}p:.O rfG',k|b!F}vYB~XQR)UFznnַ?^{{,ҒغNAR+s))|G:!} {wK럨ԯ"0/y?{"_n>o^!vzXm*9YzwG3gFj` !VAڢf0=++ͫVh1M'y*xHm}VoM}&t(patY]+} o̍S Z0O ,S OC-7ENr=ȳm((ȴ7)1&o`xp~jimcSr%r+Hp+Y#T1sڥez^g}q >P.^-b GUugK0*_L"pOTri|ػxH| QlfG]>`tO/[WVX~32e}<[{~Ik]XoC=giz^E틀Yf7*Vq)q |%K}e1m,YTbPl#%pX$btyl/ԛHi`0EPぬk 5fk`ݟ $RSVij4T){3C+V-n*g(ʹ` Kk&+ ȋ_j@rp>)cLLӌN&8ifLۢfp)êp}Lֳ>h26܌&2"Q h 0X4ZF[K ^~w:g Z*D5wzKYH:%" F'DrY[R䆦  Y\-v!`e"\qSHG;m  s )IZ0. ϝmv-ɛw3[pPP:,N4g۾L/ s]˕6o$J%y^"jlрA-9oIENDB`grafx2/share/grafx2/fonts/PF_Westa_7_.png0000644000076400010400000000327711374560410020633 0ustar vigAdministratorPNG  IHDRڄPLTEIH"""fffBftEXtSoftwareGrafx2Sj_IDAThYے0 k̜=HNY-@X֖KRiH澨2.XXdNħMGyq06ܳ 9ʏvM|nHcāAvLEs.>yˢڙWI>ƆGgntV3p;ԧ2+a aLD+DhksQ"EW}ۈJ QFNK35r HV~nCA+'y?‡fbI y0F9q Ȭ^qR<#t=Hކ<؇0ucH4t?pt!(1//A;0\ BA$w9hy])"ʝ3A^`?1pLXpD^؄X|!djR}R N@ h6@(=<חڵy" ¦IqJ4Pnylʚ@%)1|.6M.9$*f(2V׶>C[WS]H0y< Cw(}Mh1Cm?lن~!ndBoM} p rƦ~oPiٺw+b#5WU|KG8 zX@)xfbns4J+};dϖK,1 f# IdԿiO@D>3I'\ 7yQGmbyIENDB`grafx2/share/grafx2/fonts/PF_Westa_7__.png0000644000076400010400000000340711374560452020773 0ustar vigAdministratorPNG  IHDR!PLTEIH"""fffBftEXtSoftwareGrafx2SjIDAThZے0koΜ=m $9Ne6kdq*t# s %DVwp 9r1 "bY>/VȵQnXԥ$l-핼Z܉#-P(F8ҕh,&9WR|u