diff --git a/src/Makefile b/src/Makefile index 9fb267f1..56224f96 100644 --- a/src/Makefile +++ b/src/Makefile @@ -388,7 +388,7 @@ endif .PHONY : all debug release clean depend zip version force install uninstall # This is the list of the objects we want to build. Dependancies are built by "make depend" automatically. -OBJ = $(OBJDIR)/main.o $(OBJDIR)/init.o $(OBJDIR)/graph.o $(OBJDIR)/sdlscreen.o $(OBJDIR)/misc.o $(OBJDIR)/special.o $(OBJDIR)/buttons.o $(OBJDIR)/palette.o $(OBJDIR)/help.o $(OBJDIR)/operatio.o $(OBJDIR)/pages.o $(OBJDIR)/loadsave.o $(OBJDIR)/readline.o $(OBJDIR)/engine.o $(OBJDIR)/filesel.o $(OBJDIR)/op_c.o $(OBJDIR)/readini.o $(OBJDIR)/saveini.o $(OBJDIR)/shade.o $(OBJDIR)/keyboard.o $(OBJDIR)/io.o $(OBJDIR)/version.o $(OBJDIR)/text.o $(OBJDIR)/SFont.o $(OBJDIR)/setup.o $(OBJDIR)/pxsimple.o $(OBJDIR)/pxtall.o $(OBJDIR)/pxwide.o $(OBJDIR)/pxdouble.o $(OBJDIR)/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 +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 $(OBJDIR)/oldies.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 diff --git a/src/brush.c b/src/brush.c index 6b912029..969201c9 100644 --- a/src/brush.c +++ b/src/brush.c @@ -129,14 +129,119 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) byte temp_color; // color de la brosse en cours d'affichage int position; byte * temp; + byte old_color; - if (is_preview==0 || Mouse_K==0) // pas de curseur si on est en preview et - // en train de cliquer + if (is_preview && Mouse_K) // pas de curseur si on est en preview et + return; // en train de cliquer + + if (Constraint_mode && Main_current_layer < 4) + { + if (is_preview) + goto single_pixel; + else + { + // Flood-fill the enclosing area + if (x= 0 && y >= 0 + && (color=Effect_function(x,y,color)) != (old_color=Read_pixel_from_current_layer(x,y)) + && (!((Stencil_mode) && (Stencil[old_color]))) + && (!((Mask_mode) && (Mask_table[Read_pixel_from_spare_screen(x,y)]))) + ) + { + short min_x,width,min_y,height; + short xx,yy; + + // determine area + switch(Main_current_layer) + { + case 0: + default: + // Full layer + min_x=0; + min_y=0; + width=Main_image_width; + height=Main_image_height; + break; + case 1: + case 2: + // Line + min_x=0; + min_y=y; + width=Main_image_width; + height=1; + break; + case 3: + // Segment + min_x=x / 48 * 48; + min_y=y; + width=48; + height=1; + break; + //case 4: + // // 8x8 + // min_x=x / 8 * 8; + // min_y=y / 8 * 8; + // width=8; + // height=8; + // break; + } + // Clip the bottom edge. + // (Necessary if image height is not a multiple) + if (min_y+height>=Main_image_height) + height=Main_image_height-min_y; + // Clip the right edge. + // (Necessary if image width is not a multiple) + if (min_x+width>=Main_image_width) + width=Main_image_width-min_x; + + for (yy=min_y; yy0) && (height>0) ) + Clear_brush(min_x-Main_offset_X, + min_y-Main_offset_Y, + 0,0, + width,height,0, + Main_image_width); + + if (Main_magnifier_mode != 0) + { + Compute_clipped_dimensions_zoom(&min_x,&min_y,&width,&height); + xx=min_x; + yy=min_y; + + if ( (width>0) && (height>0) ) + { + // Corrections dues au Zoom: + min_x=(min_x-Main_magnifier_offset_X)*Main_magnifier_factor; + min_y=(min_y-Main_magnifier_offset_Y)*Main_magnifier_factor; + height=min_y+(height*Main_magnifier_factor); + if (height>Menu_Y) + height=Menu_Y; + + Clear_brush_scaled(Main_X_zoom+min_x,min_y, + xx,yy, + width,height,0, + Main_image_width, + Horizontal_line_buffer); + } + } + // End of graphic feedback + } + } + return; + } switch (Paintbrush_shape) { case PAINTBRUSH_SHAPE_NONE : // No paintbrush. for colorpicker for example break; case PAINTBRUSH_SHAPE_POINT : // !!! TOUJOURS EN PREVIEW !!! + single_pixel: if ( (Paintbrush_X>=Limit_left) && (Paintbrush_X<=Limit_right) && (Paintbrush_Y>=Limit_top) @@ -2025,4 +2130,4 @@ void Brush_set_palette(T_Palette *palette) } } -*/ \ No newline at end of file +*/ diff --git a/src/buttons.c b/src/buttons.c index 5499fa46..ea9c9702 100644 --- a/src/buttons.c +++ b/src/buttons.c @@ -4473,23 +4473,27 @@ void Display_effect_state(short x, short y, char * label, byte state) 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); + Window_select_normal_button(x-23, y-5, 16, 16); else - Print_in_window(x+56,y,":OFF",MC_Black,MC_Light); + Window_unselect_normal_button(x-23, y-5, 16, 16); } +#define C2 92 + 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); + 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(C2+23, 24, "Stencil",Stencil_mode); + Display_effect_state(C2+23, 43, "Mask" ,Mask_mode); + Display_effect_state(C2+23, 62, "Sieve" ,Sieve_mode); + Display_effect_state(C2+23, 81, "Grid" ,Snap_mode); + Display_effect_state(C2+23,100, "Tiling" ,Tiling_mode); + + Display_effect_state(177+23,24, "8 bit" ,Constraint_mode); } @@ -4511,25 +4515,29 @@ void Button_Effects(void) 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(C2, 19, 16,16,"",0,1,Config_Key[SPECIAL_STENCIL_MODE][0]); // 6 + Window_set_normal_button(C2, 38, 16,16,"",0,1,Config_Key[SPECIAL_MASK_MODE][0]); // 7 + Window_set_normal_button(C2, 57, 16,16,"",0,1,Config_Key[SPECIAL_SIEVE_MODE][0]); // 8 + Window_set_normal_button(C2, 76, 16,16,"",0,1,Config_Key[SPECIAL_GRID_MODE][0]); // 9 + Window_set_normal_button(C2, 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 + + Window_set_normal_button(177, 19, 16,16,"",0,1,Config_Key[SPECIAL_FORMAT_CHECKER_MENU][0]); // 14 + 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_sprite(4,C2+1,20); + Display_effect_sprite(7,C2+1,39); + Display_effect_sprite(5,C2+1,58); + Display_effect_sprite(6,C2+1,77); + Display_effect_sprite(3,C2+1,96); Display_effect_states(); Print_in_window(12,117,"click: Left:Switch / Right:Edit",MC_Dark,MC_Light); @@ -4666,7 +4674,7 @@ void Button_Effects(void) { Button_Stencil_mode(); Hide_cursor(); - Display_effect_state(176,24,"Stencil",Stencil_mode); + Display_effect_state(C2+23,24,"Stencil",Stencil_mode); Display_cursor(); } else @@ -4682,7 +4690,7 @@ void Button_Effects(void) { Button_Mask_mode(); Hide_cursor(); - Display_effect_state(176,43,"Mask",Mask_mode); + Display_effect_state(C2+23,43,"Mask",Mask_mode); Display_cursor(); } else @@ -4698,7 +4706,7 @@ void Button_Effects(void) { Button_Sieve_mode(); Hide_cursor(); - Display_effect_state(176,62,"Sieve",Sieve_mode); + Display_effect_state(C2+23,62,"Sieve",Sieve_mode); Display_cursor(); } else @@ -4714,7 +4722,7 @@ void Button_Effects(void) { Button_Snap_mode(); Hide_cursor(); - Display_effect_state(176,81,"Grid",Snap_mode); + Display_effect_state(C2+23,81,"Grid",Snap_mode); Display_cursor(); } else @@ -4757,6 +4765,22 @@ void Button_Effects(void) Display_feedback_state(); Display_cursor(); break; + + + case 14: // Constraint checker/enforcer + if (Window_attribute1==LEFT_SIDE) + { + Button_Constraint_mode(); + Hide_cursor(); + Display_effect_state(177+23,24, "8 bit" ,Constraint_mode); + Display_cursor(); + } else { + Close_window(); + Display_cursor(); + // Contraint checker/enforcer menu + clicked_button = 11; + } + break; } } while (clicked_button!=11); @@ -4766,12 +4790,14 @@ void Button_Effects(void) 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)) + if (!(Shade_mode||Quick_shade_mode||Colorize_mode||Smooth_mode||Tiling_mode||Smear_mode||Stencil_mode||Mask_mode||Sieve_mode||Snap_mode||Constraint_mode)) Unselect_button(BUTTON_EFFECTS); Display_cursor(); } +#undef C2 + // Callback to display a font name in the list void Draw_one_font_name(word x, word y, word index, byte highlighted) { diff --git a/src/buttons.h b/src/buttons.h index eed881dc..4a755f5c 100644 --- a/src/buttons.h +++ b/src/buttons.h @@ -438,6 +438,9 @@ void Button_Tiling_mode(void); */ void Button_Tiling_menu(void); +void Button_Constraint_mode(void); +void Button_Constraint_menu(void); + /*! Callback for the command that turns off all drawaing effects. */ diff --git a/src/buttons_effects.c b/src/buttons_effects.c index 6f621a63..614be571 100644 --- a/src/buttons_effects.c +++ b/src/buttons_effects.c @@ -162,6 +162,19 @@ void Menu_tag_colors(char * window_title, byte * table, byte * mode, byte can_ca } +// Constaint enforcer/checker ------------------------------------------------ +void Button_Constraint_mode(void) +{ + Constraint_mode=!Constraint_mode; +} + + +void Button_Constraint_menu(void) +{ + +} + + //--------------------------------- Stencil ---------------------------------- void Button_Stencil_mode(void) { diff --git a/src/const.h b/src/const.h index 0c1bb43e..2dcb9f6a 100644 --- a/src/const.h +++ b/src/const.h @@ -120,6 +120,7 @@ enum FILE_FORMATS FORMAT_KCF, FORMAT_PAL, FORMAT_SCR, + FORMAT_CM5, FORMAT_XPM, FORMAT_MISC, ///< Must be last of enum: others formats recognized by SDL_image }; @@ -483,6 +484,10 @@ enum SPECIAL_ACTIONS SPECIAL_RUN_SCRIPT_9, SPECIAL_RUN_SCRIPT_10, SPECIAL_CYCLE_MODE, + + SPECIAL_FORMAT_CHECKER, + SPECIAL_FORMAT_CHECKER_MENU, + NB_SPECIAL_SHORTCUTS ///< Number of special shortcuts }; diff --git a/src/engine.c b/src/engine.c index 717232fd..85a40981 100644 --- a/src/engine.c +++ b/src/engine.c @@ -1292,6 +1292,11 @@ void Main_handler(void) Layer_activate((key_index-SPECIAL_LAYER1_TOGGLE)/2, RIGHT_SIDE); action++; break; + case SPECIAL_FORMAT_CHECKER: + C64_FLI_enforcer(); + action++; + break; + case SPECIAL_REPEAT_SCRIPT: #ifdef __ENABLE_LUA__ Repeat_script(); diff --git a/src/fileformats.c b/src/fileformats.c index 18baf90c..213b8ab1 100644 --- a/src/fileformats.c +++ b/src/fileformats.c @@ -2116,7 +2116,7 @@ void Load_GIF(T_IO_Context * context) // This a second layer/frame, or more. // Attempt to add a layer to current image current_layer++; - Set_layer(context, current_layer); + Set_loading_layer(context, current_layer); } number_LID++; @@ -2480,7 +2480,7 @@ void Save_GIF(T_IO_Context * context) GCE_block[3] |= 1; // Transparent color flag GCE_block[6] = context->Transparent_color; - Set_layer(context, current_layer); + Set_saving_layer(context, current_layer); if (current_layer == context->Nb_layers -1) { diff --git a/src/global.h b/src/global.h index 2b6b9ee8..220abbf9 100644 --- a/src/global.h +++ b/src/global.h @@ -726,6 +726,9 @@ GFX2_GLOBAL byte Mask_mode; /// Array of booleans. True if the indexed color is protected by the mask. GFX2_GLOBAL byte Mask_table[256]; +// -- Constraint enforcer +GFX2_GLOBAL byte Constraint_mode; + // -- Magnifier data #ifdef GLOBAL_VARIABLES diff --git a/src/graph.c b/src/graph.c index 1bd0d9fb..b31774e7 100644 --- a/src/graph.c +++ b/src/graph.c @@ -2920,6 +2920,15 @@ byte Effect_smooth(word x,word y,__attribute__((unused)) byte color) // l'écran feedback car il s'agit de ne } // pas modifier l'écran courant. +byte Effect_layer_copy(word x,word y,byte color) +{ + if (colorPages->Nb_layers) + { + return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[color]); + } + return Read_pixel_from_feedback_screen(x,y); +} + void Horizontal_grid_line(word x_pos,word y_pos,word width) { int x; @@ -2963,6 +2972,10 @@ byte Read_pixel_from_current_screen (word x,word y) #ifndef NOLAYERS byte depth; byte color; + + if (Main_current_layer==4) + return *(Main_backups->Pages->Image[Main_current_layer] + x+y*Main_image_width); + color = *(Main_screen+y*Main_image_width+x); if (color != Main_backups->Pages->Transparent_color) // transparent color return color; @@ -2976,7 +2989,9 @@ byte Read_pixel_from_current_screen (word x,word y) void Pixel_in_current_screen (word x,word y,byte color,int with_preview) { - #ifndef NOLAYERS + #ifndef NOLAYERS + if (!Constraint_mode) + { 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) @@ -2990,13 +3005,69 @@ void Pixel_in_current_screen (word x,word y,byte color,int with_preview) 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) + + } + else if ( Main_current_layer == 4) + { + if (color<4) + { + // Paste in layer + *(Main_backups->Pages->Image[Main_current_layer] + x+y*Main_image_width)=color; + // Paste in depth buffer + *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width)=color; + // Fetch pixel color from the target raster layer + color=*(Main_backups->Pages->Image[color] + x+y*Main_image_width); + // Draw that color on the visible image buffer + *(x+y*Main_image_width+Main_screen)=color; + + if (with_preview) Pixel_preview(x,y,color); - #endif + } + } + else if (Main_current_layer<4 && (Main_layers_visible & (1<<4))) + { + byte depth; + + // Paste in layer + *(Main_backups->Pages->Image[Main_current_layer] + x+y*Main_image_width)=color; + // Search depth + depth = *(Main_backups->Pages->Image[4] + x+y*Main_image_width); + + if ( depth == Main_current_layer) + { + // Draw that color on the visible image buffer + *(x+y*Main_image_width+Main_screen)=color; + + if (with_preview) + Pixel_preview(x,y,color); + } + } + else + { + byte depth; + + *(Main_backups->Pages->Image[Main_current_layer] + x+y*Main_image_width)=color; + depth = *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width); + 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; diff --git a/src/graph.h b/src/graph.h index 5347a2d6..d27ec686 100644 --- a/src/graph.h +++ b/src/graph.h @@ -38,6 +38,7 @@ 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); +byte Effect_layer_copy(word x,word y,byte color); void Display_foreback(void); diff --git a/src/help.c b/src/help.c index 34eec25c..577c2d91 100644 --- a/src/help.c +++ b/src/help.c @@ -32,7 +32,7 @@ #include #elif defined (__linux__) #include -#elif defined(__HAIKU__) +#elif defined (__HAIKU__) #include "haiku.h" #elif defined (__MINT__) #include @@ -69,7 +69,7 @@ word * Shortcut(word shortcut_number) return &(Config_Key[shortcut_number & 0xFF][0]); } -// Nom de la touche actuallement assignée à un raccourci d'après son numéro +// 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) { @@ -707,7 +707,7 @@ void Button_Stats(void) Print_in_window(146,35,TrueType_is_supported()?"TTF fonts":"no TTF fonts",STATS_DATA_COLOR,MC_Black); #if defined (__MINT__) - // Affichage de la mémoire restante + // Display free TT/ST RAM Print_in_window(10,43,"Free memory: ",STATS_TITLE_COLOR,MC_Black); freeRam=0; @@ -751,7 +751,7 @@ void Button_Stats(void) Print_in_window(18,51,buffer,STATS_DATA_COLOR,MC_Black); #else - // Affichage de la mémoire restante + // Display free RAM (generic) Print_in_window(10,51,"Free memory: ",STATS_TITLE_COLOR,MC_Black); freeRam = Memory_free(); @@ -780,10 +780,6 @@ void Button_Stats(void) 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; @@ -791,7 +787,6 @@ void Button_Stats(void) 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); @@ -808,10 +803,18 @@ void Button_Stats(void) mem_size=drvInfo.b_free*drvInfo.b_clsiz*drvInfo.b_secsiz; #else + #define NODISKSPACESUPPORT // 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 + + // Display free space + if (mem_size != 0) + { + sprintf(buffer,"Free space on %c:",Main_current_directory[0]); + Print_in_window(10,67,buffer,STATS_TITLE_COLOR,MC_Black); + if(mem_size > (100ULL*1024*1024*1024)) sprintf(buffer,"%u Gigabytes",(unsigned int)(mem_size/(1024*1024*1024))); @@ -822,6 +825,12 @@ void Button_Stats(void) else sprintf(buffer,"%u bytes",(unsigned int)mem_size); Print_in_window(146,67,buffer,STATS_DATA_COLOR,MC_Black); + } else { + #ifndef NODISKSPACESUPPORT + Print_in_window(10,67,"Disk full!",STATS_TITLE_COLOR,MC_Black); + #endif + #undef NODISKSPACESUPPORT + } // Affichage des informations sur l'image Print_in_window(10,83,"Picture info.:",STATS_TITLE_COLOR,MC_Black); diff --git a/src/helpfile.h b/src/helpfile.h index 6afbbcb5..ed722a8b 100644 --- a/src/helpfile.h +++ b/src/helpfile.h @@ -333,6 +333,12 @@ static const T_Help_table helptable_help[] = HELP_LINK (" 6 : %s", SPECIAL_LAYER6_TOGGLE) HELP_LINK (" 7 : %s", SPECIAL_LAYER7_TOGGLE) HELP_LINK (" 8 : %s", SPECIAL_LAYER8_TOGGLE) + HELP_TEXT ("") + HELP_LINK (" Format check : %s", SPECIAL_FORMAT_CHECKER) + HELP_LINK (" Format check menu: %s", SPECIAL_FORMAT_CHECKER_MENU) + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("") }; static const T_Help_table helptable_credits[] = { diff --git a/src/hotkeys.c b/src/hotkeys.c index bdf65ba4..3467b6b2 100644 --- a/src/hotkeys.c +++ b/src/hotkeys.c @@ -1641,6 +1641,22 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { true, SDLK_BACKQUOTE|MOD_CTRL, // Ctrl + `~ 0}, + {198, + "Format checker", + "Performs a format check on the", + "current image.", + "", + true, + 0, + 0}, + {199, + "Format checker menu", + "Allows you to setup the checks", + "performed by the format checker.", + "", + true, + 0, + 0}, }; word Ordering[NB_SHORTCUTS]= @@ -1843,4 +1859,6 @@ word Ordering[NB_SHORTCUTS]= SPECIAL_RUN_SCRIPT_9, SPECIAL_RUN_SCRIPT_10, SPECIAL_CYCLE_MODE, + SPECIAL_FORMAT_CHECKER, + SPECIAL_FORMAT_CHECKER_MENU, }; diff --git a/src/hotkeys.h b/src/hotkeys.h index 38006841..6ffc2de1 100644 --- a/src/hotkeys.h +++ b/src/hotkeys.h @@ -33,7 +33,7 @@ #endif #include -#define NB_SHORTCUTS 198 ///< Number of actions that can have a key combination associated to it. +#define NB_SHORTCUTS 200 ///< Number of actions that can have a key combination associated to it. /*** Types definitions and structs ***/ diff --git a/src/loadsave.c b/src/loadsave.c index d2a06de4..39cb81c2 100644 --- a/src/loadsave.c +++ b/src/loadsave.c @@ -125,6 +125,11 @@ void Save_C64(T_IO_Context *); // -- SCR (Amstrad CPC) void Save_SCR(T_IO_Context *); +// -- CM5 (Amstrad CPC) +void Test_CM5(T_IO_Context *); +void Load_CM5(T_IO_Context *); +void Save_CM5(T_IO_Context *); + // -- XPM (X PixMap) // Loading is done through SDL_Image void Save_XPM(T_IO_Context*); @@ -142,7 +147,7 @@ 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_IMAGES, "(all)", NULL, NULL, NULL, 0, 0, 0, "", "gif;png;bmp;pcx;pkm;lbm;iff;img;sci;scq;scf;scn;sco;pi1;pc1;cel;neo;kcf;pal;c64;koa;koala;fli;bml;cdu;prg;tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico;cm5"}, {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__ @@ -160,8 +165,9 @@ T_Format File_formats[] = { {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_C64, " c64", Test_C64, Load_C64, Save_C64, 0, 1, 0, "c64", "c64;koa;koala;fli;bml;cdu;prg"}, {FORMAT_SCR, " cpc", NULL, NULL, Save_SCR, 0, 0, 0, "cpc", "cpc;scr"}, + {FORMAT_CM5, " cm5", Test_CM5, Load_CM5, Save_CM5, 0, 0, 1, "cm5", "cm5"}, {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"}, }; @@ -427,7 +433,7 @@ void Pre_load(T_IO_Context *context, short width, short height, long file_size, context->Nb_layers=1; Main_current_layer=0; Main_layers_visible=1<<0; - Set_layer(context,0); + Set_loading_layer(context,0); // Remove previous comment, unless we load just a palette if (! Get_fileformat(context->Format)->Palette_only) @@ -1274,14 +1280,25 @@ void Init_context_surface(T_IO_Context * context, char *file_name, char *file_di } /// Function to call when need to switch layers. -void Set_layer(T_IO_Context *context, byte layer) +void Set_saving_layer(T_IO_Context *context, byte layer) +{ + context->Current_layer = layer; + + if (context->Type == CONTEXT_MAIN_IMAGE) + { + context->Target_address=Main_backups->Pages->Image[layer]; + } +} + +/// Function to call when need to switch layers. +void Set_loading_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)) + while (layer >= context->Nb_layers) { if (Add_layer(Main_backups, layer)) { @@ -1291,9 +1308,9 @@ void Set_layer(T_IO_Context *context, byte layer) break; } context->Nb_layers = Main_backups->Pages->Nb_layers; - Main_current_layer = layer; Main_layers_visible = (2<Target_address=Main_backups->Pages->Image[layer]; } } diff --git a/src/loadsave.h b/src/loadsave.h index 8fcd6376..ca05b6ef 100644 --- a/src/loadsave.h +++ b/src/loadsave.h @@ -215,7 +215,9 @@ 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); +void Set_loading_layer(T_IO_Context *context, byte layer); +/// Function to call when need to switch layers. +void Set_saving_layer(T_IO_Context *context, byte layer); // ================================================================= diff --git a/src/misc.c b/src/misc.c index afaa624b..5ace68d8 100644 --- a/src/misc.c +++ b/src/misc.c @@ -853,6 +853,28 @@ double Fround(double n, unsigned d) return floor(n * exp + 0.5) / exp; } +/// Count number of bits in a word (16bit). +/// Based on Wikipedia article for Hamming_weight, it's optimized +/// for cases when zeroes are more frequent. +int Popcount_word(word x) +{ + word count; + for (count=0; x; count++) + x &= x-1; + return count; +} + +/// Count number of bits in a dword (32bit). +/// Based on Wikipedia article for Hamming_weight, it's optimized +/// for cases when zeroes are more frequent. +int Popcount_dword(dword x) +{ + dword count; + for (count=0; x; count++) + x &= x-1; + return count; +} + // Fonction retournant le libellé d'une mode (ex: " 320x200") char * Mode_label(int mode) diff --git a/src/misc.h b/src/misc.h index aabeebfe..d65b2a8c 100644 --- a/src/misc.h +++ b/src/misc.h @@ -168,3 +168,6 @@ int Max(int a,int b); char* Mode_label(int mode); int Convert_videomode_arg(const char *argument); + +int Popcount_word(word x); +int Popcount_dword(dword x); diff --git a/src/miscfileformats.c b/src/miscfileformats.c index 7715cea1..a164c0e5 100644 --- a/src/miscfileformats.c +++ b/src/miscfileformats.c @@ -6,7 +6,7 @@ Copyright 2009 Petter Lindquist Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet - Copyright 2007 Adrien Destugues + Copyright 2007-2011 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or @@ -40,6 +40,7 @@ #include "sdlscreen.h" #include "struct.h" #include "windows.h" +#include "oldies.h" //////////////////////////////////// PAL //////////////////////////////////// // @@ -862,18 +863,18 @@ void Save_CEL(T_IO_Context * context) short x_pos; short y_pos; byte last_byte=0; - dword Utilisation[256]; // Table d'utilisation de couleurs + dword color_usage[256]; // Table d'utilisation de couleurs // On commence par compter l'utilisation de chaque couleurs - Count_used_colors(Utilisation); + Count_used_colors(color_usage); File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); if ((file=fopen(filename,"wb"))) { // On regarde si des couleurs >16 sont utilisées dans l'image - for (x_pos=16;((x_pos<256) && (!Utilisation[x_pos]));x_pos++); + for (x_pos=16;((x_pos<256) && (!color_usage[x_pos]));x_pos++); if (x_pos==256) { @@ -1180,10 +1181,10 @@ void Save_KCF(T_IO_Context * context) int pal_index; int color_index; int index; - dword Utilisation[256]; // Table d'utilisation de couleurs + dword color_usage[256]; // Table d'utilisation de couleurs // On commence par compter l'utilisation de chaque couleurs - Count_used_colors(Utilisation); + Count_used_colors(color_usage); File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); @@ -1192,7 +1193,7 @@ void Save_KCF(T_IO_Context * context) // Sauvegarde de la palette // On regarde si des couleurs >16 sont utilisées dans l'image - for (index=16;((index<256) && (!Utilisation[index]));index++); + for (index=16;((index<256) && (!color_usage[index]));index++); if (index==256) { @@ -2069,6 +2070,7 @@ void Save_NEO(T_IO_Context * context) } //////////////////////////////////// C64 //////////////////////////////////// + void Test_C64(T_IO_Context * context) { FILE* file; @@ -2084,14 +2086,17 @@ void Test_C64(T_IO_Context * context) file_size = File_length_file(file); switch (file_size) { - case 1000: // screen or color - case 1002: // (screen or color) + loadaddr + // 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 9000: // bitmap + ScreenRAM + case 9002: // bitmap + ScreenRAM + loadaddr case 10001: // multicolor case 10003: // multicolor + loadaddr + case 17472: // FLI (BlackMail) + case 17474: // FLI (BlackMail) + loadaddr + case 10277: // multicolor CDU-Paint + loadaddr File_error = 0; break; default: // then we don't know for now. @@ -2105,7 +2110,7 @@ void Test_C64(T_IO_Context * context) } } -void Load_C64_hires(T_IO_Context *context, byte *bitmap, byte *colors) +void Load_C64_hires(T_IO_Context *context, byte *bitmap, byte *screen_ram) { int cx,cy,x,y,c[4],pixel,color; @@ -2113,8 +2118,8 @@ void Load_C64_hires(T_IO_Context *context, byte *bitmap, byte *colors) { for(cx=0; cx<40; cx++) { - c[0]=colors[cy*40+cx]&15; - c[1]=colors[cy*40+cx]>>4; + c[0]=screen_ram[cy*40+cx]&15; + c[1]=screen_ram[cy*40+cx]>>4; for(y=0; y<8; y++) { pixel=bitmap[cy*320+cx*8+y]; @@ -2128,7 +2133,7 @@ void Load_C64_hires(T_IO_Context *context, byte *bitmap, byte *colors) } } -void Load_C64_multi(T_IO_Context *context, byte *bitmap, byte *colors, byte *nybble, byte background) +void Load_C64_multi(T_IO_Context *context, byte *bitmap, byte *screen_ram, byte *color_ram, byte background) { int cx,cy,x,y,c[4],pixel,color; c[0]=background&15; @@ -2136,9 +2141,9 @@ void Load_C64_multi(T_IO_Context *context, byte *bitmap, byte *colors, byte *nyb { 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; + c[1]=screen_ram[cy*40+cx]>>4; + c[2]=screen_ram[cy*40+cx]&15; + c[3]=color_ram[cy*40+cx]&15; for(y=0; y<8; y++) { @@ -2154,16 +2159,113 @@ void Load_C64_multi(T_IO_Context *context, byte *bitmap, byte *colors, byte *nyb } } +void Load_C64_fli(T_IO_Context *context, byte *bitmap, byte *screen_ram, byte *color_ram, byte *background) +{ + // Thanks to MagerValp for complement of specifications. + // + // background : length: 200 (+ padding 56) + // These are the BG colors for lines 0-199 (top to bottom) + // Low nybble: the color. + // High nybble: garbage. ignore it. + // color_ram : length: 1000 (+ padding 24) + // Color RAM. Contains one color per 4x8 block. + // There are 40x25 such blocks, arranged from top left to bottom + // right, starting in right direction. For each block there is one byte. + // Low nybble: the color. + // High nybble: garbage. ignore it. + // screen_ram : length: 8192 + // Screen RAMs. The s is important. + // This is actually 8 blocks of 1000 bytes, each separated by a filler of + // 24 bytes. Each byte contains data for a 4x1 pixel group, and a complete + // block will contain 40x25 of them. 40 is from left to right, and 25 is from + // top to bottom, spacing them 8 lines apart. + // The second block start at y=1, the third block starts at y=2, etc... + // Each byte contains 2 colors that *can* be used by the 4x1 pixel group: + // Low nybble: Color 1 + // High nybble: Color 2 + // + // bitmap : length: 8000 + // This is the final structure that refers to all others. It describes + // 160x200 pixels linearly, from top left to bottom right, starting in + // right direction. For each pixel, two bits say which color is displayed + // (So 4 pixels are described by the same byte) + // 00 Use the BG color of the current line (background[y]) + // 01 Use the Color 2 from the current 4x8 block of Screen RAM + // ((screen_ram[y/8][x/4] & 0xF0) >> 8) + // 10 Use the Color 1 from the current 4x8 block of Screen RAM + // (screen_ram[y/8][x/4] & 0x0F) + // 11 Use the color from Color RAM + // (color_ram[y/8][x/4] & 0x0F) + // + + int cx,cy,x,y,c[4]; + + for(y=0; y<200; y++) + { + for(x=0; x<160; x++) + { + Set_pixel(context, x,y,background[y]); + } + } + + Set_loading_layer(context, 1); + for(cy=0; cy<25; cy++) + { + for(cx=0; cx<40; cx++) + { + c[3]=color_ram[cy*40+cx]&15; + for(y=0; y<8; y++) + { + for(x=0; x<4; x++) + { + Set_pixel(context, cx*4+(3-x),cy*8+y,c[3]); + } + } + } + } + + Set_loading_layer(context, 2); + for(cy=0; cy<25; cy++) + { + for(cx=0; cx<40; cx++) + { + c[3]=color_ram[cy*40+cx]&15; + for(y=0; y<8; y++) + { + int pixel=bitmap[cy*320+cx*8+y]; + + c[0]=background[cy*8+y]&15; + c[1]=screen_ram[y*1024+cy*40+cx]>>4; + c[2]=screen_ram[y*1024+cy*40+cx]&15; + for(x=0; x<4; x++) + { + int color=c[(pixel&3)]; + pixel>>=2; + Set_pixel(context, cx*4+(3-x),cy*8+y,color); + } + } + } + } + Set_loading_layer(context, 3); + for(y=0; y<200; y++) + { + for(x=0; x<160; x++) + { + Set_pixel(context, x,y,16); + } + } +} + void Load_C64(T_IO_Context * context) { FILE* file; char filename[MAX_PATH_CHARACTERS]; long file_size; - int i; - byte background,hasLoadAddr=0; + byte 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"}; + enum c64_format {F_hires,F_multi,F_bitmap,F_fli}; + const char *c64_format_names[]={"Hires","Multicolor","Bitmap","FLI"}; + // Palette from http://www.pepto.de/projects/colorvic/ byte pal[48]={ @@ -2184,118 +2286,194 @@ void Load_C64(T_IO_Context * context) 0x6C, 0x5E, 0xB5, 0x95, 0x95, 0x95}; - byte bitmap[8000],colors[1000],nybble[1000]; + byte *file_buffer; + byte *bitmap, *screen_ram, *color_ram=NULL, *background=NULL; // Only pointers to existing data word width=320, height=200; + static byte dummy_screen[1000]; 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); + File_error=0; + file_size = File_length_file(file); - switch (file_size) + // Check for known file sizes + switch (file_size) + { + case 8000: // raw bitmap + case 8002: // raw bitmap with loadaddr + case 9000: // bitmap + ScreenRAM + case 9002: // bitmap + ScreenRAM + loadaddr + case 10001: // multicolor + case 10003: // multicolor + loadaddr + case 10277: // multicolor CDU-Paint + loadaddr + case 17472: // FLI (BlackMail) + case 17474: // FLI (BlackMail) + loadaddr + break; + + default: + File_error = 1; + fclose(file); + return; + } + // Load entire file in memory + file_buffer=(byte *)malloc(file_size); + if (!file_buffer) + { + File_error = 1; + fclose(file); + return; + } + if (!Read_bytes(file,file_buffer,file_size)) + { + File_error = 1; + free(file_buffer); + fclose(file); + return; + } + fclose(file); + + memset(dummy_screen,1,1000); + + 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; + bitmap=file_buffer+0; // length: 8000 + screen_ram=dummy_screen; break; - + case 8002: // raw bitmap with loadaddr hasLoadAddr=1; loadFormat=F_bitmap; + bitmap=file_buffer+2; // length: 8000 + screen_ram=dummy_screen; break; - case 9000: // bitmap + screen + case 9000: // bitmap + ScreenRAM hasLoadAddr=0; loadFormat=F_hires; + bitmap=file_buffer+0; // length: 8000 + screen_ram=file_buffer+8000; // length: 1000 break; - case 9002: // bitmap + screen + loadaddr + case 9002: // bitmap + ScreenRAM + loadaddr hasLoadAddr=1; loadFormat=F_hires; + bitmap=file_buffer+2; // length: 8000 + screen_ram=file_buffer+8002; // length: 1000 break; case 10001: // multicolor hasLoadAddr=0; loadFormat=F_multi; + context->Ratio = PIXEL_WIDE; + bitmap=file_buffer+0; // length: 8000 + screen_ram=file_buffer+8000; // length: 1000 + color_ram=file_buffer+9000; // length: 1000 + background=file_buffer+10000; // only 1 break; case 10003: // multicolor + loadaddr hasLoadAddr=1; loadFormat=F_multi; + context->Ratio = PIXEL_WIDE; + bitmap=file_buffer+2; // length: 8000 + screen_ram=file_buffer+8002; // length: 1000 + color_ram=file_buffer+9002; // length: 1000 + background=file_buffer+10002; // only 1 break; - - default: // then we don't know what it is. - File_error = 1; + case 10277: // multicolor CDU-Paint + loadaddr + hasLoadAddr=1; + loadFormat=F_multi; + context->Ratio = PIXEL_WIDE; + // 273 bytes of display routine + bitmap=file_buffer+275; // length: 8000 + screen_ram=file_buffer+8275; // length: 1000 + color_ram=file_buffer+9275; // length: 1000 + background=file_buffer+10275; // only 1 + break; + + case 17472: // FLI (BlackMail) + hasLoadAddr=0; + loadFormat=F_fli; + context->Ratio = PIXEL_WIDE; + background=file_buffer+0; // length: 200 (+ padding 56) + color_ram=file_buffer+256; // length: 1000 (+ padding 24) + screen_ram=file_buffer+1280; // length: 8192 + bitmap=file_buffer+9472; // length: 8000 + break; + + case 17474: // FLI (BlackMail) + loadaddr + hasLoadAddr=1; + loadFormat=F_fli; + context->Ratio = PIXEL_WIDE; + background=file_buffer+2; // length: 200 (+ padding 56) + color_ram=file_buffer+258; // length: 1000 (+ padding 24) + screen_ram=file_buffer+1282; // length: 8192 + bitmap=file_buffer+9474; // length: 8000 + break; + + default: + File_error = 1; + free(file_buffer); + return; } + if (context->Ratio == PIXEL_WIDE) + width=160; + + // Write detailed format in comment + strcpy(context->Comment, c64_format_names[loadFormat]); + if (hasLoadAddr) + { + // get load address + word load_addr; + load_addr = file_buffer[0] | (file_buffer[1] << 8); + sprintf(context->Comment+strlen(context->Comment),", load at $%04.4X",load_addr); + } + else + { + sprintf(context->Comment+strlen(context->Comment),", no addr"); + } + + Pre_load(context, width, height, file_size, FORMAT_C64, context->Ratio,0); // Do this as soon as you can + memcpy(context->Palette,pal,48); // this set the software palette for grafx2 + // Transparent color "16" is a dark grey that is distinguishable + // from black, but darker than normal colors. + context->Palette[16].R=20; + context->Palette[16].G=20; + context->Palette[16].B=20; + 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; + context->Transparent_color=16; - Read_bytes(file,bitmap,8000); - - if (file_size>8002) - Read_bytes(file,colors,1000); - else + if(loadFormat==F_fli) { - for(i=0;i<1000;i++) - { - colors[i]=1; - } + Load_C64_fli(context,bitmap,screen_ram,color_ram,background); } - - if(width==160) + else + if(loadFormat==F_multi) { - Read_bytes(file,nybble,1000); - Read_byte(file,&background); - Load_C64_multi(context,bitmap,colors,nybble,background); + Load_C64_multi(context,bitmap,screen_ram,color_ram,*background); } else { - Load_C64_hires(context,bitmap,colors); + Load_C64_hires(context,bitmap,screen_ram); } File_error = 0; - fclose(file); + + free(file_buffer); + } else File_error = 1; @@ -2324,17 +2502,17 @@ int Save_C64_window(byte *saveWhat, byte *loadAddr) }; 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); + Window_set_normal_button(110,100,80,15,"Save",1,1,SDLK_RETURN); // 1 + Window_set_normal_button(10,100,80,15,"Cancel",1,1,SDLK_ESCAPE); // 2 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); + what=Window_set_dropdown_button(10,28,90,15,70,what_label[*saveWhat],1, 0, 1, LEFT_SIDE,0); // 3 Window_dropdown_clear_items(what); for (i=0; iFile_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"); @@ -2608,7 +2837,7 @@ void Save_C64(T_IO_Context * context) if (context->Width==320) File_error = Save_C64_hires(context,filename,saveWhat,loadAddr); else - File_error = Save_C64_multi(context,filename,saveWhat,loadAddr); + File_error = Save_C64_fli(filename,saveWhat,loadAddr); } @@ -2699,3 +2928,234 @@ void Save_SCR(T_IO_Context * context) File_error = 0; } + +// CM5 - Amstrad CPC "Mode 5" picture +// This is a format designed by SyX. There is one .SCR file in the usual amstrad format, +// and a .CM5 file with the palette, which varies over time. + +void Test_CM5(T_IO_Context * context) +{ + // check cm5 file size == 2049 bytes + FILE *file; + char filename[MAX_PATH_CHARACTERS]; + long file_size; + + Get_full_filename(filename, context->File_name, context->File_directory); + + File_error = 1; + + if ((file = fopen(filename, "rb"))) + { + file_size = File_length_file(file); + if (file_size == 2049) + File_error = 0; + } + + // TODO: check existence of a .SCR file with the same name +} + + +void Load_CM5(T_IO_Context* context) +{ + // Ensure "8bit" constraint mode is switched on + // Set palette to the CPC hardware colors + // Load the palette data to the 4 colorlayers + FILE *file; + char filename[MAX_PATH_CHARACTERS]; + byte value = 0; + int mod; + short line = 0; + int tx, ty; + byte buffer[48*6/4]; + + Get_full_filename(filename, context->File_name, context->File_directory); + + if (!(file = fopen(filename, "rb"))) + { + File_error = 1; + return; + } + + Pre_load(context, 48*6, 256, 2049, FORMAT_CM5, PIXEL_SIMPLE, 0); + context->Width=48*6; + context->Height=256; + + // Setup the palette (amstrad hardware palette) + context->Palette[0x54].R = 0; context->Palette[0x54].G = 2; context->Palette[0x54].B = 1; + context->Palette[0x44].R = 0; context->Palette[0x44].G = 2; context->Palette[0x44].B = 0x6B; + context->Palette[0x55].R = 0x0C; context->Palette[0x55].G = 2; context->Palette[0x55].B = 0xF4; + context->Palette[0x5C].R = 0x6C; context->Palette[0x5C].G = 2; context->Palette[0x5C].B = 1; + context->Palette[0x58].R = 0x69; context->Palette[0x58].G = 2; context->Palette[0x58].B = 0x68; + context->Palette[0x5D].R = 0x6C; context->Palette[0x5D].G = 2; context->Palette[0x5D].B = 0xF2; + context->Palette[0x4C].R = 0xF3; context->Palette[0x4C].G = 5; context->Palette[0x4C].B = 6; + context->Palette[0x45].R = 0xF0; context->Palette[0x45].G = 2; context->Palette[0x45].B = 0x68; + context->Palette[0x4D].R = 0xF3; context->Palette[0x4D].G = 2; context->Palette[0x4D].B = 0xF4; + context->Palette[0x56].R = 2; context->Palette[0x56].G = 0x78; context->Palette[0x56].B = 1; + context->Palette[0x46].R = 0; context->Palette[0x46].G = 0x78; context->Palette[0x46].B = 0x68; + context->Palette[0x57].R = 0xC; context->Palette[0x57].G = 0x7B; context->Palette[0x57].B = 0xF4; + context->Palette[0x5E].R = 0x6E; context->Palette[0x5E].G = 0x7B; context->Palette[0x5E].B = 1; + context->Palette[0x40].R = 0x6E; context->Palette[0x40].G = 0x7D; context->Palette[0x40].B = 0x6B; + context->Palette[0x5F].R = 0x6E; context->Palette[0x5F].G = 0x7B; context->Palette[0x5F].B = 0xF6; + context->Palette[0x4E].R = 0xF3; context->Palette[0x4E].G = 0x7D; context->Palette[0x4E].B = 0xD; + context->Palette[0x47].R = 0xF3; context->Palette[0x47].G = 0x7D; context->Palette[0x47].B = 0x6B; + context->Palette[0x4F].R = 0xFA; context->Palette[0x4F].G = 0x80; context->Palette[0x4F].B = 0xF9; + context->Palette[0x52].R = 2; context->Palette[0x52].G = 0xF0; context->Palette[0x52].B = 1; + context->Palette[0x42].R = 0; context->Palette[0x42].G = 0xF3; context->Palette[0x42].B = 0x6B; + context->Palette[0x53].R = 0xF; context->Palette[0x53].G = 0xF3; context->Palette[0x53].B = 0xF2; + context->Palette[0x5A].R = 0x71; context->Palette[0x5A].G = 0xF5; context->Palette[0x5A].B = 4; + context->Palette[0x59].R = 0x71; context->Palette[0x59].G = 0xF3; context->Palette[0x59].B = 0x6B; + context->Palette[0x5B].R = 0x71; context->Palette[0x5B].G = 0xF3; context->Palette[0x5B].B = 0xF4; + context->Palette[0x4A].R = 0xF3; context->Palette[0x4A].G = 0xF3; context->Palette[0x4A].B = 0xD; + context->Palette[0x43].R = 0xF3; context->Palette[0x43].G = 0xF3; context->Palette[0x43].B = 0x6D; + context->Palette[0x4B].R = 255; context->Palette[0x4B].G = 0xF3; context->Palette[0x4B].B = 0xF9; + + Palette_loaded(context); + + if (Constraint_mode != 1) + Constraint_mode = 1; + + if (Read_byte(file, &value)!=1) + File_error = 2; + + Set_loading_layer(context, 0); + for(ty=0; tyHeight; ty++) + for(tx=0; txWidth; tx++) + { + Set_pixel(context, tx, ty, value); + } + // Fill layer with color we just read + + while(Read_byte(file, &value) == 1) + { + switch(mod) + { + case 0: + // This is color for layer 1 + Set_loading_layer(context, 1); + for(tx=0; txWidth; tx++) + Set_pixel(context, tx, line, value); + break; + case 1: + // This is color for layer 2 + Set_loading_layer(context, 2); + for(tx=0; txWidth; tx++) + Set_pixel(context, tx, line, value); + break; + default: + // This is color for a block in layer 4 + Set_loading_layer(context, 3); + for(tx=(mod-2)*48; tx<(mod-1)*48; tx++) + Set_pixel(context, tx, line, value); + break; + } + mod = mod + 1; + if (mod > 7) + { + mod = 0; + line ++; + } + } + + fclose(file); + + // Load the pixeldata to the 5th layer + filename[strlen(filename) - 3] = 0; + strcat(filename,"gfx"); + if (!(file = fopen(filename, "rb"))) + { + File_error = 1; + return; + } + + Set_loading_layer(context, 4); + + for (ty = 0; ty < 256; ty++) + { + Read_bytes(file, buffer, 48*6/4); + for (tx = 0; tx < 48*6; tx+=4) + { + Set_pixel(context, tx+0, ty, 3-(((buffer[tx/4]&0x80) >> 7) |((buffer[tx/4]&0x8)>>2))); + Set_pixel(context, tx+1, ty, 3-(((buffer[tx/4]&0x40) >> 6) |((buffer[tx/4]&0x4)>>1))); + Set_pixel(context, tx+2, ty, 3-(((buffer[tx/4]&0x20) >> 5) |((buffer[tx/4]&0x2)>>0))); + Set_pixel(context, tx+3, ty, 3-(((buffer[tx/4]&0x10) >> 4) |((buffer[tx/4]&0x1)<<1))); + } + } + + fclose(file); + +} + + +void Save_CM5(T_IO_Context* context) +{ + char filename[MAX_PATH_CHARACTERS]; + FILE* file; + int tx, ty; + + + Get_full_filename(filename, context->File_name, context->File_directory); + // TODO: Check picture has 5 layers + // TODO: Check the constraints on the layers + // Layer 1 : 1 color Only + // Layer 2 and 3 : 1 color/line + // Layer 4 : 1 color / 48x1 block + // TODO: handle filesize + + if (!(file = fopen(filename,"wb"))) + { + File_error = 1; + return; + } + + // Write layer 0 + Set_saving_layer(context, 0); + Write_byte(file, Get_pixel(context, 0, 0)); + for(ty = 0; ty < 256; ty++) + { + Set_saving_layer(context, 1); + Write_byte(file, Get_pixel(context, 0, ty)); + Set_saving_layer(context, 2); + Write_byte(file, Get_pixel(context, 0, ty)); + Set_saving_layer(context, 3); + for(tx = 0; tx < 6; tx++) + { + Write_byte(file, Get_pixel(context, tx*48, ty)); + } + } + + fclose(file); + + // Now the pixeldata + filename[strlen(filename) - 3] = 0; + strcat(filename,"gfx"); + if (!(file = fopen(filename, "wb"))) + { + File_error = 2; + return; + } + + Set_saving_layer(context, 4); + + for (ty = 0; ty < 256; ty++) + { + for (tx = 0; tx < 48*6; tx+=4) + { + byte code = 0; + byte pixel; + + pixel = 3-Get_pixel(context, tx+3, ty); + code |= (pixel&2)>>1 | ((pixel & 1)<<4); + pixel = 3-Get_pixel(context, tx+2, ty); + code |= ((pixel&2)<<0) | ((pixel & 1)<<5); + pixel = 3-Get_pixel(context, tx+1, ty); + code |= ((pixel&2)<<1) | ((pixel & 1)<<6); + pixel = 3-Get_pixel(context, tx, ty); + code |= ((pixel&2)<<2) | ((pixel & 1)<<7); + Write_byte(file, code); + } + } + + fclose(file); + File_error = 0; + +} diff --git a/src/oldies.c b/src/oldies.c new file mode 100644 index 00000000..9be48122 --- /dev/null +++ b/src/oldies.c @@ -0,0 +1,411 @@ +/* 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 +#include +#include "struct.h" +#include "global.h" +#include "errors.h" +#include "misc.h" +#include "palette.h" + +void Pixel_in_layer(word x,word y, byte layer, byte color) +{ + *((y)*Main_image_width+(x)+Main_backups->Pages->Image[layer])=color; +} + +byte C64_FLI(byte *bitmap, byte *screen_ram, byte *color_ram, byte *background) +{ + word used_colors[200][40]; + word block_used_colors[25][40]; + word line_used_colors[200]; + byte used_colors_count[200][40]; + dword usage[16]; + word x,y,row,col; + int i; + byte line_color[200]; + byte block_color[25][40]; + word best_color_count; + byte best_color; + const byte no_color=16; + + // Prerequisites + if (Main_backups->Pages->Nb_layers < 3) + return 1; + if (Main_image_width != 160 || Main_image_height != 200) + return 2; + + memset(used_colors,0,200*40*sizeof(word)); + memset(block_used_colors,0,25*40*sizeof(word)); + memset(line_used_colors,0,200*sizeof(word)); + memset(used_colors_count,0,200*40*sizeof(byte)); + + // Initialize these as "unset" + memset(line_color,no_color,200*sizeof(byte)); + memset(block_color,no_color,25*40*sizeof(byte)); + + // Examine all 4-pixel blocks to fill used_colors[][] + for (row=0;row<200;row++) + { + for (col=0;col<40;col++) + { + for (x=0;x<4;x++) + { + byte c=*((row)*Main_image_width+(col*4+x)+Main_backups->Pages->Image[2]); + used_colors[row][col] |= 1<Pages->Image[0]); + if (c<16) + { + line_color[row]=c; + for (col=0;col<40;col++) + { + // Remove that color from the sets + used_colors[row][col] &= ~(1<Pages->Image[1]); + if (c<16) + { + block_color[row/8][col]=c; + // Remove that color from the sets + for (y=0; y<8;y++) + used_colors[row+y][col] &= ~(1<best_color_count) + { + best_color_count=usage[i]; + best_color=i; + } + } + line_color[row]=best_color; + + // Remove that color from the sets + for (col=0;col<40;col++) + { + if (used_colors[row][col] & (1<2) + { + filter &= used_colors[row+y][col]; + + for (i=0; i<16; i++) + { + if (used_colors[row+y][col] & (1<best_color_count) + { + best_color_count=usage[i]; + best_color=i; + } + } + } + } + block_color[row/8][col]=best_color; + + // Remove that color from the sets + for (y=0;y<8;y++) + { + if (used_colors[row+y][col] & (1<15) + c1=16; + if (c2>15) + c2=16; + + // Output Screen RAMs + if (screen_ram!=NULL) + screen_ram[y*1024+row*40+col] = (c1&15) | ((c2&15)<<4); + + // Output bitmap + if (bitmap!=NULL) + { + for(x=0; x<4; x++) + { + byte bits; + byte c=*((row*8+y)*Main_image_width+(col*4+x)+Main_backups->Pages->Image[2]); + + if (c==line_color[row*8+y]) + // BG color + bits=0; + else if (c==block_color[row][col]) + // block color + bits=3; + else if (c==c1) + // Color 1 + bits=2; + else if (c==c2) + // Color 2 + bits=1; + else // problem + bits=0; + // clear target bits + //bitmap[row*320+col*8+y] &= ~(3<<((3-x)*2)); + // set them + bitmap[row*320+col*8+y] |= bits<<((3-x)*2); + } + } + } + } + } + //memset(background,3,200); + //memset(color_ram,5,8000); + //memset(screen_ram,(9<<4) | 7,8192); + + return 0; + +} + +byte C64_FLI_enforcer(void) +{ + byte background[200]; + byte bitmap[8000]; + byte screen_ram[8192]; + byte color_ram[1000]; + + int row, col, x, y; + byte c[4]; + + // Checks + if (Main_image_width != 160) + return 1; + if (Main_image_height != 200) + return 1; + if (Main_backups->Pages->Nb_layers != 4) + return 2; + + Backup_layers(1<<3); + + memset(bitmap,0,8000); + memset(background,0,200); + memset(color_ram,0,1000); + memset(screen_ram,0,8192); + C64_FLI(bitmap, screen_ram, color_ram, background); + + for(row=0; row<25; row++) + { + for(col=0; col<40; col++) + { + c[3]=color_ram[row*40+col]&15; + for(y=0; y<8; y++) + { + int pixel=bitmap[row*320+col*8+y]; + + c[0]=background[row*8+y]&15; + c[1]=screen_ram[y*1024+row*40+col]>>4; + c[2]=screen_ram[y*1024+row*40+col]&15; + for(x=0; x<4; x++) + { + int color=c[(pixel&3)]; + pixel>>=2; + Pixel_in_layer(col*4+(3-x),row*8+y,3,color); + } + } + } + } + End_of_modification(); + + // Visible feedback: + + // If the "check" layer was visible, manually update the whole thing + if (Main_layers_visible & (1<<3)) + { + Hide_cursor(); + Redraw_layered_image(); + Display_all_screen(); + Display_layerbar(); + Display_cursor(); + } + else + // Otherwise, simply toggle the layer visiblity + Layer_activate(3,RIGHT_SIDE); + + + return 0; +} \ No newline at end of file diff --git a/src/oldies.h b/src/oldies.h new file mode 100644 index 00000000..8476775f --- /dev/null +++ b/src/oldies.h @@ -0,0 +1,24 @@ +/* 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 +*/ + +byte C64_FLI(byte *bitmap, byte *screen_ram, byte *color_ram, byte *background); + +byte C64_FLI_enforcer(void); + diff --git a/src/pages.c b/src/pages.c index 066eaa92..b7901bb8 100644 --- a/src/pages.c +++ b/src/pages.c @@ -197,25 +197,47 @@ void Redraw_layered_image(void) { #ifndef NOLAYERS // Re-construct the image with the visible layers - byte layer; + byte layer=0; // First layer - for (layer=0; layerPages->Nb_layers; layer++) + if (Constraint_mode && Main_layers_visible & (1<<4)) { - 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; + layer = *(Main_backups->Pages->Image[4]+i); + Main_visible_image.Image[i]=*(Main_backups->Pages->Image[layer]+i); + } + + // Copy it to the depth buffer + memcpy(Main_visible_image_depth_buffer.Image, + Main_backups->Pages->Image[4], + Main_image_width*Main_image_height); + + // Next + layer= (1<<4)+1; + } + else + { + 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) diff --git a/src/struct.h b/src/struct.h index 75e610f2..ce507262 100644 --- a/src/struct.h +++ b/src/struct.h @@ -372,11 +372,11 @@ typedef struct 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 +// 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 +// 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. @@ -401,11 +401,11 @@ typedef struct T_Page byte Transparent_color; ///< Index of transparent color. 0 to 255. byte Nb_layers; ///< Number of layers #if __GNUC__ < 3 - byte * Image[0]; + // gcc2 doesn't suport [], but supports [0] which does the same thing. + byte * Image[0]; ///< Pixel data for the (first layer of) image. #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;