/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Góralski 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 #ifndef _MSC_VER #include #else #if _MSC_VER < 1900 #define snprintf _snprintf #endif #endif #if defined(USE_SDL) || defined(USE_SDL2) #include #include #endif #if defined(WIN32) #include #include #elif defined (__MINT__) #include #elif defined(__macosx__) #import #import #elif defined(__FreeBSD__) #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 "screen.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" #include "filesel.h" #if defined(WIN32) && !(defined(USE_SDL) || defined(USE_SDL2)) #include "win32screen.h" #endif #if defined (WIN32) && (defined(USE_SDL) || defined(USE_SDL2)) // 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 static int setsize_width; static int setsize_height; #if defined(USE_SDL) || defined(USE_SDL2) /// Pointer to the current joystick controller. static SDL_Joystick* Joystick; #endif //--- Affichage de la syntaxe, et de la liste des modes vidéos disponibles --- void Display_syntax(void) { int mode_index, i; char modes[1024*2]; const char * syntax = "Syntax: grafx2 [] [] []\n\n" " can be:\n" "\t-? -h -H -help for this help screen\n" "\t-wide to emulate a video mode with wide pixels (2x1)\n" "\t-tall to emulate a video mode with tall pixels (1x2)\n" "\t-double to emulate a video mode with double pixels (2x2)\n" "\t-wide2 to emulate a video mode with double wide pixels (4x2)\n" "\t-tall2 to emulate a video mode with double tall pixels (2x4)\n" "\t-triple to emulate a video mode with triple pixels (3x3)\n" "\t-quadruple to emulate a video mode with quadruple pixels (4x4)\n" "\t-rgb n to reduce RGB precision (2 to 256, 256=max precision)\n" "\t-gamma n to adjust Gamma correction (1 to 30, 10=no correction)\n" "\t-skin to use an alternate file with the menu graphics\n" "\t-mode to set a video mode\n" "\t-size to set the image size\n" "Arguments can be prefixed either by / - or --\n" "They can also be abbreviated.\n\n"; fputs(syntax, stdout); i = snprintf(modes, sizeof(modes), "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; i += snprintf(modes + i, sizeof(modes) - i, "%12s", Mode_label(mode_index + k)); } i += snprintf(modes + i, sizeof(modes) - i, "\n"); } fputs(modes, stdout); #if defined(WIN32) MessageBoxA(NULL, syntax, "GrafX2", MB_OK); MessageBoxA(NULL, modes, "GrafX2", MB_OK); #endif } // ---------------------------- 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); #if defined(_MSC_VER) && defined(DEBUG) OutputDebugStringA(message); OutputDebugStringA("\n"); #endif } // ---------------------------- Sortie impromptue ---------------------------- void Error_function(int error_code, const char *filename, int line_number, const char *function_name) { T_Palette temp_palette; T_Palette backup_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 problème. // Toutes les autres erreurs déclenchent toujours une sortie en catastrophe du programme ! memcpy(backup_palette, Get_current_palette(), sizeof(T_Palette)); memcpy(temp_palette, backup_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(backup_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_FORBIDDEN_SIZE : printf("Error: The image dimensions all have to be in the range 1-9999!\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; } #if defined(USE_SDL) || defined(USE_SDL2) SDL_Quit(); #endif 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_TALL3, CMDPARAM_PIXELRATIO_WIDE2, CMDPARAM_RGB, CMDPARAM_GAMMA, CMDPARAM_SKIN, CMDPARAM_SIZE }; 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}, {"tall3", CMDPARAM_PIXELRATIO_TALL3}, {"wide2", CMDPARAM_PIXELRATIO_WIDE2}, {"rgb", CMDPARAM_RGB}, {"gamma", CMDPARAM_GAMMA}, {"skin", CMDPARAM_SKIN}, {"size", CMDPARAM_SIZE}, }; #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_GAMMA: /* Gamma correction */ index++; if (index 30) { Error(ERROR_COMMAND_LINE); Display_syntax(); exit(0); } Set_palette_Gamma(scale); } else { Error(ERROR_COMMAND_LINE); Display_syntax(); exit(0); } break; case CMDPARAM_SKIN: // GUI skin file index++; if (index 9999 || setsize_width < 1 || setsize_width > 9999) { Error(ERROR_FORBIDDEN_SIZE); Display_syntax(); exit(0); } } else { Error(ERROR_COMMAND_LINE); Display_syntax(); exit(0); } break; default: // Si ce n'est pas un paramètre, c'est le nom du fichier à ouvrir if (file_in_command_line > 1) { // Il y a déjà 2 noms de fichiers et on vient d'en trouver un 3ème 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; enum IMAGE_MODES starting_image_mode; 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]; #ifdef ENABLE_FILENAMES_ICONV static word main_filename_unicode[MAX_PATH_CHARACTERS]; #endif 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 #ifdef ENABLE_FILENAMES_ICONV // iconv is used to convert filenames cd = iconv_open(TOCODE, FROMCODE); // From UTF8 to ANSI cd_inv = iconv_open(FROMCODE, TOCODE); // From ANSI to UTF8 #if SDL_BYTEORDER == SDL_BIG_ENDIAN cd_utf16 = iconv_open("UTF-16BE", FROMCODE); // From UTF8 to UTF16 cd_utf16_inv = iconv_open(FROMCODE, "UTF-16BE"); // From UTF16 to UTF8 #else cd_utf16 = iconv_open("UTF-16LE", FROMCODE); // From UTF8 to UTF16 cd_utf16_inv = iconv_open(FROMCODE, "UTF-16LE"); // From UTF16 to UTF8 #endif #endif /* ENABLE_FILENAMES_ICONV */ // On crée dès 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 manipulées à // 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); // On détermine le répertoire courant: Get_current_directory(Main.selector.Directory,Main.selector.Directory_unicode,MAX_PATH_CHARACTERS); // On en profite pour le mémoriser dans le répertoire principal: strcpy(Initial_directory,Main.selector.Directory); // On initialise les données sur le nom de fichier de l'image de brouillon: strcpy(Spare.selector.Directory,Main.selector.Directory); Main.fileformat=DEFAULT_FILEFORMAT; Spare.fileformat =DEFAULT_FILEFORMAT; strcpy(Brush_selector.Directory,Main.selector.Directory); strcpy(Brush_file_directory,Main.selector.Directory); strcpy(Brush_filename ,"NO_NAME.GIF"); Brush_fileformat =DEFAULT_FILEFORMAT; strcpy(Palette_selector.Directory,Main.selector.Directory); // On initialise ce qu'il faut pour que les fileselects ne plantent pas: Main.selector.Position=0; // Au début, le fileselect est en haut de la liste des fichiers Main.selector.Offset=0; // Au début, le fileselect est en haut de la liste des fichiers Main.selector.Format_filter=FORMAT_ALL_IMAGES; Main.current_layer=0; Main.layers_visible=0xFFFFFFFF; Main.layers_visible_backup=0xFFFFFFFF; Spare.current_layer=0; Spare.layers_visible=0xFFFFFFFF; Spare.layers_visible_backup=0xFFFFFFFF; Spare.selector.Position=0; Spare.selector.Offset=0; Spare.selector.Format_filter=FORMAT_ALL_IMAGES; Brush_selector.Position=0; Brush_selector.Offset=0; Brush_selector.Format_filter=FORMAT_ALL_IMAGES; Palette_selector.Position=0; Palette_selector.Offset=0; Palette_selector.Format_filter=FORMAT_ALL_PALETTES; // 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; #if defined(USE_SDL) || defined(USE_SDL2) // 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); #endif #if defined(USE_SDL) SDL_EnableKeyRepeat(250, 32); SDL_EnableUNICODE(SDL_ENABLE); SDL_WM_SetCaption("GrafX2","GrafX2"); #endif Define_icon(); // Texte Init_text(); // On initialise tous les modes vidéo Set_all_video_modes(); Pixel_ratio=PIXEL_SIMPLE; // On initialise les données sur l'état du programme: // Donnée sur la sortie du programme: Quit_is_required=0; Quitting=0; // Données sur l'état du menu: Menu_is_visible=1; // Données sur les couleurs et la palette: First_color_in_palette=0; // Données sur le curseur: Cursor_shape=CURSOR_SHAPE_TARGET; Cursor_hidden=0; // Données sur le pinceau: Paintbrush_X=0; Paintbrush_Y=0; Paintbrush_hidden=0; // On initialise tout ce qui concerne les opérations 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 chargées avec la config Quick_shade_mode=0; // idem // On initialise les infos sur les dégradés: Gradient_pixel =Display_pixel; // Les autres infos sont chargées 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 défaut Colorize_opacity=50; // Une interpolation de 50% par défaut Colorize_current_mode=0; // Par défaut, la méthode par interpolation Compute_colorize_table(); // On initialise les infos du mode Tiling: Tiling_mode=0; // Pas besoin d'initialiser les décalages 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 opérations 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 problème, on a les valeurs par défaut. 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, 1))) if (!(Menu_font=Load_font(DEFAULT_FONT_FILENAME, 1))) { printf("Unable to open the default font file: %s\n", DEFAULT_FONT_FILENAME); Error(ERROR_GUI_MISSING); } Load_Unicode_fonts(); memcpy(Main.palette, Gfx->Default_palette, sizeof(T_Palette)); Fore_color=Best_color_range(255,255,255,Config.Palette_cells_X*Config.Palette_cells_Y); Back_color=Best_color_range(0,0,0,Config.Palette_cells_X*Config.Palette_cells_Y); // Allocation de mémoire 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; #if defined(USE_SDL) || defined(USE_SDL2) //GetWindowRect(window, &r); SetWindowPos(GFX2_Get_Window_Handle(), 0, Config.Window_pos_x, Config.Window_pos_y, 0, 0, SWP_NOSIZE); #endif } } // 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; starting_image_mode = Config.Default_mode_layers ? IMAGE_MODE_LAYERED : IMAGE_MODE_ANIMATION; // Allocation de mémoire pour les différents écrans virtuels (et brosse) if (Init_all_backup_lists(starting_image_mode , Screen_width, Screen_height)==0) Error(ERROR_MEMORY); // Update toolbars' visibility, now that the current image has a mode Check_menu_mode(); // Nettoyage de l'écran virtuel (les autres recevront celui-ci par copie) memset(Main_screen,0,Main.image_width*Main.image_height); // If image size was specified on command line, set that now if (setsize_width != 0 && setsize_height != 0) { Main.image_width=setsize_width; Main.image_height=setsize_height; Spare.image_width=setsize_width; Spare.image_height=setsize_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 débuter 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 débute 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; // Make sure the load dialog points to the right place when first shown. // Done after loading everything else, but before checking for emergency // backups if (file_in_command_line > 0) { strcpy(Main.selector.Directory, main_directory); } // Test de recuperation de fichiers sauvés 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); Check_menu_mode(); 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(BUTTON_PAGE); // no break ! proceed with the other file now case 1: Init_context_layered_image(&context, main_filename, main_directory); #ifdef ENABLE_FILENAMES_ICONV { char * input = main_filename; size_t inbytesleft = strlen(main_filename); char * output = (char *)main_filename_unicode; size_t outbytesleft = sizeof(main_filename_unicode) - 2; if (cd_utf16 != (iconv_t)-1) { size_t r = iconv(cd_utf16, &input, &inbytesleft, &output, &outbytesleft); if (r != (size_t)-1) { output[0] = '\0'; output[1] = '\0'; context.File_name_unicode = main_filename_unicode; } } } #endif Load_image(&context); Destroy_context(&context); Redraw_layered_image(); End_of_modification(); // If only one image was loaded, assume the spare has same image type if (file_in_command_line==1) Spare.backups->Pages->Image_mode = Main.backups->Pages->Image_mode; Hide_cursor(); Compute_optimal_menu_colors(Main.palette); Back_color=Main.backups->Pages->Background_transparent ? Main.backups->Pages->Transparent_color : Best_color_range(0,0,0,Config.Palette_cells_X*Config.Palette_cells_Y); Fore_color=Main.palette[Back_color].R+Main.palette[Back_color].G+Main.palette[Back_color].B < 3*127 ? Best_color_range(255,255,255,Config.Palette_cells_X*Config.Palette_cells_Y) : Best_color_range(0,0,0,Config.Palette_cells_X*Config.Palette_cells_Y); Check_menu_mode(); Display_all_screen(); Display_menu(); Display_cursor(); Resolution_in_command_line = 0; break; default: break; } } Allow_drag_and_drop(1); return(1); } // ------------------------- Program Shutdown -------------------------- // Free all allocated resources #define FREE_POINTER(p) free(p); p = NULL void Program_shutdown(void) { int i; int return_code; // Windows only: Recover the window position. #if defined(WIN32) #if defined(USE_SDL) || defined(USE_SDL2) { RECT r; GetWindowRect(GFX2_Get_Window_Handle(), &r); Config.Window_pos_x = r.left; Config.Window_pos_y = r.top; } #endif // Config.Window_pos_x / Config.Window_pos_y are set in win32screen.c #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 libère le buffer de gestion de lignes free(Horizontal_line_buffer); Horizontal_line_buffer = NULL; // On libère le pinceau spécial free(Paintbrush_sprite); Paintbrush_sprite = NULL; // Free Brushes FREE_POINTER(Brush); FREE_POINTER(Smear_brush); FREE_POINTER(Brush_original_pixels); // Free all images Set_number_of_backups(-1); // even delete the main page FREE_POINTER(Main.visible_image.Image); FREE_POINTER(Spare.visible_image.Image); FREE_POINTER(Main_visible_image_backup.Image); FREE_POINTER(Main_visible_image_depth_buffer.Image); FREE_POINTER(Main.backups); FREE_POINTER(Spare.backups); // Free the skin (Gui graphics) data free(Gfx); Gfx=NULL; free(Menu_font); Menu_font = NULL; while (Unicode_fonts != NULL) { T_Unicode_Font * ufont = Unicode_fonts->Next; free(Unicode_fonts->FontData); free(Unicode_fonts); Unicode_fonts = ufont; } // On prend bien soin de passer dans le répertoire initial: if (Change_directory(Initial_directory)==0) { // On sauvegarde les données 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); // Free Config FREE_POINTER(Config.Skin_file); FREE_POINTER(Config.Font_file); for (i=0;i 0) { for (k = 0; ShortFileName[k] != 0; k++) arg_buffer[i++] = ShortFileName[k]; } else { for (k = 0; TmpArg[k] != 0; k++) arg_buffer[i++] = TmpArg[k]; } arg_buffer[i++] = 0; k = 0; continue; } } TmpArg[k++] = pCmdLine[j]; } TmpArg[k] = '\0'; if (k > 0) { argv[argc++] = arg_buffer + i; if (GetShortPathName(TmpArg, ShortFileName, MAX_PATH) > 0) { for (k = 0; ShortFileName[k] != 0; k++) arg_buffer[i++] = ShortFileName[k]; } else { for (k = 0; TmpArg[k] != 0; k++) arg_buffer[i++] = TmpArg[k]; } arg_buffer[i++] = 0; } // TODO : nCmdShow indicates if the window must be maximized, etc. #endif if(!Init_program(argc,argv)) { Program_shutdown(); return 0; } Main_handler(); Program_shutdown(); return 0; } #if defined(WIN32) && !defined(USE_SDL) && !defined(USE_SDL2) && !defined(_MSC_VER) int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR _lpCmdLine, int nCmdShow) { WCHAR *lpCmdLine = GetCommandLineW(); if (__argc == 1) { // avoids GetCommandLineW bug that does not always quote the program name if no arguments do { ++lpCmdLine; } while (*lpCmdLine); } else { BOOL quoted = lpCmdLine[0] == L'"'; ++lpCmdLine; // skips the " or the first letter (all paths are at least 1 letter) while (*lpCmdLine) { if (quoted && lpCmdLine[0] == L'"') quoted = FALSE; // found end quote else if (!quoted && lpCmdLine[0] == L' ') { // found an unquoted space, now skip all spaces do { ++lpCmdLine; } while (lpCmdLine[0] == L' '); break; } ++lpCmdLine; } } return wWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); } #endif