diff --git a/graph.c b/graph.c
index b4d82458..c6377dad 100644
--- a/graph.c
+++ b/graph.c
@@ -1,4864 +1,2435 @@
/* Grafx2 - The Ultimate 256-color bitmap paint program
-
-
Copyright 2008 Franck Charlet
-
Copyright 2007 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.
-
-
********************************************************************************
-
-
Drawing functions and effects.
-
-
*/
-
-
#include
-
#include
-
#include
-
-
#include "global.h"
-
#include "struct.h"
-
#include "moteur.h"
-
#include "boutons.h"
-
#include "pages.h"
-
#include "erreurs.h"
-
#include "sdlscreen.h"
-
#include "graph.h"
-
#include "divers.h"
-
#include "pxsimple.h"
-
#include "pxtall.h"
-
#include "pxwide.h"
-
#include "windows.h"
-
-
// Fonction qui met à jour la zone de l'image donnée en paramètre sur l'écran.
-
// Tient compte du décalage X et Y et du zoom, et fait tous les controles nécessaires
-
void Mettre_Ecran_A_Jour(short X, short Y, short Largeur, short Hauteur)
-
{
-
short L_effectif, H_effectif;
-
short X_effectif;
-
short Y_effectif;
-
short Diff;
-
-
// Première étape, si L ou H est négatif, on doit remettre la zone à l'endroit
-
if (Largeur < 0)
-
{
-
X += Largeur;
-
Largeur = - Largeur;
-
}
-
-
if (Hauteur < 0)
-
{
-
Y += Hauteur;
-
Hauteur = - Hauteur;
-
}
-
-
// D'abord on met à jour dans la zone écran normale
-
Diff = X-Principal_Decalage_X;
-
if (Diff<0)
-
{
-
L_effectif = Largeur + Diff;
-
X_effectif = 0;
-
}
-
else
-
{
-
L_effectif = Largeur;
-
X_effectif = Diff;
-
}
-
Diff = Y-Principal_Decalage_Y;
-
if (Diff<0)
-
{
-
H_effectif = Hauteur + Diff;
-
Y_effectif = 0;
-
}
-
else
-
{
-
H_effectif = Hauteur;
-
Y_effectif = Diff;
-
}
-
-
// Normalement il ne faudrait pas updater au delà du split quand on est en mode loupe,
-
// mais personne ne devrait demander d'update en dehors de cette limite, même le fill est contraint
-
// a rester dans la zone visible de l'image
-
// ...Sauf l'affichage de brosse en preview - yr
-
if(Loupe_Mode && X_effectif + L_effectif > Principal_Split)
-
L_effectif = Principal_Split - X_effectif;
-
else if(X_effectif + L_effectif > Largeur_ecran)
-
L_effectif = Largeur_ecran - X_effectif;
-
-
if(Y_effectif + H_effectif > Menu_Ordonnee)
-
H_effectif = Menu_Ordonnee - Y_effectif;
-
/*
-
SDL_Rect r;
-
r.x=X_effectif;
-
r.y=Y_effectif;
-
r.h=H_effectif;
-
r.w=L_effectif;
-
SDL_FillRect(Ecran_SDL,&r,3);
-
*/
-
UpdateRect(X_effectif,Y_effectif,L_effectif,H_effectif);
-
-
// Et ensuite dans la partie zoomée
-
if(Loupe_Mode)
-
{
-
// Clipping en X
-
X_effectif = (X-Loupe_Decalage_X)*Loupe_Facteur;
-
Y_effectif = (Y-Loupe_Decalage_Y)*Loupe_Facteur;
-
L_effectif = Largeur * Loupe_Facteur;
-
H_effectif = Hauteur * Loupe_Facteur;
-
-
if (X_effectif < 0)
-
{
-
L_effectif+=X_effectif;
-
if (L_effectif<0)
-
return;
-
-
X_effectif = Principal_Split + LARGEUR_BARRE_SPLIT*Menu_Facteur_X;
-
}
-
else
-
X_effectif += Principal_Split + LARGEUR_BARRE_SPLIT*Menu_Facteur_X;
-
Diff = X_effectif+L_effectif-Largeur_ecran;
-
if (Diff>0)
-
{
-
L_effectif -=Diff;
-
if (L_effectif<0)
-
return;
-
}
-
-
-
// Clipping en Y
-
if (Y_effectif < 0)
-
{
-
H_effectif+=Y_effectif;
-
if (H_effectif<0)
-
return;
-
Y_effectif = 0;
-
}
-
Diff = Y_effectif+H_effectif-Menu_Ordonnee;
-
if (Diff>0)
-
{
-
H_effectif -=Diff;
-
if (H_effectif<0)
-
return;
-
}
-
-
// Très utile pour le debug :)
-
/*SDL_Rect r;
-
r.x=X_effectif;
-
r.y=Y_effectif;
-
r.h=H_effectif;
-
r.w=L_effectif;
-
SDL_FillRect(Ecran_SDL,&r,3);*/
-
-
UpdateRect(X_effectif,Y_effectif,L_effectif,H_effectif);
-
}
-
}
-
-
-
-
void Transformer_point(short X, short Y, float cosA, float sinA,
-
short * Xr, short * Yr)
-
{
-
*Xr=Round(((float)X*cosA)+((float)Y*sinA));
-
*Yr=Round(((float)Y*cosA)-((float)X*sinA));
-
}
-
-
-
-
//--------------------- Initialisation d'un mode vidéo -----------------------
-
-
void Initialiser_mode_video(int Largeur, int Hauteur, int Fullscreen)
-
{
-
int Sensibilite_X;
-
int Sensibilite_Y;
-
int Indice;
-
int Facteur;
-
-
if (Largeur_ecran!=Largeur ||
-
Hauteur_ecran!=Hauteur ||
-
Mode_video[Resolution_actuelle].Fullscreen != Fullscreen)
-
{
-
switch (Pixel_ratio)
-
{
-
case PIXEL_SIMPLE:
-
Pixel_width=1;
-
Pixel_height=1;
-
Pixel = Pixel_Simple ;
-
Lit_pixel= Lit_Pixel_Simple ;
-
Display_screen = Afficher_partie_de_l_ecran_Simple ;
-
Block = Block_Simple ;
-
Pixel_Preview_Normal = Pixel_Preview_Normal_Simple ;
-
Pixel_Preview_Loupe = Pixel_Preview_Loupe_Simple ;
-
Ligne_horizontale_XOR = Ligne_horizontale_XOR_Simple ;
-
Ligne_verticale_XOR = Ligne_verticale_XOR_Simple ;
-
Display_brush_Color = Display_brush_Color_Simple ;
-
Display_brush_Mono = Display_brush_Mono_Simple ;
-
Clear_brush = Clear_brush_Simple ;
-
Remap_screen = Remap_screen_Simple ;
-
Afficher_ligne = Afficher_une_ligne_ecran_Simple ;
-
Afficher_ligne_fast = Afficher_une_ligne_ecran_Simple ;
-
Lire_ligne = Lire_une_ligne_ecran_Simple ;
-
Display_zoomed_screen = Afficher_partie_de_l_ecran_zoomee_Simple ;
-
Display_brush_Color_zoom = Display_brush_Color_zoom_Simple ;
-
Display_brush_Mono_zoom = Display_brush_Mono_zoom_Simple ;
-
Clear_brush_zoom = Clear_brush_zoom_Simple ;
-
Affiche_brosse = Affiche_brosse_Simple ;
-
break;
-
case PIXEL_TALL:
-
Pixel_width=1;
-
Pixel_height=2;
-
Pixel = Pixel_Tall;
-
Lit_pixel= Lit_Pixel_Tall;
-
Display_screen = Afficher_partie_de_l_ecran_Tall;
-
Block = Block_Tall;
-
Pixel_Preview_Normal = Pixel_Preview_Normal_Tall;
-
Pixel_Preview_Loupe = Pixel_Preview_Loupe_Tall;
-
Ligne_horizontale_XOR = Ligne_horizontale_XOR_Tall;
-
Ligne_verticale_XOR = Ligne_verticale_XOR_Tall;
-
Display_brush_Color = Display_brush_Color_Tall;
-
Display_brush_Mono = Display_brush_Mono_Tall;
-
Clear_brush = Clear_brush_Tall;
-
Remap_screen = Remap_screen_Tall;
-
Afficher_ligne = Afficher_une_ligne_ecran_Tall;
-
Afficher_ligne_fast = Afficher_une_ligne_ecran_Tall;
-
Lire_ligne = Lire_une_ligne_ecran_Tall;
-
Display_zoomed_screen = Afficher_partie_de_l_ecran_zoomee_Tall;
-
Display_brush_Color_zoom = Display_brush_Color_zoom_Tall;
-
Display_brush_Mono_zoom = Display_brush_Mono_zoom_Tall;
-
Clear_brush_zoom = Clear_brush_zoom_Tall;
-
Affiche_brosse = Affiche_brosse_Tall;
-
break;
-
case PIXEL_WIDE:
-
Pixel_width=2;
-
Pixel_height=1;
-
Pixel = Pixel_Wide ;
-
Lit_pixel= Lit_Pixel_Wide ;
-
Display_screen = Afficher_partie_de_l_ecran_Wide ;
-
Block = Block_Wide ;
-
Pixel_Preview_Normal = Pixel_Preview_Normal_Wide ;
-
Pixel_Preview_Loupe = Pixel_Preview_Loupe_Wide ;
-
Ligne_horizontale_XOR = Ligne_horizontale_XOR_Wide ;
-
Ligne_verticale_XOR = Ligne_verticale_XOR_Wide ;
-
Display_brush_Color = Display_brush_Color_Wide ;
-
Display_brush_Mono = Display_brush_Mono_Wide ;
-
Clear_brush = Clear_brush_Wide ;
-
Remap_screen = Remap_screen_Wide ;
-
Afficher_ligne = Afficher_une_ligne_ecran_Wide ;
-
Afficher_ligne_fast = Afficher_une_ligne_ecran_fast_Wide ;
-
Lire_ligne = Lire_une_ligne_ecran_Wide ;
-
Display_zoomed_screen = Afficher_partie_de_l_ecran_zoomee_Wide ;
-
Display_brush_Color_zoom = Display_brush_Color_zoom_Wide ;
-
Display_brush_Mono_zoom = Display_brush_Mono_zoom_Wide ;
-
Clear_brush_zoom = Clear_brush_zoom_Wide ;
-
Affiche_brosse = Affiche_brosse_Wide ;
-
break;
-
}
-
// Valeurs raisonnables: minimum 320x200
-
if (Pixel_width==1 && Pixel_height==1)
-
{
-
if (Largeur < 320)
-
Largeur = 320;
-
if (Hauteur < 200)
-
Hauteur = 200;
-
}
-
else
-
{
-
if (Largeur < 640)
-
Largeur = 640;
-
if (Hauteur < 400)
-
Hauteur = 400;
-
}
-
- // La largeur doit être un multiple de 4
-#ifdef __amigaos4__
- Largeur = (Largeur + 15) & 0xFFFFFFF0;
-#else
- Largeur = (Largeur + 3 ) & 0xFFFFFFFC;
-#endif
+ // La largeur doit être un multiple de 4
+#ifdef __amigaos4__
+ Largeur = (Largeur + 15) & 0xFFFFFFF0;
+#else
+ Largeur = (Largeur + 3 ) & 0xFFFFFFFC;
+#endif
Set_Mode_SDL(&Largeur, &Hauteur,Fullscreen);
-
Largeur_ecran = Largeur/Pixel_width;
-
Hauteur_ecran = Hauteur/Pixel_height;
-
-
// Taille des menus
-
if (Largeur_ecran/320 > Hauteur_ecran/200)
-
Facteur=Hauteur_ecran/200;
-
else
-
Facteur=Largeur_ecran/320;
-
-
switch (Config.Ratio)
-
{
-
case 1: // adapter tout
-
Menu_Facteur_X=Facteur;
-
Menu_Facteur_Y=Facteur;
-
break;
-
case 2: // adapter légèrement
-
Menu_Facteur_X=Facteur-1;
-
if (Menu_Facteur_X<1) Menu_Facteur_X=1;
-
Menu_Facteur_Y=Facteur-1;
-
if (Menu_Facteur_Y<1) Menu_Facteur_Y=1;
-
break;
-
default: // ne pas adapter
-
Menu_Facteur_X=1;
-
Menu_Facteur_Y=1;
-
}
-
if (Pixel_height>Pixel_width)
-
Menu_Facteur_X*=2;
-
else if (Pixel_width>Pixel_height)
-
Menu_Facteur_Y*=2;
-
if (Buffer_de_ligne_horizontale)
-
free(Buffer_de_ligne_horizontale);
-
-
Buffer_de_ligne_horizontale=(byte *)malloc(Pixel_width*((Largeur_ecran>Principal_Largeur_image)?Largeur_ecran:Principal_Largeur_image));
-
-
Set_palette(Principal_Palette);
-
-
if (!Fullscreen)
-
Resolution_actuelle=0;
-
else
-
for (Indice=1; Indice> 3;
-
Menu_Ordonnee = Hauteur_ecran;
-
if (Menu_visible)
-
Menu_Ordonnee -= HAUTEUR_MENU * Menu_Facteur_Y;
-
Menu_Ordonnee_Texte = Hauteur_ecran-(Menu_Facteur_Y<<3);
-
Bouton[BOUTON_CHOIX_COL].Largeur=(Menu_Taille_couleur<<3)-1;
-
-
Sensibilite_X = Config.Indice_Sensibilite_souris_X;
-
Sensibilite_Y = Config.Indice_Sensibilite_souris_Y;
-
Sensibilite_X>>=Mouse_Facteur_de_correction_X;
-
Sensibilite_Y>>=Mouse_Facteur_de_correction_Y;
-
Sensibilite_souris(Sensibilite_X?Sensibilite_X:1,Sensibilite_Y?Sensibilite_Y:1);
-
-
Brouillon_Decalage_X=0; // | Il faut penser à éviter les incohérences
-
Brouillon_Decalage_Y=0; // |- de décalage du brouillon par rapport à
-
Brouillon_Loupe_Mode=0; // | la résolution.
-
}
-
if (Loupe_Mode)
-
{
-
Pixel_Preview=Pixel_Preview_Loupe;
-
}
-
else
-
{
-
Pixel_Preview=Pixel_Preview_Normal;
-
// Recaler la vue (meme clipping que dans Scroller_ecran())
-
if (Principal_Decalage_X+Largeur_ecran>Principal_Largeur_image)
-
Principal_Decalage_X=Principal_Largeur_image-Largeur_ecran;
-
if (Principal_Decalage_X<0)
-
Principal_Decalage_X=0;
-
if (Principal_Decalage_Y+Menu_Ordonnee>Principal_Hauteur_image)
-
Principal_Decalage_Y=Principal_Hauteur_image-Menu_Ordonnee;
-
if (Principal_Decalage_Y<0)
-
Principal_Decalage_Y=0;
-
}
-
-
Calculer_donnees_loupe();
-
if (Loupe_Mode)
-
Recadrer_ecran_par_rapport_au_zoom();
-
Calculer_limites();
-
Calculer_coordonnees_pinceau();
-
Afficher_ecran();
-
-
Resize_Largeur=0;
-
Resize_Hauteur=0;
-
}
-
-
-
-
// -- Redimentionner l'image (nettoie l'écran virtuel) --
-
-
void Redimentionner_image(word Largeur_choisie,word Hauteur_choisie)
-
{
-
word Ancienne_largeur=Principal_Largeur_image;
-
word Ancienne_hauteur=Principal_Hauteur_image;
-
-
// +-+-+
-
// |C| | A+B+C = Ancienne image
-
// +-+A|
-
// |B| | C = Nouvelle image
-
// +-+-+
-
-
if (Backup_avec_nouvelles_dimensions(1,Largeur_choisie,Hauteur_choisie))
-
{
-
// La nouvelle page a pu être allouée, elle est pour l'instant pleine de
-
// 0s. Elle fait Principal_Largeur_image de large.
-
-
// On copie donc maintenant la partie C dans la nouvelle image.
-
Copier_une_partie_d_image_dans_une_autre(
-
Ecran_backup,0,0,Min(Ancienne_largeur,Principal_Largeur_image),
-
Min(Ancienne_hauteur,Principal_Hauteur_image),Ancienne_largeur,
-
Principal_Ecran,0,0,Principal_Largeur_image);
-
}
-
else
-
{
-
// Afficher un message d'erreur
-
Afficher_curseur();
-
Message_Memoire_insuffisante();
-
Effacer_curseur();
-
}
-
}
-
-
-
-
void Remap_picture(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_YLimite_Gauche) &&
-
(Lit_pixel_dans_ecran_courant(Debut_X-1,Ligne)==2)) ||
-
// Test de la présence d'un point à droite du segment
-
((Fin_X-1Limite_Haut))
-
for (Pos_X=Debut_X;Pos_X*Limite_atteinte_Droite)
-
*Limite_atteinte_Droite=Fin_X;
-
// On remplit le segment de Debut_X à Fin_X-1.
-
for (Pos_X=Debut_X;Pos_XLimite_Haut)
-
Limite_courante_Haut--;
-
-
for (Ligne=Limite_courante_Bas;Ligne>=Limite_courante_Haut;Ligne--)
-
{
-
Ligne_modifiee=0;
-
// On va traiter le cas de la ligne n° Ligne.
-
-
// On commence le traitement à la gauche de l'écran
-
Debut_X=Limite_Gauche;
-
-
// Pour chaque segment de couleur 1 que peut contenir la ligne
-
while (Debut_X<=Limite_Droite)
-
{
-
// On cherche son début
-
for (;(Debut_X<=Limite_Droite) &&
-
(Lit_pixel_dans_ecran_courant(Debut_X,Ligne)!=1);Debut_X++);
-
-
if (Debut_X<=Limite_Droite)
-
{
-
// Un segment de couleur 1 existe et commence à la position Debut_X.
-
// On va donc en chercher la fin.
-
for (Fin_X=Debut_X+1;(Fin_X<=Limite_Droite) &&
-
(Lit_pixel_dans_ecran_courant(Fin_X,Ligne)==1);Fin_X++);
-
-
// On sait qu'il existe un segment de couleur 1 qui commence en
-
// Debut_X et qui se termine en Fin_X-1.
-
-
// On va maintenant regarder si une couleur sur la périphérie
-
// permet de colorier ce segment avec la couleur 2.
-
-
Propagation_possible=(
-
// Test de la présence d'un point à gauche du segment
-
((Debut_X>Limite_Gauche) &&
-
(Lit_pixel_dans_ecran_courant(Debut_X-1,Ligne)==2)) ||
-
// Test de la présence d'un point à droite du segment
-
((Fin_X-1*Limite_atteinte_Droite)
-
*Limite_atteinte_Droite=Fin_X;
-
// On remplit le segment de Debut_X à Fin_X-1.
-
for (Pos_X=Debut_X;Pos_XLimite_Haut) )
-
Limite_courante_Haut--; // On monte cette limite vers le haut
-
}
-
}
-
-
*Limite_atteinte_Haut=Limite_courante_Haut;
-
*Limite_atteinte_Bas =Limite_courante_Bas;
-
(*Limite_atteinte_Droite)--;
-
} // Fin de la routine de remplissage "Fill"
-
-
-
void Remplir(byte Couleur_de_remplissage)
-
//
-
// Cette fonction fait un remplissage qui gère tous les effets. Elle fait
-
// appel à "Fill()".
-
//
-
{
-
byte Forme_curseur_avant_remplissage;
-
byte * FX_Feedback_Ecran_avant_remplissage;
-
short Pos_X,Pos_Y;
-
short Limite_atteinte_Haut ,Limite_atteinte_Bas;
-
short Limite_atteinte_Gauche,Limite_atteinte_Droite;
-
byte Table_de_remplacement[256];
-
-
-
// Avant toute chose, on vérifie que l'on n'est pas en train de remplir
-
// en dehors de l'image:
-
-
if ( (Pinceau_X>=Limite_Gauche) &&
-
(Pinceau_X<=Limite_Droite) &&
-
(Pinceau_Y>=Limite_Haut) &&
-
(Pinceau_Y<=Limite_Bas) )
-
{
-
// On suppose que le curseur est déjà caché.
-
// Effacer_curseur();
-
-
// On va faire patienter l'utilisateur en lui affichant un joli petit
-
// sablier:
-
Forme_curseur_avant_remplissage=Forme_curseur;
-
Forme_curseur=FORME_CURSEUR_SABLIER;
-
Afficher_curseur();
-
-
// On commence par effectuer un backup de l'image.
-
Backup();
-
-
// On fait attention au Feedback qui DOIT se faire avec le backup.
-
FX_Feedback_Ecran_avant_remplissage=FX_Feedback_Ecran;
-
FX_Feedback_Ecran=Ecran_backup;
-
-
// On va maintenant "épurer" la zone visible de l'image:
-
memset(Table_de_remplacement,0,256);
-
Table_de_remplacement[Lit_pixel_dans_ecran_courant(Pinceau_X,Pinceau_Y)]=1;
-
Remplacer_toutes_les_couleurs_dans_limites(Table_de_remplacement);
-
-
// On fait maintenant un remplissage classique de la couleur 1 avec la 2
-
Fill(&Limite_atteinte_Haut ,&Limite_atteinte_Bas,
-
&Limite_atteinte_Gauche,&Limite_atteinte_Droite);
-
-
// On s'apprête à faire des opérations qui nécessitent un affichage. Il
-
// faut donc retirer de l'écran le curseur:
-
Effacer_curseur();
-
Forme_curseur=Forme_curseur_avant_remplissage;
-
-
// Il va maintenant falloir qu'on "turn" ce gros caca "into" un truc qui
-
// ressemble un peu plus à ce à quoi l'utilisateur peut s'attendre.
-
if (Limite_atteinte_Haut>Limite_Haut)
-
Copier_une_partie_d_image_dans_une_autre(Ecran_backup, // Source
-
Limite_Gauche,Limite_Haut, // Pos X et Y dans source
-
(Limite_Droite-Limite_Gauche)+1, // Largeur copie
-
Limite_atteinte_Haut-Limite_Haut,// Hauteur copie
-
Principal_Largeur_image, // Largeur de la source
-
Principal_Ecran, // Destination
-
Limite_Gauche,Limite_Haut, // Pos X et Y destination
-
Principal_Largeur_image); // Largeur destination
-
if (Limite_atteinte_BasLimite_Gauche)
-
Copier_une_partie_d_image_dans_une_autre(Ecran_backup,
-
Limite_Gauche,Limite_atteinte_Haut,
-
Limite_atteinte_Gauche-Limite_Gauche,
-
(Limite_atteinte_Bas-Limite_atteinte_Haut)+1,
-
Principal_Largeur_image,Principal_Ecran,
-
Limite_Gauche,Limite_atteinte_Haut,Principal_Largeur_image);
-
if (Limite_atteinte_Droite=Limite_Gauche) &&
-
(Pos_X<=Limite_Droite) &&
-
(Pos_Y>=Limite_Haut) &&
-
(Pos_Y<=Limite_Bas) )
-
Pixel_Preview(Pos_X,Pos_Y,Couleur);
-
}
-
// Affichage d'un point pour une preview, avec sa propre couleur
-
void Pixel_figure_Preview_auto(word Pos_X,word Pos_Y)
-
{
-
if ( (Pos_X>=Limite_Gauche) &&
-
(Pos_X<=Limite_Droite) &&
-
(Pos_Y>=Limite_Haut) &&
-
(Pos_Y<=Limite_Bas) )
-
Pixel_Preview(Pos_X,Pos_Y,Lit_pixel_dans_ecran_courant(Pos_X,Pos_Y));
-
}
-
-
// Affichage d'un point pour une preview en xor
-
void Pixel_figure_Preview_xor(word Pos_X,word Pos_Y,__attribute__((unused)) byte Couleur)
-
{
-
if ( (Pos_X>=Limite_Gauche) &&
-
(Pos_X<=Limite_Droite) &&
-
(Pos_Y>=Limite_Haut) &&
-
(Pos_Y<=Limite_Bas) )
-
Pixel_Preview(Pos_X,Pos_Y,~Lit_pixel(Pos_X-Principal_Decalage_X,
-
Pos_Y-Principal_Decalage_Y));
-
}
-
-
// Effacement d'un point de preview
-
void Pixel_figure_Effacer_preview(word Pos_X,word Pos_Y,__attribute__((unused)) byte Couleur)
-
{
-
if ( (Pos_X>=Limite_Gauche) &&
-
(Pos_X<=Limite_Droite) &&
-
(Pos_Y>=Limite_Haut) &&
-
(Pos_Y<=Limite_Bas) )
-
Pixel_Preview(Pos_X,Pos_Y,Lit_pixel_dans_ecran_courant(Pos_X,Pos_Y));
-
}
-
-
// Affichage d'un point dans la brosse
-
void Pixel_figure_Dans_brosse(word Pos_X,word Pos_Y,byte Couleur)
-
{
-
Pos_X-=Brosse_Decalage_X;
-
Pos_Y-=Brosse_Decalage_Y;
-
if ( (Pos_XLimite_Bas)
-
Fin_Y=Limite_Bas;
-
if (Debut_XLimite_Droite)
-
Fin_X=Limite_Droite;
-
-
// Affichage du cercle
-
for (Pos_Y=Debut_Y,Cercle_Curseur_Y=(long)Debut_Y-Centre_Y;Pos_Y<=Fin_Y;Pos_Y++,Cercle_Curseur_Y++)
-
for (Pos_X=Debut_X,Cercle_Curseur_X=(long)Debut_X-Centre_X;Pos_X<=Fin_X;Pos_X++,Cercle_Curseur_X++)
-
if (Pixel_dans_cercle())
-
Afficher_pixel(Pos_X,Pos_Y,Couleur);
-
-
Mettre_Ecran_A_Jour(Debut_X,Debut_Y,Fin_X+1-Debut_X,Fin_Y+1-Debut_Y);
-
}
-
-
-
// -- Tracer général d'une ellipse vide -----------------------------------
-
-
void Tracer_ellipse_vide_General(short Centre_X,short Centre_Y,short Rayon_horizontal,short Rayon_vertical,byte Couleur)
-
{
-
short Debut_X;
-
short Debut_Y;
-
short Pos_X;
-
short Pos_Y;
-
-
Debut_X=Centre_X-Rayon_horizontal;
-
Debut_Y=Centre_Y-Rayon_vertical;
-
-
// Calcul des limites de l'ellipse
-
Ellipse_Calculer_limites(Rayon_horizontal+1,Rayon_vertical+1);
-
-
// Affichage des extremitées de l'ellipse sur chaque quart de l'ellipse:
-
for (Pos_Y=Debut_Y,Ellipse_Curseur_Y=-Rayon_vertical;Pos_YLimite_Bas)
-
Fin_Y=Limite_Bas;
-
if (Debut_XLimite_Droite)
-
Fin_X=Limite_Droite;
-
-
// Affichage de l'ellipse
-
for (Pos_Y=Debut_Y,Ellipse_Curseur_Y=Debut_Y-Centre_Y;Pos_Y<=Fin_Y;Pos_Y++,Ellipse_Curseur_Y++)
-
for (Pos_X=Debut_X,Ellipse_Curseur_X=Debut_X-Centre_X;Pos_X<=Fin_X;Pos_X++,Ellipse_Curseur_X++)
-
if (Pixel_dans_ellipse())
-
Afficher_pixel(Pos_X,Pos_Y,Couleur);
-
Mettre_Ecran_A_Jour(Centre_X-Rayon_horizontal,Centre_Y-Rayon_vertical,2*Rayon_horizontal+1,2*Rayon_vertical+1);
-
}
-
-
/******************
-
* TRACÉ DE LIGNES *
-
******************/
-
-
void Rectifier_coordonnees_a_45_degres(short AX, short AY, short* BX, short* BY)
-
// Modifie BX et BY pour que la ligne AXAY - BXBY soit
-
// - une droite horizontale
-
// - une droite verticale
-
// - une droite avec une pente de 45 degrés
-
{
-
int dx, dy;
-
float tan;
-
-
dx = (*BX)-AX;
-
dy = AY- *BY; // On prend l'opposée car à l'écran les Y sont positifs en bas, et en maths, positifs en haut
-
-
if (dx==0) return; // On est en lockx et de toutes façons le X n'a pas bougé, on sort tout de suite pour éviter une méchante division par 0
-
-
tan = (float)dy/(float)dx;
-
-
if (tan <= 0.4142 && tan >= -0.4142)
-
{
-
// Cas 1 : Lock Y
-
*BY = AY;
-
}
-
else if ( tan > 0.4142 && tan < 2.4142)
-
{
-
// Cas 2 : dy=dx
-
int nBY = AY - dx;
-
*BY = (*BY + nBY)/2;
-
*BX = AX + AY - *BY;
-
}
-
else if (tan < -0.4142 && tan >= -2.4142)
-
{
-
// Cas 8 : dy = -dx
-
int nBY = AY + dx;
-
*BY = (*BY + nBY)/2;
-
*BX = AX - AY + *BY;
-
}
-
else
-
{
-
// Cas 3 : Lock X
-
*BX = AX;
-
}
-
-
return;
-
}
-
-
// -- Tracer général d'une ligne ------------------------------------------
-
-
void Tracer_ligne_General(short Debut_X,short Debut_Y,short Fin_X,short Fin_Y, byte Couleur)
-
{
-
short Pos_X,Pos_Y;
-
short Incr_X,Incr_Y;
-
short i,Cumul;
-
short Delta_X,Delta_Y;
-
-
-
Pos_X=Debut_X;
-
Pos_Y=Debut_Y;
-
-
if (Debut_XDelta_X)
-
{
-
Cumul=Delta_Y>>1;
-
for (i=1; i=Delta_Y)
-
{
-
Cumul-=Delta_Y;
-
Pos_X+=Incr_X;
-
}
-
Pixel_figure(Pos_X,Pos_Y,Couleur);
-
}
-
}
-
else
-
{
-
Cumul=Delta_X>>1;
-
for (i=1; i=Delta_X)
-
{
-
Cumul-=Delta_X;
-
Pos_Y+=Incr_Y;
-
}
-
Pixel_figure(Pos_X,Pos_Y,Couleur);
-
}
-
}
-
-
if ( (Debut_X!=Fin_X) || (Debut_Y!=Fin_Y) )
-
Pixel_figure(Fin_X,Fin_Y,Couleur);
-
-
}
-
-
// -- Tracer définitif d'une ligne --
-
-
void Tracer_ligne_Definitif(short Debut_X,short Debut_Y,short Fin_X,short Fin_Y, byte Couleur)
-
{
-
-
int L = Fin_X-Debut_X, H = Fin_Y - Debut_Y;
-
Pixel_figure=Pixel_figure_Definitif;
-
Tracer_ligne_General(Debut_X,Debut_Y,Fin_X,Fin_Y,Couleur);
-
Mettre_Ecran_A_Jour((Debut_XFin_X)
-
{
-
Tempo=Debut_X;
-
Debut_X=Fin_X;
-
Fin_X=Tempo;
-
}
-
if (Debut_Y>Fin_Y)
-
{
-
Tempo=Debut_Y;
-
Debut_Y=Fin_Y;
-
Fin_Y=Tempo;
-
}
-
-
// On trace le rectangle:
-
-
for (Pos_X=Debut_X;Pos_X<=Fin_X;Pos_X++)
-
Afficher_pinceau(Pos_X,Debut_Y,Couleur,0);
-
-
for (Pos_Y=Debut_Y+1;Pos_YFin_X)
-
{
-
Tempo=Debut_X;
-
Debut_X=Fin_X;
-
Fin_X=Tempo;
-
}
-
if (Debut_Y>Fin_Y)
-
{
-
Tempo=Debut_Y;
-
Debut_Y=Fin_Y;
-
Fin_Y=Tempo;
-
}
-
-
// Correction en cas de dépassement des limites de l'image
-
if (Fin_X>Limite_Droite)
-
Fin_X=Limite_Droite;
-
if (Fin_Y>Limite_Bas)
-
Fin_Y=Limite_Bas;
-
-
// On trace le rectangle:
-
for (Pos_Y=Debut_Y;Pos_Y<=Fin_Y;Pos_Y++)
-
for (Pos_X=Debut_X;Pos_X<=Fin_X;Pos_X++)
-
// Afficher_pixel traite chaque pixel avec tous les effets ! (smear, ...)
-
// Donc on ne peut pas otimiser en traçant ligne par ligne avec memset :(
-
Afficher_pixel(Pos_X,Pos_Y,Couleur);
-
Mettre_Ecran_A_Jour(Debut_X,Debut_Y,Fin_X-Debut_X,Fin_Y-Debut_Y);
-
-
}
-
-
-
-
-
// -- Tracer une courbe de Bézier --
-
-
void Tracer_courbe_General(short X1, short Y1,
-
short X2, short Y2,
-
short X3, short Y3,
-
short X4, short Y4,
-
byte Couleur)
-
{
-
float Delta,T,T2,T3;
-
short X,Y,Old_X,Old_Y;
-
word i;
-
int CX[4];
-
int CY[4];
-
-
// Calcul des vecteurs de coefficients
-
CX[0]= - X1 + 3*X2 - 3*X3 + X4;
-
CX[1]= + 3*X1 - 6*X2 + 3*X3;
-
CX[2]= - 3*X1 + 3*X2;
-
CX[3]= + X1;
-
CY[0]= - Y1 + 3*Y2 - 3*Y3 + Y4;
-
CY[1]= + 3*Y1 - 6*Y2 + 3*Y3;
-
CY[2]= - 3*Y1 + 3*Y2;
-
CY[3]= + Y1;
-
-
// Traçage de la courbe
-
Old_X=X1;
-
Old_Y=Y1;
-
Pixel_figure(Old_X,Old_Y,Couleur);
-
Delta=0.05; // 1.0/20
-
T=0;
-
for (i=1; i<=20; i++)
-
{
-
T=T+Delta; T2=T*T; T3=T2*T;
-
X=Round(T3*CX[0] + T2*CX[1] + T*CX[2] + CX[3]);
-
Y=Round(T3*CY[0] + T2*CY[1] + T*CY[2] + CY[3]);
-
Tracer_ligne_General(Old_X,Old_Y,X,Y,Couleur);
-
Old_X=X;
-
Old_Y=Y;
-
}
-
-
X = Min(Min(X1,X2),Min(X3,X4));
-
Y = Min(Min(Y1,Y2),Min(Y3,Y4));
-
Old_X = Max(Max(X1,X2),Max(X3,X4)) - X;
-
Old_Y = Max(Max(Y1,Y2),Max(Y3,Y4)) - Y;
-
Mettre_Ecran_A_Jour(X,Y,Old_X+1,Old_Y+1);
-
}
-
-
// -- Tracer une courbe de Bézier définitivement --
-
-
void Tracer_courbe_Definitif(short X1, short Y1,
-
short X2, short Y2,
-
short X3, short Y3,
-
short X4, short Y4,
-
byte Couleur)
-
{
-
Pixel_figure=Pixel_figure_Definitif;
-
Tracer_courbe_General(X1,Y1,X2,Y2,X3,Y3,X4,Y4,Couleur);
-
}
-
-
// -- Tracer la preview d'une courbe de Bézier --
-
-
void Tracer_courbe_Preview(short X1, short Y1,
-
short X2, short Y2,
-
short X3, short Y3,
-
short X4, short Y4,
-
byte Couleur)
-
{
-
Pixel_figure=Pixel_figure_Preview;
-
Tracer_courbe_General(X1,Y1,X2,Y2,X3,Y3,X4,Y4,Couleur);
-
}
-
-
// -- Effacer la preview d'une courbe de Bézier --
-
-
void Effacer_courbe_Preview(short X1, short Y1,
-
short X2, short Y2,
-
short X3, short Y3,
-
short X4, short Y4,
-
byte Couleur)
-
{
-
Pixel_figure=Pixel_figure_Effacer_preview;
-
Tracer_courbe_General(X1,Y1,X2,Y2,X3,Y3,X4,Y4,Couleur);
-
}
-
-
-
-
-
// -- Spray : un petit coup de Pschiitt! --
-
-
void Aerographe(short Bouton_clicke)
-
{
-
short Pos_X,Pos_Y;
-
short Rayon=Spray_Size>>1;
-
long Rayon_au_carre=(long)Rayon*Rayon;
-
short Indice,Count;
-
byte Indice_couleur;
-
byte Sens;
-
-
-
Effacer_curseur();
-
-
if (Spray_Mode)
-
{
-
for (Count=1; Count<=Spray_Mono_flow; Count++)
-
{
-
Pos_X=(rand()%Spray_Size)-Rayon;
-
Pos_Y=(rand()%Spray_Size)-Rayon;
-
if ( (Pos_X*Pos_X)+(Pos_Y*Pos_Y) <= Rayon_au_carre )
-
{
-
Pos_X+=Pinceau_X;
-
Pos_Y+=Pinceau_Y;
-
if (Bouton_clicke==1)
-
Afficher_pinceau(Pos_X,Pos_Y,Fore_color,0);
-
else
-
Afficher_pinceau(Pos_X,Pos_Y,Back_color,0);
-
}
-
}
-
}
-
else
-
{
-
// On essaye de se balader dans la table des flux de façon à ce que ce
-
// ne soit pas toujours la dernière couleur qui soit affichée en dernier
-
// Pour ça, on part d'une couleur au pif dans une direction aléatoire.
-
Sens=rand()&1;
-
for (Indice=0,Indice_couleur=rand()/*%256*/; Indice<256; Indice++)
-
{
-
for (Count=1; Count<=Spray_Multi_flow[Indice_couleur]; Count++)
-
{
-
Pos_X=(rand()%Spray_Size)-Rayon;
-
Pos_Y=(rand()%Spray_Size)-Rayon;
-
if ( (Pos_X*Pos_X)+(Pos_Y*Pos_Y) <= Rayon_au_carre )
-
{
-
Pos_X+=Pinceau_X;
-
Pos_Y+=Pinceau_Y;
-
if (Bouton_clicke==A_GAUCHE)
-
Afficher_pinceau(Pos_X,Pos_Y,Indice_couleur,0);
-
else
-
Afficher_pinceau(Pos_X,Pos_Y,Back_color,0);
-
}
-
}
-
if (Sens)
-
Indice_couleur++;
-
else
-
Indice_couleur--;
-
}
-
}
-
-
Afficher_curseur();
-
-
for (Count=1; Count<=Spray_Delay; Count++)
-
Wait_VBL();
-
}
-
-
-
-
//////////////////////////////////////////////////////////////////////////
-
////////////////////////// GESTION DES DEGRADES //////////////////////////
-
//////////////////////////////////////////////////////////////////////////
-
-
-
// -- Gestion d'un dégradé de base (le plus moche) --
-
-
void Degrade_de_base(long Indice,short Pos_X,short Pos_Y)
-
{
-
long Position;
-
-
// On fait un premier calcul partiel
-
Position=(Indice*Degrade_Intervalle_bornes);
-
-
// On gère un déplacement au hasard
-
Position+=(Degrade_Intervalle_total*(rand()%Degrade_Melange_aleatoire)) >>6;
-
Position-=(Degrade_Intervalle_total*Degrade_Melange_aleatoire) >>7;
-
-
Position/=Degrade_Intervalle_total;
-
-
// On va vérifier que nos petites idioties n'ont pas éjecté la valeur hors
-
// des valeurs autorisées par le dégradé défini par l'utilisateur.
-
-
if (Position<0)
-
Position=0;
-
else if (Position>=Degrade_Intervalle_bornes)
-
Position=Degrade_Intervalle_bornes-1;
-
-
// On ramène ensuite la position dans le dégradé vers un numéro de couleur
-
if (Degrade_Inverse)
-
Traiter_pixel_de_degrade(Pos_X,Pos_Y,Degrade_Borne_Superieure-Position);
-
else
-
Traiter_pixel_de_degrade(Pos_X,Pos_Y,Degrade_Borne_Inferieure+Position);
-
}
-
-
-
// -- Gestion d'un dégradé par trames simples --
-
-
void Degrade_de_trames_simples(long Indice,short Pos_X,short Pos_Y)
-
{
-
long Position_dans_degrade;
-
long Position_dans_segment;
-
-
//
-
// But de l'opération: en plus de calculer la position de base (désignée
-
// dans cette procédure par "Position_dans_degrade", on calcule la position
-
// de l'indice dans le schéma suivant:
-
//
-
// | Les indices qui traînent de ce côté du segment se voient subir
-
// | une incrémentation conditionnelle à leur position dans l'écran.
-
// v
-
// |---|---|---|---- - - -
-
// ^
-
// |_ Les indices qui traînent de ce côté du segment se voient subir une
-
// décrémentation conditionnelle à leur position dans l'écran.
-
-
// On fait d'abord un premier calcul partiel
-
Position_dans_degrade=(Indice*Degrade_Intervalle_bornes);
-
-
// On gère un déplacement au hasard...
-
Position_dans_degrade+=(Degrade_Intervalle_total*(rand()%Degrade_Melange_aleatoire)) >>6;
-
Position_dans_degrade-=(Degrade_Intervalle_total*Degrade_Melange_aleatoire) >>7;
-
-
if (Position_dans_degrade<0)
-
Position_dans_degrade=0;
-
-
// ... qui nous permet de calculer la position dans le segment
-
Position_dans_segment=((Position_dans_degrade<<2)/Degrade_Intervalle_total)&3;
-
-
// On peut ensuite terminer le calcul de l'indice dans le dégradé
-
Position_dans_degrade/=Degrade_Intervalle_total;
-
-
// On va pouvoir discuter de la valeur de Position_dans_degrade en fonction
-
// de la position dans l'écran et de la Position_dans_segment.
-
-
switch (Position_dans_segment)
-
{
-
case 0 : // On est sur la gauche du segment
-
if (((Pos_X+Pos_Y)&1)==0)
-
Position_dans_degrade--;
-
break;
-
-
// On n'a pas à traiter les cas 1 et 2 car ils représentent des valeurs
-
// suffisament au centre du segment pour ne pas avoir à subir la trame
-
-
case 3 : // On est sur la droite du segment
-
if (((Pos_X+Pos_Y)&1)!=0) // Note: on doit faire le test inverse au cas gauche pour synchroniser les 2 côtés de la trame.
-
Position_dans_degrade++;
-
}
-
-
// On va vérifier que nos petites idioties n'ont pas éjecté la valeur hors
-
// des valeurs autorisées par le dégradé défini par l'utilisateur.
-
-
if (Position_dans_degrade<0)
-
Position_dans_degrade=0;
-
else if (Position_dans_degrade>=Degrade_Intervalle_bornes)
-
Position_dans_degrade=Degrade_Intervalle_bornes-1;
-
-
// On ramène ensuite la position dans le dégradé vers un numéro de couleur
-
if (Degrade_Inverse)
-
Position_dans_degrade=Degrade_Borne_Superieure-Position_dans_degrade;
-
else
-
Position_dans_degrade=Degrade_Borne_Inferieure+Position_dans_degrade;
-
-
Traiter_pixel_de_degrade(Pos_X,Pos_Y,Position_dans_degrade);
-
}
-
-
-
// -- Gestion d'un dégradé par trames étendues --
-
-
void Degrade_de_trames_etendues(long Indice,short Pos_X,short Pos_Y)
-
{
-
long Position_dans_degrade;
-
long Position_dans_segment;
-
-
//
-
// But de l'opération: en plus de calculer la position de base (désignée
-
// dans cette procédure par "Position_dans_degrade", on calcule la position
-
// de l'indice dans le schéma suivant:
-
//
-
// | Les indices qui traînent de ce côté du segment se voient subir
-
// | une incrémentation conditionnelle à leur position dans l'écran.
-
// v
-
// |---|---|---|---- - - -
-
// ^
-
// |_ Les indices qui traînent de ce côté du segment se voient subir une
-
// décrémentation conditionnelle à leur position dans l'écran.
-
-
// On fait d'abord un premier calcul partiel
-
Position_dans_degrade=(Indice*Degrade_Intervalle_bornes);
-
-
// On gère un déplacement au hasard
-
Position_dans_degrade+=(Degrade_Intervalle_total*(rand()%Degrade_Melange_aleatoire)) >>6;
-
Position_dans_degrade-=(Degrade_Intervalle_total*Degrade_Melange_aleatoire) >>7;
-
-
if (Position_dans_degrade<0)
-
Position_dans_degrade=0;
-
-
// Qui nous permet de calculer la position dans le segment
-
Position_dans_segment=((Position_dans_degrade<<3)/Degrade_Intervalle_total)&7;
-
-
// On peut ensuite terminer le calcul de l'indice dans le dégradé
-
Position_dans_degrade/=Degrade_Intervalle_total;
-
-
// On va pouvoir discuter de la valeur de Position_dans_degrade en fonction
-
// de la position dans l'écran et de la Position_dans_segment.
-
-
switch (Position_dans_segment)
-
{
-
case 0 : // On est sur l'extrême gauche du segment
-
if (((Pos_X+Pos_Y)&1)==0)
-
Position_dans_degrade--;
-
break;
-
-
case 1 : // On est sur la gauche du segment
-
case 2 : // On est sur la gauche du segment
-
if (((Pos_X & 1)==0) && ((Pos_Y & 1)==0))
-
Position_dans_degrade--;
-
break;
-
-
// On n'a pas à traiter les cas 3 et 4 car ils représentent des valeurs
-
// suffisament au centre du segment pour ne pas avoir à subir la trame
-
-
case 5 : // On est sur la droite du segment
-
case 6 : // On est sur la droite du segment
-
if (((Pos_X & 1)==0) && ((Pos_Y & 1)!=0))
-
Position_dans_degrade++;
-
break;
-
-
case 7 : // On est sur l'extreme droite du segment
-
if (((Pos_X+Pos_Y)&1)!=0) // Note: on doit faire le test inverse au cas gauche pour synchroniser les 2 côtés de la trame.
-
Position_dans_degrade++;
-
}
-
-
// On va vérifier que nos petites idioties n'ont pas éjecté la valeur hors
-
// des valeurs autorisées par le dégradé défini par l'utilisateur.
-
-
if (Position_dans_degrade<0)
-
Position_dans_degrade=0;
-
else if (Position_dans_degrade>=Degrade_Intervalle_bornes)
-
Position_dans_degrade=Degrade_Intervalle_bornes-1;
-
-
// On ramène ensuite la position dans le dégradé vers un numéro de couleur
-
if (Degrade_Inverse)
-
Position_dans_degrade=Degrade_Borne_Superieure-Position_dans_degrade;
-
else
-
Position_dans_degrade=Degrade_Borne_Inferieure+Position_dans_degrade;
-
-
Traiter_pixel_de_degrade(Pos_X,Pos_Y,Position_dans_degrade);
-
}
-
-
-
-
// -- Tracer un cercle degradé (une sphère) --
-
-
void Tracer_cercle_degrade(short Centre_X,short Centre_Y,short Rayon,short Eclairage_X,short Eclairage_Y)
-
{
-
long Debut_X;
-
long Debut_Y;
-
long Pos_X;
-
long Pos_Y;
-
long Fin_X;
-
long Fin_Y;
-
long Distance_X; // Distance (au carré) sur les X du point en cours au centre d'éclairage
-
long Distance_Y; // Distance (au carré) sur les Y du point en cours au centre d'éclairage
-
-
Debut_X=Centre_X-Rayon;
-
Debut_Y=Centre_Y-Rayon;
-
Fin_X=Centre_X+Rayon;
-
Fin_Y=Centre_Y+Rayon;
-
-
// Correction des bornes d'après les limites
-
if (Debut_YLimite_Bas)
-
Fin_Y=Limite_Bas;
-
if (Debut_XLimite_Droite)
-
Fin_X=Limite_Droite;
-
-
Degrade_Intervalle_total=Cercle_Limite+
-
((Centre_X-Eclairage_X)*(Centre_X-Eclairage_X))+
-
((Centre_Y-Eclairage_Y)*(Centre_Y-Eclairage_Y))+
-
(2L*Rayon*sqrt(
-
((Centre_X-Eclairage_X)*(Centre_X-Eclairage_X))+
-
((Centre_Y-Eclairage_Y)*(Centre_Y-Eclairage_Y))));
-
-
if (Degrade_Intervalle_total==0)
-
Degrade_Intervalle_total=1;
-
-
// Affichage du cercle
-
for (Pos_Y=Debut_Y,Cercle_Curseur_Y=(long)Debut_Y-Centre_Y;Pos_Y<=Fin_Y;Pos_Y++,Cercle_Curseur_Y++)
-
{
-
Distance_Y =(Pos_Y-Eclairage_Y);
-
Distance_Y*=Distance_Y;
-
for (Pos_X=Debut_X,Cercle_Curseur_X=(long)Debut_X-Centre_X;Pos_X<=Fin_X;Pos_X++,Cercle_Curseur_X++)
-
if (Pixel_dans_cercle())
-
{
-
Distance_X =(Pos_X-Eclairage_X);
-
Distance_X*=Distance_X;
-
Traiter_degrade(Distance_X+Distance_Y,Pos_X,Pos_Y);
-
}
-
}
-
-
Mettre_Ecran_A_Jour(Centre_X-Rayon,Centre_Y-Rayon,2*Rayon+1,2*Rayon+1);
-
}
-
-
-
// -- Tracer une ellipse degradée --
-
-
void Tracer_ellipse_degradee(short Centre_X,short Centre_Y,short Rayon_horizontal,short Rayon_vertical,short Eclairage_X,short Eclairage_Y)
-
{
-
long Debut_X;
-
long Debut_Y;
-
long Pos_X;
-
long Pos_Y;
-
long Fin_X;
-
long Fin_Y;
-
long Distance_X; // Distance (au carré) sur les X du point en cours au centre d'éclairage
-
long Distance_Y; // Distance (au carré) sur les Y du point en cours au centre d'éclairage
-
-
-
Debut_X=Centre_X-Rayon_horizontal;
-
Debut_Y=Centre_Y-Rayon_vertical;
-
Fin_X=Centre_X+Rayon_horizontal;
-
Fin_Y=Centre_Y+Rayon_vertical;
-
-
// Calcul des limites de l'ellipse
-
Ellipse_Calculer_limites(Rayon_horizontal+1,Rayon_vertical+1);
-
-
// On calcule la distance maximale:
-
Degrade_Intervalle_total=(Rayon_horizontal*Rayon_horizontal)+
-
(Rayon_vertical*Rayon_vertical)+
-
((Centre_X-Eclairage_X)*(Centre_X-Eclairage_X))+
-
((Centre_Y-Eclairage_Y)*(Centre_Y-Eclairage_Y))+
-
(2L
-
*sqrt(
-
(Rayon_horizontal*Rayon_horizontal)+
-
(Rayon_vertical *Rayon_vertical ))
-
*sqrt(
-
((Centre_X-Eclairage_X)*(Centre_X-Eclairage_X))+
-
((Centre_Y-Eclairage_Y)*(Centre_Y-Eclairage_Y))));
-
-
if (Degrade_Intervalle_total==0)
-
Degrade_Intervalle_total=1;
-
-
// Correction des bornes d'après les limites
-
if (Debut_YLimite_Bas)
-
Fin_Y=Limite_Bas;
-
if (Debut_XLimite_Droite)
-
Fin_X=Limite_Droite;
-
-
// Affichage de l'ellipse
-
for (Pos_Y=Debut_Y,Ellipse_Curseur_Y=Debut_Y-Centre_Y;Pos_Y<=Fin_Y;Pos_Y++,Ellipse_Curseur_Y++)
-
{
-
Distance_Y =(Pos_Y-Eclairage_Y);
-
Distance_Y*=Distance_Y;
-
for (Pos_X=Debut_X,Ellipse_Curseur_X=Debut_X-Centre_X;Pos_X<=Fin_X;Pos_X++,Ellipse_Curseur_X++)
-
if (Pixel_dans_ellipse())
-
{
-
Distance_X =(Pos_X-Eclairage_X);
-
Distance_X*=Distance_X;
-
Traiter_degrade(Distance_X+Distance_Y,Pos_X,Pos_Y);
-
}
-
}
-
-
Mettre_Ecran_A_Jour(Debut_X,Debut_Y,Fin_X-Debut_X+1,Fin_Y-Debut_Y+1);
-
}
-
-
-
// Tracé d'un rectangle (RAX RAY - RBX RBY) dégradé selon le vecteur (VAX VAY - VBX - VBY)
-
void Tracer_rectangle_degrade(short RAX,short RAY,short RBX,short RBY,short VAX,short VAY, short VBX, short VBY)
-
{
-
short Pos_Y, Pos_X;
-
-
// On commence par s'assurer que le rectangle est à l'endroit
-
if(RBX < RAX)
-
{
-
Pos_X = RBX;
-
RBX = RAX;
-
RAX = Pos_X;
-
}
-
-
if(RBY < RAY)
-
{
-
Pos_Y = RBY;
-
RBY = RAY;
-
RAY = Pos_Y;
-
}
-
-
// Correction des bornes d'après les limites
-
if (RAYLimite_Bas)
-
RBY=Limite_Bas;
-
if (RAXLimite_Droite)
-
RBX=Limite_Droite;
-
-
if(VBX == VAX)
-
{
-
// Le vecteur est vertical, donc on évite la partie en dessous qui foirerait avec une division par 0...
-
if (VBY == VAY) return; // L'utilisateur fait n'importe quoi
-
Degrade_Intervalle_total = abs(VBY - VAY);
-
for(Pos_Y=RAY;Pos_Y<=RBY;Pos_Y++)
-
for(Pos_X=RAX;Pos_X<=RBX;Pos_X++)
-
Traiter_degrade(abs(VBY - Pos_Y),Pos_X,Pos_Y);
-
-
}
-
else
-
{
-
float a;
-
float b;
-
float Distance_X, Distance_Y;
-
-
Degrade_Intervalle_total = sqrt(pow(VBY - VAY,2)+pow(VBX - VAX,2));
-
a = (float)(VBY - VAY)/(float)(VBX - VAX);
-
b = VAY - a*VAX;
-
-
for (Pos_Y=RAY;Pos_Y<=RBY;Pos_Y++)
-
for (Pos_X = RAX;Pos_X<=RBX;Pos_X++)
-
{
-
// On calcule ou on en est dans le dégradé
-
Distance_X = pow((Pos_Y - VAY),2)+pow((Pos_X - VAX),2);
-
Distance_Y = pow((-a * Pos_X + Pos_Y - b),2)/(a*a+1);
-
-
Traiter_degrade((int)sqrt(Distance_X - Distance_Y),Pos_X,Pos_Y);
-
}
-
}
-
Mettre_Ecran_A_Jour(RAX,RAY,RBX,RBY);
-
}
-
-
-
-
-
// -- Tracer un polygône plein --
-
-
typedef struct POLYGON_EDGE /* an active edge */
-
{
-
short top; /* top y position */
-
short bottom; /* bottom y position */
-
float x, dx; /* floating point x position and gradient */
-
float w; /* width of line segment */
-
struct POLYGON_EDGE *prev; /* doubly linked list */
-
struct POLYGON_EDGE *next;
-
} POLYGON_EDGE;
-
-
-
-
/* fill_edge_structure:
-
* Polygon helper function: initialises an edge structure for the 2d
-
* rasteriser.
-
*/
-
void fill_edge_structure(POLYGON_EDGE *edge, short *i1, short *i2)
-
{
-
short *it;
-
-
if (i2[1] < i1[1])
-
{
-
it = i1;
-
i1 = i2;
-
i2 = it;
-
}
-
-
edge->top = i1[1];
-
edge->bottom = i2[1] - 1;
-
edge->dx = ((float) i2[0] - (float) i1[0]) / ((float) i2[1] - (float) i1[1]);
-
edge->x = i1[0] + 0.4999999;
-
edge->prev = NULL;
-
edge->next = NULL;
-
-
if (edge->dx+1 < 0.0)
-
edge->x += edge->dx+1;
-
-
if (edge->dx >= 0.0)
-
edge->w = edge->dx;
-
else
-
edge->w = -(edge->dx);
-
-
if (edge->w-1.0<0.0)
-
edge->w = 0.0;
-
else
-
edge->w = edge->w-1;
-
}
-
-
-
-
/* add_edge:
-
* Adds an edge structure to a linked list, returning the new head pointer.
-
*/
-
POLYGON_EDGE * add_edge(POLYGON_EDGE *list, POLYGON_EDGE *edge, int sort_by_x)
-
{
-
POLYGON_EDGE *pos = list;
-
POLYGON_EDGE *prev = NULL;
-
-
if (sort_by_x)
-
{
-
while ( (pos) && ((pos->x+((pos->w+pos->dx)/2)) < (edge->x+((edge->w+edge->dx)/2))) )
-
{
-
prev = pos;
-
pos = pos->next;
-
}
-
}
-
else
-
{
-
while ((pos) && (pos->top < edge->top))
-
{
-
prev = pos;
-
pos = pos->next;
-
}
-
}
-
-
edge->next = pos;
-
edge->prev = prev;
-
-
if (pos)
-
pos->prev = edge;
-
-
if (prev)
-
{
-
prev->next = edge;
-
return list;
-
}
-
else
-
return edge;
-
}
-
-
-
-
/* remove_edge:
-
* Removes an edge structure from a list, returning the new head pointer.
-
*/
-
POLYGON_EDGE * remove_edge(POLYGON_EDGE *list, POLYGON_EDGE *edge)
-
{
-
if (edge->next)
-
edge->next->prev = edge->prev;
-
-
if (edge->prev)
-
{
-
edge->prev->next = edge->next;
-
return list;
-
}
-
else
-
return edge->next;
-
}
-
-
-
-
/* polygon:
-
* Draws a filled polygon with an arbitrary number of corners. Pass the
-
* number of vertices, then an array containing a series of x, y points
-
* (a total of vertices*2 values).
-
*/
-
void Polyfill_General(int Vertices, short * Points, int Color)
-
{
-
short c;
-
short top = 0x7FFF;
-
short bottom = 0;
-
short *i1, *i2;
-
short Pos_X,Fin_X;
-
POLYGON_EDGE *edge, *next_edge, *initial_edge;
-
POLYGON_EDGE *active_edges = NULL;
-
POLYGON_EDGE *inactive_edges = NULL;
-
-
-
/* allocate some space and fill the edge table */
-
initial_edge=edge=(POLYGON_EDGE *) malloc(sizeof(POLYGON_EDGE) * Vertices);
-
-
i1 = Points;
-
i2 = Points + ((Vertices-1)<<1);
-
-
for (c=0; cbottom >= edge->top)
-
{
-
if (edge->top < top)
-
top = edge->top;
-
-
if (edge->bottom > bottom)
-
bottom = edge->bottom;
-
-
inactive_edges = add_edge(inactive_edges, edge, 0);
-
edge++;
-
}
-
}
-
i2 = i1;
-
i1 += 2;
-
}
-
-
/* for each scanline in the polygon... */
-
for (c=top; c<=bottom; c++)
-
{
-
/* check for newly active edges */
-
edge = inactive_edges;
-
while ((edge) && (edge->top == c))
-
{
-
next_edge = edge->next;
-
inactive_edges = remove_edge(inactive_edges, edge);
-
active_edges = add_edge(active_edges, edge, 1);
-
edge = next_edge;
-
}
-
-
/* draw horizontal line segments */
-
if ((c>=Limite_Haut) && (c<=Limite_Bas))
-
{
-
edge = active_edges;
-
while ((edge) && (edge->next))
-
{
-
Pos_X=/*Round*/(edge->x);
-
Fin_X=/*Round*/(edge->next->x+edge->next->w);
-
if (Pos_XLimite_Droite)
-
Fin_X=Limite_Droite;
-
for (; Pos_X<=Fin_X; Pos_X++)
-
Pixel_figure(Pos_X,c,Color);
-
edge = edge->next->next;
-
}
-
}
-
-
/* update edges, sorting and removing dead ones */
-
edge = active_edges;
-
while (edge)
-
{
-
next_edge = edge->next;
-
if (c >= edge->bottom)
-
active_edges = remove_edge(active_edges, edge);
-
else
-
{
-
edge->x += edge->dx;
-
while ((edge->prev) && ( (edge->x+(edge->w/2)) < (edge->prev->x+(edge->prev->w/2))) )
-
{
-
if (edge->next)
-
edge->next->prev = edge->prev;
-
edge->prev->next = edge->next;
-
edge->next = edge->prev;
-
edge->prev = edge->prev->prev;
-
edge->next->prev = edge;
-
if (edge->prev)
-
edge->prev->next = edge;
-
else
-
active_edges = edge;
-
}
-
}
-
edge = next_edge;
-
}
-
}
-
-
free(initial_edge);
-
// On ne connait pas simplement les xmin et xmax ici, mais de toutes façon ce n'est pas utilisé en preview
-
Mettre_Ecran_A_Jour(0,top,Principal_Largeur_image,bottom-top+1);
-
}
-
-
-
void Polyfill(int Vertices, short * Points, int Color)
-
{
-
Pixel_figure=Afficher_pixel;
-
Polyfill_General(Vertices,Points,Color);
-
}
-
-
-
-
//------------ Remplacement de la couleur pointée par une autre --------------
-
-
void Remplacer(byte Nouvelle_couleur)
-
{
-
byte Ancienne_couleur;
-
-
if ((Pinceau_X255))
-
Indice++;
-
-
// On note la position de la première case de la séquence
-
Premier=Indice;
-
-
// On recherche la position de la dernière case de la séquence
-
for (Dernier=Premier;Liste[Dernier+1]<256;Dernier++);
-
-
// Pour toutes les cases non vides (et non inhibées) qui suivent
-
switch (Mode)
-
{
-
case MODE_SHADE_NORMAL :
-
for (;(Indice<512) && (Liste[Indice]<256);Indice++)
-
{ // On met à jour les tables de conversion
-
Couleur=Liste[Indice];
-
Table_inc[Couleur]=Liste[(Indice+Pas<=Dernier)?Indice+Pas:Dernier];
-
Table_dec[Couleur]=Liste[(Indice-Pas>=Premier)?Indice-Pas:Premier];
-
}
-
break;
-
case MODE_SHADE_BOUCLE :
-
Temp=1+Dernier-Premier;
-
for (;(Indice<512) && (Liste[Indice]<256);Indice++)
-
{ // On met à jour les tables de conversion
-
Couleur=Liste[Indice];
-
Table_inc[Couleur]=Liste[Premier+((Pas+Indice-Premier)%Temp)];
-
Table_dec[Couleur]=Liste[Premier+(((Temp-Pas)+Indice-Premier)%Temp)];
-
}
-
break;
-
default : // MODE_SHADE_NOSAT
-
for (;(Indice<512) && (Liste[Indice]<256);Indice++)
-
{ // On met à jour les tables de conversion
-
Couleur=Liste[Indice];
-
if (Indice+Pas<=Dernier)
-
Table_inc[Couleur]=Liste[Indice+Pas];
-
if (Indice-Pas>=Premier)
-
Table_dec[Couleur]=Liste[Indice-Pas];
-
}
-
}
-
}
-
}
-
-
-
-
// -- Interface avec l'image, affectée par le facteur de grossissement -------
-
-
// fonction d'affichage "Pixel" utilisée pour les opérations définitivement
-
// Ne doit à aucune condition être appelée en dehors de la partie visible
-
// de l'image dans l'écran (ça pourrait être grave)
-
void Afficher_pixel(word X,word Y,byte Couleur)
-
// X & Y sont la position d'un point dans l'IMAGE
-
// Couleur est la couleur du point
-
// Le Stencil est géré.
-
// Les effets sont gérés par appel à Fonction_effet().
-
// La Loupe est gérée par appel à Pixel_Preview().
-
{
-
if ( ( (!Trame_Mode) || (Effet_Trame(X,Y)) )
-
&& (!((Stencil_Mode) && (Stencil[Lit_pixel_dans_ecran_courant(X,Y)])))
-
&& (!((Mask_Mode) && (Mask_table[Lit_pixel_dans_ecran_brouillon(X,Y)]))) )
-
{
-
Couleur=Fonction_effet(X,Y,Couleur);
-
Pixel_dans_ecran_courant(X,Y,Couleur);
-
Pixel_Preview(X,Y,Couleur);
-
}
-
}
-
-
-
-
// -- Calcul des différents effets -------------------------------------------
-
-
// -- Aucun effet en cours --
-
-
byte Aucun_effet(__attribute__((unused)) word X,__attribute__((unused)) word Y,byte Couleur)
-
{
-
return Couleur;
-
}
-
-
// -- Effet de Shading --
-
-
byte Effet_Shade(word X,word Y,__attribute__((unused)) byte Couleur)
-
{
-
return Shade_Table[Lit_pixel_dans_ecran_feedback(X,Y)];
-
}
-
-
byte Effet_Quick_shade(word X,word Y,byte Couleur)
-
{
-
int C=Couleur=Lit_pixel_dans_ecran_feedback(X,Y);
-
int Sens=(Fore_color<=Back_color);
-
byte Debut,Fin;
-
int Largeur;
-
-
if (Sens)
-
{
-
Debut=Fore_color;
-
Fin =Back_color;
-
}
-
else
-
{
-
Debut=Back_color;
-
Fin =Fore_color;
-
}
-
-
if ((C>=Debut) && (C<=Fin) && (Debut!=Fin))
-
{
-
Largeur=1+Fin-Debut;
-
-
if ( ((Mouse_K==A_GAUCHE) && Sens) || ((Mouse_K==A_DROITE) && (!Sens)) )
-
C-=Quick_shade_Step%Largeur;
-
else
-
C+=Quick_shade_Step%Largeur;
-
-
if (CFin)
-
switch (Quick_shade_Loop)
-
{
-
case MODE_SHADE_NORMAL : return Fin;
-
case MODE_SHADE_BOUCLE : return (C-Largeur);
-
default : return Couleur;
-
}
-
}
-
-
return C;
-
}
-
-
// -- Effet de Tiling --
-
-
byte Effet_Tiling(word X,word Y,__attribute__((unused)) byte Couleur)
-
{
-
return Lit_pixel_dans_brosse((X+Brosse_Largeur-Tiling_Decalage_X)%Brosse_Largeur,
-
(Y+Brosse_Hauteur-Tiling_Decalage_Y)%Brosse_Hauteur);
-
}
-
-
// -- Effet de Smooth --
-
-
byte Effet_Smooth(word X,word Y,__attribute__((unused)) byte Couleur)
-
{
-
int R,V,B;
-
byte C;
-
int Poids,Poids_total;
-
byte X2=((X+1)