diff --git a/src/brush.c b/src/brush.c index b69338ca..a2ace38f 100644 --- a/src/brush.c +++ b/src/brush.c @@ -1266,18 +1266,18 @@ void Capture_brush_with_lasso(int vertices, short * points,short clear) Pixel_figure=Pixel_figure_in_brush; memset(Brush,Back_color,(long)Brush_width*Brush_height); - Polyfill_general(vertices,points,~Back_color); + Polyfill_general(vertices,points,xor_lut[Back_color]); // On retrace les bordures du lasso: for (temp=1; temp=Limit_top && y<=Limit_visible_bottom) for (x=x_pos-1;x=Limit_left && x<=Limit_visible_right) - Pixel_preview(x,y,~Read_pixel(x-Main_offset_X,y-Main_offset_Y)); + Pixel_preview(x,y,xor_lut[Read_pixel(x-Main_offset_X,y-Main_offset_Y)]); Update_part_of_screen(x_pos-1, y_pos-1, 2, 2); } diff --git a/src/buttons.c b/src/buttons.c index 78780a4b..f9755195 100644 --- a/src/buttons.c +++ b/src/buttons.c @@ -956,10 +956,10 @@ void Button_Settings(void) {"Coordinates:",1,&(selected_config.Coords_rel),0,1,0,Lookup_Coords}, {"Separate colors:",1,&(selected_config.Separate_colors),0,1,0,Lookup_YesNo}, {"Safety colors:",1,&(selected_config.Safety_colors),0,1,0,Lookup_YesNo}, - {"Grid XOR color:",1,&(selected_config.Grid_XOR_color),0,255,3,NULL}, {"Sync views:",1,&(selected_config.Sync_views),0,1,0,Lookup_YesNo}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, + {"",0,NULL,0,0,0,NULL}, {" --- Input ---",0,NULL,0,0,0,NULL}, {"Scrollbar speed",0,NULL,0,0,0,NULL}, diff --git a/src/global.h b/src/global.h index 276bc503..a3beff6b 100644 --- a/src/global.h +++ b/src/global.h @@ -334,6 +334,8 @@ GFX2_GLOBAL long Main_edits_since_safety_backup; GFX2_GLOBAL Uint32 Main_time_of_safety_backup; /// Letter prefix for the filenames of safety backups. a or b GFX2_GLOBAL byte Main_safety_backup_prefix; +/// Lookup table for XOR effects, pointing each color to the most different one +GFX2_GLOBAL byte xor_lut[256]; // -- Spare page data diff --git a/src/graph.c b/src/graph.c index 15e6364f..9001eb84 100644 --- a/src/graph.c +++ b/src/graph.c @@ -1100,8 +1100,8 @@ void Fill_general(byte fill_color) (x_pos<=Limit_right) && (y_pos>=Limit_top) && (y_pos<=Limit_bottom) ) - Pixel_preview(x_pos,y_pos,~Read_pixel(x_pos-Main_offset_X, - y_pos-Main_offset_Y)); + Pixel_preview(x_pos,y_pos,xor_lut[Read_pixel(x_pos-Main_offset_X, + y_pos-Main_offset_Y)]); } // Affichage d'un point pour une preview en xor additif @@ -1114,7 +1114,7 @@ void Fill_general(byte fill_color) (x_pos<=Limit_right) && (y_pos>=Limit_top) && (y_pos<=Limit_bottom) ) - Pixel_preview(x_pos,y_pos,~Main_screen[x_pos+y_pos*Main_image_width]); + Pixel_preview(x_pos,y_pos,xor_lut[Main_screen[x_pos+y_pos*Main_image_width]]); } @@ -2884,7 +2884,7 @@ void Horizontal_grid_line(word x_pos,word y_pos,word width) int x; for (x=!(x_pos&1);xDefault_palette[Gfx->Color[color_index]]); } -byte xor_lut[256]; -int Diff(int i, int j) { - // TODO try out different difference operators to see if the results get - // better (weight the components, use ² instead of abs, use HSL or XYZ or ) - int diff = 0; - diff += abs(Main_palette[i].R - Main_palette[j].R); - diff += abs(Main_palette[i].G - Main_palette[j].G); - diff += abs(Main_palette[i].B - Main_palette[j].B); - - return diff; -} - -void compute_xor_table() -{ - int i; - byte found; - - // Initialize the table with some "random" values - for(i = 0; i < 256; i++) - { - xor_lut[i] = 255 - i; - } - - do { - // Find the smallest difference in the table - int mindiff = INT_MAX; - int idx; - for(i = 0; i < 256; i++) - { - int diff = Diff(i, xor_lut[i]); - if (diff < mindiff) { - idx = i; - mindiff = diff; - } - } - - // Try to pair these two colors better - found = 0; - for(i = 0; i < 256; i++) - { - // diffs before the swap - int before = Diff(idx, xor_lut[idx]) + Diff(i, xor_lut[i]); - - // diffs after the swap - int after = Diff(idx, xor_lut[i]) + Diff(i, xor_lut[idx]); - - if (after > before) - { - // Swapping these colors get us something "more different". Do it ! - byte idx2 = xor_lut[i]; - byte i2 = xor_lut[idx]; - - xor_lut[i] = i2; - xor_lut[i2] = i; - xor_lut[idx] = idx2; - xor_lut[idx2] = idx; - - found = 1; - break; - } - } - } while(found); -} diff --git a/src/pxdouble.c b/src/pxdouble.c index 269ffaea..b3dcdaa9 100644 --- a/src/pxdouble.c +++ b/src/pxdouble.c @@ -134,7 +134,7 @@ void Horizontal_XOR_line_double(word x_pos,word y_pos,word width) int x; for (x=0;x0;i--) { - *dest=*(dest+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=~*dest; + *dest=*(dest+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=xor_lut[*dest]; dest+=VIDEO_LINE_WIDTH*ZOOMY; } } diff --git a/src/pxquad.c b/src/pxquad.c index e9778a51..a74f090d 100644 --- a/src/pxquad.c +++ b/src/pxquad.c @@ -149,7 +149,7 @@ void Horizontal_XOR_line_quad(word x_pos,word y_pos,word width) int x; for (x=0;x0;i--) { - *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*(dest)=~*(dest); + *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*(dest)=xor_lut[*(dest)]; dest+=VIDEO_LINE_WIDTH*ZOOMY; } } diff --git a/src/pxsimple.c b/src/pxsimple.c index d00fa142..1e4a95d7 100644 --- a/src/pxsimple.c +++ b/src/pxsimple.c @@ -119,7 +119,7 @@ void Horizontal_XOR_line_simple(word x_pos,word y_pos,word width) int x; for (x=0;x0;i--) { - *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=~*(dest); + *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=xor_lut[*(dest)]; dest+=VIDEO_LINE_WIDTH*ZOOMY; } } diff --git a/src/pxtriple.c b/src/pxtriple.c index 6ca00f91..bcca69dc 100644 --- a/src/pxtriple.c +++ b/src/pxtriple.c @@ -140,7 +140,7 @@ void Horizontal_XOR_line_triple(word x_pos,word y_pos,word width) int x; for (x=0;x0;i--) { - *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=~*dest; + *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=xor_lut[*dest]; dest+=VIDEO_LINE_WIDTH*ZOOMY; } } diff --git a/src/pxwide.c b/src/pxwide.c index 761932e6..90761fc7 100644 --- a/src/pxwide.c +++ b/src/pxwide.c @@ -129,7 +129,7 @@ void Horizontal_XOR_line_wide(word x_pos,word y_pos,word width) int x; for (x=0;x0;i--) { - *dest=*(dest+1)=~*dest; + *dest=*(dest+1)=xor_lut[*dest]; dest+=VIDEO_LINE_WIDTH*ZOOMY; } } diff --git a/src/pxwide2.c b/src/pxwide2.c index 868ef942..c8e7be43 100644 --- a/src/pxwide2.c +++ b/src/pxwide2.c @@ -137,7 +137,7 @@ void Horizontal_XOR_line_wide2(word x_pos,word y_pos,word width) int x; for (x=0;x0;i--) { - *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*(dest)=~*(dest); + *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*(dest)=xor_lut[*(dest)]; dest+=VIDEO_LINE_WIDTH*ZOOMY; } } diff --git a/src/readini.c b/src/readini.c index 0f0f0ac2..91083691 100644 --- a/src/readini.c +++ b/src/readini.c @@ -849,14 +849,6 @@ int Load_INI(T_Config * conf) else conf->Font_file = strdup("font_Dpaint.png"); - conf->Grid_XOR_color=255; - // Optional, XOR color for grid overlay (>2.0) - if (!Load_INI_get_values (file,buffer,"Grid_XOR_color",1,values)) - { - if ((values[0]>0) && (values[0]<=255)) - conf->Grid_XOR_color=values[0]; - } - // Optional, "fake hardware zoom" factor (>2.1) if (!Load_INI_get_values (file, buffer,"Pixel_ratio",1,values)) { diff --git a/src/saveini.c b/src/saveini.c index fcd00a7c..46b3f607 100644 --- a/src/saveini.c +++ b/src/saveini.c @@ -655,10 +655,6 @@ int Save_INI(T_Config * conf) if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Font_file",conf->Font_file))) goto Erreur_Retour; - values[0]=(conf->Grid_XOR_color); - if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Grid_XOR_color",1,values,0))) - goto Erreur_Retour; - values[0]=(Pixel_ratio); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Pixel_ratio",1,values,0))) { DEBUG("saving pixel ratio",return_code); diff --git a/src/struct.h b/src/struct.h index 0bd4cb57..a58deed8 100644 --- a/src/struct.h +++ b/src/struct.h @@ -363,7 +363,6 @@ typedef struct int Window_pos_y; ///< Last window y position (9999 if unsupportd/irrelevant for the platform) word Double_click_speed; ///< Maximum delay for double-click, in ms. word Double_key_speed; ///< Maximum delay for double-keypress, in ms. - byte Grid_XOR_color; ///< XOR value to apply for grid color. byte Right_click_colorpick; ///< Boolean, true to enable a "tablet" mode, where RMB acts as instant colorpicker byte Sync_views; ///< Boolean, true when the Main and Spare should share their viewport settings. byte Stylus_mode; ///< Boolean, true to tweak some tools (eg:Curve) for single-button stylus. diff --git a/src/windows.c b/src/windows.c index 2f2e9e19..42bc54c3 100644 --- a/src/windows.c +++ b/src/windows.c @@ -2956,82 +2956,153 @@ void Remap_screen_after_menu_colors_change(void) } +static int Diff(int i, int j) { + int dr = Main_palette[i].R - Main_palette[j].R; + int dg = Main_palette[i].G - Main_palette[j].G; + int db = Main_palette[i].B - Main_palette[j].B; + + return dr*dr + dg*dg + db*db; +} + +static void compute_xor_table() +{ + int i; + byte found; + + // Initialize the table with some "random" values + for(i = 0; i < 256; i++) + { + xor_lut[i] = 255 - i; + } + + do { + // Find the smallest difference in the table + //int mindiff = INT_MAX; + int idx; + /* + for(i = 0; i < 256; i++) + { + int diff = Diff(i, xor_lut[i]); + if (diff < mindiff) { + idx = i; + mindiff = diff; + } + }*/ + + // Try to pair these two colors better + found = 0; + for(idx = 0; idx < 256; idx++) + { + int improvement = 0; + int betterpair = idx; + for(i = 0; i < 256; i++) + { + // diffs before the swap + int before = Diff(idx, xor_lut[idx]) + Diff(i, xor_lut[i]); + + // diffs after the swap + int after = Diff(idx, xor_lut[i]) + Diff(i, xor_lut[idx]); + + if (after - before > improvement) + { + improvement = after - before; + betterpair = i; + } + } + + if (improvement > 0) + { + // Swapping these colors get us something "more different". Do it ! + byte idx2 = xor_lut[betterpair]; + byte i2 = xor_lut[idx]; + + xor_lut[betterpair] = i2; + xor_lut[i2] = betterpair; + xor_lut[idx] = idx2; + xor_lut[idx2] = idx; + + found = 1; + } + } + } while(found); +} + int Same_color(T_Components * palette, byte c1, byte c2) { - if (palette[c1].R==palette[c2].R && - palette[c1].G==palette[c2].G && - palette[c1].B==palette[c2].B) - return 1; - return 0; + if (palette[c1].R==palette[c2].R && + palette[c1].G==palette[c2].G && + palette[c1].B==palette[c2].B) + return 1; + return 0; } void Compute_optimal_menu_colors(T_Components * palette) { - int i; - byte l[256]; - byte s[256]; - byte h; - int max_l = -1, min_l = 256; - int low_l, hi_l; - int delta_low = 999999; - int delta_high = 999999; - const int tolerence=16; - const T_Components cpc_colors[4] = { - { 0, 0, 0}, - { 0, 0,128}, // Dark blue - {128,128,128}, // Grey - {255,255,255} - }; + int i; + byte l[256]; + byte s[256]; + byte h; + int max_l = -1, min_l = 256; + int low_l, hi_l; + int delta_low = 999999; + int delta_high = 999999; + const int tolerence=16; + const T_Components cpc_colors[4] = { + { 0, 0, 0}, + { 0, 0,128}, // Dark blue + {128,128,128}, // Grey + {255,255,255} + }; - Old_black =MC_Black; - Old_dark = MC_Dark; - Old_light = MC_Light; - Old_white = MC_White; - Old_trans = MC_Trans; + Old_black =MC_Black; + Old_dark = MC_Dark; + Old_light = MC_Light; + Old_white = MC_White; + Old_trans = MC_Trans; - // First method: - // If all close matches for the ideal colors exist, pick them. - for (i=255; i>=0; i--) - { - - if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[3]].R/tolerence - && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[3]].G/tolerence - && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[3]].B/tolerence) - { - MC_White=i; - for (i=255; i>=0; i--) - { - if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[2]].R/tolerence - && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[2]].G/tolerence - && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[2]].B/tolerence) - { - MC_Light=i; - for (i=255; i>=0; i--) - { - if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[1]].R/tolerence - && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[1]].G/tolerence - && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[1]].B/tolerence) - { - MC_Dark=i; - for (i=255; i>=0; i--) - { - if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[0]].R/tolerence - && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[0]].G/tolerence - && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[0]].B/tolerence) - { - MC_Black=i; - // On cherche une couleur de transparence différente des 4 autres. - for (MC_Trans=0; ((MC_Trans==MC_Black) || (MC_Trans==MC_Dark) || - (MC_Trans==MC_Light) || (MC_Trans==MC_White)); MC_Trans++); - // Easy case - MC_OnBlack=MC_Dark; - MC_Window=MC_Light; - MC_Lighter=MC_White; - MC_Darker=MC_Dark; - Remap_menu_sprites(); - return; - } - } + // First method: + // If all close matches for the ideal colors exist, pick them. + for (i=255; i>=0; i--) + { + + if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[3]].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[3]].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[3]].B/tolerence) + { + MC_White=i; + for (i=255; i>=0; i--) + { + if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[2]].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[2]].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[2]].B/tolerence) + { + MC_Light=i; + for (i=255; i>=0; i--) + { + if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[1]].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[1]].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[1]].B/tolerence) + { + MC_Dark=i; + for (i=255; i>=0; i--) + { + if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[0]].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[0]].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[0]].B/tolerence) + { + MC_Black=i; + // On cherche une couleur de transparence différente des 4 autres. + for (MC_Trans=0; ((MC_Trans==MC_Black) || (MC_Trans==MC_Dark) || + (MC_Trans==MC_Light) || (MC_Trans==MC_White)); MC_Trans++); + // Easy case + MC_OnBlack=MC_Dark; + MC_Window=MC_Light; + MC_Lighter=MC_White; + MC_Darker=MC_Dark; + Remap_menu_sprites(); + return; + } + } } } } @@ -3199,6 +3270,7 @@ void Remap_menu_sprites() { int i, j, k, l; + compute_xor_table(); if ( (MC_Light!=Old_light) || (MC_Dark!=Old_dark) || (MC_White!=Old_white)