/* Grafx2 - The Ultimate 256-color bitmap paint program
Copyright 2008 Franck Charlet
Copyright 2007-2008 Adrien Destugues
Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud)
Grafx2 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2
of the License.
Grafx2 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grafx2; if not, see or
write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
********************************************************************************
Brush manipulation functions
*/
#include
#include
#include // memset()
#include "global.h"
#include "graph.h"
#include "divers.h"
#include "erreurs.h"
#include "windows.h"
#include "sdlscreen.h"
// Calcul de redimensionnement du pinceau pour éviter les débordements de
// l'écran et de l'image
void Compute_clipped_dimensions(short * x,short * y,short * width,short * height)
{
if ((*x)(Limit_right+1))
{
(*width)=(Limit_right-(*x))+1;
}
if ((*y)(Limit_bottom+1))
{
(*height)=(Limit_bottom-(*y))+1;
}
}
// -- Calcul de redimensionnement du pinceau pour éviter les débordements
// de l'écran zoomé et de l'image --
void Compute_clipped_dimensions_zoom(short * x,short * y,short * width,short * height)
{
if ((*x)(Limit_right_zoom+1))
{
(*width)=(Limit_right_zoom-(*x))+1;
}
if ((*y)(Limit_bottom_zoom+1))
{
(*height)=(Limit_bottom_zoom-(*y))+1;
}
}
// -- Afficher le pinceau (de façon définitive ou non) --
void Display_paintbrush(short x,short y,byte color,byte is_preview)
// x,y: position du centre du pinceau
// color: couleur à appliquer au pinceau
// is_preview: "Il ne faut l'afficher qu'à l'écran"
{
short start_x; // Position X (dans l'image) à partir de laquelle on
// affiche la brosse/pinceau
short start_y; // Position Y (dans l'image) à partir de laquelle on
// affiche la brosse/pinceau
short width; // width dans l'écran selon laquelle on affiche la
// brosse/pinceau
short height; // height dans l'écran selon laquelle on affiche la
// brosse/pinceau
short start_x_counter; // Position X (dans la brosse/pinceau) à partir
// de laquelle on affiche la brosse/pinceau
short start_y_counter; // Position Y (dans la brosse/pinceau) à partir
// de laquelle on affiche la brosse/pinceau
short x_pos; // Position X (dans l'image) en cours d'affichage
short y_pos; // Position Y (dans l'image) en cours d'affichage
short counter_x; // Position X (dans la brosse/pinceau) en cours
// d'affichage
short counter_y; // Position Y (dans la brosse/pinceau) en cours
// d'affichage
short end_counter_x; // Position X ou s'arrête l'affichade de la
// brosse/pinceau
short end_counter_y; // Position Y ou s'arrête l'affichade de la
// brosse/pinceau
byte temp_color; // color de la brosse en cours d'affichage
int position;
byte * temp;
if (!(is_preview && Mouse_K)) // Si bouton enfoncé & preview > pas de dessin
switch (Paintbrush_shape)
{
case PAINTBRUSH_SHAPE_POINT : // !!! TOUJOURS EN PREVIEW !!!
if ( (Paintbrush_X>=Limit_left)
&& (Paintbrush_X<=Limit_right)
&& (Paintbrush_Y>=Limit_top)
&& (Paintbrush_Y<=Limit_bottom) )
{
Pixel_preview(Paintbrush_X,Paintbrush_Y,color);
Update_part_of_screen(x,y,1,1);
}
break;
case PAINTBRUSH_SHAPE_COLOR_BRUSH : // Brush en couleur
start_x=x-Brush_offset_X;
start_y=y-Brush_offset_Y;
width=Brush_width;
height=Brush_height;
Compute_clipped_dimensions(&start_x,&start_y,&width,&height);
if (width<=0 || height<=0)
break;
start_x_counter=start_x-(x-Brush_offset_X);
start_y_counter=start_y-(y-Brush_offset_Y);
end_counter_x=start_x_counter+width;
end_counter_y=start_y_counter+height;
if (is_preview)
{
if ( (width>0) && (height>0) )
Display_brush_color(
start_x-Main_offset_X,
start_y-Main_offset_Y,
start_x_counter,
start_y_counter,
width,
height,
Back_color,
Brush_width
);
if (Main_magnifier_mode)
{
Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,
&height
);
start_x_counter=start_x-(x-Brush_offset_X);
start_y_counter=start_y-(y-Brush_offset_Y);
if ( (width>0) && (height>0) )
{
// Corrections dues au Zoom:
start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor;
start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor;
height=start_y+(height*Main_magnifier_factor);
if (height>Menu_Y)
height=Menu_Y;
Display_brush_color_zoom(Main_X_zoom+start_x,start_y,
start_x_counter,start_y_counter,
width,height,Back_color,
Brush_width,
Horizontal_line_buffer);
}
}
Update_part_of_screen(x-Brush_offset_X,y-Brush_offset_Y,Brush_width,Brush_height);
}
else
{
if ((Smear_mode) && (Shade_table==Shade_table_left))
{
if (Smear_start)
{
if ((width>0) && (height>0))
{
Copy_part_of_image_to_another(
Main_screen, start_x, start_y, width, height,
Main_image_width, Smear_brush,
start_x_counter, start_y_counter,
Smear_brush_width
);
Update_part_of_screen(start_x,start_y,width,height);
}
Smear_start=0;
}
else
{
for (y_pos = start_y, counter_y = start_y_counter;
counter_y < end_counter_y;
y_pos++, counter_y++
)
for (x_pos = start_x, counter_x = start_x_counter;
counter_x < end_counter_x;
x_pos++, counter_x++
)
{
temp_color = Read_pixel_from_current_screen(
x_pos,y_pos
);
position = (counter_y * Smear_brush_width)+ counter_x;
if ( (Read_pixel_from_brush(counter_x,counter_y) != Back_color)
&& (counter_y=Smear_min_Y) && (counter_x>=Smear_min_X) )
Display_pixel(x_pos,y_pos,Smear_brush[position]);
Smear_brush[position]=temp_color;
}
Update_part_of_screen(start_x,start_y,width,height);
}
Smear_min_X=start_x_counter;
Smear_min_Y=start_y_counter;
Smear_max_X=end_counter_x;
Smear_max_Y=end_counter_y;
}
else
{
if (Shade_table==Shade_table_left)
for (y_pos=start_y,counter_y=start_y_counter;counter_y0) && (height>0) )
Display_brush_mono(start_x-Main_offset_X,
start_y-Main_offset_Y,
start_x_counter,start_y_counter,
width,height,
Back_color,Fore_color,
Brush_width);
if (Main_magnifier_mode)
{
Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height);
start_x_counter=start_x-(x-Brush_offset_X);
start_y_counter=start_y-(y-Brush_offset_Y);
if ( (width>0) && (height>0) )
{
// Corrections dues au Zoom:
start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor;
start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor;
height=start_y+(height*Main_magnifier_factor);
if (height>Menu_Y)
height=Menu_Y;
Display_brush_mono_zoom(Main_X_zoom+start_x,start_y,
start_x_counter,start_y_counter,
width,height,
Back_color,Fore_color,
Brush_width,
Horizontal_line_buffer);
}
}
Update_part_of_screen(x-Brush_offset_X,y-Brush_offset_Y,Brush_width,Brush_height);
}
else
{
if ((Smear_mode) && (Shade_table==Shade_table_left))
{
if (Smear_start)
{
if ((width>0) && (height>0))
{
Copy_part_of_image_to_another(Main_screen,
start_x,start_y,
width,height,
Main_image_width,
Smear_brush,
start_x_counter,
start_y_counter,
Smear_brush_width);
Update_part_of_screen(start_x,start_y,width,height);
}
Smear_start=0;
}
else
{
for (y_pos=start_y,counter_y=start_y_counter;counter_y=Smear_min_Y) && (counter_x>=Smear_min_X) )
Display_pixel(x_pos,y_pos,Smear_brush[position]);
Smear_brush[position]=temp_color;
}
Update_part_of_screen(start_x,start_y,width,height);
}
Smear_min_X=start_x_counter;
Smear_min_Y=start_y_counter;
Smear_max_X=end_counter_x;
Smear_max_Y=end_counter_y;
}
else
{
for (y_pos=start_y,counter_y=start_y_counter;counter_y0) && (height>0) )
Display_brush_mono(start_x-Main_offset_X,
start_y-Main_offset_Y,
start_x_counter,start_y_counter,
width,height,
0,Fore_color,
MAX_PAINTBRUSH_SIZE);
if (Main_magnifier_mode)
{
Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height);
start_x_counter=start_x-(x-Paintbrush_offset_X);
start_y_counter=start_y-(y-Paintbrush_offset_Y);
if ( (width>0) && (height>0) )
{
// Corrections dues au Zoom:
start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor;
start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor;
height=start_y+(height*Main_magnifier_factor);
if (height>Menu_Y)
height=Menu_Y;
Display_brush_mono_zoom(Main_X_zoom+start_x,start_y,
start_x_counter,start_y_counter,
width,height,
0,Fore_color,
MAX_PAINTBRUSH_SIZE,
Horizontal_line_buffer);
}
}
Brush=temp;
}
else
{
if ((Smear_mode) && (Shade_table==Shade_table_left))
{
if (Smear_start)
{
if ((width>0) && (height>0))
{
Copy_part_of_image_to_another(Main_screen,
start_x,start_y,
width,height,
Main_image_width,
Smear_brush,
start_x_counter,
start_y_counter,
Smear_brush_width);
Update_part_of_screen(start_x,start_y,width,height);
}
Smear_start=0;
}
else
{
for (y_pos=start_y,counter_y=start_y_counter;counter_y=Smear_min_Y) && (counter_x>=Smear_min_X) )
Display_pixel(x_pos,y_pos,Smear_brush[position]);
Smear_brush[position]=temp_color;
}
Update_part_of_screen(start_x, start_y, width, height);
}
Smear_min_X=start_x_counter;
Smear_min_Y=start_y_counter;
Smear_max_X=end_counter_x;
Smear_max_Y=end_counter_y;
}
else
{
for (y_pos=start_y,counter_y=start_y_counter;counter_y=Limit_left)
&& (Paintbrush_X<=Limit_right)
&& (Paintbrush_Y>=Limit_top)
&& (Paintbrush_Y<=Limit_bottom) )
{
Pixel_preview(Paintbrush_X,Paintbrush_Y,Read_pixel_from_current_screen(Paintbrush_X,Paintbrush_Y));
Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1);
}
break;
case PAINTBRUSH_SHAPE_COLOR_BRUSH : // Brush en couleur
case PAINTBRUSH_SHAPE_MONO_BRUSH : // Brush monochrome
start_x=x-Brush_offset_X;
start_y=y-Brush_offset_Y;
width=Brush_width;
height=Brush_height;
Compute_clipped_dimensions(&start_x,&start_y,&width,&height);
start_x_counter=start_x-(x-Brush_offset_X);
start_y_counter=start_y-(y-Brush_offset_Y);
end_counter_x=start_x_counter+width;
end_counter_y=start_y_counter+height;
if ( (width>0) && (height>0) )
Clear_brush(start_x-Main_offset_X,
start_y-Main_offset_Y,
start_x_counter,start_y_counter,
width,height,Back_color,
Main_image_width);
if (Main_magnifier_mode)
{
Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height);
start_x_counter=start_x;
start_y_counter=start_y;
if ( (width>0) && (height>0) )
{
// Corrections dues au Zoom:
start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor;
start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor;
height=start_y+(height*Main_magnifier_factor);
if (height>Menu_Y)
height=Menu_Y;
Clear_brush_scaled(Main_X_zoom+start_x,start_y,
start_x_counter,start_y_counter,
width,height,Back_color,
Main_image_width,
Horizontal_line_buffer);
}
}
break;
default: // Pinceau
start_x=x-Paintbrush_offset_X;
start_y=y-Paintbrush_offset_Y;
width=Paintbrush_width;
height=Paintbrush_height;
Compute_clipped_dimensions(&start_x,&start_y,&width,&height);
start_x_counter=start_x-(x-Paintbrush_offset_X);
start_y_counter=start_y-(y-Paintbrush_offset_Y);
end_counter_x=start_x_counter+width;
end_counter_y=start_y_counter+height;
temp=Brush;
Brush=Paintbrush_sprite;
if ( (width>0) && (height>0) )
{
Clear_brush(start_x-Main_offset_X,
start_y-Main_offset_Y,
start_x_counter,start_y_counter,
width,height,0,
Main_image_width);
}
if (Main_magnifier_mode)
{
Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height);
start_x_counter=start_x;
start_y_counter=start_y;
if ( (width>0) && (height>0) )
{
// Corrections dues au Zoom:
start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor;
start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor;
height=start_y+(height*Main_magnifier_factor);
if (height>Menu_Y)
height=Menu_Y;
Clear_brush_scaled(Main_X_zoom+start_x,start_y,
start_x_counter,start_y_counter,
width,height,0,
Main_image_width,
Horizontal_line_buffer);
}
}
Brush=temp;
break;
}
}
void Capture_brush(short start_x,short start_y,short end_x,short end_y,short clear)
{
short temp;
short x_pos;
short y_pos;
word new_brush_width;
word new_brush_height;
// On commence par "redresser" les bornes:
if (start_x>end_x)
{
temp=start_x;
start_x =end_x;
end_x =temp;
}
if (start_y>end_y)
{
temp=start_y;
start_y =end_y;
end_y =temp;
}
// On ne capture la nouvelle brosse que si elle est au moins partiellement
// dans l'image:
if ((start_xMain_image_width)
new_brush_width=Main_image_width-start_x;
if (start_y+new_brush_height>Main_image_height)
new_brush_height=Main_image_height-start_y;
if ( (((long)Brush_height)*Brush_width) !=
(((long)new_brush_height)*new_brush_width) )
{
free(Brush);
Brush=(byte *)malloc(((long)new_brush_height)*new_brush_width);
if (!Brush)
{
Error(0);
Brush=(byte *)malloc(1*1);
new_brush_height=new_brush_width=1;
*Brush=Fore_color;
}
}
Brush_width=new_brush_width;
Brush_height=new_brush_height;
free(Smear_brush);
Smear_brush_width=(Brush_width>MAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE;
Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE;
Smear_brush=(byte *)malloc(((long)Smear_brush_height)*Smear_brush_width);
if (!Smear_brush) // On ne peut même pas allouer la brosse du smear!
{
Error(0);
free(Brush);
Brush=(byte *)malloc(1*1);
Brush_height=1;
Brush_width=1;
Smear_brush=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE);
Smear_brush_height=MAX_PAINTBRUSH_SIZE;
Smear_brush_width=MAX_PAINTBRUSH_SIZE;
}
Copy_image_to_brush(start_x,start_y,Brush_width,Brush_height,Main_image_width);
// On regarde s'il faut effacer quelque chose:
if (clear)
{
for (y_pos=start_y;y_pos>1);
Brush_offset_Y=(Brush_height>>1);
}
}
void Rotate_90_deg()
{
short temp;
byte * new_brush;
new_brush=(byte *)malloc(((long)Brush_height)*Brush_width);
if (new_brush)
{
Rotate_90_deg_lowlevel(Brush,new_brush);
free(Brush);
Brush=new_brush;
temp=Brush_width;
Brush_width=Brush_height;
Brush_height=temp;
temp=Smear_brush_width;
Smear_brush_width=Smear_brush_height;
Smear_brush_height=temp;
// On centre la prise sur la brosse
Brush_offset_X=(Brush_width>>1);
Brush_offset_Y=(Brush_height>>1);
}
else
Error(0);
}
void Remap_brush(void)
{
short x_pos; // Variable de balayage de la brosse
short y_pos; // Variable de balayage de la brosse
byte used[256]; // Tableau de booléens "La couleur est utilisée"
int color;
// On commence par initialiser le tableau de booléens à faux
for (color=0;color<=255;color++)
used[color]=0;
// On calcule la table d'utilisation des couleurs
for (y_pos=0;y_pos>1);
Brush_offset_Y=(Brush_height>>1);
free(temp); // Libération de l'ancienne brosse
// Réallocation d'un buffer de Smear
free(Smear_brush);
Smear_brush_width=(Brush_width>MAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE;
Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE;
Smear_brush=(byte *)malloc(((long)Smear_brush_width)*Smear_brush_height);
}
else
Error(0); // Pas assez de mémoire!
}
void Nibble_brush(void)
{
long /*Pos,*/x_pos,y_pos;
byte state;
byte * new_brush;
byte * temp;
word width;
word height;
if ( (Brush_width>2) && (Brush_height>2) )
{
width=Brush_width-2;
height=Brush_height-2;
new_brush=(byte *)malloc(((long)width)*height);
if (new_brush)
{
// On copie la brosse courante dans la nouvelle
Copy_part_of_image_to_another(Brush, // source
1,
1,
width,
height,
Brush_width,
new_brush, // Destination
0,
0,
width);
// On intervertit la nouvelle et l'ancienne brosse:
temp=Brush;
Brush=new_brush;
Brush_width-=2;
Brush_height-=2;
width+=2;
height+=2;
// 1er balayage (horizontal)
for (y_pos=0; y_pos0)
Pixel_in_brush(x_pos-1,y_pos,Back_color);
state=0;
}
}
else
{
if (!state)
{
Pixel_in_brush(x_pos,y_pos,Back_color);
state=1;
}
}
}
// Cas du dernier pixel à droite de la ligne
if (temp[((y_pos+1)*width)+x_pos+1]==Back_color)
Pixel_in_brush(x_pos-1,y_pos,Back_color);
}
// 2ème balayage (vertical)
for (x_pos=0; x_pos0)
Pixel_in_brush(x_pos,y_pos-1,Back_color);
state=0;
}
}
else
{
if (!state)
{
Pixel_in_brush(x_pos,y_pos,Back_color);
state=1;
}
}
}
// Cas du dernier pixel en bas de la colonne
if (temp[((y_pos+1)*width)+x_pos+1]==Back_color)
Pixel_in_brush(x_pos,y_pos-1,Back_color);
}
// On recentre la prise sur la brosse
Brush_offset_X=(Brush_width>>1);
Brush_offset_Y=(Brush_height>>1);
free(temp); // Libération de l'ancienne brosse
// Réallocation d'un buffer de Smear
free(Smear_brush);
Smear_brush_width=(Brush_width>MAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE;
Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE;
Smear_brush=(byte *)malloc(((long)Smear_brush_width)*Smear_brush_height);
}
else
Error(0); // Pas assez de mémoire!
}
}
void Capture_brush_with_lasso(int vertices, short * points,short clear)
{
short start_x=Limit_right+1;
short start_y=Limit_bottom+1;
short end_x=Limit_left-1;
short end_y=Limit_top-1;
short temp;
short x_pos;
short y_pos;
word new_brush_width;
word new_brush_height;
// On recherche les bornes de la brosse:
for (temp=0; tempend_x)
end_x=x_pos;
if (y_posend_y)
end_y=y_pos;
}
// On clippe ces bornes à l'écran:
if (start_xLimit_right)
end_x=Limit_right;
if (start_yLimit_bottom)
end_y=Limit_bottom;
// On ne capture la nouvelle brosse que si elle est au moins partiellement
// dans l'image:
if ((start_xMAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE;
Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE;
Smear_brush=(byte *)malloc(((long)Smear_brush_height)*Smear_brush_width);
if (!Smear_brush) // On ne peut même pas allouer la brosse du smear!
{
Error(0);
free(Brush);
Brush=(byte *)malloc(1*1);
Brush_height=1;
Brush_width=1;
Smear_brush=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE);
Smear_brush_height=MAX_PAINTBRUSH_SIZE;
Smear_brush_width=MAX_PAINTBRUSH_SIZE;
}
Brush_offset_X=start_x;
Brush_offset_Y=start_y;
Pixel_figure=Pixel_figure_in_brush;
memset(Brush,Back_color,(long)Brush_width*Brush_height);
Polyfill_general(vertices,points,~Back_color);
// On retrace les bordures du lasso:
for (temp=1; temp>1);
Brush_offset_Y=(Brush_height>>1);
}
}
//------------------------- Etirement de la brosse ---------------------------
void Stretch_brush(short x1, short y1, short x2, short y2)
{
int offset,line,column;
byte * new_brush;
int new_brush_width; // Width de la nouvelle brosse
int new_brush_height; // Height de la nouvelle brosse
int x_pos_in_brush; // Position courante dans l'ancienne brosse
int y_pos_in_brush;
int delta_x_in_brush; // "Vecteur incrémental" du point précédent
int delta_y_in_brush;
int initial_x_pos; // Position X de début de parcours de ligne
int dx,dy;
dx=(x1=0)
initial_x_pos = 0; // Pas d'inversion en X de la brosse
else
initial_x_pos = (Brush_width<<16)-1; // Inversion en X de la brosse
free(Smear_brush); // On libère un peu de mémoire
if ((new_brush=((byte *)malloc(new_brush_width*new_brush_height))))
{
offset=0;
// Calcul de la valeur initiale de y_pos:
if (dy>=0)
y_pos_in_brush=0; // Pas d'inversion en Y de la brosse
else
y_pos_in_brush=(Brush_height<<16)-1; // Inversion en Y de la brosse
// Pour chaque ligne
for (line=0;line>16,y_pos_in_brush>>16);
// On passe à la colonne de brosse suivante:
x_pos_in_brush+=delta_x_in_brush;
// On passe au pixel suivant de la nouvelle brosse:
offset++;
}
// On passe à la ligne de brosse suivante:
y_pos_in_brush+=delta_y_in_brush;
}
free(Brush);
Brush=new_brush;
Brush_width=new_brush_width;
Brush_height=new_brush_height;
Smear_brush_width=(Brush_width>MAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE;
Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE;
Smear_brush=(byte *)malloc(((long)Smear_brush_height)*Smear_brush_width);
if (!Smear_brush) // On ne peut même pas allouer la brosse du smear!
{
Error(0);
free(Brush);
Brush=(byte *)malloc(1*1);
Brush_height=1;
Brush_width=1;
Smear_brush=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE);
Smear_brush_height=MAX_PAINTBRUSH_SIZE;
Smear_brush_width=MAX_PAINTBRUSH_SIZE;
}
Brush_offset_X=(Brush_width>>1);
Brush_offset_Y=(Brush_height>>1);
}
else
{
// Ici la libération de mémoire n'a pas suffit donc on remet dans l'état
// où c'etait avant. On a juste à réallouer la Smear_brush car il y a
// normalement la place pour elle puisque rien d'autre n'a pu être alloué
// entre temps.
Smear_brush=(byte *)malloc(((long)Smear_brush_height)*Smear_brush_width);
Error(0);
}
}
void Stretch_brush_preview(short x1, short y1, short x2, short y2)
{
int src_x_pos,src_y_pos;
int initial_src_x_pos,initial_src_y_pos;
int delta_x,delta_y;
int dest_x_pos,dest_y_pos;
int initial_dest_x_pos,initial_dest_y_pos;
int final_dest_x_pos,final_dest_y_pos;
int dest_width,dest_height;
byte color;
// 1er calcul des positions destination extremes:
initial_dest_x_pos=Min(x1,x2);
initial_dest_y_pos=Min(y1,y2);
final_dest_x_pos =Max(x1,x2);
final_dest_y_pos =Max(y1,y2);
// Calcul des dimensions de la destination:
dest_width=final_dest_x_pos-initial_dest_x_pos+1;
dest_height=final_dest_y_pos-initial_dest_y_pos+1;
// Calcul des vecteurs d'incrémentation :
delta_x=(Brush_width<<16)/dest_width;
delta_y=(Brush_height<<16)/dest_height;
// 1er calcul de la position X initiale dans la source:
initial_src_x_pos=(Brush_width<<16)*
(Max(initial_dest_x_pos,Limit_left)-
initial_dest_x_pos)/dest_width;
// Calcul du clip de la destination:
initial_dest_x_pos=Max(initial_dest_x_pos,Limit_left);
final_dest_x_pos =Min(final_dest_x_pos ,Limit_visible_right);
// On discute selon l'inversion en X
if (x1>x2)
{
// Inversion -> Inversion du signe de delta_x
delta_x=-delta_x;
initial_src_x_pos=(Brush_width<<16)-1-initial_src_x_pos;
}
// 1er calcul de la position Y initiale dans la source:
initial_src_y_pos=(Brush_height<<16)*
(Max(initial_dest_y_pos,Limit_top)-
initial_dest_y_pos)/dest_height;
// Calcul du clip de la destination:
initial_dest_y_pos=Max(initial_dest_y_pos,Limit_top);
final_dest_y_pos =Min(final_dest_y_pos ,Limit_visible_bottom);
// On discute selon l'inversion en Y
if (y1>y2)
{
// Inversion -> Inversion du signe de delta_y
delta_y=-delta_y;
initial_src_y_pos=(Brush_height<<16)-1-initial_src_y_pos;
}
// Pour chaque ligne :
src_y_pos=initial_src_y_pos;
for (dest_y_pos=initial_dest_y_pos;dest_y_pos<=final_dest_y_pos;dest_y_pos++)
{
// Pour chaque colonne:
src_x_pos=initial_src_x_pos;
for (dest_x_pos=initial_dest_x_pos;dest_x_pos<=final_dest_x_pos;dest_x_pos++)
{
color=Read_pixel_from_brush(src_x_pos>>16,src_y_pos>>16);
if (color!=Back_color)
Pixel_preview(dest_x_pos,dest_y_pos,color);
src_x_pos+=delta_x;
}
src_y_pos+=delta_y;
}
Update_part_of_screen(initial_dest_x_pos,initial_dest_y_pos,dest_width,dest_height);
}
//------------------------- Rotation de la brosse ---------------------------
#define UNDEFINED (-1.0e20F)
float * ScanY_Xt[2];
float * ScanY_Yt[2];
float * ScanY_X[2];
void Interpolate_texture(int start_x,int start_y,int xt1,int yt1,
int end_x ,int end_y ,int xt2,int yt2,int height)
{
int x_pos,y_pos;
int incr_x,incr_y;
int i,cumul;
int delta_x,delta_y;
int delta_xt=xt2-xt1;
int delta_yt=yt2-yt1;
int delta_x2=end_x-start_x;
int delta_y2=end_y-start_y;
float xt,yt;
x_pos=start_x;
y_pos=start_y;
if (start_xdelta_y)
{
cumul=delta_x>>1;
for (i=0; i<=delta_x; i++)
{
if (cumul>=delta_x)
{
cumul-=delta_x;
y_pos+=incr_y;
}
if ((y_pos>=0) && (y_pos=ScanY_X[0][y_pos])
{
if ((ScanY_X[1][y_pos]==UNDEFINED) // Droit non défini
|| (x_pos>ScanY_X[1][y_pos]))
{
ScanY_X[1][y_pos]=x_pos;
ScanY_Xt[1][y_pos]=xt;
ScanY_Yt[1][y_pos]=yt;
}
}
else
{
if (ScanY_X[1][y_pos]==UNDEFINED) // Droit non défini
{
ScanY_X[1][y_pos]=ScanY_X[0][y_pos];
ScanY_Xt[1][y_pos]=ScanY_Xt[0][y_pos];
ScanY_Yt[1][y_pos]=ScanY_Yt[0][y_pos];
ScanY_X[0][y_pos]=x_pos;
ScanY_Xt[0][y_pos]=xt;
ScanY_Yt[0][y_pos]=yt;
}
else
{
ScanY_X[0][y_pos]=x_pos;
ScanY_Xt[0][y_pos]=xt;
ScanY_Yt[0][y_pos]=yt;
}
}
}
}
x_pos+=incr_x;
cumul+=delta_y;
}
}
else
{
cumul=delta_y>>1;
for (i=0; i<=delta_y; i++)
{
if (cumul>=delta_y)
{
cumul-=delta_y;
x_pos+=incr_x;
}
if ((y_pos>=0) && (y_pos=ScanY_X[0][y_pos])
{
if ((ScanY_X[1][y_pos]==UNDEFINED) // Droit non défini
|| (x_pos>ScanY_X[1][y_pos]))
{
ScanY_X[1][y_pos]=x_pos;
ScanY_Xt[1][y_pos]=xt;
ScanY_Yt[1][y_pos]=yt;
}
}
else
{
if (ScanY_X[1][y_pos]==UNDEFINED) // Droit non défini
{
ScanY_X[1][y_pos]=ScanY_X[0][y_pos];
ScanY_Xt[1][y_pos]=ScanY_Xt[0][y_pos];
ScanY_Yt[1][y_pos]=ScanY_Yt[0][y_pos];
ScanY_X[0][y_pos]=x_pos;
ScanY_Xt[0][y_pos]=xt;
ScanY_Yt[0][y_pos]=yt;
}
else
{
ScanY_X[0][y_pos]=x_pos;
ScanY_Xt[0][y_pos]=xt;
ScanY_Yt[0][y_pos]=yt;
}
}
}
}
y_pos+=incr_y;
cumul+=delta_x;
}
}
}
void Compute_quad_texture(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,
byte * buffer, int width, int height)
{
int x_min,/*x_max,*/y_min/*,y_max*/;
int x,y,xt,yt;
int start_x,end_x,line_width;
float temp;
//byte color;
x_min=Min(Min(x1,x2),Min(x3,x4));
y_min=Min(Min(y1,y2),Min(y3,y4));
ScanY_Xt[0]=(float *)malloc(height*sizeof(float));
ScanY_Xt[1]=(float *)malloc(height*sizeof(float));
ScanY_Yt[0]=(float *)malloc(height*sizeof(float));
ScanY_Yt[1]=(float *)malloc(height*sizeof(float));
ScanY_X[0] =(float *)malloc(height*sizeof(float));
ScanY_X[1] =(float *)malloc(height*sizeof(float));
// Fill_general avec des valeurs égales à UNDEFINED.
for (y=0; y>1);
start_y=1-(Brush_height>>1);
end_x=start_x+Brush_width-1;
end_y=start_y+Brush_height-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);
Transform_point(start_x,end_y , cos_a,sin_a, &x3,&y3);
Transform_point(end_x ,end_y , cos_a,sin_a, &x4,&y4);
// Calcul des nouvelles dimensions de la brosse:
x_min=Min(Min((int)x1,(int)x2),Min((int)x3,(int)x4));
x_max=Max(Max((int)x1,(int)x2),Max((int)x3,(int)x4));
y_min=Min(Min((int)y1,(int)y2),Min((int)y3,(int)y4));
y_max=Max(Max((int)y1,(int)y2),Max((int)y3,(int)y4));
new_brush_width=x_max+1-x_min;
new_brush_height=y_max+1-y_min;
free(Smear_brush); // On libère un peu de mémoire
if ((new_brush=((byte *)malloc(new_brush_width*new_brush_height))))
{
// 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,
new_brush,new_brush_width,new_brush_height);
free(Brush);
Brush=new_brush;
Brush_width=new_brush_width;
Brush_height=new_brush_height;
Smear_brush_width=(Brush_width>MAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE;
Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE;
Smear_brush=(byte *)malloc(((long)Smear_brush_height)*Smear_brush_width);
if (!Smear_brush) // On ne peut même pas allouer la brosse du smear!
{
Error(0);
free(Brush);
Brush=(byte *)malloc(1*1);
Brush_height=1;
Brush_width=1;
Smear_brush=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE);
Smear_brush_height=MAX_PAINTBRUSH_SIZE;
Smear_brush_width=MAX_PAINTBRUSH_SIZE;
}
Brush_offset_X=(Brush_width>>1);
Brush_offset_Y=(Brush_height>>1);
}
else
{
// Ici la libération de mémoire n'a pas suffit donc on remet dans l'état
// où c'etait avant. On a juste à réallouer la Smear_brush car il y a
// normalement la place pour elle puisque rien d'autre n'a pu être alloué
// entre temps.
Smear_brush=(byte *)malloc(((long)Smear_brush_height)*Smear_brush_width);
Error(0);
}
}
void Draw_quad_texture_preview(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)
{
int x_min,x_max,y_min,y_max;
int x,y,xt,yt;
int y_,y_min_;
int start_x,end_x,width,height;
float temp;
byte color;
x_min=Min(Min(x1,x2),Min(x3,x4));
x_max=Max(Max(x1,x2),Max(x3,x4));
y_min=Min(Min(y1,y2),Min(y3,y4));
y_max=Max(Max(y1,y2),Max(y3,y4));
height=1+y_max-y_min;
ScanY_Xt[0]=(float *)malloc(height*sizeof(float));
ScanY_Xt[1]=(float *)malloc(height*sizeof(float));
ScanY_Yt[0]=(float *)malloc(height*sizeof(float));
ScanY_Yt[1]=(float *)malloc(height*sizeof(float));
ScanY_X[0] =(float *)malloc(height*sizeof(float));
ScanY_X[1] =(float *)malloc(height*sizeof(float));
// Fill_general avec des valeurs égales à UNDEFINED.
for (y=0; yLimit_bottom) y_max=Limit_bottom;
for (y_=y_min; y_<=y_max; y_++)
{
y=y_-y_min_;
start_x=Round(ScanY_X[0][y]);
end_x =Round(ScanY_X[1][y]);
width=1+end_x-start_x;
if (start_xLimit_right) end_x=Limit_right;
for (x=start_x; x<=end_x; x++)
{
temp=(float)(0.5+(float)x-ScanY_X[0][y])/(float)width;
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])));
color=Read_pixel_from_brush(xt,yt);
if (color!=Back_color)
Pixel_preview(x,y_,color);
}
}
free(ScanY_Xt[0]);
free(ScanY_Xt[1]);
free(ScanY_Yt[0]);
free(ScanY_Yt[1]);
free(ScanY_X[0]);
free(ScanY_X[1]);
}
void Rotate_brush_preview(float angle)
{
short x1,y1,x2,y2,x3,y3,x4,y4;
int start_x,end_x,start_y,end_y;
float cos_a=cos(angle);
float sin_a=sin(angle);
// Calcul des coordonnées des 4 coins:
// 1 2
// 3 4
start_x=1-(Brush_width>>1);
start_y=1-(Brush_height>>1);
end_x=start_x+Brush_width-1;
end_y=start_y+Brush_height-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);
Transform_point(start_x,end_y , cos_a,sin_a, &x3,&y3);
Transform_point(end_x ,end_y , cos_a,sin_a, &x4,&y4);
x1+=Brush_rotation_center_X;
y1+=Brush_rotation_center_Y;
x2+=Brush_rotation_center_X;
y2+=Brush_rotation_center_Y;
x3+=Brush_rotation_center_X;
y3+=Brush_rotation_center_Y;
x4+=Brush_rotation_center_X;
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);
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));
end_y=Max(Max(y1,y2),Max(y3,y4));
Update_part_of_screen(start_x,start_y,end_x-start_x+1,end_y-start_y+1);
}