/* Grafx2 - The Ultimate 256-color bitmap paint program
Copyright 2008 Yves Rizoud
Copyright 2008 Franck Charlet
Copyright 2007 Adrien Destugues
Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud)
Grafx2 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2
of the License.
Grafx2 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grafx2; if not, see or
write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include
#include
#include
#include "struct.h"
#include "sdlscreen.h"
#include "global.h"
#include "graph.h" //Afficher_curseur
#include "erreurs.h"
#include "boutons.h"
#include "moteur.h"
#include "divers.h"
#include "clavier.h"
#include "sdlscreen.h"
#include "windows.h"
word Palette_Compter_nb_couleurs_utilisees(dword* Tableau)
{
int Nombre_De_Pixels=0;
Uint8* Pixel_Courant=Principal_Ecran;
Uint8 Couleur;
word Nombre_Couleurs=0;
int i;
for (i=0;i<256;i++) Tableau[i]=0;
//Calcul du nombre de pixels dans l'image
Nombre_De_Pixels=Principal_Hauteur_image*Principal_Largeur_image;
// On parcourt l'écran courant pour compter les utilisations des couleurs
for(i=0;i Principal_Split)
INPUT_Nouveau_Mouse_Y=INPUT_Nouveau_Mouse_Y Principal_Split)
{
INPUT_Nouveau_Mouse_Y+=Loupe_Facteur;
if (INPUT_Nouveau_Mouse_Y>=Hauteur_ecran)
INPUT_Nouveau_Mouse_Y=Hauteur_ecran-1;
}
else
INPUT_Nouveau_Mouse_Y++;
ok=1;
}
}
else if(Touche == Config_Touche[2])
{
//[Touche] = Emulation de MOUSE LEFT
if(INPUT_Nouveau_Mouse_X!=0)
{
if(Loupe_Mode && INPUT_Nouveau_Mouse_Y < Menu_Ordonnee && INPUT_Nouveau_Mouse_X > Principal_Split)
INPUT_Nouveau_Mouse_X-=Loupe_Facteur;
else
INPUT_Nouveau_Mouse_X--;
ok=1;
}
}
else if(Touche == Config_Touche[3])
{
//[Touche] = Emulation de MOUSE RIGHT
if(INPUT_Nouveau_Mouse_X Principal_Split)
{
INPUT_Nouveau_Mouse_X+=Loupe_Facteur;
if (INPUT_Nouveau_Mouse_X>=Largeur_ecran)
INPUT_Nouveau_Mouse_X=Largeur_ecran-1;
}
else
INPUT_Nouveau_Mouse_X++;
ok=1;
}
}
else if(Touche == Config_Touche[4])
{
//[Touche] = Emulation de MOUSE CLICK LEFT
INPUT_Nouveau_Mouse_K=1;
ok=1;
}
else if(Touche == Config_Touche[5])
{
//[Touche] = Emulation de MOUSE CLICK RIGHT
INPUT_Nouveau_Mouse_K=2;
ok=1;
}
if(ok)
{
SDL_WarpMouse(
INPUT_Nouveau_Mouse_X*Pixel_width,
INPUT_Nouveau_Mouse_Y*Pixel_height
);
}
}
break;
}
}
else
{
Flush_update();
return 0; // Il ne s'est rien passé
}
//Gestion "avancée" du curseur: interdire la descente du curseur dans le
//menu lorsqu'on est en train de travailler dans l'image
if(Operation_Taille_pile!=0)
{
byte bl=0;//BL va indiquer si on doit corriger la position du curseur
//Si le curseur ne se trouve plus dans l'image
if(Menu_Ordonnee<=INPUT_Nouveau_Mouse_Y)
{
//On bloque le curseur en fin d'image
bl++;
INPUT_Nouveau_Mouse_Y=Menu_Ordonnee-1; //La ligne !!au-dessus!! du menu
}
if(Loupe_Mode)
{
if(Operation_dans_loupe==0)
{
if(INPUT_Nouveau_Mouse_X>=Principal_Split)
{
bl++;
INPUT_Nouveau_Mouse_X=Principal_Split-1;
}
}
else
{
if(INPUT_Nouveau_Mouse_X0;dx--)
{
esi = Debut_de_colonne;
// Pout chaque colonne
for(cx=Brosse_Hauteur;cx>0;cx--)
{
*edi = *esi;
esi+=Brosse_Largeur;
edi++;
}
Debut_de_colonne--;
}
}
// Remplacer une couleur par une autre dans un buffer
void Remap_general_LOWLEVEL(byte * Table_conv,byte * Buffer,short Largeur,short Hauteur,short Largeur_buffer)
{
int dx,cx;
// Pour chaque ligne
for(dx=Hauteur;dx>0;dx--)
{
// Pour chaque pixel
for(cx=Largeur;cx>0;cx--)
{
*Buffer = Table_conv[*Buffer];
Buffer++;
}
Buffer += Largeur_buffer-Largeur;
}
}
void Copier_image_dans_brosse(short Debut_X,short Debut_Y,short Brosse_Largeur,short Brosse_Hauteur,word Largeur_image)
{
byte* Src=Debut_Y*Largeur_image+Debut_X+Principal_Ecran; //Adr départ image (ESI)
byte* Dest=Brosse; //Adr dest brosse (EDI)
int dx;
for (dx=Brosse_Hauteur;dx!=0;dx--)
//Pour chaque ligne
{
// On fait une copie de la ligne
memcpy(Dest,Src,Brosse_Largeur);
// On passe à la ligne suivante
Src+=Largeur_image;
Dest+=Brosse_Largeur;
}
}
byte Lit_pixel_dans_ecran_feedback (word X,word Y)
{
return *(FX_Feedback_Ecran+Y*Principal_Largeur_image+X);
}
dword Round_div(dword Numerateur,dword Diviseur)
{
return Numerateur/Diviseur;
}
byte Effet_Trame(word X,word Y)
{
return Trame[X % Trame_Largeur][Y % Trame_Hauteur];
}
void Set_mouse_position(void)
{
SDL_WarpMouse(
Mouse_X*Pixel_width,
Mouse_Y*Pixel_height
);
}
void Remplacer_toutes_les_couleurs_dans_limites(byte * Table_de_remplacement)
{
int Ligne;
int Compteur;
byte* Adresse;
byte Ancien;
// Pour chaque ligne :
for(Ligne = Limite_Haut;Ligne <= Limite_Bas; Ligne++)
{
// Pour chaque pixel sur la ligne :
for (Compteur = Limite_Gauche;Compteur <= Limite_Droite;Compteur ++)
{
Adresse = Principal_Ecran+Ligne*Principal_Largeur_image+Compteur;
Ancien=*Adresse;
*Adresse = Table_de_remplacement[Ancien];
}
}
}
byte Lit_pixel_dans_ecran_backup (word X,word Y)
{
return *(Ecran_backup + X + Principal_Largeur_image * Y);
}
// Les images ILBM sont stockés en bitplanes donc on doit trifouiller les bits pour
// en faire du chunky
byte Couleur_ILBM_line(word Pos_X, word Vraie_taille_ligne, byte HBPm1)
{
// CL sera le rang auquel on extrait les bits de la couleur
byte cl = 7 - (Pos_X & 7);
int ax,bh,dx;
byte bl=0;
for(dx=HBPm1;dx>=0;dx--)
{
//CIL_Loop
ax = (Vraie_taille_ligne * dx + Pos_X) >> 3;
bh = (LBM_Buffer[ax] >> cl) & 1;
bl = (bl << 1) + bh;
}
return bl;
}
void Palette_256_to_64(T_Palette Palette)
{
int i;
for(i=0;i<256;i++)
{
Palette[i].R = Palette[i].R >> 2;
Palette[i].V = Palette[i].V >> 2;
Palette[i].B = Palette[i].B >> 2;
}
}
void Palette_64_to_256(T_Palette Palette)
{
int i;
for(i=0;i<256;i++)
{
Palette[i].R = (Palette[i].R << 2)|(Palette[i].R >> 4);
Palette[i].V = (Palette[i].V << 2)|(Palette[i].V >> 4);
Palette[i].B = (Palette[i].B << 2)|(Palette[i].B >> 4);
}
}
byte Effet_Colorize_interpole (word X,word Y,byte Couleur)
{
// Facteur_A = 256*(100-Colorize_Opacite)/100
// Facteur_B = 256*( Colorize_Opacite)/100
//
// (Couleur_dessous*Facteur_A+Couleur*facteur_B)/256
//
// On place dans ESI 3*Couleur_dessous ( = position de cette couleur dans la
// palette des teintes) et dans EDI, 3*Couleur.
byte Bleu_dessous=Principal_Palette[*(FX_Feedback_Ecran + Y * Principal_Largeur_image + X)].B;
byte Bleu=Principal_Palette[Couleur].B;
byte Vert_dessous=Principal_Palette[*(FX_Feedback_Ecran + Y * Principal_Largeur_image + X)].V;
byte Vert=Principal_Palette[Couleur].V;
byte Rouge_dessous=Principal_Palette[*(FX_Feedback_Ecran + Y * Principal_Largeur_image + X)].R;
byte Rouge=Principal_Palette[Couleur].R;
// On récupère les 3 composantes RVB
// Bleu
Bleu = (Table_de_multiplication_par_Facteur_B[Bleu]
+ Table_de_multiplication_par_Facteur_A[Bleu_dessous]) / 256;
Vert = (Table_de_multiplication_par_Facteur_B[Vert]
+ Table_de_multiplication_par_Facteur_A[Vert_dessous]) / 256;
Rouge = (Table_de_multiplication_par_Facteur_B[Rouge]
+ Table_de_multiplication_par_Facteur_A[Rouge_dessous]) / 256;
return Meilleure_couleur(Rouge,Vert,Bleu);
}
byte Effet_Colorize_additif (word X,word Y,byte Couleur)
{
byte Bleu_dessous=Principal_Palette[*(FX_Feedback_Ecran + Y * Principal_Largeur_image + X)].B;
byte Vert_dessous=Principal_Palette[*(FX_Feedback_Ecran + Y * Principal_Largeur_image + X)].V;
byte Rouge_dessous=Principal_Palette[*(FX_Feedback_Ecran + Y * Principal_Largeur_image + X)].R;
byte Bleu=Principal_Palette[Couleur].B;
byte Vert=Principal_Palette[Couleur].V;
byte Rouge=Principal_Palette[Couleur].R;
return Meilleure_couleur(
Rouge>Rouge_dessous?Rouge:Rouge_dessous,
Vert>Vert_dessous?Vert:Vert_dessous,
Bleu>Bleu_dessous?Bleu:Bleu_dessous);
}
byte Effet_Colorize_soustractif(word X,word Y,byte Couleur)
{
byte Bleu_dessous=Principal_Palette[*(FX_Feedback_Ecran + Y * Principal_Largeur_image + X)].B;
byte Vert_dessous=Principal_Palette[*(FX_Feedback_Ecran + Y * Principal_Largeur_image + X)].V;
byte Rouge_dessous=Principal_Palette[*(FX_Feedback_Ecran + Y * Principal_Largeur_image + X)].R;
byte Bleu=Principal_Palette[Couleur].B;
byte Vert=Principal_Palette[Couleur].V;
byte Rouge=Principal_Palette[Couleur].R;
return Meilleure_couleur(
RougeChrono_cmp) Etat_chrono=1;
}
// Effectue une inversion de la brosse selon une droite horizontale
void Flip_Y_LOWLEVEL(void)
{
// ESI pointe sur la partie haute de la brosse
// EDI sur la partie basse
byte* ESI = Brosse ;
byte* EDI = Brosse + (Brosse_Hauteur - 1) *Brosse_Largeur;
byte tmp;
word cx;
while(ESI < EDI)
{
// Il faut inverser les lignes pointées par ESI et
// EDI ("Brosse_Largeur" octets en tout)
for(cx = Brosse_Largeur;cx>0;cx--)
{
tmp = *ESI;
*ESI = *EDI;
*EDI = tmp;
ESI++;
EDI++;
}
// On change de ligne :
// ESI pointe déjà sur le début de la ligne suivante
// EDI pointe sur la fin de la ligne en cours, il
// doit pointer sur le début de la précédente...
EDI -= 2 * Brosse_Largeur; // On recule de 2 lignes
}
}
// Effectue une inversion de la brosse selon une droite verticale
void Flip_X_LOWLEVEL(void)
{
// ESI pointe sur la partie gauche et EDI sur la partie
// droite
byte* ESI = Brosse;
byte* EDI = Brosse + Brosse_Largeur - 1;
byte* Debut_Ligne;
byte* Fin_Ligne;
byte tmp;
word cx;
while(ESI0;cx--)
{
tmp=*ESI;
*ESI=*EDI;
*EDI=tmp;
EDI+=Brosse_Largeur;
ESI+=Brosse_Largeur;
}
// On change de colonne
// ESI > colonne suivante
// EDI > colonne précédente
ESI = Debut_Ligne + 1;
EDI = Fin_Ligne - 1;
}
}
// Faire une rotation de 180º de la brosse
void Rotate_180_deg_LOWLEVEL(void)
{
// ESI pointe sur la partie supérieure de la brosse
// EDI pointe sur la partie basse
byte* ESI = Brosse;
byte* EDI = Brosse + Brosse_Hauteur*Brosse_Largeur - 1;
// EDI pointe sur le dernier pixel de la derniere ligne
byte tmp;
word cx;
while(ESI < EDI)
{
// On échange les deux lignes pointées par EDI et
// ESI (Brosse_Largeur octets)
// En même temps, on échange les pixels, donc EDI
// pointe sur la FIN de sa ligne
for(cx=Brosse_Largeur;cx>0;cx--)
{
tmp = *ESI;
*ESI = *EDI;
*EDI = tmp;
EDI--; // Attention ici on recule !
ESI++;
}
}
}
void Tempo_jauge(byte Vitesse)
//Boucle d'attente pour faire bouger les scrollbars à une vitesse correcte
{
while (Vitesse!=0)
{
Wait_VBL();
Vitesse--;
}
}
void Scroll_picture(short Decalage_X,short Decalage_Y)
{
byte* esi = Ecran_backup; //Source de la copie
byte* edi = Principal_Ecran + Decalage_Y * Principal_Largeur_image + Decalage_X;
const word ax = Principal_Largeur_image - Decalage_X; // Nombre de pixels à copier à droite
word dx;
for(dx = Principal_Hauteur_image - Decalage_Y;dx>0;dx--)
{
// Pour chaque ligne
memcpy(edi,esi,ax);
memcpy(edi - Decalage_X,esi+ax,Decalage_X);
// On passe à la ligne suivante
edi += Principal_Largeur_image;
esi += Principal_Largeur_image;
}
// On vient de faire le traitement pour otutes les lignes au-dessous de Decalage_Y
// Maintenant on traite celles au dessus
edi = Decalage_X + Principal_Ecran;
for(dx = Decalage_Y;dx>0;dx--)
{
memcpy(edi,esi,ax);
memcpy(edi - Decalage_X,esi+ax,Decalage_X);
edi += Principal_Largeur_image;
esi += Principal_Largeur_image;
}
UpdateRect(0,0,0,0);
}
word Get_key(void)
{
SDL_Event event;
Attendre_fin_de_click(); // On prend le controle de la boucle d'évènements, donc il ne faut pas qu'on rate la fin de click !
while(1)
{
SDL_WaitEvent(&event);
if(event.type == SDL_KEYDOWN)
{
return Conversion_ANSI(event.key.keysym);
}
else
Gere_Evenement_SDL(&event);
}
}
void Zoomer_une_ligne(byte* Ligne_originale, byte* Ligne_zoomee,
word Facteur, word Largeur
)
{
byte couleur;
word larg;
// Pour chaque pixel
for(larg=0;larg
#elif defined(__macosx__)
#include
#elif defined(__BEOS__) || defined(__HAIKU__)
// sysinfo not implemented
#elif defined(__AROS__)
#include
#else
#include // sysinfo() for free RAM
#endif
// Indique quelle est la mémoire disponible
unsigned long Memoire_libre(void)
{
// On appelle la fonction qui optimise la mémoire libre afin d'en
// regagner un maximum. Sinon, tous les "free" libèrent une mémoire qui
// n'est pas prise en compte par la fonction, et on se retrouve avec un
// manque alarmant de mémoire.
/*
A revoir, mais est-ce vraiment utile?
_heapmin();
*/
// Memory is no longer relevant. If there is ANY problem or doubt here,
// you can simply return 10*1024*1024 (10Mb), to make the "Pages"something
// memory allocation functions happy.
#if defined(__WIN32__)
MEMORYSTATUSEX mstt;
mstt.dwLength = sizeof(MEMORYSTATUSEX);
GlobalMemoryStatusEx(&mstt);
return mstt.ullAvailPhys;
#elif defined(__macosx__)
int mib[2];
int maxmem;
size_t len;
mib[0] = CTL_HW;
mib[1] = HW_USERMEM;
len = sizeof(maxmem);
sysctl(mib,2,&maxmem,&len,NULL,0);
return maxmem;
#elif defined(__BEOS__) || defined(__HAIKU__)
// No on BeOS or Haiku
return 10*1024*1024;
#elif defined(__AROS__)
return AvailMem(MEMF_ANY);
#else
struct sysinfo info;
sysinfo(&info);
return info.freeram*info.mem_unit;
#endif
}
// 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;
}
// Fonction retournant le libellé d'une mode (ex: " 320x200")
char * Libelle_mode(int Mode)
{
static char Chaine[24];
if (! Mode_video[Mode].Fullscreen)
return "window";
sprintf(Chaine, "%dx%d", Mode_video[Mode].Largeur, Mode_video[Mode].Hauteur);
return Chaine;
}
// Trouve un mode video à partir d'une chaine: soit "window",
// soit de la forme "320x200"
// Renvoie -1 si la chaine n'est pas convertible
int Conversion_argument_mode(const char *Argument)
{
// Je suis paresseux alors je vais juste tester les libellés
int Indice_mode;
for (Indice_mode=0; Indice_mode