diff --git a/src/brush.c b/src/brush.c index f3001505..6b912029 100644 --- a/src/brush.c +++ b/src/brush.c @@ -36,6 +36,10 @@ #include "sdlscreen.h" #include "brush.h" +// Data used during brush rotation operation +static byte * Brush_rotate_buffer; +static int Brush_rotate_width; +static int Brush_rotate_height; // Calcul de redimensionnement du pinceau pour éviter les débordements de // l'écran et de l'image @@ -1670,7 +1674,8 @@ void Interpolate_texture(int start_x,int start_y,int xt1,int yt1, -void Compute_quad_texture(int x1,int y1,int xt1,int yt1, +void Compute_quad_texture( byte *texture, int texture_width, + int x1,int y1,int xt1,int yt1, int x2,int y2,int xt2,int yt2, int x3,int y3,int xt3,int yt3, int x4,int y4,int xt4,int yt4, @@ -1719,7 +1724,7 @@ void Compute_quad_texture(int x1,int y1,int xt1,int yt1, xt=Round((float)(ScanY_Xt[0][y])+(temp*(ScanY_Xt[1][y]-ScanY_Xt[0][y]))); yt=Round((float)(ScanY_Yt[0][y])+(temp*(ScanY_Yt[1][y]-ScanY_Yt[0][y]))); if (xt>=0 && yt>=0) - buffer[x+(y*width)]=*(Brush_original_pixels + yt * Brush_width + xt); + buffer[x+(y*width)]=*(texture + yt * texture_width + xt); } for (; x>1); end_x=start_x+Brush_width-1; end_y=start_y+Brush_height-1; + //offset = Brush_rotate_width/Brush_width-1; Transform_point(start_x,start_y, cos_a,sin_a, &x1,&y1); Transform_point(end_x ,start_y, cos_a,sin_a, &x2,&y2); @@ -1780,10 +1859,11 @@ void Rotate_brush(float angle) return; } // Et maintenant on calcule la nouvelle brosse tournée. - Compute_quad_texture(x1,y1, 0, 0, - x2,y2,Brush_width-1, 0, - x3,y3, 0,Brush_height-1, - x4,y4,Brush_width-1,Brush_height-1, + Compute_quad_texture( Brush_rotate_buffer, Brush_rotate_width, + x1,y1, offset, offset, + x2,y2,Brush_rotate_width-offset-1, offset, + x3,y3, offset,Brush_rotate_height-offset-1, + x4,y4,Brush_rotate_width-offset-1,Brush_rotate_height-offset-1, new_brush,new_brush_width,new_brush_height); if (Realloc_brush(new_brush_width, new_brush_height, new_brush, NULL)) @@ -1802,7 +1882,8 @@ void Rotate_brush(float angle) -void Draw_quad_texture_preview(int x1,int y1,int xt1,int yt1, +void Draw_quad_texture_preview(byte *texture, int texture_width, + int x1,int y1,int xt1,int yt1, int x2,int y2,int xt2,int yt2, int x3,int y3,int xt3,int yt3, int x4,int y4,int xt4,int yt4) @@ -1861,7 +1942,7 @@ void Draw_quad_texture_preview(int x1,int y1,int xt1,int yt1, yt=Round((float)(ScanY_Yt[0][y])+(temp*(ScanY_Yt[1][y]-ScanY_Yt[0][y]))); if (xt>=0 && yt>=0) { - color=Read_pixel_from_brush(xt,yt); + color=Brush_colormap[*(texture+xt+yt*texture_width)]; if (color!=Back_color) Pixel_preview(x,y_,color); } @@ -1885,6 +1966,7 @@ void Rotate_brush_preview(float angle) int start_x,end_x,start_y,end_y; float cos_a=cos(angle); float sin_a=sin(angle); + int offset=0; // Calcul des coordonnées des 4 coins: // 1 2 @@ -1894,6 +1976,7 @@ void Rotate_brush_preview(float angle) start_y=1-(Brush_height>>1); end_x=start_x+Brush_width-1; end_y=start_y+Brush_height-1; + //offset = Brush_rotate_width/Brush_width-1; Transform_point(start_x,start_y, cos_a,sin_a, &x1,&y1); Transform_point(end_x ,start_y, cos_a,sin_a, &x2,&y2); @@ -1910,10 +1993,11 @@ void Rotate_brush_preview(float angle) y4+=Brush_rotation_center_Y; // Et maintenant on dessine la brosse tournée. - Draw_quad_texture_preview(x1,y1, 0, 0, - x2,y2,Brush_width-1, 0, - x3,y3, 0,Brush_height-1, - x4,y4,Brush_width-1,Brush_height-1); + Draw_quad_texture_preview(Brush_rotate_buffer, Brush_rotate_width, + x1, y1, offset, offset, + x2, y2, Brush_rotate_width-offset-1, offset, + x3, y3, offset, Brush_rotate_height-offset-1, + x4, y4, Brush_rotate_width-offset-1, Brush_rotate_height-offset-1); start_x=Min(Min(x1,x2),Min(x3,x4)); end_x=Max(Max(x1,x2),Max(x3,x4)); start_y=Min(Min(y1,y2),Min(y3,y4)); diff --git a/src/brush.h b/src/brush.h index 9682b1fe..d12defb2 100644 --- a/src/brush.h +++ b/src/brush.h @@ -125,5 +125,7 @@ byte Realloc_brush(word new_brush_width, word new_brush_height, byte *new_brush, /// Sets brush's original palette and color mapping. void Brush_set_palette(T_Palette *palette); +void Begin_brush_rotation(void); +void End_brush_rotation(void); #endif diff --git a/src/brush_ops.c b/src/brush_ops.c index 405ca753..046621c0 100644 --- a/src/brush_ops.c +++ b/src/brush_ops.c @@ -42,7 +42,6 @@ #define M_PI 3.141592653589793238462643 #endif - /// Simulates clicking the "Draw" button. void Return_to_draw_mode(void) { @@ -971,8 +970,7 @@ void Rotate_brush_1_5(void) { dx=Paintbrush_X-Brush_rotation_center_X; dy=Paintbrush_Y-Brush_rotation_center_Y; - angle=acos(((float)dx)/sqrt((dx*dx)+(dy*dy))); - if (dy>0) angle=M_2PI-angle; + angle=M_2PI-atan2(dy,dx); } if (Menu_is_visible) diff --git a/src/op_c.c b/src/op_c.c index 1838d5d7..45614ff8 100644 --- a/src/op_c.c +++ b/src/op_c.c @@ -386,7 +386,7 @@ int OT_count_colors(T_Occurrence_table * t) // Cluster management // Clusters are boxes in the RGB spaces, defined by 6 corner coordinates : -// Rmax, Rmin, Vmax (or Gmax), Vmin, Rmax, Rmin +// Rmax, Rmin, vmax (or Vmax), vmin, Rmax, Rmin // The median cut algorithm start with a single cluster covering the whole // colorspace then split it in two smaller clusters on the longest axis until // there are 256 non-empty clusters (with some tricks if the original image @@ -403,6 +403,7 @@ void Cluster_pack(T_Cluster * c,T_Occurrence_table * to) { int rmin,rmax,vmin,vmax,bmin,bmax; int r,g,b; + int nbocc; // Find min. and max. values actually used for each component in this cluster @@ -411,15 +412,15 @@ void Cluster_pack(T_Cluster * c,T_Occurrence_table * to) // 256^3*sizeof(int) = 64MB table. If your computer has less free ram and // malloc fails, this will not work at all ! // GIMP use only 6 bits for G and B components in this table. - rmin=c->rmax <<16; rmax=c->rmin << 16; + /*rmin=c->rmax <<16; rmax=c->rmin << 16; vmin=c->vmax << 8; vmax=c->vmin << 8; bmin=c->bmax; bmax=c->bmin; c->occurences=0; - +*/ // Unoptimized code kept here for documentation purpose because the optimized // one is unreadable : run over the whole cluster and find the min and max, // and count the occurences at the same time. - /* + for (r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) for (g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) for (b=c->bmin;b<=c->bmax;b++) @@ -436,8 +437,8 @@ void Cluster_pack(T_Cluster * c,T_Occurrence_table * to) c->occurences+=nbocc; } } - */ - + +/* // Optimized version : find the extremums one at a time, so we can reduce the // area to seek for the next one. Start at the edges of the cluster and go to // the center until we find a pixel. @@ -460,10 +461,10 @@ RMAX: if(to->table[r + g + b]) // OT_get { rmax=r; - goto VMIN; + goto vmin; } } -VMIN: +vmin: for(g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) for(r=rmin;r<=rmax;r+=1<<16) for(b=c->bmin;b<=c->bmax;b++) @@ -471,10 +472,10 @@ VMIN: if(to->table[r + g + b]) // OT_get { vmin=g; - goto VMAX; + goto vmax; } } -VMAX: +vmax: for(g=c->vmax<<8;g>=vmin;g-=1<<8) for(r=rmin;r<=rmax;r+=1<<16) for(b=c->bmin;b<=c->bmax;b++) @@ -521,7 +522,12 @@ ENDCRUSH: c->rmin=rmin>>16; c->rmax=rmax>>16; c->vmin=vmin>>8; c->vmax=vmax>>8; c->bmin=bmin; c->bmax=bmax; +*/ + c->rmin=rmin; c->rmax=rmax; + c->vmin=vmin; c->vmax=vmax; + c->bmin=bmin; c->bmax=bmax; + // Find the longest axis to know which way to split the cluster // This multiplications are supposed to improve the result, but may or may not // work, actually. @@ -559,7 +565,133 @@ ENDCRUSH: } } +void Cluster_split(T_Cluster * c,T_Cluster * c1,T_Cluster * c2,int teinte,T_Occurrence_table * to) +{ + int limite; + int cumul; + int r,v,b; + limite=(c->occurences)/2; + cumul=0; + if (teinte==0) + { + + for (r=c->rmin;r<=c->rmax;r++) + { + for (v=c->vmin;v<=c->vmax;v++) + { + for (b=c->bmin;b<=c->bmax;b++) + { + cumul+=OT_get(to,r,v,b); + if (cumul>=limite) + break; + } + if (cumul>=limite) + break; + } + if (cumul>=limite) + break; + } + + + if (r==c->rmin) + r++; + // R est la valeur de début du 2nd cluster + + c1->Rmin=c->Rmin; c1->Rmax=r-1; + c1->rmin=c->rmin; c1->rmax=r-1; + c1->Gmin=c->Gmin; c1->Vmax=c->Vmax; + c1->vmin=c->vmin; c1->vmax=c->vmax; + c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; + c1->bmin=c->bmin; c1->bmax=c->bmax; + c2->Rmin=r; c2->Rmax=c->Rmax; + c2->rmin=r; c2->rmax=c->rmax; + c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; + c2->vmin=c->vmin; c2->vmax=c->vmax; + c2->Bmin=c->Bmin; c2->Bmax=c->Bmax; + c2->bmin=c->bmin; c2->bmax=c->bmax; + } + else + if (teinte==1) + { + + for (v=c->vmin;v<=c->vmax;v++) + { + for (r=c->rmin;r<=c->rmax;r++) + { + for (b=c->bmin;b<=c->bmax;b++) + { + cumul+=OT_get(to,r,v,b); + if (cumul>=limite) + break; + } + if (cumul>=limite) + break; + } + if (cumul>=limite) + break; + } + + + if (v==c->vmin) + v++; + // V est la valeur de début du 2nd cluster + + c1->Rmin=c->Rmin; c1->Rmax=c->Rmax; + c1->rmin=c->rmin; c1->rmax=c->rmax; + c1->Gmin=c->Gmin; c1->Vmax=v-1; + c1->vmin=c->vmin; c1->vmax=v-1; + c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; + c1->bmin=c->bmin; c1->bmax=c->bmax; + c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; + c2->rmin=c->rmin; c2->rmax=c->rmax; + c2->Gmin=v; c2->Vmax=c->Vmax; + c2->vmin=v; c2->vmax=c->vmax; + c2->Bmin=c->Bmin; c2->Bmax=c->Bmax; + c2->bmin=c->bmin; c2->bmax=c->bmax; + } + else + { + + + for (b=c->bmin;b<=c->bmax;b++) + { + for (v=c->vmin;v<=c->vmax;v++) + { + for (r=c->rmin;r<=c->rmax;r++) + { + cumul+=OT_get(to,r,v,b); + if (cumul>=limite) + break; + } + if (cumul>=limite) + break; + } + if (cumul>=limite) + break; + } + + + if (b==c->bmin) + b++; + // B est la valeur de début du 2nd cluster + + c1->Rmin=c->Rmin; c1->Rmax=c->Rmax; + c1->rmin=c->rmin; c1->rmax=c->rmax; + c1->Gmin=c->Gmin; c1->Vmax=c->Vmax; + c1->vmin=c->vmin; c1->vmax=c->vmax; + c1->Bmin=c->Bmin; c1->Bmax=b-1; + c1->bmin=c->bmin; c1->bmax=b-1; + c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; + c2->rmin=c->rmin; c2->rmax=c->rmax; + c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; + c2->vmin=c->vmin; c2->vmax=c->vmax; + c2->Bmin=b; c2->Bmax=c->Bmax; + c2->bmin=b; c2->bmax=c->bmax; + } +} + +/* /// Split a cluster on its longest axis. /// c = source cluster, c1, c2 = output after split void Cluster_split(T_Cluster * c, T_Cluster * c1, T_Cluster * c2, int hue, @@ -603,14 +735,14 @@ void Cluster_split(T_Cluster * c, T_Cluster * c1, T_Cluster * c2, int hue, c1->Rmin=c->Rmin; c1->Rmax=r-1; c1->rmin=c->rmin; c1->rmax=r-1; - c1->Gmin=c->Gmin; c1->Vmax=c->Vmax; + c1->Gmin=c->Gmin; c1->vmax=c->vmax; c1->vmin=c->vmin; c1->vmax=c->vmax; c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; c1->bmin=c->bmin; c1->bmax=c->bmax; c2->Rmin=r; c2->Rmax=c->Rmax; c2->rmin=r; c2->rmax=c->rmax; - c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; + c2->Gmin=c->Gmin; c2->vmax=c->vmax; c2->vmin=c->vmin; c2->vmax=c->vmax; c2->Bmin=c->Bmin; c2->Bmax=c->Bmax; c2->bmin=c->bmin; c2->bmax=c->bmax; @@ -643,14 +775,14 @@ void Cluster_split(T_Cluster * c, T_Cluster * c1, T_Cluster * c2, int hue, c1->Rmin=c->Rmin; c1->Rmax=c->Rmax; c1->rmin=c->rmin; c1->rmax=c->rmax; - c1->Gmin=c->Gmin; c1->Vmax=g-1; + c1->Gmin=c->Gmin; c1->vmax=g-1; c1->vmin=c->vmin; c1->vmax=g-1; c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; c1->bmin=c->bmin; c1->bmax=c->bmax; c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; c2->rmin=c->rmin; c2->rmax=c->rmax; - c2->Gmin=g; c2->Vmax=c->Vmax; + c2->Gmin=g; c2->vmax=c->vmax; c2->vmin=g; c2->vmax=c->vmax; c2->Bmin=c->Bmin; c2->Bmax=c->Bmax; c2->bmin=c->bmin; c2->bmax=c->bmax; @@ -682,20 +814,20 @@ void Cluster_split(T_Cluster * c, T_Cluster * c1, T_Cluster * c2, int hue, c1->Rmin=c->Rmin; c1->Rmax=c->Rmax; c1->rmin=c->rmin; c1->rmax=c->rmax; - c1->Gmin=c->Gmin; c1->Vmax=c->Vmax; + c1->Gmin=c->Gmin; c1->vmax=c->vmax; c1->vmin=c->vmin; c1->vmax=c->vmax; c1->Bmin=c->Bmin; c1->Bmax=b-1; c1->bmin=c->bmin; c1->bmax=b-1; c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; c2->rmin=c->rmin; c2->rmax=c->rmax; - c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; + c2->Gmin=c->Gmin; c2->vmax=c->vmax; c2->vmin=c->vmin; c2->vmax=c->vmax; c2->Bmin=b; c2->Bmax=c->Bmax; c2->bmin=b; c2->bmax=c->bmax; } } - +*/ /// Compute the mean R, G, B (for palette generation) and H, L (for palette sorting) void Cluster_compute_hue(T_Cluster * c,T_Occurrence_table * to) @@ -757,7 +889,7 @@ void CS_Init(T_Cluster_set * cs, T_Occurrence_table * to) cs->clusters->Gmin = cs->clusters->vmin = 0; cs->clusters->Bmin = cs->clusters->bmin = 0; cs->clusters->Rmax = cs->clusters->rmax = to->rng_r - 1; - cs->clusters->Vmax = cs->clusters->vmax = to->rng_g - 1; + cs->clusters->vmax = cs->clusters->vmax = to->rng_g - 1; cs->clusters->Bmax = cs->clusters->bmax = to->rng_b - 1; cs->clusters->next = NULL; Cluster_pack(cs->clusters, to); @@ -1007,7 +1139,7 @@ void CS_Generate_color_table_and_palette(T_Cluster_set * cs,T_Conversion_table * palette[index].B=current->b; for (r=current->Rmin; r<=current->Rmax; r++) - for (g=current->Gmin;g<=current->Vmax;g++) + for (g=current->Gmin;g<=current->vmax;g++) for (b=current->Bmin;b<=current->Bmax;b++) CT_set(tc,r,g,b,index); current = current->next; @@ -1338,8 +1470,6 @@ void Convert_24b_bitmap_to_256_nearest_neighbor(T_Bitmap256 dest, // For some of them only the first one may work because of ugly optimizations static const byte precision_24b[]= { - 8,8,8, - 6,6,6, 6,6,5, 5,6,5, 5,5,5, diff --git a/src/operatio.c b/src/operatio.c index 92667d37..ee158e11 100644 --- a/src/operatio.c +++ b/src/operatio.c @@ -49,7 +49,17 @@ Uint32 Airbrush_next_time; void Start_operation_stack(word new_operation) { + // This part handles things that must be done when exiting an operation. Brush_rotation_center_is_defined=0; + switch(Current_operation) + { + case OPERATION_ROTATE_BRUSH: + End_brush_rotation(); + break; + + default: + break; + } // On mémorise l'opération précédente si on démarre une interruption switch(new_operation) @@ -61,6 +71,7 @@ void Start_operation_stack(word new_operation) case OPERATION_POLYBRUSH: case OPERATION_STRETCH_BRUSH: case OPERATION_ROTATE_BRUSH: + Begin_brush_rotation(); Operation_before_interrupt=Current_operation; // On passe à l'operation demandée Current_operation=new_operation; diff --git a/src/pversion.c b/src/pversion.c index b60e3b67..bcc14b4d 100644 --- a/src/pversion.c +++ b/src/pversion.c @@ -1,2 +1,2 @@ -char Program_version[]="2.3"; +char Program_version[]="2.4wip";