grafX2/brush.c
Adrien Destugues 154f5e824a Fixes all the tabulation problems.
git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@465 416bcca6-2ee7-4201-b75f-2eb2f807beb1
2009-01-05 22:55:30 +00:00

1769 lines
57 KiB
C

/* 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 <http://www.gnu.org/licenses/> or
write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
********************************************************************************
Brush manipulation functions
*/
#include <math.h>
#include <stdlib.h>
#include <string.h> // 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 * Largeur,short * Hauteur)
{
if ((*X)<Limite_Gauche)
{
(*Largeur)-=(Limite_Gauche-(*X));
(*X)=Limite_Gauche;
}
if (((*X)+(*Largeur))>(Limite_Droite+1))
{
(*Largeur)=(Limite_Droite-(*X))+1;
}
if ((*Y)<Limite_Haut)
{
(*Hauteur)-=(Limite_Haut-(*Y));
(*Y)=Limite_Haut;
}
if (((*Y)+(*Hauteur))>(Limite_Bas+1))
{
(*Hauteur)=(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 * Largeur,short * Hauteur)
{
if ((*X)<Limite_Gauche_Zoom)
{
(*Largeur)-=(Limite_Gauche_Zoom-(*X));
(*X)=Limite_Gauche_Zoom;
}
if (((*X)+(*Largeur))>(Limite_Droite_Zoom+1))
{
(*Largeur)=(Limite_Droite_Zoom-(*X))+1;
}
if ((*Y)<Limite_Haut_Zoom)
{
(*Hauteur)-=(Limite_Haut_Zoom-(*Y));
(*Y)=Limite_Haut_Zoom;
}
if (((*Y)+(*Hauteur))>(Limite_Bas_Zoom+1))
{
(*Hauteur)=(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 Preview)
// X,Y: position du centre du pinceau
// Couleur: couleur à appliquer au pinceau
// 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 Largeur; // Largeur dans l'écran selon laquelle on affiche la
// brosse/pinceau
short Hauteur; // Hauteur 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 Pos_X; // Position X (dans l'image) en cours d'affichage
short Pos_Y; // 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 (!(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;
Largeur=Brosse_Largeur;
Hauteur=Brosse_Hauteur;
Calculer_dimensions_clipees(&Debut_X,&Debut_Y,&Largeur,&Hauteur);
if (Largeur<=0 || Hauteur<=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+Largeur;
Fin_Compteur_Y=Debut_Compteur_Y+Hauteur;
if (Preview)
{
if ( (Largeur>0) && (Hauteur>0) )
Display_brush_Color(
Debut_X-Principal_Decalage_X,
Debut_Y-Principal_Decalage_Y,
Debut_Compteur_X,
Debut_Compteur_Y,
Largeur,
Hauteur,
Back_color,
Brosse_Largeur
);
if (Loupe_Mode)
{
Calculer_dimensions_clipees_zoom(&Debut_X,&Debut_Y,&Largeur,
&Hauteur
);
Debut_Compteur_X=Debut_X-(X-Brosse_Decalage_X);
Debut_Compteur_Y=Debut_Y-(Y-Brosse_Decalage_Y);
if ( (Largeur>0) && (Hauteur>0) )
{
// Corrections dues au Zoom:
Debut_X=(Debut_X-Loupe_Decalage_X)*Loupe_Facteur;
Debut_Y=(Debut_Y-Loupe_Decalage_Y)*Loupe_Facteur;
Hauteur=Debut_Y+(Hauteur*Loupe_Facteur);
if (Hauteur>Menu_Ordonnee)
Hauteur=Menu_Ordonnee;
Display_brush_Color_zoom(Principal_X_Zoom+Debut_X,Debut_Y,
Debut_Compteur_X,Debut_Compteur_Y,
Largeur,Hauteur,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 ((Largeur>0) && (Hauteur>0))
{
Copier_une_partie_d_image_dans_une_autre(
Principal_Ecran, Debut_X, Debut_Y, Largeur, Hauteur,
Principal_Largeur_image, Smear_Brosse,
Debut_Compteur_X, Debut_Compteur_Y,
Smear_Brosse_Largeur
);
Mettre_Ecran_A_Jour(Debut_X,Debut_Y,Largeur,Hauteur);
}
Smear_Debut=0;
}
else
{
for (Pos_Y = Debut_Y, Compteur_Y = Debut_Compteur_Y;
Compteur_Y < Fin_Compteur_Y;
Pos_Y++, Compteur_Y++
)
for (Pos_X = Debut_X, Compteur_X = Debut_Compteur_X;
Compteur_X < Fin_Compteur_X;
Pos_X++, Compteur_X++
)
{
Couleur_temporaire = Lit_pixel_dans_ecran_courant(
Pos_X,Pos_Y
);
Position = (Compteur_Y * Smear_Brosse_Largeur)+ Compteur_X;
if ( (Lit_pixel_dans_brosse(Compteur_X,Compteur_Y) != Back_color)
&& (Compteur_Y<Smear_Max_Y) && (Compteur_X<Smear_Max_X)
&& (Compteur_Y>=Smear_Min_Y) && (Compteur_X>=Smear_Min_X) )
Afficher_pixel(Pos_X,Pos_Y,Smear_Brosse[Position]);
Smear_Brosse[Position]=Couleur_temporaire;
}
Mettre_Ecran_A_Jour(Debut_X,Debut_Y,Largeur,Hauteur);
}
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 (Pos_Y=Debut_Y,Compteur_Y=Debut_Compteur_Y;Compteur_Y<Fin_Compteur_Y;Pos_Y++,Compteur_Y++)
for (Pos_X=Debut_X,Compteur_X=Debut_Compteur_X;Compteur_X<Fin_Compteur_X;Pos_X++,Compteur_X++)
{
Couleur_temporaire=Lit_pixel_dans_brosse(Compteur_X,Compteur_Y);
if (Couleur_temporaire!=Back_color)
Afficher_pixel(Pos_X,Pos_Y,Couleur_temporaire);
}
else
for (Pos_Y=Debut_Y,Compteur_Y=Debut_Compteur_Y;Compteur_Y<Fin_Compteur_Y;Pos_Y++,Compteur_Y++)
for (Pos_X=Debut_X,Compteur_X=Debut_Compteur_X;Compteur_X<Fin_Compteur_X;Pos_X++,Compteur_X++)
{
if (Lit_pixel_dans_brosse(Compteur_X,Compteur_Y)!=Back_color)
Afficher_pixel(Pos_X,Pos_Y,Couleur);
}
}
Mettre_Ecran_A_Jour(Debut_X,Debut_Y,Largeur,Hauteur);
}
break;
case FORME_PINCEAU_BROSSE_MONOCHROME : // Brosse monochrome
Debut_X=X-Brosse_Decalage_X;
Debut_Y=Y-Brosse_Decalage_Y;
Largeur=Brosse_Largeur;
Hauteur=Brosse_Hauteur;
Calculer_dimensions_clipees(&Debut_X,&Debut_Y,&Largeur,&Hauteur);
Debut_Compteur_X=Debut_X-(X-Brosse_Decalage_X);
Debut_Compteur_Y=Debut_Y-(Y-Brosse_Decalage_Y);
Fin_Compteur_X=Debut_Compteur_X+Largeur;
Fin_Compteur_Y=Debut_Compteur_Y+Hauteur;
if (Preview)
{
if ( (Largeur>0) && (Hauteur>0) )
Display_brush_Mono(Debut_X-Principal_Decalage_X,
Debut_Y-Principal_Decalage_Y,
Debut_Compteur_X,Debut_Compteur_Y,
Largeur,Hauteur,
Back_color,Fore_color,
Brosse_Largeur);
if (Loupe_Mode)
{
Calculer_dimensions_clipees_zoom(&Debut_X,&Debut_Y,&Largeur,&Hauteur);
Debut_Compteur_X=Debut_X-(X-Brosse_Decalage_X);
Debut_Compteur_Y=Debut_Y-(Y-Brosse_Decalage_Y);
if ( (Largeur>0) && (Hauteur>0) )
{
// Corrections dues au Zoom:
Debut_X=(Debut_X-Loupe_Decalage_X)*Loupe_Facteur;
Debut_Y=(Debut_Y-Loupe_Decalage_Y)*Loupe_Facteur;
Hauteur=Debut_Y+(Hauteur*Loupe_Facteur);
if (Hauteur>Menu_Ordonnee)
Hauteur=Menu_Ordonnee;
Display_brush_Mono_zoom(Principal_X_Zoom+Debut_X,Debut_Y,
Debut_Compteur_X,Debut_Compteur_Y,
Largeur,Hauteur,
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 ((Largeur>0) && (Hauteur>0))
{
Copier_une_partie_d_image_dans_une_autre(Principal_Ecran,
Debut_X,Debut_Y,
Largeur,Hauteur,
Principal_Largeur_image,
Smear_Brosse,
Debut_Compteur_X,
Debut_Compteur_Y,
Smear_Brosse_Largeur);
Mettre_Ecran_A_Jour(Debut_X,Debut_Y,Largeur,Hauteur);
}
Smear_Debut=0;
}
else
{
for (Pos_Y=Debut_Y,Compteur_Y=Debut_Compteur_Y;Compteur_Y<Fin_Compteur_Y;Pos_Y++,Compteur_Y++)
for (Pos_X=Debut_X,Compteur_X=Debut_Compteur_X;Compteur_X<Fin_Compteur_X;Pos_X++,Compteur_X++)
{
Couleur_temporaire=Lit_pixel_dans_ecran_courant(Pos_X,Pos_Y);
Position=(Compteur_Y*Smear_Brosse_Largeur)+Compteur_X;
if ( (Lit_pixel_dans_brosse(Compteur_X,Compteur_Y)!=Back_color)
&& (Compteur_Y<Smear_Max_Y) && (Compteur_X<Smear_Max_X)
&& (Compteur_Y>=Smear_Min_Y) && (Compteur_X>=Smear_Min_X) )
Afficher_pixel(Pos_X,Pos_Y,Smear_Brosse[Position]);
Smear_Brosse[Position]=Couleur_temporaire;
}
Mettre_Ecran_A_Jour(Debut_X,Debut_Y,Largeur,Hauteur);
}
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 (Pos_Y=Debut_Y,Compteur_Y=Debut_Compteur_Y;Compteur_Y<Fin_Compteur_Y;Pos_Y++,Compteur_Y++)
for (Pos_X=Debut_X,Compteur_X=Debut_Compteur_X;Compteur_X<Fin_Compteur_X;Pos_X++,Compteur_X++)
{
if (Lit_pixel_dans_brosse(Compteur_X,Compteur_Y)!=Back_color)
Afficher_pixel(Pos_X,Pos_Y,Couleur);
}
Mettre_Ecran_A_Jour(Debut_X,Debut_Y,Largeur,Hauteur);
}
}
break;
default : // Pinceau
Debut_X=X-Pinceau_Decalage_X;
Debut_Y=Y-Pinceau_Decalage_Y;
Largeur=Pinceau_Largeur;
Hauteur=Pinceau_Hauteur;
Calculer_dimensions_clipees(&Debut_X,&Debut_Y,&Largeur,&Hauteur);
Debut_Compteur_X=Debut_X-(X-Pinceau_Decalage_X);
Debut_Compteur_Y=Debut_Y-(Y-Pinceau_Decalage_Y);
Fin_Compteur_X=Debut_Compteur_X+Largeur;
Fin_Compteur_Y=Debut_Compteur_Y+Hauteur;
if (Preview)
{
Temp=Brosse;
Brosse=Pinceau_Sprite;
if ( (Largeur>0) && (Hauteur>0) )
Display_brush_Mono(Debut_X-Principal_Decalage_X,
Debut_Y-Principal_Decalage_Y,
Debut_Compteur_X,Debut_Compteur_Y,
Largeur,Hauteur,
0,Fore_color,
TAILLE_MAXI_PINCEAU);
if (Loupe_Mode)
{
Calculer_dimensions_clipees_zoom(&Debut_X,&Debut_Y,&Largeur,&Hauteur);
Debut_Compteur_X=Debut_X-(X-Pinceau_Decalage_X);
Debut_Compteur_Y=Debut_Y-(Y-Pinceau_Decalage_Y);
if ( (Largeur>0) && (Hauteur>0) )
{
// Corrections dues au Zoom:
Debut_X=(Debut_X-Loupe_Decalage_X)*Loupe_Facteur;
Debut_Y=(Debut_Y-Loupe_Decalage_Y)*Loupe_Facteur;
Hauteur=Debut_Y+(Hauteur*Loupe_Facteur);
if (Hauteur>Menu_Ordonnee)
Hauteur=Menu_Ordonnee;
Display_brush_Mono_zoom(Principal_X_Zoom+Debut_X,Debut_Y,
Debut_Compteur_X,Debut_Compteur_Y,
Largeur,Hauteur,
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 ((Largeur>0) && (Hauteur>0))
{
Copier_une_partie_d_image_dans_une_autre(Principal_Ecran,
Debut_X,Debut_Y,
Largeur,Hauteur,
Principal_Largeur_image,
Smear_Brosse,
Debut_Compteur_X,
Debut_Compteur_Y,
Smear_Brosse_Largeur);
Mettre_Ecran_A_Jour(Debut_X,Debut_Y,Largeur,Hauteur);
}
Smear_Debut=0;
}
else
{
for (Pos_Y=Debut_Y,Compteur_Y=Debut_Compteur_Y;Compteur_Y<Fin_Compteur_Y;Pos_Y++,Compteur_Y++)
for (Pos_X=Debut_X,Compteur_X=Debut_Compteur_X;Compteur_X<Fin_Compteur_X;Pos_X++,Compteur_X++)
{
Couleur_temporaire=Lit_pixel_dans_ecran_courant(Pos_X,Pos_Y);
Position=(Compteur_Y*Smear_Brosse_Largeur)+Compteur_X;
if ( (Pinceau_Sprite[(TAILLE_MAXI_PINCEAU*Compteur_Y)+Compteur_X]) // Le pinceau sert de masque pour dire quels pixels on doit traiter dans le rectangle
&& (Compteur_Y<Smear_Max_Y) && (Compteur_X<Smear_Max_X) // On clippe l'effet smear entre Smear_Min et Smear_Max
&& (Compteur_Y>=Smear_Min_Y) && (Compteur_X>=Smear_Min_X) )
Afficher_pixel(Pos_X,Pos_Y,Smear_Brosse[Position]);
Smear_Brosse[Position]=Couleur_temporaire;
}
Mettre_Ecran_A_Jour(Debut_X, Debut_Y, Largeur, Hauteur);
}
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 (Pos_Y=Debut_Y,Compteur_Y=Debut_Compteur_Y;Compteur_Y<Fin_Compteur_Y;Pos_Y++,Compteur_Y++)
for (Pos_X=Debut_X,Compteur_X=Debut_Compteur_X;Compteur_X<Fin_Compteur_X;Pos_X++,Compteur_X++)
{
if (Pinceau_Sprite[(TAILLE_MAXI_PINCEAU*Compteur_Y)+Compteur_X])
Afficher_pixel(Pos_X,Pos_Y,Couleur);
}
Mettre_Ecran_A_Jour(Debut_X,Debut_Y,Largeur,Hauteur);
}
}
}
}
// -- Effacer le pinceau -- //
//
void Effacer_pinceau(short X,short Y)
// X,Y: position du centre du pinceau
{
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 Largeur; // Largeur dans l'écran selon laquelle on affiche la
// brosse/pinceau
short Hauteur; // Hauteur 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 Pos_X; // Position X (dans l'image) en cours d'affichage
//short Pos_Y; // 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 * Temp;
if (!Mouse_K)
switch (Pinceau_Forme)
{
case FORME_PINCEAU_POINT :
if ( (Pinceau_X>=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;
Largeur=Brosse_Largeur;
Hauteur=Brosse_Hauteur;
Calculer_dimensions_clipees(&Debut_X,&Debut_Y,&Largeur,&Hauteur);
Debut_Compteur_X=Debut_X-(X-Brosse_Decalage_X);
Debut_Compteur_Y=Debut_Y-(Y-Brosse_Decalage_Y);
Fin_Compteur_X=Debut_Compteur_X+Largeur;
Fin_Compteur_Y=Debut_Compteur_Y+Hauteur;
if ( (Largeur>0) && (Hauteur>0) )
Clear_brush(Debut_X-Principal_Decalage_X,
Debut_Y-Principal_Decalage_Y,
Debut_Compteur_X,Debut_Compteur_Y,
Largeur,Hauteur,Back_color,
Principal_Largeur_image);
if (Loupe_Mode)
{
Calculer_dimensions_clipees_zoom(&Debut_X,&Debut_Y,&Largeur,&Hauteur);
Debut_Compteur_X=Debut_X;
Debut_Compteur_Y=Debut_Y;
if ( (Largeur>0) && (Hauteur>0) )
{
// Corrections dues au Zoom:
Debut_X=(Debut_X-Loupe_Decalage_X)*Loupe_Facteur;
Debut_Y=(Debut_Y-Loupe_Decalage_Y)*Loupe_Facteur;
Hauteur=Debut_Y+(Hauteur*Loupe_Facteur);
if (Hauteur>Menu_Ordonnee)
Hauteur=Menu_Ordonnee;
Clear_brush_zoom(Principal_X_Zoom+Debut_X,Debut_Y,
Debut_Compteur_X,Debut_Compteur_Y,
Largeur,Hauteur,Back_color,
Principal_Largeur_image,
Buffer_de_ligne_horizontale);
}
}
break;
default: // Pinceau
Debut_X=X-Pinceau_Decalage_X;
Debut_Y=Y-Pinceau_Decalage_Y;
Largeur=Pinceau_Largeur;
Hauteur=Pinceau_Hauteur;
Calculer_dimensions_clipees(&Debut_X,&Debut_Y,&Largeur,&Hauteur);
Debut_Compteur_X=Debut_X-(X-Pinceau_Decalage_X);
Debut_Compteur_Y=Debut_Y-(Y-Pinceau_Decalage_Y);
Fin_Compteur_X=Debut_Compteur_X+Largeur;
Fin_Compteur_Y=Debut_Compteur_Y+Hauteur;
Temp=Brosse;
Brosse=Pinceau_Sprite;
if ( (Largeur>0) && (Hauteur>0) )
{
Clear_brush(Debut_X-Principal_Decalage_X,
Debut_Y-Principal_Decalage_Y,
Debut_Compteur_X,Debut_Compteur_Y,
Largeur,Hauteur,0,
Principal_Largeur_image);
}
if (Loupe_Mode)
{
Calculer_dimensions_clipees_zoom(&Debut_X,&Debut_Y,&Largeur,&Hauteur);
Debut_Compteur_X=Debut_X;
Debut_Compteur_Y=Debut_Y;
if ( (Largeur>0) && (Hauteur>0) )
{
// Corrections dues au Zoom:
Debut_X=(Debut_X-Loupe_Decalage_X)*Loupe_Facteur;
Debut_Y=(Debut_Y-Loupe_Decalage_Y)*Loupe_Facteur;
Hauteur=Debut_Y+(Hauteur*Loupe_Facteur);
if (Hauteur>Menu_Ordonnee)
Hauteur=Menu_Ordonnee;
Clear_brush_zoom(Principal_X_Zoom+Debut_X,Debut_Y,
Debut_Compteur_X,Debut_Compteur_Y,
Largeur,Hauteur,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 Effacement)
{
short Temporaire;
short Pos_X;
short Pos_Y;
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_X<Principal_Largeur_image) && (Debut_Y<Principal_Hauteur_image))
{
// On met les décalages du tiling à 0 pour eviter toute incohérence.
// Si par hasard on voulait les mettre à
// min(Tiling_Decalage_?,Brosse_?a??eur-1)
// il faudrait penser à les initialiser à 0 dans "MAIN.C".
Tiling_Decalage_X=0;
Tiling_Decalage_Y=0;
// Ensuite, on calcule les dimensions de la brosse:
Nouvelle_Brosse_Largeur=(Fin_X-Debut_X)+1;
Nouvelle_Brosse_Hauteur=(Fin_Y-Debut_Y)+1;
if (Debut_X+Nouvelle_Brosse_Largeur>Principal_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 (Effacement)
{
for (Pos_Y=Debut_Y;Pos_Y<Debut_Y+Brosse_Hauteur;Pos_Y++)
for (Pos_X=Debut_X;Pos_X<Debut_X+Brosse_Largeur;Pos_X++)
{
Pixel_dans_ecran_courant(Pos_X,Pos_Y,Back_color);
Pixel_Preview (Pos_X,Pos_Y,Back_color);
}
Mettre_Ecran_A_Jour(Debut_X,Debut_Y,Brosse_Largeur,Brosse_Hauteur);
}
// On centre la prise sur la brosse
Brosse_Decalage_X=(Brosse_Largeur>>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 Pos_X; // Variable de balayage de la brosse
short Pos_Y; // 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 (Pos_Y=0;Pos_Y<Brosse_Hauteur;Pos_Y++)
for (Pos_X=0;Pos_X<Brosse_Largeur;Pos_X++)
Utilisee[Lit_pixel_dans_brosse(Pos_X,Pos_Y)]=1;
// On n'est pas censé remapper la couleur de transparence, sinon la brosse
// changera de forme, donc on dit pour l'instant qu'elle n'est pas utilisée
// ainsi on ne s'embêtera pas à la recalculer
Utilisee[Back_color]=0;
// On va maintenant se servir de la table "Utilisee" comme table de
// conversion: pour chaque indice, la table donne une couleur de
// remplacement.
// Note : Seules les couleurs utilisées on besoin d'êtres recalculées: les
// autres ne seront jamais consultées dans la nouvelle table de
// conversion puisque elles n'existent pas dans la brosse, donc elles
// ne seront pas utilisées par Remap_brush_LOWLEVEL.
for (Couleur=0;Couleur<=255;Couleur++)
if (Utilisee[Couleur])
Utilisee[Couleur]=Meilleure_couleur(Brouillon_Palette[Couleur].R,Brouillon_Palette[Couleur].V,Brouillon_Palette[Couleur].B);
// Il reste une couleur non calculée dans la table qu'il faut mettre à
// jour: c'est la couleur de fond. On l'avait inhibée pour éviter son
// calcul inutile, mais comme il est possible qu'elle soit quand même dans
// la brosse, on va mettre dans la table une relation d'équivalence entre
// les deux palettes: comme on ne veut pas que la couleur soit remplacée,
// on va dire qu'on veut qu'elle soit remplacée par la couleur en question.
Utilisee[Back_color]=Back_color;
// Maintenant qu'on a une super table de conversion qui n'a que le nom
// qui craint un peu, on peut faire l'échange dans la brosse de toutes les
// teintes.
Remap_general_LOWLEVEL(Utilisee,Brosse,Brosse_Largeur,Brosse_Hauteur,Brosse_Largeur);
//Remap_brush_LOWLEVEL(Utilisee);
}
void Outline_brush(void)
{
long /*Pos,*/Pos_X,Pos_Y;
byte Etat;
byte * Nouvelle_brosse;
byte * Temporaire;
word Largeur;
word Hauteur;
Largeur=Brosse_Largeur+2;
Hauteur=Brosse_Hauteur+2;
Nouvelle_brosse=(byte *)malloc(((long)Largeur)*Hauteur);
if (Nouvelle_brosse)
{
// On remplit la bordure ajoutée par la Backcolor
memset(Nouvelle_brosse,Back_color,((long)Largeur)*Hauteur);
// On copie la brosse courante dans la nouvelle
Copier_une_partie_d_image_dans_une_autre(Brosse, // Source
0, 0,
Brosse_Largeur,
Brosse_Hauteur,
Brosse_Largeur,
Nouvelle_brosse, // Destination
1, 1,
Largeur);
// On intervertit la nouvelle et l'ancienne brosse:
Temporaire=Brosse;
Brosse=Nouvelle_brosse;
Brosse_Largeur+=2;
Brosse_Hauteur+=2;
Largeur-=2;
Hauteur-=2;
// Si on "outline" avec une couleur différente de la Back_color on y va!
if (Fore_color!=Back_color)
{
// 1er balayage (horizontal)
for (Pos_Y=1; Pos_Y<Brosse_Hauteur-1; Pos_Y++)
{
Etat=0;
for (Pos_X=1; Pos_X<Brosse_Largeur-1; Pos_X++)
{
if (Temporaire[((Pos_Y-1)*Largeur)+Pos_X-1]==Back_color)
{
if (Etat)
{
Pixel_dans_brosse(Pos_X,Pos_Y,Fore_color);
Etat=0;
}
}
else
{
if (!Etat)
{
Pixel_dans_brosse(Pos_X-1,Pos_Y,Fore_color);
Etat=1;
}
}
}
// Cas du dernier pixel à droite de la ligne
if (Etat)
Pixel_dans_brosse(Pos_X,Pos_Y,Fore_color);
}
// 2ème balayage (vertical)
for (Pos_X=1; Pos_X<Brosse_Largeur-1; Pos_X++)
{
Etat=0;
for (Pos_Y=1; Pos_Y<Brosse_Hauteur-1; Pos_Y++)
{
if (Temporaire[((Pos_Y-1)*Largeur)+Pos_X-1]==Back_color)
{
if (Etat)
{
Pixel_dans_brosse(Pos_X,Pos_Y,Fore_color);
Etat=0;
}
}
else
{
if (!Etat)
{
Pixel_dans_brosse(Pos_X,Pos_Y-1,Fore_color);
Etat=1;
}
}
}
// Cas du dernier pixel en bas de la colonne
if (Etat)
Pixel_dans_brosse(Pos_X,Pos_Y,Fore_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 Nibble_brush(void)
{
long /*Pos,*/Pos_X,Pos_Y;
byte Etat;
byte * Nouvelle_brosse;
byte * Temporaire;
word Largeur;
word Hauteur;
if ( (Brosse_Largeur>2) && (Brosse_Hauteur>2) )
{
Largeur=Brosse_Largeur-2;
Hauteur=Brosse_Hauteur-2;
Nouvelle_brosse=(byte *)malloc(((long)Largeur)*Hauteur);
if (Nouvelle_brosse)
{
// On copie la brosse courante dans la nouvelle
Copier_une_partie_d_image_dans_une_autre(Brosse, // Source
1,
1,
Largeur,
Hauteur,
Brosse_Largeur,
Nouvelle_brosse, // Destination
0,
0,
Largeur);
// On intervertit la nouvelle et l'ancienne brosse:
Temporaire=Brosse;
Brosse=Nouvelle_brosse;
Brosse_Largeur-=2;
Brosse_Hauteur-=2;
Largeur+=2;
Hauteur+=2;
// 1er balayage (horizontal)
for (Pos_Y=0; Pos_Y<Brosse_Hauteur; Pos_Y++)
{
Etat=(Temporaire[(Pos_Y+1)*Largeur]!=Back_color);
for (Pos_X=0; Pos_X<Brosse_Largeur; Pos_X++)
{
if (Temporaire[((Pos_Y+1)*Largeur)+Pos_X+1]==Back_color)
{
if (Etat)
{
if (Pos_X>0)
Pixel_dans_brosse(Pos_X-1,Pos_Y,Back_color);
Etat=0;
}
}
else
{
if (!Etat)
{
Pixel_dans_brosse(Pos_X,Pos_Y,Back_color);
Etat=1;
}
}
}
// Cas du dernier pixel à droite de la ligne
if (Temporaire[((Pos_Y+1)*Largeur)+Pos_X+1]==Back_color)
Pixel_dans_brosse(Pos_X-1,Pos_Y,Back_color);
}
// 2ème balayage (vertical)
for (Pos_X=0; Pos_X<Brosse_Largeur; Pos_X++)
{
Etat=(Temporaire[Largeur+Pos_X+1]!=Back_color);;
for (Pos_Y=0; Pos_Y<Brosse_Hauteur; Pos_Y++)
{
if (Temporaire[((Pos_Y+1)*Largeur)+Pos_X+1]==Back_color)
{
if (Etat)
{
if (Pos_Y>0)
Pixel_dans_brosse(Pos_X,Pos_Y-1,Back_color);
Etat=0;
}
}
else
{
if (!Etat)
{
Pixel_dans_brosse(Pos_X,Pos_Y,Back_color);
Etat=1;
}
}
}
// Cas du dernier pixel en bas de la colonne
if (Temporaire[((Pos_Y+1)*Largeur)+Pos_X+1]==Back_color)
Pixel_dans_brosse(Pos_X,Pos_Y-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 Effacement)
{
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 Pos_X;
short Pos_Y;
word Nouvelle_Brosse_Largeur;
word Nouvelle_Brosse_Hauteur;
// On recherche les bornes de la brosse:
for (Temporaire=0; Temporaire<Vertices; Temporaire++)
{
Pos_X=Points[Temporaire<<1];
Pos_Y=Points[(Temporaire<<1)+1];
if (Pos_X<Debut_X)
Debut_X=Pos_X;
if (Pos_X>Fin_X)
Fin_X=Pos_X;
if (Pos_Y<Debut_Y)
Debut_Y=Pos_Y;
if (Pos_Y>Fin_Y)
Fin_Y=Pos_Y;
}
// On clippe ces bornes à l'écran:
if (Debut_X<Limite_Gauche)
Debut_X=Limite_Gauche;
if (Fin_X>Limite_Droite)
Fin_X=Limite_Droite;
if (Debut_Y<Limite_Haut)
Debut_Y=Limite_Haut;
if (Fin_Y>Limite_Bas)
Fin_Y=Limite_Bas;
// On ne capture la nouvelle brosse que si elle est au moins partiellement
// dans l'image:
if ((Debut_X<Principal_Largeur_image) && (Debut_Y<Principal_Hauteur_image))
{
// On met les décalages du tiling à 0 pour eviter toute incohérence.
// Si par hasard on voulait les mettre à
// min(Tiling_Decalage_?,Brosse_?a??eur-1)
// il faudrait penser à les initialiser à 0 dans "MAIN.C".
Tiling_Decalage_X=0;
Tiling_Decalage_Y=0;
// Ensuite, on calcule les dimensions de la brosse:
Nouvelle_Brosse_Largeur=(Fin_X-Debut_X)+1;
Nouvelle_Brosse_Hauteur=(Fin_Y-Debut_Y)+1;
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;
}
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<Vertices; Temporaire++)
{
Tracer_ligne_General(Points[(Temporaire-1)<<1],Points[((Temporaire-1)<<1)+1],
Points[Temporaire<<1],Points[(Temporaire<<1)+1],
~Back_color);
}
Tracer_ligne_General(Points[(Vertices-1)<<1],Points[((Vertices-1)<<1)+1],
Points[0],Points[1],
~Back_color);
// On scanne la brosse pour remplacer tous les pixels affectés par le
// polyfill par ceux de l'image:
for (Pos_Y=Debut_Y;Pos_Y<=Fin_Y;Pos_Y++)
for (Pos_X=Debut_X;Pos_X<=Fin_X;Pos_X++)
if (Lit_pixel_dans_brosse(Pos_X-Debut_X,Pos_Y-Debut_Y)!=Back_color)
{
Pixel_dans_brosse(Pos_X-Debut_X,Pos_Y-Debut_Y,Lit_pixel_dans_ecran_courant(Pos_X,Pos_Y));
// On regarde s'il faut effacer quelque chose:
if (Effacement)
Pixel_dans_ecran_courant(Pos_X,Pos_Y,Back_color);
}
// On centre la prise sur la brosse
Brosse_Decalage_X=(Brosse_Largeur>>1);
Brosse_Decalage_Y=(Brosse_Hauteur>>1);
}
}
//------------------------- Etirement de la brosse ---------------------------
void Etirer_brosse(short X1, short Y1, short X2, short Y2)
{
int Offset,Ligne,Colonne;
byte * New_Brosse;
int New_Brosse_Largeur; // Largeur de la nouvelle brosse
int New_Brosse_Hauteur; // Hauteur 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<X2)?1:-1;
Dy=(Y1<Y2)?1:-1;
// Calcul des nouvelles dimensions de la brosse:
if ((New_Brosse_Largeur=X1-X2)<0)
New_Brosse_Largeur=-New_Brosse_Largeur;
New_Brosse_Largeur++;
if ((New_Brosse_Hauteur=Y1-Y2)<0)
New_Brosse_Hauteur=-New_Brosse_Hauteur;
New_Brosse_Hauteur++;
// Calcul des anciennes dimensions de la brosse:
// Calcul du "vecteur incrémental":
Delta_X_dans_brosse=(Brosse_Largeur<<16)/(X2-X1+Dx);
Delta_Y_dans_brosse=(Brosse_Hauteur<<16)/(Y2-Y1+Dy);
// Calcul de la valeur initiale de Pos_X pour chaque ligne:
if (Dx>=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 Pos_Y:
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 (Ligne=0;Ligne<New_Brosse_Hauteur;Ligne++)
{
// On repart du début de la ligne:
Pos_X_dans_brosse=Pos_X_initial;
// Pour chaque colonne:
for (Colonne=0;Colonne<New_Brosse_Largeur;Colonne++)
{
// On copie le pixel:
New_Brosse[Offset]=Lit_pixel_dans_brosse(Pos_X_dans_brosse>>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;
}
UpdateRect(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 Hauteur)
{
int Pos_X,Pos_Y;
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;
Pos_X=Debut_X;
Pos_Y=Debut_Y;
if (Debut_X<Fin_X)
{
Incr_X=+1;
Delta_X=Delta_X2;
}
else
{
Incr_X=-1;
Delta_X=-Delta_X2;
}
if (Debut_Y<Fin_Y)
{
Incr_Y=+1;
Delta_Y=Delta_Y2;
}
else
{
Incr_Y=-1;
Delta_Y=-Delta_Y2;
}
if (Delta_X>Delta_Y)
{
Cumul=Delta_X>>1;
for (i=0; i<=Delta_X; i++)
{
if (Cumul>=Delta_X)
{
Cumul-=Delta_X;
Pos_Y+=Incr_Y;
}
if ((Pos_Y>=0) && (Pos_Y<Hauteur))
{
Xt=(((float)((Pos_X-Debut_X)*Delta_Xt))/(float)Delta_X2) + (float)Xt1;
Yt=(((float)((Pos_X-Debut_X)*Delta_Yt))/(float)Delta_X2) + (float)Yt1;
if (ScanY_X[0][Pos_Y]==INDEFINI) // Gauche non défini
{
ScanY_X[0][Pos_Y]=Pos_X;
ScanY_Xt[0][Pos_Y]=Xt;
ScanY_Yt[0][Pos_Y]=Yt;
}
else
{
if (Pos_X>=ScanY_X[0][Pos_Y])
{
if ((ScanY_X[1][Pos_Y]==INDEFINI) // Droit non défini
|| (Pos_X>ScanY_X[1][Pos_Y]))
{
ScanY_X[1][Pos_Y]=Pos_X;
ScanY_Xt[1][Pos_Y]=Xt;
ScanY_Yt[1][Pos_Y]=Yt;
}
}
else
{
if (ScanY_X[1][Pos_Y]==INDEFINI) // Droit non défini
{
ScanY_X[1][Pos_Y]=ScanY_X[0][Pos_Y];
ScanY_Xt[1][Pos_Y]=ScanY_Xt[0][Pos_Y];
ScanY_Yt[1][Pos_Y]=ScanY_Yt[0][Pos_Y];
ScanY_X[0][Pos_Y]=Pos_X;
ScanY_Xt[0][Pos_Y]=Xt;
ScanY_Yt[0][Pos_Y]=Yt;
}
else
{
ScanY_X[0][Pos_Y]=Pos_X;
ScanY_Xt[0][Pos_Y]=Xt;
ScanY_Yt[0][Pos_Y]=Yt;
}
}
}
}
Pos_X+=Incr_X;
Cumul+=Delta_Y;
}
}
else
{
Cumul=Delta_Y>>1;
for (i=0; i<=Delta_Y; i++)
{
if (Cumul>=Delta_Y)
{
Cumul-=Delta_Y;
Pos_X+=Incr_X;
}
if ((Pos_Y>=0) && (Pos_Y<Hauteur))
{
Xt=(((float)((Pos_Y-Debut_Y)*Delta_Xt))/(float)Delta_Y2) + (float)Xt1;
Yt=(((float)((Pos_Y-Debut_Y)*Delta_Yt))/(float)Delta_Y2) + (float)Yt1;
if (ScanY_X[0][Pos_Y]==INDEFINI) // Gauche non défini
{
ScanY_X[0][Pos_Y]=Pos_X;
ScanY_Xt[0][Pos_Y]=Xt;
ScanY_Yt[0][Pos_Y]=Yt;
}
else
{
if (Pos_X>=ScanY_X[0][Pos_Y])
{
if ((ScanY_X[1][Pos_Y]==INDEFINI) // Droit non défini
|| (Pos_X>ScanY_X[1][Pos_Y]))
{
ScanY_X[1][Pos_Y]=Pos_X;
ScanY_Xt[1][Pos_Y]=Xt;
ScanY_Yt[1][Pos_Y]=Yt;
}
}
else
{
if (ScanY_X[1][Pos_Y]==INDEFINI) // Droit non défini
{
ScanY_X[1][Pos_Y]=ScanY_X[0][Pos_Y];
ScanY_Xt[1][Pos_Y]=ScanY_Xt[0][Pos_Y];
ScanY_Yt[1][Pos_Y]=ScanY_Yt[0][Pos_Y];
ScanY_X[0][Pos_Y]=Pos_X;
ScanY_Xt[0][Pos_Y]=Xt;
ScanY_Yt[0][Pos_Y]=Yt;
}
else
{
ScanY_X[0][Pos_Y]=Pos_X;
ScanY_Xt[0][Pos_Y]=Xt;
ScanY_Yt[0][Pos_Y]=Yt;
}
}
}
}
Pos_Y+=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 Largeur, int Hauteur)
{
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(Hauteur*sizeof(float));
ScanY_Xt[1]=(float *)malloc(Hauteur*sizeof(float));
ScanY_Yt[0]=(float *)malloc(Hauteur*sizeof(float));
ScanY_Yt[1]=(float *)malloc(Hauteur*sizeof(float));
ScanY_X[0] =(float *)malloc(Hauteur*sizeof(float));
ScanY_X[1] =(float *)malloc(Hauteur*sizeof(float));
// Remplir avec des valeurs égales à INDEFINI.
for (Y=0; Y<Hauteur; Y++)
{
ScanY_X[0][Y]=INDEFINI;
ScanY_X[1][Y]=INDEFINI;
}
Interpoler_texture(X1-Xmin,Y1-Ymin,Xt1,Yt1,X3-Xmin,Y3-Ymin,Xt3,Yt3,Hauteur);
Interpoler_texture(X3-Xmin,Y3-Ymin,Xt3,Yt3,X4-Xmin,Y4-Ymin,Xt4,Yt4,Hauteur);
Interpoler_texture(X4-Xmin,Y4-Ymin,Xt4,Yt4,X2-Xmin,Y2-Ymin,Xt2,Yt2,Hauteur);
Interpoler_texture(X2-Xmin,Y2-Ymin,Xt2,Yt2,X1-Xmin,Y1-Ymin,Xt1,Yt1,Hauteur);
for (Y=0; Y<Hauteur; Y++)
{
Debut_X=Round(ScanY_X[0][Y]);
Fin_X =Round(ScanY_X[1][Y]);
Largeur_ligne=1+Fin_X-Debut_X;
for (X=0; X<Debut_X; X++)
Buffer[X+(Y*Largeur)]=Back_color;
for (; X<=Fin_X; X++)
{
Temp=(float)(0.5+(float)X-ScanY_X[0][Y])/(float)Largeur_ligne;
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])));
Buffer[X+(Y*Largeur)]=Lit_pixel_dans_brosse(Xt,Yt);
}
for (; X<Largeur; X++)
Buffer[X+(Y*Largeur)]=Back_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 Tourner_brosse(float Angle)
{
byte * New_Brosse;
int New_Brosse_Largeur; // Largeur de la nouvelle brosse
int New_Brosse_Hauteur; // Hauteur de la nouvelle brosse
short X1,Y1,X2,Y2,X3,Y3,X4,Y4;
int Debut_X,Fin_X,Debut_Y,Fin_Y;
int Xmin,Xmax,Ymin,Ymax;
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);
// 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,Largeur,Hauteur;
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));
Hauteur=1+Ymax-Ymin;
ScanY_Xt[0]=(float *)malloc(Hauteur*sizeof(float));
ScanY_Xt[1]=(float *)malloc(Hauteur*sizeof(float));
ScanY_Yt[0]=(float *)malloc(Hauteur*sizeof(float));
ScanY_Yt[1]=(float *)malloc(Hauteur*sizeof(float));
ScanY_X[0] =(float *)malloc(Hauteur*sizeof(float));
ScanY_X[1] =(float *)malloc(Hauteur*sizeof(float));
// Remplir avec des valeurs égales à INDEFINI.
for (Y=0; Y<Hauteur; Y++)
{
ScanY_X[0][Y]=INDEFINI;
ScanY_X[1][Y]=INDEFINI;
}
Interpoler_texture(X1,Y1-Ymin,Xt1,Yt1,X3,Y3-Ymin,Xt3,Yt3,Hauteur);
Interpoler_texture(X3,Y3-Ymin,Xt3,Yt3,X4,Y4-Ymin,Xt4,Yt4,Hauteur);
Interpoler_texture(X4,Y4-Ymin,Xt4,Yt4,X2,Y2-Ymin,Xt2,Yt2,Hauteur);
Interpoler_texture(X2,Y2-Ymin,Xt2,Yt2,X1,Y1-Ymin,Xt1,Yt1,Hauteur);
Ymin_=Ymin;
if (Ymin<Limite_Haut) Ymin=Limite_Haut;
if (Ymax>Limite_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]);
Largeur=1+Fin_X-Debut_X;
if (Debut_X<Limite_Gauche) Debut_X=Limite_Gauche;
if ( Fin_X>Limite_Droite) Fin_X=Limite_Droite;
for (X=Debut_X; X<=Fin_X; X++)
{
Temp=(float)(0.5+(float)X-ScanY_X[0][Y])/(float)Largeur;
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));
UpdateRect(Debut_X,Debut_Y,Fin_X-Debut_X+1,Fin_Y-Debut_Y+1);
}