/* Grafx2 - The Ultimate 256-color bitmap paint program 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 or write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // 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 #include #include #include #include #include #include #include #include #include #if defined(__WIN32__) #include // GetLogicalDrives(), GetDriveType(), DRIVE_* #endif #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) #include #include #endif #ifdef GRAFX2_CATCHES_SIGNALS #include #endif #include "const.h" #include "struct.h" #include "global.h" #include "graph.h" #include "boutons.h" #include "palette.h" #include "aide.h" #include "operatio.h" #include "divers.h" #include "erreurs.h" #include "clavier.h" #include "io.h" #include "hotkeys.h" #include "setup.h" #include "windows.h" #include "sdlscreen.h" #include "mountlist.h" // read_file_system_list #include "loadsave.h" // Image_emergency_backup // Rechercher la liste et le type des lecteurs de la machine #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) void bstrtostr( BSTR in, STRPTR out, TEXT max ); #endif // Fonctions de lecture dans la skin de l'interface graphique void 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; } y++; } while (yh); printf("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); Error(ERROR_GUI_CORRUPTED); } void 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; } x++; } while (xw); printf("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); Error(ERROR_GUI_CORRUPTED); } void Read_GUI_block(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 MC_White and MC_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) { printf("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); Error(ERROR_GUI_CORRUPTED); } for (y=start_y; yformat || gui->format->BitsPerPixel != 8) { printf("Not a 8-bit image"); Error(ERROR_GUI_CORRUPTED); } SDLPal=gui->format->palette; if (!SDLPal || SDLPal->ncolors!=256) { printf("Not a 256-color palette"); Error(ERROR_GUI_CORRUPTED); } // Lecture de la palette par défaut for (i=0; i<256; i++) { Default_palette[i].R=SDLPal->colors[i].r; Default_palette[i].G=SDLPal->colors[i].g; Default_palette[i].B=SDLPal->colors[i].b; } // Carré "noir" MC_Black = Get_SDL_pixel_8(gui,cursor_x,cursor_y); do { if (++cursor_x>=gui->w) { printf("Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); Error(ERROR_GUI_CORRUPTED); } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==MC_Black); // Carré "foncé" MC_Dark=color; do { if (++cursor_x>=gui->w) { printf("Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); Error(ERROR_GUI_CORRUPTED); } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==MC_Dark); // Carré "clair" MC_Light=color; do { if (++cursor_x>gui->w) { printf("Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); Error(ERROR_GUI_CORRUPTED); } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==MC_Light); // Carré "blanc" MC_White=color; do { if (++cursor_x>=gui->w) { printf("Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); Error(ERROR_GUI_CORRUPTED); } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==MC_White); // Carré "transparent" MC_Trans=color; do { if (++cursor_x>=gui->w) { printf("Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); Error(ERROR_GUI_CORRUPTED); } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==MC_Trans); // Reste : couleur neutre neutral_color=color; cursor_x=0; cursor_y=1; while ((color=Get_SDL_pixel_8(gui,cursor_x,cursor_y))==MC_Black) { cursor_y++; if (cursor_y>=gui->h) { printf("Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); Error(ERROR_GUI_CORRUPTED); } } // Menu GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "menu"); Read_GUI_block(gui, cursor_x, cursor_y, GFX_menu_block, MENU_WIDTH, MENU_HEIGHT,"menu",0); cursor_y+=MENU_HEIGHT; // Effets for (i=0; i>1); Preset_paintbrush_offset_Y[index]=(Preset_paintbrush_height[index]>>1); } Cursor_offset_X[CURSOR_SHAPE_ARROW]=0; Cursor_offset_Y[CURSOR_SHAPE_ARROW]=0; Cursor_offset_X[CURSOR_SHAPE_TARGET]=7; Cursor_offset_Y[CURSOR_SHAPE_TARGET]=7; Cursor_offset_X[CURSOR_SHAPE_COLORPICKER]=7; Cursor_offset_Y[CURSOR_SHAPE_COLORPICKER]=7; Cursor_offset_X[CURSOR_SHAPE_HOURGLASS]=7; Cursor_offset_Y[CURSOR_SHAPE_HOURGLASS]=7; Cursor_offset_X[CURSOR_SHAPE_MULTIDIRECTIONNAL]=7; Cursor_offset_Y[CURSOR_SHAPE_MULTIDIRECTIONNAL]=7; Cursor_offset_X[CURSOR_SHAPE_HORIZONTAL]=7; Cursor_offset_Y[CURSOR_SHAPE_HORIZONTAL]=3; Cursor_offset_X[CURSOR_SHAPE_THIN_TARGET]=7; Cursor_offset_Y[CURSOR_SHAPE_THIN_TARGET]=7; Cursor_offset_X[CURSOR_SHAPE_THIN_COLORPICKER]=7; Cursor_offset_Y[CURSOR_SHAPE_THIN_COLORPICKER]=7; } // 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 Gauche , Func_action Droite, Func_action Desenclencher, byte family) { Button[btn_number].X_offset =x_offset; Button[btn_number].Y_offset =y_offset; Button[btn_number].Width =width-1; Button[btn_number].Height =height-1; Button[btn_number].Pressed =0; Button[btn_number].Shape =shape; Button[btn_number].Gauche =Gauche; Button[btn_number].Droite =Droite; Button[btn_number].Desenclencher =Desenclencher; Button[btn_number].Famille =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 retournés 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; } // Initiliseur de tous les modes video: void Set_all_video_modes(void) { // Numero LargHaut Mode FXFY Ratio Ref WinOnly Pointeur SDL_Rect** Modes; Nb_video_modes=0; // Doit être en premier pour avoir le numéro 0: Set_video_mode( 640,480,0, 0); Set_video_mode( 320,200,0, 1); Set_video_mode( 320,224,0, 1); Set_video_mode( 320,240,0, 1); 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; for (index2=1; index2 < Nb_video_modes; index2++) if (Modes[index]->w == Video_mode[index2].Width && Modes[index]->h == Video_mode[index2].Height) { // Mode déja prévu: ok break; } if (index2 >= Nb_video_modes && Modes[index]->w>=320 && Modes[index]->h>=200) { // Nouveau mode à ajouter à la liste Set_video_mode(Modes[index]->w,Modes[index]->h,0, 1); } } // Tri des modes : ceux trouvés par SDL ont été listés à la fin. 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<(long)sizeof(cfg_header)) || (!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/sizeof(cfg_shortcut_info)); 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 : Button[Ordering[index2]&0xFF].Left_shortcut[0] = cfg_shortcut_info.Key; Button[Ordering[index2]&0xFF].Left_shortcut[1] = cfg_shortcut_info.Key2; break; case 2 : Button[Ordering[index2]&0xFF].Right_shortcut[0] = cfg_shortcut_info.Key; Button[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 vidéo for (index=0; index<(long)(Chunk.Size/sizeof(cfg_video_mode)); 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; for (index2=1; index2>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 =Button[Ordering[index]&0xFF].Left_shortcut[0]; cfg_shortcut_info.Key2=Button[Ordering[index]&0xFF].Left_shortcut[1]; break; case 2 : cfg_shortcut_info.Key =Button[Ordering[index]&0xFF].Right_shortcut[0]; cfg_shortcut_info.Key2=Button[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 préférence modes_to_save=0; for (index=1; 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 : Button[Ordering[index]&0xFF].Left_shortcut[0] = ConfigKey[index].Key; Button[Ordering[index]&0xFF].Left_shortcut[1] = ConfigKey[index].Key2; break; case 2 : Button[Ordering[index]&0xFF].Right_shortcut[0] = ConfigKey[index].Key; Button[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 défaut 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); // Masque for (index=0; index<256; index++) Mask_table[index]=0; // Stencil for (index=0; index<256; index++) Stencil[index]=1; // Dégradés Current_gradient=0; for(index=0;index<16;index++) { Gradient_array[index].Start=0; Gradient_array[index].End=0; Gradient_array[index].Inverse=0; Gradient_array[index].Mix=0; Gradient_array[index].Technique=0; } Load_gradient_data(Current_gradient); // 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; // Grille 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__) #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 }