/* 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 Calculer_dimensions_clipees(short * x,short * y,short * width,short * height)
{
if ((*x)(Limite_Droite+1))
{
(*width)=(Limite_Droite-(*x))+1;
}
if ((*y)(Limite_Bas+1))
{
(*height)=(Limite_Bas-(*y))+1;
}
}
// -- Calcul de redimensionnement du pinceau pour éviter les débordements
// de l'écran zoomé et de l'image --
void Calculer_dimensions_clipees_zoom(short * x,short * y,short * width,short * height)
{
if ((*x)(Limite_Droite_Zoom+1))
{
(*width)=(Limite_Droite_Zoom-(*x))+1;
}
if ((*y)(Limite_Bas_Zoom+1))
{
(*height)=(Limite_Bas_Zoom-(*y))+1;
}
}
// -- Afficher le pinceau (de façon définitive ou non) --
void Afficher_pinceau(short x,short y,byte Couleur,byte is_preview)
// x,y: position du centre du pinceau
// Couleur: couleur à appliquer au pinceau
// is_preview: "Il ne faut l'afficher qu'à l'écran"
{
short Debut_X; // Position X (dans l'image) à partir de laquelle on
// affiche la brosse/pinceau
short Debut_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 Debut_Compteur_X; // Position X (dans la brosse/pinceau) à partir
// de laquelle on affiche la brosse/pinceau
short Debut_Compteur_Y; // 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 Compteur_X; // Position X (dans la brosse/pinceau) en cours
// d'affichage
short Compteur_Y; // Position Y (dans la brosse/pinceau) en cours
// d'affichage
short Fin_Compteur_X; // Position X ou s'arrête l'affichade de la
// brosse/pinceau
short Fin_Compteur_Y; // Position Y ou s'arrête l'affichade de la
// brosse/pinceau
byte Couleur_temporaire; // Couleur de la brosse en cours d'affichage
int position;
byte * Temp;
if (!(is_preview && Mouse_K)) // Si bouton enfoncé & preview > pas de dessin
switch (Pinceau_Forme)
{
case FORME_PINCEAU_POINT : // !!! TOUJOURS EN PREVIEW !!!
if ( (Pinceau_X>=Limite_Gauche)
&& (Pinceau_X<=Limite_Droite)
&& (Pinceau_Y>=Limite_Haut)
&& (Pinceau_Y<=Limite_Bas) )
{
Pixel_Preview(Pinceau_X,Pinceau_Y,Couleur);
Mettre_Ecran_A_Jour(x,y,1,1);
}
break;
case FORME_PINCEAU_BROSSE_COULEUR : // Brosse en couleur
Debut_X=x-Brosse_Decalage_X;
Debut_Y=y-Brosse_Decalage_Y;
width=Brosse_Largeur;
height=Brosse_Hauteur;
Calculer_dimensions_clipees(&Debut_X,&Debut_Y,&width,&height);
if (width<=0 || height<=0)
break;
Debut_Compteur_X=Debut_X-(x-Brosse_Decalage_X);
Debut_Compteur_Y=Debut_Y-(y-Brosse_Decalage_Y);
Fin_Compteur_X=Debut_Compteur_X+width;
Fin_Compteur_Y=Debut_Compteur_Y+height;
if (is_preview)
{
if ( (width>0) && (height>0) )
Display_brush_Color(
Debut_X-Principal_Decalage_X,
Debut_Y-Principal_Decalage_Y,
Debut_Compteur_X,
Debut_Compteur_Y,
width,
height,
Back_color,
Brosse_Largeur
);
if (Loupe_Mode)
{
Calculer_dimensions_clipees_zoom(&Debut_X,&Debut_Y,&width,
&height
);
Debut_Compteur_X=Debut_X-(x-Brosse_Decalage_X);
Debut_Compteur_Y=Debut_Y-(y-Brosse_Decalage_Y);
if ( (width>0) && (height>0) )
{
// Corrections dues au Zoom:
Debut_X=(Debut_X-Loupe_Decalage_X)*Loupe_Facteur;
Debut_Y=(Debut_Y-Loupe_Decalage_Y)*Loupe_Facteur;
height=Debut_Y+(height*Loupe_Facteur);
if (height>Menu_Ordonnee)
height=Menu_Ordonnee;
Display_brush_Color_zoom(Principal_X_Zoom+Debut_X,Debut_Y,
Debut_Compteur_X,Debut_Compteur_Y,
width,height,Back_color,
Brosse_Largeur,
Buffer_de_ligne_horizontale);
}
}
Mettre_Ecran_A_Jour(x-Brosse_Decalage_X,y-Brosse_Decalage_Y,Brosse_Largeur,Brosse_Hauteur);
}
else
{
if ((Smear_Mode) && (Shade_Table==Shade_Table_gauche))
{
if (Smear_Debut)
{
if ((width>0) && (height>0))
{
Copier_une_partie_d_image_dans_une_autre(
Principal_Ecran, Debut_X, Debut_Y, width, height,
Principal_Largeur_image, Smear_Brosse,
Debut_Compteur_X, Debut_Compteur_Y,
Smear_Brosse_Largeur
);
Mettre_Ecran_A_Jour(Debut_X,Debut_Y,width,height);
}
Smear_Debut=0;
}
else
{
for (y_pos = Debut_Y, Compteur_Y = Debut_Compteur_Y;
Compteur_Y < Fin_Compteur_Y;
y_pos++, Compteur_Y++
)
for (x_pos = Debut_X, Compteur_X = Debut_Compteur_X;
Compteur_X < Fin_Compteur_X;
x_pos++, Compteur_X++
)
{
Couleur_temporaire = Lit_pixel_dans_ecran_courant(
x_pos,y_pos
);
position = (Compteur_Y * Smear_Brosse_Largeur)+ Compteur_X;
if ( (Lit_pixel_dans_brosse(Compteur_X,Compteur_Y) != Back_color)
&& (Compteur_Y=Smear_Min_Y) && (Compteur_X>=Smear_Min_X) )
Afficher_pixel(x_pos,y_pos,Smear_Brosse[position]);
Smear_Brosse[position]=Couleur_temporaire;
}
Mettre_Ecran_A_Jour(Debut_X,Debut_Y,width,height);
}
Smear_Min_X=Debut_Compteur_X;
Smear_Min_Y=Debut_Compteur_Y;
Smear_Max_X=Fin_Compteur_X;
Smear_Max_Y=Fin_Compteur_Y;
}
else
{
if (Shade_Table==Shade_Table_gauche)
for (y_pos=Debut_Y,Compteur_Y=Debut_Compteur_Y;Compteur_Y0) && (height>0) )
Display_brush_Mono(Debut_X-Principal_Decalage_X,
Debut_Y-Principal_Decalage_Y,
Debut_Compteur_X,Debut_Compteur_Y,
width,height,
Back_color,Fore_color,
Brosse_Largeur);
if (Loupe_Mode)
{
Calculer_dimensions_clipees_zoom(&Debut_X,&Debut_Y,&width,&height);
Debut_Compteur_X=Debut_X-(x-Brosse_Decalage_X);
Debut_Compteur_Y=Debut_Y-(y-Brosse_Decalage_Y);
if ( (width>0) && (height>0) )
{
// Corrections dues au Zoom:
Debut_X=(Debut_X-Loupe_Decalage_X)*Loupe_Facteur;
Debut_Y=(Debut_Y-Loupe_Decalage_Y)*Loupe_Facteur;
height=Debut_Y+(height*Loupe_Facteur);
if (height>Menu_Ordonnee)
height=Menu_Ordonnee;
Display_brush_Mono_zoom(Principal_X_Zoom+Debut_X,Debut_Y,
Debut_Compteur_X,Debut_Compteur_Y,
width,height,
Back_color,Fore_color,
Brosse_Largeur,
Buffer_de_ligne_horizontale);
}
}
Mettre_Ecran_A_Jour(x-Brosse_Decalage_X,y-Brosse_Decalage_Y,Brosse_Largeur,Brosse_Hauteur);
}
else
{
if ((Smear_Mode) && (Shade_Table==Shade_Table_gauche))
{
if (Smear_Debut)
{
if ((width>0) && (height>0))
{
Copier_une_partie_d_image_dans_une_autre(Principal_Ecran,
Debut_X,Debut_Y,
width,height,
Principal_Largeur_image,
Smear_Brosse,
Debut_Compteur_X,
Debut_Compteur_Y,
Smear_Brosse_Largeur);
Mettre_Ecran_A_Jour(Debut_X,Debut_Y,width,height);
}
Smear_Debut=0;
}
else
{
for (y_pos=Debut_Y,Compteur_Y=Debut_Compteur_Y;Compteur_Y=Smear_Min_Y) && (Compteur_X>=Smear_Min_X) )
Afficher_pixel(x_pos,y_pos,Smear_Brosse[position]);
Smear_Brosse[position]=Couleur_temporaire;
}
Mettre_Ecran_A_Jour(Debut_X,Debut_Y,width,height);
}
Smear_Min_X=Debut_Compteur_X;
Smear_Min_Y=Debut_Compteur_Y;
Smear_Max_X=Fin_Compteur_X;
Smear_Max_Y=Fin_Compteur_Y;
}
else
{
for (y_pos=Debut_Y,Compteur_Y=Debut_Compteur_Y;Compteur_Y0) && (height>0) )
Display_brush_Mono(Debut_X-Principal_Decalage_X,
Debut_Y-Principal_Decalage_Y,
Debut_Compteur_X,Debut_Compteur_Y,
width,height,
0,Fore_color,
TAILLE_MAXI_PINCEAU);
if (Loupe_Mode)
{
Calculer_dimensions_clipees_zoom(&Debut_X,&Debut_Y,&width,&height);
Debut_Compteur_X=Debut_X-(x-Pinceau_Decalage_X);
Debut_Compteur_Y=Debut_Y-(y-Pinceau_Decalage_Y);
if ( (width>0) && (height>0) )
{
// Corrections dues au Zoom:
Debut_X=(Debut_X-Loupe_Decalage_X)*Loupe_Facteur;
Debut_Y=(Debut_Y-Loupe_Decalage_Y)*Loupe_Facteur;
height=Debut_Y+(height*Loupe_Facteur);
if (height>Menu_Ordonnee)
height=Menu_Ordonnee;
Display_brush_Mono_zoom(Principal_X_Zoom+Debut_X,Debut_Y,
Debut_Compteur_X,Debut_Compteur_Y,
width,height,
0,Fore_color,
TAILLE_MAXI_PINCEAU,
Buffer_de_ligne_horizontale);
}
}
Brosse=Temp;
}
else
{
if ((Smear_Mode) && (Shade_Table==Shade_Table_gauche))
{
if (Smear_Debut)
{
if ((width>0) && (height>0))
{
Copier_une_partie_d_image_dans_une_autre(Principal_Ecran,
Debut_X,Debut_Y,
width,height,
Principal_Largeur_image,
Smear_Brosse,
Debut_Compteur_X,
Debut_Compteur_Y,
Smear_Brosse_Largeur);
Mettre_Ecran_A_Jour(Debut_X,Debut_Y,width,height);
}
Smear_Debut=0;
}
else
{
for (y_pos=Debut_Y,Compteur_Y=Debut_Compteur_Y;Compteur_Y=Smear_Min_Y) && (Compteur_X>=Smear_Min_X) )
Afficher_pixel(x_pos,y_pos,Smear_Brosse[position]);
Smear_Brosse[position]=Couleur_temporaire;
}
Mettre_Ecran_A_Jour(Debut_X, Debut_Y, width, height);
}
Smear_Min_X=Debut_Compteur_X;
Smear_Min_Y=Debut_Compteur_Y;
Smear_Max_X=Fin_Compteur_X;
Smear_Max_Y=Fin_Compteur_Y;
}
else
{
for (y_pos=Debut_Y,Compteur_Y=Debut_Compteur_Y;Compteur_Y=Limite_Gauche)
&& (Pinceau_X<=Limite_Droite)
&& (Pinceau_Y>=Limite_Haut)
&& (Pinceau_Y<=Limite_Bas) )
{
Pixel_Preview(Pinceau_X,Pinceau_Y,Lit_pixel_dans_ecran_courant(Pinceau_X,Pinceau_Y));
Mettre_Ecran_A_Jour(Pinceau_X,Pinceau_Y,1,1);
}
break;
case FORME_PINCEAU_BROSSE_COULEUR : // Brosse en couleur
case FORME_PINCEAU_BROSSE_MONOCHROME : // Brosse monochrome
Debut_X=x-Brosse_Decalage_X;
Debut_Y=y-Brosse_Decalage_Y;
width=Brosse_Largeur;
height=Brosse_Hauteur;
Calculer_dimensions_clipees(&Debut_X,&Debut_Y,&width,&height);
Debut_Compteur_X=Debut_X-(x-Brosse_Decalage_X);
Debut_Compteur_Y=Debut_Y-(y-Brosse_Decalage_Y);
Fin_Compteur_X=Debut_Compteur_X+width;
Fin_Compteur_Y=Debut_Compteur_Y+height;
if ( (width>0) && (height>0) )
Clear_brush(Debut_X-Principal_Decalage_X,
Debut_Y-Principal_Decalage_Y,
Debut_Compteur_X,Debut_Compteur_Y,
width,height,Back_color,
Principal_Largeur_image);
if (Loupe_Mode)
{
Calculer_dimensions_clipees_zoom(&Debut_X,&Debut_Y,&width,&height);
Debut_Compteur_X=Debut_X;
Debut_Compteur_Y=Debut_Y;
if ( (width>0) && (height>0) )
{
// Corrections dues au Zoom:
Debut_X=(Debut_X-Loupe_Decalage_X)*Loupe_Facteur;
Debut_Y=(Debut_Y-Loupe_Decalage_Y)*Loupe_Facteur;
height=Debut_Y+(height*Loupe_Facteur);
if (height>Menu_Ordonnee)
height=Menu_Ordonnee;
Clear_brush_zoom(Principal_X_Zoom+Debut_X,Debut_Y,
Debut_Compteur_X,Debut_Compteur_Y,
width,height,Back_color,
Principal_Largeur_image,
Buffer_de_ligne_horizontale);
}
}
break;
default: // Pinceau
Debut_X=x-Pinceau_Decalage_X;
Debut_Y=y-Pinceau_Decalage_Y;
width=Pinceau_Largeur;
height=Pinceau_Hauteur;
Calculer_dimensions_clipees(&Debut_X,&Debut_Y,&width,&height);
Debut_Compteur_X=Debut_X-(x-Pinceau_Decalage_X);
Debut_Compteur_Y=Debut_Y-(y-Pinceau_Decalage_Y);
Fin_Compteur_X=Debut_Compteur_X+width;
Fin_Compteur_Y=Debut_Compteur_Y+height;
Temp=Brosse;
Brosse=Pinceau_Sprite;
if ( (width>0) && (height>0) )
{
Clear_brush(Debut_X-Principal_Decalage_X,
Debut_Y-Principal_Decalage_Y,
Debut_Compteur_X,Debut_Compteur_Y,
width,height,0,
Principal_Largeur_image);
}
if (Loupe_Mode)
{
Calculer_dimensions_clipees_zoom(&Debut_X,&Debut_Y,&width,&height);
Debut_Compteur_X=Debut_X;
Debut_Compteur_Y=Debut_Y;
if ( (width>0) && (height>0) )
{
// Corrections dues au Zoom:
Debut_X=(Debut_X-Loupe_Decalage_X)*Loupe_Facteur;
Debut_Y=(Debut_Y-Loupe_Decalage_Y)*Loupe_Facteur;
height=Debut_Y+(height*Loupe_Facteur);
if (height>Menu_Ordonnee)
height=Menu_Ordonnee;
Clear_brush_zoom(Principal_X_Zoom+Debut_X,Debut_Y,
Debut_Compteur_X,Debut_Compteur_Y,
width,height,0,
Principal_Largeur_image,
Buffer_de_ligne_horizontale);
}
}
Brosse=Temp;
break;
}
}
void Capturer_brosse(short Debut_X,short Debut_Y,short Fin_X,short Fin_Y,short clear)
{
short Temporaire;
short x_pos;
short y_pos;
word Nouvelle_Brosse_Largeur;
word Nouvelle_Brosse_Hauteur;
// On commence par "redresser" les bornes:
if (Debut_X>Fin_X)
{
Temporaire=Debut_X;
Debut_X =Fin_X;
Fin_X =Temporaire;
}
if (Debut_Y>Fin_Y)
{
Temporaire=Debut_Y;
Debut_Y =Fin_Y;
Fin_Y =Temporaire;
}
// On ne capture la nouvelle brosse que si elle est au moins partiellement
// dans l'image:
if ((Debut_XPrincipal_Largeur_image)
Nouvelle_Brosse_Largeur=Principal_Largeur_image-Debut_X;
if (Debut_Y+Nouvelle_Brosse_Hauteur>Principal_Hauteur_image)
Nouvelle_Brosse_Hauteur=Principal_Hauteur_image-Debut_Y;
if ( (((long)Brosse_Hauteur)*Brosse_Largeur) !=
(((long)Nouvelle_Brosse_Hauteur)*Nouvelle_Brosse_Largeur) )
{
free(Brosse);
Brosse=(byte *)malloc(((long)Nouvelle_Brosse_Hauteur)*Nouvelle_Brosse_Largeur);
if (!Brosse)
{
Erreur(0);
Brosse=(byte *)malloc(1*1);
Nouvelle_Brosse_Hauteur=Nouvelle_Brosse_Largeur=1;
*Brosse=Fore_color;
}
}
Brosse_Largeur=Nouvelle_Brosse_Largeur;
Brosse_Hauteur=Nouvelle_Brosse_Hauteur;
free(Smear_Brosse);
Smear_Brosse_Largeur=(Brosse_Largeur>TAILLE_MAXI_PINCEAU)?Brosse_Largeur:TAILLE_MAXI_PINCEAU;
Smear_Brosse_Hauteur=(Brosse_Hauteur>TAILLE_MAXI_PINCEAU)?Brosse_Hauteur:TAILLE_MAXI_PINCEAU;
Smear_Brosse=(byte *)malloc(((long)Smear_Brosse_Hauteur)*Smear_Brosse_Largeur);
if (!Smear_Brosse) // On ne peut même pas allouer la brosse du smear!
{
Erreur(0);
free(Brosse);
Brosse=(byte *)malloc(1*1);
Brosse_Hauteur=1;
Brosse_Largeur=1;
Smear_Brosse=(byte *)malloc(TAILLE_MAXI_PINCEAU*TAILLE_MAXI_PINCEAU);
Smear_Brosse_Hauteur=TAILLE_MAXI_PINCEAU;
Smear_Brosse_Largeur=TAILLE_MAXI_PINCEAU;
}
Copier_image_dans_brosse(Debut_X,Debut_Y,Brosse_Largeur,Brosse_Hauteur,Principal_Largeur_image);
// On regarde s'il faut effacer quelque chose:
if (clear)
{
for (y_pos=Debut_Y;y_pos>1);
Brosse_Decalage_Y=(Brosse_Hauteur>>1);
}
}
void Rotate_90_deg()
{
short Temporaire;
byte * Nouvelle_Brosse;
Nouvelle_Brosse=(byte *)malloc(((long)Brosse_Hauteur)*Brosse_Largeur);
if (Nouvelle_Brosse)
{
Rotate_90_deg_LOWLEVEL(Brosse,Nouvelle_Brosse);
free(Brosse);
Brosse=Nouvelle_Brosse;
Temporaire=Brosse_Largeur;
Brosse_Largeur=Brosse_Hauteur;
Brosse_Hauteur=Temporaire;
Temporaire=Smear_Brosse_Largeur;
Smear_Brosse_Largeur=Smear_Brosse_Hauteur;
Smear_Brosse_Hauteur=Temporaire;
// On centre la prise sur la brosse
Brosse_Decalage_X=(Brosse_Largeur>>1);
Brosse_Decalage_Y=(Brosse_Hauteur>>1);
}
else
Erreur(0);
}
void Remap_brosse(void)
{
short x_pos; // Variable de balayage de la brosse
short y_pos; // Variable de balayage de la brosse
byte Utilisee[256]; // Tableau de booléens "La couleur est utilisée"
int Couleur;
// On commence par initialiser le tableau de booléens à faux
for (Couleur=0;Couleur<=255;Couleur++)
Utilisee[Couleur]=0;
// On calcule la table d'utilisation des couleurs
for (y_pos=0;y_pos>1);
Brosse_Decalage_Y=(Brosse_Hauteur>>1);
free(Temporaire); // Libération de l'ancienne brosse
// Réallocation d'un buffer de Smear
free(Smear_Brosse);
Smear_Brosse_Largeur=(Brosse_Largeur>TAILLE_MAXI_PINCEAU)?Brosse_Largeur:TAILLE_MAXI_PINCEAU;
Smear_Brosse_Hauteur=(Brosse_Hauteur>TAILLE_MAXI_PINCEAU)?Brosse_Hauteur:TAILLE_MAXI_PINCEAU;
Smear_Brosse=(byte *)malloc(((long)Smear_Brosse_Largeur)*Smear_Brosse_Hauteur);
}
else
Erreur(0); // Pas assez de mémoire!
}
void Nibble_brush(void)
{
long /*Pos,*/x_pos,y_pos;
byte state;
byte * Nouvelle_brosse;
byte * Temporaire;
word width;
word height;
if ( (Brosse_Largeur>2) && (Brosse_Hauteur>2) )
{
width=Brosse_Largeur-2;
height=Brosse_Hauteur-2;
Nouvelle_brosse=(byte *)malloc(((long)width)*height);
if (Nouvelle_brosse)
{
// On copie la brosse courante dans la nouvelle
Copier_une_partie_d_image_dans_une_autre(Brosse, // Source
1,
1,
width,
height,
Brosse_Largeur,
Nouvelle_brosse, // Destination
0,
0,
width);
// On intervertit la nouvelle et l'ancienne brosse:
Temporaire=Brosse;
Brosse=Nouvelle_brosse;
Brosse_Largeur-=2;
Brosse_Hauteur-=2;
width+=2;
height+=2;
// 1er balayage (horizontal)
for (y_pos=0; y_pos0)
Pixel_dans_brosse(x_pos-1,y_pos,Back_color);
state=0;
}
}
else
{
if (!state)
{
Pixel_dans_brosse(x_pos,y_pos,Back_color);
state=1;
}
}
}
// Cas du dernier pixel à droite de la ligne
if (Temporaire[((y_pos+1)*width)+x_pos+1]==Back_color)
Pixel_dans_brosse(x_pos-1,y_pos,Back_color);
}
// 2ème balayage (vertical)
for (x_pos=0; x_pos0)
Pixel_dans_brosse(x_pos,y_pos-1,Back_color);
state=0;
}
}
else
{
if (!state)
{
Pixel_dans_brosse(x_pos,y_pos,Back_color);
state=1;
}
}
}
// Cas du dernier pixel en bas de la colonne
if (Temporaire[((y_pos+1)*width)+x_pos+1]==Back_color)
Pixel_dans_brosse(x_pos,y_pos-1,Back_color);
}
// On recentre la prise sur la brosse
Brosse_Decalage_X=(Brosse_Largeur>>1);
Brosse_Decalage_Y=(Brosse_Hauteur>>1);
free(Temporaire); // Libération de l'ancienne brosse
// Réallocation d'un buffer de Smear
free(Smear_Brosse);
Smear_Brosse_Largeur=(Brosse_Largeur>TAILLE_MAXI_PINCEAU)?Brosse_Largeur:TAILLE_MAXI_PINCEAU;
Smear_Brosse_Hauteur=(Brosse_Hauteur>TAILLE_MAXI_PINCEAU)?Brosse_Hauteur:TAILLE_MAXI_PINCEAU;
Smear_Brosse=(byte *)malloc(((long)Smear_Brosse_Largeur)*Smear_Brosse_Hauteur);
}
else
Erreur(0); // Pas assez de mémoire!
}
}
void Capturer_brosse_au_lasso(int Vertices, short * Points,short clear)
{
short Debut_X=Limite_Droite+1;
short Debut_Y=Limite_Bas+1;
short Fin_X=Limite_Gauche-1;
short Fin_Y=Limite_Haut-1;
short Temporaire;
short x_pos;
short y_pos;
word Nouvelle_Brosse_Largeur;
word Nouvelle_Brosse_Hauteur;
// On recherche les bornes de la brosse:
for (Temporaire=0; TemporaireFin_X)
Fin_X=x_pos;
if (y_posFin_Y)
Fin_Y=y_pos;
}
// On clippe ces bornes à l'écran:
if (Debut_XLimite_Droite)
Fin_X=Limite_Droite;
if (Debut_YLimite_Bas)
Fin_Y=Limite_Bas;
// On ne capture la nouvelle brosse que si elle est au moins partiellement
// dans l'image:
if ((Debut_XTAILLE_MAXI_PINCEAU)?Brosse_Largeur:TAILLE_MAXI_PINCEAU;
Smear_Brosse_Hauteur=(Brosse_Hauteur>TAILLE_MAXI_PINCEAU)?Brosse_Hauteur:TAILLE_MAXI_PINCEAU;
Smear_Brosse=(byte *)malloc(((long)Smear_Brosse_Hauteur)*Smear_Brosse_Largeur);
if (!Smear_Brosse) // On ne peut même pas allouer la brosse du smear!
{
Erreur(0);
free(Brosse);
Brosse=(byte *)malloc(1*1);
Brosse_Hauteur=1;
Brosse_Largeur=1;
Smear_Brosse=(byte *)malloc(TAILLE_MAXI_PINCEAU*TAILLE_MAXI_PINCEAU);
Smear_Brosse_Hauteur=TAILLE_MAXI_PINCEAU;
Smear_Brosse_Largeur=TAILLE_MAXI_PINCEAU;
}
Brosse_Decalage_X=Debut_X;
Brosse_Decalage_Y=Debut_Y;
Pixel_figure=Pixel_figure_Dans_brosse;
memset(Brosse,Back_color,(long)Brosse_Largeur*Brosse_Hauteur);
Polyfill_General(Vertices,Points,~Back_color);
// On retrace les bordures du lasso:
for (Temporaire=1; Temporaire>1);
Brosse_Decalage_Y=(Brosse_Hauteur>>1);
}
}
//------------------------- Etirement de la brosse ---------------------------
void Etirer_brosse(short X1, short Y1, short X2, short Y2)
{
int offset,line,Colonne;
byte * New_Brosse;
int New_Brosse_Largeur; // Width de la nouvelle brosse
int New_Brosse_Hauteur; // Height de la nouvelle brosse
int Pos_X_dans_brosse; // Position courante dans l'ancienne brosse
int Pos_Y_dans_brosse;
int Delta_X_dans_brosse; // "Vecteur incrémental" du point précédent
int Delta_Y_dans_brosse;
int Pos_X_initial; // Position X de début de parcours de ligne
int Dx,Dy;
Dx=(X1=0)
Pos_X_initial = 0; // Pas d'inversion en X de la brosse
else
Pos_X_initial = (Brosse_Largeur<<16)-1; // Inversion en X de la brosse
free(Smear_Brosse); // On libère un peu de mémoire
if ((New_Brosse=((byte *)malloc(New_Brosse_Largeur*New_Brosse_Hauteur))))
{
offset=0;
// Calcul de la valeur initiale de y_pos:
if (Dy>=0)
Pos_Y_dans_brosse=0; // Pas d'inversion en Y de la brosse
else
Pos_Y_dans_brosse=(Brosse_Hauteur<<16)-1; // Inversion en Y de la brosse
// Pour chaque ligne
for (line=0;line>16,Pos_Y_dans_brosse>>16);
// On passe à la colonne de brosse suivante:
Pos_X_dans_brosse+=Delta_X_dans_brosse;
// On passe au pixel suivant de la nouvelle brosse:
offset++;
}
// On passe à la ligne de brosse suivante:
Pos_Y_dans_brosse+=Delta_Y_dans_brosse;
}
free(Brosse);
Brosse=New_Brosse;
Brosse_Largeur=New_Brosse_Largeur;
Brosse_Hauteur=New_Brosse_Hauteur;
Smear_Brosse_Largeur=(Brosse_Largeur>TAILLE_MAXI_PINCEAU)?Brosse_Largeur:TAILLE_MAXI_PINCEAU;
Smear_Brosse_Hauteur=(Brosse_Hauteur>TAILLE_MAXI_PINCEAU)?Brosse_Hauteur:TAILLE_MAXI_PINCEAU;
Smear_Brosse=(byte *)malloc(((long)Smear_Brosse_Hauteur)*Smear_Brosse_Largeur);
if (!Smear_Brosse) // On ne peut même pas allouer la brosse du smear!
{
Erreur(0);
free(Brosse);
Brosse=(byte *)malloc(1*1);
Brosse_Hauteur=1;
Brosse_Largeur=1;
Smear_Brosse=(byte *)malloc(TAILLE_MAXI_PINCEAU*TAILLE_MAXI_PINCEAU);
Smear_Brosse_Hauteur=TAILLE_MAXI_PINCEAU;
Smear_Brosse_Largeur=TAILLE_MAXI_PINCEAU;
}
Brosse_Decalage_X=(Brosse_Largeur>>1);
Brosse_Decalage_Y=(Brosse_Hauteur>>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_Brosse car il y a
// normalement la place pour elle puisque rien d'autre n'a pu être alloué
// entre temps.
Smear_Brosse=(byte *)malloc(((long)Smear_Brosse_Hauteur)*Smear_Brosse_Largeur);
Erreur(0);
}
}
void Etirer_brosse_preview(short X1, short Y1, short X2, short Y2)
{
int Pos_X_src,Pos_Y_src;
int Pos_X_src_Initiale,Pos_Y_src_Initiale;
int Delta_X,Delta_Y;
int Pos_X_dest,Pos_Y_dest;
int Pos_X_dest_Initiale,Pos_Y_dest_Initiale;
int Pos_X_dest_Finale,Pos_Y_dest_Finale;
int Largeur_dest,Hauteur_dest;
byte Couleur;
// 1er calcul des positions destination extremes:
Pos_X_dest_Initiale=Min(X1,X2);
Pos_Y_dest_Initiale=Min(Y1,Y2);
Pos_X_dest_Finale =Max(X1,X2);
Pos_Y_dest_Finale =Max(Y1,Y2);
// Calcul des dimensions de la destination:
Largeur_dest=Pos_X_dest_Finale-Pos_X_dest_Initiale+1;
Hauteur_dest=Pos_Y_dest_Finale-Pos_Y_dest_Initiale+1;
// Calcul des vecteurs d'incrémentation :
Delta_X=(Brosse_Largeur<<16)/Largeur_dest;
Delta_Y=(Brosse_Hauteur<<16)/Hauteur_dest;
// 1er calcul de la position X initiale dans la source:
Pos_X_src_Initiale=(Brosse_Largeur<<16)*
(Max(Pos_X_dest_Initiale,Limite_Gauche)-
Pos_X_dest_Initiale)/Largeur_dest;
// Calcul du clip de la destination:
Pos_X_dest_Initiale=Max(Pos_X_dest_Initiale,Limite_Gauche);
Pos_X_dest_Finale =Min(Pos_X_dest_Finale ,Limite_visible_Droite);
// On discute selon l'inversion en X
if (X1>X2)
{
// Inversion -> Inversion du signe de Delta_X
Delta_X=-Delta_X;
Pos_X_src_Initiale=(Brosse_Largeur<<16)-1-Pos_X_src_Initiale;
}
// 1er calcul de la position Y initiale dans la source:
Pos_Y_src_Initiale=(Brosse_Hauteur<<16)*
(Max(Pos_Y_dest_Initiale,Limite_Haut)-
Pos_Y_dest_Initiale)/Hauteur_dest;
// Calcul du clip de la destination:
Pos_Y_dest_Initiale=Max(Pos_Y_dest_Initiale,Limite_Haut);
Pos_Y_dest_Finale =Min(Pos_Y_dest_Finale ,Limite_visible_Bas);
// On discute selon l'inversion en Y
if (Y1>Y2)
{
// Inversion -> Inversion du signe de Delta_Y
Delta_Y=-Delta_Y;
Pos_Y_src_Initiale=(Brosse_Hauteur<<16)-1-Pos_Y_src_Initiale;
}
// Pour chaque ligne :
Pos_Y_src=Pos_Y_src_Initiale;
for (Pos_Y_dest=Pos_Y_dest_Initiale;Pos_Y_dest<=Pos_Y_dest_Finale;Pos_Y_dest++)
{
// Pour chaque colonne:
Pos_X_src=Pos_X_src_Initiale;
for (Pos_X_dest=Pos_X_dest_Initiale;Pos_X_dest<=Pos_X_dest_Finale;Pos_X_dest++)
{
Couleur=Lit_pixel_dans_brosse(Pos_X_src>>16,Pos_Y_src>>16);
if (Couleur!=Back_color)
Pixel_Preview(Pos_X_dest,Pos_Y_dest,Couleur);
Pos_X_src+=Delta_X;
}
Pos_Y_src+=Delta_Y;
}
Mettre_Ecran_A_Jour(Pos_X_dest_Initiale,Pos_Y_dest_Initiale,Largeur_dest,Hauteur_dest);
}
//------------------------- Rotation de la brosse ---------------------------
#define INDEFINI (-1.0e20F)
float * ScanY_Xt[2];
float * ScanY_Yt[2];
float * ScanY_X[2];
void Interpoler_texture(int Debut_X,int Debut_Y,int Xt1,int Yt1,
int Fin_X ,int Fin_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=Fin_X-Debut_X;
int Delta_Y2=Fin_Y-Debut_Y;
float Xt,Yt;
x_pos=Debut_X;
y_pos=Debut_Y;
if (Debut_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]==INDEFINI) // 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]==INDEFINI) // 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]==INDEFINI) // 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]==INDEFINI) // 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 Calculer_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 Xmin,/*Xmax,*/Ymin/*,Ymax*/;
int x,y,Xt,Yt;
int Debut_X,Fin_X,Largeur_ligne;
float Temp;
//byte Couleur;
Xmin=Min(Min(X1,X2),Min(X3,X4));
Ymin=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));
// Remplir avec des valeurs égales à INDEFINI.
for (y=0; y>1);
Debut_Y=1-(Brosse_Hauteur>>1);
Fin_X=Debut_X+Brosse_Largeur-1;
Fin_Y=Debut_Y+Brosse_Hauteur-1;
Transformer_point(Debut_X,Debut_Y, cosA,sinA, &X1,&Y1);
Transformer_point(Fin_X ,Debut_Y, cosA,sinA, &X2,&Y2);
Transformer_point(Debut_X,Fin_Y , cosA,sinA, &X3,&Y3);
Transformer_point(Fin_X ,Fin_Y , cosA,sinA, &X4,&Y4);
// Calcul des nouvelles dimensions de la brosse:
Xmin=Min(Min((int)X1,(int)X2),Min((int)X3,(int)X4));
Xmax=Max(Max((int)X1,(int)X2),Max((int)X3,(int)X4));
Ymin=Min(Min((int)Y1,(int)Y2),Min((int)Y3,(int)Y4));
Ymax=Max(Max((int)Y1,(int)Y2),Max((int)Y3,(int)Y4));
New_Brosse_Largeur=Xmax+1-Xmin;
New_Brosse_Hauteur=Ymax+1-Ymin;
free(Smear_Brosse); // On libère un peu de mémoire
if ((New_Brosse=((byte *)malloc(New_Brosse_Largeur*New_Brosse_Hauteur))))
{
// Et maintenant on calcule la nouvelle brosse tournée.
Calculer_quad_texture(X1,Y1, 0, 0,
X2,Y2,Brosse_Largeur-1, 0,
X3,Y3, 0,Brosse_Hauteur-1,
X4,Y4,Brosse_Largeur-1,Brosse_Hauteur-1,
New_Brosse,New_Brosse_Largeur,New_Brosse_Hauteur);
free(Brosse);
Brosse=New_Brosse;
Brosse_Largeur=New_Brosse_Largeur;
Brosse_Hauteur=New_Brosse_Hauteur;
Smear_Brosse_Largeur=(Brosse_Largeur>TAILLE_MAXI_PINCEAU)?Brosse_Largeur:TAILLE_MAXI_PINCEAU;
Smear_Brosse_Hauteur=(Brosse_Hauteur>TAILLE_MAXI_PINCEAU)?Brosse_Hauteur:TAILLE_MAXI_PINCEAU;
Smear_Brosse=(byte *)malloc(((long)Smear_Brosse_Hauteur)*Smear_Brosse_Largeur);
if (!Smear_Brosse) // On ne peut même pas allouer la brosse du smear!
{
Erreur(0);
free(Brosse);
Brosse=(byte *)malloc(1*1);
Brosse_Hauteur=1;
Brosse_Largeur=1;
Smear_Brosse=(byte *)malloc(TAILLE_MAXI_PINCEAU*TAILLE_MAXI_PINCEAU);
Smear_Brosse_Hauteur=TAILLE_MAXI_PINCEAU;
Smear_Brosse_Largeur=TAILLE_MAXI_PINCEAU;
}
Brosse_Decalage_X=(Brosse_Largeur>>1);
Brosse_Decalage_Y=(Brosse_Hauteur>>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_Brosse car il y a
// normalement la place pour elle puisque rien d'autre n'a pu être alloué
// entre temps.
Smear_Brosse=(byte *)malloc(((long)Smear_Brosse_Hauteur)*Smear_Brosse_Largeur);
Erreur(0);
}
}
void Dessiner_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 Xmin,Xmax,Ymin,Ymax;
int x,y,Xt,Yt;
int Y_,Ymin_;
int Debut_X,Fin_X,width,height;
float Temp;
byte Couleur;
Xmin=Min(Min(X1,X2),Min(X3,X4));
Xmax=Max(Max(X1,X2),Max(X3,X4));
Ymin=Min(Min(Y1,Y2),Min(Y3,Y4));
Ymax=Max(Max(Y1,Y2),Max(Y3,Y4));
height=1+Ymax-Ymin;
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));
// Remplir avec des valeurs égales à INDEFINI.
for (y=0; yLimite_Bas) Ymax=Limite_Bas;
for (Y_=Ymin; Y_<=Ymax; Y_++)
{
y=Y_-Ymin_;
Debut_X=Round(ScanY_X[0][y]);
Fin_X =Round(ScanY_X[1][y]);
width=1+Fin_X-Debut_X;
if (Debut_XLimite_Droite) Fin_X=Limite_Droite;
for (x=Debut_X; x<=Fin_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])));
Couleur=Lit_pixel_dans_brosse(Xt,Yt);
if (Couleur!=Back_color)
Pixel_Preview(x,Y_,Couleur);
}
}
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 Tourner_brosse_preview(float angle)
{
short X1,Y1,X2,Y2,X3,Y3,X4,Y4;
int Debut_X,Fin_X,Debut_Y,Fin_Y;
float cosA=cos(angle);
float sinA=sin(angle);
// Calcul des coordonnées des 4 coins:
// 1 2
// 3 4
Debut_X=1-(Brosse_Largeur>>1);
Debut_Y=1-(Brosse_Hauteur>>1);
Fin_X=Debut_X+Brosse_Largeur-1;
Fin_Y=Debut_Y+Brosse_Hauteur-1;
Transformer_point(Debut_X,Debut_Y, cosA,sinA, &X1,&Y1);
Transformer_point(Fin_X ,Debut_Y, cosA,sinA, &X2,&Y2);
Transformer_point(Debut_X,Fin_Y , cosA,sinA, &X3,&Y3);
Transformer_point(Fin_X ,Fin_Y , cosA,sinA, &X4,&Y4);
X1+=Brosse_Centre_rotation_X;
Y1+=Brosse_Centre_rotation_Y;
X2+=Brosse_Centre_rotation_X;
Y2+=Brosse_Centre_rotation_Y;
X3+=Brosse_Centre_rotation_X;
Y3+=Brosse_Centre_rotation_Y;
X4+=Brosse_Centre_rotation_X;
Y4+=Brosse_Centre_rotation_Y;
// Et maintenant on dessine la brosse tournée.
Dessiner_quad_texture_preview(X1,Y1, 0, 0,
X2,Y2,Brosse_Largeur-1, 0,
X3,Y3, 0,Brosse_Hauteur-1,
X4,Y4,Brosse_Largeur-1,Brosse_Hauteur-1);
Debut_X=Min(Min(X1,X2),Min(X3,X4));
Fin_X=Max(Max(X1,X2),Max(X3,X4));
Debut_Y=Min(Min(Y1,Y2),Min(Y3,Y4));
Fin_Y=Max(Max(Y1,Y2),Max(Y3,Y4));
Mettre_Ecran_A_Jour(Debut_X,Debut_Y,Fin_X-Debut_X+1,Fin_Y-Debut_Y+1);
}