#include "sdlscreen.h" #include "graph.h" #include "divers.h" #include #include #include #include #include "moteur.h" #include "boutons.h" #include "pages.h" #include "global.h" #include "struct.h" #include "erreurs.h" #ifdef __linux__ #include #elif __WATCOMC__ #define _WIN32_WINNT 0x0500 #include #endif // 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; // Première étape, si L ou H est négatif, on doit remettre la zone à l'endroit if (Largeur < 0) { X += Largeur; Largeur = 3 - Largeur; } if (Hauteur < 0) { Y += Hauteur; Hauteur = 3 - Hauteur; } // D'abord on met à jour dans la zone écran normale X_effectif = Max(X-Principal_Decalage_X,0); Y_effectif = Max(Y-Principal_Decalage_Y,0); // 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 if(X_effectif + Largeur <= Principal_Largeur_image) L_effectif = Largeur; else L_effectif = Principal_Largeur_image - X_effectif; if(Y_effectif + Hauteur <= Menu_Ordonnee) H_effectif = Hauteur; else H_effectif = Menu_Ordonnee - Y_effectif; SDL_UpdateRect(Ecran_SDL,X_effectif,Y_effectif,L_effectif,H_effectif); // Et ensuite dans la partie zoomée if(Loupe_Mode) { X_effectif = Max(X-Loupe_Decalage_X,0) * Loupe_Facteur; Y_effectif = Max(Y-Loupe_Decalage_Y,0) * Loupe_Facteur; Largeur *= Loupe_Facteur; Hauteur *= Loupe_Facteur; // 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 if(X_effectif + Largeur <= Principal_Largeur_image) L_effectif = Largeur; else L_effectif = Principal_Largeur_image - X_effectif; if(Y_effectif + Hauteur <= Menu_Ordonnee) H_effectif = Hauteur; else H_effectif = Menu_Ordonnee - Y_effectif; SDL_UpdateRect(Ecran_SDL,X_effectif,Y_effectif,L_effectif,H_effectif); } } byte Meilleure_couleur(byte R,byte V,byte B) { short Coul; int Delta_R,Delta_V,Delta_B; int Dist; int Best_dist=0x7FFFFFFF; byte Best_color=0; for (Coul=0; Coul<256; Coul++) { if (!Exclude_color[Coul]) { Delta_R=(int)Principal_Palette[Coul].R-R; Delta_V=(int)Principal_Palette[Coul].V-V; Delta_B=(int)Principal_Palette[Coul].B-B; if (!(Dist=(Delta_R*Delta_R*30)+(Delta_V*Delta_V*59)+(Delta_B*Delta_B*11))) return Coul; if (Dist>3)*Menu_Taille_couleur)*Menu_Facteur_X; Debut_Y=Menu_Ordonnee_avant_fenetre+((2+((Couleur&7)<<2))*Menu_Facteur_Y); Fin_X=Debut_X+Largeur; Fin_Y=Debut_Y+Hauteur; // On affiche le bloc en entier si on peut, sinon on le découpe autour // de la fenêtre. if ( (Debut_Y>=Coin_Y) || (Fin_X<=Fenetre_Pos_X) || (Debut_X>=Coin_X) ) Block(Debut_X,Debut_Y,Largeur,Hauteur,Vraie_couleur); else { if (Debut_X>=Fenetre_Pos_X) { if ( (Fin_X>Coin_X) || (Fin_Y>Coin_Y) ) { if ( (Fin_X>Coin_X) && (Fin_Y>Coin_Y) ) { Block(Coin_X,Debut_Y,Fin_X-Coin_X,Coin_Y-Debut_Y,Vraie_couleur); Block(Debut_X,Coin_Y,Largeur,Fin_Y-Coin_Y,Vraie_couleur); } else { if (Fin_Y>Coin_Y) Block(Debut_X,Coin_Y,Largeur,Fin_Y-Coin_Y,Vraie_couleur); else Block(Coin_X,Debut_Y,Fin_X-Coin_X,Hauteur,Vraie_couleur); } } } else { if (Fin_XCoin_Y) { Block(Debut_X,Debut_Y,Fenetre_Pos_X-Debut_X,Coin_Y-Debut_Y,Vraie_couleur); Block(Debut_X,Coin_Y,Largeur,Fin_Y-Coin_Y,Vraie_couleur); } else Block(Debut_X,Debut_Y,Fenetre_Pos_X-Debut_X,Hauteur,Vraie_couleur); } else { if (Fin_Y>Coin_Y) { Block(Debut_X,Debut_Y,Fenetre_Pos_X-Debut_X,Coin_Y-Debut_Y,Vraie_couleur); Block(Coin_X,Debut_Y,Fin_X-Coin_X,Coin_Y-Debut_Y,Vraie_couleur); Block(Debut_X,Coin_Y,Largeur,Fin_Y-Coin_Y,Vraie_couleur); } else { Block(Debut_X,Debut_Y,Fenetre_Pos_X-Debut_X,Hauteur,Vraie_couleur); Block(Coin_X,Debut_Y,Fin_X-Coin_X,Hauteur,Vraie_couleur); } } } } } } SDL_UpdateRect(Ecran_SDL,(LARGEUR_MENU+1)*Menu_Facteur_X,Menu_Ordonnee_avant_fenetre,Largeur,Hauteur); } void Remapper_ecran_apres_changement_couleurs_menu(void) { short Indice; byte Table_de_conversion[256]; short Temp/*,Temp2*/; if ( (CM_Clair!=Old_Clair) || (CM_Fonce!=Old_Fonce) || (CM_Blanc!=Old_Blanc) || (CM_Noir !=Old_Noir ) || (CM_Trans!=Old_Trans) ) { // Création de la table de conversion for (Indice=0; Indice<256; Indice++) Table_de_conversion[Indice]=Indice; Table_de_conversion[Old_Noir ]=CM_Noir; Table_de_conversion[Old_Fonce]=CM_Fonce; Table_de_conversion[Old_Clair]=CM_Clair; Table_de_conversion[Old_Blanc]=CM_Blanc; // Remappage de l'écran Temp=Fenetre_Hauteur*Menu_Facteur_Y; Remap_screen(Fenetre_Pos_X, Fenetre_Pos_Y, Fenetre_Largeur*Menu_Facteur_X, (Fenetre_Pos_Y+Temp255)) 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]; } } } } // Transformer un nombre (entier naturel) en chaŒne void Num2str(dword Nombre,char * Chaine,byte Taille) { int Indice; for (Indice=Taille-1;Indice>=0;Indice--) { Chaine[Indice]=(Nombre%10)+'0'; Nombre/=10; if (Nombre==0) for (Indice--;Indice>=0;Indice--) Chaine[Indice]=' '; } Chaine[Taille]='\0'; } // Transformer une chaŒne en un entier naturel (renvoie -1 si ch. invalide) int Str2num(char * Chaine) { int Valeur=0; for (;*Chaine;Chaine++) { if ( (*Chaine>='0') && (*Chaine<='9') ) Valeur=(Valeur*10)+(*Chaine-'0'); else return -1; } return Valeur; } // Arrondir un nombre réel à la valeur entière la plus proche short Round(float Valeur) { short Temp=Valeur; if (Valeur>=0) { if ((Valeur-Temp)>= 0.5) Temp++; } else { if ((Valeur-Temp)<=-0.5) Temp--; } return Temp; } // Arrondir le résultat d'une division à la valeur entière supérieure short Round_div_max(short Numerateur,short Diviseur) { if (!(Numerateur % Diviseur)) return (Numerateur/Diviseur); else return (Numerateur/Diviseur)+1; } // Retourne le minimum entre deux nombres int Min(int A,int B) { return (AB)?A:B; } 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)); } // -- Recadrer la partie non-zoomée de l'image par rapport à la partie zoomée // lorsqu'on scrolle en mode Loupe -- void Recadrer_ecran_par_rapport_au_zoom(void) { // Centrage en X if (Principal_Largeur_image>Principal_Split) { Principal_Decalage_X=Loupe_Decalage_X+(Loupe_Largeur>>1) -(Principal_Split>>1); if (Principal_Decalage_X<0) Principal_Decalage_X=0; else if (Principal_Largeur_imageMenu_Ordonnee) { Principal_Decalage_Y=Loupe_Decalage_Y+(Loupe_Hauteur>>1) -(Menu_Ordonnee>>1); if (Principal_Decalage_Y<0) Principal_Decalage_Y=0; else if (Principal_Hauteur_image>1)-X_theorique)/Loupe_Facteur)*Loupe_Facteur); Principal_Split=Principal_X_Zoom-(Menu_Facteur_X*LARGEUR_BARRE_SPLIT); // Correction en cas de débordement sur la gauche while (Principal_Split*(Loupe_Facteur+1)=X_theorique) { Principal_Split-=Loupe_Facteur; Principal_X_Zoom-=Loupe_Facteur; } } // -------------------- Calcul des information de la loupe ------------------- void Calculer_donnees_loupe(void) /* Après modification des données de la loupe, il faut recalculer les limites. */ { Calculer_split(); Loupe_Largeur=(Largeur_ecran-Principal_X_Zoom)/Loupe_Facteur; Loupe_Hauteur=Menu_Ordonnee/Loupe_Facteur; if (Menu_Ordonnee%Loupe_Facteur) Loupe_Hauteur++; if (Loupe_Mode && Loupe_Decalage_X) { if (Principal_Largeur_image=Principal_Hauteur_image) Limite_Bas=Principal_Hauteur_image-1; else Limite_Bas=Limite_visible_Bas; if (Limite_visible_Droite>=Principal_Largeur_image) Limite_Droite=Principal_Largeur_image-1; else Limite_Droite=Limite_visible_Droite; // -- Calcul des limites de la partie zoomée de l'image -- Limite_Haut_Zoom =Loupe_Decalage_Y; Limite_Gauche_Zoom=Loupe_Decalage_X; Limite_visible_Bas_Zoom =Limite_Haut_Zoom+Loupe_Hauteur-1; Limite_visible_Droite_Zoom=Limite_Gauche_Zoom+Loupe_Largeur-1; if (Limite_visible_Bas_Zoom>=Principal_Hauteur_image) Limite_Bas_Zoom=Principal_Hauteur_image-1; else Limite_Bas_Zoom=Limite_visible_Bas_Zoom; if (Limite_visible_Droite_Zoom>=Principal_Largeur_image) Limite_Droite_Zoom=Principal_Largeur_image-1; else Limite_Droite_Zoom=Limite_visible_Droite_Zoom; } else { // -- Calcul des limites de la partie visible de l'image -- Limite_Haut =Principal_Decalage_Y; Limite_Gauche=Principal_Decalage_X; Limite_visible_Bas =Limite_Haut+(Menu_visible?Menu_Ordonnee:Hauteur_ecran)-1; // A REVOIR POUR SIMPLIFICATION Limite_visible_Droite=Limite_Gauche+Largeur_ecran-1; if (Limite_visible_Bas>=Principal_Hauteur_image) Limite_Bas=Principal_Hauteur_image-1; else Limite_Bas=Limite_visible_Bas; if (Limite_visible_Droite>=Principal_Largeur_image) Limite_Droite=Principal_Largeur_image-1; else Limite_Droite=Limite_visible_Droite; } } // -- Calculer les coordonnées du pinceau en fonction du snap et de la loupe - void Calculer_coordonnees_pinceau(void) { if ((Loupe_Mode) && (Mouse_X>=Principal_X_Zoom)) { Pinceau_X=((Mouse_X-Principal_X_Zoom)/Loupe_Facteur)+Loupe_Decalage_X; Pinceau_Y=(Mouse_Y/Loupe_Facteur)+Loupe_Decalage_Y; } else { Pinceau_X=Mouse_X+Principal_Decalage_X; Pinceau_Y=Mouse_Y+Principal_Decalage_Y; } if (Snap_Mode) { Pinceau_X=(((Pinceau_X+(Snap_Largeur>>1)-Snap_Decalage_X)/Snap_Largeur)*Snap_Largeur)+Snap_Decalage_X; Pinceau_Y=(((Pinceau_Y+(Snap_Hauteur>>1)-Snap_Decalage_Y)/Snap_Hauteur)*Snap_Hauteur)+Snap_Decalage_Y; } } // ------------ Changer le facteur de zoom et tout mettre à jour ------------- void Changer_facteur_loupe(byte Indice_facteur) { short Centre_X; short Centre_Y; Centre_X=Loupe_Decalage_X+(Loupe_Largeur>>1); Centre_Y=Loupe_Decalage_Y+(Loupe_Hauteur>>1); Loupe_Facteur=FACTEUR_ZOOM[Indice_facteur]; Table_mul_facteur_zoom=TABLE_ZOOM[Indice_facteur]; Calculer_donnees_loupe(); if (Loupe_Mode) { // Recalculer le décalage de la loupe // Centrage "brut" de lécran par rapport à la loupe Loupe_Decalage_X=Centre_X-(Loupe_Largeur>>1); Loupe_Decalage_Y=Centre_Y-(Loupe_Hauteur>>1); // Correction en cas de débordement de l'image if (Loupe_Decalage_X+Loupe_Largeur>Principal_Largeur_image) Loupe_Decalage_X=Principal_Largeur_image-Loupe_Largeur; if (Loupe_Decalage_Y+Loupe_Hauteur>Principal_Hauteur_image) Loupe_Decalage_Y=Principal_Hauteur_image-Loupe_Hauteur; if (Loupe_Decalage_X<0) Loupe_Decalage_X=0; if (Loupe_Decalage_Y<0) Loupe_Decalage_Y=0; Recadrer_ecran_par_rapport_au_zoom(); Pixel_Preview=Pixel_Preview_Loupe; } else Pixel_Preview=Pixel_Preview_Normal; Calculer_limites(); Calculer_coordonnees_pinceau(); } // -- Affichage de la limite de l'image ------------------------------------- void Afficher_limites_de_l_image(void) { short Debut; short Pos; short Fin; byte Droite_visible; byte Bas_visible; short Ancienne_Limite_Zoom; Droite_visible=Principal_Largeur_image<((Loupe_Mode)?Principal_Split:Largeur_ecran); Bas_visible =Principal_Hauteur_imageMode_video[Numero].Facteur_Y) && (Menu_Facteur_X==Menu_Facteur_Y) ) Menu_Facteur_X++; break; default: // ne pas adapter Menu_Facteur_X=1; Menu_Facteur_Y=1; } if (Buffer_de_ligne_horizontale) free(Buffer_de_ligne_horizontale); Buffer_de_ligne_horizontale=(byte *)malloc((Largeur_ecran>Principal_Largeur_image)?Largeur_ecran:Principal_Largeur_image); switch (Mode_video[Numero].Mode) { case MODE_SDL: Pixel = Pixel_SDL; Lit_pixel= Lit_Pixel_SDL; Clear_screen = Effacer_Tout_l_Ecran_SDL; Display_screen = Afficher_partie_de_l_ecran_SDL; Block = Block_SDL; Block_Fast = Block_SDL_Fast; Pixel_Preview_Normal = Pixel_Preview_Normal_SDL; Pixel_Preview_Loupe = Pixel_Preview_Loupe_SDL; Ligne_horizontale_XOR = Ligne_horizontale_XOR_SDL; Ligne_verticale_XOR = Ligne_verticale_XOR_SDL; Display_brush_Color = Display_brush_Color_SDL; Display_brush_Mono = Display_brush_Mono_SDL; Clear_brush = Clear_brush_SDL; Remap_screen = Remap_screen_SDL; Afficher_ligne = Afficher_une_ligne_ecran_SDL; Lire_ligne = Lire_une_ligne_ecran_SDL; Display_zoomed_screen = Afficher_partie_de_l_ecran_zoomee_SDL; Display_brush_Color_zoom = Display_brush_Color_zoom_SDL; Display_brush_Mono_zoom = Display_brush_Mono_zoom_SDL; Clear_brush_zoom = Clear_brush_zoom_SDL; Set_Mode_SDL(); break; } Set_palette(Principal_Palette); Resolution_actuelle = Numero; Menu_Taille_couleur = ((Largeur_ecran/Menu_Facteur_X)-(LARGEUR_MENU+2)) >> 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; Clip_mouse(); Mouse_X = Largeur_ecran >> 1; Mouse_Y = Hauteur_ecran >> 1; Set_mouse_position(); Sensibilite_X = Config.Indice_Sensibilite_souris_X / Mode_video[Numero].Facteur_X; Sensibilite_Y = Config.Indice_Sensibilite_souris_Y / Mode_video[Numero].Facteur_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. } Pixel_Preview=Pixel_Preview_Normal; Principal_Decalage_X=0; // Il faut quand même modifier ces valeurs à chaque Principal_Decalage_Y=0; // fois car on n'est pas à l'abri d'une modification // des dimensions de l'image. Calculer_donnees_loupe(); Calculer_limites(); Calculer_coordonnees_pinceau(); } // -- 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[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); } } // -- Interface avec le menu et les fenêtres --------------------------------- // Affichage d'un pixel dans le menu (le menu doŒt être visible) void Pixel_dans_barre_d_outil(word X,word Y,byte Couleur) { Block_Fast(X*Menu_Facteur_X,(Y*Menu_Facteur_Y)+Menu_Ordonnee,Menu_Facteur_X,Menu_Facteur_Y,Couleur); } // Affichage d'un pixel dans la fenêtre (la fenêtre doŒt être visible) void Pixel_dans_fenetre(word X,word Y,byte Couleur) { Block_Fast((X*Menu_Facteur_X)+Fenetre_Pos_X,(Y*Menu_Facteur_Y)+Fenetre_Pos_Y,Menu_Facteur_X,Menu_Facteur_Y,Couleur); } // -- Affichages de différents cƒdres dans une fenêtre ----------------------- // -- Cadre général avec couleurs paramètrables -- void Fenetre_Afficher_cadre_general(word Pos_X,word Pos_Y,word Largeur,word Hauteur, byte Couleur_HG,byte Couleur_BD,byte Couleur_S,byte Couleur_CHG,byte Couleur_CBD) // Paramètres de couleurs: // Couleur_HG =Bords Haut et Gauche // Couleur_BD =Bords Bas et Droite // Couleur_S =Coins Haut-Droite et Bas-Gauche // Couleur_CHG=Coin Haut-Gauche // Couleur_CBD=Coin Bas-Droite { // Bord haut (sans les extrémités) Block(Fenetre_Pos_X+((Pos_X+1)*Menu_Facteur_X), Fenetre_Pos_Y+(Pos_Y*Menu_Facteur_Y), (Largeur-2)*Menu_Facteur_X,Menu_Facteur_Y,Couleur_HG); // Bord bas (sans les extrémités) Block(Fenetre_Pos_X+((Pos_X+1)*Menu_Facteur_X), Fenetre_Pos_Y+((Pos_Y+Hauteur-1)*Menu_Facteur_Y), (Largeur-2)*Menu_Facteur_X,Menu_Facteur_Y,Couleur_BD); // Bord gauche (sans les extrémités) Block(Fenetre_Pos_X+(Pos_X*Menu_Facteur_X), Fenetre_Pos_Y+((Pos_Y+1)*Menu_Facteur_Y), Menu_Facteur_X,(Hauteur-2)*Menu_Facteur_Y,Couleur_HG); // Bord droite (sans les extrémités) Block(Fenetre_Pos_X+((Pos_X+Largeur-1)*Menu_Facteur_X), Fenetre_Pos_Y+((Pos_Y+1)*Menu_Facteur_Y), Menu_Facteur_X,(Hauteur-2)*Menu_Facteur_Y,Couleur_BD); // Coin haut gauche Pixel_dans_fenetre(Pos_X,Pos_Y,Couleur_CHG); // Coin haut droite Pixel_dans_fenetre(Pos_X+Largeur-1,Pos_Y,Couleur_S); // Coin bas droite Pixel_dans_fenetre(Pos_X+Largeur-1,Pos_Y+Hauteur-1,Couleur_CBD); // Coin bas gauche Pixel_dans_fenetre(Pos_X,Pos_Y+Hauteur-1,Couleur_S); } // -- Cadre dont tout le contour est d'une seule couleur -- void Fenetre_Afficher_cadre_mono(word Pos_X,word Pos_Y,word Largeur,word Hauteur,byte Couleur) { Fenetre_Afficher_cadre_general(Pos_X,Pos_Y,Largeur,Hauteur,Couleur,Couleur,Couleur,Couleur,Couleur); } // -- Cadre creux: foncé en haut-gauche et clair en bas-droite -- void Fenetre_Afficher_cadre_creux(word Pos_X,word Pos_Y,word Largeur,word Hauteur) { Fenetre_Afficher_cadre_general(Pos_X,Pos_Y,Largeur,Hauteur,CM_Fonce,CM_Blanc,CM_Clair,CM_Fonce,CM_Blanc); } // -- Cadre bombé: clair en haut-gauche et foncé en bas-droite -- void Fenetre_Afficher_cadre_bombe(word Pos_X,word Pos_Y,word Largeur,word Hauteur) { Fenetre_Afficher_cadre_general(Pos_X,Pos_Y,Largeur,Hauteur,CM_Blanc,CM_Fonce,CM_Clair,CM_Blanc,CM_Fonce); } // -- Cadre de séparation: un cadre bombé dans un cadre creux (3D!!!) -- void Fenetre_Afficher_cadre(word Pos_X,word Pos_Y,word Largeur,word Hauteur) { Fenetre_Afficher_cadre_creux(Pos_X,Pos_Y,Largeur,Hauteur); Fenetre_Afficher_cadre_bombe(Pos_X+1,Pos_Y+1,Largeur-2,Hauteur-2); } //-- Affichages relatifs à la palette dans le menu --------------------------- // -- Affichage des couleurs courante (fore/back) de pinceau dans le menu -- void Afficher_foreback(void) { if (Menu_visible) { Block((LARGEUR_MENU-17)*Menu_Facteur_X,Menu_Ordonnee+Menu_Facteur_Y,Menu_Facteur_X<<4,Menu_Facteur_Y*7,Back_color); Block((LARGEUR_MENU-13)*Menu_Facteur_X,Menu_Ordonnee+(Menu_Facteur_Y<<1),Menu_Facteur_X<<3,Menu_Facteur_Y*5,Fore_color); } } // -- Tracer un cadre de couleur autour de la Fore_color dans le menu -- void Encadrer_couleur_menu(byte Couleur) { word Debut_X,Debut_Y,Fin_X,Fin_Y; word Indice; if ((Fore_color>=Couleur_debut_palette) && (Fore_color>3)*Menu_Taille_couleur)*Menu_Facteur_X; Debut_Y=Menu_Ordonnee+((1+(((Fore_color-Couleur_debut_palette)&7)<<2))*Menu_Facteur_Y); Block(Debut_X,Debut_Y,(Menu_Taille_couleur+1)*Menu_Facteur_X,Menu_Facteur_Y,Couleur); Block(Debut_X,Debut_Y+(Menu_Facteur_Y<<2),(Menu_Taille_couleur+1)*Menu_Facteur_X,Menu_Facteur_Y,Couleur); Block(Debut_X,Debut_Y+Menu_Facteur_Y,Menu_Facteur_X,Menu_Facteur_Y*3,Couleur); Block(Debut_X+(Menu_Taille_couleur*Menu_Facteur_X),Debut_Y+Menu_Facteur_Y,Menu_Facteur_X,Menu_Facteur_Y*3,Couleur); } else { if (Couleur==CM_Noir) { Debut_X=(LARGEUR_MENU+1+((Fore_color-Couleur_debut_palette)>>3)*Menu_Taille_couleur)*Menu_Facteur_X; Debut_Y=Menu_Ordonnee+((2+(((Fore_color-Couleur_debut_palette)&7)<<2))*Menu_Facteur_Y); Block(Debut_X,Debut_Y,Menu_Taille_couleur*Menu_Facteur_X, Menu_Facteur_Y<<2,Fore_color); } else { Debut_X=LARGEUR_MENU+1+((Fore_color-Couleur_debut_palette)>>3)*Menu_Taille_couleur; Debut_Y=2+(((Fore_color-Couleur_debut_palette)&7)<<2); Fin_X=Debut_X+Menu_Taille_couleur-1; Fin_Y=Debut_Y+3; for (Indice=Debut_X; Indice<=Fin_X; Indice++) Block(Indice*Menu_Facteur_X,Menu_Ordonnee+(Debut_Y*Menu_Facteur_Y), Menu_Facteur_X,Menu_Facteur_Y, ((Indice+Debut_Y)&1)?CM_Blanc:CM_Noir); for (Indice=Debut_Y+1; Indice>3)*Menu_Taille_couleur)*Menu_Facteur_X, Menu_Ordonnee+((2+((Couleur&7)<<2))*Menu_Facteur_Y), (Menu_Taille_couleur-1)*Menu_Facteur_X, Menu_Facteur_Y*3, Couleur_debut_palette+Couleur); else for (Couleur=0;Couleur<64;Couleur++) Block((LARGEUR_MENU+1+(Couleur>>3)*Menu_Taille_couleur)*Menu_Facteur_X, Menu_Ordonnee+((2+((Couleur&7)<<2))*Menu_Facteur_Y), Menu_Taille_couleur*Menu_Facteur_X, Menu_Facteur_Y<<2, Couleur_debut_palette+Couleur); Encadrer_couleur_menu(CM_Blanc); } } // -- Recalculer l'origine de la palette dans le menu pour rendre la // Fore_color visible -- void Recadrer_palette(void) { byte Ancienne_couleur=Couleur_debut_palette; if (Fore_color=Couleur_debut_palette+64) Couleur_debut_palette+=8; } if (Ancienne_couleur!=Couleur_debut_palette) Afficher_palette_du_menu(); } // -- Afficher la barre de séparation entre les parties zoomées ou non en // mode Loupe -- void Afficher_barre_de_split(void) { // Partie grise du milieu Block(Principal_Split+(Menu_Facteur_X<<1),Menu_Facteur_Y, (LARGEUR_BARRE_SPLIT-4)*Menu_Facteur_X, Menu_Ordonnee-(Menu_Facteur_Y<<1),CM_Clair); // Barre noire de gauche Block(Principal_Split,0,Menu_Facteur_X,Menu_Ordonnee,CM_Noir); // Barre noire de droite Block(Principal_X_Zoom-Menu_Facteur_X,0,Menu_Facteur_X,Menu_Ordonnee,CM_Noir); // Bord haut (blanc) Block(Principal_Split+Menu_Facteur_X,0, (LARGEUR_BARRE_SPLIT-3)*Menu_Facteur_X,Menu_Facteur_Y,CM_Blanc); // Bord gauche (blanc) Block(Principal_Split+Menu_Facteur_X,Menu_Facteur_Y, Menu_Facteur_X,(Menu_Ordonnee-(Menu_Facteur_Y<<1)),CM_Blanc); // Bord droite (gris foncé) Block(Principal_X_Zoom-(Menu_Facteur_X<<1),Menu_Facteur_Y, Menu_Facteur_X,(Menu_Ordonnee-(Menu_Facteur_Y<<1)),CM_Fonce); // Bord bas (gris foncé) Block(Principal_Split+(Menu_Facteur_X<<1),Menu_Ordonnee-Menu_Facteur_Y, (LARGEUR_BARRE_SPLIT-3)*Menu_Facteur_X,Menu_Facteur_Y,CM_Fonce); // Coin bas gauche Block(Principal_Split+Menu_Facteur_X,Menu_Ordonnee-Menu_Facteur_Y, Menu_Facteur_X,Menu_Facteur_Y,CM_Clair); // Coin haut droite Block(Principal_X_Zoom-(Menu_Facteur_X<<1),0, Menu_Facteur_X,Menu_Facteur_Y,CM_Clair); } // -- Afficher tout le menu -- void Afficher_menu(void) { word Pos_X; word Pos_Y; char Chaine[4]; if (Menu_visible) { // Affichage du sprite du menu for (Pos_Y=0;Pos_Y=Principal_X_Zoom) )) { if ( (Operation_en_cours!=OPERATION_PIPETTE) && (Operation_en_cours!=OPERATION_REMPLACER) ) Print_dans_menu("X: Y: ",0); else { Print_dans_menu("X: Y: ( )",0); Num2str(Pipette_Couleur,Chaine,3); Print_dans_menu(Chaine,20); Print_general(170*Menu_Facteur_X,Menu_Ordonnee_Texte," ",0,Pipette_Couleur); } Print_coordonnees(); } Print_nom_fichier(); } SDL_UpdateRect(Ecran_SDL,0,Menu_Ordonnee,LARGEUR_MENU*Menu_Facteur_X,HAUTEUR_MENU*Menu_Facteur_Y); } } // -- Affichage de texte ----------------------------------------------------- // -- Afficher une chaŒne n'importe o— à l'écran -- void Print_general(short X,short Y,char * Chaine,byte Couleur_texte,byte Couleur_fond) { word Indice; short Pos_X; short Pos_Y; char Caractere; short Reel_X; short Reel_Y; short Largeur; short Repeat_Menu_Facteur_X; short Repeat_Menu_Facteur_Y; Reel_Y=Y; Largeur=strlen(Chaine)*Menu_Facteur_X*8; for (Pos_Y=0;Pos_Y<8;Pos_Y++) { Reel_X=0; // Position dans le buffer for (Indice=0;Chaine[Indice]!='\0';Indice++) { Caractere=Chaine[Indice]; for (Pos_X=0;Pos_X<8;Pos_X++) for (Repeat_Menu_Facteur_X=0;Repeat_Menu_Facteur_X=0) && (Pinceau_Y>=0) && (Pinceau_X=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,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,byte Couleur) { int R,V,B; byte C; int Poids,Poids_total; byte X2=((X+1)(Limite_Droite+1)) { (*Largeur)=(Limite_Droite-(*X))+1; } if ((*Y)(Limite_Bas+1)) { (*Hauteur)=(Limite_Bas-(*Y))+1; } } // -- Calcul de redimensionnement du pinceau pour éviter les débordements // de l'écran zoomé et de l'image -- void Calculer_dimensions_clipees_zoom(short * X,short * Y,short * Largeur,short * Hauteur) { if ((*X)(Limite_Droite_Zoom+1)) { (*Largeur)=(Limite_Droite_Zoom-(*X))+1; } if ((*Y)(Limite_Bas_Zoom+1)) { (*Hauteur)=(Limite_Bas_Zoom-(*Y))+1; } } // -- Afficher le pinceau (de façon définitive ou non) -- void Afficher_pinceau(short X,short Y,byte Couleur,byte Preview) // X,Y: position du centre du pinceau // Couleur: couleur à appliquer au pinceau // Preview: "Il ne faut l'afficher qu'à l'écran" { short Debut_X; // Position X (dans l'image) à partir de laquelle on // affiche la brosse/pinceau short Debut_Y; // Position Y (dans l'image) à partir de laquelle on // affiche la brosse/pinceau short Largeur; // Largeur dans l'écran selon laquelle on affiche la // brosse/pinceau short Hauteur; // Hauteur dans l'écran selon laquelle on affiche la // brosse/pinceau short Debut_Compteur_X; // Position X (dans la brosse/pinceau) à partir // de laquelle on affiche la brosse/pinceau short Debut_Compteur_Y; // Position Y (dans la brosse/pinceau) à partir // de laquelle on affiche la brosse/pinceau short Pos_X; // Position X (dans l'image) en cours d'affichage short Pos_Y; // Position Y (dans l'image) en cours d'affichage short Compteur_X; // Position X (dans la brosse/pinceau) en cours // d'affichage short Compteur_Y; // Position Y (dans la brosse/pinceau) en cours // d'affichage short Fin_Compteur_X; // Position X ou s'arrête l'affichade de la // brosse/pinceau short Fin_Compteur_Y; // Position Y ou s'arrête l'affichade de la // brosse/pinceau byte Couleur_temporaire; // Couleur de la brosse en cours d'affichage int Position; byte * Temp; #define UpdateZoom(X,Y,w,h) if((Y)>= Limite_Haut_Zoom && (Y) <= Limite_visible_Bas_Zoom && (X)>= Limite_Gauche_Zoom && (X) <= Limite_visible_Droite_Zoom) SDL_UpdateRect(Ecran_SDL,Table_mul_facteur_zoom[(X)-Loupe_Decalage_X]+Principal_X_Zoom,((Y)-Loupe_Decalage_Y)*Loupe_Facteur,(w)*Loupe_Facteur,(h)*Loupe_Facteur) if (!(Preview && Mouse_K)) // Si bouton enfoncé & preview > pas de dessin switch (Pinceau_Forme) { case FORME_PINCEAU_POINT : // !!! TOUJOURS EN PREVIEW !!! if ( (Pinceau_X>=Limite_Gauche) && (Pinceau_X<=Limite_Droite) && (Pinceau_Y>=Limite_Haut) && (Pinceau_Y<=Limite_Bas) ) { Pixel_Preview(Pinceau_X,Pinceau_Y,Couleur); SDL_UpdateRect(Ecran_SDL, Max(Pinceau_X - Principal_Decalage_X,0), Max(Pinceau_Y - Principal_Decalage_Y,0), 1,1 ); // Attention au zoom ! if(Loupe_Mode) UpdateZoom(X,Y,1,1); } break; case FORME_PINCEAU_BROSSE_COULEUR : // Brosse en couleur Debut_X=X-Brosse_Decalage_X; Debut_Y=Y-Brosse_Decalage_Y; Largeur=Brosse_Largeur; Hauteur=Brosse_Hauteur; Calculer_dimensions_clipees(&Debut_X,&Debut_Y,&Largeur,&Hauteur); Debut_Compteur_X=Debut_X-(X-Brosse_Decalage_X); Debut_Compteur_Y=Debut_Y-(Y-Brosse_Decalage_Y); Fin_Compteur_X=Debut_Compteur_X+Largeur; Fin_Compteur_Y=Debut_Compteur_Y+Hauteur; if (Preview) { if ( (Largeur>0) && (Hauteur>0) ) Display_brush_Color( Debut_X-Principal_Decalage_X, Debut_Y-Principal_Decalage_Y, Debut_Compteur_X, Debut_Compteur_Y, Largeur, Hauteur, Back_color, Brosse_Largeur ); if (Loupe_Mode) { Calculer_dimensions_clipees_zoom(&Debut_X,&Debut_Y,&Largeur, &Hauteur ); Debut_Compteur_X=Debut_X-(X-Brosse_Decalage_X); Debut_Compteur_Y=Debut_Y-(Y-Brosse_Decalage_Y); if ( (Largeur>0) && (Hauteur>0) ) { // Corrections dues au Zoom: Debut_X=(Debut_X-Loupe_Decalage_X)*Loupe_Facteur; Debut_Y=(Debut_Y-Loupe_Decalage_Y)*Loupe_Facteur; Hauteur=Debut_Y+(Hauteur*Loupe_Facteur); if (Hauteur>Menu_Ordonnee) Hauteur=Menu_Ordonnee; Display_brush_Color_zoom(Principal_X_Zoom+Debut_X,Debut_Y, Debut_Compteur_X,Debut_Compteur_Y, Largeur,Hauteur,Back_color, Brosse_Largeur, Buffer_de_ligne_horizontale); } } } else { if ((Smear_Mode) && (Shade_Table==Shade_Table_gauche)) { if (Smear_Debut) { if ((Largeur>0) && (Hauteur>0)) { Copier_une_partie_d_image_dans_une_autre( Principal_Ecran, Debut_X, Debut_Y, Largeur, Hauteur, Principal_Largeur_image, Smear_Brosse, Debut_Compteur_X, Debut_Compteur_Y, Smear_Brosse_Largeur ); // UPDATERECT } Smear_Debut=0; } else { for (Pos_Y = Debut_Y, Compteur_Y = Debut_Compteur_Y; Compteur_Y < Fin_Compteur_Y; Pos_Y++, Compteur_Y++ ) for (Pos_X = Debut_X, Compteur_X = Debut_Compteur_X; Compteur_X < Fin_Compteur_X; Pos_X++, Compteur_X++ ) { Couleur_temporaire = Lit_pixel_dans_ecran_courant( Pos_X,Pos_Y ); Position = (Compteur_Y * Smear_Brosse_Largeur)+ Compteur_X; if ( (Lit_pixel_dans_brosse(Compteur_X,Compteur_Y) != Back_color) && (Compteur_Y=Smear_Min_Y) && (Compteur_X>=Smear_Min_X) ) Afficher_pixel(Pos_X,Pos_Y,Smear_Brosse[Position]); Smear_Brosse[Position]=Couleur_temporaire; } SDL_UpdateRect(Ecran_SDL,Max(Debut_X,0),Max(Debut_Y,0), Fin_Compteur_X,Fin_Compteur_Y ); } Smear_Min_X=Debut_Compteur_X; Smear_Min_Y=Debut_Compteur_Y; Smear_Max_X=Fin_Compteur_X; Smear_Max_Y=Fin_Compteur_Y; } else { if (Shade_Table==Shade_Table_gauche) for (Pos_Y=Debut_Y,Compteur_Y=Debut_Compteur_Y;Compteur_Y0) && (Hauteur>0) ) Display_brush_Mono(Debut_X-Principal_Decalage_X, Debut_Y-Principal_Decalage_Y, Debut_Compteur_X,Debut_Compteur_Y, Largeur,Hauteur, Back_color,Fore_color, Brosse_Largeur); if (Loupe_Mode) { Calculer_dimensions_clipees_zoom(&Debut_X,&Debut_Y,&Largeur,&Hauteur); Debut_Compteur_X=Debut_X-(X-Brosse_Decalage_X); Debut_Compteur_Y=Debut_Y-(Y-Brosse_Decalage_Y); if ( (Largeur>0) && (Hauteur>0) ) { // Corrections dues au Zoom: Debut_X=(Debut_X-Loupe_Decalage_X)*Loupe_Facteur; Debut_Y=(Debut_Y-Loupe_Decalage_Y)*Loupe_Facteur; Hauteur=Debut_Y+(Hauteur*Loupe_Facteur); if (Hauteur>Menu_Ordonnee) Hauteur=Menu_Ordonnee; Display_brush_Mono_zoom(Principal_X_Zoom+Debut_X,Debut_Y, Debut_Compteur_X,Debut_Compteur_Y, Largeur,Hauteur, Back_color,Fore_color, Brosse_Largeur, Buffer_de_ligne_horizontale); } } } else { if ((Smear_Mode) && (Shade_Table==Shade_Table_gauche)) { if (Smear_Debut) { if ((Largeur>0) && (Hauteur>0)) Copier_une_partie_d_image_dans_une_autre(Principal_Ecran, Debut_X,Debut_Y, Largeur,Hauteur, Principal_Largeur_image, Smear_Brosse, Debut_Compteur_X, Debut_Compteur_Y, Smear_Brosse_Largeur); //UPDATERECT Smear_Debut=0; } else { for (Pos_Y=Debut_Y,Compteur_Y=Debut_Compteur_Y;Compteur_Y=Smear_Min_Y) && (Compteur_X>=Smear_Min_X) ) Afficher_pixel(Pos_X,Pos_Y,Smear_Brosse[Position]); Smear_Brosse[Position]=Couleur_temporaire; } SDL_UpdateRect(Ecran_SDL,Max(Debut_X,0),Max(Debut_Y,0), Fin_Compteur_X,Fin_Compteur_Y ); } Smear_Min_X=Debut_Compteur_X; Smear_Min_Y=Debut_Compteur_Y; Smear_Max_X=Fin_Compteur_X; Smear_Max_Y=Fin_Compteur_Y; } else { for (Pos_Y=Debut_Y,Compteur_Y=Debut_Compteur_Y;Compteur_Y0) && (Hauteur>0) ) Display_brush_Mono(Debut_X-Principal_Decalage_X, Debut_Y-Principal_Decalage_Y, Debut_Compteur_X,Debut_Compteur_Y, Largeur,Hauteur, 0,Fore_color, TAILLE_MAXI_PINCEAU); if (Loupe_Mode) { Calculer_dimensions_clipees_zoom(&Debut_X,&Debut_Y,&Largeur,&Hauteur); Debut_Compteur_X=Debut_X-(X-Pinceau_Decalage_X); Debut_Compteur_Y=Debut_Y-(Y-Pinceau_Decalage_Y); if ( (Largeur>0) && (Hauteur>0) ) { // Corrections dues au Zoom: Debut_X=(Debut_X-Loupe_Decalage_X)*Loupe_Facteur; Debut_Y=(Debut_Y-Loupe_Decalage_Y)*Loupe_Facteur; Hauteur=Debut_Y+(Hauteur*Loupe_Facteur); if (Hauteur>Menu_Ordonnee) Hauteur=Menu_Ordonnee; Display_brush_Mono_zoom(Principal_X_Zoom+Debut_X,Debut_Y, Debut_Compteur_X,Debut_Compteur_Y, Largeur,Hauteur, 0,Fore_color, TAILLE_MAXI_PINCEAU, Buffer_de_ligne_horizontale); } } Brosse=Temp; } else { if ((Smear_Mode) && (Shade_Table==Shade_Table_gauche)) { if (Smear_Debut) { if ((Largeur>0) && (Hauteur>0)) Copier_une_partie_d_image_dans_une_autre(Principal_Ecran, Debut_X,Debut_Y, Largeur,Hauteur, Principal_Largeur_image, Smear_Brosse, Debut_Compteur_X, Debut_Compteur_Y, Smear_Brosse_Largeur); // UPDATERECT Smear_Debut=0; } else { for (Pos_Y=Debut_Y,Compteur_Y=Debut_Compteur_Y;Compteur_Y=Smear_Min_Y) && (Compteur_X>=Smear_Min_X) ) Afficher_pixel(Pos_X,Pos_Y,Smear_Brosse[Position]); Smear_Brosse[Position]=Couleur_temporaire; } } SDL_UpdateRect(Ecran_SDL,Debut_X,Debut_Y, Fin_Compteur_X,Fin_Compteur_Y ); Smear_Min_X=Debut_Compteur_X; Smear_Min_Y=Debut_Compteur_Y; Smear_Max_X=Fin_Compteur_X; Smear_Max_Y=Fin_Compteur_Y; } else { for (Pos_Y=Debut_Y,Compteur_Y=Debut_Compteur_Y;Compteur_Y 0 && Fin_Compteur_Y - Debut_Compteur_Y > 0) { SDL_UpdateRect(Ecran_SDL, Max(Debut_X-Principal_Decalage_X,1), Max(Debut_Y-Principal_Decalage_Y,1), Fin_Compteur_X-Debut_Compteur_X, Fin_Compteur_Y-Debut_Compteur_Y ); if(Loupe_Mode) UpdateZoom(Debut_X,Debut_Y, Fin_Compteur_X-Debut_Compteur_X, Fin_Compteur_Y-Debut_Compteur_Y); } } } } } // -- Effacer le pinceau -- // // void Effacer_pinceau(short X,short Y) // X,Y: position du centre du pinceau { short Debut_X; // Position X (dans l'image) à partir de laquelle on // affiche la brosse/pinceau short Debut_Y; // Position Y (dans l'image) à partir de laquelle on // affiche la brosse/pinceau short Largeur; // Largeur dans l'écran selon laquelle on affiche la // brosse/pinceau short Hauteur; // Hauteur dans l'écran selon laquelle on affiche la // brosse/pinceau short Debut_Compteur_X; // Position X (dans la brosse/pinceau) à partir // de laquelle on affiche la brosse/pinceau short Debut_Compteur_Y; // Position Y (dans la brosse/pinceau) à partir // de laquelle on affiche la brosse/pinceau //short Pos_X; // Position X (dans l'image) en cours d'affichage //short Pos_Y; // Position Y (dans l'image) en cours d'affichage //short Compteur_X; // Position X (dans la brosse/pinceau) en cours //d'affichage //short Compteur_Y; // Position Y (dans la brosse/pinceau) en cours d'affichage short Fin_Compteur_X; // Position X ou s'arrête l'affichade de la brosse/pinceau short Fin_Compteur_Y; // Position Y ou s'arrête l'affichade de la brosse/pinceau byte * Temp; if (!Mouse_K) switch (Pinceau_Forme) { case FORME_PINCEAU_POINT : if ( (Pinceau_X>=Limite_Gauche) && (Pinceau_X<=Limite_Droite) && (Pinceau_Y>=Limite_Haut) && (Pinceau_Y<=Limite_Bas) ) { Pixel_Preview(Pinceau_X,Pinceau_Y,Lit_pixel_dans_ecran_courant(Pinceau_X,Pinceau_Y)); SDL_UpdateRect(Ecran_SDL,Max(Pinceau_X-Principal_Decalage_X,0),Max(Pinceau_Y-Principal_Decalage_Y,0),1,1); if(Loupe_Mode) UpdateZoom(Pinceau_X,Pinceau_Y,1,1); } break; case FORME_PINCEAU_BROSSE_COULEUR : // Brosse en couleur case FORME_PINCEAU_BROSSE_MONOCHROME : // Brosse monochrome Debut_X=X-Brosse_Decalage_X; Debut_Y=Y-Brosse_Decalage_Y; Largeur=Brosse_Largeur; Hauteur=Brosse_Hauteur; Calculer_dimensions_clipees(&Debut_X,&Debut_Y,&Largeur,&Hauteur); Debut_Compteur_X=Debut_X-(X-Brosse_Decalage_X); Debut_Compteur_Y=Debut_Y-(Y-Brosse_Decalage_Y); Fin_Compteur_X=Debut_Compteur_X+Largeur; Fin_Compteur_Y=Debut_Compteur_Y+Hauteur; if ( (Largeur>0) && (Hauteur>0) ) Clear_brush(Debut_X-Principal_Decalage_X, Debut_Y-Principal_Decalage_Y, Debut_Compteur_X,Debut_Compteur_Y, Largeur,Hauteur,Back_color, Principal_Largeur_image); if (Loupe_Mode) { Calculer_dimensions_clipees_zoom(&Debut_X,&Debut_Y,&Largeur,&Hauteur); Debut_Compteur_X=Debut_X; Debut_Compteur_Y=Debut_Y; if ( (Largeur>0) && (Hauteur>0) ) { // Corrections dues au Zoom: Debut_X=(Debut_X-Loupe_Decalage_X)*Loupe_Facteur; Debut_Y=(Debut_Y-Loupe_Decalage_Y)*Loupe_Facteur; Hauteur=Debut_Y+(Hauteur*Loupe_Facteur); if (Hauteur>Menu_Ordonnee) Hauteur=Menu_Ordonnee; Clear_brush_zoom(Principal_X_Zoom+Debut_X,Debut_Y, Debut_Compteur_X,Debut_Compteur_Y, Largeur,Hauteur,Back_color, Principal_Largeur_image, Buffer_de_ligne_horizontale); } } break; default: // Pinceau Debut_X=X-Pinceau_Decalage_X; Debut_Y=Y-Pinceau_Decalage_Y; Largeur=Pinceau_Largeur; Hauteur=Pinceau_Hauteur; Calculer_dimensions_clipees(&Debut_X,&Debut_Y,&Largeur,&Hauteur); Debut_Compteur_X=Debut_X-(X-Pinceau_Decalage_X); Debut_Compteur_Y=Debut_Y-(Y-Pinceau_Decalage_Y); Fin_Compteur_X=Debut_Compteur_X+Largeur; Fin_Compteur_Y=Debut_Compteur_Y+Hauteur; Temp=Brosse; Brosse=Pinceau_Sprite; if ( (Largeur>0) && (Hauteur>0) ) { Clear_brush(Debut_X-Principal_Decalage_X, Debut_Y-Principal_Decalage_Y, Debut_Compteur_X,Debut_Compteur_Y, Largeur,Hauteur,0, Principal_Largeur_image); } if (Loupe_Mode) { Calculer_dimensions_clipees_zoom(&Debut_X,&Debut_Y,&Largeur,&Hauteur); Debut_Compteur_X=Debut_X; Debut_Compteur_Y=Debut_Y; if ( (Largeur>0) && (Hauteur>0) ) { // Corrections dues au Zoom: Debut_X=(Debut_X-Loupe_Decalage_X)*Loupe_Facteur; Debut_Y=(Debut_Y-Loupe_Decalage_Y)*Loupe_Facteur; Hauteur=Debut_Y+(Hauteur*Loupe_Facteur); if (Hauteur>Menu_Ordonnee) Hauteur=Menu_Ordonnee; Clear_brush_zoom(Principal_X_Zoom+Debut_X,Debut_Y, Debut_Compteur_X,Debut_Compteur_Y, Largeur,Hauteur,0, Principal_Largeur_image, Buffer_de_ligne_horizontale); } } Brosse=Temp; break; } } // -- Fonctions de manipulation du curseur ----------------------------------- // -- Afficher une barre horizontale XOR zoomée void Ligne_horizontale_XOR_Zoom(short Pos_X, short Pos_Y, short Largeur) { short Pos_X_reelle=Principal_X_Zoom+(Pos_X-Loupe_Decalage_X)*Loupe_Facteur; short Pos_Y_reelle=(Pos_Y-Loupe_Decalage_Y)*Loupe_Facteur; short Largeur_reelle=Largeur*Loupe_Facteur; short Pos_Y_Fin=(Pos_Y_reelle+Loupe_Facteur=Principal_X_Zoom) ) ) || (Une_fenetre_est_ouverte) || (Forme_curseur==FORME_CURSEUR_SABLIER) ) Forme=Forme_curseur; else Forme=FORME_CURSEUR_FLECHE; switch(Forme) { case FORME_CURSEUR_CIBLE : if (!Cacher_pinceau) Afficher_pinceau(Pinceau_X,Pinceau_Y,Fore_color,1); if (!Cacher_curseur) { if (Config.Curseur==1) { Debut_Y=(Mouse_Y<6)?6-Mouse_Y:0; if (Debut_Y<4) Ligne_verticale_XOR (Mouse_X,Mouse_Y+Debut_Y-6,4-Debut_Y); Debut_X=(Mouse_X<6)?(short)6-Mouse_X:0; if (Debut_X<4) Ligne_horizontale_XOR(Mouse_X+Debut_X-6,Mouse_Y,4-Debut_X); Fin_X=(Mouse_X+7>Largeur_ecran)?Mouse_X+7-Largeur_ecran:0; if (Fin_X<4) Ligne_horizontale_XOR(Mouse_X+3,Mouse_Y,4-Fin_X); Fin_Y=(Mouse_Y+7>Menu_Ordonnee/*Hauteur_ecran*/)?Mouse_Y+7-Menu_Ordonnee/*Hauteur_ecran*/:0; if (Fin_Y<4) Ligne_verticale_XOR (Mouse_X,Mouse_Y+3,4-Fin_Y); } else { Temp=(Config.Curseur)?FORME_CURSEUR_CIBLE_FINE:FORME_CURSEUR_CIBLE; Debut_X=Mouse_X-Curseur_Decalage_X[Temp]; Debut_Y=Mouse_Y-Curseur_Decalage_Y[Temp]; for (Pos_X=Debut_X,Compteur_X=0;Compteur_X<15;Pos_X++,Compteur_X++) for (Pos_Y=Debut_Y,Compteur_Y=0;Compteur_Y<15;Pos_Y++,Compteur_Y++) { Couleur=SPRITE_CURSEUR[Temp][Compteur_Y][Compteur_X]; if ( (Pos_X>=0) && (Pos_X=0) && (Pos_YLargeur_ecran)?Mouse_X+6-Largeur_ecran:0; if (Fin_X<3) Ligne_horizontale_XOR(Mouse_X+3,Mouse_Y,3-Fin_X); Fin_Y=(Mouse_Y+6>Menu_Ordonnee/*Hauteur_ecran*/)?Mouse_Y+6-Menu_Ordonnee/*Hauteur_ecran*/:0; if (Fin_Y<3) Ligne_verticale_XOR (Mouse_X,Mouse_Y+3,3-Fin_Y); // Petites barres aux extrémités Debut_X=(!Mouse_X); Debut_Y=(!Mouse_Y); Fin_X=(Mouse_X>=Largeur_ecran-1); Fin_Y=(Mouse_Y>=Menu_Ordonnee-1); if (Mouse_Y>5) Ligne_horizontale_XOR(Debut_X+Mouse_X-1,Mouse_Y-6,3-(Debut_X+Fin_X)); if (Mouse_X>5) Ligne_verticale_XOR (Mouse_X-6,Debut_Y+Mouse_Y-1,3-(Debut_Y+Fin_Y)); if (Mouse_X=0) && (Pos_X=0) && (Pos_Y=0) && (Pos_Y>=0) ) { // On sauvegarde dans FOND_CURSEUR pour restaurer plus tard FOND_CURSEUR[Compteur_Y][Compteur_X]=Lit_pixel(Pos_X,Pos_Y); if (Couleur!=CM_Trans) Pixel(Pos_X,Pos_Y,Couleur); } } SDL_UpdateRect(Ecran_SDL,Max(Debut_X,0),Max(Debut_Y,0),16,16); break; case FORME_CURSEUR_CIBLE_XOR : Pos_X=Pinceau_X-Principal_Decalage_X; Pos_Y=Pinceau_Y-Principal_Decalage_Y; Compteur_X=(Loupe_Mode)?Principal_Split:Largeur_ecran; // Largeur de la barre XOR if ((Pos_Y=Limite_Haut)) { Ligne_horizontale_XOR(0,Pinceau_Y-Principal_Decalage_Y,Compteur_X); SDL_UpdateRect(Ecran_SDL,0,Pinceau_Y-Principal_Decalage_Y,Compteur_X,1); } if ((Pos_X=Limite_Gauche)) { Ligne_verticale_XOR(Pinceau_X-Principal_Decalage_X,0,Menu_Ordonnee); SDL_UpdateRect(Ecran_SDL,Pinceau_X-Principal_Decalage_X,0,1,Menu_Ordonnee); } if (Loupe_Mode) { // UPDATERECT if ((Pinceau_Y>=Limite_Haut_Zoom) && (Pinceau_Y<=Limite_visible_Bas_Zoom)) Ligne_horizontale_XOR_Zoom(Limite_Gauche_Zoom,Pinceau_Y,Loupe_Largeur); if ((Pinceau_X>=Limite_Gauche_Zoom) && (Pinceau_X<=Limite_visible_Droite_Zoom)) Ligne_verticale_XOR_Zoom(Pinceau_X,Limite_Haut_Zoom,Loupe_Hauteur); } break; case FORME_CURSEUR_RECTANGLE_XOR : // !!! Cette forme ne peut pas être utilisée en mode Loupe !!! // Petite croix au centre Debut_X=(Mouse_X-3); Debut_Y=(Mouse_Y-3); Fin_X =(Mouse_X+4); Fin_Y =(Mouse_Y+4); if (Debut_X<0) Debut_X=0; if (Debut_Y<0) Debut_Y=0; if (Fin_X>Largeur_ecran) Fin_X=Largeur_ecran; if (Fin_Y>Menu_Ordonnee) Fin_Y=Menu_Ordonnee; Ligne_horizontale_XOR(Debut_X,Mouse_Y,Fin_X-Debut_X); Ligne_verticale_XOR (Mouse_X,Debut_Y,Fin_Y-Debut_Y); // Grand rectangle autour Debut_X=Mouse_X-(Loupe_Largeur>>1); Debut_Y=Mouse_Y-(Loupe_Hauteur>>1); if (Debut_X+Loupe_Largeur>=Limite_Droite-Principal_Decalage_X) Debut_X=Limite_Droite-Loupe_Largeur-Principal_Decalage_X+1; if (Debut_Y+Loupe_Hauteur>=Limite_Bas-Principal_Decalage_Y) Debut_Y=Limite_Bas-Loupe_Hauteur-Principal_Decalage_Y+1; if (Debut_X<0) Debut_X=0; if (Debut_Y<0) Debut_Y=0; Fin_X=Debut_X+Loupe_Largeur-1; Fin_Y=Debut_Y+Loupe_Hauteur-1; Ligne_horizontale_XOR(Debut_X,Debut_Y,Loupe_Largeur); Ligne_verticale_XOR(Debut_X,Debut_Y+1,Loupe_Hauteur-2); Ligne_verticale_XOR( Fin_X,Debut_Y+1,Loupe_Hauteur-2); Ligne_horizontale_XOR(Debut_X, Fin_Y,Loupe_Largeur); SDL_UpdateRect(Ecran_SDL,Debut_X,Debut_Y,Fin_X+1-Debut_X,Fin_Y+1-Debut_Y); break; default: //case FORME_CURSEUR_ROTATE_XOR : Debut_X=1-(Brosse_Largeur>>1); Debut_Y=1-(Brosse_Hauteur>>1); Fin_X=Debut_X+Brosse_Largeur-1; Fin_Y=Debut_Y+Brosse_Hauteur-1; if (Brosse_Centre_rotation_defini) { if ( (Brosse_Centre_rotation_X==Pinceau_X) && (Brosse_Centre_rotation_Y==Pinceau_Y) ) { cosA=1.0; sinA=0.0; } else { Pos_X=Pinceau_X-Brosse_Centre_rotation_X; Pos_Y=Pinceau_Y-Brosse_Centre_rotation_Y; cosA=(float)Pos_X/sqrt((Pos_X*Pos_X)+(Pos_Y*Pos_Y)); sinA=sin(acos(cosA)); if (Pos_Y>0) sinA=-sinA; } Transformer_point(Debut_X,Debut_Y, cosA,sinA, &X1,&Y1); Transformer_point(Fin_X ,Debut_Y, cosA,sinA, &X2,&Y2); Transformer_point(Debut_X,Fin_Y , cosA,sinA, &X3,&Y3); Transformer_point(Fin_X ,Fin_Y , cosA,sinA, &X4,&Y4); X1+=Brosse_Centre_rotation_X; Y1+=Brosse_Centre_rotation_Y; X2+=Brosse_Centre_rotation_X; Y2+=Brosse_Centre_rotation_Y; X3+=Brosse_Centre_rotation_X; Y3+=Brosse_Centre_rotation_Y; X4+=Brosse_Centre_rotation_X; Y4+=Brosse_Centre_rotation_Y; Pixel_figure_Preview_xor(Brosse_Centre_rotation_X,Brosse_Centre_rotation_Y,0); Tracer_ligne_Preview_xor(Brosse_Centre_rotation_X,Brosse_Centre_rotation_Y,Pinceau_X,Pinceau_Y,0); } else { X1=X3=1-Brosse_Largeur; Y1=Y2=Debut_Y; X2=X4=Pinceau_X; Y3=Y4=Fin_Y; X1+=Pinceau_X; Y1+=Pinceau_Y; Y2+=Pinceau_Y; X3+=Pinceau_X; Y3+=Pinceau_Y; Y4+=Pinceau_Y; Pixel_figure_Preview_xor(Pinceau_X-Fin_X,Pinceau_Y,0); Tracer_ligne_Preview_xor(Pinceau_X-Fin_X,Pinceau_Y,Pinceau_X,Pinceau_Y,0); } Tracer_ligne_Preview_xor(X1,Y1,X2,Y2,0); Tracer_ligne_Preview_xor(X2,Y2,X4,Y4,0); Tracer_ligne_Preview_xor(X4,Y4,X3,Y3,0); Tracer_ligne_Preview_xor(X3,Y3,X1,Y1,0); } } // -- Effacer le curseur -- void Effacer_curseur(void) { byte Forme; int Debut_X; // int car sont parfois négatifs ! (quand on dessine sur un bord) int Debut_Y; short Fin_X; short Fin_Y; int Pos_X; int Pos_Y; short Compteur_X; short Compteur_Y; //short Fin_Compteur_X; // Position X ou s'arrête l'affichage de la brosse/pinceau //short Fin_Compteur_Y; // Position Y ou s'arrête l'affichage de la brosse/pinceau int Temp; //byte Couleur; float cosA,sinA; short X1,Y1,X2,Y2,X3,Y3,X4,Y4; if ( ( (Mouse_Y=Principal_X_Zoom) ) ) || (Une_fenetre_est_ouverte) || (Forme_curseur==FORME_CURSEUR_SABLIER) ) Forme=Forme_curseur; else Forme=FORME_CURSEUR_FLECHE; switch(Forme) { case FORME_CURSEUR_CIBLE : if (!Cacher_curseur) { if (Config.Curseur==1) { Debut_Y=(Mouse_Y<6)?6-Mouse_Y:0; if (Debut_Y<4) Ligne_verticale_XOR (Mouse_X,Mouse_Y+Debut_Y-6,4-Debut_Y); Debut_X=(Mouse_X<6)?(short)6-Mouse_X:0; if (Debut_X<4) Ligne_horizontale_XOR(Mouse_X+Debut_X-6,Mouse_Y,4-Debut_X); Fin_X=(Mouse_X+7>Largeur_ecran)?Mouse_X+7-Largeur_ecran:0; if (Fin_X<4) Ligne_horizontale_XOR(Mouse_X+3,Mouse_Y,4-Fin_X); Fin_Y=(Mouse_Y+7>Hauteur_ecran)?Mouse_Y+7-Hauteur_ecran:0; if (Fin_Y<4) Ligne_verticale_XOR (Mouse_X,Mouse_Y+3,4-Fin_Y); SDL_UpdateRect(Ecran_SDL,Debut_X,Debut_Y,Fin_X-Debut_X,Fin_Y-Debut_Y); } else { Temp=(Config.Curseur)?FORME_CURSEUR_CIBLE_FINE:FORME_CURSEUR_CIBLE; Debut_X=Mouse_X-Curseur_Decalage_X[Temp]; Debut_Y=Mouse_Y-Curseur_Decalage_Y[Temp]; for (Pos_Y=Debut_Y,Compteur_Y=0;Compteur_Y<15;Pos_Y++,Compteur_Y++) for (Pos_X=Debut_X,Compteur_X=0;Compteur_X<15;Pos_X++,Compteur_X++) if ( (Pos_X>=0) && (Pos_X=0) && (Pos_YLargeur_ecran)?Mouse_X+6-Largeur_ecran:0; if (Fin_X<3) Ligne_horizontale_XOR(Mouse_X+3,Mouse_Y,3-Fin_X); Fin_Y=(Mouse_Y+6>Hauteur_ecran)?Mouse_Y+6-Hauteur_ecran:0; if (Fin_Y<3) Ligne_verticale_XOR (Mouse_X,Mouse_Y+3,3-Fin_Y); Debut_X=(!Mouse_X); Debut_Y=(!Mouse_Y); Fin_X=(Mouse_X>=Largeur_ecran-1); Fin_Y=(Mouse_Y>=Menu_Ordonnee-1); if (Mouse_Y>5) Ligne_horizontale_XOR(Debut_X+Mouse_X-1,Mouse_Y-6,3-(Debut_X+Fin_X)); if (Mouse_X>5) Ligne_verticale_XOR (Mouse_X-6,Debut_Y+Mouse_Y-1,3-(Debut_Y+Fin_Y)); if (Mouse_X=0) && (Pos_X=0) && (Pos_Y=0) && (Pos_Y>=0) ) Pixel(Pos_X,Pos_Y,FOND_CURSEUR[Compteur_Y][Compteur_X]); SDL_UpdateRect(Ecran_SDL,Max(Debut_X,0),Max(Debut_Y,0),16,16); break; case FORME_CURSEUR_CIBLE_XOR : Pos_X=Pinceau_X-Principal_Decalage_X; Pos_Y=Pinceau_Y-Principal_Decalage_Y; Compteur_X=(Loupe_Mode)?Principal_Split:Largeur_ecran; // Largeur de la barre XOR if ((Pos_Y=Limite_Haut)) { Ligne_horizontale_XOR(0,Pinceau_Y-Principal_Decalage_Y,Compteur_X); SDL_UpdateRect(Ecran_SDL,0,Pinceau_Y-Principal_Decalage_Y,Compteur_X,1); } if ((Pos_X=Limite_Gauche)) { Ligne_verticale_XOR(Pinceau_X-Principal_Decalage_X,0,Menu_Ordonnee); SDL_UpdateRect(Ecran_SDL,Pinceau_X-Principal_Decalage_X,0,1,Menu_Ordonnee); } if (Loupe_Mode) { // UPDATERECT if ((Pinceau_Y>=Limite_Haut_Zoom) && (Pinceau_Y<=Limite_visible_Bas_Zoom)) Ligne_horizontale_XOR_Zoom(Limite_Gauche_Zoom,Pinceau_Y,Loupe_Largeur); if ((Pinceau_X>=Limite_Gauche_Zoom) && (Pinceau_X<=Limite_visible_Droite_Zoom)) Ligne_verticale_XOR_Zoom(Pinceau_X,Limite_Haut_Zoom,Loupe_Hauteur); } break; case FORME_CURSEUR_RECTANGLE_XOR : // !!! Cette forme ne peut pas être utilisée en mode Loupe !!! // Petite croix au centre Debut_X=(Mouse_X-3); Debut_Y=(Mouse_Y-3); Fin_X =(Mouse_X+4); Fin_Y =(Mouse_Y+4); if (Debut_X<0) Debut_X=0; if (Debut_Y<0) Debut_Y=0; if (Fin_X>Largeur_ecran) Fin_X=Largeur_ecran; if (Fin_Y>Menu_Ordonnee) Fin_Y=Menu_Ordonnee; Ligne_horizontale_XOR(Debut_X,Mouse_Y,Fin_X-Debut_X); Ligne_verticale_XOR (Mouse_X,Debut_Y,Fin_Y-Debut_Y); // Grand rectangle autour Debut_X=Mouse_X-(Loupe_Largeur>>1); Debut_Y=Mouse_Y-(Loupe_Hauteur>>1); if (Debut_X+Loupe_Largeur>=Limite_Droite-Principal_Decalage_X) Debut_X=Limite_Droite-Loupe_Largeur-Principal_Decalage_X+1; if (Debut_Y+Loupe_Hauteur>=Limite_Bas-Principal_Decalage_Y) Debut_Y=Limite_Bas-Loupe_Hauteur-Principal_Decalage_Y+1; if (Debut_X<0) Debut_X=0; if (Debut_Y<0) Debut_Y=0; Fin_X=Debut_X+Loupe_Largeur-1; Fin_Y=Debut_Y+Loupe_Hauteur-1; Ligne_horizontale_XOR(Debut_X,Debut_Y,Loupe_Largeur); Ligne_verticale_XOR(Debut_X,Debut_Y+1,Loupe_Hauteur-2); Ligne_verticale_XOR( Fin_X,Debut_Y+1,Loupe_Hauteur-2); Ligne_horizontale_XOR(Debut_X, Fin_Y,Loupe_Largeur); SDL_UpdateRect(Ecran_SDL,Debut_X,Debut_Y,Fin_X+1-Debut_X,Fin_Y+1-Debut_Y); break; default: //case FORME_CURSEUR_ROTATE_XOR : Debut_X=1-(Brosse_Largeur>>1); Debut_Y=1-(Brosse_Hauteur>>1); Fin_X=Debut_X+Brosse_Largeur-1; Fin_Y=Debut_Y+Brosse_Hauteur-1; if (Brosse_Centre_rotation_defini) { if ( (Brosse_Centre_rotation_X==Pinceau_X) && (Brosse_Centre_rotation_Y==Pinceau_Y) ) { cosA=1.0; sinA=0.0; } else { Pos_X=Pinceau_X-Brosse_Centre_rotation_X; Pos_Y=Pinceau_Y-Brosse_Centre_rotation_Y; cosA=(float)Pos_X/sqrt((Pos_X*Pos_X)+(Pos_Y*Pos_Y)); sinA=sin(acos(cosA)); if (Pos_Y>0) sinA=-sinA; } Transformer_point(Debut_X,Debut_Y, cosA,sinA, &X1,&Y1); Transformer_point(Fin_X ,Debut_Y, cosA,sinA, &X2,&Y2); Transformer_point(Debut_X,Fin_Y , cosA,sinA, &X3,&Y3); Transformer_point(Fin_X ,Fin_Y , cosA,sinA, &X4,&Y4); X1+=Brosse_Centre_rotation_X; Y1+=Brosse_Centre_rotation_Y; X2+=Brosse_Centre_rotation_X; Y2+=Brosse_Centre_rotation_Y; X3+=Brosse_Centre_rotation_X; Y3+=Brosse_Centre_rotation_Y; X4+=Brosse_Centre_rotation_X; Y4+=Brosse_Centre_rotation_Y; Pixel_figure_Preview_xor(Brosse_Centre_rotation_X,Brosse_Centre_rotation_Y,0); Tracer_ligne_Preview_xor(Brosse_Centre_rotation_X,Brosse_Centre_rotation_Y,Pinceau_X,Pinceau_Y,0); } else { X1=X3=1-Brosse_Largeur; Y1=Y2=Debut_Y; X2=X4=Pinceau_X; Y3=Y4=Fin_Y; X1+=Pinceau_X; Y1+=Pinceau_Y; Y2+=Pinceau_Y; X3+=Pinceau_X; Y3+=Pinceau_Y; Y4+=Pinceau_Y; Pixel_figure_Preview_xor(Pinceau_X-Fin_X,Pinceau_Y,0); Tracer_ligne_Preview_xor(Pinceau_X-Fin_X,Pinceau_Y,Pinceau_X,Pinceau_Y,0); } Tracer_ligne_Preview_xor(X1,Y1,X2,Y2,0); Tracer_ligne_Preview_xor(X2,Y2,X4,Y4,0); Tracer_ligne_Preview_xor(X4,Y4,X3,Y3,0); Tracer_ligne_Preview_xor(X3,Y3,X1,Y1,0); } } //---- Fenêtre demandant de confirmer une action et renvoyant la réponse ----- byte Demande_de_confirmation(char * Message) { short Bouton_clicke; word Largeur_de_la_fenetre; Largeur_de_la_fenetre=(strlen(Message)<<3)+20; if (Largeur_de_la_fenetre<120) Largeur_de_la_fenetre=120; Ouvrir_fenetre(Largeur_de_la_fenetre,60,"Confirmation"); Print_dans_fenetre((Largeur_de_la_fenetre>>1)-(strlen(Message)<<2),20,Message,CM_Noir,CM_Clair); Fenetre_Definir_bouton_normal((Largeur_de_la_fenetre/3)-20 ,37,40,14,"Yes",1,1,0x0015); // 1 Fenetre_Definir_bouton_normal(((Largeur_de_la_fenetre<<1)/3)-20,37,40,14,"No" ,1,1,0x0031); // 2 Afficher_curseur(); do { Bouton_clicke=Fenetre_Bouton_clicke(); if (Touche==0x001C) Bouton_clicke=1; if (Touche==0x0001) Bouton_clicke=2; } while (Bouton_clicke<=0); Fermer_fenetre(); Afficher_curseur(); return (Bouton_clicke==1)? 1 : 0; } //---- Fenêtre avertissant de quelque chose et attendant un click sur OK ----- void Warning_message(char * Message) { short Bouton_clicke; word Largeur_de_la_fenetre; Largeur_de_la_fenetre=(strlen(Message)<<3)+20; if (Largeur_de_la_fenetre<120) Largeur_de_la_fenetre=120; Ouvrir_fenetre(Largeur_de_la_fenetre,60,"Warning!"); Print_dans_fenetre((Largeur_de_la_fenetre>>1)-(strlen(Message)<<2),20,Message,CM_Noir,CM_Clair); Fenetre_Definir_bouton_normal((Largeur_de_la_fenetre>>1)-20 ,37,40,14,"OK",1,1,0x001C); // 1 Afficher_curseur(); do Bouton_clicke=Fenetre_Bouton_clicke(); while ((Bouton_clicke<=0) && (Touche!=0x0001) && (Touche!=0x0018)); Fermer_fenetre(); Afficher_curseur(); } // -- Fonction diverses d'affichage ------------------------------------------ // -- Reafficher toute l'image (en prenant en compte le facteur de zoom) -- void Afficher_ecran(void) { word Largeur; word Hauteur; // ---/\/\/\ Partie non zoomée: /\/\/\--- if (Loupe_Mode) { if (Principal_Largeur_image à 64 lignes fct(Menu_Facteur) word Nb_couleurs =(Debut_block<=Fin_block)?Fin_block-Debut_block+1:Debut_block-Fin_block+1; word Ligne_en_cours=(Debut_block<=Fin_block)?0:Total_lignes-1; word Debut_X =Fenetre_Pos_X+(Menu_Facteur_X*Pos_X); word Largeur_ligne =Menu_Facteur_X<<4; // <=> à 16 pixels fct(Menu_Facteur) word Debut_Y =Fenetre_Pos_Y+(Menu_Facteur_Y*Pos_Y); word Fin_Y =Debut_Y+Total_lignes; word Indice; if (Debut_block>Fin_block) { Indice=Debut_block; Debut_block=Fin_block; Fin_block=Indice; } for (Indice=Debut_Y;IndiceFin_X) { Temporaire=Debut_X; Debut_X =Fin_X; Fin_X =Temporaire; } if (Debut_Y>Fin_Y) { Temporaire=Debut_Y; Debut_Y =Fin_Y; Fin_Y =Temporaire; } // On ne capture la nouvelle brosse que si elle est au moins partiellement // dans l'image: if ((Debut_XPrincipal_Largeur_image) Nouvelle_Brosse_Largeur=Principal_Largeur_image-Debut_X; if (Debut_Y+Nouvelle_Brosse_Hauteur>Principal_Hauteur_image) Nouvelle_Brosse_Hauteur=Principal_Hauteur_image-Debut_Y; if ( (((long)Brosse_Hauteur)*Brosse_Largeur) != (((long)Nouvelle_Brosse_Hauteur)*Nouvelle_Brosse_Largeur) ) { free(Brosse); Brosse=(byte *)malloc(((long)Nouvelle_Brosse_Hauteur)*Nouvelle_Brosse_Largeur); if (!Brosse) { Erreur(0); Brosse=(byte *)malloc(1*1); Nouvelle_Brosse_Hauteur=Nouvelle_Brosse_Largeur=1; *Brosse=Fore_color; } } Brosse_Largeur=Nouvelle_Brosse_Largeur; Brosse_Hauteur=Nouvelle_Brosse_Hauteur; free(Smear_Brosse); Smear_Brosse_Largeur=(Brosse_Largeur>TAILLE_MAXI_PINCEAU)?Brosse_Largeur:TAILLE_MAXI_PINCEAU; Smear_Brosse_Hauteur=(Brosse_Hauteur>TAILLE_MAXI_PINCEAU)?Brosse_Hauteur:TAILLE_MAXI_PINCEAU; Smear_Brosse=(byte *)malloc(((long)Smear_Brosse_Hauteur)*Smear_Brosse_Largeur); if (!Smear_Brosse) // On ne peut même pas allouer la brosse du smear! { Erreur(0); free(Brosse); Brosse=(byte *)malloc(1*1); Brosse_Hauteur=1; Brosse_Largeur=1; Smear_Brosse=(byte *)malloc(TAILLE_MAXI_PINCEAU*TAILLE_MAXI_PINCEAU); Smear_Brosse_Hauteur=TAILLE_MAXI_PINCEAU; Smear_Brosse_Largeur=TAILLE_MAXI_PINCEAU; } Copier_image_dans_brosse(Debut_X,Debut_Y,Brosse_Largeur,Brosse_Hauteur,Principal_Largeur_image); // On regarde s'il faut effacer quelque chose: if (Effacement) { for (Pos_Y=Debut_Y;Pos_Y>1); Brosse_Decalage_Y=(Brosse_Hauteur>>1); } } void Rotate_90_deg() { short Temporaire; byte * Nouvelle_Brosse; Nouvelle_Brosse=(byte *)malloc(((long)Brosse_Hauteur)*Brosse_Largeur); if (Nouvelle_Brosse) { Rotate_90_deg_LOWLEVEL(Brosse,Nouvelle_Brosse); free(Brosse); Brosse=Nouvelle_Brosse; Temporaire=Brosse_Largeur; Brosse_Largeur=Brosse_Hauteur; Brosse_Hauteur=Temporaire; Temporaire=Smear_Brosse_Largeur; Smear_Brosse_Largeur=Smear_Brosse_Hauteur; Smear_Brosse_Hauteur=Temporaire; // On centre la prise sur la brosse Brosse_Decalage_X=(Brosse_Largeur>>1); Brosse_Decalage_Y=(Brosse_Hauteur>>1); } else Erreur(0); } void Remap_brosse(void) { short Pos_X; // Variable de balayage de la brosse short Pos_Y; // Variable de balayage de la brosse byte Utilisee[256]; // Tableau de booléens "La couleur est utilisée" int Couleur; // On commence par initialiser le tableau de booléens à faux for (Couleur=0;Couleur<=255;Couleur++) Utilisee[Couleur]=0; // On calcule la table d'utilisation des couleurs for (Pos_Y=0;Pos_Y>1); Brosse_Decalage_Y=(Brosse_Hauteur>>1); free(Temporaire); // Libération de l'ancienne brosse // Réallocation d'un buffer de Smear free(Smear_Brosse); Smear_Brosse_Largeur=(Brosse_Largeur>TAILLE_MAXI_PINCEAU)?Brosse_Largeur:TAILLE_MAXI_PINCEAU; Smear_Brosse_Hauteur=(Brosse_Hauteur>TAILLE_MAXI_PINCEAU)?Brosse_Hauteur:TAILLE_MAXI_PINCEAU; Smear_Brosse=(byte *)malloc(((long)Smear_Brosse_Largeur)*Smear_Brosse_Hauteur); } else Erreur(0); // Pas assez de mémoire! } void Nibble_brush(void) { long /*Pos,*/Pos_X,Pos_Y; byte Etat; byte * Nouvelle_brosse; byte * Temporaire; word Largeur; word Hauteur; if ( (Brosse_Largeur>2) && (Brosse_Hauteur>2) ) { Largeur=Brosse_Largeur-2; Hauteur=Brosse_Hauteur-2; Nouvelle_brosse=(byte *)malloc(((long)Largeur)*Hauteur); if (Nouvelle_brosse) { // On copie la brosse courante dans la nouvelle Copier_une_partie_d_image_dans_une_autre(Brosse, // Source 1, 1, Largeur, Hauteur, Brosse_Largeur, Nouvelle_brosse, // Destination 0, 0, Largeur); // On intervertit la nouvelle et l'ancienne brosse: Temporaire=Brosse; Brosse=Nouvelle_brosse; Brosse_Largeur-=2; Brosse_Hauteur-=2; Largeur+=2; Hauteur+=2; // 1er balayage (horizontal) for (Pos_Y=0; Pos_Y0) Pixel_dans_brosse(Pos_X-1,Pos_Y,Back_color); Etat=0; } } else { if (!Etat) { Pixel_dans_brosse(Pos_X,Pos_Y,Back_color); Etat=1; } } } // Cas du dernier pixel à droite de la ligne if (Temporaire[((Pos_Y+1)*Largeur)+Pos_X+1]==Back_color) Pixel_dans_brosse(Pos_X-1,Pos_Y,Back_color); } // 2ème balayage (vertical) for (Pos_X=0; Pos_X0) Pixel_dans_brosse(Pos_X,Pos_Y-1,Back_color); Etat=0; } } else { if (!Etat) { Pixel_dans_brosse(Pos_X,Pos_Y,Back_color); Etat=1; } } } // Cas du dernier pixel en bas de la colonne if (Temporaire[((Pos_Y+1)*Largeur)+Pos_X+1]==Back_color) Pixel_dans_brosse(Pos_X,Pos_Y-1,Back_color); } // On recentre la prise sur la brosse Brosse_Decalage_X=(Brosse_Largeur>>1); Brosse_Decalage_Y=(Brosse_Hauteur>>1); free(Temporaire); // Libération de l'ancienne brosse // Réallocation d'un buffer de Smear free(Smear_Brosse); Smear_Brosse_Largeur=(Brosse_Largeur>TAILLE_MAXI_PINCEAU)?Brosse_Largeur:TAILLE_MAXI_PINCEAU; Smear_Brosse_Hauteur=(Brosse_Hauteur>TAILLE_MAXI_PINCEAU)?Brosse_Hauteur:TAILLE_MAXI_PINCEAU; Smear_Brosse=(byte *)malloc(((long)Smear_Brosse_Largeur)*Smear_Brosse_Hauteur); } else Erreur(0); // Pas assez de mémoire! } } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////// GESTION DU FILLER ///////////////////////////// ////////////////////////////////////////////////////////////////////////////// void Fill(short * Limite_atteinte_Haut , short * Limite_atteinte_Bas, short * Limite_atteinte_Gauche, short * Limite_atteinte_Droite) // // Cette fonction fait un remplissage classique d'une zone délimitée de // l'image. Les limites employées sont Limite_Haut, Limite_Bas, Limite_Gauche // et Limite_Droite. Le point de départ du remplissage est Pinceau_X,Pinceau_Y // et s'effectue en théorie sur la couleur 1 et emploie la couleur 2 pour le // remplissage. Ces restrictions sont d–es à l'utilisation qu'on en fait dans // la fonction principale "Remplir", qui se charge de faire une gestion de // tous les effets. // Cette fonction ne doit pas être directement appelée. // { short Pos_X; // Abscisse de balayage du segment, utilisée lors de l'"affichage" short Ligne; // Ordonnée de la ligne en cours de traitement short Debut_X; // Abscisse de départ du segment traité short Fin_X; // Abscisse de fin du segment traité int Modifs_effectuees; // Booléen "On a fait une modif dans le dernier passage" int Propagation_possible; // Booléen "On peut propager la couleur dans le segment" short Limite_courante_Bas; // Intervalle vertical restreint short Limite_courante_Haut; int Ligne_modifiee; // Booléen "On a fait une modif dans la ligne" Modifs_effectuees=1; Limite_courante_Haut=Pinceau_Y; Limite_courante_Bas =Min(Pinceau_Y+1,Limite_Bas); *Limite_atteinte_Gauche=Pinceau_X; *Limite_atteinte_Droite=Pinceau_X+1; Pixel_dans_ecran_courant(Pinceau_X,Pinceau_Y,2); while (Modifs_effectuees) { Modifs_effectuees=0; for (Ligne=Limite_courante_Haut;Ligne<=Limite_courante_Bas;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 while((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-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 en xor void Pixel_figure_Preview_xor(word Pos_X,word Pos_Y,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,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); SDL_UpdateRect(Ecran_SDL,Max(Debut_X+Principal_Decalage_X,0), Max(Debut_Y+Principal_Decalage_Y,0),Fin_X+1-Debut_X,Fin_Y+1-Debut_Y); if(Loupe_Mode) UpdateZoom(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); SDL_UpdateRect(Ecran_SDL,Max(Centre_X-Rayon_horizontal-Principal_Decalage_X,0),Max(Centre_Y-Rayon_vertical-Principal_Decalage_Y,0),2*Rayon_horizontal+1,2*Rayon_vertical+1); UpdateZoom(Centre_X-Rayon_horizontal,Centre_Y-Rayon_vertical,2*Rayon_horizontal+1,2*Rayon_vertical+1); } // -- 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) { Pixel_figure=Pixel_figure_Definitif; Tracer_ligne_General(Debut_X,Debut_Y,Fin_X,Fin_Y,Couleur); Mettre_Ecran_A_Jour(Debut_X,Debut_Y,Fin_X-Debut_X+1,Fin_Y-Debut_Y+1); } // -- Tracer la preview d'une ligne -- void Tracer_ligne_Preview(short Debut_X,short Debut_Y,short Fin_X,short Fin_Y,byte Couleur) { Pixel_figure=Pixel_figure_Preview; Tracer_ligne_General(Debut_X,Debut_Y,Fin_X,Fin_Y,Couleur); Mettre_Ecran_A_Jour(Debut_X,Debut_Y,Fin_X-Debut_X+1,Fin_Y-Debut_Y+1); } // -- Tracer la preview d'une ligne en xor -- void Tracer_ligne_Preview_xor(short Debut_X,short Debut_Y,short Fin_X,short Fin_Y,byte Couleur) { Pixel_figure=Pixel_figure_Preview_xor; Tracer_ligne_General(Debut_X,Debut_Y,Fin_X,Fin_Y,Couleur); Mettre_Ecran_A_Jour(Debut_X,Debut_Y,Fin_X-Debut_X+1,Fin_Y-Debut_Y+1); } // -- Effacer la preview d'une ligne -- void Effacer_ligne_Preview(short Debut_X,short Debut_Y,short Fin_X,short Fin_Y) { Pixel_figure=Pixel_figure_Effacer_preview; Tracer_ligne_General(Debut_X,Debut_Y,Fin_X,Fin_Y,0); Mettre_Ecran_A_Jour(Debut_X,Debut_Y,Fin_X-Debut_X+1,Fin_Y-Debut_Y+1); } // -- Tracer un rectangle vide -- void Tracer_rectangle_vide(short Debut_X,short Debut_Y,short Fin_X,short Fin_Y,byte Couleur) { short Tempo; short Pos_X; short Pos_Y; // On vérifie que les bornes soient dans le bon sens: if (Debut_X>Fin_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); SDL_UpdateRect(Ecran_SDL, Debut_X-Principal_Decalage_X, Debut_Y-Principal_Decalage_Y, Fin_X-Debut_X, Fin_Y-Debut_Y); if(Loupe_Mode) UpdateZoom(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; SDL_UpdateRect(Ecran_SDL,X-Principal_Decalage_X,Y-Principal_Decalage_Y,Old_X,Old_Y); UpdateZoom(X,Y,Old_X,Old_Y); } // -- 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); } } SDL_UpdateRect(Ecran_SDL,Debut_X-Principal_Decalage_X,Debut_Y-Principal_Decalage_Y,Fin_Y-Debut_Y+1,Fin_X-Debut_X+1); UpdateZoom(Debut_X,Debut_Y,Fin_Y-Debut_Y+1,Fin_X-Debut_X+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); } } SDL_UpdateRect(Ecran_SDL,Debut_X-Principal_Decalage_X,Debut_Y-Principal_Decalage_Y,Fin_X-Debut_X+1,Fin_Y-Debut_Y+1); UpdateZoom(Debut_X,Debut_Y,Fin_X-Debut_X+1,Fin_Y-Debut_Y+1); } // -- 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); } void Polyfill(int Vertices, short * Points, int Color) { Pixel_figure=Afficher_pixel; Polyfill_General(Vertices,Points,Color); } void Capturer_brosse_au_lasso(int Vertices, short * Points,short Effacement) { short Debut_X=Limite_Droite+1; short Debut_Y=Limite_Bas+1; short Fin_X=Limite_Gauche-1; short Fin_Y=Limite_Haut-1; short Temporaire; short Pos_X; short Pos_Y; word Nouvelle_Brosse_Largeur; word Nouvelle_Brosse_Hauteur; // On recherche les bornes de la brosse: for (Temporaire=0; TemporaireFin_X) Fin_X=Pos_X; if (Pos_YFin_Y) Fin_Y=Pos_Y; } // On clippe ces bornes à l'écran: if (Debut_XLimite_Droite) Fin_X=Limite_Droite; if (Debut_YLimite_Bas) Fin_Y=Limite_Bas; // On ne capture la nouvelle brosse que si elle est au moins partiellement // dans l'image: if ((Debut_XTAILLE_MAXI_PINCEAU)?Brosse_Largeur:TAILLE_MAXI_PINCEAU; Smear_Brosse_Hauteur=(Brosse_Hauteur>TAILLE_MAXI_PINCEAU)?Brosse_Hauteur:TAILLE_MAXI_PINCEAU; Smear_Brosse=(byte *)malloc(((long)Smear_Brosse_Hauteur)*Smear_Brosse_Largeur); if (!Smear_Brosse) // On ne peut même pas allouer la brosse du smear! { Erreur(0); free(Brosse); Brosse=(byte *)malloc(1*1); Brosse_Hauteur=1; Brosse_Largeur=1; Smear_Brosse=(byte *)malloc(TAILLE_MAXI_PINCEAU*TAILLE_MAXI_PINCEAU); Smear_Brosse_Hauteur=TAILLE_MAXI_PINCEAU; Smear_Brosse_Largeur=TAILLE_MAXI_PINCEAU; } Brosse_Decalage_X=Debut_X; Brosse_Decalage_Y=Debut_Y; Pixel_figure=Pixel_figure_Dans_brosse; memset(Brosse,Back_color,(long)Brosse_Largeur*Brosse_Hauteur); Polyfill_General(Vertices,Points,~Back_color); // On retrace les bordures du lasso: for (Temporaire=1; Temporaire>1); Brosse_Decalage_Y=(Brosse_Hauteur>>1); } } //------------ Remplacement de la couleur pointée par une autre -------------- void Remplacer(byte Nouvelle_couleur) { byte Ancienne_couleur; if ((Pinceau_X=0) Pos_X_initial = 0; // Pas d'inversion en X de la brosse else Pos_X_initial = (Brosse_Largeur<<16)-1; // Inversion en X de la brosse free(Smear_Brosse); // On libère un peu de mémoire if ((New_Brosse=((byte *)malloc(New_Brosse_Largeur*New_Brosse_Hauteur)))) { Offset=0; // Calcul de la valeur initiale de Pos_Y: if (Dy>=0) Pos_Y_dans_brosse=0; // Pas d'inversion en Y de la brosse else Pos_Y_dans_brosse=(Brosse_Hauteur<<16)-1; // Inversion en Y de la brosse // Pour chaque ligne for (Ligne=0;Ligne>16,Pos_Y_dans_brosse>>16); // On passe à la colonne de brosse suivante: Pos_X_dans_brosse+=Delta_X_dans_brosse; // On passe au pixel suivant de la nouvelle brosse: Offset++; } // On passe à la ligne de brosse suivante: Pos_Y_dans_brosse+=Delta_Y_dans_brosse; } free(Brosse); Brosse=New_Brosse; Brosse_Largeur=New_Brosse_Largeur; Brosse_Hauteur=New_Brosse_Hauteur; Smear_Brosse_Largeur=(Brosse_Largeur>TAILLE_MAXI_PINCEAU)?Brosse_Largeur:TAILLE_MAXI_PINCEAU; Smear_Brosse_Hauteur=(Brosse_Hauteur>TAILLE_MAXI_PINCEAU)?Brosse_Hauteur:TAILLE_MAXI_PINCEAU; Smear_Brosse=(byte *)malloc(((long)Smear_Brosse_Hauteur)*Smear_Brosse_Largeur); if (!Smear_Brosse) // On ne peut même pas allouer la brosse du smear! { Erreur(0); free(Brosse); Brosse=(byte *)malloc(1*1); Brosse_Hauteur=1; Brosse_Largeur=1; Smear_Brosse=(byte *)malloc(TAILLE_MAXI_PINCEAU*TAILLE_MAXI_PINCEAU); Smear_Brosse_Hauteur=TAILLE_MAXI_PINCEAU; Smear_Brosse_Largeur=TAILLE_MAXI_PINCEAU; } Brosse_Decalage_X=(Brosse_Largeur>>1); Brosse_Decalage_Y=(Brosse_Hauteur>>1); } else { // Ici la libération de mémoire n'a pas suffit donc on remet dans l'état // o— c'etait avant. On a juste à réallouer la Smear_Brosse car il y a // normalement la place pour elle puisque rien d'autre n'a pu être alloué // entre temps. Smear_Brosse=(byte *)malloc(((long)Smear_Brosse_Hauteur)*Smear_Brosse_Largeur); Erreur(0); } } void Etirer_brosse_preview(short X1, short Y1, short X2, short Y2) { int Pos_X_src,Pos_Y_src; int Pos_X_src_Initiale,Pos_Y_src_Initiale; int Delta_X,Delta_Y; int Pos_X_dest,Pos_Y_dest; int Pos_X_dest_Initiale,Pos_Y_dest_Initiale; int Pos_X_dest_Finale,Pos_Y_dest_Finale; int Largeur_dest,Hauteur_dest; byte Couleur; // 1er calcul des positions destination extremes: Pos_X_dest_Initiale=Min(X1,X2); Pos_Y_dest_Initiale=Min(Y1,Y2); Pos_X_dest_Finale =Max(X1,X2); Pos_Y_dest_Finale =Max(Y1,Y2); // Calcul des dimensions de la destination: Largeur_dest=Pos_X_dest_Finale-Pos_X_dest_Initiale+1; Hauteur_dest=Pos_Y_dest_Finale-Pos_Y_dest_Initiale+1; // Calcul des vecteurs d'incrémentation : Delta_X=(Brosse_Largeur<<16)/Largeur_dest; Delta_Y=(Brosse_Hauteur<<16)/Hauteur_dest; // 1er calcul de la position X initiale dans la source: Pos_X_src_Initiale=(Brosse_Largeur<<16)* (Max(Pos_X_dest_Initiale,Limite_Gauche)- Pos_X_dest_Initiale)/Largeur_dest; // Calcul du clip de la destination: Pos_X_dest_Initiale=Max(Pos_X_dest_Initiale,Limite_Gauche); Pos_X_dest_Finale =Min(Pos_X_dest_Finale ,Limite_visible_Droite); // On discute selon l'inversion en X if (X1>X2) { // Inversion -> Inversion du signe de Delta_X Delta_X=-Delta_X; Pos_X_src_Initiale=(Brosse_Largeur<<16)-1-Pos_X_src_Initiale; } // 1er calcul de la position Y initiale dans la source: Pos_Y_src_Initiale=(Brosse_Hauteur<<16)* (Max(Pos_Y_dest_Initiale,Limite_Haut)- Pos_Y_dest_Initiale)/Hauteur_dest; // Calcul du clip de la destination: Pos_Y_dest_Initiale=Max(Pos_Y_dest_Initiale,Limite_Haut); Pos_Y_dest_Finale =Min(Pos_Y_dest_Finale ,Limite_visible_Bas); // On discute selon l'inversion en Y if (Y1>Y2) { // Inversion -> Inversion du signe de Delta_Y Delta_Y=-Delta_Y; Pos_Y_src_Initiale=(Brosse_Hauteur<<16)-1-Pos_Y_src_Initiale; } // Pour chaque ligne : Pos_Y_src=Pos_Y_src_Initiale; for (Pos_Y_dest=Pos_Y_dest_Initiale;Pos_Y_dest<=Pos_Y_dest_Finale;Pos_Y_dest++) { // Pour chaque colonne: Pos_X_src=Pos_X_src_Initiale; for (Pos_X_dest=Pos_X_dest_Initiale;Pos_X_dest<=Pos_X_dest_Finale;Pos_X_dest++) { Couleur=Lit_pixel_dans_brosse(Pos_X_src>>16,Pos_Y_src>>16); if (Couleur!=Back_color) Pixel_Preview(Pos_X_dest,Pos_Y_dest,Couleur); Pos_X_src+=Delta_X; } Pos_Y_src+=Delta_Y; } } //------------------------- Rotation de la brosse --------------------------- #define INDEFINI (-1.0e20F) float * ScanY_Xt[2]; float * ScanY_Yt[2]; float * ScanY_X[2]; void Interpoler_texture(int Debut_X,int Debut_Y,int Xt1,int Yt1, int Fin_X ,int Fin_Y ,int Xt2,int Yt2,int Hauteur) { int Pos_X,Pos_Y; int Incr_X,Incr_Y; int i,Cumul; int Delta_X,Delta_Y; int Delta_Xt=Xt2-Xt1; int Delta_Yt=Yt2-Yt1; int Delta_X2=Fin_X-Debut_X; int Delta_Y2=Fin_Y-Debut_Y; float Xt,Yt; Pos_X=Debut_X; Pos_Y=Debut_Y; if (Debut_XDelta_Y) { Cumul=Delta_X>>1; for (i=0; i<=Delta_X; i++) { if (Cumul>=Delta_X) { Cumul-=Delta_X; Pos_Y+=Incr_Y; } if ((Pos_Y>=0) && (Pos_Y=ScanY_X[0][Pos_Y]) { if ((ScanY_X[1][Pos_Y]==INDEFINI) // Droit non défini || (Pos_X>ScanY_X[1][Pos_Y])) { ScanY_X[1][Pos_Y]=Pos_X; ScanY_Xt[1][Pos_Y]=Xt; ScanY_Yt[1][Pos_Y]=Yt; } } else { if (ScanY_X[1][Pos_Y]==INDEFINI) // Droit non défini { ScanY_X[1][Pos_Y]=ScanY_X[0][Pos_Y]; ScanY_Xt[1][Pos_Y]=ScanY_Xt[0][Pos_Y]; ScanY_Yt[1][Pos_Y]=ScanY_Yt[0][Pos_Y]; ScanY_X[0][Pos_Y]=Pos_X; ScanY_Xt[0][Pos_Y]=Xt; ScanY_Yt[0][Pos_Y]=Yt; } else { ScanY_X[0][Pos_Y]=Pos_X; ScanY_Xt[0][Pos_Y]=Xt; ScanY_Yt[0][Pos_Y]=Yt; } } } } Pos_X+=Incr_X; Cumul+=Delta_Y; } } else { Cumul=Delta_Y>>1; for (i=0; i<=Delta_Y; i++) { if (Cumul>=Delta_Y) { Cumul-=Delta_Y; Pos_X+=Incr_X; } if ((Pos_Y>=0) && (Pos_Y=ScanY_X[0][Pos_Y]) { if ((ScanY_X[1][Pos_Y]==INDEFINI) // Droit non défini || (Pos_X>ScanY_X[1][Pos_Y])) { ScanY_X[1][Pos_Y]=Pos_X; ScanY_Xt[1][Pos_Y]=Xt; ScanY_Yt[1][Pos_Y]=Yt; } } else { if (ScanY_X[1][Pos_Y]==INDEFINI) // Droit non défini { ScanY_X[1][Pos_Y]=ScanY_X[0][Pos_Y]; ScanY_Xt[1][Pos_Y]=ScanY_Xt[0][Pos_Y]; ScanY_Yt[1][Pos_Y]=ScanY_Yt[0][Pos_Y]; ScanY_X[0][Pos_Y]=Pos_X; ScanY_Xt[0][Pos_Y]=Xt; ScanY_Yt[0][Pos_Y]=Yt; } else { ScanY_X[0][Pos_Y]=Pos_X; ScanY_Xt[0][Pos_Y]=Xt; ScanY_Yt[0][Pos_Y]=Yt; } } } } Pos_Y+=Incr_Y; Cumul+=Delta_X; } } } void Calculer_quad_texture(int X1,int Y1,int Xt1,int Yt1, int X2,int Y2,int Xt2,int Yt2, int X3,int Y3,int Xt3,int Yt3, int X4,int Y4,int Xt4,int Yt4, byte * Buffer, int Largeur, int Hauteur) { int Xmin,/*Xmax,*/Ymin/*,Ymax*/; int X,Y,Xt,Yt; int Debut_X,Fin_X,Largeur_ligne; float Temp; //byte Couleur; Xmin=Min(Min(X1,X2),Min(X3,X4)); Ymin=Min(Min(Y1,Y2),Min(Y3,Y4)); ScanY_Xt[0]=(float *)malloc(Hauteur*sizeof(float)); ScanY_Xt[1]=(float *)malloc(Hauteur*sizeof(float)); ScanY_Yt[0]=(float *)malloc(Hauteur*sizeof(float)); ScanY_Yt[1]=(float *)malloc(Hauteur*sizeof(float)); ScanY_X[0] =(float *)malloc(Hauteur*sizeof(float)); ScanY_X[1] =(float *)malloc(Hauteur*sizeof(float)); // Remplir avec des valeurs égales à INDEFINI. for (Y=0; Y>1); Debut_Y=1-(Brosse_Hauteur>>1); Fin_X=Debut_X+Brosse_Largeur-1; Fin_Y=Debut_Y+Brosse_Hauteur-1; Transformer_point(Debut_X,Debut_Y, cosA,sinA, &X1,&Y1); Transformer_point(Fin_X ,Debut_Y, cosA,sinA, &X2,&Y2); Transformer_point(Debut_X,Fin_Y , cosA,sinA, &X3,&Y3); Transformer_point(Fin_X ,Fin_Y , cosA,sinA, &X4,&Y4); // Calcul des nouvelles dimensions de la brosse: Xmin=Min(Min((int)X1,(int)X2),Min((int)X3,(int)X4)); Xmax=Max(Max((int)X1,(int)X2),Max((int)X3,(int)X4)); Ymin=Min(Min((int)Y1,(int)Y2),Min((int)Y3,(int)Y4)); Ymax=Max(Max((int)Y1,(int)Y2),Max((int)Y3,(int)Y4)); New_Brosse_Largeur=Xmax+1-Xmin; New_Brosse_Hauteur=Ymax+1-Ymin; free(Smear_Brosse); // On libère un peu de mémoire if ((New_Brosse=((byte *)malloc(New_Brosse_Largeur*New_Brosse_Hauteur)))) { // Et maintenant on calcule la nouvelle brosse tournée. Calculer_quad_texture(X1,Y1, 0, 0, X2,Y2,Brosse_Largeur-1, 0, X3,Y3, 0,Brosse_Hauteur-1, X4,Y4,Brosse_Largeur-1,Brosse_Hauteur-1, New_Brosse,New_Brosse_Largeur,New_Brosse_Hauteur); free(Brosse); Brosse=New_Brosse; Brosse_Largeur=New_Brosse_Largeur; Brosse_Hauteur=New_Brosse_Hauteur; Smear_Brosse_Largeur=(Brosse_Largeur>TAILLE_MAXI_PINCEAU)?Brosse_Largeur:TAILLE_MAXI_PINCEAU; Smear_Brosse_Hauteur=(Brosse_Hauteur>TAILLE_MAXI_PINCEAU)?Brosse_Hauteur:TAILLE_MAXI_PINCEAU; Smear_Brosse=(byte *)malloc(((long)Smear_Brosse_Hauteur)*Smear_Brosse_Largeur); if (!Smear_Brosse) // On ne peut même pas allouer la brosse du smear! { Erreur(0); free(Brosse); Brosse=(byte *)malloc(1*1); Brosse_Hauteur=1; Brosse_Largeur=1; Smear_Brosse=(byte *)malloc(TAILLE_MAXI_PINCEAU*TAILLE_MAXI_PINCEAU); Smear_Brosse_Hauteur=TAILLE_MAXI_PINCEAU; Smear_Brosse_Largeur=TAILLE_MAXI_PINCEAU; } Brosse_Decalage_X=(Brosse_Largeur>>1); Brosse_Decalage_Y=(Brosse_Hauteur>>1); } else { // Ici la libération de mémoire n'a pas suffit donc on remet dans l'état // o— c'etait avant. On a juste à réallouer la Smear_Brosse car il y a // normalement la place pour elle puisque rien d'autre n'a pu être alloué // entre temps. Smear_Brosse=(byte *)malloc(((long)Smear_Brosse_Hauteur)*Smear_Brosse_Largeur); Erreur(0); } } void Dessiner_quad_texture_preview(int X1,int Y1,int Xt1,int Yt1, int X2,int Y2,int Xt2,int Yt2, int X3,int Y3,int Xt3,int Yt3, int X4,int Y4,int Xt4,int Yt4) { int Xmin,Xmax,Ymin,Ymax; int X,Y,Xt,Yt; int Y_,Ymin_; int Debut_X,Fin_X,Largeur,Hauteur; float Temp; byte Couleur; Xmin=Min(Min(X1,X2),Min(X3,X4)); Xmax=Max(Max(X1,X2),Max(X3,X4)); Ymin=Min(Min(Y1,Y2),Min(Y3,Y4)); Ymax=Max(Max(Y1,Y2),Max(Y3,Y4)); Hauteur=1+Ymax-Ymin; ScanY_Xt[0]=(float *)malloc(Hauteur*sizeof(float)); ScanY_Xt[1]=(float *)malloc(Hauteur*sizeof(float)); ScanY_Yt[0]=(float *)malloc(Hauteur*sizeof(float)); ScanY_Yt[1]=(float *)malloc(Hauteur*sizeof(float)); ScanY_X[0] =(float *)malloc(Hauteur*sizeof(float)); ScanY_X[1] =(float *)malloc(Hauteur*sizeof(float)); // Remplir avec des valeurs égales à INDEFINI. for (Y=0; YLimite_Bas) Ymax=Limite_Bas; for (Y_=Ymin; Y_<=Ymax; Y_++) { Y=Y_-Ymin_; Debut_X=Round(ScanY_X[0][Y]); Fin_X =Round(ScanY_X[1][Y]); Largeur=1+Fin_X-Debut_X; if (Debut_XLimite_Droite) Fin_X=Limite_Droite; for (X=Debut_X; X<=Fin_X; X++) { Temp=(float)(0.5+(float)X-ScanY_X[0][Y])/(float)Largeur; Xt=Round((float)(ScanY_Xt[0][Y])+(Temp*(ScanY_Xt[1][Y]-ScanY_Xt[0][Y]))); Yt=Round((float)(ScanY_Yt[0][Y])+(Temp*(ScanY_Yt[1][Y]-ScanY_Yt[0][Y]))); Couleur=Lit_pixel_dans_brosse(Xt,Yt); if (Couleur!=Back_color) Pixel_Preview(X,Y_,Couleur); } } free(ScanY_Xt[0]); free(ScanY_Xt[1]); free(ScanY_Yt[0]); free(ScanY_Yt[1]); free(ScanY_X[0]); free(ScanY_X[1]); } void Tourner_brosse_preview(float Angle) { short X1,Y1,X2,Y2,X3,Y3,X4,Y4; int Debut_X,Fin_X,Debut_Y,Fin_Y; float cosA=cos(Angle); float sinA=sin(Angle); // Calcul des coordonnées des 4 coins: // 1 2 // 3 4 Debut_X=1-(Brosse_Largeur>>1); Debut_Y=1-(Brosse_Hauteur>>1); Fin_X=Debut_X+Brosse_Largeur-1; Fin_Y=Debut_Y+Brosse_Hauteur-1; Transformer_point(Debut_X,Debut_Y, cosA,sinA, &X1,&Y1); Transformer_point(Fin_X ,Debut_Y, cosA,sinA, &X2,&Y2); Transformer_point(Debut_X,Fin_Y , cosA,sinA, &X3,&Y3); Transformer_point(Fin_X ,Fin_Y , cosA,sinA, &X4,&Y4); X1+=Brosse_Centre_rotation_X; Y1+=Brosse_Centre_rotation_Y; X2+=Brosse_Centre_rotation_X; Y2+=Brosse_Centre_rotation_Y; X3+=Brosse_Centre_rotation_X; Y3+=Brosse_Centre_rotation_Y; X4+=Brosse_Centre_rotation_X; Y4+=Brosse_Centre_rotation_Y; // Et maintenant on dessine la brosse tournée. Dessiner_quad_texture_preview(X1,Y1, 0, 0, X2,Y2,Brosse_Largeur-1, 0, X3,Y3, 0,Brosse_Hauteur-1, X4,Y4,Brosse_Largeur-1,Brosse_Hauteur-1); }