diff --git a/graph.c b/graph.c
index 2383cdba..b4d82458 100644
--- a/graph.c
+++ b/graph.c
@@ -1,2431 +1,4864 @@
-/* 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;
- }
+/* 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;
- 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) 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)